1
/*********************************************************
2
* Copyright (C) 2007-2010 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
* unityPlatformX11Window.c --
22
* Implementation of Unity for guest operating systems that use the X11 windowing
23
* system. This file implements per-window operations (move, minimize, etc.)
30
#include "imageUtil.h"
32
#include <sys/types.h>
41
#include "ghIntegration.h"
43
using vmware::tools::unity::WindowPathFactory;
48
static Bool UnityPlatformFindWindows(UnityPlatform *up,
50
Window *toplevelWindow,
53
static Bool UPWindowPushFullUpdate(UnityPlatform *up, UnityPlatformWindow *upw);
54
static void UPWindowSetRelevance(UnityPlatform *up,
55
UnityPlatformWindow *upw,
57
static void UPWindowUpdateActions(UnityPlatform *up, UnityPlatformWindow *upw);
58
static void UPWindowUpdateDesktop(UnityPlatform *up, UnityPlatformWindow *upw);
59
static void UPWindowUpdateIcon(UnityPlatform *up, UnityPlatformWindow *upw);
60
static void UPWindowUpdateProtocols(UnityPlatform *up, UnityPlatformWindow *upw);
61
#if defined(VM_HAVE_X11_SHAPE_EXT)
62
static void UPWindowUpdateShape(UnityPlatform *up, UnityPlatformWindow *upw);
64
static void UPWindowUpdateState(UnityPlatform *up,
65
UnityPlatformWindow *upw,
66
const XPropertyEvent *xevent);
67
static void UPWindowUpdateTitle(UnityPlatform *up, UnityPlatformWindow *upw);
68
static void UPWindowUpdateType(UnityPlatform *up, UnityPlatformWindow *upw);
69
static void UPWindowProcessConfigureEvent(UnityPlatform *up,
70
UnityPlatformWindow *upw,
71
const XEvent *xevent);
72
static void UPWindowProcessPropertyEvent(UnityPlatform *up,
73
UnityPlatformWindow *upw,
74
const XEvent *xevent);
75
static void UPWindowProcessShapeEvent(UnityPlatform *up,
76
UnityPlatformWindow *upw,
77
const XEvent *xevent);
78
static Bool UPWindowGetDesktop(UnityPlatform *up,
79
UnityPlatformWindow *upw,
81
static void UPWindowSetWindows(UnityPlatform *up,
82
UnityPlatformWindow *upw,
83
Window toplevelWindow,
85
static void UPWindowUpdateFrameExtents(UnityPlatform *up,
86
UnityPlatformWindow *upw);
91
*-----------------------------------------------------------------------------
93
* CompareStackingOrder --
95
* Very crudely compares the stacking orders of "relevant" windows as kept
96
* by the X server and ourselves. (By relevant, we mean only windows which
97
* are relayed to the window tracker.)
99
* If there's a mismatch, Debug() statements are generated showing which
100
* indices do not match and the corresponding window IDs. If there is a match,
101
* then the current stacking order is displayed. (The latter is useless on
102
* its own, but it's a handy bit of data to refer to when a mismatch is
106
* Additional noise is sent to the Tools log via Debug().
111
*-----------------------------------------------------------------------------
115
CompareStackingOrder(UnityPlatform *up, // IN
116
Window rootWindow, // IN
117
const char *callerName) // IN
119
Window *relevantUChildren = NULL;
120
Window *relevantXChildren = NULL;
121
Window *trackerChildren = NULL;
123
unsigned int numXRelevant; // relevant windows from the X server
124
unsigned int numURelevant; // relevant windows according to Unity
125
unsigned int nWindows; // Generic limit referring to all of *children variables
126
// after we determine that they are all the same
127
// size. Likely that it will be optimized out.
128
GList *unityList = NULL;
131
* First query the X server for a list of its top-level windows sorted
132
* from bottom to top stacking order.
137
Window *children = NULL;
138
unsigned int nchildren;
140
if (!XQueryTree(up->display, rootWindow, &dummyroot, &dummyparent,
141
&children, &nchildren)) {
142
Debug("%s: XQueryTree failed\n", __func__);
147
* Now, filter out all of the relevant top-level windows into a local buffer
150
relevantXChildren = g_new(Window, nchildren);
152
for (i = 0, numXRelevant = 0; i < nchildren; i++) {
153
UnityPlatformWindow *tmpupw;
154
tmpupw = UPWindow_Lookup(up, children[i]);
155
if (tmpupw && tmpupw->isRelevant) {
156
relevantXChildren[numXRelevant++] = children[i];
164
* Do the same as above but for the windows known to Unity. These lists should
165
* -usually- match, but may get out of sync when a window disappears, for example.
166
* However, it's also -usually- only a matter of time before subsequent events show
167
* up and bring them back into sync.
169
* Note that this list is created by -prepending- windows. This is done because
170
* while we store windows in top-bottom stacking order, the X server maintains
171
* windows in bottom-top stacking order. For ease of comparison, I'm reversing
172
* our order in order to match the X server.
175
UnityPlatformWindow *myupw;
176
for (myupw = up->topWindow, numURelevant = 0;
178
myupw = myupw->lowerWindow) {
179
if (myupw->isRelevant) {
180
unityList = g_list_prepend(unityList, (gpointer)myupw->toplevelWindow);
187
* The following check ensures that all three window collections are the same
188
* size. With that in mind, for the sake of readability I'll use a variable,
189
* nWindows, to refer to this common size through the remainer of the function.
191
if (numURelevant != numXRelevant ||
192
numURelevant != up->tracker->count) {
193
Debug("%s: mismatch (count): server %u, unity %u, uwt %u\n", __func__,
194
numXRelevant, numURelevant, up->tracker->count);
198
nWindows = numURelevant;
201
* We're now sure that all sets of windows to be compared are the same size.
202
* Go ahead and allocate and populate new arrays for window set comparisons.
205
relevantUChildren = g_new(Window, nWindows);
206
trackerChildren = g_new(Window, nWindows);
209
* Convert the now sorted (see above re: g_list_prepend) Unity window list to
210
* an array for easy comparison with * the X server's array.
214
for (listIter = unityList, i = 0;
216
listIter = listIter->next, i++) {
217
relevantUChildren[i] = (Window)listIter->data;
222
* Once again, UWT stores windows in top-bottom stacking order, but we're
223
* comparing an array in bottom-top stacking order. This loop just copies
224
* and reverses the UWT's zorder array.
226
for (i = 0; i < nWindows; i++) {
227
trackerChildren[i] = up->tracker->zorder[(nWindows - 1) - i];
231
size_t childrenSize = nWindows * sizeof *relevantUChildren;
233
if (memcmp(relevantXChildren, relevantUChildren, childrenSize) ||
234
memcmp(relevantXChildren, trackerChildren, childrenSize)) {
235
Debug("%s: mismatch!\n", callerName);
236
Debug("%s: %8s %10s %10s %10s\n", callerName, "index", "X Server",
239
for (i = 0; i < nWindows; i++) {
240
if (relevantXChildren[i] != relevantUChildren[i] ||
241
relevantXChildren[i] != trackerChildren[i]) {
242
Debug("%s: [%6u] %#10lx %#10lx %#10lx\n", callerName, i,
243
relevantXChildren[i], relevantUChildren[i],
248
Debug("%s: match (%u windows).\n", callerName, nWindows);
249
for (i = 0; i < nWindows; i++) {
250
Debug("%s: [%u] %#lx\n", callerName, i, relevantXChildren[i]);
256
g_free(relevantXChildren);
257
g_free(relevantUChildren);
258
g_free(trackerChildren);
259
g_list_free(unityList);
265
*-----------------------------------------------------------------------------
267
* UnityPlatformFindClientWindow --
269
* In X, the immediate children of the root window are almost always window manager
270
* windows that hold the app's windows. Sometimes we want to find the actual app's
271
* window to operate on, usually identfied by the WM_STATE property. Given a random
272
* window ID, this function figures out which is which.
275
* TRUE if successful, FALSE otherwise.
277
*-----------------------------------------------------------------------------
281
UnityPlatformFindWindows(UnityPlatform *up, // IN
282
Window currentWindow, // IN
283
Window *toplevelWindow, // OUT
284
Window *clientWindow, // OUT
285
Window *rootWindow) // OUT
291
Window *children = NULL;
292
unsigned int numChildren;
296
unsigned long itemsReturned;
297
unsigned long bytesRemaining;
298
unsigned char *valueReturned = NULL;
301
ASSERT(toplevelWindow);
302
ASSERT(clientWindow);
305
/* Check for the WM_STATE property on the window */
306
UnityPlatformResetErrorCount(up);
307
XGetWindowProperty(up->display, (Window)currentWindow, up->atoms.WM_STATE, 0,
308
1024, False, AnyPropertyType,
309
&propertyType, &propertyFormat, &itemsReturned,
310
&bytesRemaining, &valueReturned);
311
XFree(valueReturned);
312
if (UnityPlatformGetErrorCount(up)) {
313
Debug("Retrieving WM_STATE failed\n");
317
XQueryTree(up->display, currentWindow, &rootWin, &parentWin,
318
&children, &numChildren);
319
if (UnityPlatformGetErrorCount(up)) {
320
Debug("XQueryTree failed\n");
324
if (propertyType != None) {
326
* If WM_STATE exists on this window, we were given a client window
328
*clientWindow = currentWindow;
329
*rootWindow = rootWin;
335
* This loop ensures that parentWin is the direct child of the root.
337
* XXX this will break for any window managers that use subwindows to implement
340
while (parentWin != rootWin) {
341
currentWindow = parentWin;
343
XQueryTree(up->display, currentWindow, &rootWin,
344
&parentWin, &children, &numChildren);
348
*toplevelWindow = currentWindow;
351
} else if (parentWin == rootWin) {
356
* Do a breadth-first search down the window tree to find the child that has the
359
ASSERT(UnityPlatformIsRootWindow(up, rootWin));
361
*toplevelWindow = currentWindow;
362
*rootWindow = rootWin;
363
*clientWindow = None;
365
windowQueue = g_queue_new();
367
while (numChildren || !g_queue_is_empty(windowQueue)) {
370
for (i = 0; i < numChildren; i++) {
371
g_queue_push_tail(windowQueue, GUINT_TO_POINTER(children[i]));
376
childWindow = GPOINTER_TO_UINT(g_queue_pop_head(windowQueue));
379
valueReturned = NULL;
381
XGetWindowProperty(up->display, childWindow, up->atoms.WM_STATE, 0,
382
1024, False, AnyPropertyType,
383
&propertyType, &propertyFormat, &itemsReturned,
384
&bytesRemaining, &valueReturned);
385
XFree(valueReturned);
387
if (UnityPlatformGetErrorCount(up)) {
388
g_queue_free(windowQueue);
389
Debug("Getting WM_STATE on a child failed\n");
394
*clientWindow = childWindow;
398
XQueryTree(up->display, childWindow, &rootWin,
399
&parentWin, &children, &numChildren);
400
if (UnityPlatformGetErrorCount(up)) {
401
g_queue_free(windowQueue);
402
Debug("XQueryTree failed\n");
407
g_queue_free(windowQueue);
410
} /* else, retval is FALSE */
414
if (retval && (*toplevelWindow == *rootWindow || *clientWindow == *rootWindow)) {
415
Panic("Creating a UnityPlatformWindow of a root window is a big error\n");
423
*-----------------------------------------------------------------------------
425
* UPWindowSetWindows --
427
* Updates the X11 windows that a UnityPlatformWindow represents. Used mainly if a
428
* window is created or reparented.
434
* Updates internal Unity state.
436
*-----------------------------------------------------------------------------
440
UPWindowSetWindows(UnityPlatform *up, // IN
441
UnityPlatformWindow *upw, // IN
442
Window toplevelWindow, // IN
443
Window clientWindow) // IN
445
UnityPlatformWindow *scratchUpw;
451
wasRelevant = upw->isRelevant;
453
Debug("%s: %#lx::%#lx -> %#lx::%#lx\n", __func__, upw->toplevelWindow,
454
upw->clientWindow, toplevelWindow, clientWindow);
455
UPWindowSetRelevance(up, upw, FALSE);
456
if (upw->toplevelWindow) {
457
XSelectInput(up->display, upw->toplevelWindow, 0);
458
HashTable_Delete(up->allWindows, GUINT_TO_POINTER(upw->toplevelWindow));
460
if (upw->clientWindow) {
461
XSelectInput(up->display, upw->clientWindow, 0);
462
HashTable_Delete(up->allWindows, GUINT_TO_POINTER(upw->clientWindow));
464
#if defined(VM_HAVE_X11_SHAPE_EXT)
465
if (up->shapeEventBase) {
466
XShapeSelectInput(up->display, upw->toplevelWindow, 0);
468
if (upw->clientWindow) {
469
XShapeSelectInput(up->display, upw->clientWindow, 0);
475
* Okay, now we may have two UnityPlatformWindows running around, one each for
476
* the top-level and client windows in response to their CreateNotify events,
477
* and this routine wishes to unify both in a single UPW.
479
* XXX The current course of action is this:
480
* 1. If either our operand top-level or client windows belong to
481
* any other UnityPlatformWindows, said UPWs will be dereferenced.
482
* 2. We'll then assign the operand windows to the current UPW.
484
scratchUpw = UPWindow_Lookup(up, toplevelWindow);
485
if (scratchUpw && scratchUpw != upw) {
486
UPWindow_Unref(up, scratchUpw);
488
scratchUpw = UPWindow_Lookup(up, clientWindow);
489
if (scratchUpw && scratchUpw != upw) {
490
UPWindow_Unref(up, scratchUpw);
493
upw->toplevelWindow = toplevelWindow;
494
upw->clientWindow = clientWindow;
497
* Start listening to events on this window. We want these even if the window is of no
498
* interest to us, because the specified events may make the window interesting to us.
501
XSelectInput(up->display, clientWindow, PropertyChangeMask | StructureNotifyMask);
504
XSelectInput(up->display,
506
FocusChangeMask | PropertyChangeMask | StructureNotifyMask);
508
#if defined(VM_HAVE_X11_SHAPE_EXT)
509
if (up->shapeEventBase) {
510
XShapeSelectInput(up->display, toplevelWindow, ShapeNotifyMask);
512
if (upw->clientWindow) {
513
XShapeSelectInput(up->display, upw->clientWindow, ShapeNotifyMask);
518
HashTable_Insert(up->allWindows, GUINT_TO_POINTER(upw->toplevelWindow), upw);
519
if (upw->clientWindow) {
520
HashTable_Insert(up->allWindows, GUINT_TO_POINTER(upw->clientWindow), upw);
522
UPWindowSetRelevance(up, upw, wasRelevant);
527
*-----------------------------------------------------------------------------
531
* Creates a UnityPlatformWindow for the specified UnityWindowId. The resulting
532
* object will have a reference count of 1 that is owned by the caller.
535
* The newly created UnityPlatformWindow.
540
*-----------------------------------------------------------------------------
543
UnityPlatformWindow *
544
UPWindow_Create(UnityPlatform *up, // IN
547
UnityPlatformWindow *upw;
548
Window toplevelWindow;
553
ASSERT(window != None);
555
if (!UnityPlatformFindWindows(up, window,
556
&toplevelWindow, &clientWindow, &rootWindow)) {
557
Debug("FindWindows failed on %#lx\n", window);
561
if (HashTable_Lookup(up->allWindows,
562
GUINT_TO_POINTER(toplevelWindow),
564
Debug("Lookup of window %#lx returned %#lx\n",
565
toplevelWindow, upw->toplevelWindow);
569
if (HashTable_Lookup(up->allWindows,
570
GUINT_TO_POINTER(clientWindow),
572
Debug("Lookup of clientWindow %#lx returned existing toplevel %#lx\n",
573
clientWindow, upw->toplevelWindow);
577
upw = (UnityPlatformWindow*)Util_SafeCalloc(1, sizeof *upw);
580
Debug("Creating new window for %#lx/%#lx/%#lx\n",
581
toplevelWindow, clientWindow, rootWindow);
582
upw->rootWindow = rootWindow;
583
for (upw->screenNumber = 0;
584
upw->screenNumber < (int)up->rootWindows->numWindows
585
&& up->rootWindows->windows[upw->screenNumber] != rootWindow;
586
upw->screenNumber++);
587
DynBuf_Init(&upw->iconPng.data);
588
DynBuf_SetSize(&upw->iconPng.data, 0);
590
UPWindowSetWindows(up, upw, toplevelWindow, clientWindow);
593
* Put newly created windows on the top of the stack by default.
595
upw->higherWindow = NULL;
596
upw->lowerWindow = up->topWindow;
597
if (upw->lowerWindow) {
598
upw->lowerWindow->higherWindow = upw;
607
*-----------------------------------------------------------------------------
611
* Increases the reference count on the UnityPlatformWindow object by one.
619
*-----------------------------------------------------------------------------
623
UPWindow_Ref(UnityPlatform *up, // IN
624
UnityPlatformWindow *upw) // IN
631
*-----------------------------------------------------------------------------
635
* Decreases the reference count on the UnityPlatformWindow object by one.
641
* May destroy the object if no references remain.
643
*-----------------------------------------------------------------------------
647
UPWindow_Unref(UnityPlatform *up, // IN
648
UnityPlatformWindow *upw) // IN
652
if (upw->refs <= 0) { // Window needs destroying
653
UPWindowSetRelevance(up, upw, FALSE);
656
* Filter out windows that have been already destroyed on the X11 side, but which
657
* still may have had refcounts active.
659
if (upw->windowType != UNITY_WINDOW_TYPE_NONE) {
660
XSelectInput(up->display, upw->toplevelWindow, 0);
662
#if defined(VM_HAVE_X11_SHAPE_EXT)
663
if (up->shapeEventBase) {
664
XShapeSelectInput(up->display, upw->toplevelWindow, 0);
668
if (upw->clientWindow) {
669
XSelectInput(up->display, upw->clientWindow, 0);
673
HashTable_Delete(up->allWindows, GUINT_TO_POINTER(upw->toplevelWindow));
674
if (upw->clientWindow) {
675
HashTable_Delete(up->allWindows, GUINT_TO_POINTER(upw->clientWindow));
678
DynBuf_Destroy(&upw->iconPng.data);
680
if (upw->higherWindow) {
681
upw->higherWindow->lowerWindow = upw->lowerWindow;
683
if (upw->lowerWindow) {
684
upw->lowerWindow->higherWindow = upw->higherWindow;
686
if (upw == up->topWindow) {
687
up->topWindow = upw->lowerWindow;
696
*-----------------------------------------------------------------------------
700
* Retrieves the UnityPlatformWindow object associated with a given Window ID
703
* The UnityPlatformWindow object, or NULL if it was not found
708
*-----------------------------------------------------------------------------
711
UnityPlatformWindow *
712
UPWindow_Lookup(UnityPlatform *up, // IN
715
UnityPlatformWindow *retval = NULL;
717
HashTable_Lookup(up->allWindows, GUINT_TO_POINTER(window), (void **)&retval);
722
#if 0 // Very useful if ever debugging the window stacking code, but slow otherwise.
724
*-----------------------------------------------------------------------------
726
* UPWindowCheckStack --
728
* Sanity check on the linked list of windows for Z-ordering.
734
* May ASSERT() if things are broken.
736
*-----------------------------------------------------------------------------
740
UPWindowCheckStack(UnityPlatform *up)
742
UnityPlatformWindow **upwList;
745
UnityPlatformWindow *curWindow;
747
HashTable_ToArray(up->allWindows,
750
for (i = 0; i < numWindows; i++) {
751
for (curWindow = up->topWindow;
753
curWindow = curWindow->lowerWindow) {
754
if (curWindow == upwList[i]) {
759
if (curWindow != upwList[i]) {
760
Debug("%s: Wanted %p. Complete window stack is: ", __FUNCTION__, upwList[i]);
761
for (curWindow = up->topWindow;
763
curWindow = curWindow->lowerWindow) {
764
if (curWindow == upwList[i]) {
765
Debug("%p ->", curWindow);
767
Debug("[%p] ->", curWindow);
772
Debug("%s: Window stack downwards from %p: ", __FUNCTION__, upwList[i]);
773
for (curWindow = upwList[i];
775
curWindow = curWindow->lowerWindow) {
776
if (curWindow == upwList[i]) {
777
Debug("[%p] ->", curWindow);
779
Debug("%p ->", curWindow);
784
Debug("%s: Window stack upwards from %p: ", __FUNCTION__, upwList[i]);
785
for (curWindow = upwList[i];
787
curWindow = curWindow->higherWindow) {
788
if (curWindow == upwList[i]) {
789
Debug("[%p] <-", curWindow);
791
Debug("%p <-", curWindow);
797
ASSERT(curWindow == upwList[i]);
799
for (curWindow = up->topWindow;
801
curWindow = curWindow->lowerWindow) {
802
for (i = 0; i < numWindows; i++) {
803
if (curWindow == upwList[i]) {
807
ASSERT(i < numWindows);
815
*-----------------------------------------------------------------------------
817
* UPWindowCheckCycle --
819
* Checks to make sure there are no loops in the window stack.
827
*-----------------------------------------------------------------------------
831
UPWindowCheckCycle(UnityPlatform *up)
833
UnityPlatformWindow *upw;
834
UnityPlatformWindow *curWindow;
836
for (upw = up->topWindow; upw; upw = upw->lowerWindow) {
837
for (curWindow = upw->lowerWindow; curWindow; curWindow = curWindow->lowerWindow) {
838
ASSERT(curWindow != upw);
842
for (upw = up->topWindow; upw->lowerWindow; upw = upw->lowerWindow) {
843
/* Find lowest window */
846
for (; upw; upw = upw->higherWindow) {
847
for (curWindow = upw->higherWindow; curWindow; curWindow = curWindow->higherWindow) {
848
ASSERT(curWindow != upw);
856
*-----------------------------------------------------------------------------
858
* UPWindow_Restack --
860
* Changes the Z order list of the specified window so it is
861
* immediately above another window.
867
* Updates UnityWindowTracker with the latest ZOrder.
869
*-----------------------------------------------------------------------------
873
UPWindow_Restack(UnityPlatform *up, // IN
874
UnityPlatformWindow *upw, // IN
875
Window above) // IN - None indicates stack at bottom
877
UnityPlatformWindow *newLowerWindow = NULL;
883
newLowerWindow = UPWindow_Lookup(up, above);
885
if (!newLowerWindow) {
886
if (upw != up->topWindow) {
887
Debug("%s: Couldn't find the window to stack above [%#lx].\n",
895
ASSERT(newLowerWindow != upw);
897
if (newLowerWindow != upw->lowerWindow) {
899
* Stacking order has changed. Move this window to the right place in the stack.
901
* 1. Remove 'upw' from the old location in the linked list.
902
* 2. Find the 'upw' that it is now above.
903
* 3. Insert it into the right location in the list.
906
ASSERT(upw->higherWindow != upw);
907
ASSERT(upw->lowerWindow != upw);
908
if (upw->higherWindow) {
909
upw->higherWindow->lowerWindow = upw->lowerWindow;
911
up->topWindow = upw->lowerWindow;
914
ASSERT(upw->higherWindow != upw);
915
ASSERT(upw->lowerWindow != upw);
916
if (upw->lowerWindow) {
917
upw->lowerWindow->higherWindow = upw->higherWindow;
919
upw->higherWindow = NULL;
920
upw->lowerWindow = NULL;
922
ASSERT(upw->higherWindow != upw);
923
ASSERT(upw->lowerWindow != upw);
924
upw->lowerWindow = newLowerWindow;
925
if (newLowerWindow) {
926
upw->higherWindow = newLowerWindow->higherWindow;
927
upw->lowerWindow->higherWindow = upw;
928
ASSERT(newLowerWindow != upw);
931
* This window is meant to go to the bottom of the stack.
933
upw->lowerWindow = NULL;
934
upw->higherWindow = up->topWindow;
936
while (upw->higherWindow && upw->higherWindow->lowerWindow) {
937
upw->higherWindow = upw->higherWindow->lowerWindow;
939
ASSERT(newLowerWindow != upw);
942
ASSERT(newLowerWindow != upw);
943
ASSERT(upw->higherWindow != upw);
944
ASSERT(upw->lowerWindow != upw);
945
if (upw->higherWindow) {
946
ASSERT(upw->higherWindow->lowerWindow == newLowerWindow);
947
upw->higherWindow->lowerWindow = upw;
952
ASSERT(upw->higherWindow != upw);
953
ASSERT(upw->lowerWindow != upw);
954
if (upw->isRelevant) {
955
up->stackingChanged = TRUE;
956
Debug("Stacking order has changed\n");
963
*-----------------------------------------------------------------------------
965
* UPWindowSetRelevance --
967
* Changes the "relevance" of a particular window. Normally, the decision of whether
968
* to do this should be made only by CheckRelevance().
974
* May add or remove the window in UnityWindowTracker.
976
*-----------------------------------------------------------------------------
980
UPWindowSetRelevance(UnityPlatform *up, // IN
981
UnityPlatformWindow *upw, // IN
982
Bool isRelevant) // IN
984
if ((isRelevant && upw->isRelevant) || (!isRelevant && !upw->isRelevant)) {
988
upw->isRelevant = isRelevant;
993
DynBuf_Init(&windowPath);
994
DynBuf_Init(&execPath);
996
if (upw->windowType == UNITY_WINDOW_TYPE_NORMAL) {
998
retval = UnityPlatformGetWindowPath(up,
1003
Debug("GetWindowPath didn't know how to identify the window...\n");
1007
Debug("Adding window %#lx to tracker\n", upw->toplevelWindow);
1008
UnityWindowTracker_AddWindowWithData(up->tracker,
1009
upw->toplevelWindow,
1013
DynBuf_Destroy(&windowPath);
1014
DynBuf_Destroy(&execPath);
1016
UPWindowPushFullUpdate(up, upw);
1018
Debug("Removing window %#lx from tracker\n", upw->toplevelWindow);
1019
UnityWindowTracker_RemoveWindow(up->tracker, upw->toplevelWindow);
1020
UnityPlatformDoUpdate(up, TRUE);
1023
up->stackingChanged = TRUE;
1028
*-----------------------------------------------------------------------------
1030
* UPWindow_CheckRelevance --
1032
* Looks at the current state of a window to figure out whether we want to relay it
1033
* through UnityWindowTracker.
1039
* Updates various cached metadata in UnityPlatformWindow, such as windowType and
1040
* isOverrideRedirect.
1042
*-----------------------------------------------------------------------------
1046
UPWindow_CheckRelevance(UnityPlatform *up, // IN
1047
UnityPlatformWindow *upw, // IN
1048
const XEvent *motivator) // IN - optional
1050
XWindowAttributes winAttr;
1051
int shouldBeRelevant = -1;
1052
Bool regetDesktop = FALSE;
1056
* We have an event that may have modified the relevance of this window. See what
1059
switch (motivator->type) {
1060
case PropertyNotify:
1062
XPropertyEvent *event = (XPropertyEvent *)motivator;
1063
if (upw->waitingForWmState &&
1064
event->atom == up->atoms.WM_STATE &&
1065
event->state == PropertyNewValue) {
1066
Window toplevelWindow = 0;
1067
Window clientWindow = 0;
1068
Window rootWindow = 0;
1071
regetDesktop = TRUE;
1072
Debug("%s: PropertyNotify: New WM_STATE on %#lx (current upw: %#lx::%#lx)\n",
1073
__func__, event->window, upw->toplevelWindow, upw->clientWindow);
1074
success = UnityPlatformFindWindows(up, event->window,
1075
&toplevelWindow, &clientWindow,
1078
UPWindowSetWindows(up, upw, toplevelWindow, clientWindow);
1079
upw->waitingForWmState = FALSE;
1080
Debug("%s: PropertyNotify: new upw: %#lx::%#lx\n",
1081
__func__, upw->toplevelWindow, upw->clientWindow);
1083
Debug("%s: PropertyNotify: FindWindows failed again!\n", __func__);
1086
} else if (event->atom == up->atoms.WM_WINDOW_ROLE &&
1087
event->state == PropertyNewValue &&
1088
UnityX11Util_IsWindowDecorationWidget(up, upw->toplevelWindow)) {
1089
Debug("%s: Window %#lx is a decoration widget. Ignore it.\n",
1090
__func__, upw->toplevelWindow);
1091
upw->deleteWhenSafe = TRUE;
1093
} else if (event->atom == up->atoms._NET_WM_DESKTOP) {
1094
if (upw->wantSetDesktopNumberOnUnmap) {
1096
* We're to preserve _NET_WM_DESKTOP across unmapping and remapping a
1097
* window (most likely a taskbar). If we see PropertyDelete, assume
1098
* it's ours and reset the _NET_WM_DESKTOP property. If, however, we
1099
* instead see a PropertyNewValue (the only other possibility, hence
1100
* no "else" below), then we assume some other client wished to change
1101
* the property, and we forget about restoring _NET_WM_DESKTOP when
1102
* we remap the window later.
1104
if (event->state == PropertyDelete) {
1105
Debug("%s: PropertyDelete: _NET_WM_DESKTOP: %#lx. Resetting to %d.\n",
1106
__func__, upw->clientWindow, upw->onUnmapDesktopNumber);
1107
UPWindow_SetEWMHDesktop(up, upw, upw->onUnmapDesktopNumber);
1109
upw->wantSetDesktopNumberOnUnmap = FALSE;
1112
regetDesktop = TRUE;
1113
} else if (event->atom != up->atoms._NET_WM_WINDOW_TYPE) {
1119
case ConfigureNotify:
1120
if ((motivator->xconfigure.override_redirect ? TRUE : FALSE)
1121
== upw->isOverrideRedirect) {
1128
* XXX should we ignore UnmapNotify events if they come from non-override
1133
* If a window is override redirect (e.g. tooltips), then we may need to show
1134
* & hide it based on map & unmap, because we won't get WM_STATE updates to
1135
* help us do minimize/restore.
1140
if (upw->wantSetDesktopNumberOnUnmap) {
1141
Debug("%s: Expected PropertyDelete before MapNotify.\n", __func__);
1142
upw->wantSetDesktopNumberOnUnmap = FALSE;
1144
regetDesktop = TRUE;
1147
case ReparentNotify:
1149
Window toplevelWindow = 0;
1150
Window clientWindow = 0;
1151
Window rootWindow = 0;
1152
const XReparentEvent *reparent = &motivator->xreparent;
1155
regetDesktop = TRUE;
1156
Debug("%s: ReparentNotify: %#lx reparented to %#lx (current upw: %#lx::%#lx)\n",
1157
__func__, reparent->window, reparent->parent,
1158
upw->toplevelWindow, upw->clientWindow);
1159
success = UnityPlatformFindWindows(up, reparent->window,
1160
&toplevelWindow, &clientWindow,
1163
UPWindowSetWindows(up, upw, toplevelWindow, clientWindow);
1165
Debug("%s: ReparentNotify: UnityPlatformFindWindows failed."
1166
" Waiting for WM_STATE.\n", __func__);
1167
upw->waitingForWmState = TRUE;
1174
shouldBeRelevant = FALSE;
1181
regetDesktop = TRUE;
1184
if (shouldBeRelevant == -1) {
1185
Bool onCurrentDesktop = TRUE;
1186
Bool isInvisible = FALSE;
1187
Bool ignoreThisWindow = FALSE;
1189
UnityPlatformResetErrorCount(up);
1191
XGetWindowAttributes(up->display, upw->toplevelWindow, &winAttr);
1192
if (UnityPlatformGetErrorCount(up)) {
1193
shouldBeRelevant = FALSE;
1198
if (!UPWindowGetDesktop(up, upw, &upw->desktopNumber)) {
1199
upw->desktopNumber = -1;
1201
if (upw->wantSetDesktopNumberOnUnmap) {
1202
upw->onUnmapDesktopNumber = upw->desktopNumber;
1206
if (upw->desktopNumber < (int)up->desktopInfo.numDesktops
1207
&& upw->desktopNumber >= 0
1208
&& up->desktopInfo.guestDesktopToUnity[upw->desktopNumber] !=
1209
UnityWindowTracker_GetActiveDesktop(up->tracker)) {
1210
onCurrentDesktop = FALSE;
1212
upw->isViewable = (winAttr.map_state == IsViewable);
1213
if (!upw->wasViewable) {
1214
if (upw->isViewable) {
1215
upw->wasViewable = upw->isViewable;
1218
* Check if it's in iconic state (i.e. minimized), which means it was viewable
1219
* previously as far as we're concerned.
1224
unsigned long itemsReturned = 0;
1225
unsigned long bytesRemaining;
1226
Atom *valueReturned = NULL;
1227
Window mainWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
1229
if (XGetWindowProperty(up->display, mainWindow, up->atoms.WM_STATE, 0,
1230
1024, False, AnyPropertyType,
1231
&propertyType, &propertyFormat, &itemsReturned,
1232
&bytesRemaining, (unsigned char **) &valueReturned)
1234
&& itemsReturned > 0
1235
&& propertyType == up->atoms.WM_STATE
1236
&& propertyFormat == 32
1237
&& valueReturned[0] == IconicState) {
1238
upw->wasViewable = TRUE;
1239
Debug("Found window %#lx/%#lx initially in iconic state\n",
1240
upw->toplevelWindow, upw->clientWindow);
1242
upw->wasViewable = FALSE;
1245
XFree(valueReturned);
1248
upw->isOverrideRedirect = winAttr.override_redirect ? TRUE : FALSE;
1251
* More crazy tests to determine whether a window should be added to the window
1255
if (winAttr.c_class == InputOnly) {
1256
/* This is intrinsically true. */
1258
} else if (!upw->isViewable && onCurrentDesktop && !upw->clientWindow) {
1260
* Evaluate the map state. There are reasons why we'd like to keep unmapped
1261
* windows in the tracker.
1263
* 1. The window may be on another desktop.
1264
* 2. The window may be minimized.
1266
* upw->clientWindow == None implies that there is no window in the hierarchy
1267
* with a WM_STATE property. No WM_STATE property means that the window can't
1270
* I'm using these implications because it saves me from having to explicitly
1271
* query for/examine WM_STATE here.
1274
} else if (winAttr.width <= 1 && winAttr.height <= 1) {
1276
} else if ((winAttr.x + winAttr.width) < 0
1277
|| (winAttr.y + winAttr.height) < 0) {
1279
* XXX This isn't clear to me. What if winAttr.x > parent's width?
1285
char *wmname = NULL;
1288
**************************************
1289
* This section should hold all the ugly app-specific filtering that might be
1290
* needed for UnityX11.
1293
if (XFetchName(up->display,
1294
upw->clientWindow ? upw->clientWindow : upw->toplevelWindow,
1296
if (!strcmp(wmname, "gksu")
1297
&& winAttr.override_redirect) {
1298
ignoreThisWindow = TRUE;
1305
* End app-specific filtering.
1306
*******************************************
1311
shouldBeRelevant = FALSE;
1312
} else if (ignoreThisWindow) {
1313
shouldBeRelevant = FALSE;
1315
Atom netWmWindowType = up->atoms._NET_WM_WINDOW_TYPE_NORMAL;
1316
Atom netWmPropertyType;
1317
int netWmPropertyFormat = 0;
1318
unsigned long itemsReturned, bytesRemaining;
1319
unsigned char *valueReturned = NULL;
1322
mainWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
1323
XGetWindowProperty(up->display, mainWindow,
1324
up->atoms._NET_WM_WINDOW_TYPE, 0,
1325
1024, False, AnyPropertyType,
1326
&netWmPropertyType, &netWmPropertyFormat, &itemsReturned,
1327
&bytesRemaining, &valueReturned);
1329
if (UnityPlatformGetErrorCount(up)) {
1330
Debug("Error retrieving window type property\n");
1331
shouldBeRelevant = FALSE;
1335
if (netWmPropertyType == XA_ATOM && itemsReturned && !bytesRemaining) {
1336
netWmWindowType = *((Atom *) valueReturned);
1338
XFree(valueReturned);
1340
shouldBeRelevant = TRUE;
1341
if (netWmWindowType == up->atoms._NET_WM_WINDOW_TYPE_DESKTOP) {
1342
shouldBeRelevant = FALSE;
1343
upw->windowType = UNITY_WINDOW_TYPE_DESKTOP;
1344
up->desktopWindow = upw;
1345
} else if (netWmWindowType == up->atoms._NET_WM_WINDOW_TYPE_DND) {
1346
shouldBeRelevant = FALSE;
1347
} else if (netWmWindowType == up->atoms._NET_WM_WINDOW_TYPE_DOCK) {
1348
shouldBeRelevant = up->currentSettings[UNITY_UI_TASKBAR_VISIBLE];
1349
upw->windowType = UNITY_WINDOW_TYPE_DOCK;
1350
} else if (netWmWindowType == up->atoms._NET_WM_WINDOW_TYPE_UTILITY) {
1351
upw->windowType = UNITY_WINDOW_TYPE_PANEL;
1352
} else if (netWmWindowType == up->atoms._NET_WM_WINDOW_TYPE_DIALOG) {
1353
upw->windowType = UNITY_WINDOW_TYPE_DIALOG;
1354
} else if (netWmWindowType == up->atoms._NET_WM_WINDOW_TYPE_MENU
1355
|| netWmWindowType == up->atoms._NET_WM_WINDOW_TYPE_POPUP_MENU
1356
|| netWmWindowType == up->atoms._NET_WM_WINDOW_TYPE_DROPDOWN_MENU) {
1357
upw->windowType = UNITY_WINDOW_TYPE_MENU;
1358
} else if (netWmWindowType == up->atoms._NET_WM_WINDOW_TYPE_SPLASH) {
1359
upw->windowType = UNITY_WINDOW_TYPE_SPLASH;
1360
} else if (netWmWindowType == up->atoms._NET_WM_WINDOW_TYPE_TOOLBAR) {
1361
upw->windowType = UNITY_WINDOW_TYPE_TOOLBAR;
1362
} else if (netWmWindowType == up->atoms._NET_WM_WINDOW_TYPE_TOOLTIP) {
1363
upw->windowType = UNITY_WINDOW_TYPE_TOOLTIP;
1365
upw->windowType = UNITY_WINDOW_TYPE_NORMAL;
1371
ASSERT(shouldBeRelevant >= 0);
1373
Debug("Relevance for (%p) %#lx/%#lx/%#lx is %d (window type %d)\n",
1374
upw, upw->toplevelWindow, upw->clientWindow, upw->rootWindow,
1375
shouldBeRelevant, upw->windowType);
1377
UPWindowSetRelevance(up, upw, shouldBeRelevant ? TRUE : FALSE);
1382
*-----------------------------------------------------------------------------
1384
* UPWindow_SetUserTime --
1386
* Updates the _NET_WM_USER_TIME property on a window so the window manager
1387
* will let us restack the window.
1393
* Updated timestamp.
1395
*-----------------------------------------------------------------------------
1399
UPWindow_SetUserTime(UnityPlatform *up, // IN
1400
UnityPlatformWindow *upw) // IN
1406
unsigned long itemsReturned, bytesRemaining;
1407
unsigned char *valueReturned = NULL;
1409
focusWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
1411
XGetWindowProperty(up->display, focusWindow, up->atoms._NET_WM_USER_TIME_WINDOW, 0,
1412
1024, False, XA_WINDOW, &propertyType, &propertyFormat,
1413
&itemsReturned, &bytesRemaining, &valueReturned);
1414
if (valueReturned) {
1415
focusWindow = *(Window *)valueReturned;
1416
XFree(valueReturned);
1419
dummy = UnityPlatformGetServerTime(up);
1420
XChangeProperty(up->display, focusWindow,
1421
up->atoms._NET_WM_USER_TIME, XA_CARDINAL,
1422
32, PropModeReplace, (unsigned char *)&dummy, 1);
1427
*-----------------------------------------------------------------------------
1429
* UPWindowGetActualWindowAndPosition --
1431
* Figures out the right arguments to call XMoveResizeWindow with when
1432
* moving/resizing a window.
1438
* Puts the window and coordinates to use in 'actualWindow' and 'actualRect'.
1440
*-----------------------------------------------------------------------------
1444
UPWindowGetActualWindowAndPosition(UnityPlatform *up, // IN
1445
const UnityPlatformWindow *upw, // IN
1446
const UnityRect *orig, // IN
1447
const XWindowAttributes *origTop, // IN
1448
Window *actualWindow, // IN/OUT
1449
UnityRect *actualRect) // IN/OUT
1451
XWindowAttributes clientWinAttr;
1453
int propertyFormat = 0;
1454
unsigned long itemsReturned = 0;
1455
unsigned long bytesRemaining;
1456
unsigned char *valueReturned = NULL;
1458
int frameSizeBottom;
1465
ASSERT(actualWindow);
1468
*actualRect = *orig;
1469
if (!upw->clientWindow) {
1470
*actualWindow = upw->toplevelWindow;
1474
*actualWindow = upw->clientWindow;
1477
* We need to figure out how to adjust the 'orig' rect (which is in toplevelWindow
1478
* coordinates) and turn it into clientWindow coordinates. Because window managers
1479
* ignore requests to modify their frame windows (toplevelWindow), we have to request
1480
* the change on the clientWindow instead.
1482
if (UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_FRAME_EXTENTS)
1483
&& XGetWindowProperty(up->display, upw->clientWindow, up->atoms._NET_FRAME_EXTENTS, 0,
1484
1024, False, XA_CARDINAL,
1485
&propertyType, &propertyFormat, &itemsReturned,
1486
&bytesRemaining, &valueReturned) == Success
1487
&& propertyFormat == 32
1488
&& itemsReturned >= 4) {
1489
Atom *atomValue = (Atom *)valueReturned;
1491
frameSizeLeft = atomValue[0];
1492
frameSizeRight = atomValue[1];
1493
frameSizeTop = atomValue[2];
1494
frameSizeBottom = atomValue[3];
1497
* Query the current clientWindow and calculate how to adjust the frame coords to
1500
clientWinAttr.x = clientWinAttr.y = 0;
1501
clientWinAttr.width = origTop->width;
1502
clientWinAttr.height = origTop->height;
1504
XGetWindowAttributes(up->display, upw->clientWindow, &clientWinAttr);
1506
frameSizeLeft = clientWinAttr.x;
1507
frameSizeRight = origTop->width - (clientWinAttr.x + clientWinAttr.width);
1508
frameSizeTop = clientWinAttr.y;
1509
frameSizeBottom = origTop->height - (clientWinAttr.y + clientWinAttr.height);
1513
* It turns out that with metacity, we don't have to adjust x/y for the frame size,
1514
* only the width & height. XXX we should see how other window managers behave.
1517
actualRect->x += frameSizeLeft;
1518
actualRect->y += frameSizeTop;
1521
actualRect->width -= frameSizeLeft + frameSizeRight;
1522
actualRect->height -= frameSizeTop + frameSizeBottom;
1524
XFree(valueReturned);
1529
*----------------------------------------------------------------------------
1531
* UnityPlatformMoveResizeWindow --
1533
* Moves and/or resizes the given window to the specified location. Does not
1534
* attempt to move and/or resize window if (a) the destination rectangle does not
1535
* intersect with the virtual screen rectangle (b) window is minimized.
1537
* If the input width & height match the current width & height, then this
1538
* function will end up just moving the window. Similarly if the input
1539
* x & y coordinates match the current coordinates, then it will end up just
1540
* resizing the window.
1543
* Even if the move/resize operaion is not execuated or it fails, window's
1544
* current coordinates are always sent back.
1546
* Function does not return FALSE if the attempt to move and/or resize fails.
1547
* This is because the host will be comparing input and output parameters to
1548
* decide whether the window really moved and/or resized.
1550
* In a very rare case, when attempt to get window's current coordinates fail,
1556
*----------------------------------------------------------------------------
1560
UnityPlatformMoveResizeWindow(UnityPlatform *up, // IN
1561
UnityWindowId window, // IN: Window handle
1562
UnityRect *moveResizeRect) // IN/OUT: Desired coordinates,
1566
UnityPlatformWindow *upw;
1567
Bool retval = FALSE;
1568
XWindowAttributes winAttr;
1569
XWindowAttributes newAttr;
1570
UnityRect desiredRect;
1572
ASSERT(moveResizeRect);
1574
upw = UPWindow_Lookup(up, window);
1579
desiredRect = *moveResizeRect;
1581
UnityPlatformResetErrorCount(up);
1582
XGetWindowAttributes(up->display, upw->toplevelWindow, &winAttr);
1583
if (UnityPlatformGetErrorCount(up)) {
1587
if (winAttr.x == moveResizeRect->x
1588
&& winAttr.y == moveResizeRect->y
1589
&& winAttr.width == moveResizeRect->width
1590
&& winAttr.height == moveResizeRect->height) {
1595
* _NET_MOVERESIZE_WINDOW is preferable in general (because it saves us extra X
1596
* calls), but it is broken in metacity and there's no way to detect whether it works
1599
#if defined(VM_CAN_TRUST__NET_MOVERESIZE_WINDOW)
1600
if (UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_MOVERESIZE_WINDOW)
1601
&& upw->clientWindow) {
1602
Atom data[5] = {0, 0, 0, 0, 0};
1605
* The first datum in the EWMH _NET_MOVERESIZE_WINDOW message contains a bunch of
1606
* bits to signify what information is in the request and where the request came
1607
* from. The (0xF << 8) bits (lower nibble of the upper byte) signify that the request contains x, y, width, and
1608
* height data. The (2 << 12) bits (higher nibble of the upper byte) signifies that the request was made by the
1609
* pager/taskbar. StaticGravity is 10 in the lower byte.
1611
data[0] = (0xF << 8) | (2 << 12) | StaticGravity;
1613
data[1] = moveResizeRect->x;
1614
data[2] = moveResizeRect->y;
1615
data[3] = moveResizeRect->width;
1616
data[4] = moveResizeRect->height;
1617
UnityPlatformSendClientMessage(up, upw->rootWindow, upw->clientWindow,
1618
up->atoms._NET_MOVERESIZE_WINDOW,
1620
Debug("MoveResizeWindow implemented using _NET_MOVERESIZE_WINDOW\n");
1624
if (upw->desktopNumber == (int)up->desktopInfo.currentDesktop ||
1625
upw->desktopNumber == -1) {
1626
UnityRect actualRect;
1627
Window actualWindow;
1629
UPWindowGetActualWindowAndPosition(up, upw, moveResizeRect, &winAttr, &actualWindow, &actualRect);
1631
XMoveResizeWindow(up->display, actualWindow,
1632
actualRect.x, actualRect.y,
1633
actualRect.width, actualRect.height);
1634
Debug("MoveResizeWindow implemented using XMoveResizeWindow (requested (%d, %d) +(%d, %d) on %#lx\n",
1635
actualRect.x, actualRect.y, actualRect.width, actualRect.height,
1638
Debug("Trying to move window %#lx that is on desktop %d instead of the current desktop %u\n",
1639
upw->toplevelWindow, upw->desktopNumber, up->desktopInfo.currentDesktop);
1644
XSync(up->display, False);
1645
XGetWindowAttributes(up->display, upw->toplevelWindow, &newAttr);
1646
moveResizeRect->x = newAttr.x;
1647
moveResizeRect->y = newAttr.y;
1648
moveResizeRect->width = newAttr.width;
1649
moveResizeRect->height = newAttr.height;
1653
Debug("MoveResizeWindow(%#lx/%#lx): original (%d,%d)+(%d,%d), desired (%d,%d)+(%d,%d), actual (%d,%d)+(%d,%d) = %d\n",
1654
upw->toplevelWindow, upw->clientWindow,
1655
winAttr.x, winAttr.y, winAttr.width, winAttr.height,
1656
desiredRect.x, desiredRect.y, desiredRect.width, desiredRect.height,
1657
moveResizeRect->x, moveResizeRect->y,
1658
moveResizeRect->width, moveResizeRect->height,
1666
*----------------------------------------------------------------------------
1668
* UnityPlatformCloseWindow --
1670
* Close the window. Send WM_DELETE message to the specified window.
1671
* Just because the message was posted successfully, doesn't mean the
1672
* window will be closed (this is up to the underlying application/user
1676
* TRUE if we were successful in posting the close message to the window.
1680
* The window might be closed (and, potentially, an application exits)
1682
*----------------------------------------------------------------------------
1686
UnityPlatformCloseWindow(UnityPlatform *up, // IN: Platform data
1687
UnityWindowId window) // IN: window handle
1689
UnityPlatformWindow *upw;
1693
upw = UPWindow_Lookup(up, window);
1695
Debug("Closing window %#x\n", window);
1701
if (upw->clientWindow &&
1702
UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_CLOSE_WINDOW)) {
1704
2, // Bit to indicate that the pager requested it
1708
data[0] = UnityPlatformGetServerTime(up);
1709
UnityPlatformSendClientMessage(up, upw->rootWindow, upw->clientWindow,
1710
up->atoms._NET_CLOSE_WINDOW, 32, 5,
1712
} else if (UPWindow_ProtocolSupported(up, upw, UNITY_X11_WIN_WM_DELETE_WINDOW)){
1714
Window destWin = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
1716
data[0] = up->atoms.WM_DELETE_WINDOW;
1718
UnityPlatformSendClientMessage(up, destWin, destWin,
1719
up->atoms.WM_DELETE_WINDOW, 32, 1,
1722
XDestroyWindow(up->display, upw->toplevelWindow);
1723
XFlush(up->display);
1731
*----------------------------------------------------------------------------
1733
* UnityPlatformGetWindowPath --
1735
* Get the information needed to re-launch a window and retrieve further
1736
* information on it.
1738
* windowPathUtf8 uniquely identifies an X11 window (windowUri),
1739
* execPathUtf8 uniquely identifies the window's owning
1740
* executable (execUri).
1742
* windowUri is handy for getting icons and other data associated with a
1743
* specific window, whereas execUri is handy for uniquely identifying
1744
* applications for GHI. (The host uses our returned strings to uniquely
1745
* identify applications, and we don't want it to consider the window ID
1746
* for that purpose, as it causes the host to believe that two windows
1747
* from the same application are really associated with separate
1751
* TRUE if everything went ok, FALSE otherwise.
1754
* Original buffer contents are overwritten.
1756
*----------------------------------------------------------------------------
1760
UnityPlatformGetWindowPath(UnityPlatform *up, // IN: Platform data
1761
UnityWindowId window, // IN: window handle
1762
DynBuf *windowPathUtf8, // IN/OUT: full path to the window
1763
DynBuf *execPathUtf8) // IN/OUT: full path to the binary
1765
UnityPlatformWindow *upw;
1766
bool retval = false;
1770
upw = UPWindow_Lookup(up, window);
1773
Debug("GetWindowPath FAILED!\n");
1777
WindowPathFactory::WindowPathPair pathPair;
1778
retval = up->wpFactory->FindByXid(upw->clientWindow ? upw->clientWindow :
1779
upw->toplevelWindow, pathPair);
1782
Debug("GetWindowPath didn't know how to identify the window...\n");
1785
* FindByXid gives us 2 paths:
1786
* 1. Absolute path of executable owning the window.
1787
* 2. Desktop entry file for said application, if possible.
1789
* The desktop entry references additional resources, such as icons,
1790
* localized names, external launchers, etc., so it's the preferred
1791
* way to refer to an application.
1793
* Now, we're returning nearly the same path to our caller with one
1794
* subtle difference: one path includes a WindowXID URL parameter.
1795
* Given the desktop entry or executable path returned by FindByXid,
1796
* we'll just massage as needed into the caller's output DynBufs.
1798
Debug("GetWindowPath window %#x results in: \n"
1799
" desktopEntry = %s\n"
1801
window, pathPair.second.c_str(), pathPair.first.c_str());
1803
DynBuf_SetSize(windowPathUtf8, 0);
1804
DynBuf_SetSize(execPathUtf8, 0);
1806
std::ostringstream ostr;
1808
ostr << (pathPair.second.empty() ? pathPair.first : pathPair.second);
1809
DynBuf_AppendString(execPathUtf8, ostr.str().c_str());
1811
ostr << "?WindowXID=" << window;
1812
DynBuf_AppendString(windowPathUtf8, ostr.str().c_str());
1822
*------------------------------------------------------------------------------
1824
* UnityPlatformGetWindowContents --
1826
* Read the correct bits off the window regardless of whether it's minimized
1827
* or obscured. Return the result as a PNG in the imageData DynBuf.
1830
* Returns TRUE in case success and FALSE otherwise.
1835
*------------------------------------------------------------------------------
1839
UnityPlatformGetWindowContents(UnityPlatform *up, // IN
1840
UnityWindowId window, // IN
1841
DynBuf *imageData, // IN
1842
uint32 *width, // OUT
1843
uint32 *height) // OUT
1845
UnityPlatformWindow *upw;
1847
XWindowAttributes attrs;
1848
XImage *ximage = NULL;
1851
Bool result = FALSE;
1852
ImageInfo vmimage = { 0 };
1859
upw = UPWindow_Lookup(up, window);
1865
UnityPlatformResetErrorCount(up);
1866
if (!XGetWindowAttributes(up->display, upw->toplevelWindow, &attrs)
1867
|| UnityPlatformGetErrorCount(up)) {
1870
pixmap = XCreatePixmap(up->display, upw->toplevelWindow,
1871
attrs.width, attrs.height, attrs.depth);
1872
if (UnityPlatformGetErrorCount(up)) {
1876
gcvalues.background = gcvalues.foreground = 0;
1877
gcvalues.subwindow_mode = IncludeInferiors;
1878
gcvalues.fill_style = FillSolid;
1879
XFillRectangle(up->display, pixmap, xgc, 0, 0, attrs.width, attrs.height);
1880
xgc = XCreateGC(up->display, pixmap,
1886
if (UnityPlatformGetErrorCount(up)) {
1890
XCopyArea(up->display, upw->toplevelWindow, pixmap, xgc, 0, 0,
1891
attrs.width, attrs.height, 0, 0);
1892
if (UnityPlatformGetErrorCount(up)) {
1896
ximage = XGetImage(up->display, pixmap, 0, 0,
1897
attrs.width, attrs.height, ~0, XYPixmap);
1899
if (!ximage || UnityPlatformGetErrorCount(up)) {
1903
vmimage.width = ximage->width;
1904
vmimage.height = ximage->height;
1905
vmimage.depth = ximage->depth;
1906
vmimage.bpp = ximage->bitmap_unit;
1907
vmimage.redMask = ximage->red_mask;
1908
vmimage.greenMask = ximage->green_mask;
1909
vmimage.blueMask = ximage->blue_mask;
1910
vmimage.bytesPerLine = ximage->bytes_per_line;
1911
vmimage.data = (unsigned char*)ximage->data;
1913
if (ImageUtil_ConstructPNGBuffer(&vmimage, NULL, imageData)) {
1918
*width = vmimage.width;
1919
*height = vmimage.height;
1924
XDestroyImage(ximage);
1928
XFreeGC(up->display, xgc);
1932
XFreePixmap(up->display, pixmap);
1940
*------------------------------------------------------------------------------
1942
* UnityPlatformGetIconData --
1944
* Read part or all of a particular icon on a window. Return the result as a PNG in
1945
* the imageData DynBuf, and also return the full length of the PNG in fullLength.
1948
* Returns TRUE if successful, and FALSE otherwise.
1953
*------------------------------------------------------------------------------
1957
UnityPlatformGetIconData(UnityPlatform *up, // IN
1958
UnityWindowId window, // IN
1959
UnityIconType iconType, // IN
1960
UnityIconSize iconSize, // IN
1961
uint32 dataOffset, // IN
1962
uint32 dataLength, // IN
1963
DynBuf *imageData, // OUT
1964
uint32 *fullLength) // OUT
1966
UnityPlatformWindow *upw;
1972
upw = UPWindow_Lookup(up, window);
1974
if (!upw || !upw->clientWindow || iconType != UNITY_ICON_TYPE_MAIN) {
1978
Debug("GetIconData %#lx\n", (Window)window);
1980
if (!DynBuf_GetSize(&upw->iconPng.data)
1981
|| (upw->iconPng.size != iconSize)
1982
|| (upw->iconPng.type != iconType)) {
1984
Bool gotIcons = FALSE;
1986
pixbufs = AppUtil_CollectIconArray(NULL, upw->clientWindow);
1988
if (pixbufs && pixbufs->len) {
1993
pixbuf = (GdkPixbuf*)g_ptr_array_index(pixbufs, 0);
1995
if (gdk_pixbuf_save_to_buffer(pixbuf, &pngData, &pngDataSize,
1996
"png", NULL, NULL)) {
1997
DynBuf_Attach(&upw->iconPng.data, pngDataSize, pngData);
2000
DynBuf_SetSize(&upw->iconPng.data, 0);
2003
upw->iconPng.size = iconSize;
2004
upw->iconPng.type = iconType;
2007
AppUtil_FreeIconArray(pixbufs);
2014
*fullLength = DynBuf_GetSize(&upw->iconPng.data);
2015
if (dataOffset >= *fullLength) {
2016
DynBuf_SetSize(imageData, 0);
2020
if ((dataOffset + dataLength) > *fullLength) {
2021
realLength = *fullLength - dataOffset;
2023
realLength = dataLength;
2025
DynBuf_Enlarge(imageData, realLength);
2026
DynBuf_SetSize(imageData, realLength);
2028
memcpy(imageData->data,
2029
((const char *)DynBuf_Get(&upw->iconPng.data)) + dataOffset,
2038
*----------------------------------------------------------------------------
2040
* UnityPlatformUnminimizeWindow --
2042
* Tell the window to restore from the minimized state to its original
2051
*----------------------------------------------------------------------------
2055
UnityPlatformUnminimizeWindow(UnityPlatform *up, // IN
2056
UnityWindowId window) // IN
2058
UnityPlatformWindow *upw;
2062
upw = UPWindow_Lookup(up, window);
2064
if (!upw || !upw->clientWindow) {
2065
Debug("Restoring FAILED!\n");
2069
Debug("%s(%#lx)\n", __func__, upw->toplevelWindow);
2070
if (upw->isMinimized) {
2071
Atom data[5] = {0, 0, 0, 0, 0};
2073
Debug("Restoring window %#x\n", window);
2075
upw->isMinimized = FALSE;
2076
upw->wantInputFocus = TRUE;
2079
* Okay, client messages to update _NET_WM_STATE are intended only for
2080
* /mapped/ windows. (That's my interpretation considering that wm-spec
2081
* only mentions mapped windows, and window managers seem to ignore the
2082
* request for minimized windows.)
2084
* Rather than directly mapping the window, we'll instead request that
2085
* the window manager activate it. Mapping the window has a negative
2086
* consequence of stripping the window of its _NET_WM_STATE and
2087
* _NET_WM_DESKTOP properties. This is most visible when unminimizing
2088
* a sticky window -- the result is that it would lose its stickiness.
2092
data[1] = UnityPlatformGetServerTime(up);
2094
UnityPlatformSendClientMessage(up, upw->rootWindow, upw->clientWindow,
2095
up->atoms._NET_ACTIVE_WINDOW, 32, 4, data);
2097
data[0] = _NET_WM_STATE_REMOVE;
2098
data[1] = up->atoms._NET_WM_STATE_HIDDEN;
2099
data[2] = up->atoms._NET_WM_STATE_MINIMIZED;
2100
data[3] = 2; // Message is from the pager/taskbar
2101
UnityPlatformSendClientMessage(up, upw->rootWindow, upw->clientWindow,
2102
up->atoms._NET_WM_STATE, 32, 4, data);
2104
Debug("Window %#x is already restored\n", window);
2112
*-----------------------------------------------------------------------------
2114
* UPWindowProcessPropertyEvent --
2116
* Processes an notification that a property has changed on an X11 window.
2118
* N.B. The UPWindowPushFullUpdate method creates a fake 'xevent' based on all the
2119
* properties are set initially on a window, so before passing 'xevent' down the
2120
* call chain, or using any additional fields from it, make sure that
2121
* UPWindowPushFullUpdate fills in those fields properly.
2129
*-----------------------------------------------------------------------------
2133
UPWindowProcessPropertyEvent(UnityPlatform *up, // IN
2134
UnityPlatformWindow *upw, // IN
2135
const XEvent *xevent) // IN
2143
eventAtom = xevent->xproperty.atom;
2144
if (eventAtom == up->atoms._NET_WM_STATE ||
2145
eventAtom == up->atoms.WM_STATE) {
2146
UPWindowUpdateState(up, upw, &xevent->xproperty);
2147
if (eventAtom == up->atoms.WM_STATE) {
2148
UPWindowUpdateIcon(up, upw);
2150
} else if (eventAtom == up->atoms.WM_NAME) {
2151
UPWindowUpdateTitle(up, upw);
2152
} else if (eventAtom == up->atoms.WM_PROTOCOLS) {
2153
UPWindowUpdateProtocols(up, upw);
2154
} else if (eventAtom == up->atoms._NET_WM_ALLOWED_ACTIONS) {
2155
UPWindowUpdateActions(up, upw);
2156
} else if (eventAtom == up->atoms._NET_WM_WINDOW_TYPE) {
2157
UPWindowUpdateType(up, upw);
2158
} else if (eventAtom == up->atoms._NET_WM_ICON
2159
|| eventAtom == up->atoms.WM_ICON) {
2160
UPWindowUpdateIcon(up, upw);
2161
} else if (eventAtom == up->atoms._NET_WM_DESKTOP) {
2162
UPWindowUpdateDesktop(up, upw);
2163
} else if (eventAtom == up->atoms._NET_FRAME_EXTENTS) {
2164
UPWindowUpdateFrameExtents(up, upw);
2170
*-----------------------------------------------------------------------------
2172
* UPWindowProcessConfigureEvent --
2174
* Processes an notification that the window configuration has changed.
2182
*-----------------------------------------------------------------------------
2186
UPWindowProcessConfigureEvent(UnityPlatform *up, // IN
2187
UnityPlatformWindow *upw, // IN
2188
const XEvent *xevent) // IN
2190
if (xevent->xconfigure.window == upw->toplevelWindow) {
2191
const int border_width = xevent->xconfigure.border_width;
2192
int x = xevent->xconfigure.x;
2193
int y = xevent->xconfigure.y;
2197
xprime = x + xevent->xconfigure.width + border_width;
2198
yprime = y + xevent->xconfigure.height + border_width;
2203
Debug("Moving window %#lx/%#lx to (%d, %d) +(%d, %d)\n",
2204
upw->toplevelWindow, upw->clientWindow,
2205
x, y, xprime - x, yprime - y);
2209
* If these are the same, then the window hasn't been reparented by
2210
* the window manager, and its window decorations are accounted for
2211
* by the values of the _NET_FRAME_EXTENTS property.
2213
if (upw->toplevelWindow == upw->clientWindow) {
2214
x -= upw->frameExtents[0]; // left
2215
y -= upw->frameExtents[2]; // top
2216
xprime += upw->frameExtents[1]; // right
2217
yprime += upw->frameExtents[3]; // bottom
2220
UnityWindowTracker_MoveWindow(up->tracker, upw->toplevelWindow,
2221
x, y, xprime, yprime);
2223
if ((xevent->xconfigure.above != None && !upw->lowerWindow)
2224
|| (xevent->xconfigure.above == None && upw->lowerWindow)
2225
|| (upw->lowerWindow && xevent->xconfigure.above
2226
!= upw->lowerWindow->toplevelWindow)) {
2227
Debug("Marking window %#lx/%#lx for restacking\n",
2228
upw->toplevelWindow, upw->clientWindow);
2229
UPWindow_Restack(up, upw, xevent->xconfigure.above);
2232
Debug("ProcessConfigureEvent skipped event on window %#lx (upw was %#lx/%#lx)\n",
2233
xevent->xconfigure.window, upw->toplevelWindow, upw->clientWindow);
2237
CompareStackingOrder(up, upw->rootWindow, __func__);
2242
#if defined(VM_HAVE_X11_SHAPE_EXT)
2246
*-----------------------------------------------------------------------------
2248
* UPWindowUpdateShape --
2250
* Updates the window shape.
2256
* Notification to the window tracker
2258
*-----------------------------------------------------------------------------
2262
UPWindowUpdateShape(UnityPlatform *up, // IN
2263
UnityPlatformWindow *upw) // IN
2265
RegionPtr clipRegion = NULL;
2266
RegionPtr boundingRegion = NULL;
2267
RegionPtr region = NULL;
2268
XRectangle *rects = NULL;
2273
* Retrieve the X11 'clipping shape' (the window shape including its border) and turn
2276
UnityPlatformResetErrorCount(up);
2277
rects = XShapeGetRectangles(up->display, upw->toplevelWindow, ShapeClip,
2278
&rectCount, &rectOrdering);
2279
if (!UnityPlatformGetErrorCount(up) && rects && rectCount) {
2280
xRectangle *vmRects;
2283
vmRects = (xRectangle*)alloca(rectCount * (sizeof *vmRects));
2284
memset(vmRects, 0, rectCount * (sizeof *vmRects));
2285
for (i = 0; i < rectCount; i++) {
2286
ASSERT(rects[i].width);
2287
ASSERT(rects[i].height);
2288
vmRects[i].x = rects[i].x;
2289
vmRects[i].y = rects[i].y;
2290
vmRects[i].width = rects[i].width;
2291
vmRects[i].height = rects[i].height;
2292
vmRects[i].info.type = UpdateRect;
2295
clipRegion = miRectsToRegion(rectCount, vmRects, 0);
2297
XFree(rects); rects = NULL;
2301
* The X Shape Extension operates on unshaped windows by using default bounding
2302
* and clipping regions. I.e., XShapeGetRectangles will return a single rectangle
2303
* for an unshaped window. Without the following test, we'd end up informing the
2304
* Unity client that this window can be described by a single rectangle region,
2305
* and it'd expect further region updates when the window's geometry changes.
2307
* This wouldn't be a problem, except we don't receive XShapeEvents on these
2308
* windows when they're resized. To work around this, we make sure that the UWT
2309
* knows that unshaped windows are exactly that.
2317
XShapeQueryExtents(up->display, upw->toplevelWindow,
2318
&bShaped, &dummy, &dummy, &udummy, &udummy,
2319
&cShaped, &dummy, &dummy, &udummy, &udummy);
2320
if (!bShaped && !cShaped) {
2321
UnityWindowTracker_ChangeWindowRegion(up->tracker, upw->toplevelWindow, 0);
2326
UnityPlatformResetErrorCount(up);
2329
* Retrieve the X11 'clipping shape' (the window shape of the window without its
2330
* border) and turn it into a region.
2332
rects = XShapeGetRectangles(up->display, upw->toplevelWindow, ShapeBounding,
2333
&rectCount, &rectOrdering);
2334
if (!UnityPlatformGetErrorCount(up)
2335
&& rects && rectCount) {
2336
xRectangle *vmRects;
2339
vmRects = (xRectangle*)alloca(rectCount * (sizeof *vmRects));
2340
memset(vmRects, 0, rectCount * (sizeof *vmRects));
2341
for (i = 0; i < rectCount; i++) {
2342
ASSERT(rects[i].width);
2343
ASSERT(rects[i].height);
2344
vmRects[i].x = rects[i].x;
2345
vmRects[i].y = rects[i].y;
2346
vmRects[i].width = rects[i].width;
2347
vmRects[i].height = rects[i].height;
2348
vmRects[i].info.type = UpdateRect;
2351
boundingRegion = miRectsToRegion(rectCount, vmRects, 0);
2355
if (boundingRegion && clipRegion) {
2356
region = miRegionCreate(NULL, 2);
2357
miIntersect(region, clipRegion, boundingRegion);
2358
} else if (clipRegion) {
2359
region = clipRegion; clipRegion = NULL;
2360
} else if (boundingRegion) {
2361
region = boundingRegion; boundingRegion = NULL;
2364
UnityWindowTracker_ChangeWindowRegion(up->tracker, upw->toplevelWindow, region);
2366
miRegionDestroy(clipRegion);
2368
if (boundingRegion) {
2369
miRegionDestroy(boundingRegion);
2372
miRegionDestroy(region);
2378
*-----------------------------------------------------------------------------
2380
* UPWindowProcessShapeEvent --
2382
* Processes an notification that the non-rectangular window shape has changed.
2390
*-----------------------------------------------------------------------------
2394
UPWindowProcessShapeEvent(UnityPlatform *up, // IN
2395
UnityPlatformWindow *upw, // IN
2396
const XEvent *xevent) // IN
2402
ASSERT(xevent->type == (up->shapeEventBase + ShapeNotify));
2404
sev = (XShapeEvent *)xevent;
2405
ASSERT (sev->window == upw->toplevelWindow ||
2406
sev->window == upw->clientWindow);
2409
UPWindowUpdateShape(up, upw);
2411
UnityWindowTracker_ChangeWindowRegion(up->tracker, upw->toplevelWindow, NULL);
2418
*-----------------------------------------------------------------------------
2420
* UnityPlatformWindowProcessEvent --
2422
* Handle an event on a typical window.
2430
*-----------------------------------------------------------------------------
2434
UPWindow_ProcessEvent(UnityPlatform *up, // IN
2435
UnityPlatformWindow *upw, // IN
2436
Window realEventWindow, // IN
2437
const XEvent *xevent) // IN
2439
Bool eventHandled = TRUE;
2445
UPWindow_CheckRelevance(up, upw, xevent);
2447
switch (xevent->type) {
2457
case GraphicsExpose:
2461
case CirculateRequest:
2462
case SelectionClear:
2463
case SelectionRequest:
2464
case SelectionNotify:
2465
case ColormapNotify:
2468
case VisibilityNotify:
2470
case ReparentNotify:
2471
case ConfigureRequest:
2472
break; // No extra processing on these for now
2475
/* Do nothing. The UPWindow has already been created. */
2479
if (upw->isRelevant) {
2480
UnityWindowInfo *info;
2481
info = UnityWindowTracker_LookupWindow(up->tracker, upw->toplevelWindow);
2483
UnityWindowTracker_ChangeWindowState(up->tracker,
2484
upw->toplevelWindow,
2485
info->state | UNITY_WINDOW_STATE_IN_FOCUS);
2490
if (upw->isRelevant) {
2491
UnityWindowInfo *info;
2492
info = UnityWindowTracker_LookupWindow(up->tracker, upw->toplevelWindow);
2494
UnityWindowTracker_ChangeWindowState(up->tracker,
2495
upw->toplevelWindow,
2497
& ~UNITY_WINDOW_STATE_IN_FOCUS));
2502
Debug("Destroying window (%p) %#lx/%#lx\n",
2503
upw, upw->toplevelWindow, upw->clientWindow);
2506
* Release the UnityPlatform object's reference to this UnityPlatformWindow,
2508
upw->windowType = UNITY_WINDOW_TYPE_NONE;
2509
upw->deleteWhenSafe = TRUE;
2511
CompareStackingOrder(up, upw->rootWindow, __func__);
2516
upw->wantInputFocus = FALSE;
2517
upw->isViewable = FALSE;
2522
* This is here because we want to set input focus as part of UnminimizeWindow, but
2523
* can't call XSetInputFocus until the window has actually been shown.
2525
if (upw->wantInputFocus && upw->clientWindow) {
2526
XSetInputFocus(up->display, upw->clientWindow, RevertToParent,
2527
UnityPlatformGetServerTime(up));
2528
upw->wantInputFocus = FALSE;
2531
upw->isViewable = TRUE;
2534
case CirculateNotify:
2535
if (upw->isRelevant) {
2536
UPWindow_Restack(up, upw,
2537
(up->topWindow && xevent->xcirculate.place == PlaceOnTop)
2538
? up->topWindow->toplevelWindow : None);
2542
case PropertyNotify:
2543
UPWindowProcessPropertyEvent(up, upw, xevent);
2546
case ConfigureNotify:
2547
UPWindowProcessConfigureEvent(up, upw, xevent);
2551
eventHandled = FALSE; // Unknown "regular" event
2555
if (!eventHandled) { // Handle extension events here
2556
#if defined(VM_HAVE_X11_SHAPE_EXT)
2557
if (up->shapeEventBase &&
2558
xevent->type == (up->shapeEventBase + ShapeNotify)) {
2559
UPWindowProcessShapeEvent(up, upw, xevent);
2560
eventHandled = TRUE;
2564
ASSERT(eventHandled);
2570
*-----------------------------------------------------------------------------
2572
* UPWindowUpdateTitle --
2574
* Tells the window tracker about the window's latest title
2580
* Notification to the window tracker
2582
*-----------------------------------------------------------------------------
2586
UPWindowUpdateTitle(UnityPlatform *up, // IN
2587
UnityPlatformWindow *upw) // IN
2591
unsigned long itemsReturned;
2592
unsigned long bytesRemaining;
2593
unsigned char *valueReturned = NULL;
2596
if (!upw->clientWindow) {
2600
if (XGetWindowProperty(up->display, upw->clientWindow, up->atoms.WM_NAME, 0,
2601
1024, False, AnyPropertyType,
2602
&propertyType, &propertyFormat, &itemsReturned,
2603
&bytesRemaining, &valueReturned)
2606
* Some random error occurred - perhaps the window disappeared
2611
if (bytesRemaining != 0) {
2612
Log("Skipping title update for window %#lx. Title too long.\n",
2618
* propertyFormat tells us (in bits) the size of each item returned. Let's
2619
* convert that to bytes. See XGetWindowProperty(3) for details.
2621
size_t bytesRead = itemsReturned * propertyFormat / 8;
2622
Glib::ustring newTitle;
2624
if (bytesRead) { // i.e. valueReturned isn't empty
2625
if ( propertyType == XA_STRING
2626
|| propertyType == up->atoms.UTF8_STRING) {
2628
* Insert() used because NUL termination isn't guaranteed. (Is that
2629
* really the case? TODO: Look this up.)
2631
newTitle.insert(0, (const char *)valueReturned, bytesRead);
2632
} else if (propertyType == up->atoms.COMPOUND_TEXT) {
2634
* COMPOUND_TEXT strings may contain characters outside the ASCII set.
2635
* We'll convert these to something usable (*cough*UTF-8*cough*) via
2636
* our trusty good pal, Gdk.
2638
gchar **utf8List = NULL;
2640
nconverted = gdk_text_property_to_utf8_list(
2641
gdk_x11_xatom_to_atom(up->atoms.COMPOUND_TEXT), propertyFormat,
2642
valueReturned, bytesRead, &utf8List);
2644
newTitle.assign(utf8List[0]);
2646
g_strfreev(utf8List);
2649
XFree(valueReturned);
2651
DynBuf_Init(&titleBuf);
2652
DynBuf_Append(&titleBuf, newTitle.c_str(), newTitle.bytes() + 1);
2653
Debug("Set title of window %#lx to %s\n",
2654
upw->clientWindow, (char *)DynBuf_Get(&titleBuf));
2655
UnityWindowTracker_SetWindowTitle(up->tracker, (UnityWindowId) upw->toplevelWindow,
2657
DynBuf_Destroy(&titleBuf);
2662
*-----------------------------------------------------------------------------
2664
* UPWindowUpdateType --
2666
* Tells the window tracker about the window's latest type
2672
* Notification to the window tracker
2674
*-----------------------------------------------------------------------------
2678
UPWindowUpdateType(UnityPlatform *up, // IN
2679
UnityPlatformWindow *upw) // IN
2685
* upw->windowType was previously updated by the CheckRelevance method.
2687
UnityWindowTracker_ChangeWindowType(up->tracker,
2688
upw->toplevelWindow,
2694
*-----------------------------------------------------------------------------
2696
* UPWindowUpdateProtocols --
2698
* Updates the list of protocols supported by the window.
2704
* Notification to the window tracker
2706
*-----------------------------------------------------------------------------
2710
UPWindowUpdateProtocols(UnityPlatform *up, // IN
2711
UnityPlatformWindow *upw) // IN
2715
unsigned long itemsReturned;
2716
unsigned long bytesRemaining;
2717
Atom *valueReturned = NULL;
2720
if (!upw->clientWindow) {
2724
if (XGetWindowProperty(up->display, upw->clientWindow, up->atoms.WM_STATE, 0,
2725
1024, False, AnyPropertyType,
2726
&propertyType, &propertyFormat, &itemsReturned,
2727
&bytesRemaining, (unsigned char **) &valueReturned)
2730
* Some random error occurred - perhaps the window disappeared.
2735
if (propertyType != up->atoms.WM_STATE
2736
|| propertyFormat != 32) {
2740
memset(upw->windowProtocols, 0, sizeof upw->windowProtocols);
2741
for (i = 0; i < itemsReturned; i++) {
2742
UnityX11WinProtocol proto;
2744
if (valueReturned[i] == up->atoms.WM_DELETE_WINDOW) {
2745
proto = UNITY_X11_WIN_WM_DELETE_WINDOW;
2750
upw->windowProtocols[proto] = TRUE;
2752
XFree(valueReturned);
2757
*-----------------------------------------------------------------------------
2759
* UPWindowUpdateActions --
2761
* Updates the window attributes based on a new _NET_WM_ALLOWED_ACTIONS attribute.
2767
* Notification to the window tracker
2769
*-----------------------------------------------------------------------------
2773
UPWindowUpdateActions(UnityPlatform *up, // IN
2774
UnityPlatformWindow *upw) // IN
2778
unsigned long itemsReturned = 0;
2779
unsigned long bytesRemaining;
2780
Atom *valueReturned = NULL;
2782
Bool curAttrValues[UNITY_MAX_ATTRIBUTES];
2783
Bool attrsAreSet[UNITY_MAX_ATTRIBUTES];
2787
if (!upw->clientWindow) {
2791
memset(curAttrValues, 0, sizeof curAttrValues);
2792
memset(attrsAreSet, 0, sizeof attrsAreSet);
2793
haveHorizMax = haveVertMax = FALSE;
2796
* List of attributes that we know how to process from the ALLOWED_ACTIONS list. If we
2797
* don't find these in the ALLOWED_ACTIONS list, and they are supported by the window
2798
* manager, then we report that they're FALSE (set by the first memset above).
2800
attrsAreSet[UNITY_WINDOW_ATTR_MINIMIZABLE] =
2801
UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_WM_ACTION_MINIMIZE);
2802
attrsAreSet[UNITY_WINDOW_ATTR_MAXIMIZABLE] =
2803
UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_WM_ACTION_MAXIMIZE_HORZ) &&
2804
UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_WM_ACTION_MAXIMIZE_VERT);
2805
attrsAreSet[UNITY_WINDOW_ATTR_CLOSABLE] =
2806
UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_WM_ACTION_CLOSE);
2807
attrsAreSet[UNITY_WINDOW_ATTR_FULLSCREENABLE] =
2808
UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_WM_ACTION_FULLSCREEN);
2809
attrsAreSet[UNITY_WINDOW_ATTR_SHADEABLE] =
2810
UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_WM_ACTION_SHADE);
2811
attrsAreSet[UNITY_WINDOW_ATTR_STICKABLE] =
2812
UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_WM_ACTION_STICK);
2814
if (XGetWindowProperty(up->display, upw->clientWindow,
2815
up->atoms._NET_WM_ALLOWED_ACTIONS, 0,
2816
1024, False, XA_ATOM,
2817
&propertyType, &propertyFormat, &itemsReturned,
2818
&bytesRemaining, (unsigned char **) &valueReturned)
2820
&& propertyFormat == 32) {
2821
for (i = 0; i < itemsReturned; i++) {
2822
UnityWindowAttribute attr;
2823
Bool attrValue = TRUE;
2825
if (valueReturned[i] == up->atoms._NET_WM_ACTION_MINIMIZE) {
2826
attr = UNITY_WINDOW_ATTR_MINIMIZABLE;
2827
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_MAXIMIZE_HORZ) {
2828
haveHorizMax = TRUE;
2830
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_MAXIMIZE_VERT) {
2833
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_CLOSE) {
2834
attr = UNITY_WINDOW_ATTR_CLOSABLE;
2835
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_FULLSCREEN) {
2836
attr = UNITY_WINDOW_ATTR_FULLSCREENABLE;
2837
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_SHADE) {
2838
attr = UNITY_WINDOW_ATTR_SHADEABLE;
2839
} else if (valueReturned[i] == up->atoms._NET_WM_ACTION_STICK) {
2840
attr = UNITY_WINDOW_ATTR_STICKABLE;
2845
curAttrValues[attr] = attrValue;
2846
attrsAreSet[attr] = TRUE;
2848
XFree(valueReturned);
2850
curAttrValues[UNITY_WINDOW_ATTR_MINIMIZABLE] = TRUE;
2851
attrsAreSet[UNITY_WINDOW_ATTR_MINIMIZABLE] = TRUE;
2854
curAttrValues[UNITY_WINDOW_ATTR_MAXIMIZABLE] = (haveHorizMax && haveVertMax);
2855
attrsAreSet[UNITY_WINDOW_ATTR_MAXIMIZABLE] = TRUE;
2857
for (i = 0; i < UNITY_MAX_ATTRIBUTES; i++) {
2858
if (attrsAreSet[i]) {
2859
UnityWindowTracker_ChangeWindowAttribute(up->tracker, upw->toplevelWindow,
2860
(UnityWindowAttribute)i, curAttrValues[i]);
2867
*-----------------------------------------------------------------------------
2869
* UPWindowGetDesktop --
2871
* Retrieve's the current X11 virtual desktop of a window.
2874
* Virtual desktop number
2879
*-----------------------------------------------------------------------------
2883
UPWindowGetDesktop(UnityPlatform *up, // IN
2884
UnityPlatformWindow *upw, // IN
2885
int *guestDesktop) // IN/OUT
2889
unsigned long itemsReturned = 0;
2890
unsigned long bytesRemaining;
2891
Atom *valueReturned = NULL;
2892
Bool retval = FALSE;
2894
if (!upw->clientWindow) {
2898
if (XGetWindowProperty(up->display, upw->clientWindow,
2899
up->atoms._NET_WM_DESKTOP, 0,
2900
1024, False, AnyPropertyType,
2901
&propertyType, &propertyFormat, &itemsReturned,
2902
&bytesRemaining, (unsigned char **) &valueReturned)
2904
&& propertyType == XA_CARDINAL
2905
&& propertyFormat == 32
2908
*guestDesktop = *valueReturned;
2912
XFree(valueReturned);
2919
*-----------------------------------------------------------------------------
2921
* UPWindowUpdateDesktop --
2923
* Updates the window's virtual desktop based on a new _NET_WM_DESKTOP attribute.
2929
* Notification to the window tracker.
2931
*-----------------------------------------------------------------------------
2935
UPWindowUpdateDesktop(UnityPlatform *up, // IN
2936
UnityPlatformWindow *upw) // IN
2938
int guestDesktop = -1;
2940
if (!upw->clientWindow) {
2944
if (!UPWindowGetDesktop(up, upw, &guestDesktop)) {
2945
Debug("Window %#lx has a clientWindow, but its "
2946
"virtual desktop could not be retrieved\n",
2951
if (guestDesktop < ((int)up->desktopInfo.numDesktops)) {
2952
UnityDesktopId desktopId = -1;
2955
isSticky = (guestDesktop < 0);
2957
desktopId = up->desktopInfo.guestDesktopToUnity[guestDesktop];
2960
Debug("Window %#lx is now on desktop %d\n", upw->toplevelWindow, desktopId);
2961
UnityWindowTracker_ChangeWindowDesktop(up->tracker,
2962
upw->toplevelWindow,
2965
UnityWindowTracker_ChangeWindowAttribute(up->tracker,
2966
upw->toplevelWindow,
2967
UNITY_WINDOW_ATTR_STICKY,
2970
Debug("Guest's virtual desktop config may not match host's (yet?)"
2971
" (window is on desktop %d, guest is supposed to have %"FMTSZ"u desktops)\n",
2972
guestDesktop, up->desktopInfo.numDesktops);
2978
*-----------------------------------------------------------------------------
2980
* UPWindowUpdateIcon --
2982
* Updates the window's virtual desktop based on a new _NET_WM_DESKTOP attribute.
2988
* Notification to the window tracker.
2990
*-----------------------------------------------------------------------------
2994
UPWindowUpdateIcon(UnityPlatform *up, // IN
2995
UnityPlatformWindow *upw) // IN
2997
UnityWindowTracker_NotifyIconChanged(up->tracker, upw->toplevelWindow,
2998
UNITY_ICON_TYPE_MAIN);
3000
if (DynBuf_GetSize(&upw->iconPng.data)) {
3001
DynBuf_SetSize(&upw->iconPng.data, 0);
3007
*-----------------------------------------------------------------------------
3009
* UPWindowIsNowWithdrawn --
3011
* In response to an update to a window's WM_STATE property, properties, test
3012
* whether or not the window has been withdrawn.
3015
* TRUE if we believe the window was withdrawn, FALSE otherwise.
3020
*-----------------------------------------------------------------------------
3024
UPWindowIsNowWithdrawn(UnityPlatform *up, // IN
3025
UnityPlatformWindow *upw, // IN
3026
const XPropertyEvent *xevent) // IN
3029
Bool isWithdrawn = FALSE;
3033
unsigned long nitems;
3034
unsigned long bytes_remaining;
3035
unsigned char *properties = NULL;
3037
mainWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
3040
* Per ICCCM §4.1.3.1, WM_STATE.state will either be set to WithdrawnState
3041
* or WM_STATE removed from a window when it is withdrawn.
3043
if (xevent->state == PropertyDelete) {
3047
if (XGetWindowProperty(up->display, mainWindow, up->atoms.WM_STATE,
3049
1, // length (in 32-bit chunks)
3051
AnyPropertyType, // requested property type
3052
&actual_type, // returned type
3053
&actual_format, // returned format
3054
&nitems, // # of items returned
3055
&bytes_remaining, // # of bytes remaining
3056
&properties) == Success) {
3057
uint32 *state = (uint32 *)properties;
3059
if (actual_type == None ||
3060
(nitems > 0 && *state == WithdrawnState)) {
3072
*-----------------------------------------------------------------------------
3074
* UPWindowUpdateState --
3076
* Tells the window tracker about the window's changes to the _NET_WM_STATE and
3077
* WM_STATE properties.
3083
* Notification to the window tracker
3085
*-----------------------------------------------------------------------------
3089
UPWindowUpdateState(UnityPlatform *up, // IN
3090
UnityPlatformWindow *upw, // IN
3091
const XPropertyEvent *xevent) // IN
3095
unsigned long itemsReturned;
3096
unsigned long bytesRemaining;
3097
Atom *valueReturned = NULL;
3099
Bool curAttrValues[UNITY_MAX_ATTRIBUTES];
3100
Bool attrsAreSet[UNITY_MAX_ATTRIBUTES];
3101
Bool isMinimized = FALSE;
3102
Bool haveHorizMax = FALSE;
3103
Bool haveVertMax = FALSE;
3104
Bool doSkipTaskbar = FALSE;
3105
Bool doSkipPager = FALSE;
3108
mainWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
3111
* If a change to WM_STATE indicates this window was withdrawn/unmapped, simply
3112
* invalidate it from the window tracker and return.
3114
if (xevent->atom == up->atoms.WM_STATE &&
3115
UPWindowIsNowWithdrawn(up, upw, xevent)) {
3116
UPWindowSetRelevance(up, upw, FALSE);
3120
memset(curAttrValues, 0, sizeof curAttrValues);
3121
memset(attrsAreSet, 0, sizeof attrsAreSet);
3123
curAttrValues[UNITY_WINDOW_ATTR_VISIBLE] = TRUE;
3124
attrsAreSet[UNITY_WINDOW_ATTR_VISIBLE] =
3125
attrsAreSet[UNITY_WINDOW_ATTR_MAXIMIZED] =
3126
attrsAreSet[UNITY_WINDOW_ATTR_STICKY] =
3127
attrsAreSet[UNITY_WINDOW_ATTR_ALWAYS_ABOVE] =
3128
attrsAreSet[UNITY_WINDOW_ATTR_ALWAYS_BELOW] =
3129
attrsAreSet[UNITY_WINDOW_ATTR_MODAL] =
3130
attrsAreSet[UNITY_WINDOW_ATTR_SHADED] =
3131
attrsAreSet[UNITY_WINDOW_ATTR_FULLSCREENED] =
3132
attrsAreSet[UNITY_WINDOW_ATTR_ATTN_WANTED] = TRUE;
3134
if (!UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_WM_STATE_HIDDEN)) {
3135
if (XGetWindowProperty(up->display, mainWindow, up->atoms.WM_STATE, 0,
3136
1024, False, AnyPropertyType,
3137
&propertyType, &propertyFormat, &itemsReturned,
3138
&bytesRemaining, (unsigned char **) &valueReturned)
3141
* Some random error occurred - perhaps the window disappeared
3146
if (propertyType == up->atoms.WM_STATE
3147
&& propertyFormat == 32
3149
&& valueReturned[0] == IconicState) {
3152
XFree(valueReturned);
3155
if (XGetWindowProperty(up->display, mainWindow, up->atoms._NET_WM_STATE, 0,
3156
1024, False, AnyPropertyType,
3157
&propertyType, &propertyFormat, &itemsReturned,
3158
&bytesRemaining, (unsigned char **) &valueReturned)
3161
* Some random error occurred - perhaps the window disappeared
3166
if (propertyType != XA_ATOM
3167
|| propertyFormat != 32) {
3171
for (i = 0; i < itemsReturned; i++) {
3172
UnityWindowAttribute attr;
3173
Bool attrValue = TRUE;
3175
if (valueReturned[i] == up->atoms._NET_WM_STATE_MINIMIZED
3176
|| valueReturned[i] == up->atoms._NET_WM_STATE_HIDDEN) {
3179
} else if (valueReturned[i] == up->atoms._NET_WM_STATE_MAXIMIZED_HORZ) {
3180
haveHorizMax = TRUE;
3182
} else if (valueReturned[i] == up->atoms._NET_WM_STATE_MAXIMIZED_VERT) {
3185
} else if (valueReturned[i] == up->atoms._NET_WM_STATE_STICKY) {
3186
attr = UNITY_WINDOW_ATTR_STICKY;
3187
} else if (valueReturned[i] == up->atoms._NET_WM_STATE_ABOVE) {
3188
attr = UNITY_WINDOW_ATTR_ALWAYS_ABOVE;
3189
} else if (valueReturned[i] == up->atoms._NET_WM_STATE_BELOW) {
3190
attr = UNITY_WINDOW_ATTR_ALWAYS_BELOW;
3191
} else if (valueReturned[i] == up->atoms._NET_WM_STATE_MODAL) {
3192
attr = UNITY_WINDOW_ATTR_MODAL;
3193
} else if (valueReturned[i] == up->atoms._NET_WM_STATE_SHADED) {
3194
attr = UNITY_WINDOW_ATTR_SHADED;
3195
} else if (valueReturned[i] == up->atoms._NET_WM_STATE_FULLSCREEN) {
3196
attr = UNITY_WINDOW_ATTR_FULLSCREENED;
3197
} else if (valueReturned[i] == up->atoms._NET_WM_STATE_DEMANDS_ATTENTION) {
3198
attr = UNITY_WINDOW_ATTR_ATTN_WANTED;
3199
} else if (valueReturned[i] == up->atoms._NET_WM_STATE_SKIP_TASKBAR) {
3200
attr = UNITY_WINDOW_ATTR_TOOLWINDOW;
3201
doSkipTaskbar = TRUE;
3202
} else if (valueReturned[i] == up->atoms._NET_WM_STATE_SKIP_PAGER) {
3209
curAttrValues[attr] = attrValue;
3210
attrsAreSet[attr] = TRUE;
3212
XFree(valueReturned);
3214
curAttrValues[UNITY_WINDOW_ATTR_MAXIMIZED] = (haveHorizMax && haveVertMax);
3215
attrsAreSet[UNITY_WINDOW_ATTR_MAXIMIZED] = TRUE;
3216
curAttrValues[UNITY_WINDOW_ATTR_APPWINDOW] = (!doSkipPager && !doSkipTaskbar)
3217
&& (upw->windowType == UNITY_WINDOW_TYPE_NORMAL);
3218
attrsAreSet[UNITY_WINDOW_ATTR_APPWINDOW] = TRUE;
3220
if (upw->isRelevant) {
3221
UnityWindowInfo *info;
3226
info = UnityWindowTracker_LookupWindow(up->tracker, upw->toplevelWindow);
3229
newState = info->state;
3232
* Only push minimize state for windows on the same desktop (inc. sticky
3235
if (UPWindowGetDesktop(up, upw, &gDesk)) {
3236
cDesk = UnityX11GetCurrentDesktop(up);
3237
if (cDesk == gDesk || gDesk == -1) {
3239
if (! (newState & UNITY_WINDOW_STATE_MINIMIZED)) {
3240
Debug("Enabling minimized attribute for window %#lx/%#lx\n",
3241
upw->toplevelWindow, upw->clientWindow);
3242
newState |= UNITY_WINDOW_STATE_MINIMIZED;
3245
if ((newState & UNITY_WINDOW_STATE_MINIMIZED)) {
3246
Debug("Disabling minimized attribute for window %#lx/%#lx\n",
3247
upw->toplevelWindow, upw->clientWindow);
3248
newState &= ~UNITY_WINDOW_STATE_MINIMIZED;
3253
Debug("%s: Unable to get window desktop\n", __FUNCTION__);
3256
if (newState != info->state) {
3257
UnityWindowTracker_ChangeWindowState(up->tracker,
3258
upw->toplevelWindow,
3262
upw->isMinimized = isMinimized;
3263
upw->isMaximized = (haveHorizMax && haveVertMax);
3265
for (i = 0; i < UNITY_MAX_ATTRIBUTES; i++) {
3266
if (attrsAreSet[i]) {
3267
UnityWindowTracker_ChangeWindowAttribute(up->tracker, upw->toplevelWindow,
3268
(UnityWindowAttribute)i, curAttrValues[i]);
3276
*-----------------------------------------------------------------------------
3278
* UPWindowPushFullUpdate --
3280
* Pushes a full update for the given window.
3283
* TRUE if we pushed the updates for this window, FALSE otherwise.
3286
* UnityWindowTracker contains latest info on this window.
3288
*-----------------------------------------------------------------------------
3292
UPWindowPushFullUpdate(UnityPlatform *up, // IN
3293
UnityPlatformWindow *upw) // IN
3295
XWindowAttributes winAttr;
3299
int x, y, xprime, yprime;
3302
XGetWindowAttributes(up->display, upw->toplevelWindow, &winAttr);
3303
UPWindowUpdateFrameExtents(up, upw);
3307
border_width = winAttr.border_width;
3309
xprime = x + winAttr.width + border_width;
3310
yprime = y + winAttr.height + border_width;
3315
* If these are the same, then the window hasn't been reparented by
3316
* the window manager, and its window decorations are accounted for
3317
* by the values of the _NET_FRAME_EXTENTS property.
3319
if (upw->toplevelWindow == upw->clientWindow) {
3320
x -= upw->frameExtents[0]; // left
3321
y -= upw->frameExtents[2]; // top
3322
xprime += upw->frameExtents[1]; // right
3323
yprime += upw->frameExtents[3]; // bottom
3326
UnityWindowTracker_MoveWindow(up->tracker, upw->toplevelWindow,
3327
x, y, xprime, yprime);
3329
#if defined(VM_HAVE_X11_SHAPE_EXT)
3330
UPWindowUpdateShape(up, upw);
3332
UPWindowUpdateType(up, upw);
3335
UnityPlatformResetErrorCount(up);
3336
props = XListProperties(up->display,
3337
upw->clientWindow ? upw->clientWindow : upw->toplevelWindow,
3339
if (!UnityPlatformGetErrorCount(up)) {
3340
for (i = 0; i < propCount; i++) {
3341
XEvent fakeEvent = {0,};
3343
fakeEvent.xproperty.state = PropertyNewValue;
3344
fakeEvent.xproperty.atom = props[i];
3345
UPWindowProcessPropertyEvent(up, upw, &fakeEvent);
3355
*-----------------------------------------------------------------------------
3357
* UPWindow_ProtocolSupported --
3359
* Returns whether a particular window supports a particular protocol.
3362
* TRUE if supported, FALSE otherwise.
3367
*-----------------------------------------------------------------------------
3371
UPWindow_ProtocolSupported(const UnityPlatform *up, // IN
3372
const UnityPlatformWindow *upw, // IN
3373
UnityX11WinProtocol proto) // IN
3377
ASSERT(proto < UNITY_X11_MAX_WIN_PROTOCOLS);
3379
return upw->windowProtocols[proto];
3384
*----------------------------------------------------------------------------
3386
* UnityPlatformShowWindow --
3388
* Makes hidden Window visible. If the Window is already visible, it stays
3389
* visible. Window reappears at its original location. A minimized window
3390
* reappears as minimized.
3394
* FALSE if the Window handle is invalid.
3400
*----------------------------------------------------------------------------
3404
UnityPlatformShowWindow(UnityPlatform *up, // IN
3405
UnityWindowId window) // IN
3407
UnityPlatformWindow *upw;
3411
upw = UPWindow_Lookup(up, window);
3413
if (!upw || !upw->clientWindow) {
3414
Debug("Hiding FAILED!\n");
3418
if (upw->isHidden) {
3419
Atom data[5] = {0, 0, 0, 0, 0};
3422
* Unfortunately the _NET_WM_STATE messages only work for windows that are already
3423
* mapped, i.e. not iconified or withdrawn.
3425
if (!upw->isMinimized) {
3426
XMapRaised(up->display, upw->clientWindow);
3429
data[0] = _NET_WM_STATE_REMOVE;
3430
data[1] = up->atoms._NET_WM_STATE_HIDDEN;
3431
data[3] = 2; // Message is from the pager/taskbar
3432
UnityPlatformSendClientMessage(up, upw->rootWindow, upw->clientWindow,
3433
up->atoms._NET_WM_STATE, 32, 4, data);
3435
upw->wantInputFocus = TRUE;
3436
upw->isHidden = FALSE;
3444
*----------------------------------------------------------------------------
3446
* UnityPlatformHideWindow --
3448
* Hides window. If the window is already hidden it stays hidden. Hides
3449
* maximized and minimized windows too.
3452
* FALSE if the Window handle is invalid.
3458
*----------------------------------------------------------------------------
3462
UnityPlatformHideWindow(UnityPlatform *up, // IN
3463
UnityWindowId window) // IN
3465
UnityPlatformWindow *upw;
3469
upw = UPWindow_Lookup(up, window);
3472
|| !upw->clientWindow) {
3473
Debug("Hiding FAILED!\n");
3477
if (!upw->isHidden) {
3478
Atom data[5] = {0, 0, 0, 0, 0};
3480
upw->isHidden = TRUE;
3482
data[0] = _NET_WM_STATE_ADD;
3483
data[1] = up->atoms._NET_WM_STATE_HIDDEN;
3484
data[3] = 2; // Message is from a pager/taskbar/etc.
3485
UnityPlatformSendClientMessage(up, upw->rootWindow, upw->clientWindow,
3486
up->atoms._NET_WM_STATE, 32, 4, data);
3494
*----------------------------------------------------------------------------
3496
* UnityPlatformMinimizeWindow --
3498
* Mimimizes window. If the window is already mimimized it stays minimized.
3501
* FALSE if the Window handle is invalid.
3507
*----------------------------------------------------------------------------
3511
UnityPlatformMinimizeWindow(UnityPlatform *up, // IN
3512
UnityWindowId window) // IN
3514
UnityPlatformWindow *upw;
3518
upw = UPWindow_Lookup(up, window);
3521
|| !upw->clientWindow) {
3522
Debug("Minimizing FAILED!\n");
3526
Debug("UnityPlatformMinimizeWindow(%#lx)\n", upw->toplevelWindow);
3527
upw->wantInputFocus = FALSE;
3528
if (!upw->isMinimized) {
3529
Atom data[5] = {0, 0, 0, 0, 0};
3531
Debug("Minimizing window %#x\n", window);
3532
upw->isMinimized = TRUE;
3533
data[0] = _NET_WM_STATE_ADD;
3534
if (UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_WM_STATE_MINIMIZED)) {
3535
data[1] = up->atoms._NET_WM_STATE_MINIMIZED;
3537
data[1] = up->atoms._NET_WM_STATE_HIDDEN;
3539
data[3] = 2; // Message is from a pager/taskbar/etc.
3540
UnityPlatformSendClientMessage(up, upw->rootWindow, upw->clientWindow,
3541
up->atoms._NET_WM_STATE, 32, 4, data);
3543
XIconifyWindow(up->display, upw->clientWindow, 0);
3545
Debug("Window %#x is already minimized\n", window);
3554
*----------------------------------------------------------------------------
3556
* UnityPlatformMaximizeWindow --
3558
* Maximizes window. If the window is already maximized it will stay so.
3561
* FALSE if the Window handle is invalid.
3567
*----------------------------------------------------------------------------
3571
UnityPlatformMaximizeWindow(UnityPlatform *up, // IN
3572
UnityWindowId window) // IN
3574
UnityPlatformWindow *upw;
3578
upw = UPWindow_Lookup(up, window);
3581
|| !upw->clientWindow) {
3582
Debug("Maximizing FAILED!\n");
3586
if (!upw->isMaximized) {
3587
Atom data[5] = {0, 0, 0, 0, 0};
3589
upw->isMaximized = TRUE;
3590
data[0] = _NET_WM_STATE_ADD;
3591
data[1] = up->atoms._NET_WM_STATE_MAXIMIZED_HORZ;
3592
data[2] = up->atoms._NET_WM_STATE_MAXIMIZED_VERT;
3593
data[3] = 2; // Message is from a pager/taskbar/etc.
3594
UnityPlatformSendClientMessage(up, upw->rootWindow, upw->clientWindow,
3595
up->atoms._NET_WM_STATE, 32, 4, data);
3603
*----------------------------------------------------------------------------
3605
* UnityPlatformUnmaximizeWindow --
3607
* Unmaximizes window. If the window is already unmaximized, it will stay
3611
* FALSE if the Window handle is invalid.
3617
*----------------------------------------------------------------------------
3621
UnityPlatformUnmaximizeWindow(UnityPlatform *up, // IN
3622
UnityWindowId window) // IN
3624
UnityPlatformWindow *upw;
3628
upw = UPWindow_Lookup(up, window);
3631
|| !upw->clientWindow) {
3632
Debug("Maximizing FAILED!\n");
3636
if (upw->isMaximized) {
3637
Atom data[5] = {0, 0, 0, 0, 0};
3639
data[0] = _NET_WM_STATE_REMOVE;
3640
data[1] = up->atoms._NET_WM_STATE_MAXIMIZED_HORZ;
3641
data[2] = up->atoms._NET_WM_STATE_MAXIMIZED_VERT;
3642
data[3] = 2; // Message is from a pager/taskbar/etc.
3643
UnityPlatformSendClientMessage(up, upw->rootWindow, upw->clientWindow,
3644
up->atoms._NET_WM_STATE, 32, 4, data);
3646
upw->isMaximized = FALSE;
3654
*------------------------------------------------------------------------------
3656
* UnityPlatformSetWindowDesktop --
3658
* Move the window to the specified desktop. The desktopId is an index
3659
* into the desktop configuration array.
3662
* Returns TRUE if successful, and FALSE otherwise.
3667
*------------------------------------------------------------------------------
3671
UnityPlatformSetWindowDesktop(UnityPlatform *up, // IN
3672
UnityWindowId windowId, // IN
3673
UnityDesktopId desktopId) // IN
3675
UnityPlatformWindow *upw;
3676
uint32 guestDesktopId;
3680
upw = UPWindow_Lookup(up, windowId);
3683
|| !upw->clientWindow) {
3684
Debug("Desktop change FAILED on %#lx (perhaps it has no clientWindow)!\n",
3685
upw ? upw->toplevelWindow : 0);
3690
* XXX I wrote this code assuming that UnityWindowTracker on the
3691
* guest side will be updated with the latest settings as they come
3692
* from the host, but that is not currently the case. unity.c needs
3696
ASSERT(desktopId < (int)up->desktopInfo.numDesktops);
3697
guestDesktopId = up->desktopInfo.unityDesktopToGuest[desktopId];
3699
UPWindow_SetEWMHDesktop(up, upw, guestDesktopId);
3706
*------------------------------------------------------------------------------
3708
* UPWindow_SetEWMHDesktop --
3710
* Move the window to the specified desktop. ewmhDesktopId corresponds
3711
* to a desktop index to be used with _NET_WM_DESKTOP.
3714
* This will directly change _NET_WM_DESKTOP of an unmapped window,
3715
* and will instead request the window manager to update that property
3716
* for a mapped window.
3721
*------------------------------------------------------------------------------
3726
UPWindow_SetEWMHDesktop(UnityPlatform *up, // IN
3727
UnityPlatformWindow *upw, // IN
3728
uint32 ewmhDesktopId) // IN
3730
Atom data[5] = {0, 0, 0, 0, 0};
3735
if (!upw->isViewable || upw->wantSetDesktopNumberOnUnmap) {
3736
Atom currentDesktop = ewmhDesktopId; // Cast for 64-bit correctness.
3739
* Sending the _NET_WM_DESKTOP client message only works if the
3740
* window is mapped. We should still send that message to
3741
* eliminate race conditions, but if the window is not mapped, we
3742
* also need to set the property on the window so that it shows
3743
* up on the correct desktop when it is re-mapped.
3745
* wantSetDesktopNumberOnUnmap implies that we unmapped the window
3746
* in question. We evaluate this here, in addition to isViewable,
3747
* because it's totally possible that the window server processed
3748
* our unmap request, but we just haven't received the notification
3749
* yet. (In other words, if that's the case, isViewable may still
3753
XChangeProperty(up->display, (Window)upw->clientWindow, up->atoms._NET_WM_DESKTOP,
3754
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)¤tDesktop, 1);
3757
data[0] = ewmhDesktopId;
3758
data[1] = 2; // Indicates that this was requested by the pager/taskbar/etc.
3759
UnityPlatformSendClientMessage(up,
3762
up->atoms._NET_WM_DESKTOP,
3768
*-----------------------------------------------------------------------------
3770
* UPWindowUpdateFrameExtents --
3772
* Lookup and record (cache) the _NET_FRAME_EXTENTS property.
3775
* If _NET_FRAME_EXTENTS is set, upw->frameExtents may be updated.
3780
*-----------------------------------------------------------------------------
3784
UPWindowUpdateFrameExtents(UnityPlatform *up,
3785
UnityPlatformWindow *upw)
3788
int propertyFormat = 0;
3789
unsigned long itemsReturned = 0;
3790
unsigned long bytesRemaining;
3791
unsigned char *valueReturned = NULL;
3792
Window w = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
3797
if (UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_FRAME_EXTENTS)
3798
&& XGetWindowProperty(up->display, w, up->atoms._NET_FRAME_EXTENTS, 0,
3799
1024, False, XA_CARDINAL,
3800
&propertyType, &propertyFormat, &itemsReturned,
3801
&bytesRemaining, &valueReturned) == Success
3802
&& propertyFormat == 32
3803
&& itemsReturned >= 4) {
3804
Atom *atomValue = (Atom *)valueReturned;
3806
upw->frameExtents[0] = atomValue[0];
3807
upw->frameExtents[1] = atomValue[1];
3808
upw->frameExtents[2] = atomValue[2];
3809
upw->frameExtents[3] = atomValue[3];
3811
XFree(valueReturned);