~n-muench/ubuntu/precise/open-vm-tools/open-vm-tools-precise.sid-merge1

« back to all changes in this revision

Viewing changes to services/plugins/unity/unitylib/unityPlatformX11Window.cc

  • Committer: Bazaar Package Importer
  • Author(s): Serge Hallyn
  • Date: 2011-03-31 14:20:05 UTC
  • mfrom: (1.4.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110331142005-3n9red91p7ogkweo
Tags: 2011.03.28-387002-0ubuntu1
* Merge latest upstream git tag.  This has the unlocked_ioctl change
  needed to fix dkms build failures (LP: #727342)
* Changes in debian/rules:
  - work around a bug in toolbox/Makefile, where install-exec-hook is
    not happening.  This needs to get fixed the right way.
  - don't install 'vmware-user' which seems to no longer exist
  - move /etc/xdg into open-vm-toolbox (which should be done using .install)
* debian/open-vm-tools.init: add 'modprobe [-r] vmblock'. (LP: #332323)
* debian/rules and debian/open-vm-toolbox.lintian-overrides:
  - Make vmware-user-suid-wrapper suid-root (LP: #332323)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*********************************************************
 
2
 * Copyright (C) 2007-2010 VMware, Inc. All rights reserved.
 
3
 *
 
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.
 
7
 *
 
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.
 
12
 *
 
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.
 
16
 *
 
17
 *********************************************************/
 
18
 
 
19
/*
 
20
 * unityPlatformX11Window.c --
 
21
 *
 
22
 *    Implementation of Unity for guest operating systems that use the X11 windowing
 
23
 *    system. This file implements per-window operations (move, minimize, etc.)
 
24
 */
 
25
 
 
26
#include "unityX11.h"
 
27
extern "C" {
 
28
#include "base64.h"
 
29
#include "region.h"
 
30
#include "imageUtil.h"
 
31
#include <time.h>
 
32
#include <sys/types.h>
 
33
#include <unistd.h>
 
34
#include <stdio.h>
 
35
#include <stdlib.h>
 
36
#include <limits.h>
 
37
}
 
38
 
 
39
#include "Uri.h"
 
40
#include "appUtil.h"
 
41
#include "ghIntegration.h"
 
42
 
 
43
using vmware::tools::unity::WindowPathFactory;
 
44
 
 
45
/*
 
46
 * Utility routines
 
47
 */
 
48
static Bool UnityPlatformFindWindows(UnityPlatform *up,
 
49
                                     Window currentWindow,
 
50
                                     Window *toplevelWindow,
 
51
                                     Window *clientWindow,
 
52
                                     Window *rootWindow);
 
53
static Bool UPWindowPushFullUpdate(UnityPlatform *up, UnityPlatformWindow *upw);
 
54
static void UPWindowSetRelevance(UnityPlatform *up,
 
55
                                 UnityPlatformWindow *upw,
 
56
                                 Bool isRelevant);
 
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);
 
63
#endif
 
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,
 
80
                               int *guestDesktop);
 
81
static void UPWindowSetWindows(UnityPlatform *up,
 
82
                               UnityPlatformWindow *upw,
 
83
                               Window toplevelWindow,
 
84
                               Window clientWindow);
 
85
static void UPWindowUpdateFrameExtents(UnityPlatform *up,
 
86
                                       UnityPlatformWindow *upw);
 
87
 
 
88
 
 
89
#ifdef VMX86_DEVEL
 
90
/*
 
91
 *-----------------------------------------------------------------------------
 
92
 *
 
93
 * CompareStackingOrder --
 
94
 *
 
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.)
 
98
 *
 
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
 
103
 *      discovered.)
 
104
 *
 
105
 * Results:
 
106
 *      Additional noise is sent to the Tools log via Debug().
 
107
 *
 
108
 * Side effects:
 
109
 *      None.
 
110
 *
 
111
 *-----------------------------------------------------------------------------
 
112
 */
 
113
 
 
114
static void
 
115
CompareStackingOrder(UnityPlatform *up,         // IN
 
116
                     Window rootWindow,         // IN
 
117
                     const char *callerName)    // IN
 
118
{
 
119
   Window *relevantUChildren = NULL;
 
120
   Window *relevantXChildren = NULL;
 
121
   Window *trackerChildren = NULL;
 
122
   unsigned int i;
 
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;
 
129
 
 
130
   /*
 
131
    * First query the X server for a list of its top-level windows sorted
 
132
    * from bottom to top stacking order.
 
133
    */
 
134
   {
 
135
      Window dummyroot;
 
136
      Window dummyparent;
 
137
      Window *children = NULL;
 
138
      unsigned int nchildren;
 
139
 
 
140
      if (!XQueryTree(up->display, rootWindow, &dummyroot, &dummyparent,
 
141
                      &children, &nchildren)) {
 
142
         Debug("%s: XQueryTree failed\n", __func__);
 
143
         goto out;
 
144
      }
 
145
 
 
146
      /*
 
147
       * Now, filter out all of the relevant top-level windows into a local buffer
 
148
       * from the stack.
 
149
       */
 
150
      relevantXChildren = g_new(Window, nchildren);
 
151
 
 
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];
 
157
         }
 
158
      }
 
159
 
 
160
      XFree(children);
 
161
   }
 
162
 
 
163
   /*
 
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.
 
168
    *
 
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.
 
173
    */
 
174
   {
 
175
      UnityPlatformWindow *myupw;
 
176
      for (myupw = up->topWindow, numURelevant = 0;
 
177
           myupw;
 
178
           myupw = myupw->lowerWindow) {
 
179
         if (myupw->isRelevant) {
 
180
            unityList = g_list_prepend(unityList, (gpointer)myupw->toplevelWindow);
 
181
            ++numURelevant;
 
182
         }
 
183
      }
 
184
   }
 
185
 
 
186
   /*
 
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.
 
190
    */
 
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);
 
195
      goto out;
 
196
   }
 
197
 
 
198
   nWindows = numURelevant;
 
199
 
 
200
   /*
 
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.
 
203
    */
 
204
 
 
205
   relevantUChildren = g_new(Window, nWindows);
 
206
   trackerChildren = g_new(Window, nWindows);
 
207
 
 
208
   /*
 
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.
 
211
    */
 
212
   {
 
213
      GList *listIter;
 
214
      for (listIter = unityList, i = 0;
 
215
           listIter;
 
216
           listIter = listIter->next, i++) {
 
217
         relevantUChildren[i] = (Window)listIter->data;
 
218
      }
 
219
   }
 
220
 
 
221
   /*
 
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.
 
225
    */
 
226
   for (i = 0; i < nWindows; i++) {
 
227
      trackerChildren[i] = up->tracker->zorder[(nWindows - 1) - i];
 
228
   }
 
229
 
 
230
   {
 
231
      size_t childrenSize = nWindows * sizeof *relevantUChildren;
 
232
 
 
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",
 
237
               "Unity", "UWT");
 
238
 
 
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],
 
244
                     trackerChildren[i]);
 
245
            }
 
246
         }
 
247
      } else {
 
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]);
 
251
         }
 
252
      }
 
253
   }
 
254
 
 
255
out:
 
256
   g_free(relevantXChildren);
 
257
   g_free(relevantUChildren);
 
258
   g_free(trackerChildren);
 
259
   g_list_free(unityList);
 
260
}
 
261
#endif
 
262
 
 
263
 
 
264
/*
 
265
 *-----------------------------------------------------------------------------
 
266
 *
 
267
 * UnityPlatformFindClientWindow --
 
268
 *
 
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.
 
273
 *
 
274
 * Results:
 
275
 *      TRUE if successful, FALSE otherwise.
 
276
 *
 
277
 *-----------------------------------------------------------------------------
 
278
 */
 
279
 
 
280
static Bool
 
281
UnityPlatformFindWindows(UnityPlatform *up,      // IN
 
282
                         Window currentWindow,   // IN
 
283
                         Window *toplevelWindow, // OUT
 
284
                         Window *clientWindow,   // OUT
 
285
                         Window *rootWindow)     // OUT
 
286
{
 
287
   Bool retval = FALSE;
 
288
 
 
289
   Window rootWin;
 
290
   Window parentWin;
 
291
   Window *children = NULL;
 
292
   unsigned int numChildren;
 
293
 
 
294
   Atom propertyType;
 
295
   int propertyFormat;
 
296
   unsigned long itemsReturned;
 
297
   unsigned long bytesRemaining;
 
298
   unsigned char *valueReturned = NULL;
 
299
 
 
300
   ASSERT(up);
 
301
   ASSERT(toplevelWindow);
 
302
   ASSERT(clientWindow);
 
303
   ASSERT(rootWindow);
 
304
 
 
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");
 
314
      return FALSE;
 
315
   }
 
316
 
 
317
   XQueryTree(up->display, currentWindow, &rootWin, &parentWin,
 
318
              &children, &numChildren);
 
319
   if (UnityPlatformGetErrorCount(up)) {
 
320
      Debug("XQueryTree failed\n");
 
321
      return FALSE;
 
322
   }
 
323
 
 
324
   if (propertyType != None) {
 
325
      /*
 
326
       * If WM_STATE exists on this window, we were given a client window
 
327
       */
 
328
      *clientWindow = currentWindow;
 
329
      *rootWindow = rootWin;
 
330
 
 
331
      XFree(children);
 
332
      children = NULL;
 
333
 
 
334
      /*
 
335
       * This loop ensures that parentWin is the direct child of the root.
 
336
       *
 
337
       * XXX this will break for any window managers that use subwindows to implement
 
338
       * virtual desktops.
 
339
       */
 
340
      while (parentWin != rootWin) {
 
341
         currentWindow = parentWin;
 
342
 
 
343
         XQueryTree(up->display, currentWindow, &rootWin,
 
344
                    &parentWin, &children, &numChildren);
 
345
         XFree(children);
 
346
         children = NULL;
 
347
      }
 
348
      *toplevelWindow = currentWindow;
 
349
 
 
350
      retval = TRUE;
 
351
   } else if (parentWin == rootWin) {
 
352
      uint i;
 
353
      GQueue *windowQueue;
 
354
 
 
355
      /*
 
356
       * Do a breadth-first search down the window tree to find the child that has the
 
357
       * WM_STATE property.
 
358
       */
 
359
      ASSERT(UnityPlatformIsRootWindow(up, rootWin));
 
360
 
 
361
      *toplevelWindow = currentWindow;
 
362
      *rootWindow = rootWin;
 
363
      *clientWindow = None;
 
364
 
 
365
      windowQueue = g_queue_new();
 
366
 
 
367
      while (numChildren || !g_queue_is_empty(windowQueue)) {
 
368
         Window childWindow;
 
369
 
 
370
         for (i = 0; i < numChildren; i++) {
 
371
            g_queue_push_tail(windowQueue, GUINT_TO_POINTER(children[i]));
 
372
         }
 
373
         XFree(children);
 
374
         children = NULL;
 
375
 
 
376
         childWindow = GPOINTER_TO_UINT(g_queue_pop_head(windowQueue));
 
377
 
 
378
         propertyType = None;
 
379
         valueReturned = NULL;
 
380
         itemsReturned = 0;
 
381
         XGetWindowProperty(up->display, childWindow, up->atoms.WM_STATE, 0,
 
382
                            1024, False, AnyPropertyType,
 
383
                            &propertyType, &propertyFormat, &itemsReturned,
 
384
                            &bytesRemaining, &valueReturned);
 
385
         XFree(valueReturned);
 
386
 
 
387
         if (UnityPlatformGetErrorCount(up)) {
 
388
            g_queue_free(windowQueue);
 
389
            Debug("Getting WM_STATE on a child failed\n");
 
390
            return FALSE;
 
391
         }
 
392
 
 
393
         if (itemsReturned) {
 
394
            *clientWindow = childWindow;
 
395
            break;
 
396
         }
 
397
 
 
398
         XQueryTree(up->display, childWindow, &rootWin,
 
399
                    &parentWin, &children, &numChildren);
 
400
         if (UnityPlatformGetErrorCount(up)) {
 
401
            g_queue_free(windowQueue);
 
402
            Debug("XQueryTree failed\n");
 
403
            return FALSE;
 
404
         }
 
405
      }
 
406
 
 
407
      g_queue_free(windowQueue);
 
408
 
 
409
      retval = TRUE;
 
410
   } /* else, retval is FALSE */
 
411
 
 
412
   XFree(children);
 
413
 
 
414
   if (retval && (*toplevelWindow == *rootWindow || *clientWindow == *rootWindow)) {
 
415
      Panic("Creating a UnityPlatformWindow of a root window is a big error\n");
 
416
   }
 
417
 
 
418
   return retval;
 
419
}
 
420
 
 
421
 
 
422
/*
 
423
 *-----------------------------------------------------------------------------
 
424
 *
 
425
 * UPWindowSetWindows --
 
426
 *
 
427
 *      Updates the X11 windows that a UnityPlatformWindow represents. Used mainly if a
 
428
 *      window is created or reparented.
 
429
 *
 
430
 * Results:
 
431
 *      None.
 
432
 *
 
433
 * Side effects:
 
434
 *      Updates internal Unity state.
 
435
 *
 
436
 *-----------------------------------------------------------------------------
 
437
 */
 
438
 
 
439
static void
 
440
UPWindowSetWindows(UnityPlatform *up,        // IN
 
441
                   UnityPlatformWindow *upw, // IN
 
442
                   Window toplevelWindow,    // IN
 
443
                   Window clientWindow)      // IN
 
444
{
 
445
   UnityPlatformWindow *scratchUpw;
 
446
   Bool wasRelevant;
 
447
 
 
448
   ASSERT(up);
 
449
   ASSERT(upw);
 
450
 
 
451
   wasRelevant = upw->isRelevant;
 
452
 
 
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));
 
459
   }
 
460
   if (upw->clientWindow) {
 
461
      XSelectInput(up->display, upw->clientWindow, 0);
 
462
      HashTable_Delete(up->allWindows, GUINT_TO_POINTER(upw->clientWindow));
 
463
   }
 
464
#if defined(VM_HAVE_X11_SHAPE_EXT)
 
465
   if (up->shapeEventBase) {
 
466
      XShapeSelectInput(up->display, upw->toplevelWindow, 0);
 
467
 
 
468
      if (upw->clientWindow) {
 
469
         XShapeSelectInput(up->display, upw->clientWindow, 0);
 
470
      }
 
471
   }
 
472
#endif
 
473
 
 
474
   /*
 
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.
 
478
    *
 
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.
 
483
    */
 
484
   scratchUpw = UPWindow_Lookup(up, toplevelWindow);
 
485
   if (scratchUpw && scratchUpw != upw) {
 
486
      UPWindow_Unref(up, scratchUpw);
 
487
   }
 
488
   scratchUpw = UPWindow_Lookup(up, clientWindow);
 
489
   if (scratchUpw && scratchUpw != upw) {
 
490
      UPWindow_Unref(up, scratchUpw);
 
491
   }
 
492
 
 
493
   upw->toplevelWindow = toplevelWindow;
 
494
   upw->clientWindow = clientWindow;
 
495
 
 
496
   /*
 
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.
 
499
    */
 
500
   if (clientWindow) {
 
501
      XSelectInput(up->display, clientWindow, PropertyChangeMask | StructureNotifyMask);
 
502
   }
 
503
 
 
504
   XSelectInput(up->display,
 
505
                toplevelWindow,
 
506
                FocusChangeMask | PropertyChangeMask | StructureNotifyMask);
 
507
 
 
508
#if defined(VM_HAVE_X11_SHAPE_EXT)
 
509
   if (up->shapeEventBase) {
 
510
      XShapeSelectInput(up->display, toplevelWindow, ShapeNotifyMask);
 
511
 
 
512
      if (upw->clientWindow) {
 
513
         XShapeSelectInput(up->display, upw->clientWindow, ShapeNotifyMask);
 
514
      }
 
515
   }
 
516
#endif
 
517
 
 
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);
 
521
   }
 
522
   UPWindowSetRelevance(up, upw, wasRelevant);
 
523
}
 
524
 
 
525
 
 
526
/*
 
527
 *-----------------------------------------------------------------------------
 
528
 *
 
529
 * UPWindow_Create --
 
530
 *
 
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.
 
533
 *
 
534
 * Results:
 
535
 *      The newly created UnityPlatformWindow.
 
536
 *
 
537
 * Side effects:
 
538
 *      None.
 
539
 *
 
540
 *-----------------------------------------------------------------------------
 
541
 */
 
542
 
 
543
UnityPlatformWindow *
 
544
UPWindow_Create(UnityPlatform *up,     // IN
 
545
                Window window)         // IN
 
546
{
 
547
   UnityPlatformWindow *upw;
 
548
   Window toplevelWindow;
 
549
   Window clientWindow;
 
550
   Window rootWindow;
 
551
 
 
552
   ASSERT(up);
 
553
   ASSERT(window != None);
 
554
 
 
555
   if (!UnityPlatformFindWindows(up, window,
 
556
                                 &toplevelWindow, &clientWindow, &rootWindow)) {
 
557
      Debug("FindWindows failed on %#lx\n", window);
 
558
      return NULL;
 
559
   }
 
560
 
 
561
   if (HashTable_Lookup(up->allWindows,
 
562
                        GUINT_TO_POINTER(toplevelWindow),
 
563
                        (void **)&upw)) {
 
564
      Debug("Lookup of window %#lx returned %#lx\n",
 
565
            toplevelWindow, upw->toplevelWindow);
 
566
      abort();
 
567
   }
 
568
 
 
569
   if (HashTable_Lookup(up->allWindows,
 
570
                        GUINT_TO_POINTER(clientWindow),
 
571
                        (void **)&upw)) {
 
572
      Debug("Lookup of clientWindow %#lx returned existing toplevel %#lx\n",
 
573
            clientWindow, upw->toplevelWindow);
 
574
      return NULL;
 
575
   }
 
576
 
 
577
   upw = (UnityPlatformWindow*)Util_SafeCalloc(1, sizeof *upw);
 
578
   upw->refs = 1;
 
579
 
 
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);
 
589
 
 
590
   UPWindowSetWindows(up, upw, toplevelWindow, clientWindow);
 
591
 
 
592
   /*
 
593
    * Put newly created windows on the top of the stack by default.
 
594
    */
 
595
   upw->higherWindow = NULL;
 
596
   upw->lowerWindow = up->topWindow;
 
597
   if (upw->lowerWindow) {
 
598
      upw->lowerWindow->higherWindow = upw;
 
599
   }
 
600
   up->topWindow = upw;
 
601
 
 
602
   return upw;
 
603
}
 
604
 
 
605
 
 
606
/*
 
607
 *-----------------------------------------------------------------------------
 
608
 *
 
609
 * UPWindow_Ref --
 
610
 *
 
611
 *      Increases the reference count on the UnityPlatformWindow object by one.
 
612
 *
 
613
 * Results:
 
614
 *      None.
 
615
 *
 
616
 * Side effects:
 
617
 *      None.
 
618
 *
 
619
 *-----------------------------------------------------------------------------
 
620
 */
 
621
 
 
622
void
 
623
UPWindow_Ref(UnityPlatform *up,        // IN
 
624
             UnityPlatformWindow *upw) // IN
 
625
{
 
626
   upw->refs++;
 
627
}
 
628
 
 
629
 
 
630
/*
 
631
 *-----------------------------------------------------------------------------
 
632
 *
 
633
 * UPWindow_Unref --
 
634
 *
 
635
 *      Decreases the reference count on the UnityPlatformWindow object by one.
 
636
 *
 
637
 * Results:
 
638
 *      None.
 
639
 *
 
640
 * Side effects:
 
641
 *      May destroy the object if no references remain.
 
642
 *
 
643
 *-----------------------------------------------------------------------------
 
644
 */
 
645
 
 
646
void
 
647
UPWindow_Unref(UnityPlatform *up,        // IN
 
648
               UnityPlatformWindow *upw) // IN
 
649
{
 
650
   upw->refs--;
 
651
 
 
652
   if (upw->refs <= 0) { // Window needs destroying
 
653
      UPWindowSetRelevance(up, upw, FALSE);
 
654
 
 
655
      /*
 
656
       * Filter out windows that have been already destroyed on the X11 side, but which
 
657
       * still may have had refcounts active.
 
658
       */
 
659
      if (upw->windowType != UNITY_WINDOW_TYPE_NONE) {
 
660
         XSelectInput(up->display, upw->toplevelWindow, 0);
 
661
 
 
662
#if defined(VM_HAVE_X11_SHAPE_EXT)
 
663
         if (up->shapeEventBase) {
 
664
            XShapeSelectInput(up->display, upw->toplevelWindow, 0);
 
665
         }
 
666
#endif
 
667
 
 
668
         if (upw->clientWindow) {
 
669
            XSelectInput(up->display, upw->clientWindow, 0);
 
670
         }
 
671
      }
 
672
 
 
673
      HashTable_Delete(up->allWindows, GUINT_TO_POINTER(upw->toplevelWindow));
 
674
      if (upw->clientWindow) {
 
675
         HashTable_Delete(up->allWindows, GUINT_TO_POINTER(upw->clientWindow));
 
676
      }
 
677
 
 
678
      DynBuf_Destroy(&upw->iconPng.data);
 
679
 
 
680
      if (upw->higherWindow) {
 
681
         upw->higherWindow->lowerWindow = upw->lowerWindow;
 
682
      }
 
683
      if (upw->lowerWindow) {
 
684
         upw->lowerWindow->higherWindow = upw->higherWindow;
 
685
      }
 
686
      if (upw == up->topWindow) {
 
687
         up->topWindow = upw->lowerWindow;
 
688
      }
 
689
 
 
690
      free(upw);
 
691
   }
 
692
}
 
693
 
 
694
 
 
695
/*
 
696
 *-----------------------------------------------------------------------------
 
697
 *
 
698
 * UPWindow_Lookup --
 
699
 *
 
700
 *      Retrieves the UnityPlatformWindow object associated with a given Window ID
 
701
 *
 
702
 * Results:
 
703
 *      The UnityPlatformWindow object, or NULL if it was not found
 
704
 *
 
705
 * Side effects:
 
706
 *      None.
 
707
 *
 
708
 *-----------------------------------------------------------------------------
 
709
 */
 
710
 
 
711
UnityPlatformWindow *
 
712
UPWindow_Lookup(UnityPlatform *up, // IN
 
713
                Window window)     // IN
 
714
{
 
715
   UnityPlatformWindow *retval = NULL;
 
716
 
 
717
   HashTable_Lookup(up->allWindows, GUINT_TO_POINTER(window), (void **)&retval);
 
718
 
 
719
   return retval;
 
720
}
 
721
 
 
722
#if 0 // Very useful if ever debugging the window stacking code, but slow otherwise.
 
723
/*
 
724
 *-----------------------------------------------------------------------------
 
725
 *
 
726
 * UPWindowCheckStack --
 
727
 *
 
728
 *      Sanity check on the linked list of windows for Z-ordering.
 
729
 *
 
730
 * Results:
 
731
 *      None.
 
732
 *
 
733
 * Side effects:
 
734
 *      May ASSERT() if things are broken.
 
735
 *
 
736
 *-----------------------------------------------------------------------------
 
737
 */
 
738
 
 
739
static void
 
740
UPWindowCheckStack(UnityPlatform *up)
 
741
{
 
742
   UnityPlatformWindow **upwList;
 
743
   size_t numWindows;
 
744
   size_t i;
 
745
   UnityPlatformWindow *curWindow;
 
746
 
 
747
   HashTable_ToArray(up->allWindows,
 
748
                     (void ***)&upwList,
 
749
                     &numWindows);
 
750
   for (i = 0; i < numWindows; i++) {
 
751
      for (curWindow = up->topWindow;
 
752
           curWindow;
 
753
           curWindow = curWindow->lowerWindow) {
 
754
         if (curWindow == upwList[i]) {
 
755
            break;
 
756
         }
 
757
      }
 
758
 
 
759
      if (curWindow != upwList[i]) {
 
760
         Debug("%s: Wanted %p. Complete window stack is: ", __FUNCTION__, upwList[i]);
 
761
         for (curWindow = up->topWindow;
 
762
              curWindow;
 
763
              curWindow = curWindow->lowerWindow) {
 
764
            if (curWindow == upwList[i]) {
 
765
               Debug("%p ->", curWindow);
 
766
            } else {
 
767
               Debug("[%p] ->", curWindow);
 
768
            }
 
769
         }
 
770
         Debug("NULL\n");
 
771
 
 
772
         Debug("%s: Window stack downwards from %p: ", __FUNCTION__, upwList[i]);
 
773
         for (curWindow = upwList[i];
 
774
              curWindow;
 
775
              curWindow = curWindow->lowerWindow) {
 
776
            if (curWindow == upwList[i]) {
 
777
               Debug("[%p] ->", curWindow);
 
778
            } else {
 
779
               Debug("%p ->", curWindow);
 
780
            }
 
781
         }
 
782
         Debug("NULL\n");
 
783
 
 
784
         Debug("%s: Window stack upwards from %p: ", __FUNCTION__, upwList[i]);
 
785
         for (curWindow = upwList[i];
 
786
              curWindow;
 
787
              curWindow = curWindow->higherWindow) {
 
788
            if (curWindow == upwList[i]) {
 
789
               Debug("[%p] <-", curWindow);
 
790
            } else {
 
791
               Debug("%p <-", curWindow);
 
792
            }
 
793
         }
 
794
         Debug("NULL\n");
 
795
      }
 
796
 
 
797
      ASSERT(curWindow == upwList[i]);
 
798
   }
 
799
   for (curWindow = up->topWindow;
 
800
        curWindow;
 
801
        curWindow = curWindow->lowerWindow) {
 
802
      for (i = 0; i < numWindows; i++) {
 
803
         if (curWindow == upwList[i]) {
 
804
            break;
 
805
         }
 
806
      }
 
807
      ASSERT(i < numWindows);
 
808
   }
 
809
 
 
810
   free(upwList);
 
811
}
 
812
 
 
813
 
 
814
/*
 
815
 *-----------------------------------------------------------------------------
 
816
 *
 
817
 * UPWindowCheckCycle --
 
818
 *
 
819
 *      Checks to make sure there are no loops in the window stack.
 
820
 *
 
821
 * Results:
 
822
 *      None.
 
823
 *
 
824
 * Side effects:
 
825
 *      May ASSERT().
 
826
 *
 
827
 *-----------------------------------------------------------------------------
 
828
 */
 
829
 
 
830
static void
 
831
UPWindowCheckCycle(UnityPlatform *up)
 
832
{
 
833
   UnityPlatformWindow *upw;
 
834
   UnityPlatformWindow *curWindow;
 
835
 
 
836
   for (upw = up->topWindow; upw; upw = upw->lowerWindow) {
 
837
      for (curWindow = upw->lowerWindow; curWindow; curWindow = curWindow->lowerWindow) {
 
838
         ASSERT(curWindow != upw);
 
839
      }
 
840
   }
 
841
 
 
842
   for (upw = up->topWindow; upw->lowerWindow; upw = upw->lowerWindow) {
 
843
      /* Find lowest window */
 
844
   }
 
845
 
 
846
   for (; upw; upw = upw->higherWindow) {
 
847
      for (curWindow = upw->higherWindow; curWindow; curWindow = curWindow->higherWindow) {
 
848
         ASSERT(curWindow != upw);
 
849
      }
 
850
   }
 
851
}
 
852
#endif
 
853
 
 
854
 
 
855
/*
 
856
 *-----------------------------------------------------------------------------
 
857
 *
 
858
 * UPWindow_Restack --
 
859
 *
 
860
 *      Changes the Z order list of the specified window so it is
 
861
 *      immediately above another window.
 
862
 *
 
863
 * Results:
 
864
 *      None.
 
865
 *
 
866
 * Side effects:
 
867
 *      Updates UnityWindowTracker with the latest ZOrder.
 
868
 *
 
869
 *-----------------------------------------------------------------------------
 
870
 */
 
871
 
 
872
void
 
873
UPWindow_Restack(UnityPlatform *up,        // IN
 
874
                 UnityPlatformWindow *upw, // IN
 
875
                 Window above)             // IN - None indicates stack at bottom
 
876
{
 
877
   UnityPlatformWindow *newLowerWindow = NULL;
 
878
 
 
879
   ASSERT(up);
 
880
   ASSERT(upw);
 
881
 
 
882
   if (above != None) {
 
883
      newLowerWindow = UPWindow_Lookup(up, above);
 
884
 
 
885
      if (!newLowerWindow) {
 
886
         if (upw != up->topWindow) {
 
887
            Debug("%s: Couldn't find the window to stack above [%#lx].\n",
 
888
                  __func__, above);
 
889
            return;
 
890
         } else {
 
891
            return;
 
892
         }
 
893
      }
 
894
   }
 
895
   ASSERT(newLowerWindow != upw);
 
896
 
 
897
   if (newLowerWindow != upw->lowerWindow) {
 
898
      /*
 
899
       * Stacking order has changed. Move this window to the right place in the stack.
 
900
       *
 
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.
 
904
       */
 
905
 
 
906
      ASSERT(upw->higherWindow != upw);
 
907
      ASSERT(upw->lowerWindow != upw);
 
908
      if (upw->higherWindow) {
 
909
         upw->higherWindow->lowerWindow = upw->lowerWindow;
 
910
      } else {
 
911
         up->topWindow = upw->lowerWindow;
 
912
      }
 
913
 
 
914
      ASSERT(upw->higherWindow != upw);
 
915
      ASSERT(upw->lowerWindow != upw);
 
916
      if (upw->lowerWindow) {
 
917
         upw->lowerWindow->higherWindow = upw->higherWindow;
 
918
      }
 
919
      upw->higherWindow = NULL;
 
920
      upw->lowerWindow = NULL;
 
921
 
 
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);
 
929
      } else {
 
930
         /*
 
931
          * This window is meant to go to the bottom of the stack.
 
932
          */
 
933
         upw->lowerWindow = NULL;
 
934
         upw->higherWindow = up->topWindow;
 
935
 
 
936
         while (upw->higherWindow && upw->higherWindow->lowerWindow) {
 
937
            upw->higherWindow = upw->higherWindow->lowerWindow;
 
938
         }
 
939
         ASSERT(newLowerWindow != upw);
 
940
      }
 
941
 
 
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;
 
948
      } else {
 
949
         up->topWindow = upw;
 
950
      }
 
951
 
 
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");
 
957
      }
 
958
   }
 
959
}
 
960
 
 
961
 
 
962
/*
 
963
 *-----------------------------------------------------------------------------
 
964
 *
 
965
 * UPWindowSetRelevance --
 
966
 *
 
967
 *      Changes the "relevance" of a particular window. Normally, the decision of whether
 
968
 *      to do this should be made only by CheckRelevance().
 
969
 *
 
970
 * Results:
 
971
 *      None.
 
972
 *
 
973
 * Side effects:
 
974
 *      May add or remove the window in UnityWindowTracker.
 
975
 *
 
976
 *-----------------------------------------------------------------------------
 
977
 */
 
978
 
 
979
static void
 
980
UPWindowSetRelevance(UnityPlatform *up,        // IN
 
981
                     UnityPlatformWindow *upw, // IN
 
982
                     Bool isRelevant)          // IN
 
983
{
 
984
   if ((isRelevant && upw->isRelevant) || (!isRelevant && !upw->isRelevant)) {
 
985
      return;
 
986
   }
 
987
 
 
988
   upw->isRelevant = isRelevant;
 
989
   if (isRelevant) {
 
990
      DynBuf windowPath;
 
991
      DynBuf execPath;
 
992
 
 
993
      DynBuf_Init(&windowPath);
 
994
      DynBuf_Init(&execPath);
 
995
 
 
996
      if (upw->windowType == UNITY_WINDOW_TYPE_NORMAL) {
 
997
         Bool retval;
 
998
         retval = UnityPlatformGetWindowPath(up,
 
999
                                             upw->toplevelWindow,
 
1000
                                             &windowPath,
 
1001
                                             &execPath);
 
1002
         if (!retval) {
 
1003
            Debug("GetWindowPath didn't know how to identify the window...\n");
 
1004
         }
 
1005
      }
 
1006
 
 
1007
      Debug("Adding window %#lx to tracker\n", upw->toplevelWindow);
 
1008
      UnityWindowTracker_AddWindowWithData(up->tracker,
 
1009
                                           upw->toplevelWindow,
 
1010
                                           &windowPath,
 
1011
                                           &execPath,
 
1012
                                           upw);
 
1013
      DynBuf_Destroy(&windowPath);
 
1014
      DynBuf_Destroy(&execPath);
 
1015
 
 
1016
      UPWindowPushFullUpdate(up, upw);
 
1017
   } else {
 
1018
      Debug("Removing window %#lx from tracker\n", upw->toplevelWindow);
 
1019
      UnityWindowTracker_RemoveWindow(up->tracker, upw->toplevelWindow);
 
1020
      UnityPlatformDoUpdate(up, TRUE);
 
1021
   }
 
1022
 
 
1023
   up->stackingChanged = TRUE;
 
1024
}
 
1025
 
 
1026
 
 
1027
/*
 
1028
 *-----------------------------------------------------------------------------
 
1029
 *
 
1030
 * UPWindow_CheckRelevance --
 
1031
 *
 
1032
 *      Looks at the current state of a window to figure out whether we want to relay it
 
1033
 *      through UnityWindowTracker.
 
1034
 *
 
1035
 * Results:
 
1036
 *      None.
 
1037
 *
 
1038
 * Side effects:
 
1039
 *      Updates various cached metadata in UnityPlatformWindow, such as windowType and
 
1040
 *      isOverrideRedirect.
 
1041
 *
 
1042
 *-----------------------------------------------------------------------------
 
1043
 */
 
1044
 
 
1045
void
 
1046
UPWindow_CheckRelevance(UnityPlatform *up,        // IN
 
1047
                        UnityPlatformWindow *upw, // IN
 
1048
                        const XEvent *motivator)  // IN - optional
 
1049
{
 
1050
   XWindowAttributes winAttr;
 
1051
   int shouldBeRelevant = -1;
 
1052
   Bool regetDesktop = FALSE;
 
1053
 
 
1054
   if (motivator) {
 
1055
      /*
 
1056
       * We have an event that may have modified the relevance of this window. See what
 
1057
       * we need to do.
 
1058
       */
 
1059
      switch (motivator->type) {
 
1060
      case PropertyNotify:
 
1061
         {
 
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;
 
1069
               Bool success;
 
1070
 
 
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,
 
1076
                                                  &rootWindow);
 
1077
               if (success) {
 
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);
 
1082
               } else {
 
1083
                  Debug("%s: PropertyNotify: FindWindows failed again!\n", __func__);
 
1084
                  return;
 
1085
               }
 
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;
 
1092
               return;
 
1093
            } else if (event->atom == up->atoms._NET_WM_DESKTOP) {
 
1094
               if (upw->wantSetDesktopNumberOnUnmap) {
 
1095
                  /*
 
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.
 
1103
                   */
 
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);
 
1108
                  }
 
1109
                  upw->wantSetDesktopNumberOnUnmap = FALSE;
 
1110
                  return;
 
1111
               }
 
1112
               regetDesktop = TRUE;
 
1113
            } else if (event->atom != up->atoms._NET_WM_WINDOW_TYPE) {
 
1114
               return;
 
1115
            }
 
1116
         }
 
1117
         break;
 
1118
 
 
1119
      case ConfigureNotify:
 
1120
         if ((motivator->xconfigure.override_redirect ? TRUE : FALSE)
 
1121
             == upw->isOverrideRedirect) {
 
1122
            return;
 
1123
         }
 
1124
         break;
 
1125
 
 
1126
      case UnmapNotify:
 
1127
         /*
 
1128
          * XXX should we ignore UnmapNotify events if they come from non-override
 
1129
          * redirect windows?
 
1130
          */
 
1131
 
 
1132
         /*
 
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.
 
1136
          */
 
1137
         break;
 
1138
 
 
1139
      case MapNotify:
 
1140
         if (upw->wantSetDesktopNumberOnUnmap) {
 
1141
            Debug("%s: Expected PropertyDelete before MapNotify.\n", __func__);
 
1142
            upw->wantSetDesktopNumberOnUnmap = FALSE;
 
1143
         }
 
1144
         regetDesktop = TRUE;
 
1145
         break;
 
1146
 
 
1147
      case ReparentNotify:
 
1148
         {
 
1149
            Window toplevelWindow = 0;
 
1150
            Window clientWindow = 0;
 
1151
            Window rootWindow = 0;
 
1152
            const XReparentEvent *reparent = &motivator->xreparent;
 
1153
            Bool success;
 
1154
 
 
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,
 
1161
                                               &rootWindow);
 
1162
            if (success) {
 
1163
               UPWindowSetWindows(up, upw, toplevelWindow, clientWindow);
 
1164
            } else {
 
1165
               Debug("%s: ReparentNotify: UnityPlatformFindWindows failed."
 
1166
                     "  Waiting for WM_STATE.\n", __func__);
 
1167
               upw->waitingForWmState = TRUE;
 
1168
               return;
 
1169
            }
 
1170
         }
 
1171
         break;
 
1172
 
 
1173
      case DestroyNotify:
 
1174
         shouldBeRelevant = FALSE;
 
1175
         break;
 
1176
 
 
1177
      default:
 
1178
         return;
 
1179
      }
 
1180
   } else {
 
1181
      regetDesktop = TRUE;
 
1182
   }
 
1183
 
 
1184
   if (shouldBeRelevant == -1) {
 
1185
      Bool onCurrentDesktop = TRUE;
 
1186
      Bool isInvisible = FALSE;
 
1187
      Bool ignoreThisWindow = FALSE;
 
1188
 
 
1189
      UnityPlatformResetErrorCount(up);
 
1190
 
 
1191
      XGetWindowAttributes(up->display, upw->toplevelWindow, &winAttr);
 
1192
      if (UnityPlatformGetErrorCount(up)) {
 
1193
         shouldBeRelevant = FALSE;
 
1194
         goto out;
 
1195
      }
 
1196
 
 
1197
      if (regetDesktop) {
 
1198
         if (!UPWindowGetDesktop(up, upw, &upw->desktopNumber)) {
 
1199
            upw->desktopNumber = -1;
 
1200
         } else {
 
1201
            if (upw->wantSetDesktopNumberOnUnmap) {
 
1202
               upw->onUnmapDesktopNumber = upw->desktopNumber;
 
1203
            }
 
1204
         }
 
1205
      }
 
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;
 
1211
      }
 
1212
      upw->isViewable = (winAttr.map_state == IsViewable);
 
1213
      if (!upw->wasViewable) {
 
1214
         if (upw->isViewable) {
 
1215
            upw->wasViewable = upw->isViewable;
 
1216
         } else {
 
1217
            /*
 
1218
             * Check if it's in iconic state (i.e. minimized), which means it was viewable
 
1219
             * previously as far as we're concerned.
 
1220
             */
 
1221
 
 
1222
            Atom propertyType;
 
1223
            int propertyFormat;
 
1224
            unsigned long itemsReturned = 0;
 
1225
            unsigned long bytesRemaining;
 
1226
            Atom *valueReturned = NULL;
 
1227
            Window mainWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
 
1228
 
 
1229
            if (XGetWindowProperty(up->display, mainWindow, up->atoms.WM_STATE, 0,
 
1230
                                   1024, False, AnyPropertyType,
 
1231
                                   &propertyType, &propertyFormat, &itemsReturned,
 
1232
                                   &bytesRemaining, (unsigned char **) &valueReturned)
 
1233
                == Success
 
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);
 
1241
            } else {
 
1242
               upw->wasViewable = FALSE;
 
1243
            }
 
1244
 
 
1245
            XFree(valueReturned);
 
1246
         }
 
1247
      }
 
1248
      upw->isOverrideRedirect = winAttr.override_redirect ? TRUE : FALSE;
 
1249
 
 
1250
      /*
 
1251
       * More crazy tests to determine whether a window should be added to the window
 
1252
       * tracker.
 
1253
       */
 
1254
 
 
1255
      if (winAttr.c_class == InputOnly) {
 
1256
         /* This is intrinsically true. */
 
1257
         isInvisible = TRUE;
 
1258
      } else if (!upw->isViewable && onCurrentDesktop && !upw->clientWindow) {
 
1259
         /*
 
1260
          * Evaluate the map state.  There are reasons why we'd like to keep unmapped
 
1261
          * windows in the tracker.
 
1262
          *
 
1263
          *    1.  The window may be on another desktop.
 
1264
          *    2.  The window may be minimized.
 
1265
          *
 
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
 
1268
          * be "minimized".
 
1269
          *
 
1270
          * I'm using these implications because it saves me from having to explicitly
 
1271
          * query for/examine WM_STATE here.
 
1272
          */
 
1273
         isInvisible = TRUE;
 
1274
      } else if (winAttr.width <= 1 && winAttr.height <= 1) {
 
1275
         isInvisible = TRUE;
 
1276
      } else if ((winAttr.x + winAttr.width) < 0
 
1277
                 || (winAttr.y + winAttr.height) < 0) {
 
1278
         /*
 
1279
          * XXX This isn't clear to me.  What if winAttr.x > parent's width?
 
1280
          */
 
1281
         isInvisible = TRUE;
 
1282
      }
 
1283
 
 
1284
      if (!isInvisible) {
 
1285
         char *wmname = NULL;
 
1286
 
 
1287
         /*
 
1288
          **************************************
 
1289
          * This section should hold all the ugly app-specific filtering that might be
 
1290
          * needed for UnityX11.
 
1291
          */
 
1292
 
 
1293
         if (XFetchName(up->display,
 
1294
                        upw->clientWindow ? upw->clientWindow : upw->toplevelWindow,
 
1295
                        &wmname) != 0) {
 
1296
            if (!strcmp(wmname, "gksu")
 
1297
                && winAttr.override_redirect) {
 
1298
               ignoreThisWindow = TRUE;
 
1299
            }
 
1300
 
 
1301
            XFree(wmname);
 
1302
         }
 
1303
 
 
1304
         /*
 
1305
          * End app-specific filtering.
 
1306
          *******************************************
 
1307
          */
 
1308
      }
 
1309
 
 
1310
      if (isInvisible) {
 
1311
         shouldBeRelevant = FALSE;
 
1312
      } else if (ignoreThisWindow) {
 
1313
         shouldBeRelevant = FALSE;
 
1314
      } else {
 
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;
 
1320
         Window mainWindow;
 
1321
 
 
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);
 
1328
 
 
1329
         if (UnityPlatformGetErrorCount(up)) {
 
1330
            Debug("Error retrieving window type property\n");
 
1331
            shouldBeRelevant = FALSE;
 
1332
            goto out;
 
1333
         }
 
1334
 
 
1335
         if (netWmPropertyType == XA_ATOM && itemsReturned && !bytesRemaining) {
 
1336
            netWmWindowType = *((Atom *) valueReturned);
 
1337
         }
 
1338
         XFree(valueReturned);
 
1339
 
 
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;
 
1364
         } else {
 
1365
            upw->windowType = UNITY_WINDOW_TYPE_NORMAL;
 
1366
         }
 
1367
      }
 
1368
   }
 
1369
 
 
1370
out:
 
1371
   ASSERT(shouldBeRelevant >= 0);
 
1372
 
 
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);
 
1376
 
 
1377
   UPWindowSetRelevance(up, upw, shouldBeRelevant ? TRUE : FALSE);
 
1378
}
 
1379
 
 
1380
 
 
1381
/*
 
1382
 *-----------------------------------------------------------------------------
 
1383
 *
 
1384
 * UPWindow_SetUserTime --
 
1385
 *
 
1386
 *      Updates the _NET_WM_USER_TIME property on a window so the window manager
 
1387
 *      will let us restack the window.
 
1388
 *
 
1389
 * Results:
 
1390
 *      None.
 
1391
 *
 
1392
 * Side effects:
 
1393
 *      Updated timestamp.
 
1394
 *
 
1395
 *-----------------------------------------------------------------------------
 
1396
 */
 
1397
 
 
1398
void
 
1399
UPWindow_SetUserTime(UnityPlatform *up,        // IN
 
1400
                     UnityPlatformWindow *upw) // IN
 
1401
{
 
1402
   Atom dummy;
 
1403
   Window focusWindow;
 
1404
   Atom propertyType;
 
1405
   int propertyFormat;
 
1406
   unsigned long itemsReturned, bytesRemaining;
 
1407
   unsigned char *valueReturned = NULL;
 
1408
 
 
1409
   focusWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
 
1410
 
 
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);
 
1417
   }
 
1418
 
 
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);
 
1423
}
 
1424
 
 
1425
 
 
1426
/*
 
1427
 *-----------------------------------------------------------------------------
 
1428
 *
 
1429
 * UPWindowGetActualWindowAndPosition --
 
1430
 *
 
1431
 *      Figures out the right arguments to call XMoveResizeWindow with when
 
1432
 *      moving/resizing a window.
 
1433
 *
 
1434
 * Results:
 
1435
 *      None.
 
1436
 *
 
1437
 * Side effects:
 
1438
 *      Puts the window and coordinates to use in 'actualWindow' and 'actualRect'.
 
1439
 *
 
1440
 *-----------------------------------------------------------------------------
 
1441
 */
 
1442
 
 
1443
static void
 
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
 
1450
{
 
1451
   XWindowAttributes clientWinAttr;
 
1452
   Atom propertyType;
 
1453
   int propertyFormat = 0;
 
1454
   unsigned long itemsReturned = 0;
 
1455
   unsigned long bytesRemaining;
 
1456
   unsigned char *valueReturned = NULL;
 
1457
   int frameSizeTop;
 
1458
   int frameSizeBottom;
 
1459
   int frameSizeLeft;
 
1460
   int frameSizeRight;
 
1461
 
 
1462
   ASSERT(up);
 
1463
   ASSERT(upw);
 
1464
   ASSERT(orig);
 
1465
   ASSERT(actualWindow);
 
1466
   ASSERT(actualRect);
 
1467
 
 
1468
   *actualRect = *orig;
 
1469
   if (!upw->clientWindow) {
 
1470
      *actualWindow = upw->toplevelWindow;
 
1471
      return;
 
1472
   }
 
1473
 
 
1474
   *actualWindow = upw->clientWindow;
 
1475
 
 
1476
   /*
 
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.
 
1481
    */
 
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;
 
1490
 
 
1491
      frameSizeLeft = atomValue[0];
 
1492
      frameSizeRight = atomValue[1];
 
1493
      frameSizeTop = atomValue[2];
 
1494
      frameSizeBottom = atomValue[3];
 
1495
   } else {
 
1496
      /*
 
1497
       * Query the current clientWindow and calculate how to adjust the frame coords to
 
1498
       * client coords.
 
1499
       */
 
1500
      clientWinAttr.x = clientWinAttr.y = 0;
 
1501
      clientWinAttr.width = origTop->width;
 
1502
      clientWinAttr.height = origTop->height;
 
1503
 
 
1504
      XGetWindowAttributes(up->display, upw->clientWindow, &clientWinAttr);
 
1505
 
 
1506
      frameSizeLeft = clientWinAttr.x;
 
1507
      frameSizeRight = origTop->width - (clientWinAttr.x + clientWinAttr.width);
 
1508
      frameSizeTop = clientWinAttr.y;
 
1509
      frameSizeBottom = origTop->height - (clientWinAttr.y + clientWinAttr.height);
 
1510
   }
 
1511
 
 
1512
   /*
 
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.
 
1515
    */
 
1516
#if 0
 
1517
   actualRect->x += frameSizeLeft;
 
1518
   actualRect->y += frameSizeTop;
 
1519
#endif
 
1520
 
 
1521
   actualRect->width -= frameSizeLeft + frameSizeRight;
 
1522
   actualRect->height -= frameSizeTop + frameSizeBottom;
 
1523
 
 
1524
   XFree(valueReturned);
 
1525
}
 
1526
 
 
1527
 
 
1528
/*
 
1529
 *----------------------------------------------------------------------------
 
1530
 *
 
1531
 * UnityPlatformMoveResizeWindow --
 
1532
 *
 
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.
 
1536
 *
 
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.
 
1541
 *
 
1542
 * Results:
 
1543
 *      Even if the move/resize operaion is not execuated or it fails, window's
 
1544
 *      current coordinates are always sent back.
 
1545
 *
 
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.
 
1549
 *
 
1550
 *      In a very rare case, when attempt to get window's current coordinates fail,
 
1551
 *      returns FALSE.
 
1552
 *
 
1553
 * Side effects:
 
1554
 *      None
 
1555
 *
 
1556
 *----------------------------------------------------------------------------
 
1557
 */
 
1558
 
 
1559
Bool
 
1560
UnityPlatformMoveResizeWindow(UnityPlatform *up,         // IN
 
1561
                              UnityWindowId window,      // IN: Window handle
 
1562
                              UnityRect *moveResizeRect) // IN/OUT: Desired coordinates,
 
1563
                                                         // before and after
 
1564
                                                         // the operation.
 
1565
{
 
1566
   UnityPlatformWindow *upw;
 
1567
   Bool retval = FALSE;
 
1568
   XWindowAttributes winAttr;
 
1569
   XWindowAttributes newAttr;
 
1570
   UnityRect desiredRect;
 
1571
 
 
1572
   ASSERT(moveResizeRect);
 
1573
 
 
1574
   upw = UPWindow_Lookup(up, window);
 
1575
   if (!upw) {
 
1576
      return FALSE;
 
1577
   }
 
1578
 
 
1579
   desiredRect = *moveResizeRect;
 
1580
 
 
1581
   UnityPlatformResetErrorCount(up);
 
1582
   XGetWindowAttributes(up->display, upw->toplevelWindow, &winAttr);
 
1583
   if (UnityPlatformGetErrorCount(up)) {
 
1584
      return FALSE;
 
1585
   }
 
1586
 
 
1587
   if (winAttr.x == moveResizeRect->x
 
1588
       && winAttr.y == moveResizeRect->y
 
1589
       && winAttr.width == moveResizeRect->width
 
1590
       && winAttr.height == moveResizeRect->height) {
 
1591
      return TRUE;
 
1592
   }
 
1593
 
 
1594
   /*
 
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
 
1597
    * or not.
 
1598
    */
 
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};
 
1603
 
 
1604
      /*
 
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.
 
1610
       */
 
1611
      data[0] = (0xF << 8) | (2 << 12) | StaticGravity;
 
1612
 
 
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,
 
1619
                                     32, 5, data);
 
1620
      Debug("MoveResizeWindow implemented using _NET_MOVERESIZE_WINDOW\n");
 
1621
   } else
 
1622
#endif
 
1623
   {
 
1624
      if (upw->desktopNumber == (int)up->desktopInfo.currentDesktop ||
 
1625
          upw->desktopNumber == -1) {
 
1626
         UnityRect actualRect;
 
1627
         Window actualWindow;
 
1628
 
 
1629
         UPWindowGetActualWindowAndPosition(up, upw, moveResizeRect, &winAttr, &actualWindow, &actualRect);
 
1630
 
 
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,
 
1636
               actualWindow);
 
1637
      } else {
 
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);
 
1640
         return FALSE;
 
1641
      }
 
1642
   }
 
1643
 
 
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;
 
1650
 
 
1651
   retval = TRUE;
 
1652
 
 
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,
 
1659
         retval);
 
1660
 
 
1661
   return retval;
 
1662
}
 
1663
 
 
1664
 
 
1665
/*
 
1666
 *----------------------------------------------------------------------------
 
1667
 *
 
1668
 * UnityPlatformCloseWindow --
 
1669
 *
 
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
 
1673
 *      actions).
 
1674
 *
 
1675
 * Results:
 
1676
 *      TRUE if we were successful in posting the close message to the window.
 
1677
 *      FALSE otherwise.
 
1678
 *
 
1679
 * Side effects:
 
1680
 *      The window might be closed (and, potentially, an application exits)
 
1681
 *
 
1682
 *----------------------------------------------------------------------------
 
1683
 */
 
1684
 
 
1685
Bool
 
1686
UnityPlatformCloseWindow(UnityPlatform *up,         // IN: Platform data
 
1687
                         UnityWindowId window)      // IN: window handle
 
1688
{
 
1689
   UnityPlatformWindow *upw;
 
1690
 
 
1691
   ASSERT(up);
 
1692
 
 
1693
   upw = UPWindow_Lookup(up, window);
 
1694
 
 
1695
   Debug("Closing window %#x\n", window);
 
1696
 
 
1697
   if (!upw) {
 
1698
      return FALSE;
 
1699
   }
 
1700
 
 
1701
   if (upw->clientWindow &&
 
1702
       UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_CLOSE_WINDOW)) {
 
1703
      Atom data[] = {0,
 
1704
                     2, // Bit to indicate that the pager requested it
 
1705
                     0,
 
1706
                     0,
 
1707
                     0};
 
1708
      data[0] = UnityPlatformGetServerTime(up);
 
1709
      UnityPlatformSendClientMessage(up, upw->rootWindow, upw->clientWindow,
 
1710
                                     up->atoms._NET_CLOSE_WINDOW, 32, 5,
 
1711
                                     data);
 
1712
   } else if (UPWindow_ProtocolSupported(up, upw, UNITY_X11_WIN_WM_DELETE_WINDOW)){
 
1713
      Atom data[1];
 
1714
      Window destWin = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
 
1715
 
 
1716
      data[0] = up->atoms.WM_DELETE_WINDOW;
 
1717
 
 
1718
      UnityPlatformSendClientMessage(up, destWin, destWin,
 
1719
                                     up->atoms.WM_DELETE_WINDOW, 32, 1,
 
1720
                                     data);
 
1721
   } else {
 
1722
      XDestroyWindow(up->display, upw->toplevelWindow);
 
1723
      XFlush(up->display);
 
1724
   }
 
1725
 
 
1726
   return TRUE;
 
1727
}
 
1728
 
 
1729
 
 
1730
/*
 
1731
 *----------------------------------------------------------------------------
 
1732
 *
 
1733
 * UnityPlatformGetWindowPath --
 
1734
 *
 
1735
 *      Get the information needed to re-launch a window and retrieve further
 
1736
 *      information on it.
 
1737
 *
 
1738
 *      windowPathUtf8 uniquely identifies an X11 window (windowUri),
 
1739
 *      execPathUtf8 uniquely identifies the window's owning
 
1740
 *      executable (execUri).
 
1741
 *
 
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
 
1748
 *      applications.)
 
1749
 *
 
1750
 * Results:
 
1751
 *      TRUE if everything went ok, FALSE otherwise.
 
1752
 *
 
1753
 * Side effects:
 
1754
 *      Original buffer contents are overwritten.
 
1755
 *
 
1756
 *----------------------------------------------------------------------------
 
1757
 */
 
1758
 
 
1759
Bool
 
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
 
1764
{
 
1765
   UnityPlatformWindow *upw;
 
1766
   bool retval = false;
 
1767
 
 
1768
   ASSERT(up);
 
1769
 
 
1770
   upw = UPWindow_Lookup(up, window);
 
1771
 
 
1772
   if (!upw) {
 
1773
      Debug("GetWindowPath FAILED!\n");
 
1774
      return FALSE;
 
1775
   }
 
1776
 
 
1777
   WindowPathFactory::WindowPathPair pathPair;
 
1778
   retval = up->wpFactory->FindByXid(upw->clientWindow ? upw->clientWindow :
 
1779
                                     upw->toplevelWindow, pathPair);
 
1780
 
 
1781
   if (!retval) {
 
1782
      Debug("GetWindowPath didn't know how to identify the window...\n");
 
1783
   } else {
 
1784
      /*
 
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.
 
1788
       *
 
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.
 
1792
       *
 
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.
 
1797
       */
 
1798
      Debug("GetWindowPath window %#x results in: \n"
 
1799
            "   desktopEntry = %s\n"
 
1800
            "   execPath = %s\n",
 
1801
            window, pathPair.second.c_str(), pathPair.first.c_str());
 
1802
 
 
1803
      DynBuf_SetSize(windowPathUtf8, 0);
 
1804
      DynBuf_SetSize(execPathUtf8, 0);
 
1805
 
 
1806
      std::ostringstream ostr;
 
1807
      ostr << "file://";
 
1808
      ostr << (pathPair.second.empty() ? pathPair.first : pathPair.second);
 
1809
      DynBuf_AppendString(execPathUtf8, ostr.str().c_str());
 
1810
 
 
1811
      ostr << "?WindowXID=" << window;
 
1812
      DynBuf_AppendString(windowPathUtf8, ostr.str().c_str());
 
1813
 
 
1814
      retval = true;
 
1815
   }
 
1816
 
 
1817
   return retval;
 
1818
}
 
1819
 
 
1820
 
 
1821
/*
 
1822
 *------------------------------------------------------------------------------
 
1823
 *
 
1824
 * UnityPlatformGetWindowContents --
 
1825
 *
 
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.
 
1828
 *
 
1829
 * Results:
 
1830
 *     Returns TRUE in case success and FALSE otherwise.
 
1831
 *
 
1832
 * Side effects:
 
1833
 *     None.
 
1834
 *
 
1835
 *------------------------------------------------------------------------------
 
1836
 */
 
1837
 
 
1838
Bool
 
1839
UnityPlatformGetWindowContents(UnityPlatform *up,     // IN
 
1840
                               UnityWindowId window,  // IN
 
1841
                               DynBuf *imageData,     // IN
 
1842
                               uint32 *width,         // OUT
 
1843
                               uint32 *height)        // OUT
 
1844
{
 
1845
   UnityPlatformWindow *upw;
 
1846
   Pixmap pixmap = 0;
 
1847
   XWindowAttributes attrs;
 
1848
   XImage *ximage = NULL;
 
1849
   GC xgc = 0;
 
1850
   XGCValues gcvalues;
 
1851
   Bool result = FALSE;
 
1852
   ImageInfo vmimage = { 0 };
 
1853
 
 
1854
   ASSERT(up);
 
1855
   ASSERT(imageData);
 
1856
   ASSERT(width);
 
1857
   ASSERT(height);
 
1858
 
 
1859
   upw = UPWindow_Lookup(up, window);
 
1860
 
 
1861
   if (!upw) {
 
1862
      return FALSE;
 
1863
   }
 
1864
 
 
1865
   UnityPlatformResetErrorCount(up);
 
1866
   if (!XGetWindowAttributes(up->display, upw->toplevelWindow, &attrs)
 
1867
       || UnityPlatformGetErrorCount(up)) {
 
1868
      return FALSE;
 
1869
   }
 
1870
   pixmap = XCreatePixmap(up->display, upw->toplevelWindow,
 
1871
                          attrs.width, attrs.height, attrs.depth);
 
1872
   if (UnityPlatformGetErrorCount(up)) {
 
1873
      return FALSE;
 
1874
   }
 
1875
 
 
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,
 
1881
                   GCFillStyle |
 
1882
                   GCBackground |
 
1883
                   GCForeground |
 
1884
                   GCSubwindowMode,
 
1885
                   &gcvalues);
 
1886
   if (UnityPlatformGetErrorCount(up)) {
 
1887
      goto out;
 
1888
   }
 
1889
 
 
1890
   XCopyArea(up->display, upw->toplevelWindow, pixmap, xgc, 0, 0,
 
1891
             attrs.width, attrs.height, 0, 0);
 
1892
   if (UnityPlatformGetErrorCount(up)) {
 
1893
      goto out;
 
1894
   }
 
1895
 
 
1896
   ximage = XGetImage(up->display, pixmap, 0, 0,
 
1897
                      attrs.width, attrs.height, ~0, XYPixmap);
 
1898
 
 
1899
   if (!ximage || UnityPlatformGetErrorCount(up)) {
 
1900
      goto out;
 
1901
   }
 
1902
 
 
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;
 
1912
 
 
1913
   if (ImageUtil_ConstructPNGBuffer(&vmimage, NULL, imageData)) {
 
1914
      result = TRUE;
 
1915
   }
 
1916
 
 
1917
   if (result) {
 
1918
      *width = vmimage.width;
 
1919
      *height = vmimage.height;
 
1920
   }
 
1921
 
 
1922
  out:
 
1923
   if (ximage) {
 
1924
      XDestroyImage(ximage);
 
1925
   }
 
1926
 
 
1927
   if (xgc) {
 
1928
      XFreeGC(up->display, xgc);
 
1929
   }
 
1930
 
 
1931
   if (pixmap) {
 
1932
      XFreePixmap(up->display, pixmap);
 
1933
   }
 
1934
 
 
1935
   return result;
 
1936
}
 
1937
 
 
1938
 
 
1939
/*
 
1940
 *------------------------------------------------------------------------------
 
1941
 *
 
1942
 * UnityPlatformGetIconData --
 
1943
 *
 
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.
 
1946
 *
 
1947
 * Results:
 
1948
 *     Returns TRUE if successful, and FALSE otherwise.
 
1949
 *
 
1950
 * Side effects:
 
1951
 *     None.
 
1952
 *
 
1953
 *------------------------------------------------------------------------------
 
1954
 */
 
1955
 
 
1956
Bool
 
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
 
1965
{
 
1966
   UnityPlatformWindow *upw;
 
1967
 
 
1968
   ASSERT(up);
 
1969
   ASSERT(fullLength);
 
1970
   ASSERT(imageData);
 
1971
 
 
1972
   upw = UPWindow_Lookup(up, window);
 
1973
 
 
1974
   if (!upw || !upw->clientWindow || iconType != UNITY_ICON_TYPE_MAIN) {
 
1975
      return FALSE;
 
1976
   }
 
1977
 
 
1978
   Debug("GetIconData %#lx\n", (Window)window);
 
1979
 
 
1980
   if (!DynBuf_GetSize(&upw->iconPng.data)
 
1981
       || (upw->iconPng.size != iconSize)
 
1982
       || (upw->iconPng.type != iconType)) {
 
1983
      GPtrArray *pixbufs;
 
1984
      Bool gotIcons = FALSE;
 
1985
 
 
1986
      pixbufs = AppUtil_CollectIconArray(NULL, upw->clientWindow);
 
1987
 
 
1988
      if (pixbufs && pixbufs->len) {
 
1989
         GdkPixbuf *pixbuf;
 
1990
         gchar *pngData;
 
1991
         gsize pngDataSize;
 
1992
 
 
1993
         pixbuf = (GdkPixbuf*)g_ptr_array_index(pixbufs, 0);
 
1994
 
 
1995
         if (gdk_pixbuf_save_to_buffer(pixbuf, &pngData, &pngDataSize,
 
1996
                                       "png", NULL, NULL)) {
 
1997
            DynBuf_Attach(&upw->iconPng.data, pngDataSize, pngData);
 
1998
            gotIcons = TRUE;
 
1999
         } else {
 
2000
            DynBuf_SetSize(&upw->iconPng.data, 0);
 
2001
         }
 
2002
 
 
2003
         upw->iconPng.size = iconSize;
 
2004
         upw->iconPng.type = iconType;
 
2005
      }
 
2006
 
 
2007
      AppUtil_FreeIconArray(pixbufs);
 
2008
 
 
2009
      if (!gotIcons) {
 
2010
         return FALSE;
 
2011
      }
 
2012
   }
 
2013
 
 
2014
   *fullLength = DynBuf_GetSize(&upw->iconPng.data);
 
2015
   if (dataOffset >= *fullLength) {
 
2016
      DynBuf_SetSize(imageData, 0);
 
2017
   } else {
 
2018
      uint32 realLength;
 
2019
 
 
2020
      if ((dataOffset + dataLength) > *fullLength) {
 
2021
         realLength = *fullLength - dataOffset;
 
2022
      } else {
 
2023
         realLength = dataLength;
 
2024
      }
 
2025
      DynBuf_Enlarge(imageData, realLength);
 
2026
      DynBuf_SetSize(imageData, realLength);
 
2027
 
 
2028
      memcpy(imageData->data,
 
2029
             ((const char *)DynBuf_Get(&upw->iconPng.data)) + dataOffset,
 
2030
             realLength);
 
2031
   }
 
2032
 
 
2033
   return TRUE;
 
2034
}
 
2035
 
 
2036
 
 
2037
/*
 
2038
 *----------------------------------------------------------------------------
 
2039
 *
 
2040
 * UnityPlatformUnminimizeWindow --
 
2041
 *
 
2042
 *      Tell the window to restore from the minimized state to its original
 
2043
 *      size.
 
2044
 *
 
2045
 * Results:
 
2046
 *      TRUE always
 
2047
 *
 
2048
 * Side effects:
 
2049
 *      None.
 
2050
 *
 
2051
 *----------------------------------------------------------------------------
 
2052
 */
 
2053
 
 
2054
Bool
 
2055
UnityPlatformUnminimizeWindow(UnityPlatform *up,    // IN
 
2056
                              UnityWindowId window) // IN
 
2057
{
 
2058
   UnityPlatformWindow *upw;
 
2059
 
 
2060
   ASSERT(up);
 
2061
 
 
2062
   upw = UPWindow_Lookup(up, window);
 
2063
 
 
2064
   if (!upw || !upw->clientWindow) {
 
2065
      Debug("Restoring FAILED!\n");
 
2066
      return FALSE;
 
2067
   }
 
2068
 
 
2069
   Debug("%s(%#lx)\n", __func__, upw->toplevelWindow);
 
2070
   if (upw->isMinimized) {
 
2071
      Atom data[5] = {0, 0, 0, 0, 0};
 
2072
 
 
2073
      Debug("Restoring window %#x\n", window);
 
2074
 
 
2075
      upw->isMinimized = FALSE;
 
2076
      upw->wantInputFocus = TRUE;
 
2077
 
 
2078
      /*
 
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.)
 
2083
       *
 
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.
 
2089
       */
 
2090
 
 
2091
      data[0] = 2;
 
2092
      data[1] = UnityPlatformGetServerTime(up);
 
2093
      data[2] = 0;
 
2094
      UnityPlatformSendClientMessage(up, upw->rootWindow, upw->clientWindow,
 
2095
                                     up->atoms._NET_ACTIVE_WINDOW, 32, 4, data);
 
2096
 
 
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);
 
2103
   } else {
 
2104
      Debug("Window %#x is already restored\n", window);
 
2105
   }
 
2106
 
 
2107
   return TRUE;
 
2108
}
 
2109
 
 
2110
 
 
2111
/*
 
2112
 *-----------------------------------------------------------------------------
 
2113
 *
 
2114
 * UPWindowProcessPropertyEvent --
 
2115
 *
 
2116
 *      Processes an notification that a property has changed on an X11 window.
 
2117
 *
 
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.
 
2122
 *
 
2123
 * Results:
 
2124
 *      None.
 
2125
 *
 
2126
 * Side effects:
 
2127
 *      None.
 
2128
 *
 
2129
 *-----------------------------------------------------------------------------
 
2130
 */
 
2131
 
 
2132
static void
 
2133
UPWindowProcessPropertyEvent(UnityPlatform *up,        // IN
 
2134
                             UnityPlatformWindow *upw, // IN
 
2135
                             const XEvent *xevent)     // IN
 
2136
{
 
2137
   Atom eventAtom;
 
2138
 
 
2139
   ASSERT(up);
 
2140
   ASSERT(upw);
 
2141
   ASSERT(xevent);
 
2142
 
 
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);
 
2149
      }
 
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);
 
2165
   }
 
2166
}
 
2167
 
 
2168
 
 
2169
/*
 
2170
 *-----------------------------------------------------------------------------
 
2171
 *
 
2172
 * UPWindowProcessConfigureEvent --
 
2173
 *
 
2174
 *      Processes an notification that the window configuration has changed.
 
2175
 *
 
2176
 * Results:
 
2177
 *      None.
 
2178
 *
 
2179
 * Side effects:
 
2180
 *      None.
 
2181
 *
 
2182
 *-----------------------------------------------------------------------------
 
2183
 */
 
2184
 
 
2185
static void
 
2186
UPWindowProcessConfigureEvent(UnityPlatform *up,        // IN
 
2187
                              UnityPlatformWindow *upw, // IN
 
2188
                              const XEvent *xevent)     // IN
 
2189
{
 
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;
 
2194
      int xprime;
 
2195
      int yprime;
 
2196
 
 
2197
      xprime = x + xevent->xconfigure.width + border_width;
 
2198
      yprime = y + xevent->xconfigure.height + border_width;
 
2199
      x -= border_width;
 
2200
      y -= border_width;
 
2201
 
 
2202
#ifdef VMX86_DEVEL
 
2203
      Debug("Moving window %#lx/%#lx to (%d, %d) +(%d, %d)\n",
 
2204
            upw->toplevelWindow, upw->clientWindow,
 
2205
            x, y, xprime - x, yprime - y);
 
2206
#endif
 
2207
 
 
2208
      /*
 
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.
 
2212
       */
 
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
 
2218
      }
 
2219
 
 
2220
      UnityWindowTracker_MoveWindow(up->tracker, upw->toplevelWindow,
 
2221
                                    x, y, xprime, yprime);
 
2222
 
 
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);
 
2230
      }
 
2231
   } else {
 
2232
      Debug("ProcessConfigureEvent skipped event on window %#lx (upw was %#lx/%#lx)\n",
 
2233
            xevent->xconfigure.window, upw->toplevelWindow, upw->clientWindow);
 
2234
   }
 
2235
 
 
2236
#ifdef VMX86_DEVEL
 
2237
   CompareStackingOrder(up, upw->rootWindow, __func__);
 
2238
#endif
 
2239
}
 
2240
 
 
2241
 
 
2242
#if defined(VM_HAVE_X11_SHAPE_EXT)
 
2243
 
 
2244
 
 
2245
/*
 
2246
 *-----------------------------------------------------------------------------
 
2247
 *
 
2248
 * UPWindowUpdateShape --
 
2249
 *
 
2250
 *      Updates the window shape.
 
2251
 *
 
2252
 * Results:
 
2253
 *      None.
 
2254
 *
 
2255
 * Side effects:
 
2256
 *      Notification to the window tracker
 
2257
 *
 
2258
 *-----------------------------------------------------------------------------
 
2259
 */
 
2260
 
 
2261
static void
 
2262
UPWindowUpdateShape(UnityPlatform *up,        // IN
 
2263
                    UnityPlatformWindow *upw) // IN
 
2264
{
 
2265
   RegionPtr clipRegion = NULL;
 
2266
   RegionPtr boundingRegion = NULL;
 
2267
   RegionPtr region = NULL;
 
2268
   XRectangle *rects = NULL;
 
2269
   int rectCount;
 
2270
   int rectOrdering;
 
2271
 
 
2272
   /*
 
2273
    * Retrieve the X11 'clipping shape' (the window shape including its border) and turn
 
2274
    * it into a region.
 
2275
    */
 
2276
   UnityPlatformResetErrorCount(up);
 
2277
   rects = XShapeGetRectangles(up->display, upw->toplevelWindow, ShapeClip,
 
2278
                               &rectCount, &rectOrdering);
 
2279
   if (!UnityPlatformGetErrorCount(up) && rects && rectCount) {
 
2280
      xRectangle *vmRects;
 
2281
      int i;
 
2282
 
 
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;
 
2293
      }
 
2294
 
 
2295
      clipRegion = miRectsToRegion(rectCount, vmRects, 0);
 
2296
   }
 
2297
   XFree(rects); rects = NULL;
 
2298
   rectCount = 0;
 
2299
 
 
2300
   /*
 
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.
 
2306
    *
 
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.
 
2310
    */
 
2311
   {
 
2312
      int bShaped;
 
2313
      int cShaped;
 
2314
      int dummy;
 
2315
      uint udummy;
 
2316
 
 
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);
 
2322
         return;
 
2323
      }
 
2324
   }
 
2325
 
 
2326
   UnityPlatformResetErrorCount(up);
 
2327
 
 
2328
   /*
 
2329
    * Retrieve the X11 'clipping shape' (the window shape of the window without its
 
2330
    * border) and turn it into a region.
 
2331
    */
 
2332
   rects = XShapeGetRectangles(up->display, upw->toplevelWindow, ShapeBounding,
 
2333
                               &rectCount, &rectOrdering);
 
2334
   if (!UnityPlatformGetErrorCount(up)
 
2335
       && rects && rectCount) {
 
2336
      xRectangle *vmRects;
 
2337
      int i;
 
2338
 
 
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;
 
2349
      }
 
2350
 
 
2351
      boundingRegion = miRectsToRegion(rectCount, vmRects, 0);
 
2352
   }
 
2353
   XFree(rects);
 
2354
 
 
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;
 
2362
   }
 
2363
 
 
2364
   UnityWindowTracker_ChangeWindowRegion(up->tracker, upw->toplevelWindow, region);
 
2365
   if (clipRegion) {
 
2366
      miRegionDestroy(clipRegion);
 
2367
   }
 
2368
   if (boundingRegion) {
 
2369
      miRegionDestroy(boundingRegion);
 
2370
   }
 
2371
   if (region) {
 
2372
      miRegionDestroy(region);
 
2373
   }
 
2374
}
 
2375
 
 
2376
 
 
2377
/*
 
2378
 *-----------------------------------------------------------------------------
 
2379
 *
 
2380
 * UPWindowProcessShapeEvent --
 
2381
 *
 
2382
 *      Processes an notification that the non-rectangular window shape has changed.
 
2383
 *
 
2384
 * Results:
 
2385
 *      None.
 
2386
 *
 
2387
 * Side effects:
 
2388
 *      None.
 
2389
 *
 
2390
 *-----------------------------------------------------------------------------
 
2391
 */
 
2392
 
 
2393
static void
 
2394
UPWindowProcessShapeEvent(UnityPlatform *up,        // IN
 
2395
                          UnityPlatformWindow *upw, // IN
 
2396
                          const XEvent *xevent)     // IN
 
2397
{
 
2398
   XShapeEvent *sev;
 
2399
 
 
2400
   ASSERT(up);
 
2401
   ASSERT(upw);
 
2402
   ASSERT(xevent->type == (up->shapeEventBase + ShapeNotify));
 
2403
 
 
2404
   sev = (XShapeEvent *)xevent;
 
2405
   ASSERT (sev->window == upw->toplevelWindow ||
 
2406
           sev->window == upw->clientWindow);
 
2407
 
 
2408
   if (sev->shaped) {
 
2409
      UPWindowUpdateShape(up, upw);
 
2410
   } else {
 
2411
      UnityWindowTracker_ChangeWindowRegion(up->tracker, upw->toplevelWindow, NULL);
 
2412
   }
 
2413
}
 
2414
#endif
 
2415
 
 
2416
 
 
2417
/*
 
2418
 *-----------------------------------------------------------------------------
 
2419
 *
 
2420
 * UnityPlatformWindowProcessEvent --
 
2421
 *
 
2422
 *      Handle an event on a typical window.
 
2423
 *
 
2424
 * Results:
 
2425
 *      None.
 
2426
 *
 
2427
 * Side effects:
 
2428
 *      Many.
 
2429
 *
 
2430
 *-----------------------------------------------------------------------------
 
2431
 */
 
2432
 
 
2433
void
 
2434
UPWindow_ProcessEvent(UnityPlatform *up,        // IN
 
2435
                      UnityPlatformWindow *upw, // IN
 
2436
                      Window realEventWindow,   // IN
 
2437
                      const XEvent *xevent)     // IN
 
2438
{
 
2439
   Bool eventHandled = TRUE;
 
2440
 
 
2441
   ASSERT(up);
 
2442
   ASSERT(upw);
 
2443
   ASSERT(xevent);
 
2444
 
 
2445
   UPWindow_CheckRelevance(up, upw, xevent);
 
2446
 
 
2447
   switch (xevent->type) {
 
2448
   case KeyPress:
 
2449
   case KeyRelease:
 
2450
   case ButtonPress:
 
2451
   case ButtonRelease:
 
2452
   case MotionNotify:
 
2453
   case EnterNotify:
 
2454
   case LeaveNotify:
 
2455
   case KeymapNotify:
 
2456
   case Expose:
 
2457
   case GraphicsExpose:
 
2458
   case NoExpose:
 
2459
   case MapRequest:
 
2460
   case ResizeRequest:
 
2461
   case CirculateRequest:
 
2462
   case SelectionClear:
 
2463
   case SelectionRequest:
 
2464
   case SelectionNotify:
 
2465
   case ColormapNotify:
 
2466
   case ClientMessage:
 
2467
   case GravityNotify:
 
2468
   case VisibilityNotify:
 
2469
   case MappingNotify:
 
2470
   case ReparentNotify:
 
2471
   case ConfigureRequest:
 
2472
      break; // No extra processing on these for now
 
2473
 
 
2474
   case CreateNotify:
 
2475
      /* Do nothing. The UPWindow has already been created. */
 
2476
      break;
 
2477
 
 
2478
   case FocusIn:
 
2479
      if (upw->isRelevant) {
 
2480
         UnityWindowInfo *info;
 
2481
         info = UnityWindowTracker_LookupWindow(up->tracker, upw->toplevelWindow);
 
2482
 
 
2483
         UnityWindowTracker_ChangeWindowState(up->tracker,
 
2484
                                              upw->toplevelWindow,
 
2485
                                              info->state | UNITY_WINDOW_STATE_IN_FOCUS);
 
2486
      }
 
2487
      break;
 
2488
 
 
2489
   case FocusOut:
 
2490
      if (upw->isRelevant) {
 
2491
         UnityWindowInfo *info;
 
2492
         info = UnityWindowTracker_LookupWindow(up->tracker, upw->toplevelWindow);
 
2493
 
 
2494
         UnityWindowTracker_ChangeWindowState(up->tracker,
 
2495
                                              upw->toplevelWindow,
 
2496
                                              (info->state
 
2497
                                               & ~UNITY_WINDOW_STATE_IN_FOCUS));
 
2498
      }
 
2499
      break;
 
2500
 
 
2501
   case DestroyNotify:
 
2502
      Debug("Destroying window (%p) %#lx/%#lx\n",
 
2503
            upw, upw->toplevelWindow, upw->clientWindow);
 
2504
 
 
2505
      /*
 
2506
       * Release the UnityPlatform object's reference to this UnityPlatformWindow,
 
2507
       */
 
2508
      upw->windowType = UNITY_WINDOW_TYPE_NONE;
 
2509
      upw->deleteWhenSafe = TRUE;
 
2510
#ifdef VMX86_DEVEL
 
2511
   CompareStackingOrder(up, upw->rootWindow, __func__);
 
2512
#endif
 
2513
      break;
 
2514
 
 
2515
   case UnmapNotify:
 
2516
      upw->wantInputFocus = FALSE;
 
2517
      upw->isViewable = FALSE;
 
2518
      break;
 
2519
 
 
2520
   case MapNotify:
 
2521
      /*
 
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.
 
2524
       */
 
2525
      if (upw->wantInputFocus && upw->clientWindow) {
 
2526
         XSetInputFocus(up->display, upw->clientWindow, RevertToParent,
 
2527
                        UnityPlatformGetServerTime(up));
 
2528
         upw->wantInputFocus = FALSE;
 
2529
      }
 
2530
 
 
2531
      upw->isViewable = TRUE;
 
2532
      break;
 
2533
 
 
2534
   case CirculateNotify:
 
2535
      if (upw->isRelevant) {
 
2536
         UPWindow_Restack(up, upw,
 
2537
                          (up->topWindow && xevent->xcirculate.place == PlaceOnTop)
 
2538
                          ? up->topWindow->toplevelWindow : None);
 
2539
      }
 
2540
      break;
 
2541
 
 
2542
   case PropertyNotify:
 
2543
      UPWindowProcessPropertyEvent(up, upw, xevent);
 
2544
      break;
 
2545
 
 
2546
   case ConfigureNotify:
 
2547
      UPWindowProcessConfigureEvent(up, upw, xevent);
 
2548
      break;
 
2549
 
 
2550
   default:
 
2551
      eventHandled = FALSE; // Unknown "regular" event
 
2552
      break;
 
2553
   }
 
2554
 
 
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;
 
2561
      }
 
2562
#endif
 
2563
 
 
2564
      ASSERT(eventHandled);
 
2565
   }
 
2566
}
 
2567
 
 
2568
 
 
2569
/*
 
2570
 *-----------------------------------------------------------------------------
 
2571
 *
 
2572
 * UPWindowUpdateTitle --
 
2573
 *
 
2574
 *      Tells the window tracker about the window's latest title
 
2575
 *
 
2576
 * Results:
 
2577
 *      None.
 
2578
 *
 
2579
 * Side effects:
 
2580
 *      Notification to the window tracker
 
2581
 *
 
2582
 *-----------------------------------------------------------------------------
 
2583
 */
 
2584
 
 
2585
static void
 
2586
UPWindowUpdateTitle(UnityPlatform *up,        // IN
 
2587
                    UnityPlatformWindow *upw) // IN
 
2588
{
 
2589
   Atom propertyType;
 
2590
   int propertyFormat;
 
2591
   unsigned long itemsReturned;
 
2592
   unsigned long bytesRemaining;
 
2593
   unsigned char *valueReturned = NULL;
 
2594
   DynBuf titleBuf;
 
2595
 
 
2596
   if (!upw->clientWindow) {
 
2597
      return;
 
2598
   }
 
2599
 
 
2600
   if (XGetWindowProperty(up->display, upw->clientWindow, up->atoms.WM_NAME, 0,
 
2601
                          1024, False, AnyPropertyType,
 
2602
                          &propertyType, &propertyFormat, &itemsReturned,
 
2603
                          &bytesRemaining, &valueReturned)
 
2604
       != Success) {
 
2605
      /*
 
2606
       * Some random error occurred - perhaps the window disappeared
 
2607
       */
 
2608
      return;
 
2609
   }
 
2610
 
 
2611
   if (bytesRemaining != 0) {
 
2612
      Log("Skipping title update for window %#lx.  Title too long.\n",
 
2613
          upw->clientWindow);
 
2614
      return;
 
2615
   }
 
2616
 
 
2617
   /*
 
2618
    * propertyFormat tells us (in bits) the size of each item returned.  Let's
 
2619
    * convert that to bytes.  See XGetWindowProperty(3) for details.
 
2620
    */
 
2621
   size_t bytesRead = itemsReturned * propertyFormat / 8;
 
2622
   Glib::ustring newTitle;
 
2623
 
 
2624
   if (bytesRead) {                 // i.e. valueReturned isn't empty
 
2625
      if (   propertyType == XA_STRING
 
2626
          || propertyType == up->atoms.UTF8_STRING) {
 
2627
         /*
 
2628
          * Insert() used because NUL termination isn't guaranteed.  (Is that
 
2629
          * really the case?  TODO: Look this up.)
 
2630
          */
 
2631
         newTitle.insert(0, (const char *)valueReturned, bytesRead);
 
2632
      } else if (propertyType == up->atoms.COMPOUND_TEXT) {
 
2633
         /*
 
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.
 
2637
          */
 
2638
         gchar **utf8List = NULL;
 
2639
         gint nconverted;
 
2640
         nconverted = gdk_text_property_to_utf8_list(
 
2641
            gdk_x11_xatom_to_atom(up->atoms.COMPOUND_TEXT), propertyFormat,
 
2642
            valueReturned, bytesRead, &utf8List);
 
2643
         if (nconverted) {
 
2644
            newTitle.assign(utf8List[0]);
 
2645
         }
 
2646
         g_strfreev(utf8List);
 
2647
      }
 
2648
   }
 
2649
   XFree(valueReturned);
 
2650
 
 
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,
 
2656
                                     &titleBuf);
 
2657
   DynBuf_Destroy(&titleBuf);
 
2658
}
 
2659
 
 
2660
 
 
2661
/*
 
2662
 *-----------------------------------------------------------------------------
 
2663
 *
 
2664
 * UPWindowUpdateType --
 
2665
 *
 
2666
 *      Tells the window tracker about the window's latest type
 
2667
 *
 
2668
 * Results:
 
2669
 *      None.
 
2670
 *
 
2671
 * Side effects:
 
2672
 *      Notification to the window tracker
 
2673
 *
 
2674
 *-----------------------------------------------------------------------------
 
2675
 */
 
2676
 
 
2677
static void
 
2678
UPWindowUpdateType(UnityPlatform *up,        // IN
 
2679
                   UnityPlatformWindow *upw) // IN
 
2680
{
 
2681
   ASSERT(up);
 
2682
   ASSERT(upw);
 
2683
 
 
2684
   /*
 
2685
    * upw->windowType was previously updated by the CheckRelevance method.
 
2686
    */
 
2687
   UnityWindowTracker_ChangeWindowType(up->tracker,
 
2688
                                       upw->toplevelWindow,
 
2689
                                       upw->windowType);
 
2690
}
 
2691
 
 
2692
 
 
2693
/*
 
2694
 *-----------------------------------------------------------------------------
 
2695
 *
 
2696
 * UPWindowUpdateProtocols --
 
2697
 *
 
2698
 *      Updates the list of protocols supported by the window.
 
2699
 *
 
2700
 * Results:
 
2701
 *      None.
 
2702
 *
 
2703
 * Side effects:
 
2704
 *      Notification to the window tracker
 
2705
 *
 
2706
 *-----------------------------------------------------------------------------
 
2707
 */
 
2708
 
 
2709
static void
 
2710
UPWindowUpdateProtocols(UnityPlatform *up,        // IN
 
2711
                        UnityPlatformWindow *upw) // IN
 
2712
{
 
2713
   Atom propertyType;
 
2714
   int propertyFormat;
 
2715
   unsigned long itemsReturned;
 
2716
   unsigned long bytesRemaining;
 
2717
   Atom *valueReturned = NULL;
 
2718
   uint i;
 
2719
 
 
2720
   if (!upw->clientWindow) {
 
2721
      return;
 
2722
   }
 
2723
 
 
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)
 
2728
       != Success) {
 
2729
      /*
 
2730
       * Some random error occurred - perhaps the window disappeared.
 
2731
       */
 
2732
      return;
 
2733
   }
 
2734
 
 
2735
   if (propertyType != up->atoms.WM_STATE
 
2736
       || propertyFormat != 32) {
 
2737
      itemsReturned = 0;
 
2738
   }
 
2739
 
 
2740
   memset(upw->windowProtocols, 0, sizeof upw->windowProtocols);
 
2741
   for (i = 0; i < itemsReturned; i++) {
 
2742
      UnityX11WinProtocol proto;
 
2743
 
 
2744
      if (valueReturned[i] == up->atoms.WM_DELETE_WINDOW) {
 
2745
         proto = UNITY_X11_WIN_WM_DELETE_WINDOW;
 
2746
      } else {
 
2747
         continue;
 
2748
      }
 
2749
 
 
2750
      upw->windowProtocols[proto] = TRUE;
 
2751
   }
 
2752
   XFree(valueReturned);
 
2753
}
 
2754
 
 
2755
 
 
2756
/*
 
2757
 *-----------------------------------------------------------------------------
 
2758
 *
 
2759
 * UPWindowUpdateActions --
 
2760
 *
 
2761
 *      Updates the window attributes based on a new _NET_WM_ALLOWED_ACTIONS attribute.
 
2762
 *
 
2763
 * Results:
 
2764
 *      None.
 
2765
 *
 
2766
 * Side effects:
 
2767
 *      Notification to the window tracker
 
2768
 *
 
2769
 *-----------------------------------------------------------------------------
 
2770
 */
 
2771
 
 
2772
static void
 
2773
UPWindowUpdateActions(UnityPlatform *up,        // IN
 
2774
                      UnityPlatformWindow *upw) // IN
 
2775
{
 
2776
   Atom propertyType;
 
2777
   int propertyFormat;
 
2778
   unsigned long itemsReturned = 0;
 
2779
   unsigned long bytesRemaining;
 
2780
   Atom *valueReturned = NULL;
 
2781
   uint i;
 
2782
   Bool curAttrValues[UNITY_MAX_ATTRIBUTES];
 
2783
   Bool attrsAreSet[UNITY_MAX_ATTRIBUTES];
 
2784
   Bool haveHorizMax;
 
2785
   Bool haveVertMax;
 
2786
 
 
2787
   if (!upw->clientWindow) {
 
2788
      return;
 
2789
   }
 
2790
 
 
2791
   memset(curAttrValues, 0, sizeof curAttrValues);
 
2792
   memset(attrsAreSet, 0, sizeof attrsAreSet);
 
2793
   haveHorizMax = haveVertMax = FALSE;
 
2794
 
 
2795
   /*
 
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).
 
2799
    */
 
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);
 
2813
 
 
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)
 
2819
       == Success
 
2820
      && propertyFormat == 32) {
 
2821
      for (i = 0; i < itemsReturned; i++) {
 
2822
         UnityWindowAttribute attr;
 
2823
         Bool attrValue = TRUE;
 
2824
 
 
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;
 
2829
            continue;
 
2830
         } else if (valueReturned[i] == up->atoms._NET_WM_ACTION_MAXIMIZE_VERT) {
 
2831
            haveVertMax = TRUE;
 
2832
            continue;
 
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;
 
2841
         } else {
 
2842
            continue;
 
2843
         }
 
2844
 
 
2845
         curAttrValues[attr] = attrValue;
 
2846
         attrsAreSet[attr] = TRUE;
 
2847
      }
 
2848
      XFree(valueReturned);
 
2849
   } else {
 
2850
      curAttrValues[UNITY_WINDOW_ATTR_MINIMIZABLE] = TRUE;
 
2851
      attrsAreSet[UNITY_WINDOW_ATTR_MINIMIZABLE] = TRUE;
 
2852
   }
 
2853
 
 
2854
   curAttrValues[UNITY_WINDOW_ATTR_MAXIMIZABLE] = (haveHorizMax && haveVertMax);
 
2855
   attrsAreSet[UNITY_WINDOW_ATTR_MAXIMIZABLE] = TRUE;
 
2856
 
 
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]);
 
2861
      }
 
2862
   }
 
2863
}
 
2864
 
 
2865
 
 
2866
/*
 
2867
 *-----------------------------------------------------------------------------
 
2868
 *
 
2869
 * UPWindowGetDesktop --
 
2870
 *
 
2871
 *      Retrieve's the current X11 virtual desktop of a window.
 
2872
 *
 
2873
 * Results:
 
2874
 *      Virtual desktop number
 
2875
 *
 
2876
 * Side effects:
 
2877
 *      None.
 
2878
 *
 
2879
 *-----------------------------------------------------------------------------
 
2880
 */
 
2881
 
 
2882
static Bool
 
2883
UPWindowGetDesktop(UnityPlatform *up,        // IN
 
2884
                   UnityPlatformWindow *upw, // IN
 
2885
                   int *guestDesktop)        // IN/OUT
 
2886
{
 
2887
   Atom propertyType;
 
2888
   int propertyFormat;
 
2889
   unsigned long itemsReturned = 0;
 
2890
   unsigned long bytesRemaining;
 
2891
   Atom *valueReturned = NULL;
 
2892
   Bool retval = FALSE;
 
2893
 
 
2894
   if (!upw->clientWindow) {
 
2895
      return FALSE;
 
2896
   }
 
2897
 
 
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)
 
2903
       == Success
 
2904
       && propertyType == XA_CARDINAL
 
2905
       && propertyFormat == 32
 
2906
       && itemsReturned) {
 
2907
 
 
2908
      *guestDesktop = *valueReturned;
 
2909
      retval = TRUE;
 
2910
   }
 
2911
 
 
2912
   XFree(valueReturned);
 
2913
 
 
2914
   return retval;
 
2915
}
 
2916
 
 
2917
 
 
2918
/*
 
2919
 *-----------------------------------------------------------------------------
 
2920
 *
 
2921
 * UPWindowUpdateDesktop --
 
2922
 *
 
2923
 *      Updates the window's virtual desktop based on a new _NET_WM_DESKTOP attribute.
 
2924
 *
 
2925
 * Results:
 
2926
 *      None.
 
2927
 *
 
2928
 * Side effects:
 
2929
 *      Notification to the window tracker.
 
2930
 *
 
2931
 *-----------------------------------------------------------------------------
 
2932
 */
 
2933
 
 
2934
static void
 
2935
UPWindowUpdateDesktop(UnityPlatform *up,        // IN
 
2936
                      UnityPlatformWindow *upw) // IN
 
2937
{
 
2938
   int guestDesktop = -1;
 
2939
 
 
2940
   if (!upw->clientWindow) {
 
2941
      return;
 
2942
   }
 
2943
 
 
2944
   if (!UPWindowGetDesktop(up, upw, &guestDesktop)) {
 
2945
      Debug("Window %#lx has a clientWindow, but its "
 
2946
            "virtual desktop could not be retrieved\n",
 
2947
            upw->clientWindow);
 
2948
      return;
 
2949
   }
 
2950
 
 
2951
   if (guestDesktop < ((int)up->desktopInfo.numDesktops)) {
 
2952
      UnityDesktopId desktopId = -1;
 
2953
      Bool isSticky;
 
2954
 
 
2955
      isSticky = (guestDesktop < 0);
 
2956
      if (!isSticky) {
 
2957
         desktopId = up->desktopInfo.guestDesktopToUnity[guestDesktop];
 
2958
      }
 
2959
 
 
2960
      Debug("Window %#lx is now on desktop %d\n", upw->toplevelWindow, desktopId);
 
2961
      UnityWindowTracker_ChangeWindowDesktop(up->tracker,
 
2962
                                             upw->toplevelWindow,
 
2963
                                             desktopId);
 
2964
 
 
2965
      UnityWindowTracker_ChangeWindowAttribute(up->tracker,
 
2966
                                               upw->toplevelWindow,
 
2967
                                               UNITY_WINDOW_ATTR_STICKY,
 
2968
                                               isSticky);
 
2969
   } else {
 
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);
 
2973
   }
 
2974
}
 
2975
 
 
2976
 
 
2977
/*
 
2978
 *-----------------------------------------------------------------------------
 
2979
 *
 
2980
 * UPWindowUpdateIcon --
 
2981
 *
 
2982
 *      Updates the window's virtual desktop based on a new _NET_WM_DESKTOP attribute.
 
2983
 *
 
2984
 * Results:
 
2985
 *      None.
 
2986
 *
 
2987
 * Side effects:
 
2988
 *      Notification to the window tracker.
 
2989
 *
 
2990
 *-----------------------------------------------------------------------------
 
2991
 */
 
2992
 
 
2993
static void
 
2994
UPWindowUpdateIcon(UnityPlatform *up,        // IN
 
2995
                   UnityPlatformWindow *upw) // IN
 
2996
{
 
2997
   UnityWindowTracker_NotifyIconChanged(up->tracker, upw->toplevelWindow,
 
2998
                                        UNITY_ICON_TYPE_MAIN);
 
2999
 
 
3000
   if (DynBuf_GetSize(&upw->iconPng.data)) {
 
3001
      DynBuf_SetSize(&upw->iconPng.data, 0);
 
3002
   }
 
3003
}
 
3004
 
 
3005
 
 
3006
/*
 
3007
 *-----------------------------------------------------------------------------
 
3008
 *
 
3009
 * UPWindowIsNowWithdrawn  --
 
3010
 *
 
3011
 *      In response to an update to a window's WM_STATE property, properties, test
 
3012
 *      whether or not the window has been withdrawn.
 
3013
 *
 
3014
 * Results:
 
3015
 *      TRUE if we believe the window was withdrawn, FALSE otherwise.
 
3016
 *
 
3017
 * Side effects:
 
3018
 *      None.
 
3019
 *
 
3020
 *-----------------------------------------------------------------------------
 
3021
 */
 
3022
 
 
3023
static Bool
 
3024
UPWindowIsNowWithdrawn(UnityPlatform *up,            // IN
 
3025
                       UnityPlatformWindow *upw,     // IN
 
3026
                       const XPropertyEvent *xevent) // IN
 
3027
{
 
3028
   Window mainWindow;
 
3029
   Bool isWithdrawn = FALSE;
 
3030
 
 
3031
   Atom actual_type;
 
3032
   int actual_format;
 
3033
   unsigned long nitems;
 
3034
   unsigned long bytes_remaining;
 
3035
   unsigned char *properties = NULL;
 
3036
 
 
3037
   mainWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
 
3038
 
 
3039
   /*
 
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.
 
3042
    */
 
3043
   if (xevent->state == PropertyDelete) {
 
3044
      return TRUE;
 
3045
   }
 
3046
 
 
3047
   if (XGetWindowProperty(up->display, mainWindow, up->atoms.WM_STATE,
 
3048
                      0,                // offset
 
3049
                      1,                // length (in 32-bit chunks)
 
3050
                      False,            // delete
 
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;
 
3058
 
 
3059
      if (actual_type == None ||
 
3060
          (nitems > 0 && *state == WithdrawnState)) {
 
3061
         isWithdrawn = TRUE;
 
3062
      }
 
3063
 
 
3064
      XFree(properties);
 
3065
   }
 
3066
 
 
3067
   return isWithdrawn;
 
3068
}
 
3069
 
 
3070
 
 
3071
/*
 
3072
 *-----------------------------------------------------------------------------
 
3073
 *
 
3074
 * UPWindowUpdateState --
 
3075
 *
 
3076
 *      Tells the window tracker about the window's changes to the _NET_WM_STATE and
 
3077
 *      WM_STATE properties.
 
3078
 *
 
3079
 * Results:
 
3080
 *      None.
 
3081
 *
 
3082
 * Side effects:
 
3083
 *      Notification to the window tracker
 
3084
 *
 
3085
 *-----------------------------------------------------------------------------
 
3086
 */
 
3087
 
 
3088
static void
 
3089
UPWindowUpdateState(UnityPlatform *up,            // IN
 
3090
                    UnityPlatformWindow *upw,     // IN
 
3091
                    const XPropertyEvent *xevent) // IN
 
3092
{
 
3093
   Atom propertyType;
 
3094
   int propertyFormat;
 
3095
   unsigned long itemsReturned;
 
3096
   unsigned long bytesRemaining;
 
3097
   Atom *valueReturned = NULL;
 
3098
   uint i;
 
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;
 
3106
   Window mainWindow;
 
3107
 
 
3108
   mainWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
 
3109
 
 
3110
   /*
 
3111
    * If a change to WM_STATE indicates this window was withdrawn/unmapped, simply
 
3112
    * invalidate it from the window tracker and return.
 
3113
    */
 
3114
   if (xevent->atom == up->atoms.WM_STATE &&
 
3115
       UPWindowIsNowWithdrawn(up, upw, xevent)) {
 
3116
      UPWindowSetRelevance(up, upw, FALSE);
 
3117
      return;
 
3118
   }
 
3119
 
 
3120
   memset(curAttrValues, 0, sizeof curAttrValues);
 
3121
   memset(attrsAreSet, 0, sizeof attrsAreSet);
 
3122
 
 
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;
 
3133
 
 
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)
 
3139
          != Success) {
 
3140
         /*
 
3141
          * Some random error occurred - perhaps the window disappeared
 
3142
          */
 
3143
         return;
 
3144
      }
 
3145
 
 
3146
      if (propertyType == up->atoms.WM_STATE
 
3147
          && propertyFormat == 32
 
3148
          && itemsReturned
 
3149
          && valueReturned[0] == IconicState) {
 
3150
         isMinimized = TRUE;
 
3151
      }
 
3152
      XFree(valueReturned);
 
3153
   }
 
3154
 
 
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)
 
3159
       != Success) {
 
3160
      /*
 
3161
       * Some random error occurred - perhaps the window disappeared
 
3162
       */
 
3163
      return;
 
3164
   }
 
3165
 
 
3166
   if (propertyType != XA_ATOM
 
3167
       || propertyFormat != 32) {
 
3168
      itemsReturned = 0;
 
3169
   }
 
3170
 
 
3171
   for (i = 0; i < itemsReturned; i++) {
 
3172
      UnityWindowAttribute attr;
 
3173
      Bool attrValue = TRUE;
 
3174
 
 
3175
      if (valueReturned[i] == up->atoms._NET_WM_STATE_MINIMIZED
 
3176
          || valueReturned[i] == up->atoms._NET_WM_STATE_HIDDEN) {
 
3177
         isMinimized = TRUE;
 
3178
         continue;
 
3179
      } else if (valueReturned[i] == up->atoms._NET_WM_STATE_MAXIMIZED_HORZ) {
 
3180
         haveHorizMax = TRUE;
 
3181
         continue;
 
3182
      } else if (valueReturned[i] == up->atoms._NET_WM_STATE_MAXIMIZED_VERT) {
 
3183
         haveVertMax = TRUE;
 
3184
         continue;
 
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) {
 
3203
         doSkipPager = TRUE;
 
3204
         continue;
 
3205
      } else {
 
3206
         continue;
 
3207
      }
 
3208
 
 
3209
      curAttrValues[attr] = attrValue;
 
3210
      attrsAreSet[attr] = TRUE;
 
3211
   }
 
3212
   XFree(valueReturned);
 
3213
 
 
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;
 
3219
 
 
3220
   if (upw->isRelevant) {
 
3221
      UnityWindowInfo *info;
 
3222
      uint32 newState;
 
3223
      int cDesk = -1;
 
3224
      int gDesk;
 
3225
 
 
3226
      info = UnityWindowTracker_LookupWindow(up->tracker, upw->toplevelWindow);
 
3227
      ASSERT(info);
 
3228
 
 
3229
      newState = info->state;
 
3230
 
 
3231
      /*
 
3232
       * Only push minimize state for windows on the same desktop (inc. sticky
 
3233
       * windows).
 
3234
       */
 
3235
      if (UPWindowGetDesktop(up, upw, &gDesk)) {
 
3236
         cDesk = UnityX11GetCurrentDesktop(up);
 
3237
         if (cDesk == gDesk || gDesk == -1) {
 
3238
            if (isMinimized) {
 
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;
 
3243
               }
 
3244
            } else {
 
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;
 
3249
               }
 
3250
            }
 
3251
         }
 
3252
      } else {
 
3253
         Debug("%s: Unable to get window desktop\n", __FUNCTION__);
 
3254
      }
 
3255
 
 
3256
      if (newState != info->state) {
 
3257
         UnityWindowTracker_ChangeWindowState(up->tracker,
 
3258
                                              upw->toplevelWindow,
 
3259
                                              newState);
 
3260
      }
 
3261
 
 
3262
      upw->isMinimized = isMinimized;
 
3263
      upw->isMaximized = (haveHorizMax && haveVertMax);
 
3264
 
 
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]);
 
3269
         }
 
3270
      }
 
3271
   }
 
3272
}
 
3273
 
 
3274
 
 
3275
/*
 
3276
 *-----------------------------------------------------------------------------
 
3277
 *
 
3278
 * UPWindowPushFullUpdate --
 
3279
 *
 
3280
 *      Pushes a full update for the given window.
 
3281
 *
 
3282
 * Results:
 
3283
 *      TRUE if we pushed the updates for this window, FALSE otherwise.
 
3284
 *
 
3285
 * Side effects:
 
3286
 *      UnityWindowTracker contains latest info on this window.
 
3287
 *
 
3288
 *-----------------------------------------------------------------------------
 
3289
 */
 
3290
 
 
3291
static Bool
 
3292
UPWindowPushFullUpdate(UnityPlatform *up,            // IN
 
3293
                       UnityPlatformWindow *upw)     // IN
 
3294
{
 
3295
   XWindowAttributes winAttr;
 
3296
   Atom *props;
 
3297
   int propCount;
 
3298
   int i;
 
3299
   int x, y, xprime, yprime;
 
3300
   int border_width;
 
3301
 
 
3302
   XGetWindowAttributes(up->display, upw->toplevelWindow, &winAttr);
 
3303
   UPWindowUpdateFrameExtents(up, upw);
 
3304
 
 
3305
   x = winAttr.x;
 
3306
   y = winAttr.y;
 
3307
   border_width = winAttr.border_width;
 
3308
 
 
3309
   xprime = x + winAttr.width + border_width;
 
3310
   yprime = y + winAttr.height + border_width;
 
3311
   x -= border_width;
 
3312
   y -= border_width;
 
3313
 
 
3314
   /*
 
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.
 
3318
    */
 
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
 
3324
   }
 
3325
 
 
3326
   UnityWindowTracker_MoveWindow(up->tracker, upw->toplevelWindow,
 
3327
                                 x, y, xprime, yprime);
 
3328
 
 
3329
#if defined(VM_HAVE_X11_SHAPE_EXT)
 
3330
   UPWindowUpdateShape(up, upw);
 
3331
#endif
 
3332
   UPWindowUpdateType(up, upw);
 
3333
 
 
3334
   propCount = 0;
 
3335
   UnityPlatformResetErrorCount(up);
 
3336
   props = XListProperties(up->display,
 
3337
                           upw->clientWindow ? upw->clientWindow : upw->toplevelWindow,
 
3338
                           &propCount);
 
3339
   if (!UnityPlatformGetErrorCount(up)) {
 
3340
      for (i = 0; i < propCount; i++) {
 
3341
         XEvent fakeEvent = {0,};
 
3342
 
 
3343
         fakeEvent.xproperty.state = PropertyNewValue;
 
3344
         fakeEvent.xproperty.atom = props[i];
 
3345
         UPWindowProcessPropertyEvent(up, upw, &fakeEvent);
 
3346
      }
 
3347
      XFree(props);
 
3348
   }
 
3349
 
 
3350
   return TRUE;
 
3351
}
 
3352
 
 
3353
 
 
3354
/*
 
3355
 *-----------------------------------------------------------------------------
 
3356
 *
 
3357
 * UPWindow_ProtocolSupported --
 
3358
 *
 
3359
 *      Returns whether a particular window supports a particular protocol.
 
3360
 *
 
3361
 * Results:
 
3362
 *      TRUE if supported, FALSE otherwise.
 
3363
 *
 
3364
 * Side effects:
 
3365
 *      None.
 
3366
 *
 
3367
 *-----------------------------------------------------------------------------
 
3368
 */
 
3369
 
 
3370
Bool
 
3371
UPWindow_ProtocolSupported(const UnityPlatform *up,        // IN
 
3372
                           const UnityPlatformWindow *upw, // IN
 
3373
                           UnityX11WinProtocol proto)      // IN
 
3374
{
 
3375
   ASSERT(up);
 
3376
   ASSERT(upw);
 
3377
   ASSERT(proto < UNITY_X11_MAX_WIN_PROTOCOLS);
 
3378
 
 
3379
   return upw->windowProtocols[proto];
 
3380
}
 
3381
 
 
3382
 
 
3383
/*
 
3384
 *----------------------------------------------------------------------------
 
3385
 *
 
3386
 * UnityPlatformShowWindow --
 
3387
 *
 
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.
 
3391
 *
 
3392
 * Results:
 
3393
 *
 
3394
 *      FALSE if the Window handle is invalid.
 
3395
 *      TRUE otherwise.
 
3396
 *
 
3397
 * Side effects:
 
3398
 *      None.
 
3399
 *
 
3400
 *----------------------------------------------------------------------------
 
3401
 */
 
3402
 
 
3403
Bool
 
3404
UnityPlatformShowWindow(UnityPlatform *up,    // IN
 
3405
                        UnityWindowId window) // IN
 
3406
{
 
3407
   UnityPlatformWindow *upw;
 
3408
 
 
3409
   ASSERT(up);
 
3410
 
 
3411
   upw = UPWindow_Lookup(up, window);
 
3412
 
 
3413
   if (!upw || !upw->clientWindow) {
 
3414
      Debug("Hiding FAILED!\n");
 
3415
      return FALSE;
 
3416
   }
 
3417
 
 
3418
   if (upw->isHidden) {
 
3419
      Atom data[5] = {0, 0, 0, 0, 0};
 
3420
 
 
3421
      /*
 
3422
       * Unfortunately the _NET_WM_STATE messages only work for windows that are already
 
3423
       * mapped, i.e. not iconified or withdrawn.
 
3424
       */
 
3425
      if (!upw->isMinimized) {
 
3426
         XMapRaised(up->display, upw->clientWindow);
 
3427
      }
 
3428
 
 
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);
 
3434
 
 
3435
      upw->wantInputFocus = TRUE;
 
3436
      upw->isHidden = FALSE;
 
3437
   }
 
3438
 
 
3439
   return TRUE;
 
3440
}
 
3441
 
 
3442
 
 
3443
/*
 
3444
 *----------------------------------------------------------------------------
 
3445
 *
 
3446
 * UnityPlatformHideWindow --
 
3447
 *
 
3448
 *      Hides window. If the window is already hidden it stays hidden. Hides
 
3449
 *      maximized and minimized windows too.
 
3450
 *
 
3451
 * Results:
 
3452
 *      FALSE if the Window handle is invalid.
 
3453
 *      TRUE otherwise.
 
3454
 *
 
3455
 * Side effects:
 
3456
 *      None.
 
3457
 *
 
3458
 *----------------------------------------------------------------------------
 
3459
 */
 
3460
 
 
3461
Bool
 
3462
UnityPlatformHideWindow(UnityPlatform *up,    // IN
 
3463
                        UnityWindowId window) // IN
 
3464
{
 
3465
   UnityPlatformWindow *upw;
 
3466
 
 
3467
   ASSERT(up);
 
3468
 
 
3469
   upw = UPWindow_Lookup(up, window);
 
3470
 
 
3471
   if (!upw
 
3472
      || !upw->clientWindow) {
 
3473
      Debug("Hiding FAILED!\n");
 
3474
      return FALSE;
 
3475
   }
 
3476
 
 
3477
   if (!upw->isHidden) {
 
3478
      Atom data[5] = {0, 0, 0, 0, 0};
 
3479
 
 
3480
      upw->isHidden = TRUE;
 
3481
 
 
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);
 
3487
   }
 
3488
 
 
3489
   return TRUE;
 
3490
}
 
3491
 
 
3492
 
 
3493
/*
 
3494
 *----------------------------------------------------------------------------
 
3495
 *
 
3496
 * UnityPlatformMinimizeWindow --
 
3497
 *
 
3498
 *      Mimimizes window. If the window is already mimimized it stays minimized.
 
3499
 *
 
3500
 * Results:
 
3501
 *      FALSE if the Window handle is invalid.
 
3502
 *      TRUE otherwise.
 
3503
 *
 
3504
 * Side effects:
 
3505
 *      None.
 
3506
 *
 
3507
 *----------------------------------------------------------------------------
 
3508
 */
 
3509
 
 
3510
Bool
 
3511
UnityPlatformMinimizeWindow(UnityPlatform *up,    // IN
 
3512
                            UnityWindowId window) // IN
 
3513
{
 
3514
   UnityPlatformWindow *upw;
 
3515
 
 
3516
   ASSERT(up);
 
3517
 
 
3518
   upw = UPWindow_Lookup(up, window);
 
3519
 
 
3520
   if (!upw
 
3521
      || !upw->clientWindow) {
 
3522
      Debug("Minimizing FAILED!\n");
 
3523
      return FALSE;
 
3524
   }
 
3525
 
 
3526
   Debug("UnityPlatformMinimizeWindow(%#lx)\n", upw->toplevelWindow);
 
3527
   upw->wantInputFocus = FALSE;
 
3528
   if (!upw->isMinimized) {
 
3529
      Atom data[5] = {0, 0, 0, 0, 0};
 
3530
 
 
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;
 
3536
      } else {
 
3537
         data[1] = up->atoms._NET_WM_STATE_HIDDEN;
 
3538
      }
 
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);
 
3542
 
 
3543
      XIconifyWindow(up->display, upw->clientWindow, 0);
 
3544
   } else {
 
3545
      Debug("Window %#x is already minimized\n", window);
 
3546
   }
 
3547
 
 
3548
 
 
3549
   return TRUE;
 
3550
}
 
3551
 
 
3552
 
 
3553
/*
 
3554
 *----------------------------------------------------------------------------
 
3555
 *
 
3556
 * UnityPlatformMaximizeWindow --
 
3557
 *
 
3558
 *      Maximizes window. If the window is already maximized it will stay so.
 
3559
 *
 
3560
 * Results:
 
3561
 *      FALSE if the Window handle is invalid.
 
3562
 *      TRUE otherwise.
 
3563
 *
 
3564
 * Side effects:
 
3565
 *      None.
 
3566
 *
 
3567
 *----------------------------------------------------------------------------
 
3568
 */
 
3569
 
 
3570
Bool
 
3571
UnityPlatformMaximizeWindow(UnityPlatform *up,    // IN
 
3572
                            UnityWindowId window) // IN
 
3573
{
 
3574
   UnityPlatformWindow *upw;
 
3575
 
 
3576
   ASSERT(up);
 
3577
 
 
3578
   upw = UPWindow_Lookup(up, window);
 
3579
 
 
3580
   if (!upw
 
3581
      || !upw->clientWindow) {
 
3582
      Debug("Maximizing FAILED!\n");
 
3583
      return FALSE;
 
3584
   }
 
3585
 
 
3586
   if (!upw->isMaximized) {
 
3587
      Atom data[5] = {0, 0, 0, 0, 0};
 
3588
 
 
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);
 
3596
   }
 
3597
 
 
3598
   return TRUE;
 
3599
}
 
3600
 
 
3601
 
 
3602
/*
 
3603
 *----------------------------------------------------------------------------
 
3604
 *
 
3605
 * UnityPlatformUnmaximizeWindow --
 
3606
 *
 
3607
 *      Unmaximizes window. If the window is already unmaximized, it will stay
 
3608
 *      that way.
 
3609
 *
 
3610
 * Results:
 
3611
 *      FALSE if the Window handle is invalid.
 
3612
 *      TRUE otherwise.
 
3613
 *
 
3614
 * Side effects:
 
3615
 *      None.
 
3616
 *
 
3617
 *----------------------------------------------------------------------------
 
3618
 */
 
3619
 
 
3620
Bool
 
3621
UnityPlatformUnmaximizeWindow(UnityPlatform *up,    // IN
 
3622
                              UnityWindowId window) // IN
 
3623
{
 
3624
   UnityPlatformWindow *upw;
 
3625
 
 
3626
   ASSERT(up);
 
3627
 
 
3628
   upw = UPWindow_Lookup(up, window);
 
3629
 
 
3630
   if (!upw
 
3631
      || !upw->clientWindow) {
 
3632
      Debug("Maximizing FAILED!\n");
 
3633
      return FALSE;
 
3634
   }
 
3635
 
 
3636
   if (upw->isMaximized) {
 
3637
      Atom data[5] = {0, 0, 0, 0, 0};
 
3638
 
 
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);
 
3645
 
 
3646
      upw->isMaximized = FALSE;
 
3647
   }
 
3648
 
 
3649
   return TRUE;
 
3650
}
 
3651
 
 
3652
 
 
3653
/*
 
3654
 *------------------------------------------------------------------------------
 
3655
 *
 
3656
 * UnityPlatformSetWindowDesktop --
 
3657
 *
 
3658
 *     Move the window to the specified desktop. The desktopId is an index
 
3659
 *     into the desktop configuration array.
 
3660
 *
 
3661
 * Results:
 
3662
 *     Returns TRUE if successful, and FALSE otherwise.
 
3663
 *
 
3664
 * Side effects:
 
3665
 *     None.
 
3666
 *
 
3667
 *------------------------------------------------------------------------------
 
3668
 */
 
3669
 
 
3670
Bool
 
3671
UnityPlatformSetWindowDesktop(UnityPlatform *up,         // IN
 
3672
                              UnityWindowId windowId,    // IN
 
3673
                              UnityDesktopId desktopId)  // IN
 
3674
{
 
3675
   UnityPlatformWindow *upw;
 
3676
   uint32 guestDesktopId;
 
3677
 
 
3678
   ASSERT(up);
 
3679
 
 
3680
   upw = UPWindow_Lookup(up, windowId);
 
3681
 
 
3682
   if (!upw
 
3683
      || !upw->clientWindow) {
 
3684
      Debug("Desktop change FAILED on %#lx (perhaps it has no clientWindow)!\n",
 
3685
            upw ? upw->toplevelWindow : 0);
 
3686
      return FALSE;
 
3687
   }
 
3688
 
 
3689
   /*
 
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
 
3693
    * fixing.
 
3694
    */
 
3695
 
 
3696
   ASSERT(desktopId < (int)up->desktopInfo.numDesktops);
 
3697
   guestDesktopId = up->desktopInfo.unityDesktopToGuest[desktopId];
 
3698
 
 
3699
   UPWindow_SetEWMHDesktop(up, upw, guestDesktopId);
 
3700
 
 
3701
   return TRUE;
 
3702
}
 
3703
 
 
3704
 
 
3705
/*
 
3706
 *------------------------------------------------------------------------------
 
3707
 *
 
3708
 * UPWindow_SetEWMHDesktop --
 
3709
 *
 
3710
 *     Move the window to the specified desktop.  ewmhDesktopId corresponds
 
3711
 *     to a desktop index to be used with _NET_WM_DESKTOP.
 
3712
 *
 
3713
 * Results:
 
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.
 
3717
 *
 
3718
 * Side effects:
 
3719
 *     None.
 
3720
 *
 
3721
 *------------------------------------------------------------------------------
 
3722
 */
 
3723
 
 
3724
 
 
3725
void
 
3726
UPWindow_SetEWMHDesktop(UnityPlatform *up,               // IN
 
3727
                        UnityPlatformWindow *upw,        // IN
 
3728
                        uint32 ewmhDesktopId)            // IN
 
3729
{
 
3730
   Atom data[5] = {0, 0, 0, 0, 0};
 
3731
 
 
3732
   ASSERT(up);
 
3733
   ASSERT(upw);
 
3734
 
 
3735
   if (!upw->isViewable || upw->wantSetDesktopNumberOnUnmap) {
 
3736
     Atom currentDesktop = ewmhDesktopId; // Cast for 64-bit correctness.
 
3737
 
 
3738
     /*
 
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.
 
3744
      *
 
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
 
3750
      * be TRUE.)
 
3751
      */
 
3752
 
 
3753
     XChangeProperty(up->display, (Window)upw->clientWindow, up->atoms._NET_WM_DESKTOP,
 
3754
                     XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&currentDesktop, 1);
 
3755
   }
 
3756
 
 
3757
   data[0] = ewmhDesktopId;
 
3758
   data[1] = 2; // Indicates that this was requested by the pager/taskbar/etc.
 
3759
   UnityPlatformSendClientMessage(up,
 
3760
                                  upw->rootWindow,
 
3761
                                  upw->clientWindow,
 
3762
                                  up->atoms._NET_WM_DESKTOP,
 
3763
                                  32, 5, data);
 
3764
}
 
3765
 
 
3766
 
 
3767
/*
 
3768
 *-----------------------------------------------------------------------------
 
3769
 *
 
3770
 * UPWindowUpdateFrameExtents --
 
3771
 *
 
3772
 *      Lookup and record (cache) the _NET_FRAME_EXTENTS property.
 
3773
 *
 
3774
 * Results:
 
3775
 *      If _NET_FRAME_EXTENTS is set, upw->frameExtents may be updated.
 
3776
 *
 
3777
 * Side effects:
 
3778
 *      None.
 
3779
 *
 
3780
 *-----------------------------------------------------------------------------
 
3781
 */
 
3782
 
 
3783
static void
 
3784
UPWindowUpdateFrameExtents(UnityPlatform *up,
 
3785
                           UnityPlatformWindow *upw)
 
3786
{
 
3787
   Atom propertyType;
 
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;
 
3793
 
 
3794
   ASSERT(up);
 
3795
   ASSERT(upw);
 
3796
 
 
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;
 
3805
 
 
3806
      upw->frameExtents[0] = atomValue[0];
 
3807
      upw->frameExtents[1] = atomValue[1];
 
3808
      upw->frameExtents[2] = atomValue[2];
 
3809
      upw->frameExtents[3] = atomValue[3];
 
3810
 
 
3811
      XFree(valueReturned);
 
3812
   }
 
3813
}