~n-muench/ubuntu/oneiric/open-vm-tools/open-vm-tools.fix-836277

« back to all changes in this revision

Viewing changes to lib/unity/unityPlatformX11Window.c

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann
  • Date: 2008-10-23 15:32:00 UTC
  • mfrom: (1.1.2 upstream) (2.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20081023153200-gc1bfx89hj35c799
Tags: 2008.10.10-123053-2
* Correcting typo in dh_installinit call.
* Downgrading depends on module-assistant to recommends.

Show diffs side-by-side

added added

removed removed

Lines of Context:
56
56
#if defined(VM_HAVE_X11_SHAPE_EXT)
57
57
static void UPWindowUpdateShape(UnityPlatform *up, UnityPlatformWindow *upw);
58
58
#endif
59
 
static void UPWindowUpdateState(UnityPlatform *up, UnityPlatformWindow *upw);
 
59
static void UPWindowUpdateState(UnityPlatform *up,
 
60
                                UnityPlatformWindow *upw,
 
61
                                const XPropertyEvent *xevent);
60
62
static void UPWindowUpdateTitle(UnityPlatform *up, UnityPlatformWindow *upw);
61
63
static void UPWindowUpdateType(UnityPlatform *up, UnityPlatformWindow *upw);
62
64
static void UPWindowProcessConfigureEvent(UnityPlatform *up,
77
79
                               Window clientWindow);
78
80
 
79
81
 
 
82
#ifdef VMX86_DEVEL
 
83
/*
 
84
 *-----------------------------------------------------------------------------
 
85
 *
 
86
 * CompareStackingOrder --
 
87
 *
 
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.)
 
91
 *
 
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
 
96
 *      discovered.)
 
97
 *
 
98
 * Results:
 
99
 *      Additional noise is sent to the Tools log via Debug().
 
100
 *
 
101
 * Side effects:
 
102
 *      None.
 
103
 *
 
104
 *-----------------------------------------------------------------------------
 
105
 */
 
106
 
 
107
static void
 
108
CompareStackingOrder(UnityPlatform *up,         // IN
 
109
                     Window rootWindow,         // IN
 
110
                     const char *callerName)    // IN
 
111
{
 
112
   Window *relevantUChildren = NULL;
 
113
   Window *relevantXChildren = NULL;
 
114
   Window *trackerChildren = NULL;
 
115
   unsigned int i;
 
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;
 
122
 
 
123
   /*
 
124
    * First query the X server for a list of its top-level windows sorted
 
125
    * from bottom to top stacking order.
 
126
    */
 
127
   {
 
128
      Window dummyroot;
 
129
      Window dummyparent;
 
130
      Window *children = NULL;
 
131
      unsigned int nchildren;
 
132
 
 
133
      XQueryTree(up->display, rootWindow, &dummyroot, &dummyparent, &children,
 
134
                 &nchildren);
 
135
 
 
136
      /*
 
137
       * Now, filter out all of the relevant top-level windows into a local buffer
 
138
       * from the stack.
 
139
       */
 
140
      relevantXChildren = g_new(Window, nchildren);
 
141
 
 
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];
 
147
         }
 
148
      }
 
149
 
 
150
      XFree(children);
 
151
   }
 
152
 
 
153
   /*
 
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.
 
158
    *
 
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.
 
163
    */
 
164
   {
 
165
      UnityPlatformWindow *myupw;
 
166
      for (myupw = up->topWindow, numURelevant = 0;
 
167
           myupw;
 
168
           myupw = myupw->lowerWindow) {
 
169
         if (myupw->isRelevant) {
 
170
            unityList = g_list_prepend(unityList, (gpointer)myupw->toplevelWindow);
 
171
            ++numURelevant;
 
172
         }
 
173
      }
 
174
   }
 
175
 
 
176
   /*
 
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.
 
180
    */
 
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);
 
185
      goto out;
 
186
   }
 
187
 
 
188
   nWindows = numURelevant;
 
189
 
 
190
   /*
 
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.
 
193
    */
 
194
 
 
195
   relevantUChildren = g_new(Window, nWindows);
 
196
   trackerChildren = g_new(Window, nWindows);
 
197
 
 
198
   /*
 
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.
 
201
    */
 
202
   {
 
203
      GList *listIter;
 
204
      for (listIter = unityList, i = 0;
 
205
           listIter;
 
206
           listIter = listIter->next, i++) {
 
207
         relevantUChildren[i] = (Window)listIter->data;
 
208
      }
 
209
   }
 
210
 
 
211
   /*
 
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.
 
215
    */
 
216
   for (i = 0; i < nWindows; i++) {
 
217
      trackerChildren[i] = up->tracker->zorder[(nWindows - 1) - i];
 
218
   }
 
219
 
 
220
   {
 
221
      size_t childrenSize = nWindows * sizeof *relevantUChildren;
 
222
 
 
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",
 
227
               "Unity", "UWT");
 
228
 
 
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],
 
234
                     trackerChildren[i]);
 
235
            }
 
236
         }
 
237
      } else {
 
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]);
 
241
         }
 
242
      }
 
243
   }
 
244
 
 
245
out:
 
246
   g_free(relevantXChildren);
 
247
   g_free(relevantUChildren);
 
248
   g_free(trackerChildren);
 
249
   g_list_free(unityList);
 
250
}
 
251
#endif
 
252
 
 
253
 
80
254
/*
81
255
 *-----------------------------------------------------------------------------
82
256
 *
84
258
 *
85
259
 *      In X, the immediate children of the root window are almost always window manager
86
260
 *      windows that hold the app's windows. Sometimes we want to find the actual app's
87
 
 *      window to operate on. Given a random window ID, this function figures out which
88
 
 *      is which.
 
261
 *      window to operate on, usually identfied by the WM_STATE property. Given a random
 
262
 *      window ID, this function figures out which is which.
89
263
 *
90
264
 * Results:
91
265
 *      TRUE if successful, FALSE otherwise.
258
432
                   Window toplevelWindow,    // IN
259
433
                   Window clientWindow)      // IN
260
434
{
 
435
   UnityPlatformWindow *scratchUpw;
261
436
   Bool wasRelevant;
262
437
 
263
438
   ASSERT(up);
275
450
      HashTable_Delete(up->allWindows, GUINT_TO_POINTER(upw->clientWindow));
276
451
   }
277
452
 
 
453
   /*
 
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.
 
457
    *
 
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.
 
462
    */
 
463
   scratchUpw = UPWindow_Lookup(up, toplevelWindow);
 
464
   if (scratchUpw && scratchUpw != upw) {
 
465
      UPWindow_Unref(up, scratchUpw);
 
466
   }
 
467
   scratchUpw = UPWindow_Lookup(up, clientWindow);
 
468
   if (scratchUpw && scratchUpw != upw) {
 
469
      UPWindow_Unref(up, scratchUpw);
 
470
   }
 
471
 
278
472
   upw->toplevelWindow = toplevelWindow;
279
473
   upw->clientWindow = clientWindow;
280
474
 
587
781
            break;
588
782
         }
589
783
      }
590
 
      ASSERT(i < numWindows); 
 
784
      ASSERT(i < numWindows);
591
785
   }
592
786
 
593
787
   free(upwList);
667
861
 
668
862
      if (!newLowerWindow) {
669
863
         if (upw != up->topWindow) {
670
 
            Debug("BUG - couldn't find the window to stack above, placing at top.\n");
671
 
            newLowerWindow = up->topWindow;
 
864
            Debug("%s: Couldn't find the window to stack above [%#lx].\n",
 
865
                  __func__, above);
 
866
            return;
672
867
         } else {
673
868
            return;
674
869
         }
815
1010
       */
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) {
820
 
            return;
821
 
         }
822
 
         if (motivator->xproperty.atom == up->atoms._NET_WM_DESKTOP) {
823
 
            regetDesktop = TRUE;
 
1013
         {
 
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;
 
1021
               Bool success;
 
1022
 
 
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,
 
1028
                                                  &rootWindow);
 
1029
               if (success) {
 
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);
 
1034
               } else {
 
1035
                  Debug("%s: PropertyNotify: FindWindows failed again!\n", __func__);
 
1036
                  return;
 
1037
               }
 
1038
            } else if (event->atom == up->atoms._NET_WM_DESKTOP) {
 
1039
               regetDesktop = TRUE;
 
1040
            } else if (event->atom != up->atoms._NET_WM_WINDOW_TYPE) {
 
1041
               return;
 
1042
            }
824
1043
         }
825
1044
         break;
826
1045
 
850
1069
 
851
1070
      case ReparentNotify:
852
1071
         {
853
 
            Window toplevelWindow;
854
 
            Window clientWindow;
855
 
            Window rootWindow;
 
1072
            Window toplevelWindow = 0;
 
1073
            Window clientWindow = 0;
 
1074
            Window rootWindow = 0;
 
1075
            const XReparentEvent *reparent = &motivator->xreparent;
 
1076
            Bool success;
856
1077
 
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,
861
 
                                     &toplevelWindow,
862
 
                                     &clientWindow,
863
 
                                     &rootWindow);
864
 
            UPWindowSetWindows(up, upw,
865
 
                               toplevelWindow,
866
 
                               clientWindow);
 
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,
 
1084
                                               &rootWindow);
 
1085
            if (success) {
 
1086
               UPWindowSetWindows(up, upw, toplevelWindow, clientWindow);
 
1087
            } else {
 
1088
               Debug("%s: ReparentNotify: UnityPlatformFindWindows failed."
 
1089
                     "  Waiting for WM_STATE.\n", __func__);
 
1090
               upw->waitingForWmState = TRUE;
 
1091
               return;
 
1092
            }
867
1093
         }
868
1094
         break;
869
1095
 
1301
1527
   } else
1302
1528
#endif
1303
1529
   {
1304
 
      UnityRect actualRect;
1305
 
      Window actualWindow;
1306
 
 
1307
 
      UPWindowGetActualWindowAndPosition(up, upw, moveResizeRect, &winAttr, &actualWindow, &actualRect);
1308
 
 
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,
1314
 
            actualWindow);
 
1530
      if (up->desktopInfo.currentDesktop == upw->desktopNumber) {
 
1531
         UnityRect actualRect;
 
1532
         Window actualWindow;
 
1533
 
 
1534
         UPWindowGetActualWindowAndPosition(up, upw, moveResizeRect, &winAttr, &actualWindow, &actualRect);
 
1535
 
 
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,
 
1541
               actualWindow);
 
1542
      } else {
 
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);
 
1545
         return FALSE;
 
1546
      }
1315
1547
   }
1316
1548
 
1317
1549
   /*
1436
1668
/*
1437
1669
 *-----------------------------------------------------------------------------
1438
1670
 *
1439
 
 * UnityPlatformArgvToWindowPath --
 
1671
 * UnityPlatformArgvToWindowPaths --
1440
1672
 *
1441
 
 *      Encodes the string array 'argv' into the DynBuf 'buf'.
 
1673
 *      Encodes the string array 'argv' into two window paths, one uniquely
 
1674
 *      representing a window and another its owning application.
1442
1675
 *
1443
1676
 * Results:
1444
 
 *      TRUE if successful, FALSE otherwise.
 
1677
 *      TRUE on success, FALSE on failure.
1445
1678
 *
1446
1679
 * Side effects:
1447
1680
 *      None.
1449
1682
 *-----------------------------------------------------------------------------
1450
1683
 */
1451
1684
 
1452
 
static char *
1453
 
UnityPlatformArgvToWindowPath(UnityPlatform *up,        // IN
1454
 
                              UnityPlatformWindow *upw, // IN
1455
 
                              char **inArgv,            // IN
1456
 
                              int argc,                 // IN
1457
 
                              char *cwd)                // IN
 
1685
static Bool
 
1686
UnityPlatformArgvToWindowPaths(UnityPlatform *up,        // IN
 
1687
                               UnityPlatformWindow *upw, // IN
 
1688
                               char **inArgv,            // IN
 
1689
                               int argc,                 // IN
 
1690
                               char *cwd,                // IN
 
1691
                               gchar **windowUri,        // OUT
 
1692
                               gchar **execUri)          // OUT
1458
1693
{
 
1694
   int numQueryArgs;
1459
1695
   int i;
1460
1696
   int err;
1461
1697
   char *ctmp = NULL;
1462
1698
   char **argv;
1463
 
   char *queryString = NULL;
 
1699
   char *windowQueryString = NULL;
 
1700
   char *execQueryString = NULL;
1464
1701
   char *uriString = NULL;
 
1702
   Bool retval = FALSE;
1465
1703
 
1466
1704
   ASSERT(argc);
 
1705
   ASSERT(windowUri);
 
1706
   ASSERT(execUri);
1467
1707
 
1468
1708
   argv = inArgv;
1469
1709
 
1474
1714
   }
1475
1715
 
1476
1716
   if (!argc) {
1477
 
      return NULL;
 
1717
      Debug("%s: all args determined skippable.\n", __func__);
 
1718
      return FALSE;
1478
1719
   }
1479
1720
 
1480
1721
   if (argv[0][0] != '/') {
1489
1730
         g_free(ctmp);
1490
1731
      } else {
1491
1732
         Debug("%s: Program %s not found\n", __FUNCTION__, argv[0]);
1492
 
         return NULL;
 
1733
         return FALSE;
1493
1734
      }
1494
1735
   }
1495
 
 
1496
1736
#endif
1497
1737
 
1498
 
   if (argc > 1 || upw) {
 
1738
   /*
 
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.)
 
1741
    */
 
1742
   numQueryArgs = argc - 1;
 
1743
 
 
1744
   if (numQueryArgs > 0) {
1499
1745
      UriQueryListA *queryList;
1500
 
      char windowIdBuf[32];
1501
1746
      int j;
1502
1747
 
1503
 
      queryList = alloca((argc + 1) * sizeof *queryList);
 
1748
      /*
 
1749
       * First build query string containing only program arguments.
 
1750
       */
 
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];
1508
1756
      }
1509
 
      if (upw) {
1510
 
         /*
1511
 
          * The XID is used to allow GHI to retrieve icons for more apps...
1512
 
          */
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];
1518
 
         j++;
1519
 
      }
1520
 
      queryList[j - 1].next = NULL;
1521
 
 
1522
 
      if (uriComposeQueryMallocA(&queryString, queryList)) {
 
1757
 
 
1758
      /*
 
1759
       * Terminate queryList.
 
1760
       */
 
1761
      queryList[numQueryArgs - 1].next = NULL;
 
1762
 
 
1763
      if (uriComposeQueryMallocA(&execQueryString, queryList)) {
1523
1764
         Debug("uriComposeQueryMallocA failed\n");
1524
 
         return NULL;
 
1765
         return FALSE;
1525
1766
      }
1526
1767
   }
1527
1768
 
 
1769
   /*
 
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.
 
1773
    */
 
1774
   if (upw) {
 
1775
      Window xid = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
 
1776
      /*
 
1777
       * The XID is used to allow GHI to retrieve icons for more apps...
 
1778
       */
 
1779
      windowQueryString = execQueryString ?
 
1780
         g_strdup_printf("%s&WindowXID=%lu", execQueryString, xid) :
 
1781
         g_strdup_printf("WindowXID=%lu", xid);
 
1782
   }
 
1783
 
1528
1784
   uriString = alloca(10 + 3 * strlen(argv[0])); // This formula comes from URI.h
1529
1785
   err = uriUnixFilenameToUriStringA(argv[0], uriString);
1530
1786
   if (err) {
1531
1787
      Debug("uriUnixFilenameToUriStringA failed\n");
1532
 
      return NULL;
1533
 
   }
1534
 
 
1535
 
   if (queryString) {
1536
 
      /*
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
1539
 
       * steps.
1540
 
       */
1541
 
      return g_strdup_printf("%s?%s", uriString, queryString);
1542
 
   } else {
1543
 
      return g_strdup(uriString);
1544
 
   }
 
1788
      goto out;
 
1789
   }
 
1790
 
 
1791
   /*
 
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
 
1794
    * steps.
 
1795
    */
 
1796
 
 
1797
   *windowUri = windowQueryString ?
 
1798
      g_strdup_printf("%s?%s", uriString, windowQueryString) :
 
1799
      g_strdup(uriString);
 
1800
 
 
1801
   *execUri = execQueryString ?
 
1802
      g_strdup_printf("%s?%s", uriString, execQueryString) :
 
1803
      g_strdup(uriString);
 
1804
 
 
1805
   retval = TRUE;
 
1806
 
 
1807
out:
 
1808
   g_free(windowQueryString);
 
1809
   g_free(execQueryString);
 
1810
 
 
1811
   return retval;
1545
1812
}
1546
1813
 
1547
1814
 
1550
1817
 *
1551
1818
 * UnityPlatformReadProcessPath --
1552
1819
 *
1553
 
 *      Reads the cmdline of a process and stuffs it into the supplied DynBuf in
1554
 
 *      URI-encoded form.
 
1820
 *      Reads the cmdline of a process and stuffs it with and without window ID
 
1821
 *      into supplied gchar ** arguments in URI-encoded form.
1555
1822
 *
1556
1823
 * Results:
1557
1824
 *      TRUE if successful, FALSE otherwise.
1558
1825
 *
1559
1826
 * Side effects:
1560
 
 *      Stores a NULL-terminated string in 'buf' for later use by GHI.
 
1827
 *      Values of windowUri and execUri may point to strings.
1561
1828
 *
1562
1829
 *-----------------------------------------------------------------------------
1563
1830
 */
1564
1831
 
1565
 
static char *
 
1832
static Bool
1566
1833
UnityPlatformReadProcessPath(UnityPlatform *up,        // IN
1567
1834
                             UnityPlatformWindow *upw, // IN
1568
 
                             pid_t pid)                // IN
 
1835
                             pid_t pid,                // IN
 
1836
                             gchar **windowUri,        // OUT
 
1837
                             gchar **execUri)          // OUT
1569
1838
{
1570
1839
#if defined(linux)
1571
1840
   FILE *fh;
1576
1845
   Str_Snprintf(cbuf, sizeof cbuf, "/proc/%d/cwd", pid);
1577
1846
   i = readlink(cbuf, cwdbuf, sizeof cwdbuf);
1578
1847
   if (i <= 0) {
1579
 
      return NULL;
 
1848
      return FALSE;
1580
1849
   }
1581
1850
   cwdbuf[i] = '\0';
1582
1851
 
1602
1871
      }
1603
1872
      argv[argc] = NULL;
1604
1873
 
1605
 
      return UnityPlatformArgvToWindowPath(up, upw, argv, argc, cwdbuf);
 
1874
      return UnityPlatformArgvToWindowPaths(up, upw, argv, argc, cwdbuf,
 
1875
                                            windowUri, execUri);
1606
1876
   }
1607
1877
#endif
1608
1878
 
1613
1883
/*
1614
1884
 *-----------------------------------------------------------------------------
1615
1885
 *
1616
 
 * UnityX11GetWindowPath --
 
1886
 * UnityX11GetWindowPaths --
1617
1887
 *
1618
1888
 *      Internal routine used to retrieve the window path for the purpose of getting its
1619
1889
 *      icons and for the unity.get.window.path operation.
1620
1890
 *
1621
1891
 * Results:
1622
 
 *      Newly allocated window path if successful, NULL otherwise.
 
1892
 *      TRUE on success, FALSE on failure.
1623
1893
 *
1624
1894
 * Side effects:
1625
 
 *      Allocates memory to be returned to caller.
 
1895
 *      Allocates memory to be returned to caller via g_free.
1626
1896
 *
1627
1897
 *-----------------------------------------------------------------------------
1628
1898
 */
1629
1899
 
1630
 
static char *
1631
 
UnityX11GetWindowPath(UnityPlatform *up,
1632
 
                      UnityPlatformWindow *upw)
 
1900
static Bool
 
1901
UnityX11GetWindowPaths(UnityPlatform *up,        // IN
 
1902
                       UnityPlatformWindow *upw, // IN
 
1903
                       gchar **windowUri,        // OUT
 
1904
                       gchar **execUri)          // OUT
1633
1905
{
1634
1906
 
1635
1907
   Atom propertyType;
1642
1914
   XClassHint classHint = {NULL, NULL};
1643
1915
   int ret;
1644
1916
   Window checkWindow;
1645
 
   char *retval = NULL;
 
1917
   Bool retval = FALSE;
1646
1918
 
1647
1919
   checkWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
1648
1920
 
1652
1924
                            &propertyType, &propertyFormat, &itemsReturned,
1653
1925
                            &bytesRemaining, &valueReturned);
1654
1926
   if (UnityPlatformGetErrorCount(up) || ret != Success) {
1655
 
      return NULL;
 
1927
      return FALSE;
1656
1928
   }
1657
1929
 
1658
1930
   if (propertyType == XA_CARDINAL && itemsReturned >= 1) {
1672
1944
      }
1673
1945
 
1674
1946
      if (windowPid) {
1675
 
         retval = UnityPlatformReadProcessPath(up, upw, windowPid);
 
1947
         retval = UnityPlatformReadProcessPath(up, upw, windowPid, windowUri,
 
1948
                                               execUri);
1676
1949
      }
1677
1950
   }
1678
1951
   XFree(valueReturned);
1679
1952
 
1680
1953
   if (!retval && XGetCommand(up->display, checkWindow, &argv, &argc)) {
1681
 
      retval = UnityPlatformArgvToWindowPath(up, upw, argv, argc, NULL);
1682
 
 
 
1954
      retval = UnityPlatformArgvToWindowPaths(up, upw, argv, argc, NULL,
 
1955
                                              windowUri, execUri);
1683
1956
      XFreeStringList(argv);
1684
1957
   }
1685
1958
 
1697
1970
      }
1698
1971
 
1699
1972
      if (fakeArgv[0] && *(fakeArgv[0])) {
1700
 
         retval = UnityPlatformArgvToWindowPath(up, upw, fakeArgv, 1, NULL);
 
1973
         retval = UnityPlatformArgvToWindowPaths(up, upw, fakeArgv, 1, NULL,
 
1974
                                                 windowUri, execUri);
1701
1975
      }
1702
1976
 
1703
1977
      XFree(classHint.res_name);
1704
1978
      XFree(classHint.res_class);
1705
1979
   }
1706
1980
 
1707
 
   Debug("UnityX11GetWindowPath(%#lx) returning \"%s\"\n",
1708
 
         upw->toplevelWindow, retval);
 
1981
   Debug("UnityX11GetWindowPath(%#lx) returning %s\n", upw->toplevelWindow,
 
1982
         retval ? "TRUE" : "FALSE");
1709
1983
 
1710
1984
   return retval;
1711
1985
}
1716
1990
 *
1717
1991
 * UnityPlatformGetWindowPath --
1718
1992
 *
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.
 
1995
 *
 
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).
 
1999
 *
 
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
 
2006
 *      applications.)
 
2007
 *
 
2008
 *      I.e., <windowUri><nul><execUri><nul>
 
2009
 *
 
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.
1723
2013
 *
1724
2014
 * Results:
1725
2015
 *      TRUE if everything went ok, FALSE otherwise.
1737
2027
{
1738
2028
   UnityPlatformWindow *upw;
1739
2029
   Bool retval = FALSE;
1740
 
   char *retstr;
 
2030
   gchar *windowUri;
 
2031
   gchar *execUri;
1741
2032
 
1742
2033
   ASSERT(up);
1743
2034
 
1748
2039
      return FALSE;
1749
2040
   }
1750
2041
 
1751
 
   retstr = UnityX11GetWindowPath(up, upw);
 
2042
   retval = UnityX11GetWindowPaths(up, upw, &windowUri, &execUri);
1752
2043
 
1753
 
   if (!retstr) {
 
2044
   if (!retval) {
1754
2045
      Debug("GetWindowPath didn't know how to identify the window...\n");
1755
2046
   } else {
1756
 
      Debug("GetWindowPath window %#x results in: %s\n",
1757
 
            window, retstr);
1758
 
      DynBuf_AppendString(buf, retstr);
1759
 
      g_free(retstr);
 
2047
      Debug("GetWindowPath window %#x results in: \n"
 
2048
            "   windowUri = %s\n"
 
2049
            "   execUri = %s\n",
 
2050
            window, windowUri, execUri);
 
2051
 
 
2052
      DynBuf_AppendString(buf, windowUri);
 
2053
      DynBuf_AppendString(buf, execUri);
 
2054
 
 
2055
      g_free(windowUri);
 
2056
      g_free(execUri);
1760
2057
      retval = TRUE;
1761
2058
   }
1762
2059
 
1919
2216
       || (upw->iconPng.type != iconType)) {
1920
2217
      GPtrArray *pixbufs;
1921
2218
      Bool gotIcons = FALSE;
1922
 
      char *windowPath;
1923
2219
 
1924
 
      windowPath = UnityX11GetWindowPath(up, upw);
1925
 
      pixbufs = AppUtil_CollectIconArray(windowPath, upw->clientWindow);
1926
 
      g_free(windowPath);
 
2220
      pixbufs = AppUtil_CollectIconArray(NULL, upw->clientWindow);
1927
2221
 
1928
2222
      if (pixbufs && pixbufs->len) {
1929
2223
         GdkPixbuf *pixbuf;
2006
2300
      return FALSE;
2007
2301
   }
2008
2302
 
 
2303
   Debug("UnityPlatformRestoreWindow(%#lx)\n", upw->toplevelWindow);
2009
2304
   if (upw->isMinimized) {
2010
2305
      Atom data[5] = {0, 0, 0, 0, 0};
2011
2306
 
2023
2318
      }
2024
2319
 
2025
2320
      data[0] = _NET_WM_STATE_REMOVE;
2026
 
      data[1] = up->atoms._NET_WM_STATE_MINIMIZED;
2027
 
      data[2] = up->atoms._NET_WM_STATE_HIDDEN;
 
2321
      data[1] = up->atoms._NET_WM_STATE_HIDDEN;
 
2322
      data[2] = up->atoms._NET_WM_STATE_MINIMIZED;
2028
2323
      data[3] = 2; // Message is from the pager/taskbar
2029
2324
      UnityPlatformSendClientMessage(up, upw->rootWindow, upw->clientWindow,
2030
2325
                                     up->atoms._NET_WM_STATE, 32, 4, data);
 
2326
   } else {
 
2327
      Debug("Window %#x is already restored\n", window);
2031
2328
   }
2032
2329
 
2033
2330
   return TRUE;
2067
2364
   ASSERT(xevent);
2068
2365
 
2069
2366
   eventAtom = xevent->xproperty.atom;
2070
 
   if (eventAtom == up->atoms._NET_WM_STATE
2071
 
       || eventAtom == up->atoms.WM_STATE) {
2072
 
      UPWindowUpdateState(up, upw);
 
2367
   if (eventAtom == up->atoms._NET_WM_STATE ||
 
2368
       eventAtom == up->atoms.WM_STATE) {
 
2369
      UPWindowUpdateState(up, upw, &xevent->xproperty);
2073
2370
      if (eventAtom == up->atoms.WM_STATE) {
2074
2371
         UPWindowUpdateIcon(up, upw);
2075
2372
      }
2153
2450
      Debug("ProcessConfigureEvent skipped event on window %#lx (upw was %#lx/%#lx)\n",
2154
2451
            xevent->xconfigure.window, upw->toplevelWindow, upw->clientWindow);
2155
2452
   }
 
2453
 
 
2454
#ifdef VMX86_DEVEL
 
2455
   CompareStackingOrder(up, upw->rootWindow, __func__);
 
2456
#endif
2156
2457
}
2157
2458
 
2158
2459
 
2293
2594
   ASSERT(xevent->type == (up->shapeEventBase + ShapeNotify));
2294
2595
 
2295
2596
   sev = (XShapeEvent *)xevent;
2296
 
   ASSERT (sev->window == upw->toplevelWindow);
 
2597
   ASSERT (sev->window == upw->toplevelWindow ||
 
2598
           sev->window == upw->clientWindow);
2297
2599
 
2298
2600
   if (sev->shaped) {
2299
2601
      UPWindowUpdateShape(up, upw);
2397
2699
       */
2398
2700
      upw->windowType = UNITY_WINDOW_TYPE_NONE;
2399
2701
      UPWindow_Unref(up, upw);
 
2702
#ifdef VMX86_DEVEL
 
2703
   CompareStackingOrder(up, upw->rootWindow, __func__);
 
2704
#endif
2400
2705
      break;
2401
2706
 
2402
2707
   case UnmapNotify:
2812
3117
         desktopId = up->desktopInfo.guestDesktopToUnity[guestDesktop];
2813
3118
      }
2814
3119
 
 
3120
      Debug("Window %#lx is now on desktop %d\n", upw->toplevelWindow, desktopId);
2815
3121
      UnityWindowTracker_ChangeWindowDesktop(up->tracker,
2816
3122
                                             upw->toplevelWindow,
2817
3123
                                             desktopId);
2860
3166
/*
2861
3167
 *-----------------------------------------------------------------------------
2862
3168
 *
 
3169
 * UPWindowIsNowWithdrawn  --
 
3170
 *
 
3171
 *      In response to an update to a window's WM_STATE property, properties, test
 
3172
 *      whether or not the window has been withdrawn.
 
3173
 *
 
3174
 * Results:
 
3175
 *      TRUE if we believe the window was withdrawn, FALSE otherwise.
 
3176
 *
 
3177
 * Side effects:
 
3178
 *      None.
 
3179
 *
 
3180
 *-----------------------------------------------------------------------------
 
3181
 */
 
3182
 
 
3183
static Bool
 
3184
UPWindowIsNowWithdrawn(UnityPlatform *up,            // IN
 
3185
                       UnityPlatformWindow *upw,     // IN
 
3186
                       const XPropertyEvent *xevent) // IN
 
3187
{
 
3188
   Window mainWindow;
 
3189
   Bool isWithdrawn = FALSE;
 
3190
 
 
3191
   Atom actual_type;
 
3192
   int actual_format;
 
3193
   unsigned long nitems;
 
3194
   unsigned long bytes_remaining;
 
3195
   unsigned char *properties = NULL;
 
3196
 
 
3197
   mainWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
 
3198
 
 
3199
   /*
 
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.
 
3202
    */
 
3203
   if (xevent->state == PropertyDelete) {
 
3204
      return TRUE;
 
3205
   }
 
3206
 
 
3207
   if (XGetWindowProperty(up->display, mainWindow, up->atoms.WM_STATE,
 
3208
                      0,                // offset
 
3209
                      1,                // length (in 32-bit chunks)
 
3210
                      False,            // delete
 
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;
 
3218
 
 
3219
      if (actual_type == None ||
 
3220
          (nitems > 0 && *state == WithdrawnState)) {
 
3221
         isWithdrawn = TRUE;
 
3222
      }
 
3223
 
 
3224
      XFree(properties);
 
3225
   }
 
3226
 
 
3227
   return isWithdrawn;
 
3228
}
 
3229
 
 
3230
 
 
3231
/*
 
3232
 *-----------------------------------------------------------------------------
 
3233
 *
2863
3234
 * UPWindowUpdateState --
2864
3235
 *
2865
3236
 *      Tells the window tracker about the window's changes to the _NET_WM_STATE and
2875
3246
 */
2876
3247
 
2877
3248
static void
2878
 
UPWindowUpdateState(UnityPlatform *up,        // IN
2879
 
                    UnityPlatformWindow *upw) // IN
 
3249
UPWindowUpdateState(UnityPlatform *up,            // IN
 
3250
                    UnityPlatformWindow *upw,     // IN
 
3251
                    const XPropertyEvent *xevent) // IN
2880
3252
{
2881
3253
   Atom propertyType;
2882
3254
   int propertyFormat;
2895
3267
 
2896
3268
   mainWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
2897
3269
 
 
3270
   /*
 
3271
    * If a change to WM_STATE indicates this window was withdrawn/unmapped, simply
 
3272
    * invalidate it from the window tracker and return.
 
3273
    */
 
3274
   if (xevent->atom == up->atoms.WM_STATE &&
 
3275
       UPWindowIsNowWithdrawn(up, upw, xevent)) {
 
3276
      UPWindowSetRelevance(up, upw, FALSE);
 
3277
      return;
 
3278
   }
 
3279
 
2898
3280
   memset(curAttrValues, 0, sizeof curAttrValues);
2899
3281
   memset(attrsAreSet, 0, sizeof attrsAreSet);
2900
3282
 
2909
3291
      attrsAreSet[UNITY_WINDOW_ATTR_FULLSCREENED] =
2910
3292
      attrsAreSet[UNITY_WINDOW_ATTR_ATTN_WANTED] = TRUE;
2911
3293
 
2912
 
   if (XGetWindowProperty(up->display, mainWindow, up->atoms.WM_STATE, 0,
2913
 
                          1024, False, AnyPropertyType,
2914
 
                          &propertyType, &propertyFormat, &itemsReturned,
2915
 
                          &bytesRemaining, (unsigned char **) &valueReturned)
2916
 
       != Success) {
2917
 
      /*
2918
 
       * Some random error occurred - perhaps the window disappeared
2919
 
       */
2920
 
      return;
2921
 
   }
 
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)
 
3299
          != Success) {
 
3300
         /*
 
3301
          * Some random error occurred - perhaps the window disappeared
 
3302
          */
 
3303
         return;
 
3304
      }
2922
3305
 
2923
 
   if (propertyType == up->atoms.WM_STATE
2924
 
       && propertyFormat == 32
2925
 
       && itemsReturned
2926
 
       && valueReturned[0] == IconicState) {
2927
 
      isMinimized = TRUE;
 
3306
      if (propertyType == up->atoms.WM_STATE
 
3307
          && propertyFormat == 32
 
3308
          && itemsReturned
 
3309
          && valueReturned[0] == IconicState) {
 
3310
         isMinimized = TRUE;
 
3311
      }
 
3312
      XFree(valueReturned);
2928
3313
   }
2929
 
   XFree(valueReturned);
2930
3314
 
2931
3315
   if (XGetWindowProperty(up->display, mainWindow, up->atoms._NET_WM_STATE, 0,
2932
3316
                          1024, False, AnyPropertyType,
2954
3338
          * Unfortunately, the HIDDEN attribute is used by some WM's to mean
2955
3339
          * "minimized" when they should really be separate.
2956
3340
          */
2957
 
         isMinimized = TRUE;
 
3341
 
 
3342
         uint32 cDesk = -1;
 
3343
         uint32 gDesk;
 
3344
 
 
3345
         /*
 
3346
          * Only push minimize state for windows on the same desktop.
 
3347
          */
 
3348
         if (UPWindowGetDesktop(up, upw, &gDesk)) {
 
3349
            cDesk = UnityX11GetCurrentDesktop(up);
 
3350
            if (cDesk == gDesk) {
 
3351
               isMinimized = TRUE;
 
3352
            }
 
3353
         } else {
 
3354
            Debug("%s: Unable to get window desktop\n", __FUNCTION__);
 
3355
         }
2958
3356
         continue;
2959
3357
      } else if (valueReturned[i] == up->atoms._NET_WM_STATE_MAXIMIZED_HORZ) {
2960
3358
         haveHorizMax = TRUE;
3005
3403
 
3006
3404
      newState = info->state;
3007
3405
      if (isMinimized) {
3008
 
         newState |= UNITY_WINDOW_STATE_MINIMIZED;
 
3406
         if (! (newState & UNITY_WINDOW_STATE_MINIMIZED)) {
 
3407
            Debug("Enabling minimized attribute for window %#lx/%#lx\n",
 
3408
                  upw->toplevelWindow, upw->clientWindow);
 
3409
            newState |= UNITY_WINDOW_STATE_MINIMIZED;
 
3410
         }
3009
3411
      } else {
3010
 
         newState &= ~UNITY_WINDOW_STATE_MINIMIZED;
 
3412
         if ((newState & UNITY_WINDOW_STATE_MINIMIZED)) {
 
3413
            Debug("Disabling minimized attribute for window %#lx/%#lx\n",
 
3414
                  upw->toplevelWindow, upw->clientWindow);
 
3415
            newState &= ~UNITY_WINDOW_STATE_MINIMIZED;
 
3416
         }
3011
3417
      }
3012
3418
 
3013
 
      UnityWindowTracker_ChangeWindowState(up->tracker,
3014
 
                                           upw->toplevelWindow,
3015
 
                                           newState);
 
3419
      if (newState != info->state) {
 
3420
         UnityWindowTracker_ChangeWindowState(up->tracker,
 
3421
                                              upw->toplevelWindow,
 
3422
                                              newState);
 
3423
      }
3016
3424
 
3017
3425
      upw->isMinimized = isMinimized;
3018
3426
      upw->isMaximized = (haveHorizMax && haveVertMax);
3260
3668
   if (!upw->isMinimized) {
3261
3669
      Atom data[5] = {0, 0, 0, 0, 0};
3262
3670
 
 
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;
 
3676
      } else {
 
3677
         data[1] = up->atoms._NET_WM_STATE_HIDDEN;
 
3678
      }
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);
3269
3682
 
3270
3683
      XIconifyWindow(up->display, upw->clientWindow, 0);
 
3684
   } else {
 
3685
      Debug("Window %#x is already minimized\n", window);
3271
3686
   }
3272
3687
 
3273
3688