Blame server/shadow/X11/x11_shadow.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
Packit 1fb8d4
 * Copyright 2017 Thincast Technologies GmbH
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#include <errno.h>
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <stdlib.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
#include <unistd.h>
Packit 1fb8d4
Packit 1fb8d4
#include <sys/ipc.h>
Packit 1fb8d4
#include <sys/shm.h>
Packit 1fb8d4
#include <sys/select.h>
Packit 1fb8d4
#include <sys/signal.h>
Packit 1fb8d4
Packit 1fb8d4
#include <X11/Xlib.h>
Packit 1fb8d4
#include <X11/Xutil.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/path.h>
Packit 1fb8d4
#include <winpr/synch.h>
Packit 1fb8d4
#include <winpr/image.h>
Packit 1fb8d4
#include <winpr/sysinfo.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/log.h>
Packit 1fb8d4
#include <freerdp/codec/color.h>
Packit 1fb8d4
#include <freerdp/codec/region.h>
Packit 1fb8d4
Packit 1fb8d4
#include "x11_shadow.h"
Packit 1fb8d4
Packit 1fb8d4
#define TAG SERVER_TAG("shadow.x11")
Packit 1fb8d4
Packit 1fb8d4
static UINT32 x11_shadow_enum_monitors(MONITOR_DEF* monitors, UINT32 maxMonitors);
Packit 1fb8d4
Packit 1fb8d4
#ifdef WITH_PAM
Packit 1fb8d4
Packit 1fb8d4
#include <security/pam_appl.h>
Packit 1fb8d4
Packit 1fb8d4
struct _SHADOW_PAM_AUTH_DATA
Packit 1fb8d4
{
Packit 1fb8d4
	const char* user;
Packit 1fb8d4
	const char* domain;
Packit 1fb8d4
	const char* password;
Packit 1fb8d4
};
Packit 1fb8d4
typedef struct _SHADOW_PAM_AUTH_DATA SHADOW_PAM_AUTH_DATA;
Packit 1fb8d4
Packit 1fb8d4
struct _SHADOW_PAM_AUTH_INFO
Packit 1fb8d4
{
Packit 1fb8d4
	char* service_name;
Packit 1fb8d4
	pam_handle_t* handle;
Packit 1fb8d4
	struct pam_conv pamc;
Packit 1fb8d4
	SHADOW_PAM_AUTH_DATA appdata;
Packit 1fb8d4
};
Packit 1fb8d4
typedef struct _SHADOW_PAM_AUTH_INFO SHADOW_PAM_AUTH_INFO;
Packit 1fb8d4
Packit 1fb8d4
static int x11_shadow_pam_conv(int num_msg, const struct pam_message** msg,
Packit 1fb8d4
                               struct pam_response** resp, void* appdata_ptr)
Packit 1fb8d4
{
Packit 1fb8d4
	int index;
Packit 1fb8d4
	int pam_status = PAM_CONV_ERR;
Packit 1fb8d4
	SHADOW_PAM_AUTH_DATA* appdata;
Packit 1fb8d4
	struct pam_response* response;
Packit Service 5a9772
	appdata = (SHADOW_PAM_AUTH_DATA*)appdata_ptr;
Packit 1fb8d4
Packit Service 5a9772
	if (!(response = (struct pam_response*)calloc(num_msg, sizeof(struct pam_response))))
Packit 1fb8d4
		return PAM_BUF_ERR;
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < num_msg; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		switch (msg[index]->msg_style)
Packit 1fb8d4
		{
Packit 1fb8d4
			case PAM_PROMPT_ECHO_ON:
Packit 1fb8d4
				response[index].resp = _strdup(appdata->user);
Packit 1fb8d4
Packit 1fb8d4
				if (!response[index].resp)
Packit 1fb8d4
					goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
				response[index].resp_retcode = PAM_SUCCESS;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			case PAM_PROMPT_ECHO_OFF:
Packit 1fb8d4
				response[index].resp = _strdup(appdata->password);
Packit 1fb8d4
Packit 1fb8d4
				if (!response[index].resp)
Packit 1fb8d4
					goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
				response[index].resp_retcode = PAM_SUCCESS;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			default:
Packit 1fb8d4
				pam_status = PAM_CONV_ERR;
Packit 1fb8d4
				goto out_fail;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	*resp = response;
Packit 1fb8d4
	return PAM_SUCCESS;
Packit 1fb8d4
out_fail:
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < num_msg; ++index)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (response[index].resp)
Packit 1fb8d4
		{
Packit 1fb8d4
			memset(response[index].resp, 0, strlen(response[index].resp));
Packit 1fb8d4
			free(response[index].resp);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	memset(response, 0, sizeof(struct pam_response) * num_msg);
Packit 1fb8d4
	free(response);
Packit 1fb8d4
	*resp = NULL;
Packit 1fb8d4
	return pam_status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int x11_shadow_pam_get_service_name(SHADOW_PAM_AUTH_INFO* info)
Packit 1fb8d4
{
Packit 1fb8d4
	if (PathFileExistsA("/etc/pam.d/lightdm"))
Packit 1fb8d4
	{
Packit 1fb8d4
		info->service_name = _strdup("lightdm");
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (PathFileExistsA("/etc/pam.d/gdm"))
Packit 1fb8d4
	{
Packit 1fb8d4
		info->service_name = _strdup("gdm");
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (PathFileExistsA("/etc/pam.d/xdm"))
Packit 1fb8d4
	{
Packit 1fb8d4
		info->service_name = _strdup("xdm");
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (PathFileExistsA("/etc/pam.d/login"))
Packit 1fb8d4
	{
Packit 1fb8d4
		info->service_name = _strdup("login");
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (PathFileExistsA("/etc/pam.d/sshd"))
Packit 1fb8d4
	{
Packit 1fb8d4
		info->service_name = _strdup("sshd");
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!info->service_name)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static int x11_shadow_pam_authenticate(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
Packit Service 5a9772
                                       const char* user, const char* domain, const char* password)
Packit 1fb8d4
{
Packit 1fb8d4
	int pam_status;
Packit 1fb8d4
	SHADOW_PAM_AUTH_INFO* info;
Packit Service 5a9772
	WINPR_UNUSED(subsystem);
Packit Service 5a9772
	WINPR_UNUSED(client);
Packit 1fb8d4
	info = calloc(1, sizeof(SHADOW_PAM_AUTH_INFO));
Packit 1fb8d4
Packit 1fb8d4
	if (!info)
Packit 1fb8d4
		return PAM_CONV_ERR;
Packit 1fb8d4
Packit 1fb8d4
	if (x11_shadow_pam_get_service_name(info) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(info);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	info->appdata.user = user;
Packit 1fb8d4
	info->appdata.domain = domain;
Packit 1fb8d4
	info->appdata.password = password;
Packit 1fb8d4
	info->pamc.conv = &x11_shadow_pam_conv;
Packit 1fb8d4
	info->pamc.appdata_ptr = &(info->appdata);
Packit 1fb8d4
	pam_status = pam_start(info->service_name, 0, &(info->pamc), &(info->handle));
Packit 1fb8d4
Packit 1fb8d4
	if (pam_status != PAM_SUCCESS)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "pam_start failure: %s", pam_strerror(info->handle, pam_status));
Packit 1fb8d4
		free(info);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	pam_status = pam_authenticate(info->handle, 0);
Packit 1fb8d4
Packit 1fb8d4
	if (pam_status != PAM_SUCCESS)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "pam_authenticate failure: %s", pam_strerror(info->handle, pam_status));
Packit 1fb8d4
		free(info);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	pam_status = pam_acct_mgmt(info->handle, 0);
Packit 1fb8d4
Packit 1fb8d4
	if (pam_status != PAM_SUCCESS)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_ERR(TAG, "pam_acct_mgmt failure: %s", pam_strerror(info->handle, pam_status));
Packit 1fb8d4
		free(info);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(info);
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
static BOOL x11_shadow_input_synchronize_event(rdpShadowSubsystem* subsystem,
Packit Service 5a9772
                                               rdpShadowClient* client, UINT32 flags)
Packit 1fb8d4
{
Packit Service 5a9772
	/* TODO: Implement */
Packit Service 5a9772
	WLog_WARN(TAG, "%s not implemented", __FUNCTION__);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL x11_shadow_input_keyboard_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
Packit Service 5a9772
                                            UINT16 flags, UINT16 code)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef WITH_XTEST
Packit 1fb8d4
	x11ShadowSubsystem* x11 = (x11ShadowSubsystem*)subsystem;
Packit 1fb8d4
	DWORD vkcode;
Packit 1fb8d4
	DWORD keycode;
Packit 1fb8d4
	BOOL extended = FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!client || !subsystem)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (flags & KBD_FLAGS_EXTENDED)
Packit 1fb8d4
		extended = TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if (extended)
Packit 1fb8d4
		code |= KBDEXT;
Packit 1fb8d4
Packit 1fb8d4
	vkcode = GetVirtualKeyCodeFromVirtualScanCode(code, 4);
Packit 1fb8d4
Packit 1fb8d4
	if (extended)
Packit 1fb8d4
		vkcode |= KBDEXT;
Packit 1fb8d4
Packit 1fb8d4
	keycode = GetKeycodeFromVirtualKeyCode(vkcode, KEYCODE_TYPE_EVDEV);
Packit 1fb8d4
Packit 1fb8d4
	if (keycode != 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		XLockDisplay(x11->display);
Packit 1fb8d4
		XTestGrabControl(x11->display, True);
Packit 1fb8d4
Packit 1fb8d4
		if (flags & KBD_FLAGS_DOWN)
Packit 1fb8d4
			XTestFakeKeyEvent(x11->display, keycode, True, CurrentTime);
Packit 1fb8d4
		else if (flags & KBD_FLAGS_RELEASE)
Packit 1fb8d4
			XTestFakeKeyEvent(x11->display, keycode, False, CurrentTime);
Packit 1fb8d4
Packit 1fb8d4
		XTestGrabControl(x11->display, False);
Packit 1fb8d4
		XFlush(x11->display);
Packit 1fb8d4
		XUnlockDisplay(x11->display);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL x11_shadow_input_unicode_keyboard_event(rdpShadowSubsystem* subsystem,
Packit Service 5a9772
                                                    rdpShadowClient* client, UINT16 flags,
Packit Service 5a9772
                                                    UINT16 code)
Packit 1fb8d4
{
Packit Service 5a9772
	/* TODO: Implement */
Packit Service 5a9772
	WLog_WARN(TAG, "%s not implemented", __FUNCTION__);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static BOOL x11_shadow_input_mouse_event(rdpShadowSubsystem* subsystem, rdpShadowClient* client,
Packit Service 5a9772
                                         UINT16 flags, UINT16 x, UINT16 y)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef WITH_XTEST
Packit 1fb8d4
	x11ShadowSubsystem* x11 = (x11ShadowSubsystem*)subsystem;
Packit 1fb8d4
	int button = 0;
Packit 1fb8d4
	BOOL down = FALSE;
Packit 1fb8d4
	rdpShadowServer* server;
Packit 1fb8d4
	rdpShadowSurface* surface;
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem || !client)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	server = subsystem->server;
Packit 1fb8d4
Packit 1fb8d4
	if (!server)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	surface = server->surface;
Packit 1fb8d4
Packit 1fb8d4
	if (!surface)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	x11->lastMouseClient = client;
Packit 1fb8d4
	x += surface->x;
Packit 1fb8d4
	y += surface->y;
Packit 1fb8d4
	XLockDisplay(x11->display);
Packit 1fb8d4
	XTestGrabControl(x11->display, True);
Packit 1fb8d4
Packit 1fb8d4
	if (flags & PTR_FLAGS_WHEEL)
Packit 1fb8d4
	{
Packit 1fb8d4
		BOOL negative = FALSE;
Packit 1fb8d4
Packit 1fb8d4
		if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
Packit 1fb8d4
			negative = TRUE;
Packit 1fb8d4
Packit 1fb8d4
		button = (negative) ? 5 : 4;
Packit 1fb8d4
		XTestFakeButtonEvent(x11->display, button, True, CurrentTime);
Packit 1fb8d4
		XTestFakeButtonEvent(x11->display, button, False, CurrentTime);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		if (flags & PTR_FLAGS_MOVE)
Packit 1fb8d4
			XTestFakeMotionEvent(x11->display, 0, x, y, CurrentTime);
Packit 1fb8d4
Packit 1fb8d4
		if (flags & PTR_FLAGS_BUTTON1)
Packit 1fb8d4
			button = 1;
Packit 1fb8d4
		else if (flags & PTR_FLAGS_BUTTON2)
Packit 1fb8d4
			button = 3;
Packit 1fb8d4
		else if (flags & PTR_FLAGS_BUTTON3)
Packit 1fb8d4
			button = 2;
Packit 1fb8d4
Packit 1fb8d4
		if (flags & PTR_FLAGS_DOWN)
Packit 1fb8d4
			down = TRUE;
Packit 1fb8d4
Packit 1fb8d4
		if (button)
Packit 1fb8d4
			XTestFakeButtonEvent(x11->display, button, down, CurrentTime);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	XTestGrabControl(x11->display, False);
Packit 1fb8d4
	XFlush(x11->display);
Packit 1fb8d4
	XUnlockDisplay(x11->display);
Packit 1fb8d4
#endif
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL x11_shadow_input_extended_mouse_event(rdpShadowSubsystem* subsystem,
Packit Service 5a9772
                                                  rdpShadowClient* client, UINT16 flags, UINT16 x,
Packit Service 5a9772
                                                  UINT16 y)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef WITH_XTEST
Packit 1fb8d4
	x11ShadowSubsystem* x11 = (x11ShadowSubsystem*)subsystem;
Packit 1fb8d4
	int button = 0;
Packit 1fb8d4
	BOOL down = FALSE;
Packit 1fb8d4
	rdpShadowServer* server;
Packit 1fb8d4
	rdpShadowSurface* surface;
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem || !client)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	server = subsystem->server;
Packit 1fb8d4
Packit 1fb8d4
	if (!server)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	surface = server->surface;
Packit 1fb8d4
Packit 1fb8d4
	if (!surface)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	x11->lastMouseClient = client;
Packit 1fb8d4
	x += surface->x;
Packit 1fb8d4
	y += surface->y;
Packit 1fb8d4
	XLockDisplay(x11->display);
Packit 1fb8d4
	XTestGrabControl(x11->display, True);
Packit 1fb8d4
	XTestFakeMotionEvent(x11->display, 0, x, y, CurrentTime);
Packit 1fb8d4
Packit 1fb8d4
	if (flags & PTR_XFLAGS_BUTTON1)
Packit 1fb8d4
		button = 8;
Packit 1fb8d4
	else if (flags & PTR_XFLAGS_BUTTON2)
Packit 1fb8d4
		button = 9;
Packit 1fb8d4
Packit 1fb8d4
	if (flags & PTR_XFLAGS_DOWN)
Packit 1fb8d4
		down = TRUE;
Packit 1fb8d4
Packit 1fb8d4
	if (button)
Packit 1fb8d4
		XTestFakeButtonEvent(x11->display, button, down, CurrentTime);
Packit 1fb8d4
Packit 1fb8d4
	XTestGrabControl(x11->display, False);
Packit 1fb8d4
	XFlush(x11->display);
Packit 1fb8d4
	XUnlockDisplay(x11->display);
Packit 1fb8d4
#endif
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void x11_shadow_message_free(UINT32 id, SHADOW_MSG_OUT* msg)
Packit 1fb8d4
{
Packit 1fb8d4
	switch (id)
Packit 1fb8d4
	{
Packit 1fb8d4
		case SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID:
Packit 1fb8d4
			free(msg);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID:
Packit 1fb8d4
			free(((SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*)msg)->xorMaskData);
Packit 1fb8d4
			free(((SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*)msg)->andMaskData);
Packit 1fb8d4
			free(msg);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit Service 5a9772
			WLog_ERR(TAG, "Unknown message id: %" PRIu32 "", id);
Packit 1fb8d4
			free(msg);
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int x11_shadow_pointer_position_update(x11ShadowSubsystem* subsystem)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 msgId = SHADOW_MSG_OUT_POINTER_POSITION_UPDATE_ID;
Packit 1fb8d4
	rdpShadowServer* server;
Packit 1fb8d4
	SHADOW_MSG_OUT_POINTER_POSITION_UPDATE templateMsg;
Packit 1fb8d4
	int count = 0;
Packit 1fb8d4
	int index = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem || !subsystem->common.server || !subsystem->common.server->clients)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	templateMsg.xPos = subsystem->common.pointerX;
Packit 1fb8d4
	templateMsg.yPos = subsystem->common.pointerY;
Packit 1fb8d4
	templateMsg.common.Free = x11_shadow_message_free;
Packit 1fb8d4
	server = subsystem->common.server;
Packit 1fb8d4
	ArrayList_Lock(server->clients);
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < ArrayList_Count(server->clients); index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		SHADOW_MSG_OUT_POINTER_POSITION_UPDATE* msg;
Packit 1fb8d4
		rdpShadowClient* client = (rdpShadowClient*)ArrayList_GetItem(server->clients, index);
Packit 1fb8d4
Packit 1fb8d4
		/* Skip the client which send us the latest mouse event */
Packit 1fb8d4
		if (client == subsystem->lastMouseClient)
Packit 1fb8d4
			continue;
Packit 1fb8d4
Packit 1fb8d4
		msg = malloc(sizeof(templateMsg));
Packit 1fb8d4
Packit 1fb8d4
		if (!msg)
Packit 1fb8d4
		{
Packit 1fb8d4
			count = -1;
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		memcpy(msg, &templateMsg, sizeof(templateMsg));
Packit 1fb8d4
Packit Service 5a9772
		if (shadow_client_post_msg(client, NULL, msgId, (SHADOW_MSG_OUT*)msg, NULL))
Packit 1fb8d4
			count++;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ArrayList_Unlock(server->clients);
Packit 1fb8d4
	return count;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int x11_shadow_pointer_alpha_update(x11ShadowSubsystem* subsystem)
Packit 1fb8d4
{
Packit 1fb8d4
	SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE* msg;
Packit 1fb8d4
	UINT32 msgId = SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE_ID;
Packit Service 5a9772
	msg = (SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE*)calloc(1,
Packit Service 5a9772
	                                                   sizeof(SHADOW_MSG_OUT_POINTER_ALPHA_UPDATE));
Packit 1fb8d4
Packit 1fb8d4
	if (!msg)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	msg->xHot = subsystem->cursorHotX;
Packit 1fb8d4
	msg->yHot = subsystem->cursorHotY;
Packit 1fb8d4
	msg->width = subsystem->cursorWidth;
Packit 1fb8d4
	msg->height = subsystem->cursorHeight;
Packit 1fb8d4
Packit Service 5a9772
	if (shadow_subsystem_pointer_convert_alpha_pointer_data(subsystem->cursorPixels, TRUE,
Packit Service 5a9772
	                                                        msg->width, msg->height, msg) < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(msg);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	msg->common.Free = x11_shadow_message_free;
Packit Service 5a9772
	return shadow_client_boardcast_msg(subsystem->common.server, NULL, msgId, (SHADOW_MSG_OUT*)msg,
Packit Service 5a9772
	                                   NULL)
Packit Service 5a9772
	           ? 1
Packit Service 5a9772
	           : -1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int x11_shadow_query_cursor(x11ShadowSubsystem* subsystem, BOOL getImage)
Packit 1fb8d4
{
Packit 1fb8d4
	int x = 0, y = 0, n, k;
Packit 1fb8d4
	rdpShadowServer* server;
Packit 1fb8d4
	rdpShadowSurface* surface;
Packit 1fb8d4
	server = subsystem->common.server;
Packit 1fb8d4
	surface = server->surface;
Packit 1fb8d4
Packit 1fb8d4
	if (getImage)
Packit 1fb8d4
	{
Packit 1fb8d4
#ifdef WITH_XFIXES
Packit 1fb8d4
		UINT32* pDstPixel;
Packit 1fb8d4
		XFixesCursorImage* ci;
Packit 1fb8d4
		XLockDisplay(subsystem->display);
Packit 1fb8d4
		ci = XFixesGetCursorImage(subsystem->display);
Packit 1fb8d4
		XUnlockDisplay(subsystem->display);
Packit 1fb8d4
Packit 1fb8d4
		if (!ci)
Packit 1fb8d4
			return -1;
Packit 1fb8d4
Packit 1fb8d4
		x = ci->x;
Packit 1fb8d4
		y = ci->y;
Packit 1fb8d4
Packit 1fb8d4
		if (ci->width > subsystem->cursorMaxWidth)
Packit 1fb8d4
			return -1;
Packit 1fb8d4
Packit 1fb8d4
		if (ci->height > subsystem->cursorMaxHeight)
Packit 1fb8d4
			return -1;
Packit 1fb8d4
Packit 1fb8d4
		subsystem->cursorHotX = ci->xhot;
Packit 1fb8d4
		subsystem->cursorHotY = ci->yhot;
Packit 1fb8d4
		subsystem->cursorWidth = ci->width;
Packit 1fb8d4
		subsystem->cursorHeight = ci->height;
Packit 1fb8d4
		subsystem->cursorId = ci->cursor_serial;
Packit 1fb8d4
		n = ci->width * ci->height;
Packit Service 5a9772
		pDstPixel = (UINT32*)subsystem->cursorPixels;
Packit 1fb8d4
Packit 1fb8d4
		for (k = 0; k < n; k++)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* XFixesCursorImage.pixels is in *unsigned long*, which may be 8 bytes */
Packit Service 5a9772
			*pDstPixel++ = (UINT32)ci->pixels[k];
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		XFree(ci);
Packit 1fb8d4
		x11_shadow_pointer_alpha_update(subsystem);
Packit 1fb8d4
#endif
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		UINT32 mask;
Packit 1fb8d4
		int win_x, win_y;
Packit 1fb8d4
		int root_x, root_y;
Packit 1fb8d4
		Window root, child;
Packit 1fb8d4
		XLockDisplay(subsystem->display);
Packit 1fb8d4
Packit Service 5a9772
		if (!XQueryPointer(subsystem->display, subsystem->root_window, &root, &child, &root_x,
Packit Service 5a9772
		                   &root_y, &win_x, &win_y, &mask))
Packit 1fb8d4
		{
Packit 1fb8d4
			XUnlockDisplay(subsystem->display);
Packit 1fb8d4
			return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		XUnlockDisplay(subsystem->display);
Packit 1fb8d4
		x = root_x;
Packit 1fb8d4
		y = root_y;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Convert to offset based on current surface */
Packit 1fb8d4
	if (surface)
Packit 1fb8d4
	{
Packit 1fb8d4
		x -= surface->x;
Packit 1fb8d4
		y -= surface->y;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	if ((x != (INT64)subsystem->common.pointerX) || (y != (INT64)subsystem->common.pointerY))
Packit 1fb8d4
	{
Packit 1fb8d4
		subsystem->common.pointerX = x;
Packit 1fb8d4
		subsystem->common.pointerY = y;
Packit 1fb8d4
		x11_shadow_pointer_position_update(subsystem);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static int x11_shadow_handle_xevent(x11ShadowSubsystem* subsystem, XEvent* xevent)
Packit 1fb8d4
{
Packit 1fb8d4
	if (xevent->type == MotionNotify)
Packit 1fb8d4
	{
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#ifdef WITH_XFIXES
Packit 1fb8d4
	else if (xevent->type == subsystem->xfixes_cursor_notify_event)
Packit 1fb8d4
	{
Packit 1fb8d4
		x11_shadow_query_cursor(subsystem, TRUE);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void x11_shadow_validate_region(x11ShadowSubsystem* subsystem, int x, int y, int width,
Packit Service 5a9772
                                       int height)
Packit 1fb8d4
{
Packit 1fb8d4
	XRectangle region;
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem->use_xfixes || !subsystem->use_xdamage)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	region.x = x;
Packit 1fb8d4
	region.y = y;
Packit 1fb8d4
	region.width = width;
Packit 1fb8d4
	region.height = height;
Packit 1fb8d4
#ifdef WITH_XFIXES
Packit 1fb8d4
	XLockDisplay(subsystem->display);
Packit 1fb8d4
	XFixesSetRegion(subsystem->display, subsystem->xdamage_region, &region, 1);
Packit Service 5a9772
	XDamageSubtract(subsystem->display, subsystem->xdamage, subsystem->xdamage_region, None);
Packit 1fb8d4
	XUnlockDisplay(subsystem->display);
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int x11_shadow_blend_cursor(x11ShadowSubsystem* subsystem)
Packit 1fb8d4
{
Packit 1fb8d4
	int x, y;
Packit 1fb8d4
	int nXSrc;
Packit 1fb8d4
	int nYSrc;
Packit 1fb8d4
	int nXDst;
Packit 1fb8d4
	int nYDst;
Packit 1fb8d4
	int nWidth;
Packit 1fb8d4
	int nHeight;
Packit 1fb8d4
	int nSrcStep;
Packit 1fb8d4
	int nDstStep;
Packit 1fb8d4
	BYTE* pSrcData;
Packit 1fb8d4
	BYTE* pDstData;
Packit 1fb8d4
	BYTE A, R, G, B;
Packit 1fb8d4
	rdpShadowSurface* surface;
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	surface = subsystem->common.server->surface;
Packit 1fb8d4
	nXSrc = 0;
Packit 1fb8d4
	nYSrc = 0;
Packit 1fb8d4
	nWidth = subsystem->cursorWidth;
Packit 1fb8d4
	nHeight = subsystem->cursorHeight;
Packit 1fb8d4
	nXDst = subsystem->common.pointerX - subsystem->cursorHotX;
Packit 1fb8d4
	nYDst = subsystem->common.pointerY - subsystem->cursorHotY;
Packit 1fb8d4
Packit 1fb8d4
	if (nXDst >= surface->width)
Packit 1fb8d4
		return 1;
Packit 1fb8d4
Packit 1fb8d4
	if (nXDst < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		nXDst *= -1;
Packit 1fb8d4
Packit 1fb8d4
		if (nXDst >= nWidth)
Packit 1fb8d4
			return 1;
Packit 1fb8d4
Packit 1fb8d4
		nXSrc = nXDst;
Packit 1fb8d4
		nWidth -= nXDst;
Packit 1fb8d4
		nXDst = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (nYDst >= surface->height)
Packit 1fb8d4
		return 1;
Packit 1fb8d4
Packit 1fb8d4
	if (nYDst < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		nYDst *= -1;
Packit 1fb8d4
Packit 1fb8d4
		if (nYDst >= nHeight)
Packit 1fb8d4
			return 1;
Packit 1fb8d4
Packit 1fb8d4
		nYSrc = nYDst;
Packit 1fb8d4
		nHeight -= nYDst;
Packit 1fb8d4
		nYDst = 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if ((nXDst + nWidth) > surface->width)
Packit 1fb8d4
		nWidth = surface->width - nXDst;
Packit 1fb8d4
Packit 1fb8d4
	if ((nYDst + nHeight) > surface->height)
Packit 1fb8d4
		nHeight = surface->height - nYDst;
Packit 1fb8d4
Packit 1fb8d4
	pSrcData = subsystem->cursorPixels;
Packit 1fb8d4
	nSrcStep = subsystem->cursorWidth * 4;
Packit 1fb8d4
	pDstData = surface->data;
Packit 1fb8d4
	nDstStep = surface->scanline;
Packit 1fb8d4
Packit 1fb8d4
	for (y = 0; y < nHeight; y++)
Packit 1fb8d4
	{
Packit 1fb8d4
		const BYTE* pSrcPixel = &pSrcData[((nYSrc + y) * nSrcStep) + (nXSrc * 4)];
Packit 1fb8d4
		BYTE* pDstPixel = &pDstData[((nYDst + y) * nDstStep) + (nXDst * 4)];
Packit 1fb8d4
Packit 1fb8d4
		for (x = 0; x < nWidth; x++)
Packit 1fb8d4
		{
Packit 1fb8d4
			B = *pSrcPixel++;
Packit 1fb8d4
			G = *pSrcPixel++;
Packit 1fb8d4
			R = *pSrcPixel++;
Packit 1fb8d4
			A = *pSrcPixel++;
Packit 1fb8d4
Packit 1fb8d4
			if (A == 0xFF)
Packit 1fb8d4
			{
Packit 1fb8d4
				pDstPixel[0] = B;
Packit 1fb8d4
				pDstPixel[1] = G;
Packit 1fb8d4
				pDstPixel[2] = R;
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				pDstPixel[0] = B + (pDstPixel[0] * (0xFF - A) + (0xFF / 2)) / 0xFF;
Packit 1fb8d4
				pDstPixel[1] = G + (pDstPixel[1] * (0xFF - A) + (0xFF / 2)) / 0xFF;
Packit 1fb8d4
				pDstPixel[2] = R + (pDstPixel[2] * (0xFF - A) + (0xFF / 2)) / 0xFF;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			pDstPixel[3] = 0xFF;
Packit 1fb8d4
			pDstPixel += 4;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL x11_shadow_check_resize(x11ShadowSubsystem* subsystem)
Packit 1fb8d4
{
Packit 1fb8d4
	MONITOR_DEF* virtualScreen;
Packit 1fb8d4
	XWindowAttributes attr;
Packit 1fb8d4
	XLockDisplay(subsystem->display);
Packit 1fb8d4
	XGetWindowAttributes(subsystem->display, subsystem->root_window, &attr);
Packit 1fb8d4
	XUnlockDisplay(subsystem->display);
Packit 1fb8d4
Packit Service 5a9772
	if (attr.width != (INT64)subsystem->width || attr.height != (INT64)subsystem->height)
Packit 1fb8d4
	{
Packit 1fb8d4
		/* Screen size changed. Refresh monitor definitions and trigger screen resize */
Packit 1fb8d4
		subsystem->common.numMonitors = x11_shadow_enum_monitors(subsystem->common.monitors, 16);
Packit 1fb8d4
		shadow_screen_resize(subsystem->common.server->screen);
Packit 1fb8d4
		subsystem->width = attr.width;
Packit 1fb8d4
		subsystem->height = attr.height;
Packit 1fb8d4
		virtualScreen = &(subsystem->common.virtualScreen);
Packit 1fb8d4
		virtualScreen->left = 0;
Packit 1fb8d4
		virtualScreen->top = 0;
Packit 1fb8d4
		virtualScreen->right = subsystem->width;
Packit 1fb8d4
		virtualScreen->bottom = subsystem->height;
Packit 1fb8d4
		virtualScreen->flags = 1;
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static int x11_shadow_error_handler_for_capture(Display* display, XErrorEvent* event)
Packit 1fb8d4
{
Packit 1fb8d4
	char msg[256];
Packit Service 5a9772
	XGetErrorText(display, event->error_code, (char*)&msg, sizeof(msg));
Packit Service 5a9772
	WLog_ERR(TAG, "X11 error: %s Error code: %x, request code: %x, minor code: %x", msg,
Packit Service 5a9772
	         event->error_code, event->request_code, event->minor_code);
Packit 1fb8d4
Packit 1fb8d4
	/* Ignore BAD MATCH error during image capture. Abort in other case */
Packit 1fb8d4
	if (event->error_code != BadMatch)
Packit 1fb8d4
	{
Packit 1fb8d4
		abort();
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int x11_shadow_screen_grab(x11ShadowSubsystem* subsystem)
Packit 1fb8d4
{
Packit 1fb8d4
	int count;
Packit 1fb8d4
	int status;
Packit 1fb8d4
	int x, y;
Packit 1fb8d4
	int width, height;
Packit 1fb8d4
	XImage* image;
Packit 1fb8d4
	rdpShadowServer* server;
Packit 1fb8d4
	rdpShadowSurface* surface;
Packit 1fb8d4
	RECTANGLE_16 invalidRect;
Packit 1fb8d4
	RECTANGLE_16 surfaceRect;
Packit 1fb8d4
	const RECTANGLE_16* extents;
Packit 1fb8d4
	server = subsystem->common.server;
Packit 1fb8d4
	surface = server->surface;
Packit 1fb8d4
	count = ArrayList_Count(server->clients);
Packit 1fb8d4
Packit 1fb8d4
	if (count < 1)
Packit 1fb8d4
		return 1;
Packit 1fb8d4
Packit 1fb8d4
	surfaceRect.left = 0;
Packit 1fb8d4
	surfaceRect.top = 0;
Packit 1fb8d4
	surfaceRect.right = surface->width;
Packit 1fb8d4
	surfaceRect.bottom = surface->height;
Packit 1fb8d4
	XLockDisplay(subsystem->display);
Packit 1fb8d4
	/*
Packit 1fb8d4
	 * Ignore BadMatch error during image capture. The screen size may be
Packit 1fb8d4
	 * changed outside. We will resize to correct resolution at next frame
Packit 1fb8d4
	 */
Packit 1fb8d4
	XSetErrorHandler(x11_shadow_error_handler_for_capture);
Packit 1fb8d4
Packit 1fb8d4
	if (subsystem->use_xshm)
Packit 1fb8d4
	{
Packit 1fb8d4
		image = subsystem->fb_image;
Packit 1fb8d4
		XCopyArea(subsystem->display, subsystem->root_window, subsystem->fb_pixmap,
Packit 1fb8d4
		          subsystem->xshm_gc, 0, 0, subsystem->width, subsystem->height, 0, 0);
Packit Service 5a9772
		status = shadow_capture_compare(surface->data, surface->scanline, surface->width,
Packit Service 5a9772
		                                surface->height, (BYTE*)&(image->data[surface->width * 4]),
Packit Service 5a9772
		                                image->bytes_per_line, &invalidRect);
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit Service 5a9772
		image = XGetImage(subsystem->display, subsystem->root_window, surface->x, surface->y,
Packit Service 5a9772
		                  surface->width, surface->height, AllPlanes, ZPixmap);
Packit 1fb8d4
Packit 1fb8d4
		if (!image)
Packit 1fb8d4
		{
Packit 1fb8d4
			/*
Packit 1fb8d4
			 * BadMatch error happened. The size may have been changed again.
Packit 1fb8d4
			 * Give up this frame and we will resize again in next frame
Packit 1fb8d4
			 */
Packit 1fb8d4
			goto fail_capture;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit Service 5a9772
		status = shadow_capture_compare(surface->data, surface->scanline, surface->width,
Packit Service 5a9772
		                                surface->height, (BYTE*)image->data, image->bytes_per_line,
Packit Service 5a9772
		                                &invalidRect);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	/* Restore the default error handler */
Packit 1fb8d4
	XSetErrorHandler(NULL);
Packit 1fb8d4
	XSync(subsystem->display, False);
Packit 1fb8d4
	XUnlockDisplay(subsystem->display);
Packit 1fb8d4
Packit 1fb8d4
	if (status)
Packit 1fb8d4
	{
Packit Service 5a9772
		region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect);
Packit Service 5a9772
		region16_intersect_rect(&(surface->invalidRegion), &(surface->invalidRegion), &surfaceRect);
Packit 1fb8d4
Packit 1fb8d4
		if (!region16_is_empty(&(surface->invalidRegion)))
Packit 1fb8d4
		{
Packit 1fb8d4
			extents = region16_extents(&(surface->invalidRegion));
Packit 1fb8d4
			x = extents->left;
Packit 1fb8d4
			y = extents->top;
Packit 1fb8d4
			width = extents->right - extents->left;
Packit 1fb8d4
			height = extents->bottom - extents->top;
Packit 1fb8d4
Packit Service 5a9772
			if (!freerdp_image_copy(surface->data, surface->format, surface->scanline, x, y, width,
Packit Service 5a9772
			                        height, (BYTE*)image->data, PIXEL_FORMAT_BGRX32,
Packit 1fb8d4
			                        image->bytes_per_line, x, y, NULL, FREERDP_FLIP_NONE))
Packit 1fb8d4
				goto fail_capture;
Packit 1fb8d4
Packit Service 5a9772
			// x11_shadow_blend_cursor(subsystem);
Packit 1fb8d4
			count = ArrayList_Count(server->clients);
Packit 1fb8d4
			shadow_subsystem_frame_update((rdpShadowSubsystem*)subsystem);
Packit 1fb8d4
Packit 1fb8d4
			if (count == 1)
Packit 1fb8d4
			{
Packit 1fb8d4
				rdpShadowClient* client;
Packit Service 5a9772
				client = (rdpShadowClient*)ArrayList_GetItem(server->clients, 0);
Packit 1fb8d4
Packit 1fb8d4
				if (client)
Packit Service 5a9772
					subsystem->common.captureFrameRate =
Packit Service 5a9772
					    shadow_encoder_preferred_fps(client->encoder);
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			region16_clear(&(surface->invalidRegion));
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem->use_xshm)
Packit 1fb8d4
		XDestroyImage(image);
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
fail_capture:
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem->use_xshm && image)
Packit 1fb8d4
		XDestroyImage(image);
Packit 1fb8d4
Packit 1fb8d4
	XSetErrorHandler(NULL);
Packit 1fb8d4
	XSync(subsystem->display, False);
Packit 1fb8d4
	XUnlockDisplay(subsystem->display);
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static int x11_shadow_subsystem_process_message(x11ShadowSubsystem* subsystem, wMessage* message)
Packit 1fb8d4
{
Packit 1fb8d4
	switch (message->id)
Packit 1fb8d4
	{
Packit 1fb8d4
		case SHADOW_MSG_IN_REFRESH_REQUEST_ID:
Packit 1fb8d4
			shadow_subsystem_frame_update((rdpShadowSubsystem*)subsystem);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit Service 5a9772
			WLog_ERR(TAG, "Unknown message id: %" PRIu32 "", message->id);
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (message->Free)
Packit 1fb8d4
		message->Free(message);
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static DWORD WINAPI x11_shadow_subsystem_thread(LPVOID arg)
Packit 1fb8d4
{
Packit 1fb8d4
	x11ShadowSubsystem* subsystem = (x11ShadowSubsystem*)arg;
Packit 1fb8d4
	XEvent xevent;
Packit 1fb8d4
	DWORD status;
Packit 1fb8d4
	DWORD nCount;
Packit 1fb8d4
	UINT64 cTime;
Packit 1fb8d4
	DWORD dwTimeout;
Packit 1fb8d4
	DWORD dwInterval;
Packit 1fb8d4
	UINT64 frameTime;
Packit 1fb8d4
	HANDLE events[32];
Packit 1fb8d4
	wMessage message;
Packit 1fb8d4
	wMessagePipe* MsgPipe;
Packit 1fb8d4
	MsgPipe = subsystem->common.MsgPipe;
Packit 1fb8d4
	nCount = 0;
Packit 1fb8d4
	events[nCount++] = subsystem->common.event;
Packit 1fb8d4
	events[nCount++] = MessageQueue_Event(MsgPipe->In);
Packit 1fb8d4
	subsystem->common.captureFrameRate = 16;
Packit 1fb8d4
	dwInterval = 1000 / subsystem->common.captureFrameRate;
Packit 1fb8d4
	frameTime = GetTickCount64() + dwInterval;
Packit 1fb8d4
Packit 1fb8d4
	while (1)
Packit 1fb8d4
	{
Packit 1fb8d4
		cTime = GetTickCount64();
Packit 1fb8d4
		dwTimeout = (cTime > frameTime) ? 0 : frameTime - cTime;
Packit 1fb8d4
		status = WaitForMultipleObjects(nCount, events, FALSE, dwTimeout);
Packit 1fb8d4
Packit 1fb8d4
		if (WaitForSingleObject(MessageQueue_Event(MsgPipe->In), 0) == WAIT_OBJECT_0)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (MessageQueue_Peek(MsgPipe->In, &message, TRUE))
Packit 1fb8d4
			{
Packit 1fb8d4
				if (message.id == WMQ_QUIT)
Packit 1fb8d4
					break;
Packit 1fb8d4
Packit 1fb8d4
				x11_shadow_subsystem_process_message(subsystem, &message);
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (WaitForSingleObject(subsystem->common.event, 0) == WAIT_OBJECT_0)
Packit 1fb8d4
		{
Packit 1fb8d4
			XLockDisplay(subsystem->display);
Packit 1fb8d4
Packit 1fb8d4
			if (XEventsQueued(subsystem->display, QueuedAlready))
Packit 1fb8d4
			{
Packit 1fb8d4
				XNextEvent(subsystem->display, &xevent);
Packit 1fb8d4
				x11_shadow_handle_xevent(subsystem, &xevent);
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			XUnlockDisplay(subsystem->display);
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if ((status == WAIT_TIMEOUT) || (GetTickCount64() > frameTime))
Packit 1fb8d4
		{
Packit 1fb8d4
			x11_shadow_check_resize(subsystem);
Packit 1fb8d4
			x11_shadow_screen_grab(subsystem);
Packit 1fb8d4
			x11_shadow_query_cursor(subsystem, FALSE);
Packit 1fb8d4
			dwInterval = 1000 / subsystem->common.captureFrameRate;
Packit 1fb8d4
			frameTime += dwInterval;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ExitThread(0);
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int x11_shadow_subsystem_base_init(x11ShadowSubsystem* subsystem)
Packit 1fb8d4
{
Packit 1fb8d4
	if (subsystem->display)
Packit 1fb8d4
		return 1; /* initialize once */
Packit 1fb8d4
Packit 1fb8d4
	if (!getenv("DISPLAY"))
Packit 1fb8d4
		setenv("DISPLAY", ":0", 1);
Packit 1fb8d4
Packit 1fb8d4
	if (!XInitThreads())
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	subsystem->display = XOpenDisplay(NULL);
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem->display)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "failed to open display: %s", XDisplayName(NULL));
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	subsystem->xfds = ConnectionNumber(subsystem->display);
Packit 1fb8d4
	subsystem->number = DefaultScreen(subsystem->display);
Packit 1fb8d4
	subsystem->screen = ScreenOfDisplay(subsystem->display, subsystem->number);
Packit 1fb8d4
	subsystem->depth = DefaultDepthOfScreen(subsystem->screen);
Packit 1fb8d4
	subsystem->width = WidthOfScreen(subsystem->screen);
Packit 1fb8d4
	subsystem->height = HeightOfScreen(subsystem->screen);
Packit 1fb8d4
	subsystem->root_window = RootWindow(subsystem->display, subsystem->number);
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int x11_shadow_xfixes_init(x11ShadowSubsystem* subsystem)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef WITH_XFIXES
Packit 1fb8d4
	int xfixes_event;
Packit 1fb8d4
	int xfixes_error;
Packit 1fb8d4
	int major, minor;
Packit 1fb8d4
Packit 1fb8d4
	if (!XFixesQueryExtension(subsystem->display, &xfixes_event, &xfixes_error))
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (!XFixesQueryVersion(subsystem->display, &major, &minor))
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	subsystem->xfixes_cursor_notify_event = xfixes_event + XFixesCursorNotify;
Packit 1fb8d4
	XFixesSelectCursorInput(subsystem->display, subsystem->root_window,
Packit 1fb8d4
	                        XFixesDisplayCursorNotifyMask);
Packit 1fb8d4
	return 1;
Packit 1fb8d4
#else
Packit 1fb8d4
	return -1;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int x11_shadow_xinerama_init(x11ShadowSubsystem* subsystem)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef WITH_XINERAMA
Packit 1fb8d4
	int major, minor;
Packit 1fb8d4
	int xinerama_event;
Packit 1fb8d4
	int xinerama_error;
Packit 1fb8d4
	x11_shadow_subsystem_base_init(subsystem);
Packit 1fb8d4
Packit Service 5a9772
	if (!XineramaQueryExtension(subsystem->display, &xinerama_event, &xinerama_error))
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (!XDamageQueryVersion(subsystem->display, &major, &minor))
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (!XineramaIsActive(subsystem->display))
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
#else
Packit 1fb8d4
	return -1;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int x11_shadow_xdamage_init(x11ShadowSubsystem* subsystem)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef WITH_XDAMAGE
Packit 1fb8d4
	int major, minor;
Packit 1fb8d4
	int damage_event;
Packit 1fb8d4
	int damage_error;
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem->use_xfixes)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (!XDamageQueryExtension(subsystem->display, &damage_event, &damage_error))
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (!XDamageQueryVersion(subsystem->display, &major, &minor))
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (major < 1)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	subsystem->xdamage_notify_event = damage_event + XDamageNotify;
Packit Service 5a9772
	subsystem->xdamage =
Packit Service 5a9772
	    XDamageCreate(subsystem->display, subsystem->root_window, XDamageReportDeltaRectangles);
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem->xdamage)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
#ifdef WITH_XFIXES
Packit 1fb8d4
	subsystem->xdamage_region = XFixesCreateRegion(subsystem->display, NULL, 0);
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem->xdamage_region)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
	return 1;
Packit 1fb8d4
#else
Packit 1fb8d4
	return -1;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int x11_shadow_xshm_init(x11ShadowSubsystem* subsystem)
Packit 1fb8d4
{
Packit 1fb8d4
	Bool pixmaps;
Packit 1fb8d4
	int major, minor;
Packit 1fb8d4
	XGCValues values;
Packit 1fb8d4
Packit 1fb8d4
	if (!XShmQueryExtension(subsystem->display))
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (!XShmQueryVersion(subsystem->display, &major, &minor, &pixmaps))
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (!pixmaps)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	subsystem->fb_shm_info.shmid = -1;
Packit Service 5a9772
	subsystem->fb_shm_info.shmaddr = (char*)-1;
Packit 1fb8d4
	subsystem->fb_shm_info.readOnly = False;
Packit Service 5a9772
	subsystem->fb_image =
Packit Service 5a9772
	    XShmCreateImage(subsystem->display, subsystem->visual, subsystem->depth, ZPixmap, NULL,
Packit Service 5a9772
	                    &(subsystem->fb_shm_info), subsystem->width, subsystem->height);
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem->fb_image)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "XShmCreateImage failed");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	subsystem->fb_shm_info.shmid =
Packit Service 5a9772
	    shmget(IPC_PRIVATE, subsystem->fb_image->bytes_per_line * subsystem->fb_image->height,
Packit Service 5a9772
	           IPC_CREAT | 0600);
Packit 1fb8d4
Packit 1fb8d4
	if (subsystem->fb_shm_info.shmid == -1)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "shmget failed");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	subsystem->fb_shm_info.shmaddr = shmat(subsystem->fb_shm_info.shmid, 0, 0);
Packit 1fb8d4
	subsystem->fb_image->data = subsystem->fb_shm_info.shmaddr;
Packit 1fb8d4
Packit Service 5a9772
	if (subsystem->fb_shm_info.shmaddr == ((char*)-1))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "shmat failed");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!XShmAttach(subsystem->display, &(subsystem->fb_shm_info)))
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	XSync(subsystem->display, False);
Packit 1fb8d4
	shmctl(subsystem->fb_shm_info.shmid, IPC_RMID, 0);
Packit Service 5a9772
	subsystem->fb_pixmap =
Packit Service 5a9772
	    XShmCreatePixmap(subsystem->display, subsystem->root_window, subsystem->fb_image->data,
Packit Service 5a9772
	                     &(subsystem->fb_shm_info), subsystem->fb_image->width,
Packit Service 5a9772
	                     subsystem->fb_image->height, subsystem->fb_image->depth);
Packit 1fb8d4
	XSync(subsystem->display, False);
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem->fb_pixmap)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	values.subwindow_mode = IncludeInferiors;
Packit 1fb8d4
	values.graphics_exposures = False;
Packit 1fb8d4
	subsystem->xshm_gc = XCreateGC(subsystem->display, subsystem->root_window,
Packit 1fb8d4
	                               GCSubwindowMode | GCGraphicsExposures, &values);
Packit 1fb8d4
	XSetFunction(subsystem->display, subsystem->xshm_gc, GXcopy);
Packit 1fb8d4
	XSync(subsystem->display, False);
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
UINT32 x11_shadow_enum_monitors(MONITOR_DEF* monitors, UINT32 maxMonitors)
Packit 1fb8d4
{
Packit 1fb8d4
	int index;
Packit 1fb8d4
	Display* display;
Packit 1fb8d4
	int displayWidth;
Packit 1fb8d4
	int displayHeight;
Packit 1fb8d4
	int numMonitors = 0;
Packit 1fb8d4
	MONITOR_DEF* monitor;
Packit 1fb8d4
Packit 1fb8d4
	if (!getenv("DISPLAY"))
Packit 1fb8d4
		setenv("DISPLAY", ":0", 1);
Packit 1fb8d4
Packit 1fb8d4
	display = XOpenDisplay(NULL);
Packit 1fb8d4
Packit 1fb8d4
	if (!display)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "failed to open display: %s", XDisplayName(NULL));
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	displayWidth = WidthOfScreen(DefaultScreenOfDisplay(display));
Packit 1fb8d4
	displayHeight = HeightOfScreen(DefaultScreenOfDisplay(display));
Packit 1fb8d4
#ifdef WITH_XINERAMA
Packit 1fb8d4
	{
Packit 1fb8d4
		int major, minor;
Packit 1fb8d4
		int xinerama_event;
Packit 1fb8d4
		int xinerama_error;
Packit 1fb8d4
		XineramaScreenInfo* screen;
Packit 1fb8d4
		XineramaScreenInfo* screens;
Packit 1fb8d4
Packit 1fb8d4
		if (XineramaQueryExtension(display, &xinerama_event, &xinerama_error) &&
Packit 1fb8d4
		    XDamageQueryVersion(display, &major, &minor) && XineramaIsActive(display))
Packit 1fb8d4
		{
Packit 1fb8d4
			screens = XineramaQueryScreens(display, &numMonitors);
Packit 1fb8d4
Packit Service 5a9772
			if (numMonitors > (INT64)maxMonitors)
Packit Service 5a9772
				numMonitors = (int)maxMonitors;
Packit 1fb8d4
Packit 1fb8d4
			if (screens && (numMonitors > 0))
Packit 1fb8d4
			{
Packit 1fb8d4
				for (index = 0; index < numMonitors; index++)
Packit 1fb8d4
				{
Packit 1fb8d4
					screen = &screens[index];
Packit 1fb8d4
					monitor = &monitors[index];
Packit 1fb8d4
					monitor->left = screen->x_org;
Packit 1fb8d4
					monitor->top = screen->y_org;
Packit 1fb8d4
					monitor->right = monitor->left + screen->width;
Packit 1fb8d4
					monitor->bottom = monitor->top + screen->height;
Packit 1fb8d4
					monitor->flags = (index == 0) ? 1 : 0;
Packit 1fb8d4
				}
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			XFree(screens);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
#endif
Packit 1fb8d4
	XCloseDisplay(display);
Packit 1fb8d4
Packit 1fb8d4
	if (numMonitors < 1)
Packit 1fb8d4
	{
Packit 1fb8d4
		index = 0;
Packit 1fb8d4
		numMonitors = 1;
Packit 1fb8d4
		monitor = &monitors[index];
Packit 1fb8d4
		monitor->left = 0;
Packit 1fb8d4
		monitor->top = 0;
Packit 1fb8d4
		monitor->right = displayWidth;
Packit 1fb8d4
		monitor->bottom = displayHeight;
Packit 1fb8d4
		monitor->flags = 1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	errno = 0;
Packit 1fb8d4
	return numMonitors;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int x11_shadow_subsystem_init(rdpShadowSubsystem* sub)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
	int pf_count;
Packit 1fb8d4
	int vi_count;
Packit 1fb8d4
	int nextensions;
Packit 1fb8d4
	char** extensions;
Packit 1fb8d4
	XVisualInfo* vi;
Packit 1fb8d4
	XVisualInfo* vis;
Packit 1fb8d4
	XVisualInfo template;
Packit 1fb8d4
	XPixmapFormatValues* pf;
Packit 1fb8d4
	XPixmapFormatValues* pfs;
Packit 1fb8d4
	MONITOR_DEF* virtualScreen;
Packit 1fb8d4
	x11ShadowSubsystem* subsystem = (x11ShadowSubsystem*)sub;
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	subsystem->common.numMonitors = x11_shadow_enum_monitors(subsystem->common.monitors, 16);
Packit 1fb8d4
	x11_shadow_subsystem_base_init(subsystem);
Packit 1fb8d4
Packit 1fb8d4
	if ((subsystem->depth != 24) && (subsystem->depth != 32))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "unsupported X11 server color depth: %d", subsystem->depth);
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	extensions = XListExtensions(subsystem->display, &nextensions);
Packit 1fb8d4
Packit 1fb8d4
	if (!extensions || (nextensions < 0))
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < nextensions; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (strcmp(extensions[i], "Composite") == 0)
Packit 1fb8d4
			subsystem->composite = TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	XFreeExtensionList(extensions);
Packit 1fb8d4
Packit 1fb8d4
	if (subsystem->composite)
Packit 1fb8d4
		subsystem->use_xdamage = FALSE;
Packit 1fb8d4
Packit 1fb8d4
	pfs = XListPixmapFormats(subsystem->display, &pf_count);
Packit 1fb8d4
Packit 1fb8d4
	if (!pfs)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "XListPixmapFormats failed");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < pf_count; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		pf = pfs + i;
Packit 1fb8d4
Packit Service 5a9772
		if (pf->depth == (INT64)subsystem->depth)
Packit 1fb8d4
		{
Packit 1fb8d4
			subsystem->bpp = pf->bits_per_pixel;
Packit 1fb8d4
			subsystem->scanline_pad = pf->scanline_pad;
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	XFree(pfs);
Packit 1fb8d4
	ZeroMemory(&template, sizeof(template));
Packit 1fb8d4
	template.class = TrueColor;
Packit 1fb8d4
	template.screen = subsystem->number;
Packit Service 5a9772
	vis = XGetVisualInfo(subsystem->display, VisualClassMask | VisualScreenMask, &template,
Packit Service 5a9772
	                     &vi_count);
Packit 1fb8d4
Packit 1fb8d4
	if (!vis)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "XGetVisualInfo failed");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < vi_count; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		vi = vis + i;
Packit 1fb8d4
Packit Service 5a9772
		if (vi->depth == (INT64)subsystem->depth)
Packit 1fb8d4
		{
Packit 1fb8d4
			subsystem->visual = vi->visual;
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	XFree(vis);
Packit Service 5a9772
	XSelectInput(subsystem->display, subsystem->root_window, SubstructureNotifyMask);
Packit 1fb8d4
	subsystem->cursorMaxWidth = 256;
Packit 1fb8d4
	subsystem->cursorMaxHeight = 256;
Packit Service 5a9772
	subsystem->cursorPixels =
Packit Service 5a9772
	    _aligned_malloc(subsystem->cursorMaxWidth * subsystem->cursorMaxHeight * 4, 16);
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem->cursorPixels)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	x11_shadow_query_cursor(subsystem, TRUE);
Packit 1fb8d4
Packit 1fb8d4
	if (subsystem->use_xfixes)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (x11_shadow_xfixes_init(subsystem) < 0)
Packit 1fb8d4
			subsystem->use_xfixes = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (subsystem->use_xinerama)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (x11_shadow_xinerama_init(subsystem) < 0)
Packit 1fb8d4
			subsystem->use_xinerama = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (subsystem->use_xshm)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (x11_shadow_xshm_init(subsystem) < 0)
Packit 1fb8d4
			subsystem->use_xshm = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (subsystem->use_xdamage)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (x11_shadow_xdamage_init(subsystem) < 0)
Packit 1fb8d4
			subsystem->use_xdamage = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	if (!(subsystem->common.event =
Packit Service 5a9772
	          CreateFileDescriptorEvent(NULL, FALSE, FALSE, subsystem->xfds, WINPR_FD_READ)))
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	virtualScreen = &(subsystem->common.virtualScreen);
Packit 1fb8d4
	virtualScreen->left = 0;
Packit 1fb8d4
	virtualScreen->top = 0;
Packit 1fb8d4
	virtualScreen->right = subsystem->width;
Packit 1fb8d4
	virtualScreen->bottom = subsystem->height;
Packit 1fb8d4
	virtualScreen->flags = 1;
Packit 1fb8d4
	WLog_INFO(TAG,
Packit Service 5a9772
	          "X11 Extensions: XFixes: %" PRId32 " Xinerama: %" PRId32 " XDamage: %" PRId32
Packit Service 5a9772
	          " XShm: %" PRId32 "",
Packit 1fb8d4
	          subsystem->use_xfixes, subsystem->use_xinerama, subsystem->use_xdamage,
Packit 1fb8d4
	          subsystem->use_xshm);
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int x11_shadow_subsystem_uninit(rdpShadowSubsystem* sub)
Packit 1fb8d4
{
Packit 1fb8d4
	x11ShadowSubsystem* subsystem = (x11ShadowSubsystem*)sub;
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (subsystem->display)
Packit 1fb8d4
	{
Packit 1fb8d4
		XCloseDisplay(subsystem->display);
Packit 1fb8d4
		subsystem->display = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (subsystem->common.event)
Packit 1fb8d4
	{
Packit 1fb8d4
		CloseHandle(subsystem->common.event);
Packit 1fb8d4
		subsystem->common.event = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (subsystem->cursorPixels)
Packit 1fb8d4
	{
Packit 1fb8d4
		_aligned_free(subsystem->cursorPixels);
Packit 1fb8d4
		subsystem->cursorPixels = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int x11_shadow_subsystem_start(rdpShadowSubsystem* sub)
Packit 1fb8d4
{
Packit 1fb8d4
	x11ShadowSubsystem* subsystem = (x11ShadowSubsystem*)sub;
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit Service 5a9772
	if (!(subsystem->thread =
Packit Service 5a9772
	          CreateThread(NULL, 0, x11_shadow_subsystem_thread, (void*)subsystem, 0, NULL)))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Failed to create thread");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int x11_shadow_subsystem_stop(rdpShadowSubsystem* sub)
Packit 1fb8d4
{
Packit 1fb8d4
	x11ShadowSubsystem* subsystem = (x11ShadowSubsystem*)sub;
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (subsystem->thread)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (MessageQueue_PostQuit(subsystem->common.MsgPipe->In, 0))
Packit 1fb8d4
			WaitForSingleObject(subsystem->thread, INFINITE);
Packit 1fb8d4
Packit 1fb8d4
		CloseHandle(subsystem->thread);
Packit 1fb8d4
		subsystem->thread = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static rdpShadowSubsystem* x11_shadow_subsystem_new(void)
Packit 1fb8d4
{
Packit 1fb8d4
	x11ShadowSubsystem* subsystem;
Packit Service 5a9772
	subsystem = (x11ShadowSubsystem*)calloc(1, sizeof(x11ShadowSubsystem));
Packit 1fb8d4
Packit 1fb8d4
	if (!subsystem)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
#ifdef WITH_PAM
Packit 1fb8d4
	subsystem->common.Authenticate = x11_shadow_pam_authenticate;
Packit 1fb8d4
#endif
Packit 1fb8d4
	subsystem->common.SynchronizeEvent = x11_shadow_input_synchronize_event;
Packit 1fb8d4
	subsystem->common.KeyboardEvent = x11_shadow_input_keyboard_event;
Packit 1fb8d4
	subsystem->common.UnicodeKeyboardEvent = x11_shadow_input_unicode_keyboard_event;
Packit 1fb8d4
	subsystem->common.MouseEvent = x11_shadow_input_mouse_event;
Packit 1fb8d4
	subsystem->common.ExtendedMouseEvent = x11_shadow_input_extended_mouse_event;
Packit 1fb8d4
	subsystem->composite = FALSE;
Packit 1fb8d4
	subsystem->use_xshm = FALSE; /* temporarily disabled */
Packit 1fb8d4
	subsystem->use_xfixes = TRUE;
Packit 1fb8d4
	subsystem->use_xdamage = FALSE;
Packit 1fb8d4
	subsystem->use_xinerama = TRUE;
Packit 1fb8d4
	return (rdpShadowSubsystem*)subsystem;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void x11_shadow_subsystem_free(rdpShadowSubsystem* subsystem)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!subsystem)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	x11_shadow_subsystem_uninit(subsystem);
Packit 1fb8d4
	free(subsystem);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
FREERDP_API int X11_ShadowSubsystemEntry(RDP_SHADOW_ENTRY_POINTS* pEntryPoints)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!pEntryPoints)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	pEntryPoints->New = x11_shadow_subsystem_new;
Packit 1fb8d4
	pEntryPoints->Free = x11_shadow_subsystem_free;
Packit 1fb8d4
	pEntryPoints->Init = x11_shadow_subsystem_init;
Packit 1fb8d4
	pEntryPoints->Uninit = x11_shadow_subsystem_uninit;
Packit 1fb8d4
	pEntryPoints->Start = x11_shadow_subsystem_start;
Packit 1fb8d4
	pEntryPoints->Stop = x11_shadow_subsystem_stop;
Packit 1fb8d4
	pEntryPoints->EnumMonitors = x11_shadow_enum_monitors;
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}