77
79
Window clientWindow);
84
*-----------------------------------------------------------------------------
86
* CompareStackingOrder --
88
* Very crudely compares the stacking orders of "relevant" windows as kept
89
* by the X server and ourselves. (By relevant, we mean only windows which
90
* are relayed to the window tracker.)
92
* If there's a mismatch, Debug() statements are generated showing which
93
* indices do not match and the corresponding window IDs. If there is a match,
94
* then the current stacking order is displayed. (The latter is useless on
95
* its own, but it's a handy bit of data to refer to when a mismatch is
99
* Additional noise is sent to the Tools log via Debug().
104
*-----------------------------------------------------------------------------
108
CompareStackingOrder(UnityPlatform *up, // IN
109
Window rootWindow, // IN
110
const char *callerName) // IN
112
Window *relevantUChildren = NULL;
113
Window *relevantXChildren = NULL;
114
Window *trackerChildren = NULL;
116
unsigned int numXRelevant; // relevant windows from the X server
117
unsigned int numURelevant; // relevant windows according to Unity
118
unsigned int nWindows; // Generic limit referring to all of *children variables
119
// after we determine that they are all the same
120
// size. Likely that it will be optimized out.
121
GList *unityList = NULL;
124
* First query the X server for a list of its top-level windows sorted
125
* from bottom to top stacking order.
130
Window *children = NULL;
131
unsigned int nchildren;
133
XQueryTree(up->display, rootWindow, &dummyroot, &dummyparent, &children,
137
* Now, filter out all of the relevant top-level windows into a local buffer
140
relevantXChildren = g_new(Window, nchildren);
142
for (i = 0, numXRelevant = 0; i < nchildren; i++) {
143
UnityPlatformWindow *tmpupw;
144
tmpupw = UPWindow_Lookup(up, children[i]);
145
if (tmpupw && tmpupw->isRelevant) {
146
relevantXChildren[numXRelevant++] = children[i];
154
* Do the same as above but for the windows known to Unity. These lists should
155
* -usually- match, but may get out of sync when a window disappears, for example.
156
* However, it's also -usually- only a matter of time before subsequent events show
157
* up and bring them back into sync.
159
* Note that this list is created by -prepending- windows. This is done because
160
* while we store windows in top-bottom stacking order, the X server maintains
161
* windows in bottom-top stacking order. For ease of comparison, I'm reversing
162
* our order in order to match the X server.
165
UnityPlatformWindow *myupw;
166
for (myupw = up->topWindow, numURelevant = 0;
168
myupw = myupw->lowerWindow) {
169
if (myupw->isRelevant) {
170
unityList = g_list_prepend(unityList, (gpointer)myupw->toplevelWindow);
177
* The following check ensures that all three window collections are the same
178
* size. With that in mind, for the sake of readability I'll use a variable,
179
* nWindows, to refer to this common size through the remainer of the function.
181
if (numURelevant != numXRelevant ||
182
numURelevant != up->tracker->count) {
183
Debug("%s: mismatch (count): server %u, unity %u, uwt %u\n", __func__,
184
numXRelevant, numURelevant, up->tracker->count);
188
nWindows = numURelevant;
191
* We're now sure that all sets of windows to be compared are the same size.
192
* Go ahead and allocate and populate new arrays for window set comparisons.
195
relevantUChildren = g_new(Window, nWindows);
196
trackerChildren = g_new(Window, nWindows);
199
* Convert the now sorted (see above re: g_list_prepend) Unity window list to
200
* an array for easy comparison with * the X server's array.
204
for (listIter = unityList, i = 0;
206
listIter = listIter->next, i++) {
207
relevantUChildren[i] = (Window)listIter->data;
212
* Once again, UWT stores windows in top-bottom stacking order, but we're
213
* comparing an array in bottom-top stacking order. This loop just copies
214
* and reverses the UWT's zorder array.
216
for (i = 0; i < nWindows; i++) {
217
trackerChildren[i] = up->tracker->zorder[(nWindows - 1) - i];
221
size_t childrenSize = nWindows * sizeof *relevantUChildren;
223
if (memcmp(relevantXChildren, relevantUChildren, childrenSize) ||
224
memcmp(relevantXChildren, trackerChildren, childrenSize)) {
225
Debug("%s: mismatch!\n", callerName);
226
Debug("%s: %8s %10s %10s %10s\n", callerName, "index", "X Server",
229
for (i = 0; i < nWindows; i++) {
230
if (relevantXChildren[i] != relevantUChildren[i] ||
231
relevantXChildren[i] != trackerChildren[i]) {
232
Debug("%s: [%6u] %#10lx %#10lx %#10lx\n", callerName, i,
233
relevantXChildren[i], relevantUChildren[i],
238
Debug("%s: match (%u windows).\n", callerName, nWindows);
239
for (i = 0; i < nWindows; i++) {
240
Debug("%s: [%u] %#lx\n", callerName, i, relevantXChildren[i]);
246
g_free(relevantXChildren);
247
g_free(relevantUChildren);
248
g_free(trackerChildren);
249
g_list_free(unityList);
81
255
*-----------------------------------------------------------------------------
275
450
HashTable_Delete(up->allWindows, GUINT_TO_POINTER(upw->clientWindow));
454
* Okay, now we may have two UnityPlatformWindows running around, one each for
455
* the top-level and client windows in response to their CreateNotify events,
456
* and this routine wishes to unify both in a single UPW.
458
* XXX The current course of action is this:
459
* 1. If either our operand top-level or client windows belong to
460
* any other UnityPlatformWindows, said UPWs will be dereferenced.
461
* 2. We'll then assign the operand windows to the current UPW.
463
scratchUpw = UPWindow_Lookup(up, toplevelWindow);
464
if (scratchUpw && scratchUpw != upw) {
465
UPWindow_Unref(up, scratchUpw);
467
scratchUpw = UPWindow_Lookup(up, clientWindow);
468
if (scratchUpw && scratchUpw != upw) {
469
UPWindow_Unref(up, scratchUpw);
278
472
upw->toplevelWindow = toplevelWindow;
279
473
upw->clientWindow = clientWindow;
816
1011
switch (motivator->type) {
817
1012
case PropertyNotify:
818
if (motivator->xproperty.atom != up->atoms._NET_WM_WINDOW_TYPE
819
&& motivator->xproperty.atom != up->atoms._NET_WM_DESKTOP) {
822
if (motivator->xproperty.atom == up->atoms._NET_WM_DESKTOP) {
1014
XPropertyEvent *event = (XPropertyEvent *)motivator;
1015
if (upw->waitingForWmState &&
1016
event->atom == up->atoms.WM_STATE &&
1017
event->state == PropertyNewValue) {
1018
Window toplevelWindow = 0;
1019
Window clientWindow = 0;
1020
Window rootWindow = 0;
1023
regetDesktop = TRUE;
1024
Debug("%s: PropertyNotify: New WM_STATE on %#lx (current upw: %#lx::%#lx)\n",
1025
__func__, event->window, upw->toplevelWindow, upw->clientWindow);
1026
success = UnityPlatformFindWindows(up, event->window,
1027
&toplevelWindow, &clientWindow,
1030
UPWindowSetWindows(up, upw, toplevelWindow, clientWindow);
1031
upw->waitingForWmState = FALSE;
1032
Debug("%s: PropertyNotify: new upw: %#lx::%#lx\n",
1033
__func__, upw->toplevelWindow, upw->clientWindow);
1035
Debug("%s: PropertyNotify: FindWindows failed again!\n", __func__);
1038
} else if (event->atom == up->atoms._NET_WM_DESKTOP) {
1039
regetDesktop = TRUE;
1040
} else if (event->atom != up->atoms._NET_WM_WINDOW_TYPE) {
851
1070
case ReparentNotify:
853
Window toplevelWindow;
1072
Window toplevelWindow = 0;
1073
Window clientWindow = 0;
1074
Window rootWindow = 0;
1075
const XReparentEvent *reparent = &motivator->xreparent;
857
1078
regetDesktop = TRUE;
858
Debug("Window %#lx was reparented to a window %#lx\n",
859
motivator->xreparent.window, motivator->xreparent.parent);
860
UnityPlatformFindWindows(up, motivator->xreparent.window,
864
UPWindowSetWindows(up, upw,
1079
Debug("%s: ReparentNotify: %#lx reparented to %#lx (current upw: %#lx::%#lx)\n",
1080
__func__, reparent->window, reparent->parent,
1081
upw->toplevelWindow, upw->clientWindow);
1082
success = UnityPlatformFindWindows(up, reparent->window,
1083
&toplevelWindow, &clientWindow,
1086
UPWindowSetWindows(up, upw, toplevelWindow, clientWindow);
1088
Debug("%s: ReparentNotify: UnityPlatformFindWindows failed."
1089
" Waiting for WM_STATE.\n", __func__);
1090
upw->waitingForWmState = TRUE;
1304
UnityRect actualRect;
1305
Window actualWindow;
1307
UPWindowGetActualWindowAndPosition(up, upw, moveResizeRect, &winAttr, &actualWindow, &actualRect);
1309
XMoveResizeWindow(up->display, actualWindow,
1310
actualRect.x, actualRect.y,
1311
actualRect.width, actualRect.height);
1312
Debug("MoveResizeWindow implemented using XMoveResizeWindow (requested (%d, %d) +(%d, %d) on %#lx\n",
1313
actualRect.x, actualRect.y, actualRect.width, actualRect.height,
1530
if (up->desktopInfo.currentDesktop == upw->desktopNumber) {
1531
UnityRect actualRect;
1532
Window actualWindow;
1534
UPWindowGetActualWindowAndPosition(up, upw, moveResizeRect, &winAttr, &actualWindow, &actualRect);
1536
XMoveResizeWindow(up->display, actualWindow,
1537
actualRect.x, actualRect.y,
1538
actualRect.width, actualRect.height);
1539
Debug("MoveResizeWindow implemented using XMoveResizeWindow (requested (%d, %d) +(%d, %d) on %#lx\n",
1540
actualRect.x, actualRect.y, actualRect.width, actualRect.height,
1543
Debug("Trying to move window %#lx that is on desktop %d instead of the current desktop %u\n",
1544
upw->toplevelWindow, upw->desktopNumber, up->desktopInfo.currentDesktop);
1491
1732
Debug("%s: Program %s not found\n", __FUNCTION__, argv[0]);
1498
if (argc > 1 || upw) {
1739
* If the program in question takes any arguments, they will be appended as URI
1740
* query parameters. (I.e., we're adding only arguments from argv[1] and beyond.)
1742
numQueryArgs = argc - 1;
1744
if (numQueryArgs > 0) {
1499
1745
UriQueryListA *queryList;
1500
char windowIdBuf[32];
1503
queryList = alloca((argc + 1) * sizeof *queryList);
1749
* First build query string containing only program arguments.
1751
queryList = alloca(numQueryArgs * sizeof *queryList);
1504
1752
for (i = 1, j = 0; i < argc; i++, j++) {
1505
1753
queryList[j].key = "argv[]";
1506
1754
queryList[j].value = argv[i];
1507
1755
queryList[j].next = &queryList[j + 1];
1511
* The XID is used to allow GHI to retrieve icons for more apps...
1513
queryList[j].key = "WindowXID";
1514
Str_Sprintf(windowIdBuf, sizeof windowIdBuf, "%lu",
1515
upw->clientWindow ? upw->clientWindow : upw->toplevelWindow);
1516
queryList[j].value = windowIdBuf;
1517
queryList[j].next = &queryList[j + 1];
1520
queryList[j - 1].next = NULL;
1522
if (uriComposeQueryMallocA(&queryString, queryList)) {
1759
* Terminate queryList.
1761
queryList[numQueryArgs - 1].next = NULL;
1763
if (uriComposeQueryMallocA(&execQueryString, queryList)) {
1523
1764
Debug("uriComposeQueryMallocA failed\n");
1770
* Now, if we are to identify a specific window, go ahead and tack on its
1771
* XID in a second buffer. Please see UnityPlatformGetWindowPath for more
1772
* an explanation about keeping the XID separate.
1775
Window xid = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
1777
* The XID is used to allow GHI to retrieve icons for more apps...
1779
windowQueryString = execQueryString ?
1780
g_strdup_printf("%s&WindowXID=%lu", execQueryString, xid) :
1781
g_strdup_printf("WindowXID=%lu", xid);
1528
1784
uriString = alloca(10 + 3 * strlen(argv[0])); // This formula comes from URI.h
1529
1785
err = uriUnixFilenameToUriStringA(argv[0], uriString);
1531
1787
Debug("uriUnixFilenameToUriStringA failed\n");
1537
* We could use uriparser to construct the whole URI with querystring for us, but
1538
* there doesn't seem to be any advantage to that right now, and it'd involve more
1541
return g_strdup_printf("%s?%s", uriString, queryString);
1543
return g_strdup(uriString);
1792
* We could use uriparser to construct the whole URI with querystring for us, but
1793
* there doesn't seem to be any advantage to that right now, and it'd involve more
1797
*windowUri = windowQueryString ?
1798
g_strdup_printf("%s?%s", uriString, windowQueryString) :
1799
g_strdup(uriString);
1801
*execUri = execQueryString ?
1802
g_strdup_printf("%s?%s", uriString, execQueryString) :
1803
g_strdup(uriString);
1808
g_free(windowQueryString);
1809
g_free(execQueryString);
1717
1991
* UnityPlatformGetWindowPath --
1719
* Get the information needed to re-launch a window and retrieve further information
1720
* on it. 'buf' should hold a null-terminated string that will be passed to the
1721
* UnityPlatformGetBinaryInfo() and GHIntegrationShellOpen() routines. The exact
1722
* meaning of its contents is platform-specific.
1993
* Get the information needed to re-launch a window and retrieve further
1994
* information on it.
1996
* 'buf' will hold two URI strings, one which uniquely identifies an X11
1997
* window (windowUri) and one which uniquely identifies the window's owning
1998
* executable (execUri).
2000
* windowUri is handy for getting icons and other data associated with a
2001
* specific window, whereas execUri is handy for uniquely identifying
2002
* applications for GHI. (The host uses our returned strings to uniquely
2003
* identify applications, and we don't want it to consider the window ID
2004
* for that purpose, as it causes the host to believe that two windows
2005
* from the same application are really associated with separate
2008
* I.e., <windowUri><nul><execUri><nul>
2010
* This RPC is overloaded with two URIs in order to maintain backwards
2011
* compatibility with older VMXs / host UIs expecting to pass the first
2012
* (and, to them, only known) URI to GHIGetBinaryInfo.
1725
2015
* TRUE if everything went ok, FALSE otherwise.
2861
3167
*-----------------------------------------------------------------------------
3169
* UPWindowIsNowWithdrawn --
3171
* In response to an update to a window's WM_STATE property, properties, test
3172
* whether or not the window has been withdrawn.
3175
* TRUE if we believe the window was withdrawn, FALSE otherwise.
3180
*-----------------------------------------------------------------------------
3184
UPWindowIsNowWithdrawn(UnityPlatform *up, // IN
3185
UnityPlatformWindow *upw, // IN
3186
const XPropertyEvent *xevent) // IN
3189
Bool isWithdrawn = FALSE;
3193
unsigned long nitems;
3194
unsigned long bytes_remaining;
3195
unsigned char *properties = NULL;
3197
mainWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
3200
* Per ICCCM §4.1.3.1, WM_STATE.state will either be set to WithdrawnState
3201
* or WM_STATE removed from a window when it is withdrawn.
3203
if (xevent->state == PropertyDelete) {
3207
if (XGetWindowProperty(up->display, mainWindow, up->atoms.WM_STATE,
3209
1, // length (in 32-bit chunks)
3211
AnyPropertyType, // requested property type
3212
&actual_type, // returned type
3213
&actual_format, // returned format
3214
&nitems, // # of items returned
3215
&bytes_remaining, // # of bytes remaining
3216
&properties) == Success) {
3217
uint32 *state = (uint32 *)properties;
3219
if (actual_type == None ||
3220
(nitems > 0 && *state == WithdrawnState)) {
3232
*-----------------------------------------------------------------------------
2863
3234
* UPWindowUpdateState --
2865
3236
* Tells the window tracker about the window's changes to the _NET_WM_STATE and
2909
3291
attrsAreSet[UNITY_WINDOW_ATTR_FULLSCREENED] =
2910
3292
attrsAreSet[UNITY_WINDOW_ATTR_ATTN_WANTED] = TRUE;
2912
if (XGetWindowProperty(up->display, mainWindow, up->atoms.WM_STATE, 0,
2913
1024, False, AnyPropertyType,
2914
&propertyType, &propertyFormat, &itemsReturned,
2915
&bytesRemaining, (unsigned char **) &valueReturned)
2918
* Some random error occurred - perhaps the window disappeared
3294
if (!UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_WM_STATE_HIDDEN)) {
3295
if (XGetWindowProperty(up->display, mainWindow, up->atoms.WM_STATE, 0,
3296
1024, False, AnyPropertyType,
3297
&propertyType, &propertyFormat, &itemsReturned,
3298
&bytesRemaining, (unsigned char **) &valueReturned)
3301
* Some random error occurred - perhaps the window disappeared
2923
if (propertyType == up->atoms.WM_STATE
2924
&& propertyFormat == 32
2926
&& valueReturned[0] == IconicState) {
3306
if (propertyType == up->atoms.WM_STATE
3307
&& propertyFormat == 32
3309
&& valueReturned[0] == IconicState) {
3312
XFree(valueReturned);
2929
XFree(valueReturned);
2931
3315
if (XGetWindowProperty(up->display, mainWindow, up->atoms._NET_WM_STATE, 0,
2932
3316
1024, False, AnyPropertyType,
3260
3668
if (!upw->isMinimized) {
3261
3669
Atom data[5] = {0, 0, 0, 0, 0};
3671
Debug("Minimizing window %#x\n", window);
3263
3672
upw->isMinimized = TRUE;
3264
3673
data[0] = _NET_WM_STATE_ADD;
3265
data[1] = up->atoms._NET_WM_STATE_MINIMIZED;
3674
if (UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_WM_STATE_MINIMIZED)) {
3675
data[1] = up->atoms._NET_WM_STATE_MINIMIZED;
3677
data[1] = up->atoms._NET_WM_STATE_HIDDEN;
3266
3679
data[3] = 2; // Message is from a pager/taskbar/etc.
3267
3680
UnityPlatformSendClientMessage(up, upw->rootWindow, upw->clientWindow,
3268
3681
up->atoms._NET_WM_STATE, 32, 4, data);
3270
3683
XIconifyWindow(up->display, upw->clientWindow, 0);
3685
Debug("Window %#x is already minimized\n", window);