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

« back to all changes in this revision

Viewing changes to lib/unity/unity.c

  • Committer: Bazaar Package Importer
  • Author(s): Devid Antonio Filoni
  • Date: 2008-08-15 21:21:40 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080815212140-05fhxj8wroosysmj
Tags: 2008.08.08-109361-1ubuntu1
* Merge from Debian unstable (LP: #258393), remaining Ubuntu change:
  - add ubuntu_toolchain_FTBFS.dpatch patch, fix FTBFS
* Update ubuntu_toolchain_FTBFS.dpatch patch for the new version.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*********************************************************
 
2
 * Copyright (C) 2007 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
 * Unity.c --
 
21
 *
 
22
 *    Unity window manager intergration tools service.
 
23
 *
 
24
 *    RPC Usage:
 
25
 *       unity.get.update [incremental]
 
26
 *
 
27
 *    The tools service response to requests for windows events via the
 
28
 *    "unity.get.update" RPC from the host.  Upon receiving the RPC, the
 
29
 *    service will crawl the window manager, taking note of the positions,
 
30
 *    window regions, etc for every window in the system.  The service
 
31
 *    will reply describing the current state.
 
32
 *
 
33
 *    If the intial request included the "incremental" argument, a list
 
34
 *    of all the changes to the windowing system  since the last
 
35
 *    unity.get.update request will be sent (e.g. if a window moves
 
36
 *    or has been destroyed).
 
37
 *
 
38
 *    If the "incremental" argument is not present, the entire state
 
39
 *    of the windowing system is returned.
 
40
 *
 
41
 *    The reply to the RPC is a double null terminated list of null
 
42
 *    terminated strings.  Each string in the list has one of the following
 
43
 *    formats:
 
44
 *
 
45
 *     add <windowid>
 
46
 *        A window with the specified integer windowid has just been
 
47
 *        created.
 
48
 *
 
49
 *     remove <windowid>
 
50
 *        The window with integer windowid has been removed.  Get rid of it.
 
51
 *
 
52
 *     move <windowid> <x1> <y1> <x2> <y2>
 
53
 *        The window with specified integer windowid has moved or resized
 
54
 *        such that its top left corner rests at x1,y1 and its bottom right
 
55
 *        at x2,y2.
 
56
 *
 
57
 *     region <windowid> <numrects>
 
58
 *        The window with specified windowid has a not-rectangular window
 
59
 *        region (e.g. the curved corner windows in Windows XP).  Immediately,
 
60
 *        after this messages are numrects messages with the following format:
 
61
 *
 
62
 *        rect <x1> <y1> <x2> <y2>
 
63
 *            Defines a rectangle in the coordinate system of the window
 
64
 *            for this region (not the coordinate system of the desktop!!)
 
65
 *
 
66
 *        The actual window region is the union of all the rectangles in the
 
67
 *        list.  A value of 0 for numrects indicates that the window region
 
68
 *        should be ignored (i.e. the window region is identical to the
 
69
 *        bounds of the window).
 
70
 *
 
71
 *     title <windowid> <title>
 
72
 *        A window with the specified integer windowid has just changed its
 
73
 *        title.
 
74
 *
 
75
 *     zorder <num windows> <window id 1> <window id 2> ... <window id n>
 
76
 *        Z order of windows from top to bottom(or front to rear)
 
77
 *
 
78
 *     attr <windowid> <attr> <enabled>
 
79
 *        The window with specified windowid has an attribute enabled/disabled.
 
80
 *
 
81
 *     type <windowid> <type>
 
82
 *        The window with specified windowid is of a certain type
 
83
 *
 
84
 *     icon <windowid> <icontype>
 
85
 *        The window with specified windowid has changed an icon of the specified
 
86
 *        type.
 
87
 *
 
88
 *     desktop <windowid> <desktopid>
 
89
 *        The window with specified windowid has been moved to a different desktop.
 
90
 *
 
91
 *     activedesktop <desktopid>
 
92
 *        The desktop with specified desktopid has become active.
 
93
 *
 
94
 *     The guest is also capable of pushing incremental updates to the VMX.
 
95
 *     When we enter Unity (upon getting "unity.enter" command from the VMX),
 
96
 *     start a separate Unity window update thread. This thread will gather
 
97
 *     window updates from the guest, and send them to the VMX (if there are
 
98
 *     any updates to be sent).
 
99
 *     The incremental updates will be sent using 'tools.unity.push.update' command.
 
100
 *
 
101
 */
 
102
 
 
103
#include "vmware.h"
 
104
#include "rpcin.h"
 
105
#include "rpcout.h"
 
106
#include "debug.h"
 
107
#include "util.h"
 
108
#include "strutil.h"
 
109
#include "region.h"
 
110
#include "unityWindowTracker.h"
 
111
#include "unityCommon.h"
 
112
#include "unity.h"
 
113
#include "unityPlatform.h"
 
114
#include "unityDebug.h"
 
115
 
 
116
#include <stdio.h>
 
117
 
 
118
/*
 
119
 * Singleton object for tracking the state of the service.
 
120
 */
 
121
typedef struct UnityState {
 
122
   UnityWindowTracker tracker;
 
123
   Bool forceEnable;
 
124
   Bool isEnabled;
 
125
   UnityVirtualDesktopArray virtDesktopArray;   // Virtual desktop configuration
 
126
 
 
127
   UnityPlatform *up; // Platform-specific state
 
128
} UnityState;
 
129
 
 
130
static UnityState unity;
 
131
 
 
132
 
 
133
/*
 
134
 * Helper Functions
 
135
 */
 
136
 
 
137
static void UnityUpdateCallbackFn(void *param, UnityUpdate *update);
 
138
static Bool UnityTcloGetUpdate(char const **result, size_t *resultLen, const char *name,
 
139
                               const char *args, size_t argsSize, void *clientData);
 
140
static Bool UnityTcloEnter(char const **result, size_t *resultLen, const char *name,
 
141
                           const char *args, size_t argsSize, void *clientData);
 
142
static Bool UnityTcloExit(char const **result, size_t *resultLen, const char *name,
 
143
                          const char *args, size_t argsSize, void *clientData);
 
144
static Bool UnityTcloGetWindowPath(char const **result, size_t *resultLen,
 
145
                                   const char *name, const char *args,
 
146
                                   size_t argsSize, void *clientData);
 
147
static Bool UnityTcloWindowCommand(char const **result,
 
148
                                   size_t *resultLen,
 
149
                                   const char *name,
 
150
                                   const char *args,
 
151
                                   size_t argsSize,
 
152
                                   void *clientData);
 
153
static Bool UnityTcloGetWindowContents(char const **result,
 
154
                                       size_t *resultLen,
 
155
                                       const char *name,
 
156
                                       const char *args,
 
157
                                       size_t argsSize,
 
158
                                       void *clientData);
 
159
static Bool UnityTcloGetIconData(char const **result,
 
160
                                 size_t *resultLen,
 
161
                                 const char *name,
 
162
                                 const char *args,
 
163
                                 size_t argsSize,
 
164
                                 void *clientData);
 
165
static Bool UnityTcloSetDesktopWorkArea(char const **result,
 
166
                                       size_t *resultLen,
 
167
                                       const char *name,
 
168
                                       const char *args,
 
169
                                       size_t argsSize,
 
170
                                       void *clientData);
 
171
static Bool UnityTcloSetTopWindowGroup(char const **result,
 
172
                                       size_t *resultLen,
 
173
                                       const char *name,
 
174
                                       const char *args,
 
175
                                       size_t argsSize,
 
176
                                       void *clientData);
 
177
static Bool UnityTcloShowTaskbar(char const **result,
 
178
                                 size_t *resultLen,
 
179
                                 const char *name,
 
180
                                 const char *args,
 
181
                                 size_t argsSize,
 
182
                                 void *clientData);
 
183
static Bool UnityTcloMoveResizeWindow(char const **result,
 
184
                                      size_t *resultLen,
 
185
                                      const char *name,
 
186
                                      const char *args,
 
187
                                      size_t argsSize,
 
188
                                      void *clientData);
 
189
static Bool UnityTcloSetDesktopConfig(char const **result,
 
190
                                      size_t *resultLen,
 
191
                                      const char *name,
 
192
                                      const char *args,
 
193
                                      size_t argsSize,
 
194
                                      void *clientData);
 
195
static Bool UnityTcloSetDesktopActive(char const **result,
 
196
                                      size_t *resultLen,
 
197
                                      const char *name,
 
198
                                      const char *args,
 
199
                                      size_t argsSize,
 
200
                                      void *clientData);
 
201
static Bool UnityTcloSetWindowDesktop(char const **result,
 
202
                                      size_t *resultLen,
 
203
                                      const char *name,
 
204
                                      const char *args,
 
205
                                      size_t argsSize,
 
206
                                      void *clientData);
 
207
 
 
208
 
 
209
/*
 
210
 * Dispatch table for Unity window commands. All commands performing actions on
 
211
 * guest unity windows go here.
 
212
 */
 
213
 
 
214
typedef struct {
 
215
   const char *name;
 
216
   Bool (*exec)(UnityPlatform *up, UnityWindowId window);
 
217
} UnityCommandElem;
 
218
 
 
219
static UnityCommandElem unityCommandTable[] = {
 
220
   { UNITY_RPC_WINDOW_RESTORE, UnityPlatformRestoreWindow },
 
221
   { UNITY_RPC_WINDOW_CLOSE, UnityPlatformCloseWindow },
 
222
   { UNITY_RPC_WINDOW_SHOW, UnityPlatformShowWindow },
 
223
   { UNITY_RPC_WINDOW_HIDE, UnityPlatformHideWindow },
 
224
   { UNITY_RPC_WINDOW_MINIMIZE, UnityPlatformMinimizeWindow },
 
225
   { UNITY_RPC_WINDOW_MAXIMIZE, UnityPlatformMaximizeWindow },
 
226
   { UNITY_RPC_WINDOW_UNMAXIMIZE, UnityPlatformUnmaximizeWindow },
 
227
   /* Add more commands and handlers above this. */
 
228
   { NULL, NULL }
 
229
};
 
230
 
 
231
/*
 
232
 * XXX:
 
233
 * According to Adar:
 
234
 *    "UnityTcloGetUpdate cannot return the contents of a DynBuf. This will leak
 
235
 *     the DynBuf's memory, since nobody at a lower level will ever free it.  It's
 
236
 *     a crappy interface, but we make due by using a static buffer to hold the
 
237
 *     results."
 
238
 *
 
239
 * We ideally would not use a static buffer because the maximum size of the
 
240
 * update is unknown.  To work around this, make the DynBuf returned in
 
241
 * UnityTcloGetUpdate file-global and recycle it across update requests.
 
242
 */
 
243
 
 
244
static DynBuf gTcloUpdate;
 
245
 
 
246
 
 
247
/*
 
248
 *----------------------------------------------------------------------------
 
249
 *
 
250
 * Unity_IsSupported --
 
251
 *
 
252
 *      Determine whether this guest supports unity.
 
253
 *
 
254
 * Results:
 
255
 *      TRUE if the guest supports Unity (i.e. if the guest is WinXP) or
 
256
 *      if the option to always enable unity was specified in the tools
 
257
 *      configuration file
 
258
 *      FALSE otherwise
 
259
 *
 
260
 * Side effects:
 
261
 *      None
 
262
 *
 
263
 *----------------------------------------------------------------------------
 
264
 */
 
265
 
 
266
Bool
 
267
Unity_IsSupported(void)
 
268
{
 
269
   return UnityPlatformIsSupported() || unity.forceEnable;
 
270
}
 
271
 
 
272
 
 
273
/*
 
274
 *-----------------------------------------------------------------------------
 
275
 *
 
276
 * Unity_Init  --
 
277
 *
 
278
 *     One time initialization stuff.
 
279
 *
 
280
 *
 
281
 * Results:
 
282
 *     None.
 
283
 *
 
284
 * Side effects:
 
285
 *     May register with the tools poll loop.
 
286
 *
 
287
 *-----------------------------------------------------------------------------
 
288
 */
 
289
 
 
290
void
 
291
Unity_Init(GuestApp_Dict *conf, // IN
 
292
           int* blockedWnd)     // IN
 
293
{
 
294
   Debug("Unity_Init\n");
 
295
 
 
296
   /*
 
297
    * Initialize the UnityWindowTracker object.  The uwt does all the actual work
 
298
    * of computing differences between two states of the windowing system.  The
 
299
    * callbacks we register here will fire when we request an update via
 
300
    * UnityWindowTracker_RequestUpdates.  See bora/lib/unityWindowTracker for more
 
301
    * information.
 
302
    */
 
303
   UnityWindowTracker_Init(&unity.tracker, UnityUpdateCallbackFn);
 
304
 
 
305
   /*
 
306
    * Initialize the host-specific portion of the unity service.
 
307
    */
 
308
   unity.up = UnityPlatformInit(&unity.tracker, blockedWnd);
 
309
 
 
310
   /*
 
311
    * Init our global dynbuf used to send results back.
 
312
    */
 
313
   DynBuf_Init(&gTcloUpdate);
 
314
 
 
315
   /*
 
316
    * If debugging has been enabled, initialize the debug module.  On Windows,
 
317
    * this will pop up a small HUD window which shows an echo of the current
 
318
    * state of the windowing system.
 
319
    */
 
320
   if (GuestApp_GetDictEntryBool(conf, "unity.debug")) {
 
321
      UnityDebug_Init(&unity.tracker);
 
322
   }
 
323
 
 
324
   /*
 
325
    * Check if the user specified the option to always enable unity regardless
 
326
    * of the guest OS type.
 
327
    */
 
328
 
 
329
   unity.forceEnable = GuestApp_GetDictEntryBool(conf, "unity.forceEnable");
 
330
   unity.isEnabled = FALSE;
 
331
 
 
332
   unity.virtDesktopArray.desktopCount = 0;
 
333
}
 
334
 
 
335
 
 
336
/*
 
337
 *-----------------------------------------------------------------------------
 
338
 *
 
339
 * Unity_Cleanup  --
 
340
 *
 
341
 *    Exit Unity and do final cleanup.
 
342
 *
 
343
 * Results:
 
344
 *    None.
 
345
 *
 
346
 * Side effects:
 
347
 *    None
 
348
 *
 
349
 *-----------------------------------------------------------------------------
 
350
 */
 
351
 
 
352
void
 
353
Unity_Cleanup(void)
 
354
{
 
355
   UnityPlatform *up;
 
356
 
 
357
   Debug("%s\n", __FUNCTION__);
 
358
 
 
359
   /*
 
360
    * Exit Unity.
 
361
    */
 
362
 
 
363
   Unity_Exit();
 
364
 
 
365
   /*
 
366
    * Do one-time final platform-specific cleanup.
 
367
    */
 
368
 
 
369
   up = unity.up;
 
370
   unity.up = NULL;
 
371
   UnityPlatformCleanup(up);
 
372
 
 
373
   UnityWindowTracker_Cleanup(&unity.tracker);
 
374
   DynBuf_Destroy(&gTcloUpdate);
 
375
}
 
376
 
 
377
 
 
378
/*
 
379
 *-----------------------------------------------------------------------------
 
380
 *
 
381
 * Unity_InitBackdoor  --
 
382
 *
 
383
 *    One time initialization stuff for the backdoor.
 
384
 *
 
385
 *
 
386
 * Results:
 
387
 *    None.
 
388
 *
 
389
 * Side effects:
 
390
 *    None.
 
391
 *
 
392
 *-----------------------------------------------------------------------------
 
393
 */
 
394
 
 
395
void
 
396
Unity_InitBackdoor(struct RpcIn *rpcIn)   // IN
 
397
{
 
398
   /*
 
399
    * Only register the callback if the guest is capable of supporting Unity.
 
400
    * This way, if the VMX/UI sends us a Unity request on a non-supported platform
 
401
    * (for whatever reason), we will reply with 'command not supported'.
 
402
    */
 
403
 
 
404
   if (Unity_IsSupported()) {
 
405
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_ENTER, UnityTcloEnter, NULL);
 
406
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_GET_UPDATE_FULL, UnityTcloGetUpdate, NULL);
 
407
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_GET_UPDATE_INCREMENTAL,
 
408
                             UnityTcloGetUpdate, NULL);
 
409
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_GET_WINDOW_PATH,
 
410
                             UnityTcloGetWindowPath, NULL);
 
411
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_WINDOW_RESTORE,
 
412
                             UnityTcloWindowCommand, NULL);
 
413
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_WINDOW_SETTOP,
 
414
                             UnityTcloSetTopWindowGroup, NULL);
 
415
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_WINDOW_CLOSE,
 
416
                             UnityTcloWindowCommand, NULL);
 
417
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_GET_WINDOW_CONTENTS,
 
418
                             UnityTcloGetWindowContents, NULL);
 
419
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_GET_ICON_DATA,
 
420
                             UnityTcloGetIconData, NULL);
 
421
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_DESKTOP_WORK_AREA_SET,
 
422
                             UnityTcloSetDesktopWorkArea, NULL);
 
423
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_SHOW_TASKBAR, UnityTcloShowTaskbar, NULL);
 
424
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_EXIT, UnityTcloExit, NULL);
 
425
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_WINDOW_MOVE_RESIZE,
 
426
                             UnityTcloMoveResizeWindow, NULL);
 
427
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_WINDOW_SHOW,
 
428
                             UnityTcloWindowCommand, NULL);
 
429
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_WINDOW_HIDE,
 
430
                             UnityTcloWindowCommand, NULL);
 
431
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_WINDOW_MINIMIZE,
 
432
                             UnityTcloWindowCommand, NULL);
 
433
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_WINDOW_MAXIMIZE,
 
434
                             UnityTcloWindowCommand, NULL);
 
435
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_WINDOW_UNMAXIMIZE,
 
436
                             UnityTcloWindowCommand, NULL);
 
437
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_DESKTOP_CONFIG_SET,
 
438
                             UnityTcloSetDesktopConfig, NULL);
 
439
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_DESKTOP_ACTIVE_SET,
 
440
                             UnityTcloSetDesktopActive, NULL);
 
441
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_WINDOW_DESKTOP_SET,
 
442
                             UnityTcloSetWindowDesktop, NULL);
 
443
   }
 
444
}
 
445
 
 
446
 
 
447
/*
 
448
 *-----------------------------------------------------------------------------
 
449
 *
 
450
 * Unity_SetActiveDnDDetWnd  --
 
451
 *
 
452
 *    Right now we have 2 Unity DnD full screen detection window, one for version
 
453
 *    2 or older, another for version 3 or newer. This function is to set active
 
454
 *    one according to host DnD version.
 
455
 *
 
456
 *    XXX Both full-screent window is still bottom-most and is showed all time
 
457
 *    during Unity mode. Another change is needed to change it to only show the
 
458
 *    window during guest->host DnD. Also the window should not be bottom-most,
 
459
 *    but dynamicly change z-order during DnD.
 
460
 *
 
461
 * Results:
 
462
 *    None.
 
463
 *
 
464
 * Side effects:
 
465
 *    None.
 
466
 *
 
467
 *-----------------------------------------------------------------------------
 
468
 */
 
469
 
 
470
void
 
471
Unity_SetActiveDnDDetWnd(UnityDnD *state)
 
472
{
 
473
   UnityPlatformSetActiveDnDDetWnd(unity.up, state);
 
474
}
 
475
 
 
476
 
 
477
/*
 
478
 *-----------------------------------------------------------------------------
 
479
 *
 
480
 * Unity_Exit  --
 
481
 *
 
482
 *    Called everytime we exit Unity. This function can be called when we are
 
483
 *    not in Unity mode. Right now it is called every time a 'reset' TCLO command
 
484
 *    is sent to the guest. Therefore, there's no guarantee that we were in the
 
485
 *    Unity mode when this function is called.
 
486
 *
 
487
 *    Try to do the following:
 
488
 *    Restore system settings if needed.
 
489
 *    Kills all unity helper threads if any are running.
 
490
 *    Hide the unity dnd detection window.
 
491
 *
 
492
 * Results:
 
493
 *    None.
 
494
 *
 
495
 * Side effects:
 
496
 *    Restores system settings since we are exiting Unity.
 
497
 *    Kills all unity helper threads if any.
 
498
 *    Hides the unity dnd detection window if needed.
 
499
 *
 
500
 *-----------------------------------------------------------------------------
 
501
 */
 
502
 
 
503
void
 
504
Unity_Exit(void)
 
505
{
 
506
   if (unity.isEnabled) {
 
507
      /* Hide full-screen detection window for Unity DnD. */
 
508
      UnityPlatformUpdateDnDDetWnd(unity.up, FALSE);
 
509
   
 
510
      /* Kill Unity helper threads. */
 
511
      UnityPlatformKillHelperThreads(unity.up);
 
512
   
 
513
      /* Restore previously saved user settings. */
 
514
      UnityPlatformRestoreSystemSettings(unity.up);
 
515
      
 
516
      unity.isEnabled = FALSE;
 
517
   }
 
518
}
 
519
 
 
520
 
 
521
/*
 
522
 *-----------------------------------------------------------------------------
 
523
 *
 
524
 * Unity_RegisterCaps  --
 
525
 *
 
526
 *    Called by the application (VMwareUser) to allow the unity subsystem to
 
527
 *    register its capabilities.
 
528
 *
 
529
 * Results:
 
530
 *    None.
 
531
 *
 
532
 * Side effects:
 
533
 *    None.
 
534
 *
 
535
 *-----------------------------------------------------------------------------
 
536
 */
 
537
 
 
538
void
 
539
Unity_RegisterCaps(void)
 
540
{
 
541
   /*
 
542
    * Send Unity capability.
 
543
    */
 
544
 
 
545
   if (!RpcOut_sendOne(NULL, NULL, UNITY_RPC_UNITY_CAP" %d",
 
546
                       Unity_IsSupported() ? 1 : 0)) {
 
547
      Debug("%s: could not set unity capability\n", __FUNCTION__);
 
548
   }
 
549
 
 
550
   /*
 
551
    * Register guest platform specific capabilities.
 
552
    */
 
553
 
 
554
   UnityPlatformRegisterCaps(unity.up);
 
555
}
 
556
 
 
557
 
 
558
/*
 
559
 *-----------------------------------------------------------------------------
 
560
 *
 
561
 * Unity_UnregisterCaps  --
 
562
 *
 
563
 *    Called by the application (VMwareUser) to allow the unity subsystem to
 
564
 *    unregister its capabilities.
 
565
 *
 
566
 * Results:
 
567
 *    None.
 
568
 *
 
569
 * Side effects:
 
570
 *    None.
 
571
 *
 
572
 *-----------------------------------------------------------------------------
 
573
 */
 
574
 
 
575
void
 
576
Unity_UnregisterCaps(void)
 
577
{
 
578
   /*
 
579
    * Unregister guest platform specific capabilities.
 
580
    */
 
581
 
 
582
   UnityPlatformUnregisterCaps(unity.up);
 
583
 
 
584
   /*
 
585
    * Unregister the unity capability.
 
586
    */
 
587
 
 
588
   if (!RpcOut_sendOne(NULL, NULL, UNITY_RPC_UNITY_CAP" 0")) {
 
589
      Debug("Failed to unregister Unity capability\n");
 
590
   }
 
591
}
 
592
 
 
593
 
 
594
/*
 
595
 *----------------------------------------------------------------------------
 
596
 *
 
597
 * UnityTcloEnter --
 
598
 *
 
599
 *     RPC handler for 'unity.enter'. Save and disable certain user
 
600
 *     settings. Start Unity updates thread and any other platform
 
601
 *     specific threads (like a thread that listens for
 
602
 *     the desktop switch event on Windows). Note that we first set
 
603
 *     the UI settings, and then start the threads. This way the UI
 
604
 *     settings take effect before we start sending Unity updates,
 
605
 *     so that we never send things like task bar (see bug 166085).
 
606
 *
 
607
 * Results:
 
608
 *     TRUE if helper threads were started.
 
609
 *     FALSE otherwise.
 
610
 *
 
611
 * Side effects:
 
612
 *     Certain UI system settings will be disabled.
 
613
 *     Unity update thread will be started.
 
614
 *     Any other platform specific helper threads will be started as well.
 
615
 *
 
616
 *----------------------------------------------------------------------------
 
617
 */
 
618
 
 
619
static Bool
 
620
UnityTcloEnter(char const **result,     // OUT
 
621
               size_t *resultLen,       // OUT
 
622
               const char *name,        // IN
 
623
               const char *args,        // IN
 
624
               size_t argsSize,         // ignored
 
625
               void *clientData)        // ignored
 
626
{
 
627
   Debug("%s\n", __FUNCTION__);
 
628
 
 
629
   if (!unity.isEnabled) {
 
630
      /* Save and disable certain user settings here. */
 
631
      UnityPlatformSaveSystemSettings(unity.up);
 
632
 
 
633
      /* Start Unity helper threads. */
 
634
      if (!UnityPlatformStartHelperThreads(unity.up)) {
 
635
 
 
636
         /*
 
637
          * If we couldn't start one or more helper threads,
 
638
          * we cannot enter Unity. Kill all running helper
 
639
          * threads and restore ui settings.
 
640
          */
 
641
 
 
642
         UnityPlatformKillHelperThreads(unity.up);
 
643
         UnityPlatformRestoreSystemSettings(unity.up);
 
644
         return RpcIn_SetRetVals(result, resultLen,
 
645
                                 "Could not start unity helper threads", FALSE);
 
646
      }
 
647
 
 
648
      /*
 
649
       * Show full-screen detection window for Unity DnD. It is a bottom-most (but
 
650
       * still in front of desktop) transparent detection window for guest->host DnD
 
651
       * as drop target. We need this window because:
 
652
       * 1. All active windows except desktop will be shown on host desktop and can
 
653
       *    accept DnD signal. This full-screen detection window will block any DnD signal
 
654
       *    (even mouse signal) to the desktop, which will fix bug 164880.
 
655
       * 2. With this full-screen but bottommost detection window, every time when user
 
656
       *    drag something out from active window, the dragEnter will always be immediately
 
657
       *    catched for Unity DnD.
 
658
       */
 
659
      UnityPlatformUpdateDnDDetWnd(unity.up, TRUE);
 
660
      unity.isEnabled = TRUE;
 
661
   }
 
662
 
 
663
   return RpcIn_SetRetVals(result, resultLen, "", TRUE);
 
664
}
 
665
 
 
666
 
 
667
/*
 
668
 *----------------------------------------------------------------------------
 
669
 *
 
670
 * UnityTcloExit --
 
671
 *
 
672
 *     RPC handler for 'unity.exit'.
 
673
 *
 
674
 * Results:
 
675
 *     Always TRUE.
 
676
 *
 
677
 * Side effects:
 
678
 *     Same as side effects of Unity_Exit().
 
679
 *
 
680
 *----------------------------------------------------------------------------
 
681
 */
 
682
 
 
683
static Bool
 
684
UnityTcloExit(char const **result,     // OUT
 
685
              size_t *resultLen,       // OUT
 
686
              const char *name,        // IN
 
687
              const char *args,        // IN
 
688
              size_t argsSize,         // ignored
 
689
              void *clientData)        // ignored
 
690
{
 
691
   Debug("UnityTcloExit.\n");
 
692
 
 
693
   Unity_Exit();
 
694
 
 
695
   return RpcIn_SetRetVals(result, resultLen, "", TRUE);
 
696
}
 
697
 
 
698
 
 
699
/*
 
700
 *----------------------------------------------------------------------------
 
701
 *
 
702
 * UnityTcloGetWindowInfo --
 
703
 *
 
704
 *     RPC handler for 'unity.get.window.info'. Get required window info
 
705
 *     and send it back to the VMX.
 
706
 *
 
707
 * Results:
 
708
 *     TRUE if everything is successful.
 
709
 *     FALSE otherwise.
 
710
 *
 
711
 * Side effects:
 
712
 *     None.
 
713
 *
 
714
 *----------------------------------------------------------------------------
 
715
 */
 
716
 
 
717
static Bool
 
718
UnityTcloGetWindowPath(char const **result,     // OUT
 
719
                       size_t *resultLen,       // OUT
 
720
                       const char *name,        // IN
 
721
                       const char *args,        // IN
 
722
                       size_t argsSize,         // ignored
 
723
                       void *clientData)        // ignored
 
724
 
 
725
{
 
726
   UnityWindowId window;
 
727
   DynBuf *buf = &gTcloUpdate;
 
728
   unsigned int index = 0;
 
729
   Bool ret = TRUE;
 
730
 
 
731
   Debug("UnityTcloGetWindowPath name:%s args:'%s'\n", name, args);
 
732
 
 
733
   /* Parse the command & window id.*/
 
734
 
 
735
   if (!StrUtil_GetNextIntToken(&window, &index, args, " ")) {
 
736
      Debug("UnityTcloGetWindowInfo: Invalid RPC arguments.\n");
 
737
      return RpcIn_SetRetVals(result, resultLen,
 
738
                              "Invalid arguments. Expected \"windowId\"",
 
739
                              FALSE);
 
740
   }
 
741
 
 
742
   Debug("UnityTcloGetWindowInfo: window %d\n", window);
 
743
 
 
744
   /*
 
745
    * Please note that the UnityPlatformGetWindowPath implementations assume that the
 
746
    * dynbuf passed in does not contain any existing data that needs to be appended to,
 
747
    * so this code should continue to accomodate that assumption.
 
748
    */
 
749
   DynBuf_SetSize(buf, 0);
 
750
   if (!UnityPlatformGetWindowPath(unity.up, window, buf)) {
 
751
      Debug("UnityTcloGetWindowInfo: Could not get window path.\n");
 
752
      return RpcIn_SetRetVals(result, resultLen,
 
753
                              "Could not get window path",
 
754
                              FALSE);
 
755
   }
 
756
 
 
757
   /*
 
758
    * Write the final result into the result out parameters and return!
 
759
    */
 
760
   *result = (char *)DynBuf_Get(buf);
 
761
   *resultLen = DynBuf_GetSize(buf);
 
762
 
 
763
   return ret;
 
764
}
 
765
 
 
766
 
 
767
/*
 
768
 *----------------------------------------------------------------------------
 
769
 *
 
770
 * UnityTcloWindowCommand --
 
771
 *
 
772
 *     RPC handler for 'unity.window.*' (excluding 'unity.window.settop')
 
773
 *
 
774
 * Results:
 
775
 *     TRUE if everything is successful.
 
776
 *     FALSE otherwise.
 
777
 *
 
778
 * Side effects:
 
779
 *     None.
 
780
 *
 
781
 *----------------------------------------------------------------------------
 
782
 */
 
783
 
 
784
static Bool
 
785
UnityTcloWindowCommand(char const **result,     // OUT
 
786
                       size_t *resultLen,       // OUT
 
787
                       const char *name,        // IN
 
788
                       const char *args,        // IN
 
789
                       size_t argsSize,         // ignored
 
790
                       void *clientData)        // ignored
 
791
{
 
792
   UnityWindowId window;
 
793
   unsigned int index = 0;
 
794
   unsigned int i;
 
795
 
 
796
   Debug("UnityTcloWindowCommand: name:%s args:'%s'\n", name, args);
 
797
 
 
798
   /* Parse the command & window id.*/
 
799
 
 
800
   if (!StrUtil_GetNextIntToken(&window, &index, args, " ")) {
 
801
      Debug("UnityTcloWindowCommand: Invalid RPC arguments.\n");
 
802
      return RpcIn_SetRetVals(result, resultLen,
 
803
                              "Invalid arguments. Expected \"windowId\"",
 
804
                              FALSE);
 
805
 
 
806
   }
 
807
 
 
808
   Debug("UnityTcloWindowCommand: %s window %d\n", name, window);
 
809
 
 
810
   for (i = 0; unityCommandTable[i].name != NULL; i++) {
 
811
      if (strcmp(unityCommandTable[i].name, name) == 0) {
 
812
         if (!unityCommandTable[i].exec(unity.up, window)) {
 
813
            Debug("Unity window command failed.\n");
 
814
            return RpcIn_SetRetVals(result, resultLen,
 
815
                                   "Could not execute window command",
 
816
                                   FALSE);
 
817
         } else {
 
818
            return RpcIn_SetRetVals(result, resultLen, "", TRUE);
 
819
         }
 
820
      }
 
821
   }
 
822
 
 
823
   return RpcIn_SetRetVals(result, resultLen, "Bad command", FALSE);
 
824
}
 
825
 
 
826
 
 
827
/*
 
828
 *----------------------------------------------------------------------------
 
829
 *
 
830
 * UnityTcloSetDesktopWorkArea --
 
831
 *
 
832
 *     RPC handler for 'unity.desktop.work_area.set'.
 
833
 *
 
834
 * Results:
 
835
 *     TRUE if everything is successful.
 
836
 *     FALSE otherwise.
 
837
 *
 
838
 * Side effects:
 
839
 *     None.
 
840
 *
 
841
 *----------------------------------------------------------------------------
 
842
 */
 
843
 
 
844
static Bool
 
845
UnityTcloSetDesktopWorkArea(char const **result,  // IN
 
846
                            size_t *resultLen,    // IN
 
847
                            const char *name,     // IN
 
848
                            const char *args,     // IN
 
849
                            size_t argsSize,      // IN
 
850
                            void *clientData)     // IN
 
851
{
 
852
   Bool success = FALSE;
 
853
   unsigned int count;
 
854
   unsigned int i;
 
855
   UnityRect *workAreas = NULL;
 
856
 
 
857
   /*
 
858
    * The argument string will look something like:
 
859
    *   <count> [ , <x> <y> <w> <h> ] * count.
 
860
    *
 
861
    * e.g.
 
862
    *    3 , 0 0 640 480 , 640 0 800 600 , 0 480 640 480
 
863
    */
 
864
 
 
865
   if (sscanf(args, "%u", &count) != 1) {
 
866
      return RpcIn_SetRetVals(result, resultLen,
 
867
                              "Invalid arguments. Expected \"count\"",
 
868
                              FALSE);
 
869
   }
 
870
 
 
871
   workAreas = (UnityRect *)malloc(sizeof *workAreas * count);
 
872
   if (!workAreas) {
 
873
      RpcIn_SetRetVals(result, resultLen,
 
874
                       "Failed to alloc buffer for work areas",
 
875
                       FALSE);
 
876
      goto out;
 
877
   }
 
878
 
 
879
   for (i = 0; i < count; i++) {
 
880
      args = strchr(args, ',');
 
881
      if (!args) {
 
882
         RpcIn_SetRetVals(result, resultLen,
 
883
                          "Expected comma separated display list",
 
884
                          FALSE);
 
885
         goto out;
 
886
      }
 
887
      args++; /* Skip past the , */
 
888
 
 
889
      if (sscanf(args, " %d %d %d %d ",
 
890
                 &workAreas[i].x, &workAreas[i].y,
 
891
                 &workAreas[i].width, &workAreas[i].height) != 4) {
 
892
         RpcIn_SetRetVals(result, resultLen,
 
893
                          "Expected x, y, w, h in display entry",
 
894
                          FALSE);
 
895
         goto out;
 
896
      }
 
897
   }
 
898
 
 
899
   if (!UnityPlatformSetDesktopWorkAreas(unity.up, workAreas, count)) {
 
900
      RpcIn_SetRetVals(result, resultLen,
 
901
                       "UnityPlatformSetDesktopWorkAreas failed",
 
902
                       FALSE);
 
903
      goto out;
 
904
   }
 
905
 
 
906
   success = RpcIn_SetRetVals(result, resultLen, "", TRUE);
 
907
 
 
908
out:
 
909
   free(workAreas);
 
910
   return success;
 
911
}
 
912
 
 
913
 
 
914
/*
 
915
 *----------------------------------------------------------------------------
 
916
 *
 
917
 * UnityTcloSetTopWindowGroup --
 
918
 *
 
919
 *     RPC handler for 'unity.window.settop'.
 
920
 *
 
921
 * Results:
 
922
 *     TRUE if everything is successful.
 
923
 *     FALSE otherwise.
 
924
 *
 
925
 * Side effects:
 
926
 *     None.
 
927
 *
 
928
 *----------------------------------------------------------------------------
 
929
 */
 
930
 
 
931
static Bool
 
932
UnityTcloSetTopWindowGroup(char const **result,     // OUT
 
933
                           size_t *resultLen,       // OUT
 
934
                           const char *name,        // IN
 
935
                           const char *args,        // IN
 
936
                           size_t argsSize,         // ignored
 
937
                           void *clientData)        // ignored
 
938
{
 
939
   UnityWindowId window;
 
940
   unsigned int index = 0;
 
941
   unsigned int windowCount = 0;
 
942
   UnityWindowId windows[UNITY_MAX_SETTOP_WINDOW_COUNT];
 
943
 
 
944
   Debug("%s: name:%s args:'%s'\n", __FUNCTION__, name, args);
 
945
 
 
946
   /* Parse the command & window ids.*/
 
947
 
 
948
   while (StrUtil_GetNextUintToken(&window, &index, args, " ")) {
 
949
      windows[windowCount] = window;
 
950
      windowCount++;
 
951
      if (windowCount == UNITY_MAX_SETTOP_WINDOW_COUNT) {
 
952
         Debug("%s: Too many windows.\n", __FUNCTION__);
 
953
         return RpcIn_SetRetVals(result, resultLen,
 
954
                                 "Invalid arguments. Too many windows",
 
955
                                 FALSE);
 
956
      }
 
957
   }
 
958
 
 
959
   if (windowCount == 0) {
 
960
      Debug("%s: Invalid RPC arguments.\n", __FUNCTION__);
 
961
      return RpcIn_SetRetVals(result, resultLen,
 
962
                              "Invalid arguments. Expected at least one windowId",
 
963
                              FALSE);
 
964
   }
 
965
 
 
966
   if (!UnityPlatformSetTopWindowGroup(unity.up, windows, windowCount)) {
 
967
      return RpcIn_SetRetVals(result, resultLen,
 
968
                              "Could not execute window command",
 
969
                              FALSE);
 
970
   }
 
971
 
 
972
   return RpcIn_SetRetVals(result, resultLen, "", TRUE);
 
973
}
 
974
 
 
975
 
 
976
/*
 
977
 *----------------------------------------------------------------------------
 
978
 *
 
979
 * UnityTcloGetUpdate --
 
980
 *
 
981
 *     RPC handler for 'unity.get.update'.  Ask the unity window tracker
 
982
 *     to give us an update (either incremental or non-incremental based
 
983
 *     on whether the 'incremental' arg is present) and send the result
 
984
 *     back to the VMX.
 
985
 *
 
986
 * Results:
 
987
 *     None.
 
988
 *
 
989
 * Side effects:
 
990
 *     Clearly.
 
991
 *
 
992
 *----------------------------------------------------------------------------
 
993
 */
 
994
 
 
995
static Bool
 
996
UnityTcloGetUpdate(char const **result,     // OUT
 
997
                   size_t *resultLen,       // OUT
 
998
                   const char *name,        // IN
 
999
                   const char *args,        // IN
 
1000
                   size_t argsSize,         // ignored
 
1001
                   void *clientData)        // ignored
 
1002
{
 
1003
   DynBuf *buf = &gTcloUpdate;
 
1004
   uint32 flags = 0;
 
1005
 
 
1006
   // Debug("UnityTcloGetUpdate name:%s args:'%s'", name, args);
 
1007
 
 
1008
   /*
 
1009
    * Specify incremental or non-incremetal updates based on whether or
 
1010
    * not the client set the "incremental" arg.
 
1011
    */
 
1012
   if (strstr(name, "incremental")) {
 
1013
      flags |= UNITY_UPDATE_INCREMENTAL;
 
1014
   }
 
1015
 
 
1016
   DynBuf_SetSize(buf, 0);
 
1017
 
 
1018
   UnityGetUpdateCommon(flags, buf);
 
1019
 
 
1020
   /*
 
1021
    * Write the final result into the result out parameters.
 
1022
    */
 
1023
   *result = (char *)DynBuf_Get(buf);
 
1024
   *resultLen = DynBuf_GetSize(buf);
 
1025
 
 
1026
   /*
 
1027
    * Give the debugger a crack to do something interesting at this point
 
1028
    */
 
1029
   UnityDebug_OnUpdate();
 
1030
 
 
1031
   return TRUE;
 
1032
}
 
1033
 
 
1034
 
 
1035
/*
 
1036
 *----------------------------------------------------------------------------
 
1037
 *
 
1038
 * UnityGetUpdateCommon --
 
1039
 *
 
1040
 *     Get the unity window update and append it to the specified output buffer.
 
1041
 *     This function can be called from two different threads: either from
 
1042
 *     the main thread that is trying to execute a TCLO command (unity.get.update)
 
1043
 *     or from the unity update thread that is gathering periodic updates and
 
1044
 *     pushes them to the VMX as needed (by calling 'tools.unity.push.update RPC).
 
1045
 *     Since this function can be called from two different threads, protect
 
1046
 *     the global unity singleton with locks.
 
1047
 *
 
1048
 * Results:
 
1049
 *     None.
 
1050
 *
 
1051
 * Side effects:
 
1052
 *     None.
 
1053
 *
 
1054
 *----------------------------------------------------------------------------
 
1055
 */
 
1056
 
 
1057
void
 
1058
UnityGetUpdateCommon(int flags,     //  IN: unity update flags
 
1059
                     DynBuf *buf)   //  IN/OUT: unity update buffer
 
1060
{
 
1061
 
 
1062
   ASSERT(buf);
 
1063
 
 
1064
   UnityPlatformLock(unity.up);
 
1065
 
 
1066
   /*
 
1067
    * Ask the guest to crawl the windowing system and push updates
 
1068
    * into the unity window tracker.  If the guest backend isn't able to get
 
1069
    * notification of destroyed windows, UnityPlatformUpdateWindowState will
 
1070
    * return TRUE, which is are signal to set the UNITY_UPDATE_REMOVE_UNTOUCHED
 
1071
    * flag.  This make the unity window tracker generate remove events for
 
1072
    * windows that it hasn't seen an update for since the last update
 
1073
    * request.
 
1074
    */
 
1075
   if (UnityPlatformUpdateWindowState(unity.up, &unity.tracker)) {
 
1076
      flags |= UNITY_UPDATE_REMOVE_UNTOUCHED;
 
1077
   }
 
1078
 
 
1079
   /*
 
1080
    * Generate the update string.  We'll accumulate updates in the DynBuf
 
1081
    * buf via the callbacks registered in Unity_Init().  Each update will
 
1082
    * append a null terminated string to buf.
 
1083
    */
 
1084
   UnityWindowTracker_RequestUpdates(&unity.tracker, flags, buf);
 
1085
 
 
1086
   UnityPlatformUnlock(unity.up);
 
1087
 
 
1088
   /*
 
1089
    * Write the final '\0' to the DynBuf to signal that we're all out of
 
1090
    * updates.
 
1091
    */
 
1092
   DynBuf_AppendString(buf, "");
 
1093
 
 
1094
   return;
 
1095
}
 
1096
 
 
1097
 
 
1098
/*
 
1099
 *----------------------------------------------------------------------------
 
1100
 *
 
1101
 * UnityUpdateCallbackFn --
 
1102
 *
 
1103
 *     Callback from the unity window tracker indicating something's
 
1104
 *     changed.
 
1105
 *
 
1106
 *     Write the update string into our dynbuf accumlating the update
 
1107
 *     and return.
 
1108
 *
 
1109
 * Results:
 
1110
 *     None.
 
1111
 *
 
1112
 * Side effects:
 
1113
 *     Clearly.
 
1114
 *
 
1115
 *----------------------------------------------------------------------------
 
1116
 */
 
1117
 
 
1118
void
 
1119
UnityUpdateCallbackFn(void *param,          // IN: dynbuf
 
1120
                      UnityUpdate *update)  // IN
 
1121
{
 
1122
   DynBuf *buf = (DynBuf *)param;
 
1123
   char data[1024];
 
1124
   int i, n, count = 0;
 
1125
   RegionPtr region;
 
1126
   char *titleUtf8 = NULL;
 
1127
 
 
1128
   switch (update->type) {
 
1129
 
 
1130
   case UNITY_UPDATE_ADD_WINDOW:
 
1131
      Str_Sprintf(data, sizeof data, "add %u", update->u.addWindow.id);
 
1132
      DynBuf_AppendString(buf, data);
 
1133
      break;
 
1134
 
 
1135
   case UNITY_UPDATE_MOVE_WINDOW:
 
1136
      Str_Sprintf(data, sizeof data, "move %u %d %d %d %d",
 
1137
                  update->u.moveWindow.id,
 
1138
                  update->u.moveWindow.rect.x1,
 
1139
                  update->u.moveWindow.rect.y1,
 
1140
                  update->u.moveWindow.rect.x2,
 
1141
                  update->u.moveWindow.rect.y2);
 
1142
      DynBuf_AppendString(buf, data);
 
1143
      break;
 
1144
 
 
1145
   case UNITY_UPDATE_REMOVE_WINDOW:
 
1146
      Str_Sprintf(data, sizeof data, "remove %u", update->u.removeWindow.id);
 
1147
      DynBuf_AppendString(buf, data);
 
1148
      break;
 
1149
 
 
1150
   case UNITY_UPDATE_CHANGE_WINDOW_REGION:
 
1151
      /*
 
1152
       * A null region indicates that the region should be deleted.
 
1153
       * Make sure we write "region <id> 0" for the reply.
 
1154
       */
 
1155
      region = update->u.changeWindowRegion.region;
 
1156
      if (region) {
 
1157
         count = REGION_NUM_RECTS(region);
 
1158
      }
 
1159
      Str_Sprintf(data, sizeof data, "region %u %d",
 
1160
                  update->u.changeWindowRegion.id, count);
 
1161
      DynBuf_AppendString(buf, data);
 
1162
 
 
1163
      for (i = 0; i < count; i++) {
 
1164
         BoxPtr p = REGION_RECTS(region) + i;
 
1165
         Str_Sprintf(data, sizeof data, "rect %d %d %d %d",
 
1166
                     p->x1, p->y1, p->x2, p->y2);
 
1167
         DynBuf_AppendString(buf, data);
 
1168
      }
 
1169
      break;
 
1170
 
 
1171
   case UNITY_UPDATE_CHANGE_WINDOW_TITLE:
 
1172
      titleUtf8 = DynBuf_Get(&update->u.changeWindowTitle.titleUtf8);
 
1173
 
 
1174
      if (titleUtf8 &&
 
1175
          (DynBuf_GetSize(&update->u.changeWindowTitle.titleUtf8) ==
 
1176
           strlen(titleUtf8) + 1)) {
 
1177
         Str_Sprintf(data, sizeof data, "title %u %s",
 
1178
                     update->u.changeWindowTitle.id,
 
1179
                     (const char*)titleUtf8);
 
1180
      } else {
 
1181
         Str_Sprintf(data, sizeof data, "title %u",
 
1182
                     update->u.changeWindowTitle.id);
 
1183
      }
 
1184
      DynBuf_AppendString(buf, data);
 
1185
      break;
 
1186
 
 
1187
   case UNITY_UPDATE_CHANGE_ZORDER:
 
1188
      n = Str_Snprintf(data, sizeof data, "zorder %d", update->u.zorder.count);
 
1189
      DynBuf_Append(buf, data, n);
 
1190
      for (i = 0; i < update->u.zorder.count; i++) {
 
1191
         n = Str_Snprintf(data, sizeof data, " %d", update->u.zorder.ids[i]);
 
1192
         DynBuf_Append(buf, data, n);
 
1193
      }
 
1194
      DynBuf_AppendString(buf, ""); // for appending NULL
 
1195
      break;
 
1196
 
 
1197
   case UNITY_UPDATE_CHANGE_WINDOW_STATE:
 
1198
      Str_Sprintf(data, sizeof data, "state %u %u",
 
1199
                  update->u.changeWindowState.id,
 
1200
                  update->u.changeWindowState.state);
 
1201
      DynBuf_AppendString(buf, data);
 
1202
      break;
 
1203
 
 
1204
   case UNITY_UPDATE_CHANGE_WINDOW_ATTRIBUTE:
 
1205
      Str_Sprintf(data, sizeof data, "attr %u %u %u",
 
1206
                  update->u.changeWindowAttribute.id,
 
1207
                  update->u.changeWindowAttribute.attr,
 
1208
                  update->u.changeWindowAttribute.value);
 
1209
      DynBuf_AppendString(buf, data);
 
1210
      break;
 
1211
 
 
1212
   case UNITY_UPDATE_CHANGE_WINDOW_TYPE:
 
1213
      Str_Sprintf(data, sizeof data, "type %u %d",
 
1214
                  update->u.changeWindowType.id,
 
1215
                  update->u.changeWindowType.winType);
 
1216
      DynBuf_AppendString(buf, data);
 
1217
      break;
 
1218
 
 
1219
   case UNITY_UPDATE_CHANGE_WINDOW_ICON:
 
1220
      Str_Sprintf(data, sizeof data, "icon %u %u",
 
1221
                  update->u.changeWindowIcon.id,
 
1222
                  update->u.changeWindowIcon.iconType);
 
1223
      DynBuf_AppendString(buf, data);
 
1224
      break;
 
1225
 
 
1226
   case UNITY_UPDATE_CHANGE_WINDOW_DESKTOP:
 
1227
      Str_Sprintf(data, sizeof data, "desktop %u %d",
 
1228
                  update->u.changeWindowDesktop.id,
 
1229
                  update->u.changeWindowDesktop.desktopId);
 
1230
      DynBuf_AppendString(buf, data);
 
1231
      break;
 
1232
 
 
1233
   case UNITY_UPDATE_CHANGE_ACTIVE_DESKTOP:
 
1234
      Str_Sprintf(data, sizeof data, "activedesktop %d",
 
1235
                  update->u.changeActiveDesktop.desktopId);
 
1236
      DynBuf_AppendString(buf, data);
 
1237
      break;
 
1238
 
 
1239
   default:
 
1240
      NOT_IMPLEMENTED();
 
1241
   }
 
1242
}
 
1243
 
 
1244
 
 
1245
/*
 
1246
 *-----------------------------------------------------------------------------
 
1247
 *
 
1248
 * UnityUpdateThreadInit --
 
1249
 *
 
1250
 *      Initialize the state for the update thread.
 
1251
 *
 
1252
 * Return value:
 
1253
 *      TRUE if all needed data was initialized.
 
1254
 *      FALSE otherwise
 
1255
 *
 
1256
 * Side effects:
 
1257
 *      RpcOut channel might be open.
 
1258
 *      Memory for the update buffer might be allocated.
 
1259
 *
 
1260
 *-----------------------------------------------------------------------------
 
1261
 */
 
1262
 
 
1263
Bool
 
1264
UnityUpdateThreadInit(UnityUpdateThreadData *updateData) // IN
 
1265
{
 
1266
   ASSERT(updateData);
 
1267
 
 
1268
   updateData->flags = UNITY_UPDATE_INCREMENTAL;
 
1269
   updateData->rpcOut = NULL;
 
1270
   updateData->cmdSize = 0;
 
1271
 
 
1272
   DynBuf_Init(&updateData->updates);
 
1273
   DynBuf_AppendString(&updateData->updates, UNITY_RPC_PUSH_UPDATE_CMD " ");
 
1274
 
 
1275
   /* Exclude the null. */
 
1276
   updateData->cmdSize = DynBuf_GetSize(&updateData->updates) - 1;
 
1277
 
 
1278
   updateData->rpcOut = RpcOut_Construct();
 
1279
   if (updateData->rpcOut == NULL) {
 
1280
      goto error;
 
1281
   }
 
1282
 
 
1283
   if (!RpcOut_start(updateData->rpcOut)) {
 
1284
      RpcOut_Destruct(updateData->rpcOut);
 
1285
      goto error;
 
1286
   }
 
1287
 
 
1288
   return TRUE;
 
1289
 
 
1290
error:
 
1291
   DynBuf_Destroy(&updateData->updates);
 
1292
 
 
1293
   return FALSE;
 
1294
}
 
1295
 
 
1296
 
 
1297
/*
 
1298
 *-----------------------------------------------------------------------------
 
1299
 *
 
1300
 * UnityUpdateThreadCleanup --
 
1301
 *
 
1302
 *      Cleanup the unity update thread state.
 
1303
 *
 
1304
 * Return value:
 
1305
 *      None.
 
1306
 *
 
1307
 * Side effects:
 
1308
 *      RpcOut channel will be closed.
 
1309
 *      Memory will be freed.
 
1310
 *
 
1311
 *-----------------------------------------------------------------------------
 
1312
 */
 
1313
 
 
1314
void
 
1315
UnityUpdateThreadCleanup(UnityUpdateThreadData *updateData) // IN
 
1316
{
 
1317
   ASSERT(updateData);
 
1318
 
 
1319
   if (updateData->rpcOut) {
 
1320
      RpcOut_stop(updateData->rpcOut);
 
1321
      RpcOut_Destruct(updateData->rpcOut);
 
1322
      updateData->rpcOut = NULL;
 
1323
 
 
1324
      DynBuf_Destroy(&updateData->updates); // Avoid double-free by guarding this as well
 
1325
   }
 
1326
}
 
1327
 
 
1328
 
 
1329
/*
 
1330
 *-----------------------------------------------------------------------------
 
1331
 *
 
1332
 * UnitySendUpdates --
 
1333
 *
 
1334
 *      Gather and send a round of unity updates. The caller is responsible
 
1335
 *      for gathering updates into updateData->updates buffer prior to the
 
1336
 *      function call. This function should only be called if there's data
 
1337
 *      in the update buffer to avoid sending empty update string to the VMX.
 
1338
 *
 
1339
 * Return value:
 
1340
 *      TRUE if the update was sent,
 
1341
 *      FALSE if something went wrong (an invalid RPC channel, for example).
 
1342
 *
 
1343
 * Side effects:
 
1344
 *      None.
 
1345
 *
 
1346
 *-----------------------------------------------------------------------------
 
1347
 */
 
1348
 
 
1349
Bool
 
1350
UnitySendUpdates(UnityUpdateThreadData *updateData) // IN
 
1351
{
 
1352
   char const *myReply;
 
1353
   size_t myRepLen;
 
1354
   Bool retry = FALSE;
 
1355
 
 
1356
   ASSERT(updateData);
 
1357
   ASSERT(updateData->rpcOut);
 
1358
 
 
1359
   /* Send 'tools.unity.push.update <updates>' to the VMX. */
 
1360
 
 
1361
retry_send:
 
1362
   if (!RpcOut_send(updateData->rpcOut,
 
1363
                    (char *)DynBuf_Get(&updateData->updates),
 
1364
                    DynBuf_GetSize(&updateData->updates),
 
1365
                    &myReply, &myRepLen)) {
 
1366
 
 
1367
      /*
 
1368
       * We could not send the RPC. If we haven't tried to reopen
 
1369
       * the channel, try to reopen and resend. If we already
 
1370
       * tried to resend, then it's time to give up. I hope that
 
1371
       * trying to resend once is enough.
 
1372
       */
 
1373
 
 
1374
      if (!retry) {
 
1375
         retry = TRUE;
 
1376
         Debug("%s: could not send rpc. Reopening channel.\n", __FUNCTION__);
 
1377
         RpcOut_stop(updateData->rpcOut);
 
1378
         if (!RpcOut_start(updateData->rpcOut)) {
 
1379
            Debug("%s: could not reopen rpc channel. Exiting...\n", __FUNCTION__);
 
1380
            return FALSE;
 
1381
         }
 
1382
         goto retry_send;
 
1383
 
 
1384
      } else {
 
1385
         Debug("%s: could not resend rpc. Giving up and exiting...\n", __FUNCTION__);
 
1386
         return FALSE;
 
1387
      }
 
1388
   }
 
1389
 
 
1390
   return TRUE;
 
1391
}
 
1392
 
 
1393
 
 
1394
/*
 
1395
 *----------------------------------------------------------------------------
 
1396
 *
 
1397
 * UnityTcloGetWindowContents --
 
1398
 *
 
1399
 *     RPC handler for 'unity.get.window.contents'. Suck the bits off the
 
1400
 *     window and return a .png image over the backdoor.
 
1401
 *
 
1402
 * Results:
 
1403
 *     TRUE if everything is successful.
 
1404
 *     FALSE otherwise.
 
1405
 *
 
1406
 * Side effects:
 
1407
 *     None.
 
1408
 *
 
1409
 *----------------------------------------------------------------------------
 
1410
 */
 
1411
 
 
1412
static Bool
 
1413
UnityTcloGetWindowContents(char const **result,     // OUT
 
1414
                           size_t *resultLen,       // OUT
 
1415
                           const char *name,        // IN
 
1416
                           const char *args,        // IN
 
1417
                           size_t argsSize,         // ignored
 
1418
                           void *clientData)        // ignored
 
1419
{
 
1420
   unsigned int window;
 
1421
   unsigned int index = 0;
 
1422
   DynBuf *imageData = &gTcloUpdate;
 
1423
 
 
1424
   Debug("UnityTcloGetWindowContents: name:%s args:'%s'\n", name, args);
 
1425
 
 
1426
   /*
 
1427
    * Parse the command & window id.
 
1428
    */
 
1429
   if (!StrUtil_GetNextIntToken(&window, &index, args, " ")) {
 
1430
      Debug("UnityTcloGetWindowContents: Invalid RPC arguments.\n");
 
1431
      return RpcIn_SetRetVals(result, resultLen,
 
1432
                              "failed: arguments. Expected \"windowId\"",
 
1433
                              FALSE);
 
1434
 
 
1435
   }
 
1436
   Debug("UnityTcloGetWindowContents: window %d\n", window);
 
1437
 
 
1438
   /*
 
1439
    * Read the contents of the window, compress it as a .png and
 
1440
    * send the .png back to the vmx as the RPC result.
 
1441
    */
 
1442
   DynBuf_SetSize(imageData, 0);
 
1443
   if (!UnityPlatformGetWindowContents(unity.up, window, imageData)) {
 
1444
      return RpcIn_SetRetVals(result, resultLen,
 
1445
                              "failed: Could not read window contents",
 
1446
                              FALSE);
 
1447
   }
 
1448
 
 
1449
   *result = (char *)DynBuf_Get(imageData);
 
1450
   *resultLen = DynBuf_GetSize(imageData);
 
1451
 
 
1452
   return TRUE;
 
1453
}
 
1454
 
 
1455
 
 
1456
/*
 
1457
 *----------------------------------------------------------------------------
 
1458
 *
 
1459
 * UnityTcloGetIconData --
 
1460
 *
 
1461
 *     RPC handler for 'unity.get.icon.data'. Suck the bits off the
 
1462
 *     window and return a .png image over the backdoor.
 
1463
 *
 
1464
 * Results:
 
1465
 *     TRUE if everything is successful.
 
1466
 *     FALSE otherwise.
 
1467
 *
 
1468
 * Side effects:
 
1469
 *     None.
 
1470
 *
 
1471
 *----------------------------------------------------------------------------
 
1472
 */
 
1473
 
 
1474
static Bool
 
1475
UnityTcloGetIconData(char const **result,     // OUT
 
1476
                     size_t *resultLen,       // OUT
 
1477
                     const char *name,        // IN
 
1478
                     const char *args,        // IN
 
1479
                     size_t argsSize,         // ignored
 
1480
                     void *clientData)        // ignored
 
1481
{
 
1482
   UnityWindowId window;
 
1483
   UnityIconType iconType;
 
1484
   UnityIconSize iconSize;
 
1485
   unsigned int dataOffset, dataLength;
 
1486
   uint32 fullLength;
 
1487
   size_t retLength;
 
1488
   DynBuf *results = &gTcloUpdate, imageData;
 
1489
   char data[1024];
 
1490
 
 
1491
   Debug("UnityTcloGetIconData: name:%s args:'%s'\n", name, args);
 
1492
 
 
1493
   /*
 
1494
    * Parse the arguments.
 
1495
    */
 
1496
   if ((sscanf(args, "%u %u %u %u %u",
 
1497
               &window,
 
1498
               &iconType,
 
1499
               &iconSize,
 
1500
               &dataOffset,
 
1501
               &dataLength) != 5)
 
1502
       || (dataLength > UNITY_MAX_ICON_DATA_CHUNK)) {
 
1503
      Debug("UnityTcloGetIconData: Invalid RPC arguments.\n");
 
1504
      return RpcIn_SetRetVals(result, resultLen,
 
1505
                              "failed: arguments missing",
 
1506
                              FALSE);
 
1507
   }
 
1508
 
 
1509
   Debug("%s: window %u iconType %u" \
 
1510
         " iconSize %u dataOffset %u dataLength %u\n",
 
1511
         __FUNCTION__,
 
1512
         window, iconType, iconSize, dataOffset, dataLength);
 
1513
 
 
1514
   /*
 
1515
    * Retrieve part/all of the icon in PNG format.
 
1516
    */
 
1517
   DynBuf_Init(&imageData);
 
1518
   if (!UnityPlatformGetIconData(unity.up, window, iconType, iconSize,
 
1519
                                 dataOffset, dataLength, &imageData, &fullLength)) {
 
1520
      return RpcIn_SetRetVals(result, resultLen,
 
1521
                              "failed: Could not read icon data properly",
 
1522
                              FALSE);
 
1523
   }
 
1524
 
 
1525
 
 
1526
   DynBuf_SetSize(results, 0);
 
1527
   retLength = DynBuf_GetSize(&imageData);
 
1528
   retLength = MIN(retLength, UNITY_MAX_ICON_DATA_CHUNK);
 
1529
   DynBuf_Append(results, data, Str_Snprintf(data, sizeof data, "%u %" FMTSZ "u ",
 
1530
                                             fullLength, retLength));
 
1531
   DynBuf_Append(results, DynBuf_Get(&imageData), retLength);
 
1532
 
 
1533
   /*
 
1534
    * Guarantee that the results have a trailing \0 in case anything does a strlen...
 
1535
    */
 
1536
   DynBuf_AppendString(results, "");
 
1537
   *result = (char *)DynBuf_Get(results);
 
1538
   *resultLen = DynBuf_GetSize(results);
 
1539
   DynBuf_Destroy(&imageData);
 
1540
 
 
1541
   return TRUE;
 
1542
}
 
1543
 
 
1544
 
 
1545
/*
 
1546
 *----------------------------------------------------------------------------
 
1547
 *
 
1548
 * UnityTcloShowTaskbar --
 
1549
 *
 
1550
 *     RPC handler for 'unity.show.taskbar'.
 
1551
 *
 
1552
 * Results:
 
1553
 *     TRUE if everything is successful.
 
1554
 *     FALSE otherwise.
 
1555
 *
 
1556
 * Side effects:
 
1557
 *     None.
 
1558
 *
 
1559
 *----------------------------------------------------------------------------
 
1560
 */
 
1561
 
 
1562
static Bool
 
1563
UnityTcloShowTaskbar(char const **result,     // OUT
 
1564
                     size_t *resultLen,       // OUT
 
1565
                     const char *name,        // IN
 
1566
                     const char *args,        // IN
 
1567
                     size_t argsSize,         // IN: Size of args
 
1568
                     void *clientData)        // ignored
 
1569
{
 
1570
   uint32 command = 0;
 
1571
   unsigned int index = 0;
 
1572
 
 
1573
   Debug("%s: name:%s args:'%s'\n", __FUNCTION__, name, args);
 
1574
 
 
1575
   if (!StrUtil_GetNextUintToken(&command, &index, args, " ")) {
 
1576
      Debug("%s: Invalid RPC arguments.\n", __FUNCTION__);
 
1577
      return RpcIn_SetRetVals(result, resultLen,
 
1578
                              "Invalid arguments.",
 
1579
                              FALSE);
 
1580
   }
 
1581
 
 
1582
   Debug("%s: command %d\n", __FUNCTION__, command);
 
1583
 
 
1584
   UnityPlatformShowTaskbar(unity.up, (command == 0) ? FALSE : TRUE);
 
1585
 
 
1586
   return RpcIn_SetRetVals(result, resultLen, "", TRUE);
 
1587
}
 
1588
 
 
1589
 
 
1590
/*
 
1591
 *----------------------------------------------------------------------------
 
1592
 *
 
1593
 * UnityTcloMoveResizeWindow --
 
1594
 *
 
1595
 *     RPC handler for 'unity.window.move_resize'.
 
1596
 *
 
1597
 * Results:
 
1598
 *     TRUE if everything is successful.
 
1599
 *     FALSE otherwise.
 
1600
 *     If successful adds null terminated strings for each output coordinates.
 
1601
 *
 
1602
 * Side effects:
 
1603
 *     None.
 
1604
 *
 
1605
 *----------------------------------------------------------------------------
 
1606
 */
 
1607
 
 
1608
static Bool
 
1609
UnityTcloMoveResizeWindow(char const **result,     // OUT
 
1610
                          size_t *resultLen,       // OUT
 
1611
                          const char *name,        // IN
 
1612
                          const char *args,        // IN
 
1613
                          size_t argsSize,         // IN: Size of args
 
1614
                          void *clientData)        // ignored
 
1615
{
 
1616
   DynBuf *buf = &gTcloUpdate;
 
1617
   UnityWindowId window;
 
1618
   UnityRect moveResizeRect = {0};
 
1619
   char temp[1024];
 
1620
 
 
1621
   Debug("%s: name:%s args:'%s'\n", __FUNCTION__, name, args);
 
1622
 
 
1623
   if (sscanf(args, "%u %d %d %d %d",
 
1624
              &window,
 
1625
              &moveResizeRect.x,
 
1626
              &moveResizeRect.y,
 
1627
              &moveResizeRect.width,
 
1628
              &moveResizeRect.height) != 5) {
 
1629
      Debug("%s: Invalid RPC arguments.\n", __FUNCTION__);
 
1630
      return RpcIn_SetRetVals(result, resultLen,
 
1631
                              "Invalid arguments.",
 
1632
                              FALSE);
 
1633
   }
 
1634
 
 
1635
   if (!UnityPlatformMoveResizeWindow(unity.up, window, &moveResizeRect)) {
 
1636
      Debug("%s: Could not read window coordinates.\n", __FUNCTION__);
 
1637
      return RpcIn_SetRetVals(result, resultLen,
 
1638
                              "Could not read window coordinates",
 
1639
                              FALSE);
 
1640
   }
 
1641
 
 
1642
   /*
 
1643
    *  Send back the new (post move/resize operation) window coordinates.
 
1644
    */
 
1645
 
 
1646
   DynBuf_SetSize(buf, 0);
 
1647
   Str_Sprintf(temp, sizeof temp, "%d %d %d %d", moveResizeRect.x,
 
1648
               moveResizeRect.y, moveResizeRect.width, moveResizeRect.height);
 
1649
   DynBuf_AppendString(buf, temp);
 
1650
 
 
1651
   /*
 
1652
    * Write the final result into the result out parameters and return!
 
1653
    */
 
1654
 
 
1655
   *result = (char *)DynBuf_Get(buf);
 
1656
   *resultLen = DynBuf_GetSize(buf);
 
1657
 
 
1658
   return TRUE;
 
1659
}
 
1660
 
 
1661
 
 
1662
/*
 
1663
 *----------------------------------------------------------------------------
 
1664
 *
 
1665
 * UnityTcloSetDesktopConfig --
 
1666
 *
 
1667
 *     RPC handler for 'unity.set.desktop.config'.
 
1668
 *
 
1669
 * Results:
 
1670
 *     TRUE if everything is successful.
 
1671
 *     FALSE otherwise.
 
1672
 *
 
1673
 * Side effects:
 
1674
 *     Might change virtual desktop configuration in the guest.
 
1675
 *
 
1676
 *----------------------------------------------------------------------------
 
1677
 */
 
1678
 
 
1679
static Bool
 
1680
UnityTcloSetDesktopConfig(char const **result,  // OUT
 
1681
                          size_t *resultLen,    // OUT
 
1682
                          const char *name,     // IN
 
1683
                          const char *args,     // IN
 
1684
                          size_t argsSize,      // IN
 
1685
                          void *clientData)     // IN: ignored
 
1686
{
 
1687
   unsigned int index = 0;
 
1688
   char *desktopStr = NULL;
 
1689
   char *errorMsg;
 
1690
 
 
1691
   Debug("%s: name:%s args:'%s'\n", __FUNCTION__, name, args);
 
1692
 
 
1693
   if (argsSize == 0) {
 
1694
      errorMsg = "Invalid arguments: desktop config is expected";
 
1695
      goto error;
 
1696
   }
 
1697
 
 
1698
   unity.virtDesktopArray.desktopCount = 0;
 
1699
   /* Read the virtual desktop configuration. */
 
1700
   while ((desktopStr = StrUtil_GetNextToken(&index, args, " ")) != NULL) {
 
1701
      UnityVirtualDesktop desktop;
 
1702
      uint32 desktopCount = unity.virtDesktopArray.desktopCount;
 
1703
 
 
1704
      int res = sscanf(desktopStr, "{%d,%d}", &desktop.x, &desktop.y);
 
1705
      free(desktopStr);
 
1706
      if (res == 2) {
 
1707
         if (desktopCount >= MAX_VIRT_DESK - 1) {
 
1708
            errorMsg = "Invalid arguments: too many desktops";
 
1709
            goto error;
 
1710
         }
 
1711
         unity.virtDesktopArray.desktops[desktopCount] = desktop;
 
1712
         unity.virtDesktopArray.desktopCount++;
 
1713
      } else {
 
1714
         errorMsg = "Invalid arguments: invalid desktop config";
 
1715
         goto error;
 
1716
      }
 
1717
   }
 
1718
 
 
1719
   /*
 
1720
    * Call the platform specific function to set the desktop configuration.
 
1721
    */
 
1722
 
 
1723
   if (!UnityPlatformSetDesktopConfig(unity.up, &unity.virtDesktopArray)) {
 
1724
      errorMsg = "Could not set desktop configuration";
 
1725
      goto error;
 
1726
   }
 
1727
 
 
1728
   return RpcIn_SetRetVals(result, resultLen,
 
1729
                           "",
 
1730
                           TRUE);
 
1731
error:
 
1732
   unity.virtDesktopArray.desktopCount = 0;
 
1733
   Debug("%s: %s\n", __FUNCTION__, errorMsg);
 
1734
 
 
1735
   return RpcIn_SetRetVals(result, resultLen,
 
1736
                           errorMsg,
 
1737
                           FALSE);
 
1738
}
 
1739
 
 
1740
 
 
1741
/*
 
1742
 *----------------------------------------------------------------------------
 
1743
 *
 
1744
 * UnityTcloSetDesktopActive --
 
1745
 *
 
1746
 *     RPC handler for 'unity.set.desktop.active'.
 
1747
 *
 
1748
 * Results:
 
1749
 *     TRUE if everything is successful.
 
1750
 *     FALSE otherwise.
 
1751
 *
 
1752
 * Side effects:
 
1753
 *     Might change the active virtual desktop in the guest.
 
1754
 *
 
1755
 *----------------------------------------------------------------------------
 
1756
 */
 
1757
 
 
1758
static Bool
 
1759
UnityTcloSetDesktopActive(char const **result,  // OUT
 
1760
                          size_t *resultLen,    // OUT
 
1761
                          const char *name,     // IN
 
1762
                          const char *args,     // IN
 
1763
                          size_t argsSize,      // IN
 
1764
                          void *clientData)     // IN: ignored
 
1765
{
 
1766
   UnityDesktopId desktopId = 0;
 
1767
   char *errorMsg;
 
1768
 
 
1769
   Debug("%s: name:%s args:'%s'\n", __FUNCTION__, name, args);
 
1770
 
 
1771
   if (sscanf(args, " %d", &desktopId) != 1) {
 
1772
      errorMsg = "Invalid arguments: expected \"desktopId\"";
 
1773
      goto error;
 
1774
   }
 
1775
 
 
1776
   if (desktopId >= unity.virtDesktopArray.desktopCount) {
 
1777
      errorMsg = "Desktop does not exist in the guest";
 
1778
      goto error;
 
1779
   }
 
1780
 
 
1781
   /*
 
1782
    * Call the platform specific function to set the desktop active.
 
1783
    */
 
1784
 
 
1785
   if (!UnityPlatformSetDesktopActive(unity.up, desktopId)) {
 
1786
      errorMsg = "Could not set active desktop";
 
1787
      goto error;
 
1788
   }
 
1789
 
 
1790
   /*
 
1791
    * Update the uwt with the new active desktop info.
 
1792
    */
 
1793
 
 
1794
   UnityWindowTracker_ChangeActiveDesktop(&unity.tracker, desktopId);
 
1795
 
 
1796
   return RpcIn_SetRetVals(result, resultLen,
 
1797
                           "",
 
1798
                           TRUE);
 
1799
error:
 
1800
   Debug("%s: %s\n", __FUNCTION__, errorMsg);
 
1801
   return RpcIn_SetRetVals(result, resultLen,
 
1802
                           errorMsg,
 
1803
                           FALSE);
 
1804
}
 
1805
 
 
1806
 
 
1807
/*
 
1808
 *----------------------------------------------------------------------------
 
1809
 *
 
1810
 * UnityTcloSetWindowDesktop --
 
1811
 *
 
1812
 *     RPC handler for 'unity.set.window.desktop'.
 
1813
 *
 
1814
 * Results:
 
1815
 *     TRUE if everything is successful.
 
1816
 *     FALSE otherwise.
 
1817
 *
 
1818
 * Side effects:
 
1819
 *     Might change the active virtual desktop in the guest.
 
1820
 *
 
1821
 *----------------------------------------------------------------------------
 
1822
 */
 
1823
 
 
1824
static Bool
 
1825
UnityTcloSetWindowDesktop(char const **result,  // OUT
 
1826
                          size_t *resultLen,    // OUT
 
1827
                          const char *name,     // IN
 
1828
                          const char *args,     // IN
 
1829
                          size_t argsSize,      // IN
 
1830
                          void *clientData)     // IN: ignored
 
1831
{
 
1832
   UnityWindowId windowId;
 
1833
   uint32 desktopId = 0;
 
1834
   char *errorMsg;
 
1835
 
 
1836
   Debug("%s: name:%s args:'%s'\n", __FUNCTION__, name, args);
 
1837
 
 
1838
   if (sscanf(args, " %u %d", &windowId, &desktopId) != 2) {
 
1839
      errorMsg = "Invalid arguments: expected \"windowId desktopId\"";
 
1840
      goto error;
 
1841
   }
 
1842
 
 
1843
   if (desktopId >= unity.virtDesktopArray.desktopCount) {
 
1844
      errorMsg = "The desktop does not exist in the guest";
 
1845
      goto error;
 
1846
   }
 
1847
 
 
1848
   /*
 
1849
    * Call the platform specific function to move the window to the
 
1850
    * specified desktop.
 
1851
    */
 
1852
 
 
1853
   if (!UnityPlatformSetWindowDesktop(unity.up, windowId, desktopId)) {
 
1854
      errorMsg = "Could not move the window to the desktop";
 
1855
      goto error;
 
1856
   }
 
1857
 
 
1858
   UnityWindowTracker_ChangeWindowDesktop(&unity.tracker, windowId, desktopId);
 
1859
 
 
1860
   return RpcIn_SetRetVals(result, resultLen,
 
1861
                           "",
 
1862
                           TRUE);
 
1863
error:
 
1864
   Debug("%s: %s\n", __FUNCTION__, errorMsg);
 
1865
   return RpcIn_SetRetVals(result, resultLen,
 
1866
                           errorMsg,
 
1867
                           FALSE);
 
1868
}