~ubuntu-branches/ubuntu/quantal/open-vm-tools/quantal-201210021442

« back to all changes in this revision

Viewing changes to lib/unity/unityPlatformX11.c

  • 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-2008 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
 
 * @file unityPlatformX11.c
21
 
 *
22
 
 * Implementation of Unity for guest operating systems that use the X11 windowing
23
 
 * system. This file holds the basic things such as initialization/destruction of the
24
 
 * UnityPlatform object, overall event handling, and handling of some Unity
25
 
 * RPCs that are not window-centric.
26
 
 */
27
 
 
28
 
#include "unityX11.h"
29
 
#include "appUtil.h"
30
 
#include "region.h"
31
 
#include <sys/time.h>
32
 
 
33
 
#include <X11/extensions/Xinerama.h>
34
 
#include <X11/extensions/XTest.h>
35
 
 
36
 
typedef struct {
37
 
   Window realWindowID;
38
 
   XEvent xevent;
39
 
} UnityTemporaryEvent;
40
 
 
41
 
static UnitySpecialWindow *USWindowCreate(UnityPlatform *up,
42
 
                                           UnitySpecialEventHandler evHandler,
43
 
                                           Window *windows,
44
 
                                           int windowCount);
45
 
static void USWindowUpdate(UnityPlatform *up,
46
 
                           UnitySpecialWindow *usw,
47
 
                           Window *windows,
48
 
                           int windowCount);
49
 
static UnitySpecialWindow *USWindowLookup(UnityPlatform *up, Window window);
50
 
static void USWindowDestroy(UnityPlatform *up, UnitySpecialWindow *usw);
51
 
 
52
 
static void UnityPlatformProcessXEvent(UnityPlatform *up,
53
 
                                       const XEvent *xevent,
54
 
                                       Window realEventWindow);
55
 
static Window UnityPlatformGetRealEventWindow(UnityPlatform *up, const XEvent *xevent);
56
 
static void USRootWindowsProcessEvent(UnityPlatform *up,
57
 
                                       UnitySpecialWindow *usw,
58
 
                                       const XEvent *xevent,
59
 
                                       Window window);
60
 
static int UnityPlatformXErrorHandler(Display *dpy, XErrorEvent *xev);
61
 
static UnitySpecialWindow *UnityPlatformMakeRootWindowsObject(UnityPlatform *up);
62
 
 
63
 
static void UnityPlatformSendClientMessageFull(Display *d,
64
 
                                               Window destWindow,
65
 
                                               Window w,
66
 
                                               Atom messageType,
67
 
                                               int format,
68
 
                                               int numItems,
69
 
                                               const void *data);
70
 
static void UnityPlatformStackDnDDetWnd(UnityPlatform *up);
71
 
static void UnityPlatformDnDSendClientMessage(UnityPlatform *up,
72
 
                                              Window destWindow,
73
 
                                              Window w,
74
 
                                              Atom messageType,
75
 
                                              int format,
76
 
                                              int numItems,
77
 
                                              const void *data);
78
 
 
79
 
static Bool GetRelevantWMWindow(UnityPlatform *up,
80
 
                                UnityWindowId windowId,
81
 
                                Window *wmWindow);
82
 
static Bool SetWindowStickiness(UnityPlatform *up,
83
 
                                UnityWindowId windowId,
84
 
                                Bool wantSticky);
85
 
 
86
 
static const GuestCapabilities platformUnityCaps[] = {
87
 
   UNITY_CAP_WORK_AREA,
88
 
   UNITY_CAP_START_MENU,
89
 
   UNITY_CAP_MULTI_MON,
90
 
   UNITY_CAP_VIRTUAL_DESK,
91
 
   UNITY_CAP_STICKY_WINDOWS,
92
 
};
93
 
 
94
 
/*
95
 
 * Has to be global for UnityPlatformXErrorHandler
96
 
 */
97
 
static int unityX11ErrorCount = 0;
98
 
 
99
 
/*
100
 
 *----------------------------------------------------------------------------
101
 
 *
102
 
 * UnityPlatformIsSupported --
103
 
 *
104
 
 *      Determine whether this guest supports unity.
105
 
 *
106
 
 * Results:
107
 
 *      TRUE if the guest supports Unity
108
 
 *      FALSE otherwise
109
 
 *
110
 
 * Side effects:
111
 
 *      None
112
 
 *
113
 
 *----------------------------------------------------------------------------
114
 
 */
115
 
 
116
 
Bool
117
 
UnityPlatformIsSupported(void)
118
 
{
119
 
   Display *dpy;
120
 
   int major;
121
 
   int event_base;
122
 
   int error_base;
123
 
 
124
 
   dpy = GDK_DISPLAY();
125
 
   /*
126
 
    * Unity/X11 doesn't yet work with the new vmwgfx driver.  Until that is
127
 
    * fixed, we have to disable the feature.
128
 
    *
129
 
    * As for detecting which driver is in use, the legacy driver provides the
130
 
    * VMWARE_CTRL extension for resolution and topology operations, while the
131
 
    * new driver is instead controlled via XRandR.  If we don't find said
132
 
    * extension, then we'll assume the new driver is in use and disable Unity.
133
 
    */
134
 
   if (XQueryExtension(dpy, "VMWARE_CTRL", &major, &event_base, &error_base) ==
135
 
       False) {
136
 
      Debug("Unity is not yet supported under the vmwgfx driver.\n");
137
 
      return FALSE;
138
 
   }
139
 
 
140
 
   return TRUE;
141
 
}
142
 
 
143
 
 
144
 
/*
145
 
 *----------------------------------------------------------------------------
146
 
 *
147
 
 * UnityPlatformInit --
148
 
 *
149
 
 *      Initialize the UnityPlatform object that represents the platform-specific state.
150
 
 *
151
 
 * Results:
152
 
 *      Pointer to newly allocated UnityPlatform data.
153
 
 *
154
 
 * Side effects:
155
 
 *      No.
156
 
 *
157
 
 *----------------------------------------------------------------------------
158
 
 */
159
 
 
160
 
UnityPlatform *
161
 
UnityPlatformInit(UnityWindowTracker *tracker,                            // IN
162
 
                  UnityUpdateChannel *updateChannel,                      // IN
163
 
                  int *blockedWnd,                                        // IN, not used
164
 
                  DesktopSwitchCallbackManager *desktopSwitchCallbackMgr) // IN, not used
165
 
{
166
 
   UnityPlatform *up;
167
 
   char *displayName;
168
 
 
169
 
   ASSERT(tracker);
170
 
   ASSERT(updateChannel);
171
 
 
172
 
   Debug("UnityPlatformInit: Running\n");
173
 
 
174
 
   up = Util_SafeCalloc(1, sizeof *up);
175
 
   up->tracker = tracker;
176
 
   up->updateChannel = updateChannel;
177
 
 
178
 
   up->savedScreenSaverTimeout = -1;
179
 
 
180
 
   /*
181
 
    * Because GDK filters events heavily, and we need to do a lot of low-level X work, we
182
 
    * just open another connection to the same display.
183
 
    */
184
 
   displayName = gdk_get_display();
185
 
   up->display = XOpenDisplay(displayName);
186
 
   if (!up->display) {
187
 
      free(up);
188
 
      return NULL; // We couldn't connect to the display for some strange reason
189
 
   }
190
 
   XSetErrorHandler(UnityPlatformXErrorHandler);
191
 
   XSynchronize(up->display, TRUE); // So error counting works properly...
192
 
 
193
 
   /*
194
 
    * Certain applications, like gnome-session during logout, may grab the X
195
 
    * server before displaying a modal window.  With the server grabbed, we're
196
 
    * unable to correctly track and display windows.
197
 
    *
198
 
    * The following snippet attempts to work around this by using the XTest
199
 
    * extension's ability to make ourselves impervious to X server grabs.
200
 
    */
201
 
   {
202
 
      int dummy1;
203
 
      int dummy2;
204
 
      int major;
205
 
      int minor;
206
 
 
207
 
      if ((XTestQueryExtension(up->display, &dummy1, &dummy2,
208
 
                               &major, &minor) == True) &&
209
 
          ((major > 2) || (major == 2 && minor >= 2))) {
210
 
         if (XTestGrabControl(up->display, True) != 1) {
211
 
            Debug("XTestGrabControl failed.\n");
212
 
         }
213
 
      } else {
214
 
         Debug("XTest extension not available.\n");
215
 
      }
216
 
   }
217
 
 
218
 
   up->allWindows = HashTable_Alloc(128, HASH_INT_KEY, NULL);
219
 
   up->specialWindows = HashTable_Alloc(32, HASH_INT_KEY, NULL);
220
 
   up->desktopWindow = NULL;
221
 
   up->desktopInfo.initialDesktop = UNITY_X11_INITIALDESKTOP_UNSET;
222
 
 
223
 
   /*
224
 
    * Find the values of all the atoms
225
 
    */
226
 
#  define INIT_ATOM(x) up->atoms.x = XInternAtom(up->display, #x, False)
227
 
 
228
 
   INIT_ATOM(_NET_WM_WINDOW_TYPE);
229
 
   INIT_ATOM(_NET_WM_WINDOW_TYPE_DESKTOP);
230
 
   INIT_ATOM(_NET_WM_WINDOW_TYPE_DOCK);
231
 
   INIT_ATOM(_NET_WM_WINDOW_TYPE_TOOLBAR);
232
 
   INIT_ATOM(_NET_WM_WINDOW_TYPE_TOOLTIP);
233
 
   INIT_ATOM(_NET_WM_WINDOW_TYPE_DROPDOWN_MENU);
234
 
   INIT_ATOM(_NET_WM_WINDOW_TYPE_POPUP_MENU);
235
 
   INIT_ATOM(_NET_WM_WINDOW_TYPE_MENU);
236
 
   INIT_ATOM(_NET_WM_WINDOW_TYPE_UTILITY);
237
 
   INIT_ATOM(_NET_WM_WINDOW_TYPE_SPLASH);
238
 
   INIT_ATOM(_NET_WM_WINDOW_TYPE_DIALOG);
239
 
   INIT_ATOM(_NET_WM_WINDOW_TYPE_NORMAL);
240
 
   INIT_ATOM(_NET_WM_WINDOW_TYPE_DND);
241
 
   INIT_ATOM(_NET_WM_STATE);
242
 
   INIT_ATOM(_NET_WM_STATE_HIDDEN);
243
 
   INIT_ATOM(_NET_WM_STATE_MODAL);
244
 
   INIT_ATOM(_NET_WM_STATE_STICKY);
245
 
   INIT_ATOM(_NET_WM_STATE_MAXIMIZED_HORZ);
246
 
   INIT_ATOM(_NET_WM_STATE_MAXIMIZED_VERT);
247
 
   INIT_ATOM(_NET_WM_STATE_MINIMIZED);
248
 
   INIT_ATOM(_NET_WM_STATE_SHADED);
249
 
   INIT_ATOM(_NET_WM_STATE_SKIP_TASKBAR);
250
 
   INIT_ATOM(_NET_WM_STATE_SKIP_PAGER);
251
 
   INIT_ATOM(_NET_WM_STATE_FULLSCREEN);
252
 
   INIT_ATOM(_NET_WM_STATE_ABOVE);
253
 
   INIT_ATOM(_NET_WM_STATE_BELOW);
254
 
   INIT_ATOM(_NET_WM_STATE_DEMANDS_ATTENTION);
255
 
   INIT_ATOM(_NET_WM_USER_TIME);
256
 
   INIT_ATOM(_NET_WM_USER_TIME_WINDOW);
257
 
   INIT_ATOM(_NET_ACTIVE_WINDOW);
258
 
   INIT_ATOM(_NET_RESTACK_WINDOW);
259
 
   INIT_ATOM(_NET_WM_ICON);
260
 
   INIT_ATOM(_NET_WM_PID);
261
 
   INIT_ATOM(_NET_WM_STRUT);
262
 
   INIT_ATOM(_NET_WM_STRUT_PARTIAL);
263
 
   INIT_ATOM(_NET_MOVERESIZE_WINDOW);
264
 
   INIT_ATOM(_NET_CLOSE_WINDOW);
265
 
   INIT_ATOM(_NET_WM_ALLOWED_ACTIONS);
266
 
   INIT_ATOM(_NET_WM_ACTION_MOVE);
267
 
   INIT_ATOM(_NET_WM_ACTION_RESIZE);
268
 
   INIT_ATOM(_NET_WM_ACTION_MINIMIZE);
269
 
   INIT_ATOM(_NET_WM_ACTION_SHADE);
270
 
   INIT_ATOM(_NET_WM_ACTION_STICK);
271
 
   INIT_ATOM(_NET_WM_ACTION_MAXIMIZE_HORZ);
272
 
   INIT_ATOM(_NET_WM_ACTION_MAXIMIZE_VERT);
273
 
   INIT_ATOM(_NET_WM_ACTION_FULLSCREEN);
274
 
   INIT_ATOM(_NET_WM_ACTION_CHANGE_DESKTOP);
275
 
   INIT_ATOM(_NET_WM_ACTION_CLOSE);
276
 
   INIT_ATOM(_NET_NUMBER_OF_DESKTOPS);
277
 
   INIT_ATOM(_NET_WM_DESKTOP);
278
 
   INIT_ATOM(_NET_CURRENT_DESKTOP);
279
 
   INIT_ATOM(_NET_DESKTOP_LAYOUT);
280
 
   INIT_ATOM(_NET_SUPPORTED);
281
 
   INIT_ATOM(_NET_FRAME_EXTENTS);
282
 
   INIT_ATOM(WM_CLASS);
283
 
   INIT_ATOM(WM_CLIENT_LEADER);
284
 
   INIT_ATOM(WM_DELETE_WINDOW);
285
 
   INIT_ATOM(WM_ICON);
286
 
   INIT_ATOM(WM_NAME);
287
 
   INIT_ATOM(WM_PROTOCOLS);
288
 
   INIT_ATOM(WM_STATE);
289
 
   INIT_ATOM(WM_TRANSIENT_FOR);
290
 
   INIT_ATOM(WM_WINDOW_ROLE);
291
 
 
292
 
#  undef INIT_ATOM
293
 
 
294
 
#if defined(VM_HAVE_X11_SHAPE_EXT)
295
 
   if (!XShapeQueryExtension(up->display, &up->shapeEventBase, &up->shapeErrorBase)) {
296
 
      up->shapeEventBase = 0;
297
 
   }
298
 
#endif
299
 
 
300
 
   return up;
301
 
}
302
 
 
303
 
 
304
 
/*
305
 
 *----------------------------------------------------------------------------
306
 
 *
307
 
 * UnityPlatformCleanup --
308
 
 *
309
 
 *      One-time platform-specific cleanup code.
310
 
 *
311
 
 * Results:
312
 
 *      None.
313
 
 *
314
 
 * Side effects:
315
 
 *      None.
316
 
 *
317
 
 *----------------------------------------------------------------------------
318
 
 */
319
 
 
320
 
void
321
 
UnityPlatformCleanup(UnityPlatform *up) // IN
322
 
{
323
 
   if (!up) {
324
 
      return;
325
 
   }
326
 
 
327
 
   /*
328
 
    * Caller should've called Unity_Exit first.
329
 
    */
330
 
   ASSERT(!up->isRunning);
331
 
   ASSERT(up->glibSource == NULL);
332
 
 
333
 
   if (up->specialWindows) {
334
 
      HashTable_Free(up->specialWindows);
335
 
      up->specialWindows = NULL;
336
 
   }
337
 
   if (up->allWindows) {
338
 
      HashTable_Free(up->allWindows);
339
 
      up->allWindows = NULL;
340
 
   }
341
 
 
342
 
   if (up->display) {
343
 
      XCloseDisplay(up->display);
344
 
      up->display = NULL;
345
 
   }
346
 
 
347
 
   free(up->desktopInfo.guestDesktopToUnity);
348
 
   up->desktopInfo.guestDesktopToUnity = NULL;
349
 
   free(up->desktopInfo.unityDesktopToGuest);
350
 
   up->desktopInfo.unityDesktopToGuest = NULL;
351
 
   up->desktopWindow = NULL;
352
 
 
353
 
   free(up);
354
 
}
355
 
 
356
 
 
357
 
/*
358
 
 *----------------------------------------------------------------------------
359
 
 *
360
 
 * UnityPlatformRegisterCaps --
361
 
 *
362
 
 *      Register guest platform specific capabilities with the VMX.
363
 
 *
364
 
 * Results:
365
 
 *      None.
366
 
 *
367
 
 * Side effects:
368
 
 *      None.
369
 
 *
370
 
 *----------------------------------------------------------------------------
371
 
 */
372
 
 
373
 
void
374
 
UnityPlatformRegisterCaps(UnityPlatform *up) // IN
375
 
{
376
 
   ASSERT(up);
377
 
 
378
 
   if (!RpcOut_sendOne(NULL, NULL, UNITY_RPC_SHOW_TASKBAR_CAP " %d",
379
 
                       Unity_IsSupported() ? 1 : 0)) {
380
 
      Debug("Could not set unity show taskbar cap\n");
381
 
   }
382
 
 
383
 
   AppUtil_SendGuestCaps(platformUnityCaps, ARRAYSIZE(platformUnityCaps), TRUE);
384
 
}
385
 
 
386
 
 
387
 
/*
388
 
 *----------------------------------------------------------------------------
389
 
 *
390
 
 * UnityPlatformUnregisterCaps --
391
 
 *
392
 
 *      Unregister guest platform specific capabilities with the VMX.
393
 
 *
394
 
 * Results:
395
 
 *      None.
396
 
 *
397
 
 * Side effects:
398
 
 *      None.
399
 
 *
400
 
 *----------------------------------------------------------------------------
401
 
 */
402
 
 
403
 
void
404
 
UnityPlatformUnregisterCaps(UnityPlatform *up) // IN
405
 
{
406
 
   /*
407
 
    * This function may potentially be called during UnityPlatform destruction.
408
 
    */
409
 
   if (!up) {
410
 
      return;
411
 
   }
412
 
 
413
 
   AppUtil_SendGuestCaps(platformUnityCaps, ARRAYSIZE(platformUnityCaps), FALSE);
414
 
 
415
 
   if (!RpcOut_sendOne(NULL, NULL, UNITY_RPC_SHOW_TASKBAR_CAP " 0")) {
416
 
      Debug("Failed to unregister Unity taskbar capability\n");
417
 
   }
418
 
}
419
 
 
420
 
 
421
 
/*****************************************************************************
422
 
 * Unity main loop and event handling                                        *
423
 
 *****************************************************************************/
424
 
 
425
 
 
426
 
/*
427
 
 *-----------------------------------------------------------------------------
428
 
 *
429
 
 * USWindowCreate --
430
 
 *
431
 
 *      Creates a new UnitySpecialWindow. Ownership of the 'windows' memory is taken over
432
 
 *      by the newly created object, but that memory MUST be malloc'd...
433
 
 *
434
 
 * Results:
435
 
 *      New UnitySpecialWindow object.
436
 
 *
437
 
 * Side effects:
438
 
 *      Allocates memory.
439
 
 *
440
 
 *-----------------------------------------------------------------------------
441
 
 */
442
 
 
443
 
static UnitySpecialWindow *
444
 
USWindowCreate(UnityPlatform *up,                    // IN
445
 
               UnitySpecialEventHandler evHandler,   // IN
446
 
               Window *windows,                      // IN
447
 
               int windowCount)                      // IN
448
 
{
449
 
   UnitySpecialWindow *usw;
450
 
 
451
 
   ASSERT(up);
452
 
 
453
 
   usw = Util_SafeCalloc(1, sizeof *usw);
454
 
   usw->evHandler = evHandler;
455
 
   USWindowUpdate(up, usw, windows, windowCount);
456
 
 
457
 
   return usw;
458
 
}
459
 
 
460
 
 
461
 
/*
462
 
 *-----------------------------------------------------------------------------
463
 
 *
464
 
 * USWindowUpdate --
465
 
 *
466
 
 *      Updates this USWindow with a new list of X windows. Ownership of the 'windows'
467
 
 *      memory is taken over by this USWindow object. That memory MUST be malloc'd...
468
 
 *
469
 
 * Results:
470
 
 *      None.
471
 
 *
472
 
 * Side effects:
473
 
 *      Old window list may be destroyed and freed.
474
 
 *
475
 
 *-----------------------------------------------------------------------------
476
 
 */
477
 
 
478
 
static void
479
 
USWindowUpdate(UnityPlatform *up,       // IN
480
 
               UnitySpecialWindow *usw, // IN
481
 
               Window *windows,         // IN
482
 
               int windowCount)         // IN
483
 
{
484
 
   int i;
485
 
 
486
 
   ASSERT(up);
487
 
   ASSERT(usw);
488
 
 
489
 
   for (i = 0; i < usw->numWindows; i++) {
490
 
      XSelectInput(up->display, usw->windows[i], 0);
491
 
      HashTable_Delete(up->specialWindows, GUINT_TO_POINTER(usw->windows[i]));
492
 
   }
493
 
 
494
 
   free(usw->windows);
495
 
   usw->windows = windows;
496
 
   usw->numWindows = windowCount;
497
 
 
498
 
   for (i = 0; i < windowCount; i++) {
499
 
      HashTable_Insert(up->specialWindows, GUINT_TO_POINTER(windows[i]), usw);
500
 
   }
501
 
}
502
 
 
503
 
 
504
 
/*
505
 
 *-----------------------------------------------------------------------------
506
 
 *
507
 
 * USWindowLookup --
508
 
 *
509
 
 *      Looks up a special window
510
 
 *
511
 
 * Results:
512
 
 *      UnitySpecialWindow object
513
 
 *
514
 
 * Side effects:
515
 
 *      None.
516
 
 *
517
 
 *-----------------------------------------------------------------------------
518
 
 */
519
 
 
520
 
static UnitySpecialWindow *
521
 
USWindowLookup(UnityPlatform *up, // IN
522
 
               Window window)     // IN
523
 
{
524
 
   UnitySpecialWindow *retval = NULL;
525
 
 
526
 
   HashTable_Lookup(up->specialWindows, GUINT_TO_POINTER(window), (void **)&retval);
527
 
 
528
 
   return retval;
529
 
}
530
 
 
531
 
 
532
 
/*
533
 
 *-----------------------------------------------------------------------------
534
 
 *
535
 
 * USWindowDestroy --
536
 
 *
537
 
 *      Destroys a UnitySpecialWindow
538
 
 *
539
 
 * Results:
540
 
 *      None.
541
 
 *
542
 
 * Side effects:
543
 
 *      Memory is freed.
544
 
 *
545
 
 *-----------------------------------------------------------------------------
546
 
 */
547
 
 
548
 
static void
549
 
USWindowDestroy(UnityPlatform *up,       // IN
550
 
                UnitySpecialWindow *usw) // IN
551
 
{
552
 
   int i;
553
 
 
554
 
   ASSERT(up);
555
 
   ASSERT(usw);
556
 
 
557
 
   for (i = 0; i < usw->numWindows; i++) {
558
 
      HashTable_Delete(up->specialWindows, GUINT_TO_POINTER(usw->windows[i]));
559
 
 
560
 
      if (usw->windowsAreOwned) {
561
 
         XDestroyWindow(up->display, usw->windows[i]);
562
 
      } else {
563
 
         /*
564
 
          * For now, assume we don't have any special windows that get extension events
565
 
          * and need a call like XScreenSaverSelectInput...
566
 
          */
567
 
         XSelectInput(up->display, usw->windows[i], 0);
568
 
      }
569
 
   }
570
 
   free(usw->windows);
571
 
 
572
 
   free(usw);
573
 
}
574
 
 
575
 
 
576
 
/*
577
 
 *-----------------------------------------------------------------------------
578
 
 *
579
 
 * UnityPlatformMakeRootWindowsObject --
580
 
 *
581
 
 *      Creates a UnitySpecialWindow to handle the root windows.
582
 
 *
583
 
 * Results:
584
 
 *      UnitySpecialWindow
585
 
 *
586
 
 * Side effects:
587
 
 *      Selects for events on the root windows.
588
 
 *
589
 
 *-----------------------------------------------------------------------------
590
 
 */
591
 
 
592
 
static UnitySpecialWindow *
593
 
UnityPlatformMakeRootWindowsObject(UnityPlatform *up) // IN
594
 
{
595
 
   static const long eventMask =
596
 
      StructureNotifyMask
597
 
      | PropertyChangeMask
598
 
      | SubstructureNotifyMask
599
 
      | FocusChangeMask;
600
 
   int i;
601
 
   int numRootWindows;
602
 
   Window *rootWindows;
603
 
 
604
 
   ASSERT(up);
605
 
 
606
 
   numRootWindows = ScreenCount(up->display);
607
 
   ASSERT(numRootWindows > 0);
608
 
 
609
 
   rootWindows = Util_SafeCalloc(numRootWindows, sizeof rootWindows[0]);
610
 
   for (i = 0; i < numRootWindows; i++) {
611
 
      rootWindows[i] = RootWindow(up->display, i);
612
 
   }
613
 
 
614
 
   for (i = 0; i < numRootWindows; i++) {
615
 
      XSelectInput(up->display, rootWindows[i], eventMask);
616
 
   }
617
 
 
618
 
   return USWindowCreate(up, USRootWindowsProcessEvent, rootWindows, numRootWindows);
619
 
}
620
 
 
621
 
 
622
 
/*
623
 
 *-----------------------------------------------------------------------------
624
 
 *
625
 
 * UnityPlatformGetErrorCount --
626
 
 *
627
 
 *      Retrieves the current count of X11 errors received by Unity.
628
 
 *
629
 
 * Results:
630
 
 *      Current error count.
631
 
 *
632
 
 * Side effects:
633
 
 *      None.
634
 
 *
635
 
 *-----------------------------------------------------------------------------
636
 
 */
637
 
 
638
 
int
639
 
UnityPlatformGetErrorCount(UnityPlatform *up) // IN
640
 
{
641
 
   return unityX11ErrorCount;
642
 
}
643
 
 
644
 
 
645
 
/*
646
 
 *-----------------------------------------------------------------------------
647
 
 *
648
 
 * UnityPlatformResetErrorCount --
649
 
 *
650
 
 *      Resets the Unity X11 error count to zero.
651
 
 *
652
 
 * Results:
653
 
 *      None.
654
 
 *
655
 
 * Side effects:
656
 
 *      Error count reset.
657
 
 *
658
 
 *-----------------------------------------------------------------------------
659
 
 */
660
 
 
661
 
void
662
 
UnityPlatformResetErrorCount(UnityPlatform *up) // IN
663
 
{
664
 
   unityX11ErrorCount = 0;
665
 
}
666
 
 
667
 
 
668
 
/*
669
 
 *-----------------------------------------------------------------------------
670
 
 *
671
 
 * UnityPlatformXErrorHandler --
672
 
 *
673
 
 *      Handler for all X event errors.
674
 
 *
675
 
 * Results:
676
 
 *      1.
677
 
 *
678
 
 * Side effects:
679
 
 *      Updates our X11 error counter.
680
 
 *
681
 
 *-----------------------------------------------------------------------------
682
 
 */
683
 
 
684
 
static int
685
 
UnityPlatformXErrorHandler(Display *dpy,     // IN
686
 
                           XErrorEvent *xev) // IN
687
 
{
688
 
   char buf[1024];
689
 
   XGetErrorText(dpy, xev->error_code, buf, sizeof buf);
690
 
   Debug("> VMwareUserXErrorHandler: error %s on resource %#lx for request %d\n",
691
 
         buf, xev->resourceid, xev->request_code);
692
 
 
693
 
   unityX11ErrorCount++;
694
 
 
695
 
   return 1;
696
 
}
697
 
 
698
 
 
699
 
/*
700
 
 *-----------------------------------------------------------------------------
701
 
 *
702
 
 * UnityPlatformGetServerTime --
703
 
 *
704
 
 *      Returns an educated guess at the X server's current timestamp
705
 
 *
706
 
 * Results:
707
 
 *      X server timestamp
708
 
 *
709
 
 * Side effects:
710
 
 *      None.
711
 
 *
712
 
 *-----------------------------------------------------------------------------
713
 
 */
714
 
 
715
 
Time
716
 
UnityPlatformGetServerTime(UnityPlatform *up) // IN
717
 
{
718
 
   Time retval;
719
 
   struct timeval tv;
720
 
 
721
 
   gettimeofday(&tv, NULL);
722
 
   retval = up->eventTimeDiff + (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
723
 
 
724
 
   Debug("UserTime is guessed at %lu\n", retval);
725
 
 
726
 
   return retval;
727
 
}
728
 
 
729
 
 
730
 
/*
731
 
 *-----------------------------------------------------------------------------
732
 
 *
733
 
 * ComparePointers --
734
 
 *
735
 
 *      Compares two pointers to see whether they're equal.
736
 
 *
737
 
 * Results:
738
 
 *      -1, 0, or 1 (same meaning as strcmp return values)
739
 
 *
740
 
 * Side effects:
741
 
 *      None.
742
 
 *
743
 
 *-----------------------------------------------------------------------------
744
 
 */
745
 
 
746
 
static INLINE int
747
 
ComparePointers(const void *p1, // IN
748
 
                const void *p2) // IN
749
 
{
750
 
   /*
751
 
    * Helper function for UnityPlatformKillHelperThreads
752
 
    */
753
 
   const void * const *ptr1 = p1;
754
 
   const void * const *ptr2 = p2;
755
 
   ptrdiff_t diff = (*ptr2 - *ptr1);
756
 
 
757
 
   if (diff < 0) {
758
 
      return -1;
759
 
   } else if (diff > 0) {
760
 
      return 1;
761
 
   }
762
 
 
763
 
   return 0;
764
 
}
765
 
 
766
 
 
767
 
/*
768
 
 *----------------------------------------------------------------------------
769
 
 *
770
 
 * UnityPlatformKillHelperThreads --
771
 
 *
772
 
 *      Tears down the Unity "running" state.
773
 
 *
774
 
 * Results:
775
 
 *      None.
776
 
 *
777
 
 * Side effects:
778
 
 *      Restores system settings.
779
 
 *
780
 
 *----------------------------------------------------------------------------
781
 
 */
782
 
 
783
 
void
784
 
UnityPlatformKillHelperThreads(UnityPlatform *up) // IN
785
 
{
786
 
   UnityPlatformWindow **upwList;
787
 
   UnitySpecialWindow **uswList;
788
 
   size_t i;
789
 
   size_t numWindows;
790
 
 
791
 
   if (!up || !up->isRunning) {
792
 
      ASSERT(up->glibSource == NULL);
793
 
      return;
794
 
   }
795
 
 
796
 
   UnityX11EventTeardownSource(up);
797
 
 
798
 
   up->desktopInfo.numDesktops = 0; // Zero means host has not set virtual desktop config
799
 
   UnityX11RestoreSystemSettings(up);
800
 
 
801
 
   HashTable_ToArray(up->allWindows,
802
 
                     (void ***)&upwList,
803
 
                     &numWindows);
804
 
   qsort(upwList, numWindows, sizeof *upwList, ComparePointers);
805
 
   for (i = 0; i < numWindows; i++) {
806
 
      if (i < (numWindows - 1) && upwList[i] == upwList[i + 1]) {
807
 
         continue;
808
 
      }
809
 
 
810
 
      UPWindow_Unref(up, upwList[i]);
811
 
   }
812
 
   free(upwList);
813
 
 
814
 
   up->workAreas = NULL;
815
 
   up->rootWindows = NULL;
816
 
   HashTable_ToArray(up->specialWindows,
817
 
                     (void ***)&uswList,
818
 
                     &numWindows);
819
 
   qsort(uswList, numWindows, sizeof *uswList, ComparePointers);
820
 
   for (i = 0; i < numWindows; i++) {
821
 
      if (i < (numWindows - 1) && uswList[i] == uswList[i + 1]) {
822
 
         continue;
823
 
      }
824
 
 
825
 
      USWindowDestroy(up, uswList[i]);
826
 
   }
827
 
   free(uswList);
828
 
 
829
 
   XSync(up->display, TRUE);
830
 
   up->desktopInfo.initialDesktop = UNITY_X11_INITIALDESKTOP_UNSET;
831
 
   up->isRunning = FALSE;
832
 
 
833
 
   Debug("Leaving unity mode\n");
834
 
}
835
 
 
836
 
 
837
 
/*
838
 
 *-----------------------------------------------------------------------------
839
 
 *
840
 
 * UnityX11GetWMProtocols --
841
 
 *
842
 
 *      Updates the list of protocols supported by the window manager.
843
 
 *
844
 
 * Results:
845
 
 *      None.
846
 
 *
847
 
 * Side effects:
848
 
 *      None.
849
 
 *
850
 
 *-----------------------------------------------------------------------------
851
 
 */
852
 
 
853
 
static void
854
 
UnityX11GetWMProtocols(UnityPlatform *up) // IN
855
 
{
856
 
   Atom propertyType;
857
 
   int propertyFormat;
858
 
   unsigned long itemsReturned;
859
 
   unsigned long bytesRemaining;
860
 
   Atom *valueReturned = NULL;
861
 
 
862
 
   ASSERT(up);
863
 
 
864
 
   memset(up->wmProtocols, 0, sizeof up->wmProtocols);
865
 
   if (XGetWindowProperty(up->display, up->rootWindows->windows[0],
866
 
                          up->atoms._NET_SUPPORTED, 0,
867
 
                          1024, False, AnyPropertyType,
868
 
                          &propertyType, &propertyFormat, &itemsReturned,
869
 
                          &bytesRemaining, (unsigned char **)&valueReturned)
870
 
      != Success) {
871
 
      return;
872
 
   }
873
 
 
874
 
   if ((propertyType == XA_ATOM || propertyType == XA_CARDINAL)
875
 
       && propertyFormat == 32) {
876
 
      int i;
877
 
 
878
 
      for (i = 0; i < itemsReturned; i++) {
879
 
         if (valueReturned[i] == up->atoms._NET_MOVERESIZE_WINDOW) {
880
 
            up->wmProtocols[UNITY_X11_WM__NET_MOVERESIZE_WINDOW] = TRUE;
881
 
         } else if (valueReturned[i] == up->atoms._NET_CLOSE_WINDOW) {
882
 
            up->wmProtocols[UNITY_X11_WM__NET_CLOSE_WINDOW] = TRUE;
883
 
         } else if (valueReturned[i] == up->atoms._NET_RESTACK_WINDOW) {
884
 
            up->wmProtocols[UNITY_X11_WM__NET_RESTACK_WINDOW] = TRUE;
885
 
         } else if (valueReturned[i] == up->atoms._NET_ACTIVE_WINDOW) {
886
 
            up->wmProtocols[UNITY_X11_WM__NET_ACTIVE_WINDOW] = TRUE;
887
 
         } else if (valueReturned[i] == up->atoms._NET_WM_ACTION_MINIMIZE) {
888
 
            up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_MINIMIZE] = TRUE;
889
 
         } else if (valueReturned[i] == up->atoms._NET_WM_ACTION_CLOSE) {
890
 
            up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_CLOSE] = TRUE;
891
 
         } else if (valueReturned[i] == up->atoms._NET_WM_ACTION_SHADE) {
892
 
            up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_SHADE] = TRUE;
893
 
         } else if (valueReturned[i] == up->atoms._NET_WM_ACTION_STICK) {
894
 
            up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_STICK] = TRUE;
895
 
         } else if (valueReturned[i] == up->atoms._NET_WM_ACTION_FULLSCREEN) {
896
 
            up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_FULLSCREEN] = TRUE;
897
 
         } else if (valueReturned[i] == up->atoms._NET_WM_ACTION_MAXIMIZE_HORZ) {
898
 
            up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_MAXIMIZE_HORZ] = TRUE;
899
 
         } else if (valueReturned[i] == up->atoms._NET_WM_ACTION_MAXIMIZE_VERT) {
900
 
            up->wmProtocols[UNITY_X11_WM__NET_WM_ACTION_MAXIMIZE_VERT] = TRUE;
901
 
         } else if (valueReturned[i] == up->atoms._NET_FRAME_EXTENTS) {
902
 
            up->wmProtocols[UNITY_X11_WM__NET_FRAME_EXTENTS] = TRUE;
903
 
         } else if (valueReturned[i] == up->atoms._NET_WM_STRUT_PARTIAL) {
904
 
            up->wmProtocols[UNITY_X11_WM__NET_WM_STRUT_PARTIAL] = TRUE;
905
 
         } else if (valueReturned[i] == up->atoms._NET_WM_STATE_HIDDEN) {
906
 
            up->wmProtocols[UNITY_X11_WM__NET_WM_STATE_HIDDEN] = TRUE;
907
 
         } else if (valueReturned[i] == up->atoms._NET_WM_STATE_MINIMIZED) {
908
 
            up->wmProtocols[UNITY_X11_WM__NET_WM_STATE_MINIMIZED] = TRUE;
909
 
         }
910
 
      }
911
 
   }
912
 
 
913
 
   XFree(valueReturned);
914
 
}
915
 
 
916
 
 
917
 
/*
918
 
 *----------------------------------------------------------------------------
919
 
 *
920
 
 * UnityPlatformStartHelperThreads --
921
 
 *
922
 
 *      Start Unity running.
923
 
 *
924
 
 * Results:
925
 
 *      TRUE if successful
926
 
 *      FALSE otherwise
927
 
 *
928
 
 * Side effects:
929
 
 *      Saves and changes system settings.
930
 
 *      Starts watching for windowing system events.
931
 
 *
932
 
 *----------------------------------------------------------------------------
933
 
 */
934
 
 
935
 
Bool
936
 
UnityPlatformStartHelperThreads(UnityPlatform *up) // IN
937
 
{
938
 
   ASSERT(up);
939
 
   ASSERT(up->glibSource == NULL);
940
 
 
941
 
   XSync(up->display, TRUE);
942
 
   up->rootWindows = UnityPlatformMakeRootWindowsObject(up);
943
 
   up->isRunning = TRUE;
944
 
   up->eventTimeDiff = 0;
945
 
 
946
 
   UnityX11SaveSystemSettings(up);
947
 
 
948
 
   UnityX11GetWMProtocols(up);
949
 
 
950
 
   if (up->desktopInfo.numDesktops) {
951
 
      UnityDesktopId activeDesktop;
952
 
 
953
 
      UnityPlatformSyncDesktopConfig(up);
954
 
 
955
 
      if (up->desktopInfo.initialDesktop != UNITY_X11_INITIALDESKTOP_UNSET) {
956
 
         Debug("%s: Setting activeDesktop to initialDesktop (%u).\n", __func__,
957
 
               up->desktopInfo.initialDesktop);
958
 
         activeDesktop = up->desktopInfo.initialDesktop;
959
 
      } else {
960
 
         activeDesktop = UnityWindowTracker_GetActiveDesktop(up->tracker);
961
 
      }
962
 
      if (UnityPlatformSetDesktopActive(up, activeDesktop)) {;
963
 
         /*
964
 
          * XXX Rather than setting this directly here, should we instead wait for a
965
 
          * PropertyNotify event from the window manager to one of the root windows?
966
 
          * Doing so may be safer in that it confirms that our request was honored by
967
 
          * the window manager.
968
 
          */
969
 
         UnityWindowTracker_ChangeActiveDesktop(up->tracker, activeDesktop);
970
 
      }
971
 
   }
972
 
 
973
 
   if (up->needWorkAreas) {
974
 
      /*
975
 
       * UNEXPECTED: The host called SetDesktopWorkArea before entering Unity mode, so we
976
 
       * need to go back and apply the remembered work area info.
977
 
       */
978
 
 
979
 
      UnityPlatformSetDesktopWorkAreas(up, up->needWorkAreas, up->needNumWorkAreas);
980
 
      free(up->needWorkAreas);
981
 
      up->needWorkAreas = NULL;
982
 
   }
983
 
 
984
 
   /*
985
 
    * Set up a callback in the glib main loop to listen for incoming X events on the
986
 
    * unity display connection.
987
 
    */
988
 
   UnityX11EventEstablishSource(up);
989
 
 
990
 
   return TRUE;
991
 
}
992
 
 
993
 
 
994
 
/*
995
 
 *----------------------------------------------------------------------------
996
 
 *
997
 
 * UnityPlatformIsUnityRunning --
998
 
 *
999
 
 *      Check to see if we are still in the unity mode.
1000
 
 *
1001
 
 * Results:
1002
 
 *      TRUE if we are in Unity mode
1003
 
 *      FALSE otherwise.
1004
 
 *
1005
 
 * Side effects:
1006
 
 *      None.
1007
 
 *
1008
 
 *----------------------------------------------------------------------------
1009
 
 */
1010
 
 
1011
 
Bool
1012
 
UnityPlatformIsUnityRunning(UnityPlatform *up) // IN
1013
 
{
1014
 
   ASSERT(up);
1015
 
 
1016
 
   return up->isRunning;
1017
 
}
1018
 
 
1019
 
 
1020
 
/*
1021
 
 *----------------------------------------------------------------------------
1022
 
 *
1023
 
 * UnityPlatformLock --
1024
 
 *
1025
 
 *      Does nothing - our implementation is not threaded.
1026
 
 *
1027
 
 * Results:
1028
 
 *      None.
1029
 
 *
1030
 
 * Side effects:
1031
 
 *      None (really).
1032
 
 *
1033
 
 *----------------------------------------------------------------------------
1034
 
 */
1035
 
 
1036
 
void
1037
 
UnityPlatformLock(UnityPlatform *up) // IN
1038
 
{
1039
 
}
1040
 
 
1041
 
 
1042
 
/*
1043
 
 *----------------------------------------------------------------------------
1044
 
 *
1045
 
 * UnityPlatformUnlock --
1046
 
 *
1047
 
 *      Does nothing - our implementation is not threaded.
1048
 
 *
1049
 
 * Results:
1050
 
 *      None.
1051
 
 *
1052
 
 * Side effects:
1053
 
 *      None.
1054
 
 *
1055
 
 *----------------------------------------------------------------------------
1056
 
 */
1057
 
 
1058
 
void
1059
 
UnityPlatformUnlock(UnityPlatform *up) // IN
1060
 
{
1061
 
}
1062
 
 
1063
 
 
1064
 
/*
1065
 
 *----------------------------------------------------------------------------
1066
 
 *
1067
 
 * UnityPlatformUpdateZOrder --
1068
 
 *
1069
 
 *      Push the Z-Order of all windows into the window tracker.
1070
 
 *
1071
 
 * Results:
1072
 
 *      None.
1073
 
 *
1074
 
 * Side effects:
1075
 
 *      None.
1076
 
 *
1077
 
 *----------------------------------------------------------------------------
1078
 
 */
1079
 
 
1080
 
static void
1081
 
UnityPlatformUpdateZOrder(UnityPlatform *up) // IN
1082
 
{
1083
 
   UnityWindowId *elements;
1084
 
   size_t numElements;
1085
 
   UnityPlatformWindow *curWindow;
1086
 
 
1087
 
   ASSERT(up);
1088
 
   if (!up->stackingChanged) {
1089
 
      return;
1090
 
   }
1091
 
 
1092
 
   elements = alloca(UNITY_MAX_WINDOWS * sizeof elements[0]);
1093
 
   for (numElements = 0, curWindow = up->topWindow;
1094
 
        curWindow; curWindow = curWindow->lowerWindow) {
1095
 
      if (curWindow->isRelevant) {
1096
 
         elements[numElements++] = curWindow->toplevelWindow;
1097
 
      }
1098
 
   }
1099
 
 
1100
 
   UnityWindowTracker_SetZOrder(up->tracker,
1101
 
                                elements,
1102
 
                                numElements);
1103
 
   up->stackingChanged = FALSE;
1104
 
}
1105
 
 
1106
 
 
1107
 
/*
1108
 
 *----------------------------------------------------------------------------
1109
 
 *
1110
 
 * UnityPlatformUpdateWindowState --
1111
 
 *
1112
 
 *      Walk through /all/ the windows on the guest, pushing everything we know about
1113
 
 *      them into the unity window tracker.
1114
 
 *
1115
 
 * Results:
1116
 
 *      TRUE indicating we need help from the common code to generate
1117
 
 *      remove window events (see unity.c)
1118
 
 *
1119
 
 * Side effects:
1120
 
 *      None
1121
 
 *
1122
 
 *----------------------------------------------------------------------------
1123
 
 */
1124
 
 
1125
 
Bool
1126
 
UnityPlatformUpdateWindowState(UnityPlatform *up,               // IN
1127
 
                               UnityWindowTracker *tracker)     // IN
1128
 
{
1129
 
   int curRoot;
1130
 
   Window lowerWindow = None;
1131
 
 
1132
 
   if (!up || !up->rootWindows) {
1133
 
      Debug("BUG: UpdateWindowState was called before we are fully in Unity mode...\n");
1134
 
      return FALSE;
1135
 
   }
1136
 
 
1137
 
   for (curRoot = 0; curRoot < up->rootWindows->numWindows; curRoot++) {
1138
 
      int i;
1139
 
      Window dummyWin;
1140
 
      Window *children;
1141
 
      unsigned int numChildren;
1142
 
 
1143
 
      XQueryTree(up->display, up->rootWindows->windows[curRoot],
1144
 
                 &dummyWin, &dummyWin, &children, &numChildren);
1145
 
 
1146
 
      for (i = 0; i < numChildren; i++) {
1147
 
         UnityPlatformWindow *upw;
1148
 
 
1149
 
         if (!HashTable_Lookup(up->allWindows,
1150
 
                               GUINT_TO_POINTER(children[i]),
1151
 
                               (void **)&upw)) {
1152
 
            upw = UPWindow_Create(up, children[i]);
1153
 
            if (!upw) {
1154
 
               continue; // Window may have disappeared since the XQueryTree
1155
 
            }
1156
 
            UPWindow_CheckRelevance(up, upw, NULL);
1157
 
            UPWindow_Restack(up, upw, lowerWindow);
1158
 
         }
1159
 
 
1160
 
         lowerWindow = upw->toplevelWindow;
1161
 
      }
1162
 
 
1163
 
      XFree(children);
1164
 
   }
1165
 
 
1166
 
   UnityPlatformUpdateZOrder(up);
1167
 
   /*
1168
 
    * up is not populated with the window layout structure when
1169
 
    * UnityPlatformUpdateDnDDetWnd is intially called.
1170
 
    */
1171
 
   UnityPlatformStackDnDDetWnd(up);
1172
 
 
1173
 
   if (up->needTaskbarSetting) {
1174
 
      up->needTaskbarSetting = FALSE;
1175
 
      /*
1176
 
       * This is called in this seemingly random spot to make sure that the taskbar
1177
 
       * visibility is properly set once we have a full picture of the windowing system
1178
 
       * state. Although the routine is called prior to this by SaveSystemSettings(), the
1179
 
       * up->allWindows hash table is not complete until this point, which occurs at a
1180
 
       * random time of the host's choosing.
1181
 
       */
1182
 
      UnityPlatformSetTaskbarVisible(up, up->currentSettings[UNITY_UI_TASKBAR_VISIBLE]);
1183
 
   }
1184
 
 
1185
 
   return FALSE;
1186
 
}
1187
 
 
1188
 
 
1189
 
/*
1190
 
 *-----------------------------------------------------------------------------
1191
 
 *
1192
 
 * UnityX11HandleEvents --
1193
 
 *
1194
 
 *      Handle incoming events
1195
 
 *
1196
 
 * Results:
1197
 
 *      TRUE if the main loop should continue watching for events from the display.
1198
 
 *
1199
 
 * Side effects:
1200
 
 *      Events read from the X display and processed.
1201
 
 *
1202
 
 *-----------------------------------------------------------------------------
1203
 
 */
1204
 
 
1205
 
gboolean
1206
 
UnityX11HandleEvents(gpointer data) // IN
1207
 
{
1208
 
   UnityPlatform *up = (UnityPlatform *) data;
1209
 
   GList *incomingEvents = NULL;
1210
 
   Bool restackDetWnd = FALSE;
1211
 
 
1212
 
   ASSERT(up);
1213
 
   ASSERT(up->isRunning);
1214
 
 
1215
 
   Debug("Starting unity event handling\n");
1216
 
   while (XEventsQueued(up->display, QueuedAfterFlush)) {
1217
 
      /*
1218
 
       * This outer loop is here to make sure we really process all available events
1219
 
       * before returning.
1220
 
       */
1221
 
 
1222
 
      while (XEventsQueued(up->display, QueuedAlready)) {
1223
 
         UnityTemporaryEvent *ev;
1224
 
 
1225
 
         ev = Util_SafeCalloc(1, sizeof *ev);
1226
 
         XNextEvent(up->display, &ev->xevent);
1227
 
         ev->realWindowID = UnityPlatformGetRealEventWindow(up, &ev->xevent);
1228
 
 
1229
 
         /*
1230
 
          * Restack dnd detection window when either
1231
 
          *   1.  the desktop window may overlap detection window, or
1232
 
          *   2.  a window is inserted directly above the desktop (and therefore
1233
 
          *       below the DND window).
1234
 
          */
1235
 
         if (up->desktopWindow &&
1236
 
             ev->xevent.type == ConfigureNotify &&
1237
 
             (up->desktopWindow->toplevelWindow == ev->realWindowID ||
1238
 
              up->desktopWindow->toplevelWindow == ev->xevent.xconfigure.above)) {
1239
 
            restackDetWnd = TRUE;
1240
 
         }
1241
 
 
1242
 
         if (ev->xevent.type == DestroyNotify) {
1243
 
            /*
1244
 
             * Unfortunately, X's event-driven model has an inherent race condition for
1245
 
             * parties that are observing events on windows that are controlled by other
1246
 
             * applications. Basically, if we're processing an event on a window, that
1247
 
             * window may have already been destroyed, and there doesn't seem to really
1248
 
             * be a way to detect this. We just have to try to cut down the probability
1249
 
             * of those as much as possible, by discarding any events on a window if
1250
 
             * they're immediately followed by a DestroyNotify on the same window...
1251
 
             */
1252
 
            GList *curItem;
1253
 
            GList *nextItem = NULL;
1254
 
 
1255
 
            for (curItem = incomingEvents; curItem; curItem = nextItem) {
1256
 
               UnityTemporaryEvent *otherEvent = curItem->data;
1257
 
               nextItem = curItem->next;
1258
 
 
1259
 
               if (otherEvent->realWindowID == ev->realWindowID) {
1260
 
                  free(curItem->data);
1261
 
                  incomingEvents = g_list_remove_link(incomingEvents, curItem);
1262
 
               }
1263
 
            }
1264
 
         }
1265
 
 
1266
 
         incomingEvents = g_list_append(incomingEvents, ev);
1267
 
      }
1268
 
 
1269
 
      while (incomingEvents) {
1270
 
         GList *nextItem;
1271
 
         UnityTemporaryEvent *tempEvent = incomingEvents->data;
1272
 
 
1273
 
         UnityPlatformProcessXEvent(up, &tempEvent->xevent, tempEvent->realWindowID);
1274
 
 
1275
 
         nextItem = incomingEvents->next;
1276
 
         free(incomingEvents->data);
1277
 
         g_list_free_1(incomingEvents);
1278
 
         incomingEvents = nextItem;
1279
 
      }
1280
 
 
1281
 
      if (restackDetWnd) {
1282
 
         UnityPlatformStackDnDDetWnd(up);
1283
 
      }
1284
 
      UnityPlatformUpdateZOrder(up);
1285
 
      UnityPlatformDoUpdate(up, TRUE);
1286
 
   }
1287
 
 
1288
 
   return TRUE;
1289
 
}
1290
 
 
1291
 
 
1292
 
/*
1293
 
 *-----------------------------------------------------------------------------
1294
 
 *
1295
 
 * UnityPlatformGetEventString --
1296
 
 *
1297
 
 *      Allows stringifying events for debugging purposes
1298
 
 *
1299
 
 * Results:
1300
 
 *      A stringified version of the event name. It's a static value - do not free this.
1301
 
 *
1302
 
 * Side effects:
1303
 
 *      None.
1304
 
 *-----------------------------------------------------------------------------
1305
 
 */
1306
 
 
1307
 
const char *
1308
 
UnityPlatformGetEventString(UnityPlatform *up, // IN
1309
 
                            int type)          // IN
1310
 
{
1311
 
#if defined(VM_HAVE_X11_SHAPE_EXT)
1312
 
   if (up->shapeEventBase
1313
 
       && type == (up->shapeEventBase + ShapeNotify)) {
1314
 
      return "ShapeNotify";
1315
 
   }
1316
 
#endif
1317
 
 
1318
 
   switch (type) {
1319
 
   case KeyPress: return "KeyPress";
1320
 
   case KeyRelease: return "KeyRelease";
1321
 
   case ButtonPress: return "ButtonPress";
1322
 
   case ButtonRelease: return "ButtonRelease";
1323
 
   case MotionNotify: return "MotionNotify";
1324
 
   case EnterNotify: return "EnterNotify";
1325
 
   case LeaveNotify: return "LeaveNotify";
1326
 
   case FocusIn: return "FocusIn";
1327
 
   case FocusOut: return "FocusOut";
1328
 
   case KeymapNotify: return "KeymapNotify";
1329
 
   case Expose: return "Expose";
1330
 
   case GraphicsExpose: return "GraphicsExpose";
1331
 
   case NoExpose: return "NoExpose";
1332
 
   case VisibilityNotify: return "VisibilityNotify";
1333
 
   case CreateNotify: return "CreateNotify";
1334
 
   case DestroyNotify: return "DestroyNotify";
1335
 
   case UnmapNotify: return "UnmapNotify";
1336
 
   case MapNotify: return "MapNotify";
1337
 
   case MapRequest: return "MapRequest";
1338
 
   case ReparentNotify: return "ReparentNotify";
1339
 
   case ConfigureNotify: return "ConfigureNotify";
1340
 
   case ConfigureRequest: return "ConfigureRequest";
1341
 
   case GravityNotify: return "GravityNotify";
1342
 
   case ResizeRequest: return "ResizeRequest";
1343
 
   case CirculateNotify: return "CirculateNotify";
1344
 
   case CirculateRequest: return "CirculateRequest";
1345
 
   case PropertyNotify: return "PropertyNotify";
1346
 
   case SelectionClear: return "SelectionClear";
1347
 
   case SelectionRequest: return "SelectionRequest";
1348
 
   case SelectionNotify: return "SelectionNotify";
1349
 
   case ColormapNotify: return "ColormapNotify";
1350
 
   case ClientMessage: return "ClientMessage";
1351
 
   case MappingNotify: return "MappingNotify";
1352
 
   default: return "<Unknown>";
1353
 
   }
1354
 
}
1355
 
 
1356
 
 
1357
 
/*
1358
 
 *-----------------------------------------------------------------------------
1359
 
 *
1360
 
 * UnityPlatformGetRealEventWindow --
1361
 
 *
1362
 
 *      For debugging purposes, retrieves the window that the event happened on (as
1363
 
 *      opposed to the window the event was sent to)
1364
 
 *
1365
 
 * Results:
1366
 
 *      The window that the event actually happened on.
1367
 
 *
1368
 
 * Side effects:
1369
 
 *      None.
1370
 
 *
1371
 
 *-----------------------------------------------------------------------------
1372
 
 */
1373
 
 
1374
 
static Window
1375
 
UnityPlatformGetRealEventWindow(UnityPlatform *up,    // IN
1376
 
                                const XEvent *xevent) // IN
1377
 
{
1378
 
#if defined(VM_HAVE_X11_SHAPE_EXT)
1379
 
   if (up->shapeEventBase
1380
 
       && xevent->type == (up->shapeEventBase + ShapeNotify)) {
1381
 
      XShapeEvent *sev = (XShapeEvent *) xevent;
1382
 
 
1383
 
      return sev->window;
1384
 
   }
1385
 
#endif
1386
 
 
1387
 
   switch (xevent->type) {
1388
 
   case CreateNotify:
1389
 
      return xevent->xcreatewindow.window;
1390
 
 
1391
 
   case DestroyNotify:
1392
 
      return xevent->xdestroywindow.window;
1393
 
 
1394
 
   case MapNotify:
1395
 
      return xevent->xmap.window;
1396
 
 
1397
 
   case UnmapNotify:
1398
 
      return xevent->xunmap.window;
1399
 
 
1400
 
   case ReparentNotify:
1401
 
      return xevent->xreparent.window;
1402
 
 
1403
 
   case ConfigureNotify:
1404
 
      return xevent->xconfigure.window;
1405
 
 
1406
 
   case CirculateNotify:
1407
 
      return xevent->xcirculate.window;
1408
 
 
1409
 
   case PropertyNotify:
1410
 
      return xevent->xproperty.window;
1411
 
 
1412
 
   case FocusIn:
1413
 
   case FocusOut:
1414
 
      return xevent->xfocus.window;
1415
 
 
1416
 
   default:
1417
 
      return xevent->xany.window;
1418
 
 
1419
 
   }
1420
 
}
1421
 
 
1422
 
 
1423
 
/*
1424
 
 *-----------------------------------------------------------------------------
1425
 
 *
1426
 
 * UnityPlatformUpdateEventTimeDiff --
1427
 
 *
1428
 
 *      Updates our idea of the difference between X server time and our local time.
1429
 
 *
1430
 
 * Results:
1431
 
 *      None.
1432
 
 *
1433
 
 * Side effects:
1434
 
 *      Updated event time diff.
1435
 
 *
1436
 
 *-----------------------------------------------------------------------------
1437
 
 */
1438
 
 
1439
 
static void
1440
 
UnityPlatformUpdateEventTimeDiff(UnityPlatform *up,    // IN
1441
 
                                 const XEvent *xevent) // IN
1442
 
{
1443
 
   Time serverTime;
1444
 
   Time localTime;
1445
 
   struct timeval localTv;
1446
 
 
1447
 
   switch (xevent->type) {
1448
 
   case KeyPress:
1449
 
   case KeyRelease:
1450
 
      serverTime = xevent->xkey.time;
1451
 
      break;
1452
 
   case ButtonPress:
1453
 
   case ButtonRelease:
1454
 
      serverTime = xevent->xbutton.time;
1455
 
      break;
1456
 
   case MotionNotify:
1457
 
      serverTime = xevent->xmotion.time;
1458
 
      break;
1459
 
   case EnterNotify:
1460
 
   case LeaveNotify:
1461
 
      serverTime = xevent->xcrossing.time;
1462
 
      break;
1463
 
   case PropertyNotify:
1464
 
      serverTime = xevent->xproperty.time;
1465
 
      break;
1466
 
   case SelectionClear:
1467
 
      serverTime = xevent->xselectionclear.time;
1468
 
      break;
1469
 
   case SelectionRequest:
1470
 
      serverTime = xevent->xselectionrequest.time;
1471
 
      break;
1472
 
   case SelectionNotify:
1473
 
      serverTime = xevent->xselection.time;
1474
 
      break;
1475
 
 
1476
 
   default:
1477
 
      return;
1478
 
   }
1479
 
 
1480
 
   gettimeofday(&localTv, NULL);
1481
 
   localTime = (localTv.tv_sec * 1000) + (localTv.tv_usec / 1000); // Convert to ms
1482
 
   up->eventTimeDiff = serverTime - localTime;
1483
 
}
1484
 
 
1485
 
 
1486
 
/*
1487
 
 *-----------------------------------------------------------------------------
1488
 
 *
1489
 
 * UnityPlatformProcessXEvent --
1490
 
 *
1491
 
 *      Processes an incoming X event.
1492
 
 *
1493
 
 * Results:
1494
 
 *      None.
1495
 
 *
1496
 
 * Side effects:
1497
 
 *      May create or destroy UnityPlatformWindow objects.
1498
 
 *
1499
 
 *-----------------------------------------------------------------------------
1500
 
 */
1501
 
 
1502
 
static void
1503
 
UnityPlatformProcessXEvent(UnityPlatform *up,      // IN
1504
 
                           const XEvent *xevent,   // IN
1505
 
                           Window realEventWindow) // IN
1506
 
{
1507
 
   UnityPlatformWindow *upw = NULL;
1508
 
   const char *eventName;
1509
 
 
1510
 
   ASSERT(up);
1511
 
   ASSERT(xevent);
1512
 
 
1513
 
   UnityPlatformUpdateEventTimeDiff(up, xevent);
1514
 
 
1515
 
   eventName = UnityPlatformGetEventString(up, xevent->type);
1516
 
   upw = UPWindow_Lookup(up, realEventWindow);
1517
 
   if (!upw) {
1518
 
      UnitySpecialWindow *usw = USWindowLookup(up, realEventWindow);
1519
 
      if (usw) {
1520
 
         if (usw->evHandler) {
1521
 
            usw->evHandler(up, usw, xevent, realEventWindow);
1522
 
         }
1523
 
 
1524
 
         return;
1525
 
      } else if (xevent->type == CreateNotify) {
1526
 
         /* Ignore decoration widgets.  They'll be reparented later. */
1527
 
         if (UnityX11Util_IsWindowDecorationWidget(up, realEventWindow)) {
1528
 
            Debug("%s: Window %#lx is a decoration widget.  Ignore it.\n",
1529
 
                  __func__, realEventWindow);
1530
 
            return;
1531
 
         }
1532
 
 
1533
 
         /*
1534
 
          * It may be a new window that we don't know about yet. Let's create an object
1535
 
          * to track it.
1536
 
          */
1537
 
         upw = UPWindow_Create(up, realEventWindow);
1538
 
         if (upw) {
1539
 
            UPWindow_CheckRelevance(up, upw, NULL);
1540
 
         } else {
1541
 
            Debug("UnityX11ThreadProcessEvent BOMBED:"
1542
 
                  " %s on window %#lx (reported to %#lx)\n",
1543
 
                  eventName, realEventWindow, xevent->xany.window);
1544
 
         }
1545
 
      } else {
1546
 
         /*
1547
 
          * If we use them on non-CreateNotify events, the above lines of code wind up
1548
 
          * trying to create objects for crazy windows that don't exist...
1549
 
          */
1550
 
         Debug("Ignoring %s event on unknown window %#lx (reported to %#lx)\n",
1551
 
               eventName, realEventWindow, xevent->xany.window);
1552
 
      }
1553
 
   }
1554
 
 
1555
 
   if (upw) {
1556
 
      UPWindow_ProcessEvent(up, upw, realEventWindow, xevent);
1557
 
      if (upw->deleteWhenSafe) {
1558
 
         Debug("%s: refs %u, deleteWhenSafe %u\n", __func__, upw->refs,
1559
 
               upw->deleteWhenSafe);
1560
 
         UPWindow_Unref(up, upw);
1561
 
      }
1562
 
   }
1563
 
}
1564
 
 
1565
 
 
1566
 
/*
1567
 
 *-----------------------------------------------------------------------------
1568
 
 *
1569
 
 * UnityPlatformIsRootWindow --
1570
 
 *
1571
 
 *      Checks whether a given window ID is the root window. Necessary because each
1572
 
 *      screen has a separate root window, which makes checking a little more complicated
1573
 
 *      than ==.
1574
 
 *
1575
 
 * Results:
1576
 
 *      TRUE if the given window is a root window, FALSE otherwise.
1577
 
 *
1578
 
 * Side effects:
1579
 
 *      None.
1580
 
 *
1581
 
 *-----------------------------------------------------------------------------
1582
 
 */
1583
 
 
1584
 
Bool
1585
 
UnityPlatformIsRootWindow(UnityPlatform *up, // IN
1586
 
                          Window window)     // IN
1587
 
{
1588
 
   ASSERT(up);
1589
 
 
1590
 
   return (USWindowLookup(up, window) == up->rootWindows);
1591
 
}
1592
 
 
1593
 
 
1594
 
/*
1595
 
 *-----------------------------------------------------------------------------
1596
 
 *
1597
 
 * UnityX11SetCurrentDesktop --
1598
 
 *
1599
 
 *      Sets the active virtual desktop.
1600
 
 *
1601
 
 * Results:
1602
 
 *      None.
1603
 
 *
1604
 
 * Side effects:
1605
 
 *      Changes the virtual desktop.
1606
 
 *
1607
 
 *-----------------------------------------------------------------------------
1608
 
 */
1609
 
 
1610
 
void
1611
 
UnityX11SetCurrentDesktop(UnityPlatform *up,     // IN
1612
 
                          uint32 currentDesktop) // IN: guest-side desktop ID
1613
 
{
1614
 
   Atom data[5] = {0,0,0,0,0};
1615
 
 
1616
 
   ASSERT(up);
1617
 
   ASSERT(up->rootWindows->windows);
1618
 
 
1619
 
   up->desktopInfo.currentDesktop = currentDesktop;
1620
 
   data[0] = currentDesktop;
1621
 
   data[1] = UnityPlatformGetServerTime(up);
1622
 
   UnityPlatformSendClientMessage(up,
1623
 
                                  up->rootWindows->windows[0],
1624
 
                                  up->rootWindows->windows[0],
1625
 
                                  up->atoms._NET_CURRENT_DESKTOP,
1626
 
                                  32, 5, data);
1627
 
}
1628
 
 
1629
 
 
1630
 
/*
1631
 
 *-----------------------------------------------------------------------------
1632
 
 *
1633
 
 * UnityX11GetCurrentDesktop --
1634
 
 *
1635
 
 *      Gets the active virtual desktop.
1636
 
 *
1637
 
 * Results:
1638
 
 *      The active virtual desktop. If it cannot be retrieved for any reason, a
1639
 
 *      reasonable default of '0' will be returned.
1640
 
 *
1641
 
 * Side effects:
1642
 
 *      None.
1643
 
 *
1644
 
 *-----------------------------------------------------------------------------
1645
 
 */
1646
 
 
1647
 
uint32
1648
 
UnityX11GetCurrentDesktop(UnityPlatform *up) // IN
1649
 
{
1650
 
   Atom propertyType;
1651
 
   int propertyFormat;
1652
 
   unsigned long itemsReturned;
1653
 
   unsigned long bytesRemaining;
1654
 
   Atom *valueReturned;
1655
 
   uint32 currentDesktop;
1656
 
 
1657
 
   ASSERT(up);
1658
 
   ASSERT(up->rootWindows);
1659
 
 
1660
 
   if (XGetWindowProperty(up->display, up->rootWindows->windows[0],
1661
 
                          up->atoms._NET_CURRENT_DESKTOP, 0,
1662
 
                          1024, False, AnyPropertyType,
1663
 
                          &propertyType, &propertyFormat, &itemsReturned,
1664
 
                          &bytesRemaining, (unsigned char **)&valueReturned)
1665
 
       == Success
1666
 
       && propertyType == XA_CARDINAL
1667
 
       && propertyFormat == 32) {
1668
 
      ASSERT(itemsReturned == 1);
1669
 
 
1670
 
      currentDesktop = valueReturned[0];
1671
 
   } else {
1672
 
      currentDesktop = 0;
1673
 
   }
1674
 
   XFree(valueReturned);
1675
 
 
1676
 
   return currentDesktop;
1677
 
}
1678
 
 
1679
 
 
1680
 
/*
1681
 
 *-----------------------------------------------------------------------------
1682
 
 *
1683
 
 * USRootWindowsUpdateCurrentDesktop --
1684
 
 *
1685
 
 *      Looks at the root window to figure out the current desktop
1686
 
 *
1687
 
 * Results:
1688
 
 *      None.
1689
 
 *
1690
 
 * Side effects:
1691
 
 *      Updates UnityWindowTracker.
1692
 
 *
1693
 
 *-----------------------------------------------------------------------------
1694
 
 */
1695
 
 
1696
 
static void
1697
 
USRootWindowsUpdateCurrentDesktop(UnityPlatform *up,       // IN
1698
 
                                  UnitySpecialWindow *usw, // IN
1699
 
                                  Window window)           // IN
1700
 
{
1701
 
   uint32 currentDesktop;
1702
 
   UnityDesktopId unityDesktop;
1703
 
 
1704
 
   /*
1705
 
    * XXX right now this is going to break if there are multiple screens in the guest,
1706
 
    * since each one can have an independant 'current' desktop...
1707
 
    */
1708
 
 
1709
 
   ASSERT(up);
1710
 
   currentDesktop = UnityX11GetCurrentDesktop(up);
1711
 
 
1712
 
   if (currentDesktop >= up->desktopInfo.numDesktops) {
1713
 
      Warning("Active desktop is out of range for some strange reason\n");
1714
 
      currentDesktop = 0;
1715
 
   }
1716
 
 
1717
 
   unityDesktop = up->desktopInfo.guestDesktopToUnity[currentDesktop];
1718
 
   Debug("%s: currentDesktop %u, unityDesktop %u\n", __func__, currentDesktop, unityDesktop);
1719
 
   UnityWindowTracker_ChangeActiveDesktop(up->tracker, unityDesktop);
1720
 
}
1721
 
 
1722
 
 
1723
 
/*
1724
 
 *-----------------------------------------------------------------------------
1725
 
 *
1726
 
 * USRootWindowsProcessEvent --
1727
 
 *
1728
 
 *      Processes an event that occurred on one of the root windows.
1729
 
 *
1730
 
 * Results:
1731
 
 *      None.
1732
 
 *
1733
 
 * Side effects:
1734
 
 *      None.
1735
 
 *
1736
 
 *-----------------------------------------------------------------------------
1737
 
 */
1738
 
 
1739
 
static void
1740
 
USRootWindowsProcessEvent(UnityPlatform *up,       // IN
1741
 
                          UnitySpecialWindow *usw, // IN
1742
 
                          const XEvent *xevent,    // IN
1743
 
                          Window window)           // IN
1744
 
{
1745
 
 
1746
 
   /*
1747
 
    * XXX Do we need to handle situations where the root window changes size? Any other
1748
 
    * properties?
1749
 
    */
1750
 
   switch (xevent->type) {
1751
 
   case PropertyNotify:
1752
 
      if (xevent->xproperty.atom == up->atoms._NET_CURRENT_DESKTOP) {
1753
 
         USRootWindowsUpdateCurrentDesktop(up, usw, window);
1754
 
      } else if (xevent->xproperty.atom == up->atoms._NET_NUMBER_OF_DESKTOPS) {
1755
 
         size_t numDesktops;
1756
 
 
1757
 
         numDesktops = UnityPlatformGetNumVirtualDesktops(up);
1758
 
         if (numDesktops != up->desktopInfo.numDesktops) {
1759
 
            UnityPlatformSyncDesktopConfig(up);
1760
 
         }
1761
 
      } else if (xevent->xproperty.atom == up->atoms._NET_DESKTOP_LAYOUT) {
1762
 
         Atom layoutData[4];
1763
 
 
1764
 
         UnityPlatformGetVirtualDesktopLayout(up, layoutData);
1765
 
         if (memcmp(layoutData, up->desktopInfo.layoutData, sizeof layoutData) != 0) {
1766
 
            UnityPlatformSyncDesktopConfig(up);
1767
 
         }
1768
 
      }
1769
 
      break;
1770
 
   }
1771
 
}
1772
 
 
1773
 
 
1774
 
/*
1775
 
 *-----------------------------------------------------------------------------
1776
 
 *
1777
 
 * UnityPlatformWMProtocolSupported --
1778
 
 *
1779
 
 *      Returns whether the window manager supports a particular protocol.
1780
 
 *
1781
 
 * Results:
1782
 
 *      TRUE if the protocol is supported, FALSE otherwise.
1783
 
 *
1784
 
 * Side effects:
1785
 
 *      None.
1786
 
 *
1787
 
 *-----------------------------------------------------------------------------
1788
 
 */
1789
 
 
1790
 
Bool
1791
 
UnityPlatformWMProtocolSupported(UnityPlatform *up,         // IN
1792
 
                                 UnityX11WMProtocol proto)  // IN
1793
 
{
1794
 
   ASSERT(up);
1795
 
   ASSERT(proto < UNITY_X11_MAX_WM_PROTOCOLS);
1796
 
 
1797
 
   return up->wmProtocols[proto];
1798
 
}
1799
 
 
1800
 
 
1801
 
/*
1802
 
 *----------------------------------------------------------------------------
1803
 
 *
1804
 
 * UnityPlatformSendClientMessageFull --
1805
 
 *
1806
 
 *      Sends an XSendEvent.
1807
 
 *
1808
 
 * Results:
1809
 
 *
1810
 
 * Side effects:
1811
 
 *
1812
 
 *----------------------------------------------------------------------------
1813
 
 */
1814
 
 
1815
 
 
1816
 
static void
1817
 
UnityPlatformSendClientMessageFull(Display *d,        // IN
1818
 
                                   Window destWindow, // IN: Window to send msg to
1819
 
                                   Window w,          // IN: What the msg's "To:"
1820
 
                                                      // header should be, so to speak.
1821
 
                                   Atom messageType,  // IN
1822
 
                                   int format,        // IN
1823
 
                                   int numItems,      // IN
1824
 
                                   const void *data)  // IN
1825
 
{
1826
 
   XClientMessageEvent ev;
1827
 
   int i;
1828
 
 
1829
 
   memset(&ev, 0, sizeof ev);
1830
 
   ev.type = ClientMessage;
1831
 
   ev.window = w;
1832
 
   ev.message_type = messageType;
1833
 
   ev.format = format;
1834
 
   switch (format) {
1835
 
   case 8:
1836
 
      ASSERT(numItems <= ARRAYSIZE(ev.data.b));
1837
 
      for (i = 0; i < numItems; i++) {
1838
 
         const char *datab = data;
1839
 
         ev.data.b[i] = datab[i];
1840
 
      }
1841
 
      break;
1842
 
   case 16:
1843
 
      ASSERT(numItems <= ARRAYSIZE(ev.data.s));
1844
 
      for (i = 0; i < numItems; i++) {
1845
 
         const short *datas = data;
1846
 
         ev.data.s[i] = datas[i];
1847
 
      }
1848
 
      break;
1849
 
   case 32:
1850
 
      ASSERT(numItems <= ARRAYSIZE(ev.data.l));
1851
 
      for (i = 0; i < numItems; i++) {
1852
 
         const Atom *datal = data;
1853
 
         ev.data.l[i] = datal[i];
1854
 
      }
1855
 
      break;
1856
 
   }
1857
 
   if (! XSendEvent(d, destWindow, False,
1858
 
                    PropertyChangeMask|SubstructureRedirectMask|SubstructureNotifyMask, (XEvent *)&ev)) {
1859
 
      Debug("XSendEvent failed\n");
1860
 
   }
1861
 
}
1862
 
 
1863
 
/*
1864
 
 *-----------------------------------------------------------------------------
1865
 
 *
1866
 
 * UnityPlatformSendClientMessage --
1867
 
 *
1868
 
 *      Sends an XClientMessageEvent (such as one of the _NET_WM messages)
1869
 
 *
1870
 
 * Results:
1871
 
 *      None.
1872
 
 *
1873
 
 * Side effects:
1874
 
 *      None.
1875
 
 *
1876
 
 *-----------------------------------------------------------------------------
1877
 
 */
1878
 
 
1879
 
void
1880
 
UnityPlatformSendClientMessage(UnityPlatform *up, // IN
1881
 
                               Window destWindow, // IN: Window to actually send msg to
1882
 
                               Window w,          // IN: What the msg's "To:" header
1883
 
                                                  // should be, so to speak.
1884
 
                               Atom messageType,  // IN
1885
 
                               int format,        // IN
1886
 
                               int numItems,      // IN
1887
 
                               const void *data)  // IN
1888
 
{
1889
 
   UnityPlatformSendClientMessageFull(up->display, destWindow, w, messageType,
1890
 
                                      format, numItems, data);
1891
 
}
1892
 
 
1893
 
 
1894
 
/*****************************************************************************
1895
 
 * Misc Unity RPCs that need to be handled                                   *
1896
 
 *****************************************************************************/
1897
 
 
1898
 
 
1899
 
/*
1900
 
 *----------------------------------------------------------------------------
1901
 
 *
1902
 
 * UnityPlatformSetTopWindowGroup --
1903
 
 *
1904
 
 *      Set the group of windows on top of all others.
1905
 
 *
1906
 
 * Results:
1907
 
 *      TRUE if success,
1908
 
 *      FALSE otherwise.
1909
 
 *
1910
 
 * Side effects:
1911
 
 *      None
1912
 
 *
1913
 
 *----------------------------------------------------------------------------
1914
 
 */
1915
 
 
1916
 
Bool
1917
 
UnityPlatformSetTopWindowGroup(UnityPlatform *up,        // IN: Platform data
1918
 
                               UnityWindowId *windows,   // IN: array of window ids
1919
 
                               unsigned int windowCount) // IN: # of windows in the array
1920
 
{
1921
 
   Window sibling = None;
1922
 
   int i;
1923
 
 
1924
 
   ASSERT(up);
1925
 
   ASSERT(windows);
1926
 
   ASSERT(windowCount);
1927
 
 
1928
 
   /*
1929
 
    * Restack everything bottom to top.
1930
 
    */
1931
 
   for (i = 0; i < windowCount; i++) {
1932
 
      UnityPlatformWindow *upw;
1933
 
      Window curWindow;
1934
 
      Atom data[5] = {0,0,0,0,0};
1935
 
 
1936
 
      upw = UPWindow_Lookup(up, windows[i]);
1937
 
      if (!upw) {
1938
 
         continue;
1939
 
      }
1940
 
 
1941
 
      curWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
1942
 
      UPWindow_SetUserTime(up, upw);
1943
 
 
1944
 
      if (UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_RESTACK_WINDOW)) {
1945
 
         data[0] = 2;           // Magic source indicator to give full control
1946
 
         data[1] = sibling;
1947
 
         data[2] = Above;
1948
 
 
1949
 
         UnityPlatformSendClientMessage(up, up->rootWindows->windows[0],
1950
 
                                        curWindow,
1951
 
                                        up->atoms._NET_RESTACK_WINDOW,
1952
 
                                        32, 5, data);
1953
 
      } else {
1954
 
         XWindowChanges winch = {
1955
 
            .stack_mode = Above,
1956
 
            .sibling = sibling
1957
 
         };
1958
 
         unsigned int valueMask = CWStackMode;
1959
 
 
1960
 
         if (sibling != None) {
1961
 
            valueMask |= CWSibling;
1962
 
         }
1963
 
 
1964
 
         /*
1965
 
          * As of writing, Metacity doesn't support _NET_RESTACK_WINDOW and
1966
 
          * will block our attempt to raise a window unless it's active, so
1967
 
          * we activate the window first.
1968
 
          */
1969
 
         if (UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_ACTIVE_WINDOW)) {
1970
 
            data[0] = 2;           // Magic source indicator to give full control
1971
 
            data[1] = UnityPlatformGetServerTime(up);
1972
 
            data[2] = None;
1973
 
            UnityPlatformSendClientMessage(up, up->rootWindows->windows[0],
1974
 
                                           curWindow,
1975
 
                                           up->atoms._NET_ACTIVE_WINDOW,
1976
 
                                           32, 5, data);
1977
 
         }
1978
 
 
1979
 
         XReconfigureWMWindow(up->display, upw->toplevelWindow, 0, valueMask, &winch);
1980
 
      }
1981
 
 
1982
 
      sibling = upw->toplevelWindow;
1983
 
   }
1984
 
 
1985
 
   XSync(up->display, False);
1986
 
 
1987
 
   return TRUE;
1988
 
}
1989
 
 
1990
 
 
1991
 
/*
1992
 
 *-----------------------------------------------------------------------------
1993
 
 *
1994
 
 * UnityPlatformDnDSendClientMessage --
1995
 
 *
1996
 
 *      XXX This is a hack because UnityPlatformSendClientMessage doesn't work
1997
 
 *      for dnd windows.
1998
 
 *      Sends an XClientMessageEvent (such as one of the _NET_WM messages)
1999
 
 *
2000
 
 * Results:
2001
 
 *      None.
2002
 
 *
2003
 
 * Side effects:
2004
 
 *      None.
2005
 
 *
2006
 
 *-----------------------------------------------------------------------------
2007
 
 */
2008
 
 
2009
 
static void
2010
 
UnityPlatformDnDSendClientMessage(UnityPlatform *up, // IN
2011
 
                                  Window destWindow, // IN: Window to send msg to
2012
 
                                  Window w,          // IN: What the msg's "To:"
2013
 
                                                     // header should be, so to speak.
2014
 
                                  Atom messageType,  // IN
2015
 
                                  int format,        // IN
2016
 
                                  int numItems,      // IN
2017
 
                                  const void *data)  // IN
2018
 
{
2019
 
   UnityPlatformSendClientMessageFull(GDK_DISPLAY(), destWindow, w,
2020
 
                                      messageType, format, numItems, data);
2021
 
}
2022
 
 
2023
 
 
2024
 
/*
2025
 
 *----------------------------------------------------------------------------
2026
 
 *
2027
 
 * UnityPlatformStackDnDDetWnd --
2028
 
 *
2029
 
 *      Updates the stacking order of the dnd detection window.
2030
 
 *
2031
 
 * Results:
2032
 
 *      None.
2033
 
 *
2034
 
 * Side effects:
2035
 
 *      None.
2036
 
 *
2037
 
 *----------------------------------------------------------------------------
2038
 
 */
2039
 
 
2040
 
static void
2041
 
UnityPlatformStackDnDDetWnd(UnityPlatform *up)
2042
 
{
2043
 
   static const Atom onDesktop[] = { 0xFFFFFFFF, 0, 0, 0, 0 };
2044
 
 
2045
 
   if (!up->dnd.setMode || !up->dnd.detWnd) {
2046
 
      Debug("%s: DnD not yet initialized.\n", __func__);
2047
 
      return;
2048
 
   }
2049
 
 
2050
 
   if (!up->desktopWindow) {
2051
 
      Debug("Desktop Window not cached. Tracker isn't populated.\n");
2052
 
      return;
2053
 
   }
2054
 
 
2055
 
   /* Show the window on every desktop. */
2056
 
   UnityPlatformDnDSendClientMessage(up,
2057
 
                                     up->rootWindows->windows[0],
2058
 
                                     GDK_WINDOW_XWINDOW(up->dnd.detWnd->window),
2059
 
                                     up->atoms._NET_WM_DESKTOP,
2060
 
                                     32, 5, onDesktop);
2061
 
 
2062
 
   if (up->desktopWindow) {
2063
 
      XWindowChanges ch;
2064
 
      XSetWindowAttributes sa;
2065
 
      Window desktop = up->desktopWindow->toplevelWindow;
2066
 
 
2067
 
      /* Prevent the window manager from managing our detection window. */
2068
 
      sa.override_redirect = True;
2069
 
      XChangeWindowAttributes(GDK_DISPLAY(),
2070
 
                              GDK_WINDOW_XWINDOW(up->dnd.detWnd->window),
2071
 
                              CWOverrideRedirect, &sa);
2072
 
 
2073
 
      /* Resize and restack the detection window. */
2074
 
      ch.x = 0;
2075
 
      ch.y = 0;
2076
 
      ch.width = 65535;
2077
 
      ch.height = 65535;
2078
 
      ch.sibling = desktop;
2079
 
      ch.stack_mode = Above;
2080
 
 
2081
 
      XConfigureWindow(GDK_DISPLAY(), GDK_WINDOW_XWINDOW(up->dnd.detWnd->window),
2082
 
                       CWX|CWY|CWWidth|CWHeight|CWStackMode | CWSibling, &ch);
2083
 
 
2084
 
      Debug("Restacking dnd detection window.\n");
2085
 
   } else {
2086
 
      /*
2087
 
       * Attempt to rely on window manager if we cannot find a window to stack
2088
 
       * above.
2089
 
       */
2090
 
      Atom position[] = { _NET_WM_STATE_ADD,
2091
 
      up->atoms._NET_WM_STATE_STICKY,
2092
 
      up->atoms._NET_WM_STATE_BELOW, 0, 0 };
2093
 
 
2094
 
      Debug("Unable to locate desktop window to restack detection window above.\n");
2095
 
      UnityPlatformDnDSendClientMessage(up,
2096
 
                                        up->rootWindows->windows[0],
2097
 
                                        GDK_WINDOW_XWINDOW(up->dnd.detWnd->window),
2098
 
                                        up->atoms._NET_WM_STATE,
2099
 
                                        32, 5, position);
2100
 
      XMoveResizeWindow(GDK_DISPLAY(),
2101
 
                        GDK_WINDOW_XWINDOW(up->dnd.detWnd->window),
2102
 
                        0, 0, 65535, 65535);
2103
 
   }
2104
 
}
2105
 
 
2106
 
 
2107
 
/*
2108
 
 *------------------------------------------------------------------------------
2109
 
 *
2110
 
 * UnityPlatformUpdateDnDDetWnd --
2111
 
 *
2112
 
 *     Shows/hides a full-screen drag detection wnd for unity guest->host DnD.
2113
 
 *
2114
 
 * Results:
2115
 
 *     None.
2116
 
 *
2117
 
 * Side effects:
2118
 
 *     None.
2119
 
 *
2120
 
 *------------------------------------------------------------------------------
2121
 
 */
2122
 
 
2123
 
void
2124
 
UnityPlatformUpdateDnDDetWnd(UnityPlatform *up, // IN
2125
 
                             Bool show)         // IN
2126
 
{
2127
 
 
2128
 
   if (!up || !up->dnd.setMode || !up->dnd.detWnd) {
2129
 
      /*
2130
 
       * This function may potentially be called during UnityPlatform destruction.
2131
 
       */
2132
 
      return;
2133
 
   }
2134
 
 
2135
 
   if (show) {
2136
 
      gtk_widget_show(up->dnd.detWnd);
2137
 
      UnityPlatformStackDnDDetWnd(up);
2138
 
      Debug("Showing dnd detection window.\n");
2139
 
   } else {
2140
 
      gtk_widget_hide(up->dnd.detWnd);
2141
 
      Debug("Hiding dnd detection window.\n");
2142
 
   }
2143
 
 
2144
 
   up->dnd.setMode(show);
2145
 
}
2146
 
 
2147
 
 
2148
 
/*
2149
 
 *------------------------------------------------------------------------------
2150
 
 *
2151
 
 * UnityPlatformSetActiveDnDDetWnd --
2152
 
 *
2153
 
 *     Set current full-screen drag detection wnd. The caller retains ownership
2154
 
 *     of the data. The caller is responsible for updating the active dnd det
2155
 
 *     wnd.
2156
 
 *
2157
 
 * Results:
2158
 
 *     None.
2159
 
 *
2160
 
 * Side effects:
2161
 
 *     None.
2162
 
 *
2163
 
 *------------------------------------------------------------------------------
2164
 
 */
2165
 
 
2166
 
void
2167
 
UnityPlatformSetActiveDnDDetWnd(UnityPlatform *up, // IN
2168
 
                                UnityDnD *data)      // IN
2169
 
{
2170
 
   up->dnd = *data;
2171
 
}
2172
 
 
2173
 
 
2174
 
/*
2175
 
 *------------------------------------------------------------------------------
2176
 
 *
2177
 
 * UnityPlatformSetDesktopWorkAreas --
2178
 
 *
2179
 
 *     Sets the work areas for all screens.
2180
 
 *
2181
 
 * Results:
2182
 
 *     None.
2183
 
 *
2184
 
 * Side effects:
2185
 
 *     None.
2186
 
 *
2187
 
 *------------------------------------------------------------------------------
2188
 
 */
2189
 
 
2190
 
Bool
2191
 
UnityPlatformSetDesktopWorkAreas(UnityPlatform *up,     // IN
2192
 
                                 UnityRect workAreas[], // IN
2193
 
                                 uint32 numWorkAreas)   // IN
2194
 
{
2195
 
   int iScreens;
2196
 
   int i;
2197
 
   XineramaScreenInfo *screenInfo = NULL;
2198
 
   int numScreens;
2199
 
   RegionPtr strutsRegion;
2200
 
   RegionPtr screenRegion;
2201
 
   RegionPtr workAreasRegion;
2202
 
   XID (*strutInfos)[12];
2203
 
   int numStrutInfos;
2204
 
 
2205
 
   if (!up->rootWindows) {
2206
 
      /*
2207
 
       * We're not in Unity mode yet. Save the info until we are.
2208
 
       */
2209
 
 
2210
 
      up->needWorkAreas = Util_SafeMalloc(numWorkAreas * sizeof *up->needWorkAreas);
2211
 
      memcpy(up->needWorkAreas, workAreas, numWorkAreas * sizeof *up->needWorkAreas);
2212
 
      up->needNumWorkAreas = numWorkAreas;
2213
 
      return TRUE;
2214
 
   }
2215
 
 
2216
 
   if (!UnityPlatformWMProtocolSupported(up, UNITY_X11_WM__NET_WM_STRUT_PARTIAL)) {
2217
 
      Debug("Window manager does not support _NET_WM_STRUT_PARTIAL - not setting desktop work area.\n");
2218
 
      return FALSE;
2219
 
   }
2220
 
 
2221
 
   ASSERT(up);
2222
 
   ASSERT(up->rootWindows);
2223
 
 
2224
 
   /*
2225
 
    * Get the geometry of all attached screens.  If we're running multi-mon,
2226
 
    * we'll query the Xinerama extension.  Otherwise we just fall back to
2227
 
    * examining our root window's geometry.
2228
 
    */
2229
 
   if (XineramaQueryExtension(up->display, &i, &i)) {
2230
 
      screenInfo = XineramaQueryScreens(up->display, &numScreens);
2231
 
   }
2232
 
 
2233
 
   if (!screenInfo) {
2234
 
      uint32 rootX;
2235
 
      uint32 rootY;
2236
 
      uint32 rootWidth;
2237
 
      uint32 rootHeight;
2238
 
      uint32 dummy;
2239
 
      Window winDummy;
2240
 
 
2241
 
      if (numWorkAreas > 1) {
2242
 
         Debug("Xinerama extension not present, or XineramaQueryScreens failed,"
2243
 
               " but multiple work areas were requested.\n");
2244
 
         return FALSE;
2245
 
      }
2246
 
 
2247
 
      if (!XGetGeometry(up->display, up->rootWindows->windows[0], &winDummy,
2248
 
                        &rootX, &rootY, &rootWidth, &rootHeight,
2249
 
                        &dummy, &dummy)) {
2250
 
         return FALSE;
2251
 
      }
2252
 
 
2253
 
      screenInfo = Util_SafeCalloc(1, sizeof *screenInfo);
2254
 
      numScreens = 1;
2255
 
 
2256
 
      screenInfo->x_org = rootX;
2257
 
      screenInfo->y_org = rootY;
2258
 
      screenInfo->width = rootWidth;
2259
 
      screenInfo->height = rootHeight;
2260
 
   }
2261
 
 
2262
 
   /*
2263
 
    * New and improved wild'n'crazy scheme to map the host's work area
2264
 
    * coordinates to a collection of struts.
2265
 
    *
2266
 
    * This implementation depends upon the y-x banded rectangles
2267
 
    * implementation of lib/region.
2268
 
    *
2269
 
    * In short, here's how things go:
2270
 
    *
2271
 
    *    1.  For each Xinerama screen (or the root window in case we have no
2272
 
    *        Xinerama) and host work area, a region is created.  A strut
2273
 
    *        region is then created by subtracting the work area region from
2274
 
    *        the screen region.
2275
 
    *
2276
 
    *    2.  This remaining region will contain between 0 and 4 rectangles,
2277
 
    *        each of which will be transformed into a strut window.
2278
 
    *
2279
 
    *        For each of these rectangles, we infer based on their dimensions
2280
 
    *        which screen boundary the resulting strut should be bound to.
2281
 
    *
2282
 
    *        a.  Boxes touching both the left and right sides of the screen
2283
 
    *            are either top or bottom struts, depending on whether they
2284
 
    *            also touch the top or bottom edge.
2285
 
    *
2286
 
    *        b.  Any remaining box will touch either the left OR the right
2287
 
    *            side, but not both.  (Such an irregular layout cannot be
2288
 
    *            described by the work areas RPC.)  That box's strut will
2289
 
    *            then be attached to the same side of the screen.
2290
 
    *
2291
 
    * While also not perfect, this algorithm should do a better job of creating
2292
 
    * struts along their correct sides of a screen than its predecessor.  It
2293
 
    * will let us assume the common case that what we define as a strut attached
2294
 
    * to the left or right side really should be attached to the left or right,
2295
 
    * rather than attached to the top or bottom and spanning the height of the
2296
 
    * display.
2297
 
    *
2298
 
    * Pathological case:
2299
 
    *    1.  Screen geometry: 1280x960.
2300
 
    *        Left strut: 100px wide, 600px tall.  Touches top of screen.
2301
 
    *        Right strut: 1180px wide, 100px tall.  Touches top of screen.
2302
 
    *
2303
 
    *    2.  Note that these struts touch each other.  We'd interpret the resulting
2304
 
    *        work area as follows:
2305
 
    *
2306
 
    *        Top strut: 1280px wide, 100px tall.
2307
 
    *        Left strut: 100px wide, 500px tall, starting from y = 100.
2308
 
    *
2309
 
    * I believe this sort of layout to be uncommon enough that we can accept
2310
 
    * failure here.  If we -really- want to get these things right, then
2311
 
    * we should send strut information explicitly, rather than having the
2312
 
    * guest try to deduce it from work area geometry.
2313
 
    */
2314
 
 
2315
 
   /*
2316
 
    * One strut per screen edge = at most 4 strutInfos.
2317
 
    */
2318
 
   strutInfos = alloca(4 * sizeof *strutInfos * numScreens);
2319
 
   memset(strutInfos, 0, 4 * sizeof *strutInfos * numScreens);
2320
 
   numStrutInfos = 0;
2321
 
 
2322
 
   for (iScreens = 0; iScreens < numScreens; iScreens++) {
2323
 
      int iRects;
2324
 
 
2325
 
      xRectangle screenRect;
2326
 
      xRectangle workAreaRect;
2327
 
 
2328
 
      /*
2329
 
       * Steps 1a. Create screen, work area regions.
2330
 
       */
2331
 
      screenRect.x = screenInfo[iScreens].x_org;
2332
 
      screenRect.y = screenInfo[iScreens].y_org;
2333
 
      screenRect.width = screenInfo[iScreens].width;
2334
 
      screenRect.height = screenInfo[iScreens].height;
2335
 
      screenRect.info.type = UpdateRect;
2336
 
 
2337
 
      workAreaRect.x = workAreas[iScreens].x;
2338
 
      workAreaRect.y = workAreas[iScreens].y;
2339
 
      workAreaRect.width = workAreas[iScreens].width;
2340
 
      workAreaRect.height = workAreas[iScreens].height;
2341
 
      workAreaRect.info.type = UpdateRect;
2342
 
 
2343
 
      screenRegion = miRectsToRegion(1, &screenRect, 0);
2344
 
      workAreasRegion = miRectsToRegion(1, &workAreaRect, 0);
2345
 
 
2346
 
      /*
2347
 
       * Step 1b.  Create struts region by subtracting work area from screen.
2348
 
       */
2349
 
      strutsRegion = miRegionCreate(NULL, 0);
2350
 
      miSubtract(strutsRegion, screenRegion, workAreasRegion);
2351
 
      miRegionDestroy(workAreasRegion);
2352
 
      miRegionDestroy(screenRegion);
2353
 
 
2354
 
      /*
2355
 
       * Step 2.  Transform struts region rectangles into individual struts.
2356
 
       */
2357
 
      for (iRects = 0; iRects < REGION_NUM_RECTS(strutsRegion);
2358
 
           iRects++, numStrutInfos++) {
2359
 
         BoxPtr p = REGION_RECTS(strutsRegion) + iRects;
2360
 
         int bounds = 0;
2361
 
#define TOUCHES_LEFT          0x1
2362
 
#define TOUCHES_RIGHT         0x2
2363
 
#define TOUCHES_TOP           0x4
2364
 
#define TOUCHES_BOTTOM        0x8
2365
 
 
2366
 
         if (p->x1 == screenRect.x) { bounds |= TOUCHES_LEFT; }
2367
 
         if (p->x2 == screenRect.x + screenRect.width) { bounds |= TOUCHES_RIGHT; }
2368
 
         if (p->y1 == screenRect.y) { bounds |= TOUCHES_TOP; }
2369
 
         if (p->y2 == screenRect.y + screenRect.height) { bounds |= TOUCHES_BOTTOM; }
2370
 
 
2371
 
         /*
2372
 
          * strutInfos is passed directly to
2373
 
          * XSetProperty(..._NET_WM_STRUTS_PARTIAL).  I.e., look up that
2374
 
          * property's entry in NetWM/wm-spec for more info on the indices.
2375
 
          *
2376
 
          * I went the switch/case route only because it does a better job
2377
 
          * (for me) of organizing & showing -all- possible cases.  YMMV.
2378
 
          *
2379
 
          * The region code treats rectanges as ranges from [x1,x2) and
2380
 
          * [y1,y2).  In other words, x2 and y2 are OUTSIDE the region.  I
2381
 
          * guess it makes calculating widths/heights easier.  However, the
2382
 
          * strut width/height dimensions are INCLUSIVE, so we'll subtract 1
2383
 
          * from the "end" (as opposed to "start") value.
2384
 
          *
2385
 
          * (Ex:  A 1600x1200 display with a 25px top strut would be marked
2386
 
          * as top = 25, top_start_x = 0, top_end_x = 1599.)
2387
 
          */
2388
 
         switch (bounds) {
2389
 
         case TOUCHES_LEFT | TOUCHES_RIGHT | TOUCHES_TOP:
2390
 
            /* Top strut. */
2391
 
            strutInfos[numStrutInfos][2] = p->y2 - p->y1;
2392
 
            strutInfos[numStrutInfos][8] = p->x1;
2393
 
            strutInfos[numStrutInfos][9] = p->x2 - 1;
2394
 
            break;
2395
 
         case TOUCHES_LEFT | TOUCHES_RIGHT | TOUCHES_BOTTOM:
2396
 
            /* Bottom strut. */
2397
 
            strutInfos[numStrutInfos][3] = p->y2 - p->y1;
2398
 
            strutInfos[numStrutInfos][10] = p->x1;
2399
 
            strutInfos[numStrutInfos][11] = p->x2 - 1;
2400
 
            break;
2401
 
         case TOUCHES_LEFT:
2402
 
         case TOUCHES_LEFT | TOUCHES_TOP:
2403
 
         case TOUCHES_LEFT | TOUCHES_BOTTOM:
2404
 
         case TOUCHES_LEFT | TOUCHES_TOP | TOUCHES_BOTTOM:
2405
 
            /* Left strut. */
2406
 
            strutInfos[numStrutInfos][0] = p->x2 - p->x1;
2407
 
            strutInfos[numStrutInfos][4] = p->y1;
2408
 
            strutInfos[numStrutInfos][5] = p->y2 - 1;
2409
 
            break;
2410
 
         case TOUCHES_RIGHT:
2411
 
         case TOUCHES_RIGHT | TOUCHES_TOP:
2412
 
         case TOUCHES_RIGHT | TOUCHES_BOTTOM:
2413
 
         case TOUCHES_RIGHT | TOUCHES_TOP | TOUCHES_BOTTOM:
2414
 
            /* Right strut. */
2415
 
            strutInfos[numStrutInfos][1] = p->x2 - p->x1;
2416
 
            strutInfos[numStrutInfos][6] = p->y1;
2417
 
            strutInfos[numStrutInfos][7] = p->y2 - 1;
2418
 
            break;
2419
 
         case TOUCHES_LEFT | TOUCHES_RIGHT | TOUCHES_TOP | TOUCHES_BOTTOM:
2420
 
            Warning("%s: Struts occupy entire display.", __func__);
2421
 
            /* FALLTHROUGH */
2422
 
         default:
2423
 
            Warning("%s: Irregular strut configuration: bounds %4x\n", __func__, bounds);
2424
 
            miRegionDestroy(strutsRegion);
2425
 
            goto out;
2426
 
            break;
2427
 
         }
2428
 
      }
2429
 
#undef TOUCHES_LEFT
2430
 
#undef TOUCHES_RIGHT
2431
 
#undef TOUCHES_TOP
2432
 
#undef TOUCHES_BOTTOM
2433
 
 
2434
 
      miRegionDestroy(strutsRegion);
2435
 
   }
2436
 
 
2437
 
   /*
2438
 
    * The first step is making sure we have enough windows in existence to list the
2439
 
    * _NET_WM_STRUT_PARTIAL properties for each screen.
2440
 
    */
2441
 
   if (!up->workAreas
2442
 
       || up->workAreas->numWindows != numStrutInfos) {
2443
 
      Window *newWinList;
2444
 
 
2445
 
      newWinList = Util_SafeCalloc(numStrutInfos, sizeof *newWinList);
2446
 
      if (up->workAreas) {
2447
 
         memcpy(newWinList, up->workAreas->windows,
2448
 
                MIN(numStrutInfos, up->workAreas->numWindows) * sizeof *newWinList);
2449
 
      }
2450
 
 
2451
 
      /*
2452
 
       * Destroy unneeded windows
2453
 
       */
2454
 
      for (i = numStrutInfos; i < (up->workAreas ? up->workAreas->numWindows : 0); i++) {
2455
 
         XDestroyWindow(up->display, up->workAreas->windows[i]);
2456
 
      }
2457
 
 
2458
 
      /*
2459
 
       * Create additional windows as needed.
2460
 
       */
2461
 
      for (i = up->workAreas ? up->workAreas->numWindows : 0; i < numStrutInfos; i++) {
2462
 
         static const char strutWindowName[] = "vmware-user workarea struts";
2463
 
         Atom allDesktops = -1;
2464
 
         newWinList[i] = XCreateWindow(up->display, up->rootWindows->windows[0],
2465
 
                                       -50, -50, 1, 1, 0, CopyFromParent, InputOnly,
2466
 
                                       CopyFromParent, 0, NULL);
2467
 
         XChangeProperty(up->display, newWinList[i], up->atoms._NET_WM_WINDOW_TYPE,
2468
 
                         XA_ATOM, 32, PropModeReplace,
2469
 
                         (unsigned char *)&up->atoms._NET_WM_WINDOW_TYPE_DOCK, 1);
2470
 
         XChangeProperty(up->display, newWinList[i], up->atoms._NET_WM_DESKTOP,
2471
 
                         XA_CARDINAL, 32, PropModeReplace,
2472
 
                         (unsigned char *)&allDesktops, 1);
2473
 
         XStoreName(up->display, newWinList[i], strutWindowName);
2474
 
         XMapWindow(up->display, newWinList[i]);
2475
 
      }
2476
 
 
2477
 
      if (up->workAreas) {
2478
 
         USWindowUpdate(up, up->workAreas, newWinList, numStrutInfos);
2479
 
      } else {
2480
 
         up->workAreas = USWindowCreate(up, NULL, newWinList, numStrutInfos);
2481
 
         up->workAreas->windowsAreOwned = TRUE;
2482
 
      }
2483
 
   }
2484
 
 
2485
 
   /*
2486
 
    * Now actually set the _NET_WM_STRUT_PARTIAL property on our special 'struts'
2487
 
    * windows.
2488
 
    */
2489
 
   for (i = 0; i < numStrutInfos; i++) {
2490
 
      Window strutWindow;
2491
 
 
2492
 
      strutWindow = up->workAreas->windows[i];
2493
 
 
2494
 
      XChangeProperty(up->display, strutWindow, up->atoms._NET_WM_STRUT_PARTIAL, XA_CARDINAL,
2495
 
                      32, PropModeReplace, (unsigned char *)strutInfos[i], ARRAYSIZE(strutInfos[i]));
2496
 
   }
2497
 
 
2498
 
out:
2499
 
   free(screenInfo);
2500
 
 
2501
 
   return TRUE;
2502
 
}
2503
 
 
2504
 
 
2505
 
/*
2506
 
 *-----------------------------------------------------------------------------
2507
 
 *
2508
 
 * UnityPlatformGetNumVirtualDesktops --
2509
 
 *
2510
 
 *      Retrieves the number of virtual desktops currently set in the guest.
2511
 
 *
2512
 
 * Results:
2513
 
 *      Number of desktops.
2514
 
 *
2515
 
 * Side effects:
2516
 
 *      None
2517
 
 *
2518
 
 *-----------------------------------------------------------------------------
2519
 
 */
2520
 
 
2521
 
size_t
2522
 
UnityPlatformGetNumVirtualDesktops(UnityPlatform *up) // IN
2523
 
{
2524
 
   Atom propertyType;
2525
 
   int propertyFormat;
2526
 
   unsigned long itemsReturned;
2527
 
   unsigned long bytesRemaining;
2528
 
   Atom *valueReturned;
2529
 
   size_t retval;
2530
 
 
2531
 
   ASSERT(up);
2532
 
   if (XGetWindowProperty(up->display, up->rootWindows->windows[0],
2533
 
                          up->atoms._NET_NUMBER_OF_DESKTOPS, 0,
2534
 
                          1024, False, AnyPropertyType,
2535
 
                          &propertyType, &propertyFormat, &itemsReturned,
2536
 
                          &bytesRemaining, (unsigned char **)&valueReturned)
2537
 
       == Success
2538
 
       && propertyType == XA_CARDINAL
2539
 
       && propertyFormat == 32) {
2540
 
      ASSERT(itemsReturned == 1);
2541
 
 
2542
 
      retval = valueReturned[0];
2543
 
   } else {
2544
 
      retval = 1;
2545
 
   }
2546
 
   XFree(valueReturned);
2547
 
 
2548
 
   return retval;
2549
 
}
2550
 
 
2551
 
 
2552
 
/*
2553
 
 *-----------------------------------------------------------------------------
2554
 
 *
2555
 
 * UnityPlatformGetVirtualDesktopLayout --
2556
 
 *
2557
 
 *      Retrieves the guest's current virtual desktop layout info, and stores it in
2558
 
 *      'layoutData' (an array of 4 Atoms).
2559
 
 *
2560
 
 * Results:
2561
 
 *      Desktop layout stored in 'layoutData'
2562
 
 *
2563
 
 * Side effects:
2564
 
 *      None.
2565
 
 *
2566
 
 *-----------------------------------------------------------------------------
2567
 
 */
2568
 
 
2569
 
void
2570
 
UnityPlatformGetVirtualDesktopLayout(UnityPlatform *up, // IN
2571
 
                                     Atom *layoutData)  // OUT
2572
 
{
2573
 
   Atom propertyType;
2574
 
   int propertyFormat;
2575
 
   unsigned long itemsReturned;
2576
 
   unsigned long bytesRemaining;
2577
 
   Atom *valueReturned;
2578
 
 
2579
 
   ASSERT(up);
2580
 
 
2581
 
   layoutData[3] = _NET_WM_TOPLEFT;
2582
 
   if (XGetWindowProperty(up->display, up->rootWindows->windows[0],
2583
 
                          up->atoms._NET_DESKTOP_LAYOUT, 0,
2584
 
                          1024, False, AnyPropertyType,
2585
 
                          &propertyType, &propertyFormat, &itemsReturned,
2586
 
                          &bytesRemaining, (unsigned char **)&valueReturned)
2587
 
       == Success
2588
 
       && propertyType == XA_CARDINAL
2589
 
       && propertyFormat == 32) {
2590
 
      ASSERT(itemsReturned == 3 || itemsReturned == 4);
2591
 
 
2592
 
      memcpy(layoutData,
2593
 
             valueReturned,
2594
 
             itemsReturned * sizeof *valueReturned);
2595
 
   } else {
2596
 
      layoutData[0] = _NET_WM_ORIENTATION_HORZ;
2597
 
      layoutData[1] = 0;
2598
 
      layoutData[2] = 1;
2599
 
   }
2600
 
   XFree(valueReturned);
2601
 
}
2602
 
 
2603
 
 
2604
 
/*
2605
 
 *-----------------------------------------------------------------------------
2606
 
 *
2607
 
 * UnityPlatformSyncDesktopConfig --
2608
 
 *
2609
 
 *      This routine takes the virtual desktop configuration stored in UnityPlatform and
2610
 
 *      makes sure that the guest's actual virtual desktop configuration matches. This is
2611
 
 *      done in three situations:
2612
 
 *        1. Updating the guest's virtual desktop config to match the host's, right after
2613
 
 *        the host's virtual desktop config has changed.
2614
 
 *        2. Forcing the guest's virtual desktop config back to the host's, right after
2615
 
 *        the user uses the guest's pager to alter the guest virtual desktop config.
2616
 
 *        3. Restoring the guest's virtual desktop configuration when exiting Unity mode.
2617
 
 *
2618
 
 * Results:
2619
 
 *      None.
2620
 
 *
2621
 
 * Side effects:
2622
 
 *      Guest windows may jump to different virtual desktops if desktops are removed.
2623
 
 *
2624
 
 *-----------------------------------------------------------------------------
2625
 
 */
2626
 
 
2627
 
void
2628
 
UnityPlatformSyncDesktopConfig(UnityPlatform *up) // IN
2629
 
{
2630
 
   Atom data[5] = {0, 0, 0, 0, 0};
2631
 
 
2632
 
   ASSERT(up);
2633
 
 
2634
 
   if (!up->rootWindows || !up->display) {
2635
 
      return; // This function might be called while not in Unity mode
2636
 
   }
2637
 
 
2638
 
   data[0] = up->desktopInfo.numDesktops;
2639
 
   UnityPlatformSendClientMessage(up,
2640
 
                                  up->rootWindows->windows[0],
2641
 
                                  up->rootWindows->windows[0],
2642
 
                                  up->atoms._NET_NUMBER_OF_DESKTOPS,
2643
 
                                  32, 5,
2644
 
                                  data);
2645
 
   XChangeProperty(up->display, up->rootWindows->windows[0],
2646
 
                   up->atoms._NET_DESKTOP_LAYOUT, XA_CARDINAL,
2647
 
                   32, PropModeReplace, (unsigned char *)up->desktopInfo.layoutData, 4);
2648
 
}
2649
 
 
2650
 
 
2651
 
/*
2652
 
 *------------------------------------------------------------------------------
2653
 
 *
2654
 
 * UnityPlatformSetDesktopConfig --
2655
 
 *
2656
 
 *     Set the virtual desktop configuration as specified by the host.
2657
 
 *
2658
 
 * Results:
2659
 
 *     Returns TRUE if successful, and FALSE otherwise.
2660
 
 *
2661
 
 * Side effects:
2662
 
 *     None.
2663
 
 *
2664
 
 *------------------------------------------------------------------------------
2665
 
 */
2666
 
 
2667
 
Bool
2668
 
UnityPlatformSetDesktopConfig(UnityPlatform *up,                             // IN
2669
 
                              const UnityVirtualDesktopArray *desktopConfig) // IN
2670
 
{
2671
 
   int i;
2672
 
   int x;
2673
 
   int y;
2674
 
   UnityVirtualDesktop minDesktop;
2675
 
   UnityVirtualDesktop maxDesktop;
2676
 
   UnityVirtualDesktop desktopSpread;
2677
 
   int unityDesktopLayout[MAX_VIRT_DESK][MAX_VIRT_DESK];
2678
 
   int guestDesktopLayout[MAX_VIRT_DESK][MAX_VIRT_DESK];
2679
 
 
2680
 
   ASSERT(up);
2681
 
   ASSERT(desktopConfig);
2682
 
   ASSERT(desktopConfig->desktopCount >= 1);
2683
 
 
2684
 
   /*
2685
 
    * This long section of code mainly exists to verify that the host's virtual desktop
2686
 
    * setup can be represented on our end, and to figure out how best to do it. We could
2687
 
    * do this simply, if we didn't have to deal with the possibility of having 5 virtual
2688
 
    * desktops in a 3x2 layout, which is a very real possibility on Linux hosts...
2689
 
    */
2690
 
   memset(unityDesktopLayout, 0xFF, sizeof unityDesktopLayout); // Set all entries to -1
2691
 
   minDesktop = desktopConfig->desktops[0];
2692
 
   maxDesktop = minDesktop;
2693
 
   for (i = 1; i < desktopConfig->desktopCount; i++) {
2694
 
      if (desktopConfig->desktops[i].x < minDesktop.x) {
2695
 
         minDesktop.x = desktopConfig->desktops[i].x;
2696
 
      }
2697
 
      if (desktopConfig->desktops[i].y < minDesktop.y) {
2698
 
         minDesktop.y = desktopConfig->desktops[i].y;
2699
 
      }
2700
 
      if (desktopConfig->desktops[i].x > maxDesktop.x) {
2701
 
         maxDesktop.x = desktopConfig->desktops[i].x;
2702
 
      }
2703
 
      if (desktopConfig->desktops[i].y > maxDesktop.y) {
2704
 
         maxDesktop.y = desktopConfig->desktops[i].y;
2705
 
      }
2706
 
   }
2707
 
   desktopSpread.x = maxDesktop.x - minDesktop.x;
2708
 
   desktopSpread.y = maxDesktop.y - minDesktop.y;
2709
 
 
2710
 
   for (i = 0; i < desktopConfig->desktopCount; i++) {
2711
 
      int32 localX = desktopConfig->desktops[i].x - minDesktop.x;
2712
 
      int32 localY = desktopConfig->desktops[i].y - minDesktop.y;
2713
 
 
2714
 
      if (localY >= MAX_VIRT_DESK || localX >= MAX_VIRT_DESK) {
2715
 
         Warning("Unity virtual desktop layout has holes that are too big to handle\n");
2716
 
         return FALSE;
2717
 
      }
2718
 
 
2719
 
      unityDesktopLayout[localX][localY] = i;
2720
 
   }
2721
 
 
2722
 
   for (x = 0; x < desktopSpread.x; x++) {
2723
 
      for (y = 0; y < desktopSpread.y; y++) {
2724
 
         if (unityDesktopLayout[x][y] < 0) {
2725
 
            Warning("Unity virtual desktop layout has holes that we can't handle.\n");
2726
 
            return FALSE;
2727
 
         }
2728
 
      }
2729
 
   }
2730
 
 
2731
 
   /*
2732
 
    * Check along the left edge to make sure that there aren't any gaps between virtual
2733
 
    * desktops.
2734
 
    */
2735
 
   for (x = desktopSpread.x, y = 0; y <= desktopSpread.y; y++) {
2736
 
      if (unityDesktopLayout[x][y] < 0) {
2737
 
         break;
2738
 
      }
2739
 
   }
2740
 
   for (; y <= desktopSpread.y; y++) {
2741
 
      if (unityDesktopLayout[x][y] >= 0) {
2742
 
         Warning("Unity virtual desktop layout has holes along the right edge.\n");
2743
 
         return FALSE;
2744
 
      }
2745
 
   }
2746
 
 
2747
 
   /*
2748
 
    * Check along the bottom edge to make sure that there aren't any gaps between virtual
2749
 
    * desktops.
2750
 
    */
2751
 
   for (y = desktopSpread.y, x = 0; x <= desktopSpread.x; x++) {
2752
 
      if (unityDesktopLayout[x][y] < 0) {
2753
 
         break;
2754
 
      }
2755
 
   }
2756
 
   for (; x <= desktopSpread.x; x++) {
2757
 
      if (unityDesktopLayout[x][y] >= 0) {
2758
 
         Warning("Unity virtual desktop layout has holes along the bottom edge.\n");
2759
 
         return FALSE;
2760
 
      }
2761
 
   }
2762
 
 
2763
 
   /*
2764
 
    * Now we know we have a workable virtual desktop layout - let's figure out how to
2765
 
    * communicate it to the window manager & pager.
2766
 
    */
2767
 
   up->desktopInfo.layoutData[0] = _NET_WM_ORIENTATION_HORZ; // Orientation
2768
 
   up->desktopInfo.layoutData[1] = (desktopSpread.x + 1); // # of columns
2769
 
   up->desktopInfo.layoutData[2] = (desktopSpread.y + 1); // # of rows
2770
 
   up->desktopInfo.layoutData[3] = _NET_WM_TOPLEFT; // Starting corner
2771
 
 
2772
 
   if (((desktopSpread.x + 1) * (desktopSpread.y + 1)) >= desktopConfig->desktopCount
2773
 
       && desktopSpread.x > 0
2774
 
       && desktopSpread.y > 1
2775
 
       && unityDesktopLayout[desktopSpread.x][desktopSpread.y - 1] < 0) {
2776
 
      /*
2777
 
       * We know there is are least two holes at the end of the layout, /and/ the holes
2778
 
       * go up the right side, so therefore we need to use vertical orientation for the
2779
 
       * EWMH layout.
2780
 
       */
2781
 
      up->desktopInfo.layoutData[0] = _NET_WM_ORIENTATION_VERT;
2782
 
   }
2783
 
 
2784
 
   /*
2785
 
    * Figure out what the guest-side desktop IDs will be, based on our chosen
2786
 
    * orientation.
2787
 
    */
2788
 
   i = 0;
2789
 
   memset(guestDesktopLayout, 0xFF, sizeof guestDesktopLayout); // Set all entries to -1
2790
 
   if (up->desktopInfo.layoutData[0] == _NET_WM_ORIENTATION_HORZ) {
2791
 
      for (y = 0; y <= desktopSpread.y; y++) {
2792
 
         for (x = 0; x <= desktopSpread.x; x++) {
2793
 
            if (unityDesktopLayout[x][y] >= 0) {
2794
 
               guestDesktopLayout[x][y] = i++;
2795
 
            }
2796
 
         }
2797
 
      }
2798
 
   } else {
2799
 
      for (x = 0; x <= desktopSpread.x; x++) {
2800
 
         for (y = 0; y <= desktopSpread.y; y++) {
2801
 
            if (unityDesktopLayout[x][y] >= 0) {
2802
 
               guestDesktopLayout[x][y] = i++;
2803
 
            }
2804
 
         }
2805
 
      }
2806
 
   }
2807
 
 
2808
 
   up->desktopInfo.numDesktops = desktopConfig->desktopCount;
2809
 
 
2810
 
   /*
2811
 
    * Build tables to translate between guest-side and Unity-side desktop IDs.
2812
 
    */
2813
 
   up->desktopInfo.guestDesktopToUnity =
2814
 
      Util_SafeRealloc(up->desktopInfo.guestDesktopToUnity,
2815
 
                       up->desktopInfo.numDesktops
2816
 
                       * sizeof up->desktopInfo.guestDesktopToUnity[0]);
2817
 
   up->desktopInfo.unityDesktopToGuest =
2818
 
      Util_SafeRealloc(up->desktopInfo.unityDesktopToGuest,
2819
 
                       up->desktopInfo.numDesktops
2820
 
                       * sizeof up->desktopInfo.unityDesktopToGuest[0]);
2821
 
   for (i = 0; i < up->desktopInfo.numDesktops; i++) {
2822
 
      int guestNum;
2823
 
      UnityVirtualDesktop curDesk = desktopConfig->desktops[i];
2824
 
 
2825
 
      guestNum = guestDesktopLayout[curDesk.x - minDesktop.x][curDesk.y - minDesktop.y];
2826
 
      up->desktopInfo.guestDesktopToUnity[guestNum] = i;
2827
 
      up->desktopInfo.unityDesktopToGuest[i] = guestNum;
2828
 
   }
2829
 
 
2830
 
   /*
2831
 
    * Make the configuration actually take effect.
2832
 
    */
2833
 
   UnityPlatformSyncDesktopConfig(up);
2834
 
 
2835
 
   return TRUE;
2836
 
}
2837
 
 
2838
 
 
2839
 
/*
2840
 
 *------------------------------------------------------------------------------
2841
 
 *
2842
 
 * UnityPlatformSetInitialDesktop --
2843
 
 *
2844
 
 *     Set a desktop specified by the desktop id as the initial state.
2845
 
 *
2846
 
 * Results:
2847
 
 *     Returns TRUE if successful, and FALSE otherwise.
2848
 
 *
2849
 
 * Side effects:
2850
 
 *     Some windows might be hidden and some shown.
2851
 
 *
2852
 
 *------------------------------------------------------------------------------
2853
 
 */
2854
 
 
2855
 
Bool
2856
 
UnityPlatformSetInitialDesktop(UnityPlatform *up,         // IN
2857
 
                               UnityDesktopId desktopId)  // IN
2858
 
{
2859
 
   ASSERT(up);
2860
 
   up->desktopInfo.initialDesktop = desktopId;
2861
 
   return UnityPlatformSetDesktopActive(up, desktopId);
2862
 
}
2863
 
 
2864
 
 
2865
 
/*
2866
 
 *------------------------------------------------------------------------------
2867
 
 *
2868
 
 * UnityPlatformSetDesktopActive --
2869
 
 *
2870
 
 *     Switch to the specified virtual desktop. The desktopId is an index
2871
 
 *     into the desktop configuration array.
2872
 
 *
2873
 
 * Results:
2874
 
 *     Returns TRUE if successful, and FALSE otherwise.
2875
 
 *
2876
 
 * Side effects:
2877
 
 *     None.
2878
 
 *
2879
 
 *------------------------------------------------------------------------------
2880
 
 */
2881
 
 
2882
 
Bool
2883
 
UnityPlatformSetDesktopActive(UnityPlatform *up,         // IN
2884
 
                              UnityDesktopId desktopId)  // IN
2885
 
{
2886
 
   ASSERT(up);
2887
 
 
2888
 
   /*
2889
 
    * Update the uwt with the new active desktop info.
2890
 
    */
2891
 
 
2892
 
   UnityWindowTracker_ChangeActiveDesktop(up->tracker, desktopId);
2893
 
 
2894
 
   if (desktopId >= up->desktopInfo.numDesktops) {
2895
 
      return FALSE;
2896
 
   }
2897
 
 
2898
 
   if (!up->rootWindows) {
2899
 
      /*
2900
 
       * We may not be into Unity mode yet, but we pretend it succeeded, and then do the
2901
 
       * switch later for real.
2902
 
       */
2903
 
      return TRUE;
2904
 
   }
2905
 
 
2906
 
   UnityX11SetCurrentDesktop(up, up->desktopInfo.unityDesktopToGuest[desktopId]);
2907
 
 
2908
 
   return TRUE;
2909
 
}
2910
 
 
2911
 
 
2912
 
/*
2913
 
 *-----------------------------------------------------------------------------
2914
 
 *
2915
 
 * UnityPlatformDoUpdate --
2916
 
 *
2917
 
 *      This function is used to (possibly asynchronously) collect Unity window
2918
 
 *      updates and send them to the host via the RPCI update channel.
2919
 
 *
2920
 
 * Results:
2921
 
 *      Updates will be collected.  Updates may be sent.
2922
 
 *
2923
 
 * Side effects:
2924
 
 *      None.
2925
 
 *
2926
 
 *-----------------------------------------------------------------------------
2927
 
 */
2928
 
 
2929
 
void
2930
 
UnityPlatformDoUpdate(UnityPlatform *up,        // IN:
2931
 
                      Bool incremental)         // IN: Incremental vs. full update
2932
 
{
2933
 
   ASSERT(up);
2934
 
   ASSERT(up->updateChannel);
2935
 
 
2936
 
   if (!incremental) {
2937
 
      UnityPlatformUpdateWindowState(up, up->tracker);
2938
 
   }
2939
 
 
2940
 
   UnityWindowTracker_RequestUpdates(up->tracker,
2941
 
                                     incremental ? UNITY_UPDATE_INCREMENTAL : 0,
2942
 
                                     &up->updateChannel->updates);
2943
 
 
2944
 
   /*
2945
 
    * Notify the host iff UnityWindowTracker_RequestUpdates pushed a valid
2946
 
    * update into the UpdateChannel buffer.
2947
 
    */
2948
 
   if (DynBuf_GetSize(&up->updateChannel->updates) > (up->updateChannel->cmdSize + 2)) {
2949
 
#ifdef VMX86_DEBUG
2950
 
      const char *dataBuf = DynBuf_Get(&up->updateChannel->updates);
2951
 
      size_t dataSize = DynBuf_GetSize(&up->updateChannel->updates);
2952
 
      ASSERT(dataBuf[up->updateChannel->cmdSize] != '\0');
2953
 
      ASSERT(dataBuf[dataSize - 1] == '\0');
2954
 
#endif
2955
 
 
2956
 
      /* The update must be double nul terminated. */
2957
 
      DynBuf_AppendString(&up->updateChannel->updates, "");
2958
 
 
2959
 
      if (!UnitySendUpdates(up->updateChannel)) {
2960
 
         /* XXX We should probably exit Unity. */
2961
 
         Debug("UPDATE TRANSMISSION FAILED! --------------------\n");
2962
 
         /*
2963
 
          * At this point, the update buffer contains a stream of updates
2964
 
          * terminated by a double nul. Rather than flush the input stream,
2965
 
          * let's "unseal" it by removing the second nul, allowing further
2966
 
          * updates to be appended and sent later.
2967
 
          */
2968
 
         DynBuf_SetSize(&up->updateChannel->updates,
2969
 
                        DynBuf_GetSize(&up->updateChannel->updates) - 1);
2970
 
      }
2971
 
   }
2972
 
}
2973
 
 
2974
 
 
2975
 
/*
2976
 
 *----------------------------------------------------------------------------
2977
 
 *
2978
 
 * Unity_UnityToLocalPoint --
2979
 
 *
2980
 
 *      Initializes localPt structure based on the input unityPt structure.
2981
 
 *      Translate point from Unity coordinate to local coordinate.
2982
 
 *
2983
 
 * Results:
2984
 
 *      None
2985
 
 *
2986
 
 * Side effects:
2987
 
 *      None
2988
 
 *----------------------------------------------------------------------------
2989
 
 */
2990
 
 
2991
 
void
2992
 
Unity_UnityToLocalPoint(UnityPoint *localPt, // IN/OUT
2993
 
                        UnityPoint *unityPt) // IN
2994
 
{
2995
 
   ASSERT(localPt);
2996
 
   ASSERT(unityPt);
2997
 
   localPt->x = unityPt->x;
2998
 
   localPt->y = unityPt->y;
2999
 
}
3000
 
 
3001
 
 
3002
 
/*
3003
 
 *----------------------------------------------------------------------------
3004
 
 *
3005
 
 * Unity_LocalToUnityPoint --
3006
 
 *
3007
 
 *      Initializes unityPt structure based on the input localPt structure.
3008
 
 *      Translate point from local coordinate to Unity coordinate.
3009
 
 *
3010
 
 * Results:
3011
 
 *      None
3012
 
 *
3013
 
 * Side effects:
3014
 
 *      None
3015
 
 *----------------------------------------------------------------------------
3016
 
 */
3017
 
 
3018
 
void
3019
 
Unity_LocalToUnityPoint(UnityPoint *unityPt, // IN/OUT
3020
 
                        UnityPoint *localPt) // IN
3021
 
{
3022
 
   ASSERT(unityPt);
3023
 
   ASSERT(localPt);
3024
 
   unityPt->x = localPt->x;
3025
 
   unityPt->y = localPt->y;
3026
 
}
3027
 
 
3028
 
 
3029
 
/*
3030
 
 ******************************************************************************
3031
 
 * UnityPlatformStickWindow --                                           */ /**
3032
 
 *
3033
 
 * @brief "Stick" a window to the desktop.
3034
 
 *
3035
 
 * @param[in] up       Platform context.
3036
 
 * @param[in] windowId Operand window.
3037
 
 *
3038
 
 * @retval TRUE  Success.
3039
 
 * @retval FALSE Failure.
3040
 
 *
3041
 
 ******************************************************************************
3042
 
 */
3043
 
 
3044
 
Bool
3045
 
UnityPlatformStickWindow(UnityPlatform *up,      // IN
3046
 
                         UnityWindowId windowId) // IN
3047
 
{
3048
 
   return SetWindowStickiness(up, windowId, TRUE);
3049
 
}
3050
 
 
3051
 
 
3052
 
/*
3053
 
 ******************************************************************************
3054
 
 * UnityPlatformUnstickWindow --                                         */ /**
3055
 
 *
3056
 
 * @brief "Unstick" a window from the desktop.
3057
 
 *
3058
 
 * @param[in] up       Platform context.
3059
 
 * @param[in] windowId Operand window.
3060
 
 *
3061
 
 * @retval TRUE  Success.
3062
 
 * @retval FALSE Failure.
3063
 
 *
3064
 
 ******************************************************************************
3065
 
 */
3066
 
 
3067
 
Bool
3068
 
UnityPlatformUnstickWindow(UnityPlatform *up,      // IN
3069
 
                           UnityWindowId windowId) // IN
3070
 
{
3071
 
   return SetWindowStickiness(up, windowId, FALSE);
3072
 
}
3073
 
 
3074
 
 
3075
 
/*
3076
 
 *-----------------------------------------------------------------------------
3077
 
 *
3078
 
 * UnityPlatformSetConfigDesktopColor --
3079
 
 *
3080
 
 *      Set the preferred desktop background color for use when in Unity Mode.
3081
 
 *
3082
 
 * Results:
3083
 
 *      None.
3084
 
 *
3085
 
 * Side effects:
3086
 
 *      None.
3087
 
 *
3088
 
 *-----------------------------------------------------------------------------
3089
 
 */
3090
 
 
3091
 
void
3092
 
UnityPlatformSetConfigDesktopColor(UnityPlatform *up, int desktopColor)
3093
 
{
3094
 
   ASSERT(up);
3095
 
}
3096
 
 
3097
 
 
3098
 
/*
3099
 
 *-----------------------------------------------------------------------------
3100
 
 *
3101
 
 * UnityPlatformRequestWindowContents --
3102
 
 *
3103
 
 *     Validate the list of supplied window IDs and once validated add them to a list
3104
 
 *     of windows whose contents should be sent to the host.
3105
 
 *
3106
 
 * Results:
3107
 
 *      None.
3108
 
 *
3109
 
 * Side effects:
3110
 
 *      None.
3111
 
 *
3112
 
 *-----------------------------------------------------------------------------
3113
 
 */
3114
 
 
3115
 
Bool
3116
 
UnityPlatformRequestWindowContents(UnityPlatform *up,
3117
 
                                   UnityWindowId windowIds[],
3118
 
                                   uint32 numWindowIds)
3119
 
{
3120
 
   ASSERT(up);
3121
 
 
3122
 
   /* Not implemented */
3123
 
   return FALSE;
3124
 
}
3125
 
 
3126
 
 
3127
 
/*
3128
 
 *-----------------------------------------------------------------------------
3129
 
 *
3130
 
 * UnityPlatformConfirmMinimizeOperation --
3131
 
 *
3132
 
 *     Minimize a window (if allowed) by the host.
3133
 
 *
3134
 
 * Results:
3135
 
 *     Returns TRUE if successful, and FALSE otherwise.
3136
 
 *
3137
 
 * Side effects:
3138
 
 *     None.
3139
 
 *
3140
 
 *------------------------------------------------------------------------------
3141
 
 */
3142
 
 
3143
 
Bool
3144
 
UnityPlatformConfirmMinimizeOperation(UnityPlatform *up,        // IN
3145
 
                                      UnityWindowId windowId,   // IN
3146
 
                                      uint32 sequence,          // IN
3147
 
                                      Bool allow)               // IN
3148
 
{
3149
 
   ASSERT(up);
3150
 
   return FALSE;
3151
 
}
3152
 
 
3153
 
 
3154
 
/*
3155
 
 *-----------------------------------------------------------------------------
3156
 
 *
3157
 
 * UnityPlatformSetInterlockMinimizeOperation --
3158
 
 *
3159
 
 *     Enable (or Disable) the interlocking (relaying) of minimize operations
3160
 
 *     through the host.
3161
 
 *
3162
 
 * Results:
3163
 
 *     None.
3164
 
 *
3165
 
 * Side effects:
3166
 
 *     None.
3167
 
 *
3168
 
 *------------------------------------------------------------------------------
3169
 
 */
3170
 
 
3171
 
void UnityPlatformSetInterlockMinimizeOperation(UnityPlatform *up,   // IN
3172
 
                                                Bool enabled)        // IN
3173
 
{
3174
 
   ASSERT(up);
3175
 
}
3176
 
 
3177
 
 
3178
 
/*
3179
 
 *------------------------------------------------------------------------------
3180
 
 *
3181
 
 * UnityPlatformWillRemoveWindow --
3182
 
 *
3183
 
 *    Called when a window is removed from the UnityWindowTracker.
3184
 
 *
3185
 
 *    NOTE: This function is called with the platform lock held.
3186
 
 *
3187
 
 * Results:
3188
 
 *    None.
3189
 
 *
3190
 
 * Side effects:
3191
 
 *    None.
3192
 
 *------------------------------------------------------------------------------
3193
 
 */
3194
 
 
3195
 
void
3196
 
UnityPlatformWillRemoveWindow(UnityPlatform *up,      // IN
3197
 
                              UnityWindowId windowId) // IN
3198
 
{
3199
 
   ASSERT(up);
3200
 
}
3201
 
 
3202
 
 
3203
 
/*
3204
 
 ******************************************************************************
3205
 
 * Begin file-scope functions.
3206
 
 *
3207
 
 */
3208
 
 
3209
 
 
3210
 
/*
3211
 
 ******************************************************************************
3212
 
 * GetRelevantWMWindow --                                                */ /**
3213
 
 *
3214
 
 * @brief Given a UnityWindowId, return the X11 window relevant to WM operations.
3215
 
 *
3216
 
 * Starting with a Unity window, look for and return its associated
3217
 
 * clientWindow.  If there is no clientWindow, then return the top-level window.
3218
 
 *
3219
 
 * @param[in]  up        Unity/X11 context.
3220
 
 * @param[in]  windowId  Window search for.
3221
 
 * @param[out] wmWindow  Set to the relevant X11 window.
3222
 
 *
3223
 
 * @todo Consider exporting this for use in unityPlatformX11Window.c.
3224
 
 *
3225
 
 * @retval TRUE  Relevant window found and recorded in @a wmWindow.
3226
 
 * @retval FALSE Unable to find @a windowId.
3227
 
 *
3228
 
 ******************************************************************************
3229
 
 */
3230
 
 
3231
 
static Bool
3232
 
GetRelevantWMWindow(UnityPlatform *up,          // IN
3233
 
                    UnityWindowId windowId,     // IN
3234
 
                    Window *wmWindow)           // OUT
3235
 
{
3236
 
   UnityPlatformWindow *upw;
3237
 
 
3238
 
   ASSERT(up);
3239
 
 
3240
 
   upw = UPWindow_Lookup(up, windowId);
3241
 
   if (!upw) {
3242
 
      return FALSE;
3243
 
   }
3244
 
 
3245
 
   *wmWindow = upw->clientWindow ? upw->clientWindow : upw->toplevelWindow;
3246
 
   return TRUE;
3247
 
}
3248
 
 
3249
 
 
3250
 
/*
3251
 
 ******************************************************************************
3252
 
 * SetWindowStickiness --                                                */ /**
3253
 
 *
3254
 
 * @brief Sets or clears a window's sticky state.
3255
 
 *
3256
 
 * @param[in] up         Unity/X11 context.
3257
 
 * @param[in] windowId   Operand window.
3258
 
 * @param[in] wantSticky Set to TRUE to stick a window, FALSE to unstick it.
3259
 
 *
3260
 
 * @retval TRUE  Request successfully sent to X server.
3261
 
 * @retval FALSE Request failed.
3262
 
 *
3263
 
 ******************************************************************************
3264
 
 */
3265
 
 
3266
 
static Bool
3267
 
SetWindowStickiness(UnityPlatform *up,          // IN
3268
 
                    UnityWindowId windowId,     // IN
3269
 
                    Bool wantSticky)            // IN
3270
 
{
3271
 
   GdkWindow *gdkWindow;
3272
 
   Window curWindow;
3273
 
 
3274
 
   ASSERT(up);
3275
 
 
3276
 
   if (!GetRelevantWMWindow(up, windowId, &curWindow)) {
3277
 
      Debug("%s: Lookup against window %#x failed.\n", __func__, windowId);
3278
 
      return FALSE;
3279
 
   }
3280
 
 
3281
 
   gdkWindow = gdk_window_foreign_new(curWindow);
3282
 
   if (gdkWindow == NULL) {
3283
 
      Debug("%s: Unable to create Gdk window?! (%#x)\n", __func__, windowId);
3284
 
      return FALSE;
3285
 
   }
3286
 
 
3287
 
   if (wantSticky) {
3288
 
      gdk_window_stick(gdkWindow);
3289
 
   } else {
3290
 
      gdk_window_unstick(gdkWindow);
3291
 
   }
3292
 
 
3293
 
   gdk_flush();
3294
 
   g_object_unref(G_OBJECT(gdkWindow));
3295
 
 
3296
 
   return TRUE;
3297
 
}
3298
 
 
3299
 
 
3300
 
/*
3301
 
 *
3302
 
 * End file-scope functions.
3303
 
 ******************************************************************************
3304
 
 */