Blame client/Wayland/wlf_disp.c

Packit Service 5a9772
/**
Packit Service 5a9772
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service 5a9772
 * Wayland Display Control Channel
Packit Service 5a9772
 *
Packit Service 5a9772
 * Copyright 2018 Armin Novak <armin.novak@thincast.com>
Packit Service 5a9772
 * Copyright 2018 Thincast Technologies GmbH
Packit Service 5a9772
 *
Packit Service 5a9772
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service 5a9772
 * you may not use this file except in compliance with the License.
Packit Service 5a9772
 * You may obtain a copy of the License at
Packit Service 5a9772
 *
Packit Service 5a9772
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service 5a9772
 *
Packit Service 5a9772
 * Unless required by applicable law or agreed to in writing, software
Packit Service 5a9772
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service 5a9772
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service 5a9772
 * See the License for the specific language governing permissions and
Packit Service 5a9772
 * limitations under the License.
Packit Service 5a9772
 */
Packit Service 5a9772
Packit Service 5a9772
#include <winpr/sysinfo.h>
Packit Service 5a9772
Packit Service 5a9772
#include "wlf_disp.h"
Packit Service 5a9772
Packit Service 5a9772
#define TAG CLIENT_TAG("wayland.disp")
Packit Service 5a9772
Packit Service 5a9772
#define RESIZE_MIN_DELAY 200 /* minimum delay in ms between two resizes */
Packit Service 5a9772
Packit Service 5a9772
struct _wlfDispContext
Packit Service 5a9772
{
Packit Service 5a9772
	wlfContext* wlc;
Packit Service 5a9772
	DispClientContext* disp;
Packit Service 5a9772
	BOOL haveXRandr;
Packit Service 5a9772
	int eventBase, errorBase;
Packit Service 5a9772
	int lastSentWidth, lastSentHeight;
Packit Service 5a9772
	UINT64 lastSentDate;
Packit Service 5a9772
	int targetWidth, targetHeight;
Packit Service 5a9772
	BOOL activated;
Packit Service 5a9772
	BOOL waitingResize;
Packit Service 5a9772
	BOOL fullscreen;
Packit Service 5a9772
	UINT16 lastSentDesktopOrientation;
Packit Service 5a9772
	UINT32 lastSentDesktopScaleFactor;
Packit Service 5a9772
	UINT32 lastSentDeviceScaleFactor;
Packit Service 5a9772
};
Packit Service 5a9772
Packit Service 5a9772
static UINT wlf_disp_sendLayout(DispClientContext* disp, rdpMonitor* monitors, size_t nmonitors);
Packit Service 5a9772
Packit Service 5a9772
static BOOL wlf_disp_settings_changed(wlfDispContext* wlfDisp)
Packit Service 5a9772
{
Packit Service 5a9772
	rdpSettings* settings = wlfDisp->wlc->context.settings;
Packit Service 5a9772
Packit Service 5a9772
	if (wlfDisp->lastSentWidth != wlfDisp->targetWidth)
Packit Service 5a9772
		return TRUE;
Packit Service 5a9772
Packit Service 5a9772
	if (wlfDisp->lastSentHeight != wlfDisp->targetHeight)
Packit Service 5a9772
		return TRUE;
Packit Service 5a9772
Packit Service 5a9772
	if (wlfDisp->lastSentDesktopOrientation != settings->DesktopOrientation)
Packit Service 5a9772
		return TRUE;
Packit Service 5a9772
Packit Service 5a9772
	if (wlfDisp->lastSentDesktopScaleFactor != settings->DesktopScaleFactor)
Packit Service 5a9772
		return TRUE;
Packit Service 5a9772
Packit Service 5a9772
	if (wlfDisp->lastSentDeviceScaleFactor != settings->DeviceScaleFactor)
Packit Service 5a9772
		return TRUE;
Packit Service 5a9772
Packit Service 5a9772
	if (wlfDisp->fullscreen != wlfDisp->wlc->fullscreen)
Packit Service 5a9772
		return TRUE;
Packit Service 5a9772
Packit Service 5a9772
	return FALSE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static BOOL wlf_update_last_sent(wlfDispContext* wlfDisp)
Packit Service 5a9772
{
Packit Service 5a9772
	rdpSettings* settings = wlfDisp->wlc->context.settings;
Packit Service 5a9772
	wlfDisp->lastSentWidth = wlfDisp->targetWidth;
Packit Service 5a9772
	wlfDisp->lastSentHeight = wlfDisp->targetHeight;
Packit Service 5a9772
	wlfDisp->lastSentDesktopOrientation = settings->DesktopOrientation;
Packit Service 5a9772
	wlfDisp->lastSentDesktopScaleFactor = settings->DesktopScaleFactor;
Packit Service 5a9772
	wlfDisp->lastSentDeviceScaleFactor = settings->DeviceScaleFactor;
Packit Service 5a9772
	wlfDisp->fullscreen = wlfDisp->wlc->fullscreen;
Packit Service 5a9772
	return TRUE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static BOOL wlf_disp_sendResize(wlfDispContext* wlfDisp)
Packit Service 5a9772
{
Packit Service 5a9772
	DISPLAY_CONTROL_MONITOR_LAYOUT layout;
Packit Service 5a9772
	wlfContext* wlc;
Packit Service 5a9772
	rdpSettings* settings;
Packit Service 5a9772
Packit Service 5a9772
	if (!wlfDisp || !wlfDisp->wlc)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	wlc = wlfDisp->wlc;
Packit Service 5a9772
	settings = wlc->context.settings;
Packit Service 5a9772
Packit Service 5a9772
	if (!settings)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	if (!wlfDisp->activated || !wlfDisp->disp)
Packit Service 5a9772
		return TRUE;
Packit Service 5a9772
Packit Service 5a9772
	if (GetTickCount64() - wlfDisp->lastSentDate < RESIZE_MIN_DELAY)
Packit Service 5a9772
		return TRUE;
Packit Service 5a9772
Packit Service 5a9772
	wlfDisp->lastSentDate = GetTickCount64();
Packit Service 5a9772
Packit Service 5a9772
	if (!wlf_disp_settings_changed(wlfDisp))
Packit Service 5a9772
		return TRUE;
Packit Service 5a9772
Packit Service 5a9772
	/* TODO: Multimonitor support for wayland
Packit Service 5a9772
	if (wlc->fullscreen && (settings->MonitorCount > 0))
Packit Service 5a9772
	{
Packit Service 5a9772
	    if (wlf_disp_sendLayout(wlfDisp->disp, settings->MonitorDefArray,
Packit Service 5a9772
	                           settings->MonitorCount) != CHANNEL_RC_OK)
Packit Service 5a9772
	        return FALSE;
Packit Service 5a9772
	}
Packit Service 5a9772
	else
Packit Service 5a9772
	*/
Packit Service 5a9772
	{
Packit Service 5a9772
		wlfDisp->waitingResize = TRUE;
Packit Service 5a9772
		layout.Flags = DISPLAY_CONTROL_MONITOR_PRIMARY;
Packit Service 5a9772
		layout.Top = layout.Left = 0;
Packit Service 5a9772
		layout.Width = wlfDisp->targetWidth;
Packit Service 5a9772
		layout.Height = wlfDisp->targetHeight;
Packit Service 5a9772
		layout.Orientation = settings->DesktopOrientation;
Packit Service 5a9772
		layout.DesktopScaleFactor = settings->DesktopScaleFactor;
Packit Service 5a9772
		layout.DeviceScaleFactor = settings->DeviceScaleFactor;
Packit Service 5a9772
		layout.PhysicalWidth = wlfDisp->targetWidth;
Packit Service 5a9772
		layout.PhysicalHeight = wlfDisp->targetHeight;
Packit Service 5a9772
Packit Service 5a9772
		if (IFCALLRESULT(CHANNEL_RC_OK, wlfDisp->disp->SendMonitorLayout, wlfDisp->disp, 1,
Packit Service 5a9772
		                 &layout) != CHANNEL_RC_OK)
Packit Service 5a9772
			return FALSE;
Packit Service 5a9772
	}
Packit Service 5a9772
	return wlf_update_last_sent(wlfDisp);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static BOOL wlf_disp_set_window_resizable(wlfDispContext* wlfDisp)
Packit Service 5a9772
{
Packit Service 5a9772
#if 0 // TODO
Packit Service 5a9772
#endif
Packit Service 5a9772
	return TRUE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static BOOL wlf_disp_check_context(void* context, wlfContext** ppwlc, wlfDispContext** ppwlfDisp,
Packit Service 5a9772
                                   rdpSettings** ppSettings)
Packit Service 5a9772
{
Packit Service 5a9772
	wlfContext* wlc;
Packit Service 5a9772
Packit Service 5a9772
	if (!context)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	wlc = (wlfContext*)context;
Packit Service 5a9772
Packit Service 5a9772
	if (!(wlc->disp))
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	if (!wlc->context.settings)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	*ppwlc = wlc;
Packit Service 5a9772
	*ppwlfDisp = wlc->disp;
Packit Service 5a9772
	*ppSettings = wlc->context.settings;
Packit Service 5a9772
	return TRUE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static void wlf_disp_OnActivated(void* context, ActivatedEventArgs* e)
Packit Service 5a9772
{
Packit Service 5a9772
	wlfContext* wlc;
Packit Service 5a9772
	wlfDispContext* wlfDisp;
Packit Service 5a9772
	rdpSettings* settings;
Packit Service 5a9772
Packit Service 5a9772
	if (!wlf_disp_check_context(context, &wlc, &wlfDisp, &settings))
Packit Service 5a9772
		return;
Packit Service 5a9772
Packit Service 5a9772
	wlfDisp->waitingResize = FALSE;
Packit Service 5a9772
Packit Service 5a9772
	if (wlfDisp->activated && !settings->Fullscreen)
Packit Service 5a9772
	{
Packit Service 5a9772
		wlf_disp_set_window_resizable(wlfDisp);
Packit Service 5a9772
Packit Service 5a9772
		if (e->firstActivation)
Packit Service 5a9772
			return;
Packit Service 5a9772
Packit Service 5a9772
		wlf_disp_sendResize(wlfDisp);
Packit Service 5a9772
	}
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static void wlf_disp_OnGraphicsReset(void* context, GraphicsResetEventArgs* e)
Packit Service 5a9772
{
Packit Service 5a9772
	wlfContext* wlc;
Packit Service 5a9772
	wlfDispContext* wlfDisp;
Packit Service 5a9772
	rdpSettings* settings;
Packit Service 5a9772
Packit Service 5a9772
	WINPR_UNUSED(e);
Packit Service 5a9772
	if (!wlf_disp_check_context(context, &wlc, &wlfDisp, &settings))
Packit Service 5a9772
		return;
Packit Service 5a9772
Packit Service 5a9772
	wlfDisp->waitingResize = FALSE;
Packit Service 5a9772
Packit Service 5a9772
	if (wlfDisp->activated && !settings->Fullscreen)
Packit Service 5a9772
	{
Packit Service 5a9772
		wlf_disp_set_window_resizable(wlfDisp);
Packit Service 5a9772
		wlf_disp_sendResize(wlfDisp);
Packit Service 5a9772
	}
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static void wlf_disp_OnTimer(void* context, TimerEventArgs* e)
Packit Service 5a9772
{
Packit Service 5a9772
	wlfContext* wlc;
Packit Service 5a9772
	wlfDispContext* wlfDisp;
Packit Service 5a9772
	rdpSettings* settings;
Packit Service 5a9772
Packit Service 5a9772
	WINPR_UNUSED(e);
Packit Service 5a9772
	if (!wlf_disp_check_context(context, &wlc, &wlfDisp, &settings))
Packit Service 5a9772
		return;
Packit Service 5a9772
Packit Service 5a9772
	if (!wlfDisp->activated || settings->Fullscreen)
Packit Service 5a9772
		return;
Packit Service 5a9772
Packit Service 5a9772
	wlf_disp_sendResize(wlfDisp);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
wlfDispContext* wlf_disp_new(wlfContext* wlc)
Packit Service 5a9772
{
Packit Service 5a9772
	wlfDispContext* ret;
Packit Service 5a9772
Packit Service 5a9772
	if (!wlc || !wlc->context.settings || !wlc->context.pubSub)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit Service 5a9772
	ret = calloc(1, sizeof(wlfDispContext));
Packit Service 5a9772
Packit Service 5a9772
	if (!ret)
Packit Service 5a9772
		return NULL;
Packit Service 5a9772
Packit Service 5a9772
	ret->wlc = wlc;
Packit Service 5a9772
	ret->lastSentWidth = ret->targetWidth = wlc->context.settings->DesktopWidth;
Packit Service 5a9772
	ret->lastSentHeight = ret->targetHeight = wlc->context.settings->DesktopHeight;
Packit Service 5a9772
	PubSub_SubscribeActivated(wlc->context.pubSub, wlf_disp_OnActivated);
Packit Service 5a9772
	PubSub_SubscribeGraphicsReset(wlc->context.pubSub, wlf_disp_OnGraphicsReset);
Packit Service 5a9772
	PubSub_SubscribeTimer(wlc->context.pubSub, wlf_disp_OnTimer);
Packit Service 5a9772
	return ret;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
void wlf_disp_free(wlfDispContext* disp)
Packit Service 5a9772
{
Packit Service 5a9772
	if (!disp)
Packit Service 5a9772
		return;
Packit Service 5a9772
Packit Service 5a9772
	if (disp->wlc)
Packit Service 5a9772
	{
Packit Service 5a9772
		PubSub_UnsubscribeActivated(disp->wlc->context.pubSub, wlf_disp_OnActivated);
Packit Service 5a9772
		PubSub_UnsubscribeGraphicsReset(disp->wlc->context.pubSub, wlf_disp_OnGraphicsReset);
Packit Service 5a9772
		PubSub_UnsubscribeTimer(disp->wlc->context.pubSub, wlf_disp_OnTimer);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	free(disp);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
UINT wlf_disp_sendLayout(DispClientContext* disp, rdpMonitor* monitors, size_t nmonitors)
Packit Service 5a9772
{
Packit Service 5a9772
	UINT ret = CHANNEL_RC_OK;
Packit Service 5a9772
	DISPLAY_CONTROL_MONITOR_LAYOUT* layouts;
Packit Service 5a9772
	size_t i;
Packit Service 5a9772
	wlfDispContext* wlfDisp = (wlfDispContext*)disp->custom;
Packit Service 5a9772
	rdpSettings* settings = wlfDisp->wlc->context.settings;
Packit Service 5a9772
	layouts = calloc(nmonitors, sizeof(DISPLAY_CONTROL_MONITOR_LAYOUT));
Packit Service 5a9772
Packit Service 5a9772
	if (!layouts)
Packit Service 5a9772
		return CHANNEL_RC_NO_MEMORY;
Packit Service 5a9772
Packit Service 5a9772
	for (i = 0; i < nmonitors; i++)
Packit Service 5a9772
	{
Packit Service 5a9772
		layouts[i].Flags = (monitors[i].is_primary ? DISPLAY_CONTROL_MONITOR_PRIMARY : 0);
Packit Service 5a9772
		layouts[i].Left = monitors[i].x;
Packit Service 5a9772
		layouts[i].Top = monitors[i].y;
Packit Service 5a9772
		layouts[i].Width = monitors[i].width;
Packit Service 5a9772
		layouts[i].Height = monitors[i].height;
Packit Service 5a9772
		layouts[i].Orientation = ORIENTATION_LANDSCAPE;
Packit Service 5a9772
		layouts[i].PhysicalWidth = monitors[i].attributes.physicalWidth;
Packit Service 5a9772
		layouts[i].PhysicalHeight = monitors[i].attributes.physicalHeight;
Packit Service 5a9772
Packit Service 5a9772
		switch (monitors[i].attributes.orientation)
Packit Service 5a9772
		{
Packit Service 5a9772
			case 90:
Packit Service 5a9772
				layouts[i].Orientation = ORIENTATION_PORTRAIT;
Packit Service 5a9772
				break;
Packit Service 5a9772
Packit Service 5a9772
			case 180:
Packit Service 5a9772
				layouts[i].Orientation = ORIENTATION_LANDSCAPE_FLIPPED;
Packit Service 5a9772
				break;
Packit Service 5a9772
Packit Service 5a9772
			case 270:
Packit Service 5a9772
				layouts[i].Orientation = ORIENTATION_PORTRAIT_FLIPPED;
Packit Service 5a9772
				break;
Packit Service 5a9772
Packit Service 5a9772
			case 0:
Packit Service 5a9772
			default:
Packit Service 5a9772
				/* MS-RDPEDISP - 2.2.2.2.1:
Packit Service 5a9772
				 * Orientation (4 bytes): A 32-bit unsigned integer that specifies the
Packit Service 5a9772
				 * orientation of the monitor in degrees. Valid values are 0, 90, 180
Packit Service 5a9772
				 * or 270
Packit Service 5a9772
				 *
Packit Service 5a9772
				 * So we default to ORIENTATION_LANDSCAPE
Packit Service 5a9772
				 */
Packit Service 5a9772
				layouts[i].Orientation = ORIENTATION_LANDSCAPE;
Packit Service 5a9772
				break;
Packit Service 5a9772
		}
Packit Service 5a9772
Packit Service 5a9772
		layouts[i].DesktopScaleFactor = settings->DesktopScaleFactor;
Packit Service 5a9772
		layouts[i].DeviceScaleFactor = settings->DeviceScaleFactor;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	ret = IFCALLRESULT(CHANNEL_RC_OK, disp->SendMonitorLayout, disp, nmonitors, layouts);
Packit Service 5a9772
	free(layouts);
Packit Service 5a9772
	return ret;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
BOOL wlf_disp_handle_configure(wlfDispContext* disp, int32_t width, int32_t height)
Packit Service 5a9772
{
Packit Service 5a9772
	if (!disp)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	disp->targetWidth = width;
Packit Service 5a9772
	disp->targetHeight = height;
Packit Service 5a9772
	return wlf_disp_sendResize(disp);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static UINT wlf_DisplayControlCaps(DispClientContext* disp, UINT32 maxNumMonitors,
Packit Service 5a9772
                                   UINT32 maxMonitorAreaFactorA, UINT32 maxMonitorAreaFactorB)
Packit Service 5a9772
{
Packit Service 5a9772
	/* we're called only if dynamic resolution update is activated */
Packit Service 5a9772
	wlfDispContext* wlfDisp = (wlfDispContext*)disp->custom;
Packit Service 5a9772
	rdpSettings* settings = wlfDisp->wlc->context.settings;
Packit Service 5a9772
	WLog_DBG(TAG,
Packit Service 5a9772
	         "DisplayControlCapsPdu: MaxNumMonitors: %" PRIu32 " MaxMonitorAreaFactorA: %" PRIu32
Packit Service 5a9772
	         " MaxMonitorAreaFactorB: %" PRIu32 "",
Packit Service 5a9772
	         maxNumMonitors, maxMonitorAreaFactorA, maxMonitorAreaFactorB);
Packit Service 5a9772
	wlfDisp->activated = TRUE;
Packit Service 5a9772
Packit Service 5a9772
	if (settings->Fullscreen)
Packit Service 5a9772
		return CHANNEL_RC_OK;
Packit Service 5a9772
Packit Service 5a9772
	WLog_DBG(TAG, "DisplayControlCapsPdu: setting the window as resizable");
Packit Service 5a9772
	return wlf_disp_set_window_resizable(wlfDisp) ? CHANNEL_RC_OK : CHANNEL_RC_NO_MEMORY;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
BOOL wlf_disp_init(wlfDispContext* wlfDisp, DispClientContext* disp)
Packit Service 5a9772
{
Packit Service 5a9772
	rdpSettings* settings;
Packit Service 5a9772
Packit Service 5a9772
	if (!wlfDisp || !wlfDisp->wlc || !disp)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	settings = wlfDisp->wlc->context.settings;
Packit Service 5a9772
Packit Service 5a9772
	if (!settings)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	wlfDisp->disp = disp;
Packit Service 5a9772
	disp->custom = (void*)wlfDisp;
Packit Service 5a9772
Packit Service 5a9772
	if (settings->DynamicResolutionUpdate)
Packit Service 5a9772
	{
Packit Service 5a9772
		disp->DisplayControlCaps = wlf_DisplayControlCaps;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return TRUE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
BOOL wlf_disp_uninit(wlfDispContext* wlfDisp, DispClientContext* disp)
Packit Service 5a9772
{
Packit Service 5a9772
	if (!wlfDisp || !disp)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	wlfDisp->disp = NULL;
Packit Service 5a9772
	return TRUE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
int wlf_list_monitors(wlfContext* wlc)
Packit Service 5a9772
{
Packit Service 5a9772
	uint32_t i, nmonitors = UwacDisplayGetNbOutputs(wlc->display);
Packit Service 5a9772
Packit Service 5a9772
	for (i = 0; i < nmonitors; i++)
Packit Service 5a9772
	{
Packit Service 5a9772
		const UwacOutput* monitor = UwacDisplayGetOutput(wlc->display, i);
Packit Service 5a9772
		UwacSize resolution;
Packit Service 5a9772
		UwacPosition pos;
Packit Service 5a9772
Packit Service 5a9772
		if (!monitor)
Packit Service 5a9772
			continue;
Packit Service 5a9772
		UwacOutputGetPosition(monitor, &pos;;
Packit Service 5a9772
		UwacOutputGetResolution(monitor, &resolution);
Packit Service 5a9772
Packit Service 5a9772
		printf("     %s [%d] %dx%d\t+%d+%d\n", (i == 0) ? "*" : " ", i, resolution.width,
Packit Service 5a9772
		       resolution.height, pos.x, pos.y);
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return 0;
Packit Service 5a9772
}