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.
35
#include <X11/extensions/Xinerama.h>
36
#include <X11/extensions/XTest.h>
39
# include <X11/extensions/Xcomposite.h>
46
} UnityTemporaryEvent;
48
static UnitySpecialWindow *USWindowCreate(UnityPlatform *up,
49
UnitySpecialEventHandler evHandler,
52
static void USWindowUpdate(UnityPlatform *up,
53
UnitySpecialWindow *usw,
56
static UnitySpecialWindow *USWindowLookup(UnityPlatform *up, Window window);
57
static void USWindowDestroy(UnityPlatform *up, UnitySpecialWindow *usw);
59
static void UnityPlatformProcessXEvent(UnityPlatform *up,
61
Window realEventWindow);
62
static Window UnityPlatformGetRealEventWindow(UnityPlatform *up, const XEvent *xevent);
63
static void USRootWindowsProcessEvent(UnityPlatform *up,
64
UnitySpecialWindow *usw,
67
static int UnityPlatformXErrorHandler(Display *dpy, XErrorEvent *xev);
68
static UnitySpecialWindow *UnityPlatformMakeRootWindowsObject(UnityPlatform *up);
70
static void UnityPlatformSendClientMessageFull(Display *d,
77
static void UnityPlatformStackDnDDetWnd(UnityPlatform *up);
78
static void UnityPlatformDnDSendClientMessage(UnityPlatform *up,
86
static Bool GetRelevantWMWindow(UnityPlatform *up,
87
UnityWindowId windowId,
89
static Bool SetWindowStickiness(UnityPlatform *up,
90
UnityWindowId windowId,
92
static UnitySpecialWindow *MakeCompositeOverlaysObject(UnityPlatform *up);
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
UnityHostCallbacks hostCallbacks) // IN:
169
Debug("UnityPlatformInit: Running\n");
171
up = (UnityPlatform*)Util_SafeCalloc(1, sizeof *up);
172
up->tracker = tracker;
173
up->hostCallbacks = hostCallbacks;
175
up->savedScreenSaverTimeout = -1;
178
* Because GDK filters events heavily, and we need to do a lot of low-level X work, we
179
* just open another connection to the same display.
181
displayName = gdk_get_display();
182
up->display = XOpenDisplay(displayName);
185
return NULL; // We couldn't connect to the display for some strange reason
187
XSetErrorHandler(UnityPlatformXErrorHandler);
188
XSynchronize(up->display, TRUE); // So error counting works properly...
191
* Certain applications, like gnome-session during logout, may grab the X
192
* server before displaying a modal window. With the server grabbed, we're
193
* unable to correctly track and display windows.
195
* The following snippet attempts to work around this by using the XTest
196
* extension's ability to make ourselves impervious to X server grabs.
204
if ((XTestQueryExtension(up->display, &dummy1, &dummy2,
205
&major, &minor) == True) &&
206
((major > 2) || (major == 2 && minor >= 2))) {
207
if (XTestGrabControl(up->display, True) != 1) {
208
Debug("XTestGrabControl failed.\n");
211
Debug("XTest extension not available.\n");
215
up->allWindows = HashTable_Alloc(128, HASH_INT_KEY, NULL);
216
up->specialWindows = HashTable_Alloc(32, HASH_INT_KEY, NULL);
217
up->desktopWindow = NULL;
218
up->desktopInfo.initialDesktop = UNITY_X11_INITIALDESKTOP_UNSET;
221
* Find the values of all the atoms
223
# define INIT_ATOM(x) up->atoms.x = XInternAtom(up->display, #x, False)
225
INIT_ATOM(_NET_WM_WINDOW_TYPE);
226
INIT_ATOM(_NET_WM_WINDOW_TYPE_DESKTOP);
227
INIT_ATOM(_NET_WM_WINDOW_TYPE_DOCK);
228
INIT_ATOM(_NET_WM_WINDOW_TYPE_TOOLBAR);
229
INIT_ATOM(_NET_WM_WINDOW_TYPE_TOOLTIP);
230
INIT_ATOM(_NET_WM_WINDOW_TYPE_DROPDOWN_MENU);
231
INIT_ATOM(_NET_WM_WINDOW_TYPE_POPUP_MENU);
232
INIT_ATOM(_NET_WM_WINDOW_TYPE_MENU);
233
INIT_ATOM(_NET_WM_WINDOW_TYPE_UTILITY);
234
INIT_ATOM(_NET_WM_WINDOW_TYPE_SPLASH);
235
INIT_ATOM(_NET_WM_WINDOW_TYPE_DIALOG);
236
INIT_ATOM(_NET_WM_WINDOW_TYPE_NORMAL);
237
INIT_ATOM(_NET_WM_WINDOW_TYPE_DND);
238
INIT_ATOM(_NET_WM_STATE);
239
INIT_ATOM(_NET_WM_STATE_HIDDEN);
240
INIT_ATOM(_NET_WM_STATE_MODAL);
241
INIT_ATOM(_NET_WM_STATE_STICKY);
242
INIT_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
243
INIT_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
244
INIT_ATOM(_NET_WM_STATE_MINIMIZED);
245
INIT_ATOM(_NET_WM_STATE_SHADED);
246
INIT_ATOM(_NET_WM_STATE_SKIP_TASKBAR);
247
INIT_ATOM(_NET_WM_STATE_SKIP_PAGER);
248
INIT_ATOM(_NET_WM_STATE_FULLSCREEN);
249
INIT_ATOM(_NET_WM_STATE_ABOVE);
250
INIT_ATOM(_NET_WM_STATE_BELOW);
251
INIT_ATOM(_NET_WM_STATE_DEMANDS_ATTENTION);
252
INIT_ATOM(_NET_WM_USER_TIME);
253
INIT_ATOM(_NET_WM_USER_TIME_WINDOW);
254
INIT_ATOM(_NET_ACTIVE_WINDOW);
255
INIT_ATOM(_NET_RESTACK_WINDOW);
256
INIT_ATOM(_NET_WM_ICON);
257
INIT_ATOM(_NET_WM_PID);
258
INIT_ATOM(_NET_WM_STRUT);
259
INIT_ATOM(_NET_WM_STRUT_PARTIAL);
260
INIT_ATOM(_NET_MOVERESIZE_WINDOW);
261
INIT_ATOM(_NET_CLOSE_WINDOW);
262
INIT_ATOM(_NET_WM_ALLOWED_ACTIONS);
263
INIT_ATOM(_NET_WM_ACTION_MOVE);
264
INIT_ATOM(_NET_WM_ACTION_RESIZE);
265
INIT_ATOM(_NET_WM_ACTION_MINIMIZE);
266
INIT_ATOM(_NET_WM_ACTION_SHADE);
267
INIT_ATOM(_NET_WM_ACTION_STICK);
268
INIT_ATOM(_NET_WM_ACTION_MAXIMIZE_HORZ);
269
INIT_ATOM(_NET_WM_ACTION_MAXIMIZE_VERT);
270
INIT_ATOM(_NET_WM_ACTION_FULLSCREEN);
271
INIT_ATOM(_NET_WM_ACTION_CHANGE_DESKTOP);
272
INIT_ATOM(_NET_WM_ACTION_CLOSE);
273
INIT_ATOM(_NET_NUMBER_OF_DESKTOPS);
274
INIT_ATOM(_NET_WM_DESKTOP);
275
INIT_ATOM(_NET_CURRENT_DESKTOP);
276
INIT_ATOM(_NET_DESKTOP_LAYOUT);
277
INIT_ATOM(_NET_SUPPORTED);
278
INIT_ATOM(_NET_FRAME_EXTENTS);
280
INIT_ATOM(WM_CLIENT_LEADER);
281
INIT_ATOM(WM_DELETE_WINDOW);
284
INIT_ATOM(WM_PROTOCOLS);
286
INIT_ATOM(WM_TRANSIENT_FOR);
287
INIT_ATOM(WM_WINDOW_ROLE);
288
INIT_ATOM(COMPOUND_TEXT);
289
INIT_ATOM(UTF8_STRING);
293
#if defined(VM_HAVE_X11_SHAPE_EXT)
294
if (!XShapeQueryExtension(up->display, &up->shapeEventBase, &up->shapeErrorBase)) {
295
up->shapeEventBase = 0;
299
up->wpFactory = new vmware::tools::unity::WindowPathFactory(up->display);
306
*----------------------------------------------------------------------------
308
* UnityPlatformCleanup --
310
* One-time platform-specific cleanup code.
318
*----------------------------------------------------------------------------
322
UnityPlatformCleanup(UnityPlatform *up) // IN
329
* Caller should've called Unity_Exit first.
331
ASSERT(!up->isRunning);
332
ASSERT(up->glibSource == NULL);
334
delete up->wpFactory;
336
if (up->specialWindows) {
337
HashTable_Free(up->specialWindows);
338
up->specialWindows = NULL;
340
if (up->allWindows) {
341
HashTable_Free(up->allWindows);
342
up->allWindows = NULL;
346
XCloseDisplay(up->display);
350
up->desktopWindow = NULL;
356
/*****************************************************************************
357
* Unity main loop and event handling *
358
*****************************************************************************/
362
*-----------------------------------------------------------------------------
366
* Creates a new UnitySpecialWindow. Ownership of the 'windows' memory is taken over
367
* by the newly created object, but that memory MUST be malloc'd...
370
* New UnitySpecialWindow object.
375
*-----------------------------------------------------------------------------
378
static UnitySpecialWindow *
379
USWindowCreate(UnityPlatform *up, // IN
380
UnitySpecialEventHandler evHandler, // IN
381
Window *windows, // IN
382
int windowCount) // IN
384
UnitySpecialWindow *usw;
388
usw = (UnitySpecialWindow*)Util_SafeCalloc(1, sizeof *usw);
389
usw->evHandler = evHandler;
390
USWindowUpdate(up, usw, windows, windowCount);
397
*-----------------------------------------------------------------------------
401
* Updates this USWindow with a new list of X windows. Ownership of the 'windows'
402
* memory is taken over by this USWindow object. That memory MUST be malloc'd...
408
* Old window list may be destroyed and freed.
410
*-----------------------------------------------------------------------------
414
USWindowUpdate(UnityPlatform *up, // IN
415
UnitySpecialWindow *usw, // IN
416
Window *windows, // IN
417
int windowCount) // IN
422
for (unsigned int i = 0; i < usw->numWindows; i++) {
423
XSelectInput(up->display, usw->windows[i], 0);
424
HashTable_Delete(up->specialWindows, GUINT_TO_POINTER(usw->windows[i]));
428
usw->windows = windows;
429
usw->numWindows = windowCount;
431
for (int i = 0; i < windowCount; i++) {
432
HashTable_Insert(up->specialWindows, GUINT_TO_POINTER(windows[i]), usw);
438
*-----------------------------------------------------------------------------
442
* Looks up a special window
445
* UnitySpecialWindow object
450
*-----------------------------------------------------------------------------
453
static UnitySpecialWindow *
454
USWindowLookup(UnityPlatform *up, // IN
457
UnitySpecialWindow *retval = NULL;
459
HashTable_Lookup(up->specialWindows, GUINT_TO_POINTER(window), (void **)&retval);
466
*-----------------------------------------------------------------------------
470
* Destroys a UnitySpecialWindow
478
*-----------------------------------------------------------------------------
482
USWindowDestroy(UnityPlatform *up, // IN
483
UnitySpecialWindow *usw) // IN
488
for (unsigned int i = 0; i < usw->numWindows; i++) {
489
HashTable_Delete(up->specialWindows, GUINT_TO_POINTER(usw->windows[i]));
491
if (usw->windowsAreOwned) {
492
XDestroyWindow(up->display, usw->windows[i]);
495
* For now, assume we don't have any special windows that get extension events
496
* and need a call like XScreenSaverSelectInput...
498
XSelectInput(up->display, usw->windows[i], 0);
508
*-----------------------------------------------------------------------------
510
* UnityPlatformMakeRootWindowsObject --
512
* Creates a UnitySpecialWindow to handle the root windows.
518
* Selects for events on the root windows.
520
*-----------------------------------------------------------------------------
523
static UnitySpecialWindow *
524
UnityPlatformMakeRootWindowsObject(UnityPlatform *up) // IN
526
static const long eventMask =
529
| SubstructureNotifyMask
537
numRootWindows = ScreenCount(up->display);
538
ASSERT(numRootWindows > 0);
540
rootWindows = (Window*)Util_SafeCalloc(numRootWindows, sizeof rootWindows[0]);
541
for (i = 0; i < numRootWindows; i++) {
542
rootWindows[i] = RootWindow(up->display, i);
545
for (i = 0; i < numRootWindows; i++) {
546
XSelectInput(up->display, rootWindows[i], eventMask);
549
return USWindowCreate(up, USRootWindowsProcessEvent, rootWindows, numRootWindows);
554
*-----------------------------------------------------------------------------
556
* UnityPlatformGetErrorCount --
558
* Retrieves the current count of X11 errors received by Unity.
561
* Current error count.
566
*-----------------------------------------------------------------------------
570
UnityPlatformGetErrorCount(UnityPlatform *up) // IN
572
return unityX11ErrorCount;
577
*-----------------------------------------------------------------------------
579
* UnityPlatformResetErrorCount --
581
* Resets the Unity X11 error count to zero.
589
*-----------------------------------------------------------------------------
593
UnityPlatformResetErrorCount(UnityPlatform *up) // IN
595
unityX11ErrorCount = 0;
600
*-----------------------------------------------------------------------------
602
* UnityPlatformXErrorHandler --
604
* Handler for all X event errors.
610
* Updates our X11 error counter.
612
*-----------------------------------------------------------------------------
616
UnityPlatformXErrorHandler(Display *dpy, // IN
617
XErrorEvent *xev) // IN
620
XGetErrorText(dpy, xev->error_code, buf, sizeof buf);
621
Debug("> VMwareUserXErrorHandler: error %s on resource %#lx for request %d\n",
622
buf, xev->resourceid, xev->request_code);
624
unityX11ErrorCount++;
631
*-----------------------------------------------------------------------------
633
* UnityPlatformGetServerTime --
635
* Returns an educated guess at the X server's current timestamp
643
*-----------------------------------------------------------------------------
647
UnityPlatformGetServerTime(UnityPlatform *up) // IN
652
gettimeofday(&tv, NULL);
653
retval = up->eventTimeDiff + (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
655
Debug("UserTime is guessed at %lu\n", retval);
662
*-----------------------------------------------------------------------------
666
* Compares two pointers to see whether they're equal.
669
* -1, 0, or 1 (same meaning as strcmp return values)
674
*-----------------------------------------------------------------------------
678
ComparePointers(const void *p1, // IN
679
const void *p2) // IN
682
* Helper function for UnityPlatformKillHelperThreads
684
char** ptr1 = (char**)p1;
685
char** ptr2 = (char**)p2;
686
ptrdiff_t diff = (*ptr2 - *ptr1);
690
} else if (diff > 0) {
699
*----------------------------------------------------------------------------
701
* UnityPlatformExitUnity --
703
* Tears down the Unity "running" state.
709
* Restores system settings.
711
*----------------------------------------------------------------------------
715
UnityPlatformExitUnity(UnityPlatform *up) // IN
717
UnityPlatformWindow **upwList;
718
UnitySpecialWindow **uswList;
722
if (!up || !up->isRunning) {
723
ASSERT(up->glibSource == NULL);
727
UnityX11EventTeardownSource(up);
729
up->desktopInfo.numDesktops = 0; // Zero means host has not set virtual desktop config
730
free(up->desktopInfo.guestDesktopToUnity);
731
up->desktopInfo.guestDesktopToUnity = NULL;
732
free(up->desktopInfo.unityDesktopToGuest);
733
up->desktopInfo.unityDesktopToGuest = NULL;
735
UnityX11RestoreSystemSettings(up);
737
HashTable_ToArray(up->allWindows,
740
qsort(upwList, numWindows, sizeof *upwList, ComparePointers);
741
for (i = 0; i < numWindows; i++) {
742
if (i < (numWindows - 1) && upwList[i] == upwList[i + 1]) {
746
UPWindow_Unref(up, upwList[i]);
750
up->workAreas = NULL;
751
up->rootWindows = NULL;
752
HashTable_ToArray(up->specialWindows,
755
qsort(uswList, numWindows, sizeof *uswList, ComparePointers);
756
for (i = 0; i < numWindows; i++) {
757
if (i < (numWindows - 1) && uswList[i] == uswList[i + 1]) {
761
USWindowDestroy(up, uswList[i]);
765
XSync(up->display, TRUE);
766
up->desktopInfo.initialDesktop = UNITY_X11_INITIALDESKTOP_UNSET;
767
up->isRunning = FALSE;
769
Debug("Leaving unity mode\n");
774
*-----------------------------------------------------------------------------
776
* UnityX11GetWMProtocols --
778
* Updates the list of protocols supported by the window manager.
786
*-----------------------------------------------------------------------------
790
UnityX11GetWMProtocols(UnityPlatform *up) // IN
794
unsigned long itemsReturned;
795
unsigned long bytesRemaining;
796
Atom *valueReturned = NULL;
800
memset(up->wmProtocols, 0, sizeof up->wmProtocols);
801
if (XGetWindowProperty(up->display, up->rootWindows->windows[0],
802
up->atoms._NET_SUPPORTED, 0,
803
1024, False, AnyPropertyType,
804
&propertyType, &propertyFormat, &itemsReturned,
805
&bytesRemaining, (unsigned char **)&valueReturned)
810
if ((propertyType == XA_ATOM || propertyType == XA_CARDINAL)
811
&& propertyFormat == 32) {
814
for (i = 0; i < itemsReturned; i++) {
815
if (valueReturned[i] == up->atoms._NET_MOVERESIZE_WINDOW) {
816
up->wmProtocols[UNITY_X11_WM__NET_MOVERESIZE_WINDOW] = TRUE;
817
} else if (valueReturned[i] == up->atoms._NET_CLOSE_WINDOW) {
818
up->wmProtocols[UNITY_X11_WM__NET_CLOSE_WINDOW] = TRUE;
819
} else if (valueReturned[i] == up->atoms._NET_RESTACK_WINDOW) {
820
up->wmProtocols[UNITY_X11_WM__NET_RESTACK_WINDOW] = TRUE;
821
} else if (valueReturned[i] == up->atoms._NET_ACTIVE_WINDOW) {
822
up->wmProtocols[UNITY_X11_WM__NET_ACTIVE_WINDOW] = TRUE;
823
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_MINIMIZE) {
824
up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_MINIMIZE] = TRUE;
825
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_CLOSE) {
826
up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_CLOSE] = TRUE;
827
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_SHADE) {
828
up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_SHADE] = TRUE;
829
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_STICK) {
830
up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_STICK] = TRUE;
831
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_FULLSCREEN) {
832
up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_FULLSCREEN] = TRUE;
833
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_MAXIMIZE_HORZ) {
834
up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_MAXIMIZE_HORZ] = TRUE;
835
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_MAXIMIZE_VERT) {
836
up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_MAXIMIZE_VERT] = TRUE;
837
} else if (valueReturned[i] == up->atoms._NET_FRAME_EXTENTS) {
838
up->wmProtocols[UNITY_X11_WM__NET_FRAME_EXTENTS] = TRUE;
839
} else if (valueReturned[i] == up->atoms._NET_WM_STRUT_PARTIAL) {
840
up->wmProtocols[UNITY_X11_WM__NET_WM_STRUT_PARTIAL] = TRUE;
841
} else if (valueReturned[i] == up->atoms._NET_WM_STATE_HIDDEN) {
842
up->wmProtocols[UNITY_X11_WM__NET_WM_STATE_HIDDEN] = TRUE;
843
} else if (valueReturned[i] == up->atoms._NET_WM_STATE_MINIMIZED) {
844
up->wmProtocols[UNITY_X11_WM__NET_WM_STATE_MINIMIZED] = TRUE;
849
XFree(valueReturned);
854
*----------------------------------------------------------------------------
856
* UnityPlatformEnterUnity --
858
* Start Unity running.
865
* Saves and changes system settings.
866
* Starts watching for windowing system events.
868
*----------------------------------------------------------------------------
872
UnityPlatformEnterUnity(UnityPlatform *up) // IN
874
UnityDesktopId activeDesktop;
877
ASSERT(up->glibSource == NULL);
879
XSync(up->display, TRUE);
880
up->rootWindows = UnityPlatformMakeRootWindowsObject(up);
881
MakeCompositeOverlaysObject(up);
882
up->isRunning = TRUE;
883
up->eventTimeDiff = 0;
885
UnityX11SaveSystemSettings(up);
887
UnityX11GetWMProtocols(up);
889
if (up->desktopInfo.numDesktops == 0) {
891
* PR 633099: Host UI hasn't set the desktop config yet. In that case,
892
* let's go ahead and initialize our the host:guest desktop mappings
893
* based on the guest's current configuration. (This avoids unnecessarily
894
* changing the guest desktop layout.)
896
* XXX Consider factoring this out of UPSetDesktopConfig.
900
ASSERT(up->desktopInfo.guestDesktopToUnity == NULL);
901
ASSERT(up->desktopInfo.unityDesktopToGuest == NULL);
903
up->desktopInfo.numDesktops = UnityPlatformGetNumVirtualDesktops(up);
904
if (up->desktopInfo.numDesktops == 0) {
905
Warning("%s: _NET_NUMBER_OF_DESKTOPS set to 0; impossible.\n", __FUNCTION__);
909
up->desktopInfo.guestDesktopToUnity = (UnityDesktopId*)
910
Util_SafeMalloc(up->desktopInfo.numDesktops *
911
sizeof up->desktopInfo.guestDesktopToUnity[0]);
912
up->desktopInfo.unityDesktopToGuest = (uint32*)
913
Util_SafeMalloc(up->desktopInfo.numDesktops *
914
sizeof up->desktopInfo.unityDesktopToGuest[0]);
916
for (i = 0; i < up->desktopInfo.numDesktops; i++) {
917
up->desktopInfo.guestDesktopToUnity[i] =
918
up->desktopInfo.unityDesktopToGuest[i] = i;
922
UnityPlatformSyncDesktopConfig(up);
924
if (up->desktopInfo.initialDesktop != UNITY_X11_INITIALDESKTOP_UNSET) {
925
Debug("%s: Setting activeDesktop to initialDesktop (%u).\n", __func__,
926
up->desktopInfo.initialDesktop);
927
activeDesktop = up->desktopInfo.initialDesktop;
929
activeDesktop = UnityWindowTracker_GetActiveDesktop(up->tracker);
931
if (UnityPlatformSetDesktopActive(up, activeDesktop)) {;
933
* XXX Rather than setting this directly here, should we instead wait for a
934
* PropertyNotify event from the window manager to one of the root windows?
935
* Doing so may be safer in that it confirms that our request was honored by
936
* the window manager.
938
UnityWindowTracker_ChangeActiveDesktop(up->tracker, activeDesktop);
941
if (up->needWorkAreas) {
943
* UNEXPECTED: The host called SetDesktopWorkArea before entering Unity mode, so we
944
* need to go back and apply the remembered work area info.
947
UnityPlatformSetDesktopWorkAreas(up, up->needWorkAreas, up->needNumWorkAreas);
948
free(up->needWorkAreas);
949
up->needWorkAreas = NULL;
953
* Set up a callback in the glib main loop to listen for incoming X events on the
954
* unity display connection.
956
UnityX11EventEstablishSource(up);
963
*----------------------------------------------------------------------------
965
* UnityPlatformIsUnityRunning --
967
* Check to see if we are still in the unity mode.
970
* TRUE if we are in Unity mode
976
*----------------------------------------------------------------------------
980
UnityPlatformIsUnityRunning(UnityPlatform *up) // IN
984
return up->isRunning;
989
*----------------------------------------------------------------------------
991
* UnityPlatformLock --
993
* Does nothing - our implementation is not threaded.
1001
*----------------------------------------------------------------------------
1005
UnityPlatformLock(UnityPlatform *up) // IN
1011
*----------------------------------------------------------------------------
1013
* UnityPlatformUnlock --
1015
* Does nothing - our implementation is not threaded.
1023
*----------------------------------------------------------------------------
1027
UnityPlatformUnlock(UnityPlatform *up) // IN
1033
*----------------------------------------------------------------------------
1035
* UnityPlatformUpdateZOrder --
1037
* Push the Z-Order of all windows into the window tracker.
1045
*----------------------------------------------------------------------------
1049
UnityPlatformUpdateZOrder(UnityPlatform *up) // IN
1051
UnityWindowId *elements;
1053
UnityPlatformWindow *curWindow;
1056
if (!up->stackingChanged) {
1060
elements = (UnityWindowId*)alloca(UNITY_MAX_WINDOWS * sizeof elements[0]);
1061
for (numElements = 0, curWindow = up->topWindow;
1062
curWindow; curWindow = curWindow->lowerWindow) {
1063
if (curWindow->isRelevant) {
1064
elements[numElements++] = curWindow->toplevelWindow;
1068
UnityWindowTracker_SetZOrder(up->tracker,
1071
up->stackingChanged = FALSE;
1076
*----------------------------------------------------------------------------
1078
* UnityPlatformUpdateWindowState --
1080
* Walk through /all/ the windows on the guest, pushing everything we know about
1081
* them into the unity window tracker.
1084
* TRUE indicating we need help from the common code to generate
1085
* remove window events (see unity.c)
1090
*----------------------------------------------------------------------------
1094
UnityPlatformUpdateWindowState(UnityPlatform *up, // IN
1095
UnityWindowTracker *tracker) // IN
1097
unsigned int curRoot;
1098
Window lowerWindow = None;
1100
if (!up || !up->rootWindows) {
1101
Debug("BUG: UpdateWindowState was called before we are fully in Unity mode...\n");
1105
for (curRoot = 0; curRoot < up->rootWindows->numWindows; curRoot++) {
1109
unsigned int numChildren;
1111
XQueryTree(up->display, up->rootWindows->windows[curRoot],
1112
&dummyWin, &dummyWin, &children, &numChildren);
1114
for (i = 0; i < numChildren; i++) {
1115
UnityPlatformWindow *upw;
1117
if (!HashTable_Lookup(up->allWindows,
1118
GUINT_TO_POINTER(children[i]),
1120
upw = UPWindow_Create(up, children[i]);
1122
continue; // Window may have disappeared since the XQueryTree
1124
UPWindow_CheckRelevance(up, upw, NULL);
1125
UPWindow_Restack(up, upw, lowerWindow);
1128
lowerWindow = upw->toplevelWindow;
1134
UnityPlatformUpdateZOrder(up);
1136
* up is not populated with the window layout structure when
1137
* UnityPlatformUpdateDnDDetWnd is intially called.
1139
UnityPlatformStackDnDDetWnd(up);
1141
if (up->needTaskbarSetting) {
1142
up->needTaskbarSetting = FALSE;
1144
* This is called in this seemingly random spot to make sure that the taskbar
1145
* visibility is properly set once we have a full picture of the windowing system
1146
* state. Although the routine is called prior to this by SaveSystemSettings(), the
1147
* up->allWindows hash table is not complete until this point, which occurs at a
1148
* random time of the host's choosing.
1150
UnityPlatformSetTaskbarVisible(up, up->currentSettings[UNITY_UI_TASKBAR_VISIBLE]);
1158
*-----------------------------------------------------------------------------
1160
* UnityX11HandleEvents --
1162
* Handle incoming events
1165
* TRUE if the main loop should continue watching for events from the display.
1168
* Events read from the X display and processed.
1170
*-----------------------------------------------------------------------------
1174
UnityX11HandleEvents(gpointer data) // IN
1176
UnityPlatform *up = (UnityPlatform *) data;
1177
GList *incomingEvents = NULL;
1178
Bool restackDetWnd = FALSE;
1181
ASSERT(up->isRunning);
1183
while (XEventsQueued(up->display, QueuedAfterFlush)) {
1185
* This outer loop is here to make sure we really process all available events
1189
while (XEventsQueued(up->display, QueuedAlready)) {
1190
UnityTemporaryEvent *ev;
1192
ev = (UnityTemporaryEvent*)Util_SafeCalloc(1, sizeof *ev);
1193
XNextEvent(up->display, &ev->xevent);
1194
ev->realWindowID = UnityPlatformGetRealEventWindow(up, &ev->xevent);
1197
* Restack dnd detection window when either
1198
* 1. the desktop window may overlap detection window, or
1199
* 2. a window is inserted directly above the desktop (and therefore
1200
* below the DND window).
1202
if (up->desktopWindow &&
1203
ev->xevent.type == ConfigureNotify &&
1204
(up->desktopWindow->toplevelWindow == ev->realWindowID ||
1205
up->desktopWindow->toplevelWindow == ev->xevent.xconfigure.above)) {
1206
restackDetWnd = TRUE;
1209
if (ev->xevent.type == DestroyNotify) {
1211
* Unfortunately, X's event-driven model has an inherent race condition for
1212
* parties that are observing events on windows that are controlled by other
1213
* applications. Basically, if we're processing an event on a window, that
1214
* window may have already been destroyed, and there doesn't seem to really
1215
* be a way to detect this. We just have to try to cut down the probability
1216
* of those as much as possible, by discarding any events on a window if
1217
* they're immediately followed by a DestroyNotify on the same window...
1220
GList *nextItem = NULL;
1222
for (curItem = incomingEvents; curItem; curItem = nextItem) {
1223
UnityTemporaryEvent *otherEvent = (UnityTemporaryEvent*)curItem->data;
1224
nextItem = curItem->next;
1226
if (otherEvent->realWindowID == ev->realWindowID) {
1227
free(curItem->data);
1228
incomingEvents = g_list_remove_link(incomingEvents, curItem);
1233
incomingEvents = g_list_append(incomingEvents, ev);
1236
while (incomingEvents) {
1238
UnityTemporaryEvent *tempEvent = (UnityTemporaryEvent*)incomingEvents->data;
1240
UnityPlatformProcessXEvent(up, &tempEvent->xevent, tempEvent->realWindowID);
1242
nextItem = incomingEvents->next;
1243
free(incomingEvents->data);
1244
g_list_free_1(incomingEvents);
1245
incomingEvents = nextItem;
1248
if (restackDetWnd) {
1249
UnityPlatformStackDnDDetWnd(up);
1251
UnityPlatformUpdateZOrder(up);
1252
UnityPlatformDoUpdate(up, TRUE);
1260
*-----------------------------------------------------------------------------
1262
* UnityPlatformGetEventString --
1264
* Allows stringifying events for debugging purposes
1267
* A stringified version of the event name. It's a static value - do not free this.
1271
*-----------------------------------------------------------------------------
1275
UnityPlatformGetEventString(UnityPlatform *up, // IN
1278
#if defined(VM_HAVE_X11_SHAPE_EXT)
1279
if (up->shapeEventBase
1280
&& type == (up->shapeEventBase + ShapeNotify)) {
1281
return "ShapeNotify";
1286
case KeyPress: return "KeyPress";
1287
case KeyRelease: return "KeyRelease";
1288
case ButtonPress: return "ButtonPress";
1289
case ButtonRelease: return "ButtonRelease";
1290
case MotionNotify: return "MotionNotify";
1291
case EnterNotify: return "EnterNotify";
1292
case LeaveNotify: return "LeaveNotify";
1293
case FocusIn: return "FocusIn";
1294
case FocusOut: return "FocusOut";
1295
case KeymapNotify: return "KeymapNotify";
1296
case Expose: return "Expose";
1297
case GraphicsExpose: return "GraphicsExpose";
1298
case NoExpose: return "NoExpose";
1299
case VisibilityNotify: return "VisibilityNotify";
1300
case CreateNotify: return "CreateNotify";
1301
case DestroyNotify: return "DestroyNotify";
1302
case UnmapNotify: return "UnmapNotify";
1303
case MapNotify: return "MapNotify";
1304
case MapRequest: return "MapRequest";
1305
case ReparentNotify: return "ReparentNotify";
1306
case ConfigureNotify: return "ConfigureNotify";
1307
case ConfigureRequest: return "ConfigureRequest";
1308
case GravityNotify: return "GravityNotify";
1309
case ResizeRequest: return "ResizeRequest";
1310
case CirculateNotify: return "CirculateNotify";
1311
case CirculateRequest: return "CirculateRequest";
1312
case PropertyNotify: return "PropertyNotify";
1313
case SelectionClear: return "SelectionClear";
1314
case SelectionRequest: return "SelectionRequest";
1315
case SelectionNotify: return "SelectionNotify";
1316
case ColormapNotify: return "ColormapNotify";
1317
case ClientMessage: return "ClientMessage";
1318
case MappingNotify: return "MappingNotify";
1319
default: return "<Unknown>";
1325
*-----------------------------------------------------------------------------
1327
* UnityPlatformGetRealEventWindow --
1329
* For debugging purposes, retrieves the window that the event happened on (as
1330
* opposed to the window the event was sent to)
1333
* The window that the event actually happened on.
1338
*-----------------------------------------------------------------------------
1342
UnityPlatformGetRealEventWindow(UnityPlatform *up, // IN
1343
const XEvent *xevent) // IN
1345
#if defined(VM_HAVE_X11_SHAPE_EXT)
1346
if (up->shapeEventBase
1347
&& xevent->type == (up->shapeEventBase + ShapeNotify)) {
1348
XShapeEvent *sev = (XShapeEvent *) xevent;
1354
switch (xevent->type) {
1356
return xevent->xcreatewindow.window;
1359
return xevent->xdestroywindow.window;
1362
return xevent->xmap.window;
1365
return xevent->xunmap.window;
1367
case ReparentNotify:
1368
return xevent->xreparent.window;
1370
case ConfigureNotify:
1371
return xevent->xconfigure.window;
1373
case CirculateNotify:
1374
return xevent->xcirculate.window;
1376
case PropertyNotify:
1377
return xevent->xproperty.window;
1381
return xevent->xfocus.window;
1384
return xevent->xany.window;
1391
*-----------------------------------------------------------------------------
1393
* UnityPlatformUpdateEventTimeDiff --
1395
* Updates our idea of the difference between X server time and our local time.
1401
* Updated event time diff.
1403
*-----------------------------------------------------------------------------
1407
UnityPlatformUpdateEventTimeDiff(UnityPlatform *up, // IN
1408
const XEvent *xevent) // IN
1412
struct timeval localTv;
1414
switch (xevent->type) {
1417
serverTime = xevent->xkey.time;
1421
serverTime = xevent->xbutton.time;
1424
serverTime = xevent->xmotion.time;
1428
serverTime = xevent->xcrossing.time;
1430
case PropertyNotify:
1431
serverTime = xevent->xproperty.time;
1433
case SelectionClear:
1434
serverTime = xevent->xselectionclear.time;
1436
case SelectionRequest:
1437
serverTime = xevent->xselectionrequest.time;
1439
case SelectionNotify:
1440
serverTime = xevent->xselection.time;
1447
gettimeofday(&localTv, NULL);
1448
localTime = (localTv.tv_sec * 1000) + (localTv.tv_usec / 1000); // Convert to ms
1449
up->eventTimeDiff = serverTime - localTime;
1454
*-----------------------------------------------------------------------------
1456
* UnityPlatformProcessXEvent --
1458
* Processes an incoming X event.
1464
* May create or destroy UnityPlatformWindow objects.
1466
*-----------------------------------------------------------------------------
1470
UnityPlatformProcessXEvent(UnityPlatform *up, // IN
1471
const XEvent *xevent, // IN
1472
Window realEventWindow) // IN
1474
UnityPlatformWindow *upw = NULL;
1475
const char *eventName;
1480
UnityPlatformUpdateEventTimeDiff(up, xevent);
1482
eventName = UnityPlatformGetEventString(up, xevent->type);
1483
upw = UPWindow_Lookup(up, realEventWindow);
1485
UnitySpecialWindow *usw = USWindowLookup(up, realEventWindow);
1487
if (usw->evHandler) {
1488
usw->evHandler(up, usw, xevent, realEventWindow);
1492
} else if (xevent->type == CreateNotify) {
1493
/* Ignore decoration widgets. They'll be reparented later. */
1494
if (UnityX11Util_IsWindowDecorationWidget(up, realEventWindow)) {
1495
Debug("%s: Window %#lx is a decoration widget. Ignore it.\n",
1496
__func__, realEventWindow);
1501
* It may be a new window that we don't know about yet. Let's create an object
1504
upw = UPWindow_Create(up, realEventWindow);
1506
UPWindow_CheckRelevance(up, upw, NULL);
1508
Debug("UnityX11ThreadProcessEvent BOMBED:"
1509
" %s on window %#lx (reported to %#lx)\n",
1510
eventName, realEventWindow, xevent->xany.window);
1514
* If we use them on non-CreateNotify events, the above lines of code wind up
1515
* trying to create objects for crazy windows that don't exist...
1517
Debug("Ignoring %s event on unknown window %#lx (reported to %#lx)\n",
1518
eventName, realEventWindow, xevent->xany.window);
1523
UPWindow_ProcessEvent(up, upw, realEventWindow, xevent);
1524
if (upw->deleteWhenSafe) {
1525
Debug("%s: refs %u, deleteWhenSafe %u\n", __func__, upw->refs,
1526
upw->deleteWhenSafe);
1527
UPWindow_Unref(up, upw);
1534
*-----------------------------------------------------------------------------
1536
* UnityPlatformIsRootWindow --
1538
* Checks whether a given window ID is the root window. Necessary because each
1539
* screen has a separate root window, which makes checking a little more complicated
1543
* TRUE if the given window is a root window, FALSE otherwise.
1548
*-----------------------------------------------------------------------------
1552
UnityPlatformIsRootWindow(UnityPlatform *up, // IN
1553
Window window) // IN
1557
return (USWindowLookup(up, window) == up->rootWindows);
1562
*-----------------------------------------------------------------------------
1564
* UnityX11SetCurrentDesktop --
1566
* Sets the active virtual desktop.
1572
* Changes the virtual desktop.
1574
*-----------------------------------------------------------------------------
1578
UnityX11SetCurrentDesktop(UnityPlatform *up, // IN
1579
uint32 currentDesktop) // IN: guest-side desktop ID
1581
Atom data[5] = {0,0,0,0,0};
1584
ASSERT(up->rootWindows->windows);
1586
up->desktopInfo.currentDesktop = currentDesktop;
1587
data[0] = currentDesktop;
1588
data[1] = UnityPlatformGetServerTime(up);
1589
UnityPlatformSendClientMessage(up,
1590
up->rootWindows->windows[0],
1591
up->rootWindows->windows[0],
1592
up->atoms._NET_CURRENT_DESKTOP,
1598
*-----------------------------------------------------------------------------
1600
* UnityX11GetCurrentDesktop --
1602
* Gets the active virtual desktop.
1605
* The active virtual desktop. If it cannot be retrieved for any reason, a
1606
* reasonable default of '0' will be returned.
1611
*-----------------------------------------------------------------------------
1615
UnityX11GetCurrentDesktop(UnityPlatform *up) // IN
1619
unsigned long itemsReturned;
1620
unsigned long bytesRemaining;
1621
Atom *valueReturned;
1622
uint32 currentDesktop;
1625
ASSERT(up->rootWindows);
1627
if (XGetWindowProperty(up->display, up->rootWindows->windows[0],
1628
up->atoms._NET_CURRENT_DESKTOP, 0,
1629
1024, False, AnyPropertyType,
1630
&propertyType, &propertyFormat, &itemsReturned,
1631
&bytesRemaining, (unsigned char **)&valueReturned)
1633
&& propertyType == XA_CARDINAL
1634
&& propertyFormat == 32) {
1635
ASSERT(itemsReturned == 1);
1637
currentDesktop = valueReturned[0];
1641
XFree(valueReturned);
1643
return currentDesktop;
1648
*-----------------------------------------------------------------------------
1650
* USRootWindowsUpdateCurrentDesktop --
1652
* Looks at the root window to figure out the current desktop
1658
* Updates UnityWindowTracker.
1660
*-----------------------------------------------------------------------------
1664
USRootWindowsUpdateCurrentDesktop(UnityPlatform *up, // IN
1665
UnitySpecialWindow *usw, // IN
1666
Window window) // IN
1668
uint32 currentDesktop;
1669
UnityDesktopId unityDesktop;
1672
* XXX right now this is going to break if there are multiple screens in the guest,
1673
* since each one can have an independant 'current' desktop...
1677
currentDesktop = UnityX11GetCurrentDesktop(up);
1679
if (currentDesktop >= up->desktopInfo.numDesktops) {
1680
Warning("Active desktop is out of range for some strange reason\n");
1684
unityDesktop = up->desktopInfo.guestDesktopToUnity[currentDesktop];
1685
Debug("%s: currentDesktop %u, unityDesktop %u\n", __func__, currentDesktop, unityDesktop);
1686
UnityWindowTracker_ChangeActiveDesktop(up->tracker, unityDesktop);
1691
*-----------------------------------------------------------------------------
1693
* USRootWindowsProcessEvent --
1695
* Processes an event that occurred on one of the root windows.
1703
*-----------------------------------------------------------------------------
1707
USRootWindowsProcessEvent(UnityPlatform *up, // IN
1708
UnitySpecialWindow *usw, // IN
1709
const XEvent *xevent, // IN
1710
Window window) // IN
1714
* XXX Do we need to handle situations where the root window changes size? Any other
1717
switch (xevent->type) {
1718
case PropertyNotify:
1719
if (xevent->xproperty.atom == up->atoms._NET_CURRENT_DESKTOP) {
1720
USRootWindowsUpdateCurrentDesktop(up, usw, window);
1721
} else if (xevent->xproperty.atom == up->atoms._NET_NUMBER_OF_DESKTOPS) {
1724
numDesktops = UnityPlatformGetNumVirtualDesktops(up);
1725
if (numDesktops != up->desktopInfo.numDesktops) {
1726
UnityPlatformSyncDesktopConfig(up);
1728
} else if (xevent->xproperty.atom == up->atoms._NET_DESKTOP_LAYOUT) {
1731
UnityPlatformGetVirtualDesktopLayout(up, layoutData);
1732
if (memcmp(layoutData, up->desktopInfo.layoutData, sizeof layoutData) != 0) {
1733
UnityPlatformSyncDesktopConfig(up);
1742
*-----------------------------------------------------------------------------
1744
* UnityPlatformWMProtocolSupported --
1746
* Returns whether the window manager supports a particular protocol.
1749
* TRUE if the protocol is supported, FALSE otherwise.
1754
*-----------------------------------------------------------------------------
1758
UnityPlatformWMProtocolSupported(UnityPlatform *up, // IN
1759
UnityX11WMProtocol proto) // IN
1762
ASSERT(proto < UNITY_X11_MAX_WM_PROTOCOLS);
1764
return up->wmProtocols[proto];
1769
*----------------------------------------------------------------------------
1771
* UnityPlatformSendClientMessageFull --
1773
* Sends an XSendEvent.
1779
*----------------------------------------------------------------------------
1784
UnityPlatformSendClientMessageFull(Display *d, // IN
1785
Window destWindow, // IN: Window to send msg to
1786
Window w, // IN: What the msg's "To:"
1787
// header should be, so to speak.
1788
Atom messageType, // IN
1790
uint numItems, // IN
1791
const void *data) // IN
1793
XClientMessageEvent ev;
1796
memset(&ev, 0, sizeof ev);
1797
ev.type = ClientMessage;
1799
ev.message_type = messageType;
1803
ASSERT(numItems <= ARRAYSIZE(ev.data.b));
1804
for (i = 0; i < numItems; i++) {
1805
const char *datab = (const char*)data;
1806
ev.data.b[i] = datab[i];
1810
ASSERT(numItems <= ARRAYSIZE(ev.data.s));
1811
for (i = 0; i < numItems; i++) {
1812
const short *datas = (const short*)data;
1813
ev.data.s[i] = datas[i];
1817
ASSERT(numItems <= ARRAYSIZE(ev.data.l));
1818
for (i = 0; i < numItems; i++) {
1819
const Atom *datal = (const Atom*)data;
1820
ev.data.l[i] = datal[i];
1824
if (! XSendEvent(d, destWindow, False,
1825
PropertyChangeMask|SubstructureRedirectMask|SubstructureNotifyMask, (XEvent *)&ev)) {
1826
Debug("XSendEvent failed\n");
1831
*-----------------------------------------------------------------------------
1833
* UnityPlatformSendClientMessage --
1835
* Sends an XClientMessageEvent (such as one of the _NET_WM messages)
1843
*-----------------------------------------------------------------------------
1847
UnityPlatformSendClientMessage(UnityPlatform *up, // IN
1848
Window destWindow, // IN: Window to actually send msg to
1849
Window w, // IN: What the msg's "To:" header
1850
// should be, so to speak.
1851
Atom messageType, // IN
1854
const void *data) // IN
1856
UnityPlatformSendClientMessageFull(up->display, destWindow, w, messageType,
1857
format, numItems, data);
1861
/*****************************************************************************
1862
* Misc Unity RPCs that need to be handled *
1863
*****************************************************************************/
1867
*----------------------------------------------------------------------------
1869
* UnityPlatformSetTopWindowGroup --
1871
* Set the group of windows on top of all others.
1880
*----------------------------------------------------------------------------
1884
UnityPlatformSetTopWindowGroup(UnityPlatform *up, // IN: Platform data
1885
UnityWindowId *windows, // IN: array of window ids
1886
unsigned int windowCount) // IN: # of windows in the array
1888
Window sibling = None;
1893
ASSERT(windowCount);
1896
* Restack everything bottom to top.
1898
for (i = 0; i < windowCount; i++) {
1899
UnityPlatformWindow *upw;
1901
Atom data[5] = {0,0,0,0,0};
1903
upw = UPWindow_Lookup(up, windows[i]);
1908
curWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
1909
UPWindow_SetUserTime(up, upw);
1911
if (UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_RESTACK_WINDOW)) {
1912
data[0] = 2; // Magic source indicator to give full control
1916
UnityPlatformSendClientMessage(up, up->rootWindows->windows[0],
1918
up->atoms._NET_RESTACK_WINDOW,
1921
XWindowChanges winch = {0,};
1922
winch.stack_mode = Above;
1923
winch.sibling = sibling;
1924
unsigned int valueMask = CWStackMode;
1926
if (sibling != None) {
1927
valueMask |= CWSibling;
1931
* As of writing, Metacity doesn't support _NET_RESTACK_WINDOW and
1932
* will block our attempt to raise a window unless it's active, so
1933
* we activate the window first.
1935
if (UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_ACTIVE_WINDOW)) {
1936
data[0] = 2; // Magic source indicator to give full control
1937
data[1] = UnityPlatformGetServerTime(up);
1939
UnityPlatformSendClientMessage(up, up->rootWindows->windows[0],
1941
up->atoms._NET_ACTIVE_WINDOW,
1945
XReconfigureWMWindow(up->display, upw->toplevelWindow, 0, valueMask, &winch);
1948
sibling = upw->toplevelWindow;
1951
XSync(up->display, False);
1958
*-----------------------------------------------------------------------------
1960
* UnityPlatformDnDSendClientMessage --
1962
* XXX This is a hack because UnityPlatformSendClientMessage doesn't work
1964
* Sends an XClientMessageEvent (such as one of the _NET_WM messages)
1972
*-----------------------------------------------------------------------------
1976
UnityPlatformDnDSendClientMessage(UnityPlatform *up, // IN
1977
Window destWindow, // IN: Window to send msg to
1978
Window w, // IN: What the msg's "To:"
1979
// header should be, so to speak.
1980
Atom messageType, // IN
1983
const void *data) // IN
1985
UnityPlatformSendClientMessageFull(GDK_DISPLAY(), destWindow, w,
1986
messageType, format, numItems, data);
1991
*----------------------------------------------------------------------------
1993
* UnityPlatformStackDnDDetWnd --
1995
* Updates the stacking order of the dnd detection window.
2003
*----------------------------------------------------------------------------
2007
UnityPlatformStackDnDDetWnd(UnityPlatform *up)
2009
static const Atom onDesktop[] = { 0xFFFFFFFF, 0, 0, 0, 0 };
2011
if (!up->dnd.setMode || !up->dnd.detWnd) {
2012
Debug("%s: DnD not yet initialized.\n", __func__);
2016
if (!up->desktopWindow) {
2017
Debug("Desktop Window not cached. Tracker isn't populated.\n");
2021
/* Show the window on every desktop. */
2022
UnityPlatformDnDSendClientMessage(up,
2023
up->rootWindows->windows[0],
2024
GDK_WINDOW_XWINDOW(up->dnd.detWnd->window),
2025
up->atoms._NET_WM_DESKTOP,
2028
if (up->desktopWindow) {
2030
XSetWindowAttributes sa;
2031
Window desktop = up->desktopWindow->toplevelWindow;
2033
/* Prevent the window manager from managing our detection window. */
2034
sa.override_redirect = True;
2035
XChangeWindowAttributes(GDK_DISPLAY(),
2036
GDK_WINDOW_XWINDOW(up->dnd.detWnd->window),
2037
CWOverrideRedirect, &sa);
2039
/* Resize and restack the detection window. */
2044
ch.sibling = desktop;
2045
ch.stack_mode = Above;
2047
XConfigureWindow(GDK_DISPLAY(), GDK_WINDOW_XWINDOW(up->dnd.detWnd->window),
2048
CWX|CWY|CWWidth|CWHeight|CWStackMode | CWSibling, &ch);
2050
Debug("Restacking dnd detection window.\n");
2053
* Attempt to rely on window manager if we cannot find a window to stack
2056
Atom position[] = { _NET_WM_STATE_ADD,
2057
up->atoms._NET_WM_STATE_STICKY,
2058
up->atoms._NET_WM_STATE_BELOW, 0, 0 };
2060
Debug("Unable to locate desktop window to restack detection window above.\n");
2061
UnityPlatformDnDSendClientMessage(up,
2062
up->rootWindows->windows[0],
2063
GDK_WINDOW_XWINDOW(up->dnd.detWnd->window),
2064
up->atoms._NET_WM_STATE,
2066
XMoveResizeWindow(GDK_DISPLAY(),
2067
GDK_WINDOW_XWINDOW(up->dnd.detWnd->window),
2068
0, 0, 65535, 65535);
2074
*------------------------------------------------------------------------------
2076
* UnityPlatformUpdateDnDDetWnd --
2078
* Shows/hides a full-screen drag detection wnd for unity guest->host DnD.
2086
*------------------------------------------------------------------------------
2090
UnityPlatformUpdateDnDDetWnd(UnityPlatform *up, // IN
2094
if (!up || !up->dnd.setMode || !up->dnd.detWnd) {
2096
* This function may potentially be called during UnityPlatform destruction.
2102
gtk_widget_show(up->dnd.detWnd);
2103
UnityPlatformStackDnDDetWnd(up);
2104
Debug("Showing dnd detection window.\n");
2106
gtk_widget_hide(up->dnd.detWnd);
2107
Debug("Hiding dnd detection window.\n");
2110
up->dnd.setMode(show);
2115
*------------------------------------------------------------------------------
2117
* UnityPlatformSetActiveDnDDetWnd --
2119
* Set current full-screen drag detection wnd. The caller retains ownership
2120
* of the data. The caller is responsible for updating the active dnd det
2129
*------------------------------------------------------------------------------
2133
UnityPlatformSetActiveDnDDetWnd(UnityPlatform *up, // IN
2134
UnityDnD *data) // IN
2141
*------------------------------------------------------------------------------
2143
* UnityPlatformSetDesktopWorkAreas --
2145
* Sets the work areas for all screens.
2153
*------------------------------------------------------------------------------
2157
UnityPlatformSetDesktopWorkAreas(UnityPlatform *up, // IN
2158
UnityRect workAreas[], // IN
2159
uint32 numWorkAreas) // IN
2163
XineramaScreenInfo *screenInfo = NULL;
2165
RegionPtr strutsRegion;
2166
RegionPtr screenRegion;
2167
RegionPtr workAreasRegion;
2168
XID (*strutInfos)[12];
2171
if (!up->rootWindows) {
2173
* We're not in Unity mode yet. Save the info until we are.
2176
up->needWorkAreas = (UnityRect*)Util_SafeMalloc(numWorkAreas * sizeof *up->needWorkAreas);
2177
memcpy(up->needWorkAreas, workAreas, numWorkAreas * sizeof *up->needWorkAreas);
2178
up->needNumWorkAreas = numWorkAreas;
2182
if (!UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_WM_STRUT_PARTIAL)) {
2183
Debug("Window manager does not support _NET_WM_STRUT_PARTIAL - not setting desktop work area.\n");
2188
ASSERT(up->rootWindows);
2191
* Get the geometry of all attached screens. If we're running multi-mon,
2192
* we'll query the Xinerama extension. Otherwise we just fall back to
2193
* examining our root window's geometry.
2196
if (XineramaQueryExtension(up->display, &q, &q)) {
2197
screenInfo = XineramaQueryScreens(up->display, &numScreens);
2208
if (numWorkAreas > 1) {
2209
Debug("Xinerama extension not present, or XineramaQueryScreens failed,"
2210
" but multiple work areas were requested.\n");
2214
if (!XGetGeometry(up->display, up->rootWindows->windows[0], &winDummy,
2215
&rootX, &rootY, &rootWidth, &rootHeight,
2220
screenInfo = (XineramaScreenInfo*)Util_SafeCalloc(1, sizeof *screenInfo);
2223
screenInfo->x_org = rootX;
2224
screenInfo->y_org = rootY;
2225
screenInfo->width = rootWidth;
2226
screenInfo->height = rootHeight;
2229
if ((uint32)numScreens != numWorkAreas) {
2230
Warning("Mismatch between host-specified work areas and available "
2231
"screens. Request dropped.\n");
2237
* New and improved wild'n'crazy scheme to map the host's work area
2238
* coordinates to a collection of struts.
2240
* This implementation depends upon the y-x banded rectangles
2241
* implementation of lib/region.
2243
* In short, here's how things go:
2245
* 1. For each Xinerama screen (or the root window in case we have no
2246
* Xinerama) and host work area, a region is created. A strut
2247
* region is then created by subtracting the work area region from
2248
* the screen region.
2250
* 2. This remaining region will contain between 0 and 4 rectangles,
2251
* each of which will be transformed into a strut window.
2253
* For each of these rectangles, we infer based on their dimensions
2254
* which screen boundary the resulting strut should be bound to.
2256
* a. Boxes touching both the left and right sides of the screen
2257
* are either top or bottom struts, depending on whether they
2258
* also touch the top or bottom edge.
2260
* b. Any remaining box will touch either the left OR the right
2261
* side, but not both. (Such an irregular layout cannot be
2262
* described by the work areas RPC.) That box's strut will
2263
* then be attached to the same side of the screen.
2265
* While also not perfect, this algorithm should do a better job of creating
2266
* struts along their correct sides of a screen than its predecessor. It
2267
* will let us assume the common case that what we define as a strut attached
2268
* to the left or right side really should be attached to the left or right,
2269
* rather than attached to the top or bottom and spanning the height of the
2272
* Pathological case:
2273
* 1. Screen geometry: 1280x960.
2274
* Left strut: 100px wide, 600px tall. Touches top of screen.
2275
* Right strut: 1180px wide, 100px tall. Touches top of screen.
2277
* 2. Note that these struts touch each other. We'd interpret the resulting
2278
* work area as follows:
2280
* Top strut: 1280px wide, 100px tall.
2281
* Left strut: 100px wide, 500px tall, starting from y = 100.
2283
* I believe this sort of layout to be uncommon enough that we can accept
2284
* failure here. If we -really- want to get these things right, then
2285
* we should send strut information explicitly, rather than having the
2286
* guest try to deduce it from work area geometry.
2290
* One strut per screen edge = at most 4 strutInfos.
2292
strutInfos = (XID(*)[12])alloca(4 * sizeof *strutInfos * numScreens);
2293
memset(strutInfos, 0, 4 * sizeof *strutInfos * numScreens);
2296
for (iScreens = 0; iScreens < numScreens; iScreens++) {
2299
xRectangle screenRect;
2300
xRectangle workAreaRect;
2303
* Steps 1a. Create screen, work area regions.
2305
screenRect.x = screenInfo[iScreens].x_org;
2306
screenRect.y = screenInfo[iScreens].y_org;
2307
screenRect.width = screenInfo[iScreens].width;
2308
screenRect.height = screenInfo[iScreens].height;
2309
screenRect.info.type = UpdateRect;
2311
workAreaRect.x = workAreas[iScreens].x;
2312
workAreaRect.y = workAreas[iScreens].y;
2313
workAreaRect.width = workAreas[iScreens].width;
2314
workAreaRect.height = workAreas[iScreens].height;
2315
workAreaRect.info.type = UpdateRect;
2317
screenRegion = miRectsToRegion(1, &screenRect, 0);
2318
workAreasRegion = miRectsToRegion(1, &workAreaRect, 0);
2321
* Step 1b. Create struts region by subtracting work area from screen.
2323
strutsRegion = miRegionCreate(NULL, 0);
2324
miSubtract(strutsRegion, screenRegion, workAreasRegion);
2325
miRegionDestroy(workAreasRegion);
2326
miRegionDestroy(screenRegion);
2329
* Step 2. Transform struts region rectangles into individual struts.
2331
for (iRects = 0; iRects < REGION_NUM_RECTS(strutsRegion);
2332
iRects++, numStrutInfos++) {
2333
BoxPtr p = REGION_RECTS(strutsRegion) + iRects;
2335
#define TOUCHES_LEFT 0x1
2336
#define TOUCHES_RIGHT 0x2
2337
#define TOUCHES_TOP 0x4
2338
#define TOUCHES_BOTTOM 0x8
2340
if (p->x1 == screenRect.x) { bounds |= TOUCHES_LEFT; }
2341
if (p->x2 == screenRect.x + screenRect.width) { bounds |= TOUCHES_RIGHT; }
2342
if (p->y1 == screenRect.y) { bounds |= TOUCHES_TOP; }
2343
if (p->y2 == screenRect.y + screenRect.height) { bounds |= TOUCHES_BOTTOM; }
2346
* strutInfos is passed directly to
2347
* XSetProperty(..._NET_WM_STRUTS_PARTIAL). I.e., look up that
2348
* property's entry in NetWM/wm-spec for more info on the indices.
2350
* I went the switch/case route only because it does a better job
2351
* (for me) of organizing & showing -all- possible cases. YMMV.
2353
* The region code treats rectanges as ranges from [x1,x2) and
2354
* [y1,y2). In other words, x2 and y2 are OUTSIDE the region. I
2355
* guess it makes calculating widths/heights easier. However, the
2356
* strut width/height dimensions are INCLUSIVE, so we'll subtract 1
2357
* from the "end" (as opposed to "start") value.
2359
* (Ex: A 1600x1200 display with a 25px top strut would be marked
2360
* as top = 25, top_start_x = 0, top_end_x = 1599.)
2363
case TOUCHES_LEFT | TOUCHES_RIGHT | TOUCHES_TOP:
2365
strutInfos[numStrutInfos][2] = p->y2 - p->y1;
2366
strutInfos[numStrutInfos][8] = p->x1;
2367
strutInfos[numStrutInfos][9] = p->x2 - 1;
2369
case TOUCHES_LEFT | TOUCHES_RIGHT | TOUCHES_BOTTOM:
2371
strutInfos[numStrutInfos][3] = p->y2 - p->y1;
2372
strutInfos[numStrutInfos][10] = p->x1;
2373
strutInfos[numStrutInfos][11] = p->x2 - 1;
2376
case TOUCHES_LEFT | TOUCHES_TOP:
2377
case TOUCHES_LEFT | TOUCHES_BOTTOM:
2378
case TOUCHES_LEFT | TOUCHES_TOP | TOUCHES_BOTTOM:
2380
strutInfos[numStrutInfos][0] = p->x2 - p->x1;
2381
strutInfos[numStrutInfos][4] = p->y1;
2382
strutInfos[numStrutInfos][5] = p->y2 - 1;
2385
case TOUCHES_RIGHT | TOUCHES_TOP:
2386
case TOUCHES_RIGHT | TOUCHES_BOTTOM:
2387
case TOUCHES_RIGHT | TOUCHES_TOP | TOUCHES_BOTTOM:
2389
strutInfos[numStrutInfos][1] = p->x2 - p->x1;
2390
strutInfos[numStrutInfos][6] = p->y1;
2391
strutInfos[numStrutInfos][7] = p->y2 - 1;
2393
case TOUCHES_LEFT | TOUCHES_RIGHT | TOUCHES_TOP | TOUCHES_BOTTOM:
2394
Warning("%s: Struts occupy entire display.", __func__);
2397
Warning("%s: Irregular strut configuration: bounds %4x\n", __func__, bounds);
2398
miRegionDestroy(strutsRegion);
2404
#undef TOUCHES_RIGHT
2406
#undef TOUCHES_BOTTOM
2408
miRegionDestroy(strutsRegion);
2412
* The first step is making sure we have enough windows in existence to list the
2413
* _NET_WM_STRUT_PARTIAL properties for each screen.
2416
|| up->workAreas->numWindows != numStrutInfos) {
2419
newWinList = (Window*)Util_SafeCalloc(numStrutInfos, sizeof *newWinList);
2420
if (up->workAreas) {
2421
memcpy(newWinList, up->workAreas->windows,
2422
MIN(numStrutInfos, up->workAreas->numWindows) * sizeof *newWinList);
2426
* Destroy unneeded windows
2428
for (i = numStrutInfos; i < (up->workAreas ? up->workAreas->numWindows : 0); i++) {
2429
XDestroyWindow(up->display, up->workAreas->windows[i]);
2433
* Create additional windows as needed.
2435
for (i = up->workAreas ? up->workAreas->numWindows : 0; i < numStrutInfos; i++) {
2436
static const char strutWindowName[] = "vmware-user workarea struts";
2437
Atom allDesktops = -1;
2438
newWinList[i] = XCreateWindow(up->display, up->rootWindows->windows[0],
2439
-50, -50, 1, 1, 0, CopyFromParent, InputOnly,
2440
CopyFromParent, 0, NULL);
2441
XChangeProperty(up->display, newWinList[i], up->atoms._NET_WM_WINDOW_TYPE,
2442
XA_ATOM, 32, PropModeReplace,
2443
(unsigned char *)&up->atoms._NET_WM_WINDOW_TYPE_DOCK, 1);
2444
XChangeProperty(up->display, newWinList[i], up->atoms._NET_WM_DESKTOP,
2445
XA_CARDINAL, 32, PropModeReplace,
2446
(unsigned char *)&allDesktops, 1);
2447
XStoreName(up->display, newWinList[i], strutWindowName);
2448
XMapWindow(up->display, newWinList[i]);
2451
if (up->workAreas) {
2452
USWindowUpdate(up, up->workAreas, newWinList, numStrutInfos);
2454
up->workAreas = USWindowCreate(up, NULL, newWinList, numStrutInfos);
2455
up->workAreas->windowsAreOwned = TRUE;
2460
* Now actually set the _NET_WM_STRUT_PARTIAL property on our special 'struts'
2463
for (i = 0; i < numStrutInfos; i++) {
2466
strutWindow = up->workAreas->windows[i];
2468
XChangeProperty(up->display, strutWindow, up->atoms._NET_WM_STRUT_PARTIAL, XA_CARDINAL,
2469
32, PropModeReplace, (unsigned char *)strutInfos[i], ARRAYSIZE(strutInfos[i]));
2480
*-----------------------------------------------------------------------------
2482
* UnityPlatformGetNumVirtualDesktops --
2484
* Retrieves the number of virtual desktops currently set in the guest.
2487
* Number of desktops.
2492
*-----------------------------------------------------------------------------
2496
UnityPlatformGetNumVirtualDesktops(UnityPlatform *up) // IN
2500
unsigned long itemsReturned;
2501
unsigned long bytesRemaining;
2502
Atom *valueReturned;
2506
if (XGetWindowProperty(up->display, up->rootWindows->windows[0],
2507
up->atoms._NET_NUMBER_OF_DESKTOPS, 0,
2508
1024, False, AnyPropertyType,
2509
&propertyType, &propertyFormat, &itemsReturned,
2510
&bytesRemaining, (unsigned char **)&valueReturned)
2512
&& propertyType == XA_CARDINAL
2513
&& propertyFormat == 32) {
2514
ASSERT(itemsReturned == 1);
2516
retval = valueReturned[0];
2520
XFree(valueReturned);
2527
*-----------------------------------------------------------------------------
2529
* UnityPlatformGetVirtualDesktopLayout --
2531
* Retrieves the guest's current virtual desktop layout info, and stores it in
2532
* 'layoutData' (an array of 4 Atoms).
2535
* Desktop layout stored in 'layoutData'
2540
*-----------------------------------------------------------------------------
2544
UnityPlatformGetVirtualDesktopLayout(UnityPlatform *up, // IN
2545
Atom *layoutData) // OUT
2549
unsigned long itemsReturned;
2550
unsigned long bytesRemaining;
2551
Atom *valueReturned;
2555
layoutData[3] = _NET_WM_TOPLEFT;
2556
if (XGetWindowProperty(up->display, up->rootWindows->windows[0],
2557
up->atoms._NET_DESKTOP_LAYOUT, 0,
2558
1024, False, AnyPropertyType,
2559
&propertyType, &propertyFormat, &itemsReturned,
2560
&bytesRemaining, (unsigned char **)&valueReturned)
2562
&& propertyType == XA_CARDINAL
2563
&& propertyFormat == 32) {
2564
ASSERT(itemsReturned == 3 || itemsReturned == 4);
2568
itemsReturned * sizeof *valueReturned);
2570
layoutData[0] = _NET_WM_ORIENTATION_HORZ;
2574
XFree(valueReturned);
2579
*-----------------------------------------------------------------------------
2581
* UnityPlatformSyncDesktopConfig --
2583
* This routine takes the virtual desktop configuration stored in UnityPlatform and
2584
* makes sure that the guest's actual virtual desktop configuration matches. This is
2585
* done in three situations:
2586
* 1. Updating the guest's virtual desktop config to match the host's, right after
2587
* the host's virtual desktop config has changed.
2588
* 2. Forcing the guest's virtual desktop config back to the host's, right after
2589
* the user uses the guest's pager to alter the guest virtual desktop config.
2590
* 3. Restoring the guest's virtual desktop configuration when exiting Unity mode.
2596
* Guest windows may jump to different virtual desktops if desktops are removed.
2598
*-----------------------------------------------------------------------------
2602
UnityPlatformSyncDesktopConfig(UnityPlatform *up) // IN
2604
Atom data[5] = {0, 0, 0, 0, 0};
2608
if (!up->rootWindows || !up->display) {
2609
return; // This function might be called while not in Unity mode
2612
data[0] = up->desktopInfo.numDesktops;
2613
UnityPlatformSendClientMessage(up,
2614
up->rootWindows->windows[0],
2615
up->rootWindows->windows[0],
2616
up->atoms._NET_NUMBER_OF_DESKTOPS,
2619
XChangeProperty(up->display, up->rootWindows->windows[0],
2620
up->atoms._NET_DESKTOP_LAYOUT, XA_CARDINAL,
2621
32, PropModeReplace, (unsigned char *)up->desktopInfo.layoutData, 4);
2626
*------------------------------------------------------------------------------
2628
* UnityPlatformSetDesktopConfig --
2630
* Set the virtual desktop configuration as specified by the host.
2633
* Returns TRUE if successful, and FALSE otherwise.
2638
*------------------------------------------------------------------------------
2642
UnityPlatformSetDesktopConfig(UnityPlatform *up, // IN
2643
const UnityVirtualDesktopArray *desktopConfig) // IN
2648
UnityVirtualDesktop minDesktop;
2649
UnityVirtualDesktop maxDesktop;
2650
UnityVirtualDesktop desktopSpread;
2651
int unityDesktopLayout[MAX_VIRT_DESK][MAX_VIRT_DESK];
2652
int guestDesktopLayout[MAX_VIRT_DESK][MAX_VIRT_DESK];
2655
ASSERT(desktopConfig);
2656
ASSERT(desktopConfig->desktopCount >= 1);
2659
* This long section of code mainly exists to verify that the host's virtual desktop
2660
* setup can be represented on our end, and to figure out how best to do it. We could
2661
* do this simply, if we didn't have to deal with the possibility of having 5 virtual
2662
* desktops in a 3x2 layout, which is a very real possibility on Linux hosts...
2664
memset(unityDesktopLayout, 0xFF, sizeof unityDesktopLayout); // Set all entries to -1
2665
minDesktop = desktopConfig->desktops[0];
2666
maxDesktop = minDesktop;
2667
for (i = 1; i < desktopConfig->desktopCount; i++) {
2668
if (desktopConfig->desktops[i].x < minDesktop.x) {
2669
minDesktop.x = desktopConfig->desktops[i].x;
2671
if (desktopConfig->desktops[i].y < minDesktop.y) {
2672
minDesktop.y = desktopConfig->desktops[i].y;
2674
if (desktopConfig->desktops[i].x > maxDesktop.x) {
2675
maxDesktop.x = desktopConfig->desktops[i].x;
2677
if (desktopConfig->desktops[i].y > maxDesktop.y) {
2678
maxDesktop.y = desktopConfig->desktops[i].y;
2681
desktopSpread.x = maxDesktop.x - minDesktop.x;
2682
desktopSpread.y = maxDesktop.y - minDesktop.y;
2684
for (i = 0; i < desktopConfig->desktopCount; i++) {
2685
int32 localX = desktopConfig->desktops[i].x - minDesktop.x;
2686
int32 localY = desktopConfig->desktops[i].y - minDesktop.y;
2688
if (localY >= MAX_VIRT_DESK || localX >= MAX_VIRT_DESK) {
2689
Warning("Unity virtual desktop layout has holes that are too big to handle\n");
2693
unityDesktopLayout[localX][localY] = i;
2696
for (x = 0; x < desktopSpread.x; x++) {
2697
for (y = 0; y < desktopSpread.y; y++) {
2698
if (unityDesktopLayout[x][y] < 0) {
2699
Warning("Unity virtual desktop layout has holes that we can't handle.\n");
2706
* Check along the left edge to make sure that there aren't any gaps between virtual
2709
for (x = desktopSpread.x, y = 0; y <= desktopSpread.y; y++) {
2710
if (unityDesktopLayout[x][y] < 0) {
2714
for (; y <= desktopSpread.y; y++) {
2715
if (unityDesktopLayout[x][y] >= 0) {
2716
Warning("Unity virtual desktop layout has holes along the right edge.\n");
2722
* Check along the bottom edge to make sure that there aren't any gaps between virtual
2725
for (y = desktopSpread.y, x = 0; x <= desktopSpread.x; x++) {
2726
if (unityDesktopLayout[x][y] < 0) {
2730
for (; x <= desktopSpread.x; x++) {
2731
if (unityDesktopLayout[x][y] >= 0) {
2732
Warning("Unity virtual desktop layout has holes along the bottom edge.\n");
2738
* Now we know we have a workable virtual desktop layout - let's figure out how to
2739
* communicate it to the window manager & pager.
2741
up->desktopInfo.layoutData[0] = _NET_WM_ORIENTATION_HORZ; // Orientation
2742
up->desktopInfo.layoutData[1] = (desktopSpread.x + 1); // # of columns
2743
up->desktopInfo.layoutData[2] = (desktopSpread.y + 1); // # of rows
2744
up->desktopInfo.layoutData[3] = _NET_WM_TOPLEFT; // Starting corner
2746
if (((desktopSpread.x + 1) * (desktopSpread.y + 1)) >= (int)desktopConfig->desktopCount
2747
&& desktopSpread.x > 0
2748
&& desktopSpread.y > 1
2749
&& unityDesktopLayout[desktopSpread.x][desktopSpread.y - 1] < 0) {
2751
* We know there is are least two holes at the end of the layout, /and/ the holes
2752
* go up the right side, so therefore we need to use vertical orientation for the
2755
up->desktopInfo.layoutData[0] = _NET_WM_ORIENTATION_VERT;
2759
* Figure out what the guest-side desktop IDs will be, based on our chosen
2763
memset(guestDesktopLayout, 0xFF, sizeof guestDesktopLayout); // Set all entries to -1
2764
if (up->desktopInfo.layoutData[0] == _NET_WM_ORIENTATION_HORZ) {
2765
for (y = 0; y <= desktopSpread.y; y++) {
2766
for (x = 0; x <= desktopSpread.x; x++) {
2767
if (unityDesktopLayout[x][y] >= 0) {
2768
guestDesktopLayout[x][y] = i++;
2773
for (x = 0; x <= desktopSpread.x; x++) {
2774
for (y = 0; y <= desktopSpread.y; y++) {
2775
if (unityDesktopLayout[x][y] >= 0) {
2776
guestDesktopLayout[x][y] = i++;
2782
up->desktopInfo.numDesktops = desktopConfig->desktopCount;
2785
* Build tables to translate between guest-side and Unity-side desktop IDs.
2787
up->desktopInfo.guestDesktopToUnity = (UnityDesktopId*)
2788
Util_SafeRealloc(up->desktopInfo.guestDesktopToUnity,
2789
up->desktopInfo.numDesktops
2790
* sizeof up->desktopInfo.guestDesktopToUnity[0]);
2791
up->desktopInfo.unityDesktopToGuest = (uint32*)
2792
Util_SafeRealloc(up->desktopInfo.unityDesktopToGuest,
2793
up->desktopInfo.numDesktops
2794
* sizeof up->desktopInfo.unityDesktopToGuest[0]);
2795
for (i = 0; i < up->desktopInfo.numDesktops; i++) {
2797
UnityVirtualDesktop curDesk = desktopConfig->desktops[i];
2799
guestNum = guestDesktopLayout[curDesk.x - minDesktop.x][curDesk.y - minDesktop.y];
2800
up->desktopInfo.guestDesktopToUnity[guestNum] = i;
2801
up->desktopInfo.unityDesktopToGuest[i] = guestNum;
2805
* Make the configuration actually take effect.
2807
UnityPlatformSyncDesktopConfig(up);
2814
*------------------------------------------------------------------------------
2816
* UnityPlatformSetInitialDesktop --
2818
* Set a desktop specified by the desktop id as the initial state.
2821
* Returns TRUE if successful, and FALSE otherwise.
2824
* Some windows might be hidden and some shown.
2826
*------------------------------------------------------------------------------
2830
UnityPlatformSetInitialDesktop(UnityPlatform *up, // IN
2831
UnityDesktopId desktopId) // IN
2834
up->desktopInfo.initialDesktop = desktopId;
2835
return UnityPlatformSetDesktopActive(up, desktopId);
2840
*------------------------------------------------------------------------------
2842
* UnityPlatformSetDesktopActive --
2844
* Switch to the specified virtual desktop. The desktopId is an index
2845
* into the desktop configuration array.
2848
* Returns TRUE if successful, and FALSE otherwise.
2853
*------------------------------------------------------------------------------
2857
UnityPlatformSetDesktopActive(UnityPlatform *up, // IN
2858
UnityDesktopId desktopId) // IN
2863
* Update the uwt with the new active desktop info.
2866
UnityWindowTracker_ChangeActiveDesktop(up->tracker, desktopId);
2868
if (desktopId >= (UnityDesktopId)up->desktopInfo.numDesktops) {
2872
if (!up->rootWindows) {
2874
* We may not be into Unity mode yet, but we pretend it succeeded, and then do the
2875
* switch later for real.
2880
UnityX11SetCurrentDesktop(up, up->desktopInfo.unityDesktopToGuest[desktopId]);
2887
*-----------------------------------------------------------------------------
2889
* UnityPlatformDoUpdate --
2891
* This function is used to (possibly asynchronously) collect Unity window
2892
* updates and send them to the host via the RPCI update channel.
2895
* Updates will be collected. Updates may be sent.
2900
*-----------------------------------------------------------------------------
2904
UnityPlatformDoUpdate(UnityPlatform *up, // IN:
2905
Bool incremental) // IN: Incremental vs. full update
2912
flags |= UNITY_UPDATE_INCREMENTAL;
2915
* Only update the window state for full updates. Incremental updates can be
2916
* satisfied by the current state in the tracker.
2918
UnityPlatformUpdateWindowState(up, up->tracker);
2921
up->hostCallbacks.buildUpdateCB(up->hostCallbacks.updateCbCtx, flags);
2926
*----------------------------------------------------------------------------
2928
* Unity_UnityToLocalPoint --
2930
* Initializes localPt structure based on the input unityPt structure.
2931
* Translate point from Unity coordinate to local coordinate.
2938
*----------------------------------------------------------------------------
2942
Unity_UnityToLocalPoint(UnityPoint *localPt, // IN/OUT
2943
UnityPoint *unityPt) // IN
2947
localPt->x = unityPt->x;
2948
localPt->y = unityPt->y;
2953
*----------------------------------------------------------------------------
2955
* Unity_LocalToUnityPoint --
2957
* Initializes unityPt structure based on the input localPt structure.
2958
* Translate point from local coordinate to Unity coordinate.
2965
*----------------------------------------------------------------------------
2969
Unity_LocalToUnityPoint(UnityPoint *unityPt, // IN/OUT
2970
UnityPoint *localPt) // IN
2974
unityPt->x = localPt->x;
2975
unityPt->y = localPt->y;
2980
******************************************************************************
2981
* UnityPlatformStickWindow -- */ /**
2983
* @brief "Stick" a window to the desktop.
2985
* @param[in] up Platform context.
2986
* @param[in] windowId Operand window.
2988
* @retval TRUE Success.
2989
* @retval FALSE Failure.
2991
******************************************************************************
2995
UnityPlatformStickWindow(UnityPlatform *up, // IN
2996
UnityWindowId windowId) // IN
2998
return SetWindowStickiness(up, windowId, TRUE);
3003
******************************************************************************
3004
* UnityPlatformUnstickWindow -- */ /**
3006
* @brief "Unstick" a window from the desktop.
3008
* @param[in] up Platform context.
3009
* @param[in] windowId Operand window.
3011
* @retval TRUE Success.
3012
* @retval FALSE Failure.
3014
******************************************************************************
3018
UnityPlatformUnstickWindow(UnityPlatform *up, // IN
3019
UnityWindowId windowId) // IN
3021
return SetWindowStickiness(up, windowId, FALSE);
3026
*-----------------------------------------------------------------------------
3028
* UnityPlatformSetConfigDesktopColor --
3030
* Set the preferred desktop background color for use when in Unity Mode.
3038
*-----------------------------------------------------------------------------
3042
UnityPlatformSetConfigDesktopColor(UnityPlatform *up, int desktopColor)
3049
*-----------------------------------------------------------------------------
3051
* UnityPlatformRequestWindowContents --
3053
* Validate the list of supplied window IDs and once validated add them to a list
3054
* of windows whose contents should be sent to the host.
3062
*-----------------------------------------------------------------------------
3066
UnityPlatformRequestWindowContents(UnityPlatform *up,
3067
UnityWindowId windowIds[],
3068
uint32 numWindowIds)
3072
/* Not implemented */
3078
*-----------------------------------------------------------------------------
3080
* UnityPlatformConfirmMinimizeOperation --
3082
* Minimize a window (if allowed) by the host.
3085
* Returns TRUE if successful, and FALSE otherwise.
3090
*------------------------------------------------------------------------------
3094
UnityPlatformConfirmMinimizeOperation(UnityPlatform *up, // IN
3095
UnityWindowId windowId, // IN
3096
uint32 sequence, // IN
3105
*-----------------------------------------------------------------------------
3107
* UnityPlatformSetInterlockMinimizeOperation --
3109
* Enable (or Disable) the interlocking (relaying) of minimize operations
3118
*------------------------------------------------------------------------------
3121
void UnityPlatformSetInterlockMinimizeOperation(UnityPlatform *up, // IN
3129
*-----------------------------------------------------------------------------
3131
* UnityPlatformSetDisableCompositing --
3133
* Disable (or Enable) the compositing features of the window manager the
3134
* next time Unity starts.
3142
*------------------------------------------------------------------------------
3145
void UnityPlatformSetDisableCompositing(UnityPlatform *up, // IN
3146
Bool disabled) // IN
3153
******************************************************************************
3154
* Begin file-scope functions.
3160
******************************************************************************
3161
* GetRelevantWMWindow -- */ /**
3163
* @brief Given a UnityWindowId, return the X11 window relevant to WM operations.
3165
* Starting with a Unity window, look for and return its associated
3166
* clientWindow. If there is no clientWindow, then return the top-level window.
3168
* @param[in] up Unity/X11 context.
3169
* @param[in] windowId Window search for.
3170
* @param[out] wmWindow Set to the relevant X11 window.
3172
* @todo Consider exporting this for use in unityPlatformX11Window.c.
3174
* @retval TRUE Relevant window found and recorded in @a wmWindow.
3175
* @retval FALSE Unable to find @a windowId.
3177
******************************************************************************
3181
GetRelevantWMWindow(UnityPlatform *up, // IN
3182
UnityWindowId windowId, // IN
3183
Window *wmWindow) // OUT
3185
UnityPlatformWindow *upw;
3189
upw = UPWindow_Lookup(up, windowId);
3194
*wmWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
3200
******************************************************************************
3201
* SetWindowStickiness -- */ /**
3203
* @brief Sets or clears a window's sticky state.
3205
* @param[in] up Unity/X11 context.
3206
* @param[in] windowId Operand window.
3207
* @param[in] wantSticky Set to TRUE to stick a window, FALSE to unstick it.
3209
* @retval TRUE Request successfully sent to X server.
3210
* @retval FALSE Request failed.
3212
******************************************************************************
3216
SetWindowStickiness(UnityPlatform *up, // IN
3217
UnityWindowId windowId, // IN
3218
Bool wantSticky) // IN
3220
GdkWindow *gdkWindow;
3225
if (!GetRelevantWMWindow(up, windowId, &curWindow)) {
3226
Debug("%s: Lookup against window %#x failed.\n", __func__, windowId);
3230
gdkWindow = gdk_window_foreign_new(curWindow);
3231
if (gdkWindow == NULL) {
3232
Debug("%s: Unable to create Gdk window?! (%#x)\n", __func__, windowId);
3237
gdk_window_stick(gdkWindow);
3239
gdk_window_unstick(gdkWindow);
3243
g_object_unref(G_OBJECT(gdkWindow));
3250
*-----------------------------------------------------------------------------
3252
* UnityPlatformSendMouseWheel --
3254
* Sends the given mouse wheel event to the window at the given location.
3257
* Returns TRUE if successful, and FALSE otherwise.
3262
*------------------------------------------------------------------------------
3266
UnityPlatformSendMouseWheel(UnityPlatform *up, // IN
3270
uint32 modifierFlags) // IN
3278
*-----------------------------------------------------------------------------
3280
* MakeCompositeOverlaysObject --
3282
* Probes X server for any composite overlay windows. If found, they're
3283
* monitored as UnitySpecialWindows whereby we won't mistakenly place them
3284
* in the global window tracker.
3287
* Returns pointer to new UnitySpecialWindow on success, NULL on failure.
3290
* If overlay windows haven't yet been mapped, they will be (temporarily).
3292
* Caller doesn't need to free returned UnitySpecialWindow*. That's handled
3293
* automatically when exiting Unity.
3295
*-----------------------------------------------------------------------------
3298
static UnitySpecialWindow *
3299
MakeCompositeOverlaysObject(UnityPlatform *up) // IN
3302
ASSERT(up->rootWindows);
3304
#ifndef NO_XCOMPOSITE
3307
if (XCompositeQueryExtension(up->display, &eventBase, &errorBase)) {
3309
* XCompositeGetOverlayWindow didn't appear until XComposite 0.3.
3313
XCompositeQueryVersion(up->display, &major, &minor);
3314
if (major > 0 || (major == 0 && minor >= 3)) {
3315
size_t nWindows = up->rootWindows->numWindows;
3316
Window *overlays = (Window*)Util_SafeCalloc(nWindows, sizeof *overlays);
3317
for (unsigned int i = 0; i < nWindows; i++) {
3318
overlays[i] = XCompositeGetOverlayWindow(up->display,
3319
up->rootWindows->windows[i]);
3320
XCompositeReleaseOverlayWindow(up->display, overlays[i]);
3324
* Note 1: See above. Caller doesn't need to need to track this explicitly.
3325
* Note 2: The NULL event handler parameter is how we tell the X event handling
3326
* pieces to ignore this window, thereby keeping it out of the window
3329
return USWindowCreate(up, NULL, overlays, nWindows);
3332
#endif // ifndef NO_XCOMPOSITE
3339
* End file-scope functions.
3340
******************************************************************************