1
/*********************************************************
2
* Copyright (C) 2007-2008 VMware, Inc. All rights reserved.
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms of the GNU Lesser General Public License as published
6
* by the Free Software Foundation version 2.1 and no later version.
8
* This program is distributed in the hope that it will be useful, but
9
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
10
* or FITNESS FOR A PARTICULAR PURPOSE. See the Lesser GNU General Public
11
* License for more details.
13
* You should have received a copy of the GNU Lesser General Public License
14
* along with this program; if not, write to the Free Software Foundation, Inc.,
15
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
17
*********************************************************/
20
* @file unityPlatformX11.c
22
* Implementation of Unity for guest operating systems that use the X11 windowing
23
* system. This file holds the basic things such as initialization/destruction of the
24
* UnityPlatform object, overall event handling, and handling of some Unity
25
* RPCs that are not window-centric.
33
#include <X11/extensions/Xinerama.h>
34
#include <X11/extensions/XTest.h>
39
} UnityTemporaryEvent;
41
static UnitySpecialWindow *USWindowCreate(UnityPlatform *up,
42
UnitySpecialEventHandler evHandler,
45
static void USWindowUpdate(UnityPlatform *up,
46
UnitySpecialWindow *usw,
49
static UnitySpecialWindow *USWindowLookup(UnityPlatform *up, Window window);
50
static void USWindowDestroy(UnityPlatform *up, UnitySpecialWindow *usw);
52
static void UnityPlatformProcessXEvent(UnityPlatform *up,
54
Window realEventWindow);
55
static Window UnityPlatformGetRealEventWindow(UnityPlatform *up, const XEvent *xevent);
56
static void USRootWindowsProcessEvent(UnityPlatform *up,
57
UnitySpecialWindow *usw,
60
static int UnityPlatformXErrorHandler(Display *dpy, XErrorEvent *xev);
61
static UnitySpecialWindow *UnityPlatformMakeRootWindowsObject(UnityPlatform *up);
63
static void UnityPlatformSendClientMessageFull(Display *d,
70
static void UnityPlatformStackDnDDetWnd(UnityPlatform *up);
71
static void UnityPlatformDnDSendClientMessage(UnityPlatform *up,
79
static Bool GetRelevantWMWindow(UnityPlatform *up,
80
UnityWindowId windowId,
82
static Bool SetWindowStickiness(UnityPlatform *up,
83
UnityWindowId windowId,
86
static const GuestCapabilities platformUnityCaps[] = {
90
UNITY_CAP_VIRTUAL_DESK,
91
UNITY_CAP_STICKY_WINDOWS,
95
* Has to be global for UnityPlatformXErrorHandler
97
static int unityX11ErrorCount = 0;
100
*----------------------------------------------------------------------------
102
* UnityPlatformIsSupported --
104
* Determine whether this guest supports unity.
107
* TRUE if the guest supports Unity
113
*----------------------------------------------------------------------------
117
UnityPlatformIsSupported(void)
126
* Unity/X11 doesn't yet work with the new vmwgfx driver. Until that is
127
* fixed, we have to disable the feature.
129
* As for detecting which driver is in use, the legacy driver provides the
130
* VMWARE_CTRL extension for resolution and topology operations, while the
131
* new driver is instead controlled via XRandR. If we don't find said
132
* extension, then we'll assume the new driver is in use and disable Unity.
134
if (XQueryExtension(dpy, "VMWARE_CTRL", &major, &event_base, &error_base) ==
136
Debug("Unity is not yet supported under the vmwgfx driver.\n");
145
*----------------------------------------------------------------------------
147
* UnityPlatformInit --
149
* Initialize the UnityPlatform object that represents the platform-specific state.
152
* Pointer to newly allocated UnityPlatform data.
157
*----------------------------------------------------------------------------
161
UnityPlatformInit(UnityWindowTracker *tracker, // IN
162
UnityUpdateChannel *updateChannel, // IN
163
int *blockedWnd, // IN, not used
164
DesktopSwitchCallbackManager *desktopSwitchCallbackMgr) // IN, not used
170
ASSERT(updateChannel);
172
Debug("UnityPlatformInit: Running\n");
174
up = Util_SafeCalloc(1, sizeof *up);
175
up->tracker = tracker;
176
up->updateChannel = updateChannel;
178
up->savedScreenSaverTimeout = -1;
181
* Because GDK filters events heavily, and we need to do a lot of low-level X work, we
182
* just open another connection to the same display.
184
displayName = gdk_get_display();
185
up->display = XOpenDisplay(displayName);
188
return NULL; // We couldn't connect to the display for some strange reason
190
XSetErrorHandler(UnityPlatformXErrorHandler);
191
XSynchronize(up->display, TRUE); // So error counting works properly...
194
* Certain applications, like gnome-session during logout, may grab the X
195
* server before displaying a modal window. With the server grabbed, we're
196
* unable to correctly track and display windows.
198
* The following snippet attempts to work around this by using the XTest
199
* extension's ability to make ourselves impervious to X server grabs.
207
if ((XTestQueryExtension(up->display, &dummy1, &dummy2,
208
&major, &minor) == True) &&
209
((major > 2) || (major == 2 && minor >= 2))) {
210
if (XTestGrabControl(up->display, True) != 1) {
211
Debug("XTestGrabControl failed.\n");
214
Debug("XTest extension not available.\n");
218
up->allWindows = HashTable_Alloc(128, HASH_INT_KEY, NULL);
219
up->specialWindows = HashTable_Alloc(32, HASH_INT_KEY, NULL);
220
up->desktopWindow = NULL;
221
up->desktopInfo.initialDesktop = UNITY_X11_INITIALDESKTOP_UNSET;
224
* Find the values of all the atoms
226
# define INIT_ATOM(x) up->atoms.x = XInternAtom(up->display, #x, False)
228
INIT_ATOM(_NET_WM_WINDOW_TYPE);
229
INIT_ATOM(_NET_WM_WINDOW_TYPE_DESKTOP);
230
INIT_ATOM(_NET_WM_WINDOW_TYPE_DOCK);
231
INIT_ATOM(_NET_WM_WINDOW_TYPE_TOOLBAR);
232
INIT_ATOM(_NET_WM_WINDOW_TYPE_TOOLTIP);
233
INIT_ATOM(_NET_WM_WINDOW_TYPE_DROPDOWN_MENU);
234
INIT_ATOM(_NET_WM_WINDOW_TYPE_POPUP_MENU);
235
INIT_ATOM(_NET_WM_WINDOW_TYPE_MENU);
236
INIT_ATOM(_NET_WM_WINDOW_TYPE_UTILITY);
237
INIT_ATOM(_NET_WM_WINDOW_TYPE_SPLASH);
238
INIT_ATOM(_NET_WM_WINDOW_TYPE_DIALOG);
239
INIT_ATOM(_NET_WM_WINDOW_TYPE_NORMAL);
240
INIT_ATOM(_NET_WM_WINDOW_TYPE_DND);
241
INIT_ATOM(_NET_WM_STATE);
242
INIT_ATOM(_NET_WM_STATE_HIDDEN);
243
INIT_ATOM(_NET_WM_STATE_MODAL);
244
INIT_ATOM(_NET_WM_STATE_STICKY);
245
INIT_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
246
INIT_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
247
INIT_ATOM(_NET_WM_STATE_MINIMIZED);
248
INIT_ATOM(_NET_WM_STATE_SHADED);
249
INIT_ATOM(_NET_WM_STATE_SKIP_TASKBAR);
250
INIT_ATOM(_NET_WM_STATE_SKIP_PAGER);
251
INIT_ATOM(_NET_WM_STATE_FULLSCREEN);
252
INIT_ATOM(_NET_WM_STATE_ABOVE);
253
INIT_ATOM(_NET_WM_STATE_BELOW);
254
INIT_ATOM(_NET_WM_STATE_DEMANDS_ATTENTION);
255
INIT_ATOM(_NET_WM_USER_TIME);
256
INIT_ATOM(_NET_WM_USER_TIME_WINDOW);
257
INIT_ATOM(_NET_ACTIVE_WINDOW);
258
INIT_ATOM(_NET_RESTACK_WINDOW);
259
INIT_ATOM(_NET_WM_ICON);
260
INIT_ATOM(_NET_WM_PID);
261
INIT_ATOM(_NET_WM_STRUT);
262
INIT_ATOM(_NET_WM_STRUT_PARTIAL);
263
INIT_ATOM(_NET_MOVERESIZE_WINDOW);
264
INIT_ATOM(_NET_CLOSE_WINDOW);
265
INIT_ATOM(_NET_WM_ALLOWED_ACTIONS);
266
INIT_ATOM(_NET_WM_ACTION_MOVE);
267
INIT_ATOM(_NET_WM_ACTION_RESIZE);
268
INIT_ATOM(_NET_WM_ACTION_MINIMIZE);
269
INIT_ATOM(_NET_WM_ACTION_SHADE);
270
INIT_ATOM(_NET_WM_ACTION_STICK);
271
INIT_ATOM(_NET_WM_ACTION_MAXIMIZE_HORZ);
272
INIT_ATOM(_NET_WM_ACTION_MAXIMIZE_VERT);
273
INIT_ATOM(_NET_WM_ACTION_FULLSCREEN);
274
INIT_ATOM(_NET_WM_ACTION_CHANGE_DESKTOP);
275
INIT_ATOM(_NET_WM_ACTION_CLOSE);
276
INIT_ATOM(_NET_NUMBER_OF_DESKTOPS);
277
INIT_ATOM(_NET_WM_DESKTOP);
278
INIT_ATOM(_NET_CURRENT_DESKTOP);
279
INIT_ATOM(_NET_DESKTOP_LAYOUT);
280
INIT_ATOM(_NET_SUPPORTED);
281
INIT_ATOM(_NET_FRAME_EXTENTS);
283
INIT_ATOM(WM_CLIENT_LEADER);
284
INIT_ATOM(WM_DELETE_WINDOW);
287
INIT_ATOM(WM_PROTOCOLS);
289
INIT_ATOM(WM_TRANSIENT_FOR);
290
INIT_ATOM(WM_WINDOW_ROLE);
294
#if defined(VM_HAVE_X11_SHAPE_EXT)
295
if (!XShapeQueryExtension(up->display, &up->shapeEventBase, &up->shapeErrorBase)) {
296
up->shapeEventBase = 0;
305
*----------------------------------------------------------------------------
307
* UnityPlatformCleanup --
309
* One-time platform-specific cleanup code.
317
*----------------------------------------------------------------------------
321
UnityPlatformCleanup(UnityPlatform *up) // IN
328
* Caller should've called Unity_Exit first.
330
ASSERT(!up->isRunning);
331
ASSERT(up->glibSource == NULL);
333
if (up->specialWindows) {
334
HashTable_Free(up->specialWindows);
335
up->specialWindows = NULL;
337
if (up->allWindows) {
338
HashTable_Free(up->allWindows);
339
up->allWindows = NULL;
343
XCloseDisplay(up->display);
347
free(up->desktopInfo.guestDesktopToUnity);
348
up->desktopInfo.guestDesktopToUnity = NULL;
349
free(up->desktopInfo.unityDesktopToGuest);
350
up->desktopInfo.unityDesktopToGuest = NULL;
351
up->desktopWindow = NULL;
358
*----------------------------------------------------------------------------
360
* UnityPlatformRegisterCaps --
362
* Register guest platform specific capabilities with the VMX.
370
*----------------------------------------------------------------------------
374
UnityPlatformRegisterCaps(UnityPlatform *up) // IN
378
if (!RpcOut_sendOne(NULL, NULL, UNITY_RPC_SHOW_TASKBAR_CAP " %d",
379
Unity_IsSupported() ? 1 : 0)) {
380
Debug("Could not set unity show taskbar cap\n");
383
AppUtil_SendGuestCaps(platformUnityCaps, ARRAYSIZE(platformUnityCaps), TRUE);
388
*----------------------------------------------------------------------------
390
* UnityPlatformUnregisterCaps --
392
* Unregister guest platform specific capabilities with the VMX.
400
*----------------------------------------------------------------------------
404
UnityPlatformUnregisterCaps(UnityPlatform *up) // IN
407
* This function may potentially be called during UnityPlatform destruction.
413
AppUtil_SendGuestCaps(platformUnityCaps, ARRAYSIZE(platformUnityCaps), FALSE);
415
if (!RpcOut_sendOne(NULL, NULL, UNITY_RPC_SHOW_TASKBAR_CAP " 0")) {
416
Debug("Failed to unregister Unity taskbar capability\n");
421
/*****************************************************************************
422
* Unity main loop and event handling *
423
*****************************************************************************/
427
*-----------------------------------------------------------------------------
431
* Creates a new UnitySpecialWindow. Ownership of the 'windows' memory is taken over
432
* by the newly created object, but that memory MUST be malloc'd...
435
* New UnitySpecialWindow object.
440
*-----------------------------------------------------------------------------
443
static UnitySpecialWindow *
444
USWindowCreate(UnityPlatform *up, // IN
445
UnitySpecialEventHandler evHandler, // IN
446
Window *windows, // IN
447
int windowCount) // IN
449
UnitySpecialWindow *usw;
453
usw = Util_SafeCalloc(1, sizeof *usw);
454
usw->evHandler = evHandler;
455
USWindowUpdate(up, usw, windows, windowCount);
462
*-----------------------------------------------------------------------------
466
* Updates this USWindow with a new list of X windows. Ownership of the 'windows'
467
* memory is taken over by this USWindow object. That memory MUST be malloc'd...
473
* Old window list may be destroyed and freed.
475
*-----------------------------------------------------------------------------
479
USWindowUpdate(UnityPlatform *up, // IN
480
UnitySpecialWindow *usw, // IN
481
Window *windows, // IN
482
int windowCount) // IN
489
for (i = 0; i < usw->numWindows; i++) {
490
XSelectInput(up->display, usw->windows[i], 0);
491
HashTable_Delete(up->specialWindows, GUINT_TO_POINTER(usw->windows[i]));
495
usw->windows = windows;
496
usw->numWindows = windowCount;
498
for (i = 0; i < windowCount; i++) {
499
HashTable_Insert(up->specialWindows, GUINT_TO_POINTER(windows[i]), usw);
505
*-----------------------------------------------------------------------------
509
* Looks up a special window
512
* UnitySpecialWindow object
517
*-----------------------------------------------------------------------------
520
static UnitySpecialWindow *
521
USWindowLookup(UnityPlatform *up, // IN
524
UnitySpecialWindow *retval = NULL;
526
HashTable_Lookup(up->specialWindows, GUINT_TO_POINTER(window), (void **)&retval);
533
*-----------------------------------------------------------------------------
537
* Destroys a UnitySpecialWindow
545
*-----------------------------------------------------------------------------
549
USWindowDestroy(UnityPlatform *up, // IN
550
UnitySpecialWindow *usw) // IN
557
for (i = 0; i < usw->numWindows; i++) {
558
HashTable_Delete(up->specialWindows, GUINT_TO_POINTER(usw->windows[i]));
560
if (usw->windowsAreOwned) {
561
XDestroyWindow(up->display, usw->windows[i]);
564
* For now, assume we don't have any special windows that get extension events
565
* and need a call like XScreenSaverSelectInput...
567
XSelectInput(up->display, usw->windows[i], 0);
577
*-----------------------------------------------------------------------------
579
* UnityPlatformMakeRootWindowsObject --
581
* Creates a UnitySpecialWindow to handle the root windows.
587
* Selects for events on the root windows.
589
*-----------------------------------------------------------------------------
592
static UnitySpecialWindow *
593
UnityPlatformMakeRootWindowsObject(UnityPlatform *up) // IN
595
static const long eventMask =
598
| SubstructureNotifyMask
606
numRootWindows = ScreenCount(up->display);
607
ASSERT(numRootWindows > 0);
609
rootWindows = Util_SafeCalloc(numRootWindows, sizeof rootWindows[0]);
610
for (i = 0; i < numRootWindows; i++) {
611
rootWindows[i] = RootWindow(up->display, i);
614
for (i = 0; i < numRootWindows; i++) {
615
XSelectInput(up->display, rootWindows[i], eventMask);
618
return USWindowCreate(up, USRootWindowsProcessEvent, rootWindows, numRootWindows);
623
*-----------------------------------------------------------------------------
625
* UnityPlatformGetErrorCount --
627
* Retrieves the current count of X11 errors received by Unity.
630
* Current error count.
635
*-----------------------------------------------------------------------------
639
UnityPlatformGetErrorCount(UnityPlatform *up) // IN
641
return unityX11ErrorCount;
646
*-----------------------------------------------------------------------------
648
* UnityPlatformResetErrorCount --
650
* Resets the Unity X11 error count to zero.
658
*-----------------------------------------------------------------------------
662
UnityPlatformResetErrorCount(UnityPlatform *up) // IN
664
unityX11ErrorCount = 0;
669
*-----------------------------------------------------------------------------
671
* UnityPlatformXErrorHandler --
673
* Handler for all X event errors.
679
* Updates our X11 error counter.
681
*-----------------------------------------------------------------------------
685
UnityPlatformXErrorHandler(Display *dpy, // IN
686
XErrorEvent *xev) // IN
689
XGetErrorText(dpy, xev->error_code, buf, sizeof buf);
690
Debug("> VMwareUserXErrorHandler: error %s on resource %#lx for request %d\n",
691
buf, xev->resourceid, xev->request_code);
693
unityX11ErrorCount++;
700
*-----------------------------------------------------------------------------
702
* UnityPlatformGetServerTime --
704
* Returns an educated guess at the X server's current timestamp
712
*-----------------------------------------------------------------------------
716
UnityPlatformGetServerTime(UnityPlatform *up) // IN
721
gettimeofday(&tv, NULL);
722
retval = up->eventTimeDiff + (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
724
Debug("UserTime is guessed at %lu\n", retval);
731
*-----------------------------------------------------------------------------
735
* Compares two pointers to see whether they're equal.
738
* -1, 0, or 1 (same meaning as strcmp return values)
743
*-----------------------------------------------------------------------------
747
ComparePointers(const void *p1, // IN
748
const void *p2) // IN
751
* Helper function for UnityPlatformKillHelperThreads
753
const void * const *ptr1 = p1;
754
const void * const *ptr2 = p2;
755
ptrdiff_t diff = (*ptr2 - *ptr1);
759
} else if (diff > 0) {
768
*----------------------------------------------------------------------------
770
* UnityPlatformKillHelperThreads --
772
* Tears down the Unity "running" state.
778
* Restores system settings.
780
*----------------------------------------------------------------------------
784
UnityPlatformKillHelperThreads(UnityPlatform *up) // IN
786
UnityPlatformWindow **upwList;
787
UnitySpecialWindow **uswList;
791
if (!up || !up->isRunning) {
792
ASSERT(up->glibSource == NULL);
796
UnityX11EventTeardownSource(up);
798
up->desktopInfo.numDesktops = 0; // Zero means host has not set virtual desktop config
799
UnityX11RestoreSystemSettings(up);
801
HashTable_ToArray(up->allWindows,
804
qsort(upwList, numWindows, sizeof *upwList, ComparePointers);
805
for (i = 0; i < numWindows; i++) {
806
if (i < (numWindows - 1) && upwList[i] == upwList[i + 1]) {
810
UPWindow_Unref(up, upwList[i]);
814
up->workAreas = NULL;
815
up->rootWindows = NULL;
816
HashTable_ToArray(up->specialWindows,
819
qsort(uswList, numWindows, sizeof *uswList, ComparePointers);
820
for (i = 0; i < numWindows; i++) {
821
if (i < (numWindows - 1) && uswList[i] == uswList[i + 1]) {
825
USWindowDestroy(up, uswList[i]);
829
XSync(up->display, TRUE);
830
up->desktopInfo.initialDesktop = UNITY_X11_INITIALDESKTOP_UNSET;
831
up->isRunning = FALSE;
833
Debug("Leaving unity mode\n");
838
*-----------------------------------------------------------------------------
840
* UnityX11GetWMProtocols --
842
* Updates the list of protocols supported by the window manager.
850
*-----------------------------------------------------------------------------
854
UnityX11GetWMProtocols(UnityPlatform *up) // IN
858
unsigned long itemsReturned;
859
unsigned long bytesRemaining;
860
Atom *valueReturned = NULL;
864
memset(up->wmProtocols, 0, sizeof up->wmProtocols);
865
if (XGetWindowProperty(up->display, up->rootWindows->windows[0],
866
up->atoms._NET_SUPPORTED, 0,
867
1024, False, AnyPropertyType,
868
&propertyType, &propertyFormat, &itemsReturned,
869
&bytesRemaining, (unsigned char **)&valueReturned)
874
if ((propertyType == XA_ATOM || propertyType == XA_CARDINAL)
875
&& propertyFormat == 32) {
878
for (i = 0; i < itemsReturned; i++) {
879
if (valueReturned[i] == up->atoms._NET_MOVERESIZE_WINDOW) {
880
up->wmProtocols[UNITY_X11_WM__NET_MOVERESIZE_WINDOW] = TRUE;
881
} else if (valueReturned[i] == up->atoms._NET_CLOSE_WINDOW) {
882
up->wmProtocols[UNITY_X11_WM__NET_CLOSE_WINDOW] = TRUE;
883
} else if (valueReturned[i] == up->atoms._NET_RESTACK_WINDOW) {
884
up->wmProtocols[UNITY_X11_WM__NET_RESTACK_WINDOW] = TRUE;
885
} else if (valueReturned[i] == up->atoms._NET_ACTIVE_WINDOW) {
886
up->wmProtocols[UNITY_X11_WM__NET_ACTIVE_WINDOW] = TRUE;
887
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_MINIMIZE) {
888
up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_MINIMIZE] = TRUE;
889
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_CLOSE) {
890
up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_CLOSE] = TRUE;
891
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_SHADE) {
892
up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_SHADE] = TRUE;
893
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_STICK) {
894
up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_STICK] = TRUE;
895
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_FULLSCREEN) {
896
up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_FULLSCREEN] = TRUE;
897
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_MAXIMIZE_HORZ) {
898
up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_MAXIMIZE_HORZ] = TRUE;
899
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_MAXIMIZE_VERT) {
900
up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_MAXIMIZE_VERT] = TRUE;
901
} else if (valueReturned[i] == up->atoms._NET_FRAME_EXTENTS) {
902
up->wmProtocols[UNITY_X11_WM__NET_FRAME_EXTENTS] = TRUE;
903
} else if (valueReturned[i] == up->atoms._NET_WM_STRUT_PARTIAL) {
904
up->wmProtocols[UNITY_X11_WM__NET_WM_STRUT_PARTIAL] = TRUE;
905
} else if (valueReturned[i] == up->atoms._NET_WM_STATE_HIDDEN) {
906
up->wmProtocols[UNITY_X11_WM__NET_WM_STATE_HIDDEN] = TRUE;
907
} else if (valueReturned[i] == up->atoms._NET_WM_STATE_MINIMIZED) {
908
up->wmProtocols[UNITY_X11_WM__NET_WM_STATE_MINIMIZED] = TRUE;
913
XFree(valueReturned);
918
*----------------------------------------------------------------------------
920
* UnityPlatformStartHelperThreads --
922
* Start Unity running.
929
* Saves and changes system settings.
930
* Starts watching for windowing system events.
932
*----------------------------------------------------------------------------
936
UnityPlatformStartHelperThreads(UnityPlatform *up) // IN
939
ASSERT(up->glibSource == NULL);
941
XSync(up->display, TRUE);
942
up->rootWindows = UnityPlatformMakeRootWindowsObject(up);
943
up->isRunning = TRUE;
944
up->eventTimeDiff = 0;
946
UnityX11SaveSystemSettings(up);
948
UnityX11GetWMProtocols(up);
950
if (up->desktopInfo.numDesktops) {
951
UnityDesktopId activeDesktop;
953
UnityPlatformSyncDesktopConfig(up);
955
if (up->desktopInfo.initialDesktop != UNITY_X11_INITIALDESKTOP_UNSET) {
956
Debug("%s: Setting activeDesktop to initialDesktop (%u).\n", __func__,
957
up->desktopInfo.initialDesktop);
958
activeDesktop = up->desktopInfo.initialDesktop;
960
activeDesktop = UnityWindowTracker_GetActiveDesktop(up->tracker);
962
if (UnityPlatformSetDesktopActive(up, activeDesktop)) {;
964
* XXX Rather than setting this directly here, should we instead wait for a
965
* PropertyNotify event from the window manager to one of the root windows?
966
* Doing so may be safer in that it confirms that our request was honored by
967
* the window manager.
969
UnityWindowTracker_ChangeActiveDesktop(up->tracker, activeDesktop);
973
if (up->needWorkAreas) {
975
* UNEXPECTED: The host called SetDesktopWorkArea before entering Unity mode, so we
976
* need to go back and apply the remembered work area info.
979
UnityPlatformSetDesktopWorkAreas(up, up->needWorkAreas, up->needNumWorkAreas);
980
free(up->needWorkAreas);
981
up->needWorkAreas = NULL;
985
* Set up a callback in the glib main loop to listen for incoming X events on the
986
* unity display connection.
988
UnityX11EventEstablishSource(up);
995
*----------------------------------------------------------------------------
997
* UnityPlatformIsUnityRunning --
999
* Check to see if we are still in the unity mode.
1002
* TRUE if we are in Unity mode
1008
*----------------------------------------------------------------------------
1012
UnityPlatformIsUnityRunning(UnityPlatform *up) // IN
1016
return up->isRunning;
1021
*----------------------------------------------------------------------------
1023
* UnityPlatformLock --
1025
* Does nothing - our implementation is not threaded.
1033
*----------------------------------------------------------------------------
1037
UnityPlatformLock(UnityPlatform *up) // IN
1043
*----------------------------------------------------------------------------
1045
* UnityPlatformUnlock --
1047
* Does nothing - our implementation is not threaded.
1055
*----------------------------------------------------------------------------
1059
UnityPlatformUnlock(UnityPlatform *up) // IN
1065
*----------------------------------------------------------------------------
1067
* UnityPlatformUpdateZOrder --
1069
* Push the Z-Order of all windows into the window tracker.
1077
*----------------------------------------------------------------------------
1081
UnityPlatformUpdateZOrder(UnityPlatform *up) // IN
1083
UnityWindowId *elements;
1085
UnityPlatformWindow *curWindow;
1088
if (!up->stackingChanged) {
1092
elements = alloca(UNITY_MAX_WINDOWS * sizeof elements[0]);
1093
for (numElements = 0, curWindow = up->topWindow;
1094
curWindow; curWindow = curWindow->lowerWindow) {
1095
if (curWindow->isRelevant) {
1096
elements[numElements++] = curWindow->toplevelWindow;
1100
UnityWindowTracker_SetZOrder(up->tracker,
1103
up->stackingChanged = FALSE;
1108
*----------------------------------------------------------------------------
1110
* UnityPlatformUpdateWindowState --
1112
* Walk through /all/ the windows on the guest, pushing everything we know about
1113
* them into the unity window tracker.
1116
* TRUE indicating we need help from the common code to generate
1117
* remove window events (see unity.c)
1122
*----------------------------------------------------------------------------
1126
UnityPlatformUpdateWindowState(UnityPlatform *up, // IN
1127
UnityWindowTracker *tracker) // IN
1130
Window lowerWindow = None;
1132
if (!up || !up->rootWindows) {
1133
Debug("BUG: UpdateWindowState was called before we are fully in Unity mode...\n");
1137
for (curRoot = 0; curRoot < up->rootWindows->numWindows; curRoot++) {
1141
unsigned int numChildren;
1143
XQueryTree(up->display, up->rootWindows->windows[curRoot],
1144
&dummyWin, &dummyWin, &children, &numChildren);
1146
for (i = 0; i < numChildren; i++) {
1147
UnityPlatformWindow *upw;
1149
if (!HashTable_Lookup(up->allWindows,
1150
GUINT_TO_POINTER(children[i]),
1152
upw = UPWindow_Create(up, children[i]);
1154
continue; // Window may have disappeared since the XQueryTree
1156
UPWindow_CheckRelevance(up, upw, NULL);
1157
UPWindow_Restack(up, upw, lowerWindow);
1160
lowerWindow = upw->toplevelWindow;
1166
UnityPlatformUpdateZOrder(up);
1168
* up is not populated with the window layout structure when
1169
* UnityPlatformUpdateDnDDetWnd is intially called.
1171
UnityPlatformStackDnDDetWnd(up);
1173
if (up->needTaskbarSetting) {
1174
up->needTaskbarSetting = FALSE;
1176
* This is called in this seemingly random spot to make sure that the taskbar
1177
* visibility is properly set once we have a full picture of the windowing system
1178
* state. Although the routine is called prior to this by SaveSystemSettings(), the
1179
* up->allWindows hash table is not complete until this point, which occurs at a
1180
* random time of the host's choosing.
1182
UnityPlatformSetTaskbarVisible(up, up->currentSettings[UNITY_UI_TASKBAR_VISIBLE]);
1190
*-----------------------------------------------------------------------------
1192
* UnityX11HandleEvents --
1194
* Handle incoming events
1197
* TRUE if the main loop should continue watching for events from the display.
1200
* Events read from the X display and processed.
1202
*-----------------------------------------------------------------------------
1206
UnityX11HandleEvents(gpointer data) // IN
1208
UnityPlatform *up = (UnityPlatform *) data;
1209
GList *incomingEvents = NULL;
1210
Bool restackDetWnd = FALSE;
1213
ASSERT(up->isRunning);
1215
Debug("Starting unity event handling\n");
1216
while (XEventsQueued(up->display, QueuedAfterFlush)) {
1218
* This outer loop is here to make sure we really process all available events
1222
while (XEventsQueued(up->display, QueuedAlready)) {
1223
UnityTemporaryEvent *ev;
1225
ev = Util_SafeCalloc(1, sizeof *ev);
1226
XNextEvent(up->display, &ev->xevent);
1227
ev->realWindowID = UnityPlatformGetRealEventWindow(up, &ev->xevent);
1230
* Restack dnd detection window when either
1231
* 1. the desktop window may overlap detection window, or
1232
* 2. a window is inserted directly above the desktop (and therefore
1233
* below the DND window).
1235
if (up->desktopWindow &&
1236
ev->xevent.type == ConfigureNotify &&
1237
(up->desktopWindow->toplevelWindow == ev->realWindowID ||
1238
up->desktopWindow->toplevelWindow == ev->xevent.xconfigure.above)) {
1239
restackDetWnd = TRUE;
1242
if (ev->xevent.type == DestroyNotify) {
1244
* Unfortunately, X's event-driven model has an inherent race condition for
1245
* parties that are observing events on windows that are controlled by other
1246
* applications. Basically, if we're processing an event on a window, that
1247
* window may have already been destroyed, and there doesn't seem to really
1248
* be a way to detect this. We just have to try to cut down the probability
1249
* of those as much as possible, by discarding any events on a window if
1250
* they're immediately followed by a DestroyNotify on the same window...
1253
GList *nextItem = NULL;
1255
for (curItem = incomingEvents; curItem; curItem = nextItem) {
1256
UnityTemporaryEvent *otherEvent = curItem->data;
1257
nextItem = curItem->next;
1259
if (otherEvent->realWindowID == ev->realWindowID) {
1260
free(curItem->data);
1261
incomingEvents = g_list_remove_link(incomingEvents, curItem);
1266
incomingEvents = g_list_append(incomingEvents, ev);
1269
while (incomingEvents) {
1271
UnityTemporaryEvent *tempEvent = incomingEvents->data;
1273
UnityPlatformProcessXEvent(up, &tempEvent->xevent, tempEvent->realWindowID);
1275
nextItem = incomingEvents->next;
1276
free(incomingEvents->data);
1277
g_list_free_1(incomingEvents);
1278
incomingEvents = nextItem;
1281
if (restackDetWnd) {
1282
UnityPlatformStackDnDDetWnd(up);
1284
UnityPlatformUpdateZOrder(up);
1285
UnityPlatformDoUpdate(up, TRUE);
1293
*-----------------------------------------------------------------------------
1295
* UnityPlatformGetEventString --
1297
* Allows stringifying events for debugging purposes
1300
* A stringified version of the event name. It's a static value - do not free this.
1304
*-----------------------------------------------------------------------------
1308
UnityPlatformGetEventString(UnityPlatform *up, // IN
1311
#if defined(VM_HAVE_X11_SHAPE_EXT)
1312
if (up->shapeEventBase
1313
&& type == (up->shapeEventBase + ShapeNotify)) {
1314
return "ShapeNotify";
1319
case KeyPress: return "KeyPress";
1320
case KeyRelease: return "KeyRelease";
1321
case ButtonPress: return "ButtonPress";
1322
case ButtonRelease: return "ButtonRelease";
1323
case MotionNotify: return "MotionNotify";
1324
case EnterNotify: return "EnterNotify";
1325
case LeaveNotify: return "LeaveNotify";
1326
case FocusIn: return "FocusIn";
1327
case FocusOut: return "FocusOut";
1328
case KeymapNotify: return "KeymapNotify";
1329
case Expose: return "Expose";
1330
case GraphicsExpose: return "GraphicsExpose";
1331
case NoExpose: return "NoExpose";
1332
case VisibilityNotify: return "VisibilityNotify";
1333
case CreateNotify: return "CreateNotify";
1334
case DestroyNotify: return "DestroyNotify";
1335
case UnmapNotify: return "UnmapNotify";
1336
case MapNotify: return "MapNotify";
1337
case MapRequest: return "MapRequest";
1338
case ReparentNotify: return "ReparentNotify";
1339
case ConfigureNotify: return "ConfigureNotify";
1340
case ConfigureRequest: return "ConfigureRequest";
1341
case GravityNotify: return "GravityNotify";
1342
case ResizeRequest: return "ResizeRequest";
1343
case CirculateNotify: return "CirculateNotify";
1344
case CirculateRequest: return "CirculateRequest";
1345
case PropertyNotify: return "PropertyNotify";
1346
case SelectionClear: return "SelectionClear";
1347
case SelectionRequest: return "SelectionRequest";
1348
case SelectionNotify: return "SelectionNotify";
1349
case ColormapNotify: return "ColormapNotify";
1350
case ClientMessage: return "ClientMessage";
1351
case MappingNotify: return "MappingNotify";
1352
default: return "<Unknown>";
1358
*-----------------------------------------------------------------------------
1360
* UnityPlatformGetRealEventWindow --
1362
* For debugging purposes, retrieves the window that the event happened on (as
1363
* opposed to the window the event was sent to)
1366
* The window that the event actually happened on.
1371
*-----------------------------------------------------------------------------
1375
UnityPlatformGetRealEventWindow(UnityPlatform *up, // IN
1376
const XEvent *xevent) // IN
1378
#if defined(VM_HAVE_X11_SHAPE_EXT)
1379
if (up->shapeEventBase
1380
&& xevent->type == (up->shapeEventBase + ShapeNotify)) {
1381
XShapeEvent *sev = (XShapeEvent *) xevent;
1387
switch (xevent->type) {
1389
return xevent->xcreatewindow.window;
1392
return xevent->xdestroywindow.window;
1395
return xevent->xmap.window;
1398
return xevent->xunmap.window;
1400
case ReparentNotify:
1401
return xevent->xreparent.window;
1403
case ConfigureNotify:
1404
return xevent->xconfigure.window;
1406
case CirculateNotify:
1407
return xevent->xcirculate.window;
1409
case PropertyNotify:
1410
return xevent->xproperty.window;
1414
return xevent->xfocus.window;
1417
return xevent->xany.window;
1424
*-----------------------------------------------------------------------------
1426
* UnityPlatformUpdateEventTimeDiff --
1428
* Updates our idea of the difference between X server time and our local time.
1434
* Updated event time diff.
1436
*-----------------------------------------------------------------------------
1440
UnityPlatformUpdateEventTimeDiff(UnityPlatform *up, // IN
1441
const XEvent *xevent) // IN
1445
struct timeval localTv;
1447
switch (xevent->type) {
1450
serverTime = xevent->xkey.time;
1454
serverTime = xevent->xbutton.time;
1457
serverTime = xevent->xmotion.time;
1461
serverTime = xevent->xcrossing.time;
1463
case PropertyNotify:
1464
serverTime = xevent->xproperty.time;
1466
case SelectionClear:
1467
serverTime = xevent->xselectionclear.time;
1469
case SelectionRequest:
1470
serverTime = xevent->xselectionrequest.time;
1472
case SelectionNotify:
1473
serverTime = xevent->xselection.time;
1480
gettimeofday(&localTv, NULL);
1481
localTime = (localTv.tv_sec * 1000) + (localTv.tv_usec / 1000); // Convert to ms
1482
up->eventTimeDiff = serverTime - localTime;
1487
*-----------------------------------------------------------------------------
1489
* UnityPlatformProcessXEvent --
1491
* Processes an incoming X event.
1497
* May create or destroy UnityPlatformWindow objects.
1499
*-----------------------------------------------------------------------------
1503
UnityPlatformProcessXEvent(UnityPlatform *up, // IN
1504
const XEvent *xevent, // IN
1505
Window realEventWindow) // IN
1507
UnityPlatformWindow *upw = NULL;
1508
const char *eventName;
1513
UnityPlatformUpdateEventTimeDiff(up, xevent);
1515
eventName = UnityPlatformGetEventString(up, xevent->type);
1516
upw = UPWindow_Lookup(up, realEventWindow);
1518
UnitySpecialWindow *usw = USWindowLookup(up, realEventWindow);
1520
if (usw->evHandler) {
1521
usw->evHandler(up, usw, xevent, realEventWindow);
1525
} else if (xevent->type == CreateNotify) {
1526
/* Ignore decoration widgets. They'll be reparented later. */
1527
if (UnityX11Util_IsWindowDecorationWidget(up, realEventWindow)) {
1528
Debug("%s: Window %#lx is a decoration widget. Ignore it.\n",
1529
__func__, realEventWindow);
1534
* It may be a new window that we don't know about yet. Let's create an object
1537
upw = UPWindow_Create(up, realEventWindow);
1539
UPWindow_CheckRelevance(up, upw, NULL);
1541
Debug("UnityX11ThreadProcessEvent BOMBED:"
1542
" %s on window %#lx (reported to %#lx)\n",
1543
eventName, realEventWindow, xevent->xany.window);
1547
* If we use them on non-CreateNotify events, the above lines of code wind up
1548
* trying to create objects for crazy windows that don't exist...
1550
Debug("Ignoring %s event on unknown window %#lx (reported to %#lx)\n",
1551
eventName, realEventWindow, xevent->xany.window);
1556
UPWindow_ProcessEvent(up, upw, realEventWindow, xevent);
1557
if (upw->deleteWhenSafe) {
1558
Debug("%s: refs %u, deleteWhenSafe %u\n", __func__, upw->refs,
1559
upw->deleteWhenSafe);
1560
UPWindow_Unref(up, upw);
1567
*-----------------------------------------------------------------------------
1569
* UnityPlatformIsRootWindow --
1571
* Checks whether a given window ID is the root window. Necessary because each
1572
* screen has a separate root window, which makes checking a little more complicated
1576
* TRUE if the given window is a root window, FALSE otherwise.
1581
*-----------------------------------------------------------------------------
1585
UnityPlatformIsRootWindow(UnityPlatform *up, // IN
1586
Window window) // IN
1590
return (USWindowLookup(up, window) == up->rootWindows);
1595
*-----------------------------------------------------------------------------
1597
* UnityX11SetCurrentDesktop --
1599
* Sets the active virtual desktop.
1605
* Changes the virtual desktop.
1607
*-----------------------------------------------------------------------------
1611
UnityX11SetCurrentDesktop(UnityPlatform *up, // IN
1612
uint32 currentDesktop) // IN: guest-side desktop ID
1614
Atom data[5] = {0,0,0,0,0};
1617
ASSERT(up->rootWindows->windows);
1619
up->desktopInfo.currentDesktop = currentDesktop;
1620
data[0] = currentDesktop;
1621
data[1] = UnityPlatformGetServerTime(up);
1622
UnityPlatformSendClientMessage(up,
1623
up->rootWindows->windows[0],
1624
up->rootWindows->windows[0],
1625
up->atoms._NET_CURRENT_DESKTOP,
1631
*-----------------------------------------------------------------------------
1633
* UnityX11GetCurrentDesktop --
1635
* Gets the active virtual desktop.
1638
* The active virtual desktop. If it cannot be retrieved for any reason, a
1639
* reasonable default of '0' will be returned.
1644
*-----------------------------------------------------------------------------
1648
UnityX11GetCurrentDesktop(UnityPlatform *up) // IN
1652
unsigned long itemsReturned;
1653
unsigned long bytesRemaining;
1654
Atom *valueReturned;
1655
uint32 currentDesktop;
1658
ASSERT(up->rootWindows);
1660
if (XGetWindowProperty(up->display, up->rootWindows->windows[0],
1661
up->atoms._NET_CURRENT_DESKTOP, 0,
1662
1024, False, AnyPropertyType,
1663
&propertyType, &propertyFormat, &itemsReturned,
1664
&bytesRemaining, (unsigned char **)&valueReturned)
1666
&& propertyType == XA_CARDINAL
1667
&& propertyFormat == 32) {
1668
ASSERT(itemsReturned == 1);
1670
currentDesktop = valueReturned[0];
1674
XFree(valueReturned);
1676
return currentDesktop;
1681
*-----------------------------------------------------------------------------
1683
* USRootWindowsUpdateCurrentDesktop --
1685
* Looks at the root window to figure out the current desktop
1691
* Updates UnityWindowTracker.
1693
*-----------------------------------------------------------------------------
1697
USRootWindowsUpdateCurrentDesktop(UnityPlatform *up, // IN
1698
UnitySpecialWindow *usw, // IN
1699
Window window) // IN
1701
uint32 currentDesktop;
1702
UnityDesktopId unityDesktop;
1705
* XXX right now this is going to break if there are multiple screens in the guest,
1706
* since each one can have an independant 'current' desktop...
1710
currentDesktop = UnityX11GetCurrentDesktop(up);
1712
if (currentDesktop >= up->desktopInfo.numDesktops) {
1713
Warning("Active desktop is out of range for some strange reason\n");
1717
unityDesktop = up->desktopInfo.guestDesktopToUnity[currentDesktop];
1718
Debug("%s: currentDesktop %u, unityDesktop %u\n", __func__, currentDesktop, unityDesktop);
1719
UnityWindowTracker_ChangeActiveDesktop(up->tracker, unityDesktop);
1724
*-----------------------------------------------------------------------------
1726
* USRootWindowsProcessEvent --
1728
* Processes an event that occurred on one of the root windows.
1736
*-----------------------------------------------------------------------------
1740
USRootWindowsProcessEvent(UnityPlatform *up, // IN
1741
UnitySpecialWindow *usw, // IN
1742
const XEvent *xevent, // IN
1743
Window window) // IN
1747
* XXX Do we need to handle situations where the root window changes size? Any other
1750
switch (xevent->type) {
1751
case PropertyNotify:
1752
if (xevent->xproperty.atom == up->atoms._NET_CURRENT_DESKTOP) {
1753
USRootWindowsUpdateCurrentDesktop(up, usw, window);
1754
} else if (xevent->xproperty.atom == up->atoms._NET_NUMBER_OF_DESKTOPS) {
1757
numDesktops = UnityPlatformGetNumVirtualDesktops(up);
1758
if (numDesktops != up->desktopInfo.numDesktops) {
1759
UnityPlatformSyncDesktopConfig(up);
1761
} else if (xevent->xproperty.atom == up->atoms._NET_DESKTOP_LAYOUT) {
1764
UnityPlatformGetVirtualDesktopLayout(up, layoutData);
1765
if (memcmp(layoutData, up->desktopInfo.layoutData, sizeof layoutData) != 0) {
1766
UnityPlatformSyncDesktopConfig(up);
1775
*-----------------------------------------------------------------------------
1777
* UnityPlatformWMProtocolSupported --
1779
* Returns whether the window manager supports a particular protocol.
1782
* TRUE if the protocol is supported, FALSE otherwise.
1787
*-----------------------------------------------------------------------------
1791
UnityPlatformWMProtocolSupported(UnityPlatform *up, // IN
1792
UnityX11WMProtocol proto) // IN
1795
ASSERT(proto < UNITY_X11_MAX_WM_PROTOCOLS);
1797
return up->wmProtocols[proto];
1802
*----------------------------------------------------------------------------
1804
* UnityPlatformSendClientMessageFull --
1806
* Sends an XSendEvent.
1812
*----------------------------------------------------------------------------
1817
UnityPlatformSendClientMessageFull(Display *d, // IN
1818
Window destWindow, // IN: Window to send msg to
1819
Window w, // IN: What the msg's "To:"
1820
// header should be, so to speak.
1821
Atom messageType, // IN
1824
const void *data) // IN
1826
XClientMessageEvent ev;
1829
memset(&ev, 0, sizeof ev);
1830
ev.type = ClientMessage;
1832
ev.message_type = messageType;
1836
ASSERT(numItems <= ARRAYSIZE(ev.data.b));
1837
for (i = 0; i < numItems; i++) {
1838
const char *datab = data;
1839
ev.data.b[i] = datab[i];
1843
ASSERT(numItems <= ARRAYSIZE(ev.data.s));
1844
for (i = 0; i < numItems; i++) {
1845
const short *datas = data;
1846
ev.data.s[i] = datas[i];
1850
ASSERT(numItems <= ARRAYSIZE(ev.data.l));
1851
for (i = 0; i < numItems; i++) {
1852
const Atom *datal = data;
1853
ev.data.l[i] = datal[i];
1857
if (! XSendEvent(d, destWindow, False,
1858
PropertyChangeMask|SubstructureRedirectMask|SubstructureNotifyMask, (XEvent *)&ev)) {
1859
Debug("XSendEvent failed\n");
1864
*-----------------------------------------------------------------------------
1866
* UnityPlatformSendClientMessage --
1868
* Sends an XClientMessageEvent (such as one of the _NET_WM messages)
1876
*-----------------------------------------------------------------------------
1880
UnityPlatformSendClientMessage(UnityPlatform *up, // IN
1881
Window destWindow, // IN: Window to actually send msg to
1882
Window w, // IN: What the msg's "To:" header
1883
// should be, so to speak.
1884
Atom messageType, // IN
1887
const void *data) // IN
1889
UnityPlatformSendClientMessageFull(up->display, destWindow, w, messageType,
1890
format, numItems, data);
1894
/*****************************************************************************
1895
* Misc Unity RPCs that need to be handled *
1896
*****************************************************************************/
1900
*----------------------------------------------------------------------------
1902
* UnityPlatformSetTopWindowGroup --
1904
* Set the group of windows on top of all others.
1913
*----------------------------------------------------------------------------
1917
UnityPlatformSetTopWindowGroup(UnityPlatform *up, // IN: Platform data
1918
UnityWindowId *windows, // IN: array of window ids
1919
unsigned int windowCount) // IN: # of windows in the array
1921
Window sibling = None;
1926
ASSERT(windowCount);
1929
* Restack everything bottom to top.
1931
for (i = 0; i < windowCount; i++) {
1932
UnityPlatformWindow *upw;
1934
Atom data[5] = {0,0,0,0,0};
1936
upw = UPWindow_Lookup(up, windows[i]);
1941
curWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
1942
UPWindow_SetUserTime(up, upw);
1944
if (UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_RESTACK_WINDOW)) {
1945
data[0] = 2; // Magic source indicator to give full control
1949
UnityPlatformSendClientMessage(up, up->rootWindows->windows[0],
1951
up->atoms._NET_RESTACK_WINDOW,
1954
XWindowChanges winch = {
1955
.stack_mode = Above,
1958
unsigned int valueMask = CWStackMode;
1960
if (sibling != None) {
1961
valueMask |= CWSibling;
1965
* As of writing, Metacity doesn't support _NET_RESTACK_WINDOW and
1966
* will block our attempt to raise a window unless it's active, so
1967
* we activate the window first.
1969
if (UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_ACTIVE_WINDOW)) {
1970
data[0] = 2; // Magic source indicator to give full control
1971
data[1] = UnityPlatformGetServerTime(up);
1973
UnityPlatformSendClientMessage(up, up->rootWindows->windows[0],
1975
up->atoms._NET_ACTIVE_WINDOW,
1979
XReconfigureWMWindow(up->display, upw->toplevelWindow, 0, valueMask, &winch);
1982
sibling = upw->toplevelWindow;
1985
XSync(up->display, False);
1992
*-----------------------------------------------------------------------------
1994
* UnityPlatformDnDSendClientMessage --
1996
* XXX This is a hack because UnityPlatformSendClientMessage doesn't work
1998
* Sends an XClientMessageEvent (such as one of the _NET_WM messages)
2006
*-----------------------------------------------------------------------------
2010
UnityPlatformDnDSendClientMessage(UnityPlatform *up, // IN
2011
Window destWindow, // IN: Window to send msg to
2012
Window w, // IN: What the msg's "To:"
2013
// header should be, so to speak.
2014
Atom messageType, // IN
2017
const void *data) // IN
2019
UnityPlatformSendClientMessageFull(GDK_DISPLAY(), destWindow, w,
2020
messageType, format, numItems, data);
2025
*----------------------------------------------------------------------------
2027
* UnityPlatformStackDnDDetWnd --
2029
* Updates the stacking order of the dnd detection window.
2037
*----------------------------------------------------------------------------
2041
UnityPlatformStackDnDDetWnd(UnityPlatform *up)
2043
static const Atom onDesktop[] = { 0xFFFFFFFF, 0, 0, 0, 0 };
2045
if (!up->dnd.setMode || !up->dnd.detWnd) {
2046
Debug("%s: DnD not yet initialized.\n", __func__);
2050
if (!up->desktopWindow) {
2051
Debug("Desktop Window not cached. Tracker isn't populated.\n");
2055
/* Show the window on every desktop. */
2056
UnityPlatformDnDSendClientMessage(up,
2057
up->rootWindows->windows[0],
2058
GDK_WINDOW_XWINDOW(up->dnd.detWnd->window),
2059
up->atoms._NET_WM_DESKTOP,
2062
if (up->desktopWindow) {
2064
XSetWindowAttributes sa;
2065
Window desktop = up->desktopWindow->toplevelWindow;
2067
/* Prevent the window manager from managing our detection window. */
2068
sa.override_redirect = True;
2069
XChangeWindowAttributes(GDK_DISPLAY(),
2070
GDK_WINDOW_XWINDOW(up->dnd.detWnd->window),
2071
CWOverrideRedirect, &sa);
2073
/* Resize and restack the detection window. */
2078
ch.sibling = desktop;
2079
ch.stack_mode = Above;
2081
XConfigureWindow(GDK_DISPLAY(), GDK_WINDOW_XWINDOW(up->dnd.detWnd->window),
2082
CWX|CWY|CWWidth|CWHeight|CWStackMode | CWSibling, &ch);
2084
Debug("Restacking dnd detection window.\n");
2087
* Attempt to rely on window manager if we cannot find a window to stack
2090
Atom position[] = { _NET_WM_STATE_ADD,
2091
up->atoms._NET_WM_STATE_STICKY,
2092
up->atoms._NET_WM_STATE_BELOW, 0, 0 };
2094
Debug("Unable to locate desktop window to restack detection window above.\n");
2095
UnityPlatformDnDSendClientMessage(up,
2096
up->rootWindows->windows[0],
2097
GDK_WINDOW_XWINDOW(up->dnd.detWnd->window),
2098
up->atoms._NET_WM_STATE,
2100
XMoveResizeWindow(GDK_DISPLAY(),
2101
GDK_WINDOW_XWINDOW(up->dnd.detWnd->window),
2102
0, 0, 65535, 65535);
2108
*------------------------------------------------------------------------------
2110
* UnityPlatformUpdateDnDDetWnd --
2112
* Shows/hides a full-screen drag detection wnd for unity guest->host DnD.
2120
*------------------------------------------------------------------------------
2124
UnityPlatformUpdateDnDDetWnd(UnityPlatform *up, // IN
2128
if (!up || !up->dnd.setMode || !up->dnd.detWnd) {
2130
* This function may potentially be called during UnityPlatform destruction.
2136
gtk_widget_show(up->dnd.detWnd);
2137
UnityPlatformStackDnDDetWnd(up);
2138
Debug("Showing dnd detection window.\n");
2140
gtk_widget_hide(up->dnd.detWnd);
2141
Debug("Hiding dnd detection window.\n");
2144
up->dnd.setMode(show);
2149
*------------------------------------------------------------------------------
2151
* UnityPlatformSetActiveDnDDetWnd --
2153
* Set current full-screen drag detection wnd. The caller retains ownership
2154
* of the data. The caller is responsible for updating the active dnd det
2163
*------------------------------------------------------------------------------
2167
UnityPlatformSetActiveDnDDetWnd(UnityPlatform *up, // IN
2168
UnityDnD *data) // IN
2175
*------------------------------------------------------------------------------
2177
* UnityPlatformSetDesktopWorkAreas --
2179
* Sets the work areas for all screens.
2187
*------------------------------------------------------------------------------
2191
UnityPlatformSetDesktopWorkAreas(UnityPlatform *up, // IN
2192
UnityRect workAreas[], // IN
2193
uint32 numWorkAreas) // IN
2197
XineramaScreenInfo *screenInfo = NULL;
2199
RegionPtr strutsRegion;
2200
RegionPtr screenRegion;
2201
RegionPtr workAreasRegion;
2202
XID (*strutInfos)[12];
2205
if (!up->rootWindows) {
2207
* We're not in Unity mode yet. Save the info until we are.
2210
up->needWorkAreas = Util_SafeMalloc(numWorkAreas * sizeof *up->needWorkAreas);
2211
memcpy(up->needWorkAreas, workAreas, numWorkAreas * sizeof *up->needWorkAreas);
2212
up->needNumWorkAreas = numWorkAreas;
2216
if (!UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_WM_STRUT_PARTIAL)) {
2217
Debug("Window manager does not support _NET_WM_STRUT_PARTIAL - not setting desktop work area.\n");
2222
ASSERT(up->rootWindows);
2225
* Get the geometry of all attached screens. If we're running multi-mon,
2226
* we'll query the Xinerama extension. Otherwise we just fall back to
2227
* examining our root window's geometry.
2229
if (XineramaQueryExtension(up->display, &i, &i)) {
2230
screenInfo = XineramaQueryScreens(up->display, &numScreens);
2241
if (numWorkAreas > 1) {
2242
Debug("Xinerama extension not present, or XineramaQueryScreens failed,"
2243
" but multiple work areas were requested.\n");
2247
if (!XGetGeometry(up->display, up->rootWindows->windows[0], &winDummy,
2248
&rootX, &rootY, &rootWidth, &rootHeight,
2253
screenInfo = Util_SafeCalloc(1, sizeof *screenInfo);
2256
screenInfo->x_org = rootX;
2257
screenInfo->y_org = rootY;
2258
screenInfo->width = rootWidth;
2259
screenInfo->height = rootHeight;
2263
* New and improved wild'n'crazy scheme to map the host's work area
2264
* coordinates to a collection of struts.
2266
* This implementation depends upon the y-x banded rectangles
2267
* implementation of lib/region.
2269
* In short, here's how things go:
2271
* 1. For each Xinerama screen (or the root window in case we have no
2272
* Xinerama) and host work area, a region is created. A strut
2273
* region is then created by subtracting the work area region from
2274
* the screen region.
2276
* 2. This remaining region will contain between 0 and 4 rectangles,
2277
* each of which will be transformed into a strut window.
2279
* For each of these rectangles, we infer based on their dimensions
2280
* which screen boundary the resulting strut should be bound to.
2282
* a. Boxes touching both the left and right sides of the screen
2283
* are either top or bottom struts, depending on whether they
2284
* also touch the top or bottom edge.
2286
* b. Any remaining box will touch either the left OR the right
2287
* side, but not both. (Such an irregular layout cannot be
2288
* described by the work areas RPC.) That box's strut will
2289
* then be attached to the same side of the screen.
2291
* While also not perfect, this algorithm should do a better job of creating
2292
* struts along their correct sides of a screen than its predecessor. It
2293
* will let us assume the common case that what we define as a strut attached
2294
* to the left or right side really should be attached to the left or right,
2295
* rather than attached to the top or bottom and spanning the height of the
2298
* Pathological case:
2299
* 1. Screen geometry: 1280x960.
2300
* Left strut: 100px wide, 600px tall. Touches top of screen.
2301
* Right strut: 1180px wide, 100px tall. Touches top of screen.
2303
* 2. Note that these struts touch each other. We'd interpret the resulting
2304
* work area as follows:
2306
* Top strut: 1280px wide, 100px tall.
2307
* Left strut: 100px wide, 500px tall, starting from y = 100.
2309
* I believe this sort of layout to be uncommon enough that we can accept
2310
* failure here. If we -really- want to get these things right, then
2311
* we should send strut information explicitly, rather than having the
2312
* guest try to deduce it from work area geometry.
2316
* One strut per screen edge = at most 4 strutInfos.
2318
strutInfos = alloca(4 * sizeof *strutInfos * numScreens);
2319
memset(strutInfos, 0, 4 * sizeof *strutInfos * numScreens);
2322
for (iScreens = 0; iScreens < numScreens; iScreens++) {
2325
xRectangle screenRect;
2326
xRectangle workAreaRect;
2329
* Steps 1a. Create screen, work area regions.
2331
screenRect.x = screenInfo[iScreens].x_org;
2332
screenRect.y = screenInfo[iScreens].y_org;
2333
screenRect.width = screenInfo[iScreens].width;
2334
screenRect.height = screenInfo[iScreens].height;
2335
screenRect.info.type = UpdateRect;
2337
workAreaRect.x = workAreas[iScreens].x;
2338
workAreaRect.y = workAreas[iScreens].y;
2339
workAreaRect.width = workAreas[iScreens].width;
2340
workAreaRect.height = workAreas[iScreens].height;
2341
workAreaRect.info.type = UpdateRect;
2343
screenRegion = miRectsToRegion(1, &screenRect, 0);
2344
workAreasRegion = miRectsToRegion(1, &workAreaRect, 0);
2347
* Step 1b. Create struts region by subtracting work area from screen.
2349
strutsRegion = miRegionCreate(NULL, 0);
2350
miSubtract(strutsRegion, screenRegion, workAreasRegion);
2351
miRegionDestroy(workAreasRegion);
2352
miRegionDestroy(screenRegion);
2355
* Step 2. Transform struts region rectangles into individual struts.
2357
for (iRects = 0; iRects < REGION_NUM_RECTS(strutsRegion);
2358
iRects++, numStrutInfos++) {
2359
BoxPtr p = REGION_RECTS(strutsRegion) + iRects;
2361
#define TOUCHES_LEFT 0x1
2362
#define TOUCHES_RIGHT 0x2
2363
#define TOUCHES_TOP 0x4
2364
#define TOUCHES_BOTTOM 0x8
2366
if (p->x1 == screenRect.x) { bounds |= TOUCHES_LEFT; }
2367
if (p->x2 == screenRect.x + screenRect.width) { bounds |= TOUCHES_RIGHT; }
2368
if (p->y1 == screenRect.y) { bounds |= TOUCHES_TOP; }
2369
if (p->y2 == screenRect.y + screenRect.height) { bounds |= TOUCHES_BOTTOM; }
2372
* strutInfos is passed directly to
2373
* XSetProperty(..._NET_WM_STRUTS_PARTIAL). I.e., look up that
2374
* property's entry in NetWM/wm-spec for more info on the indices.
2376
* I went the switch/case route only because it does a better job
2377
* (for me) of organizing & showing -all- possible cases. YMMV.
2379
* The region code treats rectanges as ranges from [x1,x2) and
2380
* [y1,y2). In other words, x2 and y2 are OUTSIDE the region. I
2381
* guess it makes calculating widths/heights easier. However, the
2382
* strut width/height dimensions are INCLUSIVE, so we'll subtract 1
2383
* from the "end" (as opposed to "start") value.
2385
* (Ex: A 1600x1200 display with a 25px top strut would be marked
2386
* as top = 25, top_start_x = 0, top_end_x = 1599.)
2389
case TOUCHES_LEFT | TOUCHES_RIGHT | TOUCHES_TOP:
2391
strutInfos[numStrutInfos][2] = p->y2 - p->y1;
2392
strutInfos[numStrutInfos][8] = p->x1;
2393
strutInfos[numStrutInfos][9] = p->x2 - 1;
2395
case TOUCHES_LEFT | TOUCHES_RIGHT | TOUCHES_BOTTOM:
2397
strutInfos[numStrutInfos][3] = p->y2 - p->y1;
2398
strutInfos[numStrutInfos][10] = p->x1;
2399
strutInfos[numStrutInfos][11] = p->x2 - 1;
2402
case TOUCHES_LEFT | TOUCHES_TOP:
2403
case TOUCHES_LEFT | TOUCHES_BOTTOM:
2404
case TOUCHES_LEFT | TOUCHES_TOP | TOUCHES_BOTTOM:
2406
strutInfos[numStrutInfos][0] = p->x2 - p->x1;
2407
strutInfos[numStrutInfos][4] = p->y1;
2408
strutInfos[numStrutInfos][5] = p->y2 - 1;
2411
case TOUCHES_RIGHT | TOUCHES_TOP:
2412
case TOUCHES_RIGHT | TOUCHES_BOTTOM:
2413
case TOUCHES_RIGHT | TOUCHES_TOP | TOUCHES_BOTTOM:
2415
strutInfos[numStrutInfos][1] = p->x2 - p->x1;
2416
strutInfos[numStrutInfos][6] = p->y1;
2417
strutInfos[numStrutInfos][7] = p->y2 - 1;
2419
case TOUCHES_LEFT | TOUCHES_RIGHT | TOUCHES_TOP | TOUCHES_BOTTOM:
2420
Warning("%s: Struts occupy entire display.", __func__);
2423
Warning("%s: Irregular strut configuration: bounds %4x\n", __func__, bounds);
2424
miRegionDestroy(strutsRegion);
2430
#undef TOUCHES_RIGHT
2432
#undef TOUCHES_BOTTOM
2434
miRegionDestroy(strutsRegion);
2438
* The first step is making sure we have enough windows in existence to list the
2439
* _NET_WM_STRUT_PARTIAL properties for each screen.
2442
|| up->workAreas->numWindows != numStrutInfos) {
2445
newWinList = Util_SafeCalloc(numStrutInfos, sizeof *newWinList);
2446
if (up->workAreas) {
2447
memcpy(newWinList, up->workAreas->windows,
2448
MIN(numStrutInfos, up->workAreas->numWindows) * sizeof *newWinList);
2452
* Destroy unneeded windows
2454
for (i = numStrutInfos; i < (up->workAreas ? up->workAreas->numWindows : 0); i++) {
2455
XDestroyWindow(up->display, up->workAreas->windows[i]);
2459
* Create additional windows as needed.
2461
for (i = up->workAreas ? up->workAreas->numWindows : 0; i < numStrutInfos; i++) {
2462
static const char strutWindowName[] = "vmware-user workarea struts";
2463
Atom allDesktops = -1;
2464
newWinList[i] = XCreateWindow(up->display, up->rootWindows->windows[0],
2465
-50, -50, 1, 1, 0, CopyFromParent, InputOnly,
2466
CopyFromParent, 0, NULL);
2467
XChangeProperty(up->display, newWinList[i], up->atoms._NET_WM_WINDOW_TYPE,
2468
XA_ATOM, 32, PropModeReplace,
2469
(unsigned char *)&up->atoms._NET_WM_WINDOW_TYPE_DOCK, 1);
2470
XChangeProperty(up->display, newWinList[i], up->atoms._NET_WM_DESKTOP,
2471
XA_CARDINAL, 32, PropModeReplace,
2472
(unsigned char *)&allDesktops, 1);
2473
XStoreName(up->display, newWinList[i], strutWindowName);
2474
XMapWindow(up->display, newWinList[i]);
2477
if (up->workAreas) {
2478
USWindowUpdate(up, up->workAreas, newWinList, numStrutInfos);
2480
up->workAreas = USWindowCreate(up, NULL, newWinList, numStrutInfos);
2481
up->workAreas->windowsAreOwned = TRUE;
2486
* Now actually set the _NET_WM_STRUT_PARTIAL property on our special 'struts'
2489
for (i = 0; i < numStrutInfos; i++) {
2492
strutWindow = up->workAreas->windows[i];
2494
XChangeProperty(up->display, strutWindow, up->atoms._NET_WM_STRUT_PARTIAL, XA_CARDINAL,
2495
32, PropModeReplace, (unsigned char *)strutInfos[i], ARRAYSIZE(strutInfos[i]));
2506
*-----------------------------------------------------------------------------
2508
* UnityPlatformGetNumVirtualDesktops --
2510
* Retrieves the number of virtual desktops currently set in the guest.
2513
* Number of desktops.
2518
*-----------------------------------------------------------------------------
2522
UnityPlatformGetNumVirtualDesktops(UnityPlatform *up) // IN
2526
unsigned long itemsReturned;
2527
unsigned long bytesRemaining;
2528
Atom *valueReturned;
2532
if (XGetWindowProperty(up->display, up->rootWindows->windows[0],
2533
up->atoms._NET_NUMBER_OF_DESKTOPS, 0,
2534
1024, False, AnyPropertyType,
2535
&propertyType, &propertyFormat, &itemsReturned,
2536
&bytesRemaining, (unsigned char **)&valueReturned)
2538
&& propertyType == XA_CARDINAL
2539
&& propertyFormat == 32) {
2540
ASSERT(itemsReturned == 1);
2542
retval = valueReturned[0];
2546
XFree(valueReturned);
2553
*-----------------------------------------------------------------------------
2555
* UnityPlatformGetVirtualDesktopLayout --
2557
* Retrieves the guest's current virtual desktop layout info, and stores it in
2558
* 'layoutData' (an array of 4 Atoms).
2561
* Desktop layout stored in 'layoutData'
2566
*-----------------------------------------------------------------------------
2570
UnityPlatformGetVirtualDesktopLayout(UnityPlatform *up, // IN
2571
Atom *layoutData) // OUT
2575
unsigned long itemsReturned;
2576
unsigned long bytesRemaining;
2577
Atom *valueReturned;
2581
layoutData[3] = _NET_WM_TOPLEFT;
2582
if (XGetWindowProperty(up->display, up->rootWindows->windows[0],
2583
up->atoms._NET_DESKTOP_LAYOUT, 0,
2584
1024, False, AnyPropertyType,
2585
&propertyType, &propertyFormat, &itemsReturned,
2586
&bytesRemaining, (unsigned char **)&valueReturned)
2588
&& propertyType == XA_CARDINAL
2589
&& propertyFormat == 32) {
2590
ASSERT(itemsReturned == 3 || itemsReturned == 4);
2594
itemsReturned * sizeof *valueReturned);
2596
layoutData[0] = _NET_WM_ORIENTATION_HORZ;
2600
XFree(valueReturned);
2605
*-----------------------------------------------------------------------------
2607
* UnityPlatformSyncDesktopConfig --
2609
* This routine takes the virtual desktop configuration stored in UnityPlatform and
2610
* makes sure that the guest's actual virtual desktop configuration matches. This is
2611
* done in three situations:
2612
* 1. Updating the guest's virtual desktop config to match the host's, right after
2613
* the host's virtual desktop config has changed.
2614
* 2. Forcing the guest's virtual desktop config back to the host's, right after
2615
* the user uses the guest's pager to alter the guest virtual desktop config.
2616
* 3. Restoring the guest's virtual desktop configuration when exiting Unity mode.
2622
* Guest windows may jump to different virtual desktops if desktops are removed.
2624
*-----------------------------------------------------------------------------
2628
UnityPlatformSyncDesktopConfig(UnityPlatform *up) // IN
2630
Atom data[5] = {0, 0, 0, 0, 0};
2634
if (!up->rootWindows || !up->display) {
2635
return; // This function might be called while not in Unity mode
2638
data[0] = up->desktopInfo.numDesktops;
2639
UnityPlatformSendClientMessage(up,
2640
up->rootWindows->windows[0],
2641
up->rootWindows->windows[0],
2642
up->atoms._NET_NUMBER_OF_DESKTOPS,
2645
XChangeProperty(up->display, up->rootWindows->windows[0],
2646
up->atoms._NET_DESKTOP_LAYOUT, XA_CARDINAL,
2647
32, PropModeReplace, (unsigned char *)up->desktopInfo.layoutData, 4);
2652
*------------------------------------------------------------------------------
2654
* UnityPlatformSetDesktopConfig --
2656
* Set the virtual desktop configuration as specified by the host.
2659
* Returns TRUE if successful, and FALSE otherwise.
2664
*------------------------------------------------------------------------------
2668
UnityPlatformSetDesktopConfig(UnityPlatform *up, // IN
2669
const UnityVirtualDesktopArray *desktopConfig) // IN
2674
UnityVirtualDesktop minDesktop;
2675
UnityVirtualDesktop maxDesktop;
2676
UnityVirtualDesktop desktopSpread;
2677
int unityDesktopLayout[MAX_VIRT_DESK][MAX_VIRT_DESK];
2678
int guestDesktopLayout[MAX_VIRT_DESK][MAX_VIRT_DESK];
2681
ASSERT(desktopConfig);
2682
ASSERT(desktopConfig->desktopCount >= 1);
2685
* This long section of code mainly exists to verify that the host's virtual desktop
2686
* setup can be represented on our end, and to figure out how best to do it. We could
2687
* do this simply, if we didn't have to deal with the possibility of having 5 virtual
2688
* desktops in a 3x2 layout, which is a very real possibility on Linux hosts...
2690
memset(unityDesktopLayout, 0xFF, sizeof unityDesktopLayout); // Set all entries to -1
2691
minDesktop = desktopConfig->desktops[0];
2692
maxDesktop = minDesktop;
2693
for (i = 1; i < desktopConfig->desktopCount; i++) {
2694
if (desktopConfig->desktops[i].x < minDesktop.x) {
2695
minDesktop.x = desktopConfig->desktops[i].x;
2697
if (desktopConfig->desktops[i].y < minDesktop.y) {
2698
minDesktop.y = desktopConfig->desktops[i].y;
2700
if (desktopConfig->desktops[i].x > maxDesktop.x) {
2701
maxDesktop.x = desktopConfig->desktops[i].x;
2703
if (desktopConfig->desktops[i].y > maxDesktop.y) {
2704
maxDesktop.y = desktopConfig->desktops[i].y;
2707
desktopSpread.x = maxDesktop.x - minDesktop.x;
2708
desktopSpread.y = maxDesktop.y - minDesktop.y;
2710
for (i = 0; i < desktopConfig->desktopCount; i++) {
2711
int32 localX = desktopConfig->desktops[i].x - minDesktop.x;
2712
int32 localY = desktopConfig->desktops[i].y - minDesktop.y;
2714
if (localY >= MAX_VIRT_DESK || localX >= MAX_VIRT_DESK) {
2715
Warning("Unity virtual desktop layout has holes that are too big to handle\n");
2719
unityDesktopLayout[localX][localY] = i;
2722
for (x = 0; x < desktopSpread.x; x++) {
2723
for (y = 0; y < desktopSpread.y; y++) {
2724
if (unityDesktopLayout[x][y] < 0) {
2725
Warning("Unity virtual desktop layout has holes that we can't handle.\n");
2732
* Check along the left edge to make sure that there aren't any gaps between virtual
2735
for (x = desktopSpread.x, y = 0; y <= desktopSpread.y; y++) {
2736
if (unityDesktopLayout[x][y] < 0) {
2740
for (; y <= desktopSpread.y; y++) {
2741
if (unityDesktopLayout[x][y] >= 0) {
2742
Warning("Unity virtual desktop layout has holes along the right edge.\n");
2748
* Check along the bottom edge to make sure that there aren't any gaps between virtual
2751
for (y = desktopSpread.y, x = 0; x <= desktopSpread.x; x++) {
2752
if (unityDesktopLayout[x][y] < 0) {
2756
for (; x <= desktopSpread.x; x++) {
2757
if (unityDesktopLayout[x][y] >= 0) {
2758
Warning("Unity virtual desktop layout has holes along the bottom edge.\n");
2764
* Now we know we have a workable virtual desktop layout - let's figure out how to
2765
* communicate it to the window manager & pager.
2767
up->desktopInfo.layoutData[0] = _NET_WM_ORIENTATION_HORZ; // Orientation
2768
up->desktopInfo.layoutData[1] = (desktopSpread.x + 1); // # of columns
2769
up->desktopInfo.layoutData[2] = (desktopSpread.y + 1); // # of rows
2770
up->desktopInfo.layoutData[3] = _NET_WM_TOPLEFT; // Starting corner
2772
if (((desktopSpread.x + 1) * (desktopSpread.y + 1)) >= desktopConfig->desktopCount
2773
&& desktopSpread.x > 0
2774
&& desktopSpread.y > 1
2775
&& unityDesktopLayout[desktopSpread.x][desktopSpread.y - 1] < 0) {
2777
* We know there is are least two holes at the end of the layout, /and/ the holes
2778
* go up the right side, so therefore we need to use vertical orientation for the
2781
up->desktopInfo.layoutData[0] = _NET_WM_ORIENTATION_VERT;
2785
* Figure out what the guest-side desktop IDs will be, based on our chosen
2789
memset(guestDesktopLayout, 0xFF, sizeof guestDesktopLayout); // Set all entries to -1
2790
if (up->desktopInfo.layoutData[0] == _NET_WM_ORIENTATION_HORZ) {
2791
for (y = 0; y <= desktopSpread.y; y++) {
2792
for (x = 0; x <= desktopSpread.x; x++) {
2793
if (unityDesktopLayout[x][y] >= 0) {
2794
guestDesktopLayout[x][y] = i++;
2799
for (x = 0; x <= desktopSpread.x; x++) {
2800
for (y = 0; y <= desktopSpread.y; y++) {
2801
if (unityDesktopLayout[x][y] >= 0) {
2802
guestDesktopLayout[x][y] = i++;
2808
up->desktopInfo.numDesktops = desktopConfig->desktopCount;
2811
* Build tables to translate between guest-side and Unity-side desktop IDs.
2813
up->desktopInfo.guestDesktopToUnity =
2814
Util_SafeRealloc(up->desktopInfo.guestDesktopToUnity,
2815
up->desktopInfo.numDesktops
2816
* sizeof up->desktopInfo.guestDesktopToUnity[0]);
2817
up->desktopInfo.unityDesktopToGuest =
2818
Util_SafeRealloc(up->desktopInfo.unityDesktopToGuest,
2819
up->desktopInfo.numDesktops
2820
* sizeof up->desktopInfo.unityDesktopToGuest[0]);
2821
for (i = 0; i < up->desktopInfo.numDesktops; i++) {
2823
UnityVirtualDesktop curDesk = desktopConfig->desktops[i];
2825
guestNum = guestDesktopLayout[curDesk.x - minDesktop.x][curDesk.y - minDesktop.y];
2826
up->desktopInfo.guestDesktopToUnity[guestNum] = i;
2827
up->desktopInfo.unityDesktopToGuest[i] = guestNum;
2831
* Make the configuration actually take effect.
2833
UnityPlatformSyncDesktopConfig(up);
2840
*------------------------------------------------------------------------------
2842
* UnityPlatformSetInitialDesktop --
2844
* Set a desktop specified by the desktop id as the initial state.
2847
* Returns TRUE if successful, and FALSE otherwise.
2850
* Some windows might be hidden and some shown.
2852
*------------------------------------------------------------------------------
2856
UnityPlatformSetInitialDesktop(UnityPlatform *up, // IN
2857
UnityDesktopId desktopId) // IN
2860
up->desktopInfo.initialDesktop = desktopId;
2861
return UnityPlatformSetDesktopActive(up, desktopId);
2866
*------------------------------------------------------------------------------
2868
* UnityPlatformSetDesktopActive --
2870
* Switch to the specified virtual desktop. The desktopId is an index
2871
* into the desktop configuration array.
2874
* Returns TRUE if successful, and FALSE otherwise.
2879
*------------------------------------------------------------------------------
2883
UnityPlatformSetDesktopActive(UnityPlatform *up, // IN
2884
UnityDesktopId desktopId) // IN
2889
* Update the uwt with the new active desktop info.
2892
UnityWindowTracker_ChangeActiveDesktop(up->tracker, desktopId);
2894
if (desktopId >= up->desktopInfo.numDesktops) {
2898
if (!up->rootWindows) {
2900
* We may not be into Unity mode yet, but we pretend it succeeded, and then do the
2901
* switch later for real.
2906
UnityX11SetCurrentDesktop(up, up->desktopInfo.unityDesktopToGuest[desktopId]);
2913
*-----------------------------------------------------------------------------
2915
* UnityPlatformDoUpdate --
2917
* This function is used to (possibly asynchronously) collect Unity window
2918
* updates and send them to the host via the RPCI update channel.
2921
* Updates will be collected. Updates may be sent.
2926
*-----------------------------------------------------------------------------
2930
UnityPlatformDoUpdate(UnityPlatform *up, // IN:
2931
Bool incremental) // IN: Incremental vs. full update
2934
ASSERT(up->updateChannel);
2937
UnityPlatformUpdateWindowState(up, up->tracker);
2940
UnityWindowTracker_RequestUpdates(up->tracker,
2941
incremental ? UNITY_UPDATE_INCREMENTAL : 0,
2942
&up->updateChannel->updates);
2945
* Notify the host iff UnityWindowTracker_RequestUpdates pushed a valid
2946
* update into the UpdateChannel buffer.
2948
if (DynBuf_GetSize(&up->updateChannel->updates) > (up->updateChannel->cmdSize + 2)) {
2950
const char *dataBuf = DynBuf_Get(&up->updateChannel->updates);
2951
size_t dataSize = DynBuf_GetSize(&up->updateChannel->updates);
2952
ASSERT(dataBuf[up->updateChannel->cmdSize] != '\0');
2953
ASSERT(dataBuf[dataSize - 1] == '\0');
2956
/* The update must be double nul terminated. */
2957
DynBuf_AppendString(&up->updateChannel->updates, "");
2959
if (!UnitySendUpdates(up->updateChannel)) {
2960
/* XXX We should probably exit Unity. */
2961
Debug("UPDATE TRANSMISSION FAILED! --------------------\n");
2963
* At this point, the update buffer contains a stream of updates
2964
* terminated by a double nul. Rather than flush the input stream,
2965
* let's "unseal" it by removing the second nul, allowing further
2966
* updates to be appended and sent later.
2968
DynBuf_SetSize(&up->updateChannel->updates,
2969
DynBuf_GetSize(&up->updateChannel->updates) - 1);
2976
*----------------------------------------------------------------------------
2978
* Unity_UnityToLocalPoint --
2980
* Initializes localPt structure based on the input unityPt structure.
2981
* Translate point from Unity coordinate to local coordinate.
2988
*----------------------------------------------------------------------------
2992
Unity_UnityToLocalPoint(UnityPoint *localPt, // IN/OUT
2993
UnityPoint *unityPt) // IN
2997
localPt->x = unityPt->x;
2998
localPt->y = unityPt->y;
3003
*----------------------------------------------------------------------------
3005
* Unity_LocalToUnityPoint --
3007
* Initializes unityPt structure based on the input localPt structure.
3008
* Translate point from local coordinate to Unity coordinate.
3015
*----------------------------------------------------------------------------
3019
Unity_LocalToUnityPoint(UnityPoint *unityPt, // IN/OUT
3020
UnityPoint *localPt) // IN
3024
unityPt->x = localPt->x;
3025
unityPt->y = localPt->y;
3030
******************************************************************************
3031
* UnityPlatformStickWindow -- */ /**
3033
* @brief "Stick" a window to the desktop.
3035
* @param[in] up Platform context.
3036
* @param[in] windowId Operand window.
3038
* @retval TRUE Success.
3039
* @retval FALSE Failure.
3041
******************************************************************************
3045
UnityPlatformStickWindow(UnityPlatform *up, // IN
3046
UnityWindowId windowId) // IN
3048
return SetWindowStickiness(up, windowId, TRUE);
3053
******************************************************************************
3054
* UnityPlatformUnstickWindow -- */ /**
3056
* @brief "Unstick" a window from the desktop.
3058
* @param[in] up Platform context.
3059
* @param[in] windowId Operand window.
3061
* @retval TRUE Success.
3062
* @retval FALSE Failure.
3064
******************************************************************************
3068
UnityPlatformUnstickWindow(UnityPlatform *up, // IN
3069
UnityWindowId windowId) // IN
3071
return SetWindowStickiness(up, windowId, FALSE);
3076
*-----------------------------------------------------------------------------
3078
* UnityPlatformSetConfigDesktopColor --
3080
* Set the preferred desktop background color for use when in Unity Mode.
3088
*-----------------------------------------------------------------------------
3092
UnityPlatformSetConfigDesktopColor(UnityPlatform *up, int desktopColor)
3099
*-----------------------------------------------------------------------------
3101
* UnityPlatformRequestWindowContents --
3103
* Validate the list of supplied window IDs and once validated add them to a list
3104
* of windows whose contents should be sent to the host.
3112
*-----------------------------------------------------------------------------
3116
UnityPlatformRequestWindowContents(UnityPlatform *up,
3117
UnityWindowId windowIds[],
3118
uint32 numWindowIds)
3122
/* Not implemented */
3128
*-----------------------------------------------------------------------------
3130
* UnityPlatformConfirmMinimizeOperation --
3132
* Minimize a window (if allowed) by the host.
3135
* Returns TRUE if successful, and FALSE otherwise.
3140
*------------------------------------------------------------------------------
3144
UnityPlatformConfirmMinimizeOperation(UnityPlatform *up, // IN
3145
UnityWindowId windowId, // IN
3146
uint32 sequence, // IN
3155
*-----------------------------------------------------------------------------
3157
* UnityPlatformSetInterlockMinimizeOperation --
3159
* Enable (or Disable) the interlocking (relaying) of minimize operations
3168
*------------------------------------------------------------------------------
3171
void UnityPlatformSetInterlockMinimizeOperation(UnityPlatform *up, // IN
3179
*------------------------------------------------------------------------------
3181
* UnityPlatformWillRemoveWindow --
3183
* Called when a window is removed from the UnityWindowTracker.
3185
* NOTE: This function is called with the platform lock held.
3192
*------------------------------------------------------------------------------
3196
UnityPlatformWillRemoveWindow(UnityPlatform *up, // IN
3197
UnityWindowId windowId) // IN
3204
******************************************************************************
3205
* Begin file-scope functions.
3211
******************************************************************************
3212
* GetRelevantWMWindow -- */ /**
3214
* @brief Given a UnityWindowId, return the X11 window relevant to WM operations.
3216
* Starting with a Unity window, look for and return its associated
3217
* clientWindow. If there is no clientWindow, then return the top-level window.
3219
* @param[in] up Unity/X11 context.
3220
* @param[in] windowId Window search for.
3221
* @param[out] wmWindow Set to the relevant X11 window.
3223
* @todo Consider exporting this for use in unityPlatformX11Window.c.
3225
* @retval TRUE Relevant window found and recorded in @a wmWindow.
3226
* @retval FALSE Unable to find @a windowId.
3228
******************************************************************************
3232
GetRelevantWMWindow(UnityPlatform *up, // IN
3233
UnityWindowId windowId, // IN
3234
Window *wmWindow) // OUT
3236
UnityPlatformWindow *upw;
3240
upw = UPWindow_Lookup(up, windowId);
3245
*wmWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
3251
******************************************************************************
3252
* SetWindowStickiness -- */ /**
3254
* @brief Sets or clears a window's sticky state.
3256
* @param[in] up Unity/X11 context.
3257
* @param[in] windowId Operand window.
3258
* @param[in] wantSticky Set to TRUE to stick a window, FALSE to unstick it.
3260
* @retval TRUE Request successfully sent to X server.
3261
* @retval FALSE Request failed.
3263
******************************************************************************
3267
SetWindowStickiness(UnityPlatform *up, // IN
3268
UnityWindowId windowId, // IN
3269
Bool wantSticky) // IN
3271
GdkWindow *gdkWindow;
3276
if (!GetRelevantWMWindow(up, windowId, &curWindow)) {
3277
Debug("%s: Lookup against window %#x failed.\n", __func__, windowId);
3281
gdkWindow = gdk_window_foreign_new(curWindow);
3282
if (gdkWindow == NULL) {
3283
Debug("%s: Unable to create Gdk window?! (%#x)\n", __func__, windowId);
3288
gdk_window_stick(gdkWindow);
3290
gdk_window_unstick(gdkWindow);
3294
g_object_unref(G_OBJECT(gdkWindow));
3302
* End file-scope functions.
3303
******************************************************************************