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

« back to all changes in this revision

Viewing changes to lib/unity/unity.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 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 unity.c
21
 
 *
22
 
 *    Unity: Guest window manager integration service.
23
 
 *
24
 
 * This file implements the guest-side Unity agent as part of the VMware Tools.
25
 
 * It contains entry points for embedding within the VMware Tools User Agent and
26
 
 * handles the GuestRpc (TCLO, RPCI) interface.
27
 
 *
28
 
 * UnityWindowTracker updates are sent to the MKS in two ways:
29
 
 *    @li @ref UNITY_RPC_GET_UPDATE GuestRpc (host-to-guest).
30
 
 *    @li @ref UNITY_RPC_PUSH_UPDATE_CMD GuestRpc (guest-to-host).
31
 
 *
32
 
 * @note Looking for the old "unity.get.update" return syntax?  See @ref
33
 
 * UNITY_RPC_GET_UPDATE and @ref UnityGetUpdateReturn instead.
34
 
 *
35
 
 * @sa
36
 
 *    @li UnityRpcHG
37
 
 *    @li UnityRpcGH
38
 
 */
39
 
 
40
 
#include "vmware.h"
41
 
#include "rpcin.h"
42
 
#include "rpcout.h"
43
 
#include "debug.h"
44
 
#include "util.h"
45
 
#include "strutil.h"
46
 
#include "region.h"
47
 
#include "unityWindowTracker.h"
48
 
#include "unityCommon.h"
49
 
#include "unity.h"
50
 
#include "unityPlatform.h"
51
 
#include "unityDebug.h"
52
 
#include "dynxdr.h"
53
 
#include "guestrpc/unity.h"
54
 
#include "guestrpc/unityActive.h"
55
 
#include "guestrpc/unity.h"
56
 
#include "appUtil.h"
57
 
#include "xdrutil.h"
58
 
#include <stdio.h>
59
 
 
60
 
 
61
 
/*
62
 
 * Singleton object for tracking the state of the service.
63
 
 */
64
 
typedef struct UnityState {
65
 
   UnityWindowTracker tracker;
66
 
   Bool forceEnable;
67
 
   Bool isEnabled;
68
 
   uint32 currentOptions;                       // Last feature mask received via 'set.options'
69
 
   UnityVirtualDesktopArray virtDesktopArray;   // Virtual desktop configuration
70
 
   UnityUpdateChannel updateChannel;            // Unity update transmission channel.
71
 
   UnityPlatform *up; // Platform-specific state
72
 
} UnityState;
73
 
 
74
 
static UnityState unity;
75
 
 
76
 
static GuestCapabilities unityCaps[] = {
77
 
   UNITY_CAP_STATUS_UNITY_ACTIVE
78
 
};
79
 
 
80
 
 
81
 
/*
82
 
 * Helper Functions
83
 
 */
84
 
 
85
 
static Bool UnityUpdateState(void);
86
 
static void UnityUpdateCallbackFn(void *param, UnityUpdate *update);
87
 
static Bool UnityTcloGetUpdate(char const **result, size_t *resultLen, const char *name,
88
 
                               const char *args, size_t argsSize, void *clientData);
89
 
static Bool UnityTcloEnter(char const **result, size_t *resultLen, const char *name,
90
 
                           const char *args, size_t argsSize, void *clientData);
91
 
static Bool UnityTcloExit(char const **result, size_t *resultLen, const char *name,
92
 
                          const char *args, size_t argsSize, void *clientData);
93
 
static Bool UnityTcloGetWindowPath(char const **result, size_t *resultLen,
94
 
                                   const char *name, const char *args,
95
 
                                   size_t argsSize, void *clientData);
96
 
static Bool UnityTcloWindowCommand(char const **result,
97
 
                                   size_t *resultLen,
98
 
                                   const char *name,
99
 
                                   const char *args,
100
 
                                   size_t argsSize,
101
 
                                   void *clientData);
102
 
static Bool UnityTcloGetWindowContents(char const **result,
103
 
                                       size_t *resultLen,
104
 
                                       const char *name,
105
 
                                       const char *args,
106
 
                                       size_t argsSize,
107
 
                                       void *clientData);
108
 
static Bool UnityTcloGetIconData(char const **result,
109
 
                                 size_t *resultLen,
110
 
                                 const char *name,
111
 
                                 const char *args,
112
 
                                 size_t argsSize,
113
 
                                 void *clientData);
114
 
static Bool UnityTcloSetDesktopWorkArea(char const **result,
115
 
                                       size_t *resultLen,
116
 
                                       const char *name,
117
 
                                       const char *args,
118
 
                                       size_t argsSize,
119
 
                                       void *clientData);
120
 
static Bool UnityTcloSetTopWindowGroup(char const **result,
121
 
                                       size_t *resultLen,
122
 
                                       const char *name,
123
 
                                       const char *args,
124
 
                                       size_t argsSize,
125
 
                                       void *clientData);
126
 
static Bool UnityTcloShowTaskbar(char const **result,
127
 
                                 size_t *resultLen,
128
 
                                 const char *name,
129
 
                                 const char *args,
130
 
                                 size_t argsSize,
131
 
                                 void *clientData);
132
 
static Bool UnityTcloMoveResizeWindow(char const **result,
133
 
                                      size_t *resultLen,
134
 
                                      const char *name,
135
 
                                      const char *args,
136
 
                                      size_t argsSize,
137
 
                                      void *clientData);
138
 
static Bool UnityTcloSetDesktopConfig(char const **result,
139
 
                                      size_t *resultLen,
140
 
                                      const char *name,
141
 
                                      const char *args,
142
 
                                      size_t argsSize,
143
 
                                      void *clientData);
144
 
static Bool UnityTcloSetDesktopActive(char const **result,
145
 
                                      size_t *resultLen,
146
 
                                      const char *name,
147
 
                                      const char *args,
148
 
                                      size_t argsSize,
149
 
                                      void *clientData);
150
 
static Bool UnityTcloSetWindowDesktop(char const **result,
151
 
                                      size_t *resultLen,
152
 
                                      const char *name,
153
 
                                      const char *args,
154
 
                                      size_t argsSize,
155
 
                                      void *clientData);
156
 
static Bool UnityTcloConfirmOperation(char const **result,
157
 
                                      size_t *resultLen,
158
 
                                      const char *name,
159
 
                                      const char *args,
160
 
                                      size_t argsSize,
161
 
                                      void *clientData);
162
 
 
163
 
static void UnitySetAddHiddenWindows(Bool enabled);
164
 
static void UnitySetInterlockMinimizeOperation(Bool enabled);
165
 
static void UnitySetSendWindowContents(Bool enabled);
166
 
 
167
 
/*
168
 
 * Wrapper function for the "unity.set.options" RPC.
169
 
 */
170
 
static Bool UnityTcloSetUnityOptions(RpcInData *data);
171
 
 
172
 
/*
173
 
 * Wrapper function for the "unity.window.contents.request" RPC.
174
 
 */
175
 
static Bool UnityTcloRequestWindowContents(RpcInData *data);
176
 
 
177
 
/* Sends the unity.window.contents.start RPC to the host. */
178
 
Bool UnitySendWindowContentsStart(UnityWindowId window,
179
 
                                  uint32 width,
180
 
                                  uint32 height,
181
 
                                  uint32 length);
182
 
 
183
 
/* Sends the unity.window.contents.chunk RPC to the host. */
184
 
Bool UnitySendWindowContentsChunk(UnityWindowId window,
185
 
                                  uint32 seq,
186
 
                                  const char *data,
187
 
                                  uint32 length);
188
 
 
189
 
/* Sends the unity.window.contents.end RPC to the host. */
190
 
Bool UnitySendWindowContentsEnd(UnityWindowId window);
191
 
 
192
 
/*
193
 
 * Callback function used by UnityXdrSendRpc() to encode XDR-serialized
194
 
 * arguments.
195
 
 */
196
 
typedef Bool(*UnityXdrEncodeFunc)(XDR*,void*);
197
 
 
198
 
/*
199
 
 * Helper function used to send an RPC to the host with XDR-serialized
200
 
 * arguments. Calls encodeFn on the XDR* and the provied arg to perform
201
 
 * XDR encoding.
202
 
 */
203
 
Bool UnityXdrSendRpc(const char *rpcName, UnityXdrEncodeFunc encodeFn, void *arg);
204
 
 
205
 
/*
206
 
 * Dispatch table for Unity window commands. All commands performing actions on
207
 
 * guest unity windows go here.
208
 
 */
209
 
 
210
 
typedef struct {
211
 
   const char *name;
212
 
   Bool (*exec)(UnityPlatform *up, UnityWindowId window);
213
 
} UnityCommandElem;
214
 
 
215
 
static UnityCommandElem unityCommandTable[] = {
216
 
   { UNITY_RPC_WINDOW_CLOSE, UnityPlatformCloseWindow },
217
 
   { UNITY_RPC_WINDOW_SHOW, UnityPlatformShowWindow },
218
 
   { UNITY_RPC_WINDOW_HIDE, UnityPlatformHideWindow },
219
 
   { UNITY_RPC_WINDOW_MINIMIZE, UnityPlatformMinimizeWindow },
220
 
   { UNITY_RPC_WINDOW_UNMINIMIZE, UnityPlatformUnminimizeWindow },
221
 
   { UNITY_RPC_WINDOW_MAXIMIZE, UnityPlatformMaximizeWindow },
222
 
   { UNITY_RPC_WINDOW_UNMAXIMIZE, UnityPlatformUnmaximizeWindow },
223
 
   { UNITY_RPC_WINDOW_STICK, UnityPlatformStickWindow },
224
 
   { UNITY_RPC_WINDOW_UNSTICK, UnityPlatformUnstickWindow },
225
 
   /* Add more commands and handlers above this. */
226
 
   { NULL, NULL }
227
 
};
228
 
 
229
 
typedef struct {
230
 
   uint32 featureBit;
231
 
   void (*setter)(Bool enabled);
232
 
} UnityFeatureSetter;
233
 
 
234
 
/*
235
 
 * Dispatch table for each unity option and a specific function to handle enabling
236
 
 * or disabling the option. The function is called with an enable (TRUE) bool value.
237
 
 */
238
 
static UnityFeatureSetter unityFeatureTable[] = {
239
 
   { UNITY_ADD_HIDDEN_WINDOWS_TO_TRACKER, UnitySetAddHiddenWindows },
240
 
   { UNITY_INTERLOCK_MINIMIZE_OPERATION, UnitySetInterlockMinimizeOperation },
241
 
   { UNITY_SEND_WINDOW_CONTENTS, UnitySetSendWindowContents },
242
 
   /* Add more Unity Feature Setters above this. */
243
 
   {0, NULL}
244
 
};
245
 
 
246
 
/*
247
 
 * XXX:
248
 
 * According to Adar:
249
 
 *    "UnityTcloGetUpdate cannot return the contents of a DynBuf. This will leak
250
 
 *     the DynBuf's memory, since nobody at a lower level will ever free it.  It's
251
 
 *     a crappy interface, but we make due by using a static buffer to hold the
252
 
 *     results."
253
 
 *
254
 
 * We ideally would not use a static buffer because the maximum size of the
255
 
 * update is unknown.  To work around this, make the DynBuf returned in
256
 
 * UnityTcloGetUpdate file-global and recycle it across update requests.
257
 
 */
258
 
 
259
 
static DynBuf gTcloUpdate;
260
 
 
261
 
 
262
 
/*
263
 
 *----------------------------------------------------------------------------
264
 
 *
265
 
 * Unity_IsSupported --
266
 
 *
267
 
 *      Determine whether this guest supports unity.
268
 
 *
269
 
 * Results:
270
 
 *      TRUE if the guest supports Unity (i.e. if the guest is WinXP) or
271
 
 *      if the option to always enable unity was specified in the tools
272
 
 *      configuration file
273
 
 *      FALSE otherwise
274
 
 *
275
 
 * Side effects:
276
 
 *      None
277
 
 *
278
 
 *----------------------------------------------------------------------------
279
 
 */
280
 
 
281
 
Bool
282
 
Unity_IsSupported(void)
283
 
{
284
 
   return UnityPlatformIsSupported() || unity.forceEnable;
285
 
}
286
 
 
287
 
 
288
 
/*
289
 
 *----------------------------------------------------------------------------
290
 
 *
291
 
 * Unity_IsActive --
292
 
 *
293
 
 *      Determine whether we are in Unity mode at this moment.
294
 
 *
295
 
 * Results:
296
 
 *      TRUE if Unity is active.
297
 
 *      FALSE is Unity is not active.
298
 
 *
299
 
 * Side effects:
300
 
 *      None
301
 
 *
302
 
 *----------------------------------------------------------------------------
303
 
 */
304
 
 
305
 
Bool
306
 
Unity_IsActive(void)
307
 
{
308
 
   return unity.isEnabled;
309
 
}
310
 
 
311
 
 
312
 
/*
313
 
 *-----------------------------------------------------------------------------
314
 
 *
315
 
 * Unity_Init  --
316
 
 *
317
 
 *     One time initialization stuff.
318
 
 *
319
 
 *
320
 
 * Results:
321
 
 *     None.
322
 
 *
323
 
 * Side effects:
324
 
 *     May register with the tools poll loop.
325
 
 *
326
 
 *-----------------------------------------------------------------------------
327
 
 */
328
 
 
329
 
void
330
 
Unity_Init(GuestApp_Dict *conf,                                    // IN
331
 
           int *blockedWnd,                                        // IN
332
 
           DesktopSwitchCallbackManager *desktopSwitchCallbackMgr) // IN
333
 
{
334
 
   /*
335
 
    * If no preferred color is in the config file then use a light gray tone,
336
 
    * the value is stored as xBGR.
337
 
    */
338
 
   int desktopColor =  /* red */ 0xdc |
339
 
                       /* green */ 0xdc << 8 |
340
 
                       /* blue */ 0xdc << 16;
341
 
   Debug("Unity_Init\n");
342
 
 
343
 
   /*
344
 
    * Initialize the UnityWindowTracker object.  The uwt does all the actual work
345
 
    * of computing differences between two states of the windowing system.  The
346
 
    * callbacks we register here will fire when we request an update via
347
 
    * UnityWindowTracker_RequestUpdates.  See bora/lib/unityWindowTracker for more
348
 
    * information.
349
 
    */
350
 
   UnityWindowTracker_Init(&unity.tracker, UnityUpdateCallbackFn);
351
 
 
352
 
   /*
353
 
    * Initialize the update channel.
354
 
    */
355
 
   if (UnityUpdateChannelInit(&unity.updateChannel) == FALSE) {
356
 
      Warning("%s: Unable to initialize Unity update channel.\n", __FUNCTION__);
357
 
      return;
358
 
   }
359
 
 
360
 
   /*
361
 
    * Initialize the host-specific portion of the unity service.
362
 
    */
363
 
   unity.up = UnityPlatformInit(&unity.tracker,
364
 
                                &unity.updateChannel,
365
 
                                blockedWnd,
366
 
                                desktopSwitchCallbackMgr);
367
 
 
368
 
   /*
369
 
    * Init our global dynbuf used to send results back.
370
 
    */
371
 
   DynBuf_Init(&gTcloUpdate);
372
 
 
373
 
   /*
374
 
    * If debugging has been enabled, initialize the debug module.  On Windows,
375
 
    * this will pop up a small HUD window which shows an echo of the current
376
 
    * state of the windowing system.
377
 
    */
378
 
   if (GuestApp_GetDictEntryBool(conf, "unity.debug")) {
379
 
      UnityDebug_Init(&unity.tracker);
380
 
   }
381
 
 
382
 
   /*
383
 
    * Check if the user specified the option to always enable unity regardless
384
 
    * of the guest OS type.
385
 
    */
386
 
 
387
 
   unity.forceEnable = GuestApp_GetDictEntryBool(conf, "unity.forceEnable");
388
 
   unity.isEnabled = FALSE;
389
 
 
390
 
   GuestApp_GetDictEntryInt(conf, "unity.desktop.backgroundColor", &desktopColor);
391
 
   UnityPlatformSetConfigDesktopColor(unity.up, desktopColor);
392
 
   unity.virtDesktopArray.desktopCount = 0;
393
 
}
394
 
 
395
 
 
396
 
/*
397
 
 *-----------------------------------------------------------------------------
398
 
 *
399
 
 * Unity_Cleanup  --
400
 
 *
401
 
 *    Exit Unity and do final cleanup.
402
 
 *
403
 
 * Results:
404
 
 *    None.
405
 
 *
406
 
 * Side effects:
407
 
 *    None
408
 
 *
409
 
 *-----------------------------------------------------------------------------
410
 
 */
411
 
 
412
 
void
413
 
Unity_Cleanup(void)
414
 
{
415
 
   UnityPlatform *up;
416
 
 
417
 
   Debug("%s\n", __FUNCTION__);
418
 
 
419
 
 
420
 
   /*
421
 
    * Exit Unity.
422
 
    */
423
 
   Unity_Exit();
424
 
 
425
 
   /*
426
 
    * Do one-time final platform-specific cleanup.
427
 
    */
428
 
   up = unity.up;
429
 
   unity.up = NULL;
430
 
   UnityPlatformCleanup(up);
431
 
 
432
 
   UnityUpdateChannelCleanup(&unity.updateChannel);
433
 
   UnityWindowTracker_Cleanup(&unity.tracker);
434
 
   DynBuf_Destroy(&gTcloUpdate);
435
 
}
436
 
 
437
 
 
438
 
/*
439
 
 *-----------------------------------------------------------------------------
440
 
 *
441
 
 * Unity_InitBackdoor  --
442
 
 *
443
 
 *    One time initialization stuff for the backdoor.
444
 
 *
445
 
 *
446
 
 * Results:
447
 
 *    None.
448
 
 *
449
 
 * Side effects:
450
 
 *    None.
451
 
 *
452
 
 *-----------------------------------------------------------------------------
453
 
 */
454
 
 
455
 
void
456
 
Unity_InitBackdoor(struct RpcIn *rpcIn)   // IN
457
 
{
458
 
   /*
459
 
    * Only register the callback if the guest is capable of supporting Unity.
460
 
    * This way, if the VMX/UI sends us a Unity request on a non-supported platform
461
 
    * (for whatever reason), we will reply with 'command not supported'.
462
 
    */
463
 
 
464
 
   if (Unity_IsSupported()) {
465
 
      UnityCommandElem *elem;
466
 
 
467
 
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_ENTER, UnityTcloEnter, NULL);
468
 
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_GET_UPDATE_FULL, UnityTcloGetUpdate, NULL);
469
 
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_GET_UPDATE_INCREMENTAL,
470
 
                             UnityTcloGetUpdate, NULL);
471
 
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_GET_WINDOW_PATH,
472
 
                             UnityTcloGetWindowPath, NULL);
473
 
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_WINDOW_SETTOP,
474
 
                             UnityTcloSetTopWindowGroup, NULL);
475
 
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_GET_WINDOW_CONTENTS,
476
 
                             UnityTcloGetWindowContents, NULL);
477
 
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_GET_ICON_DATA,
478
 
                             UnityTcloGetIconData, NULL);
479
 
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_DESKTOP_WORK_AREA_SET,
480
 
                             UnityTcloSetDesktopWorkArea, NULL);
481
 
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_SHOW_TASKBAR, UnityTcloShowTaskbar, NULL);
482
 
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_EXIT, UnityTcloExit, NULL);
483
 
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_WINDOW_MOVE_RESIZE,
484
 
                             UnityTcloMoveResizeWindow, NULL);
485
 
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_DESKTOP_CONFIG_SET,
486
 
                             UnityTcloSetDesktopConfig, NULL);
487
 
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_DESKTOP_ACTIVE_SET,
488
 
                             UnityTcloSetDesktopActive, NULL);
489
 
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_WINDOW_DESKTOP_SET,
490
 
                             UnityTcloSetWindowDesktop, NULL);
491
 
      RpcIn_RegisterCallback(rpcIn, UNITY_RPC_CONFIRM_OPERATION,
492
 
                             UnityTcloConfirmOperation, NULL);
493
 
 
494
 
      RpcIn_RegisterCallbackEx(rpcIn, UNITY_RPC_SET_OPTIONS,
495
 
                               UnityTcloSetUnityOptions, NULL);
496
 
 
497
 
      RpcIn_RegisterCallbackEx(rpcIn, UNITY_RPC_WINDOW_CONTENTS_REQUEST,
498
 
                               UnityTcloRequestWindowContents, NULL);
499
 
 
500
 
      /*
501
 
       * Handle all of the UnityTcloWindowCommand RPCs at once.
502
 
       */
503
 
      for (elem = unityCommandTable; elem->name != NULL; elem++) {
504
 
         RpcIn_RegisterCallback(rpcIn, elem->name, UnityTcloWindowCommand,
505
 
                                NULL);
506
 
      }
507
 
   }
508
 
}
509
 
 
510
 
 
511
 
/*
512
 
 *-----------------------------------------------------------------------------
513
 
 *
514
 
 * Unity_SetActiveDnDDetWnd  --
515
 
 *
516
 
 *    Right now we have 2 Unity DnD full screen detection window, one for version
517
 
 *    2 or older, another for version 3 or newer. This function is to set active
518
 
 *    one according to host DnD version.
519
 
 *
520
 
 *    XXX Both full-screent window is still bottom-most and is showed all time
521
 
 *    during Unity mode. Another change is needed to change it to only show the
522
 
 *    window during guest->host DnD. Also the window should not be bottom-most,
523
 
 *    but dynamicly change z-order during DnD.
524
 
 *
525
 
 * Results:
526
 
 *    None.
527
 
 *
528
 
 * Side effects:
529
 
 *    None.
530
 
 *
531
 
 *-----------------------------------------------------------------------------
532
 
 */
533
 
 
534
 
void
535
 
Unity_SetActiveDnDDetWnd(UnityDnD *state)
536
 
{
537
 
   if (unity.up != NULL) {
538
 
      UnityPlatformSetActiveDnDDetWnd(unity.up, state);
539
 
   }
540
 
}
541
 
 
542
 
 
543
 
/*
544
 
 *-----------------------------------------------------------------------------
545
 
 *
546
 
 * Unity_Exit  --
547
 
 *
548
 
 *    Called everytime we exit Unity. This function can be called when we are
549
 
 *    not in Unity mode. Right now it is called every time a 'reset' TCLO command
550
 
 *    is sent to the guest. Therefore, there's no guarantee that we were in the
551
 
 *    Unity mode when this function is called.
552
 
 *
553
 
 *    Try to do the following:
554
 
 *    Restore system settings if needed.
555
 
 *    Kills all unity helper threads if any are running.
556
 
 *    Hide the unity dnd detection window.
557
 
 *
558
 
 * Results:
559
 
 *    None.
560
 
 *
561
 
 * Side effects:
562
 
 *    Restores system settings since we are exiting Unity.
563
 
 *    Kills all unity helper threads if any.
564
 
 *    Hides the unity dnd detection window if needed.
565
 
 *
566
 
 *-----------------------------------------------------------------------------
567
 
 */
568
 
 
569
 
void
570
 
Unity_Exit(void)
571
 
{
572
 
   int featureIndex = 0;
573
 
 
574
 
   if (unity.isEnabled) {
575
 
      /*
576
 
       * Reset any Unity Options - they'll be re-enabled as required before the
577
 
       * next UnityTcloEnter.
578
 
       */
579
 
      while (unityFeatureTable[featureIndex].featureBit != 0) {
580
 
         if (unity.currentOptions & unityFeatureTable[featureIndex].featureBit) {
581
 
            unityFeatureTable[featureIndex].setter(FALSE);
582
 
         }
583
 
         featureIndex++;
584
 
      }
585
 
      unity.currentOptions = 0;
586
 
 
587
 
      /* Hide full-screen detection window for Unity DnD. */
588
 
      UnityPlatformUpdateDnDDetWnd(unity.up, FALSE);
589
 
 
590
 
      /* Kill Unity helper threads. */
591
 
      UnityPlatformKillHelperThreads(unity.up);
592
 
 
593
 
      /* Restore previously saved user settings. */
594
 
      UnityPlatformRestoreSystemSettings(unity.up);
595
 
 
596
 
      unity.isEnabled = FALSE;
597
 
   }
598
 
}
599
 
 
600
 
 
601
 
/*
602
 
 *-----------------------------------------------------------------------------
603
 
 *
604
 
 * Unity_RegisterCaps  --
605
 
 *
606
 
 *    Called by the application (VMwareUser) to allow the unity subsystem to
607
 
 *    register its capabilities.
608
 
 *
609
 
 * Results:
610
 
 *    None.
611
 
 *
612
 
 * Side effects:
613
 
 *    None.
614
 
 *
615
 
 *-----------------------------------------------------------------------------
616
 
 */
617
 
 
618
 
void
619
 
Unity_RegisterCaps(void)
620
 
{
621
 
   /*
622
 
    * Send Unity capability.
623
 
    */
624
 
 
625
 
   if (!RpcOut_sendOne(NULL, NULL, UNITY_RPC_UNITY_CAP" %d",
626
 
                       Unity_IsSupported() ? 1 : 0)) {
627
 
      Debug("%s: could not set unity capability\n", __FUNCTION__);
628
 
   }
629
 
 
630
 
   /*
631
 
    * Register guest platform specific capabilities.
632
 
    */
633
 
 
634
 
   UnityPlatformRegisterCaps(unity.up);
635
 
   AppUtil_SendGuestCaps(unityCaps, ARRAYSIZE(unityCaps), TRUE);
636
 
}
637
 
 
638
 
 
639
 
/*
640
 
 *-----------------------------------------------------------------------------
641
 
 *
642
 
 * Unity_UnregisterCaps  --
643
 
 *
644
 
 *    Called by the application (VMwareUser) to allow the unity subsystem to
645
 
 *    unregister its capabilities.
646
 
 *
647
 
 * Results:
648
 
 *    None.
649
 
 *
650
 
 * Side effects:
651
 
 *    None.
652
 
 *
653
 
 *-----------------------------------------------------------------------------
654
 
 */
655
 
 
656
 
void
657
 
Unity_UnregisterCaps(void)
658
 
{
659
 
   /*
660
 
    * Unregister guest platform specific capabilities.
661
 
    */
662
 
 
663
 
   UnityPlatformUnregisterCaps(unity.up);
664
 
 
665
 
   /*
666
 
    * Unregister the unity capability.
667
 
    */
668
 
 
669
 
   if (!RpcOut_sendOne(NULL, NULL, UNITY_RPC_UNITY_CAP" 0")) {
670
 
      Debug("Failed to unregister Unity capability\n");
671
 
   }
672
 
   AppUtil_SendGuestCaps(unityCaps, ARRAYSIZE(unityCaps), FALSE);
673
 
}
674
 
 
675
 
 
676
 
/*
677
 
 *----------------------------------------------------------------------------
678
 
 *
679
 
 * UnityTcloEnter --
680
 
 *
681
 
 *     RPC handler for 'unity.enter'. Save and disable certain user
682
 
 *     settings. Start Unity updates thread and any other platform
683
 
 *     specific threads (like a thread that listens for
684
 
 *     the desktop switch event on Windows). Note that we first set
685
 
 *     the UI settings, and then start the threads. This way the UI
686
 
 *     settings take effect before we start sending Unity updates,
687
 
 *     so that we never send things like task bar (see bug 166085).
688
 
 *
689
 
 * Results:
690
 
 *     TRUE if helper threads were started.
691
 
 *     FALSE otherwise.
692
 
 *
693
 
 * Side effects:
694
 
 *     Certain UI system settings will be disabled.
695
 
 *     Unity update thread will be started.
696
 
 *     Any other platform specific helper threads will be started as well.
697
 
 *
698
 
 *----------------------------------------------------------------------------
699
 
 */
700
 
 
701
 
static Bool
702
 
UnityTcloEnter(char const **result,     // OUT
703
 
               size_t *resultLen,       // OUT
704
 
               const char *name,        // IN
705
 
               const char *args,        // IN
706
 
               size_t argsSize,         // ignored
707
 
               void *clientData)        // ignored
708
 
{
709
 
   Debug("%s\n", __FUNCTION__);
710
 
 
711
 
   if (!unity.isEnabled) {
712
 
      /* Save and disable certain user settings here. */
713
 
      UnityPlatformSaveSystemSettings(unity.up);
714
 
 
715
 
      /* Start Unity helper threads. */
716
 
      if (!UnityPlatformStartHelperThreads(unity.up)) {
717
 
 
718
 
         /*
719
 
          * If we couldn't start one or more helper threads,
720
 
          * we cannot enter Unity. Kill all running helper
721
 
          * threads and restore ui settings.
722
 
          */
723
 
 
724
 
         UnityPlatformKillHelperThreads(unity.up);
725
 
         UnityPlatformRestoreSystemSettings(unity.up);
726
 
         return RpcIn_SetRetVals(result, resultLen,
727
 
                                 "Could not start unity helper threads", FALSE);
728
 
      }
729
 
 
730
 
      /*
731
 
       * Show full-screen detection window for Unity DnD. It is a bottom-most (but
732
 
       * still in front of desktop) transparent detection window for guest->host DnD
733
 
       * as drop target. We need this window because:
734
 
       * 1. All active windows except desktop will be shown on host desktop and can
735
 
       *    accept DnD signal. This full-screen detection window will block any DnD signal
736
 
       *    (even mouse signal) to the desktop, which will fix bug 164880.
737
 
       * 2. With this full-screen but bottommost detection window, every time when user
738
 
       *    drag something out from active window, the dragEnter will always be immediately
739
 
       *    catched for Unity DnD.
740
 
       */
741
 
      UnityPlatformUpdateDnDDetWnd(unity.up, TRUE);
742
 
      unity.isEnabled = TRUE;
743
 
   }
744
 
 
745
 
   UnityUpdateState();
746
 
 
747
 
   return RpcIn_SetRetVals(result, resultLen, "", TRUE);
748
 
}
749
 
 
750
 
 
751
 
/*
752
 
 *----------------------------------------------------------------------------
753
 
 *
754
 
 * UnityTcloExit --
755
 
 *
756
 
 *     RPC handler for 'unity.exit'.
757
 
 *
758
 
 * Results:
759
 
 *     Always TRUE.
760
 
 *
761
 
 * Side effects:
762
 
 *     Same as side effects of Unity_Exit().
763
 
 *
764
 
 *----------------------------------------------------------------------------
765
 
 */
766
 
 
767
 
static Bool
768
 
UnityTcloExit(char const **result,     // OUT
769
 
              size_t *resultLen,       // OUT
770
 
              const char *name,        // IN
771
 
              const char *args,        // IN
772
 
              size_t argsSize,         // ignored
773
 
              void *clientData)        // ignored
774
 
{
775
 
   Debug("UnityTcloExit.\n");
776
 
 
777
 
   Unity_Exit();
778
 
 
779
 
   UnityUpdateState();
780
 
   return RpcIn_SetRetVals(result, resultLen, "", TRUE);
781
 
}
782
 
 
783
 
 
784
 
/*
785
 
 *----------------------------------------------------------------------------
786
 
 *
787
 
 * UnityTcloGetWindowPath --
788
 
 *
789
 
 *      RPC handler for UNITY_RPC_GET_WINDOW_PATH.
790
 
 *
791
 
 *      Get the information needed to re-launch a window and retrieve further
792
 
 *      information on it.  Returns double-NUL-terminated buffer consisting of
793
 
 *      NUL-terminated strings "windowPath" and "execPath" strings, the first
794
 
 *      uniquely identifying the window and the second uniquely identifying the
795
 
 *      window's owning executable.
796
 
 *
797
 
 * Results:
798
 
 *     TRUE if everything is successful.
799
 
 *     FALSE otherwise.
800
 
 *
801
 
 * Side effects:
802
 
 *     None.
803
 
 *
804
 
 *----------------------------------------------------------------------------
805
 
 */
806
 
 
807
 
static Bool
808
 
UnityTcloGetWindowPath(char const **result,     // OUT
809
 
                       size_t *resultLen,       // OUT
810
 
                       const char *name,        // IN
811
 
                       const char *args,        // IN
812
 
                       size_t argsSize,         // ignored
813
 
                       void *clientData)        // ignored
814
 
 
815
 
{
816
 
   UnityWindowId window;
817
 
   DynBuf windowPathUtf8;
818
 
   DynBuf execPathUtf8;
819
 
 
820
 
   unsigned int index = 0;
821
 
   Bool ret = TRUE;
822
 
 
823
 
   Debug("UnityTcloGetWindowPath name:%s args:'%s'\n", name, args);
824
 
 
825
 
   /* Parse the command & window id.*/
826
 
 
827
 
   if (!StrUtil_GetNextIntToken(&window, &index, args, " ")) {
828
 
      Debug("UnityTcloGetWindowInfo: Invalid RPC arguments.\n");
829
 
      return RpcIn_SetRetVals(result, resultLen,
830
 
                              "Invalid arguments. Expected \"windowId\"",
831
 
                              FALSE);
832
 
   }
833
 
 
834
 
   Debug("UnityTcloGetWindowInfo: window %d\n", window);
835
 
 
836
 
   /*
837
 
    * Please note that the UnityPlatformGetWindowPath implementations assume that the
838
 
    * dynbuf passed in does not contain any existing data that needs to be appended to,
839
 
    * so this code should continue to accomodate that assumption.
840
 
    */
841
 
   DynBuf_Destroy(&gTcloUpdate);
842
 
   DynBuf_Init(&gTcloUpdate);
843
 
   DynBuf_Init(&windowPathUtf8);
844
 
   DynBuf_Init(&execPathUtf8);
845
 
   if (!UnityPlatformGetWindowPath(unity.up, window, &windowPathUtf8, &execPathUtf8)) {
846
 
      Debug("UnityTcloGetWindowInfo: Could not get window path.\n");
847
 
      ret = RpcIn_SetRetVals(result, resultLen,
848
 
                             "Could not get window path",
849
 
                             FALSE);
850
 
      goto exit;
851
 
   }
852
 
 
853
 
   /*
854
 
    * Construct the buffer holding the result. Note that we need to use gTcloUpdate
855
 
    * here to avoid leaking during the RPC handler.
856
 
    */
857
 
   DynBuf_Copy(&windowPathUtf8, &gTcloUpdate);
858
 
   DynBuf_Append(&gTcloUpdate, DynBuf_Get(&execPathUtf8), DynBuf_GetSize(&execPathUtf8));
859
 
 
860
 
   /*
861
 
    * Write the final result into the result out parameters and return!
862
 
    */
863
 
   *result = (char *)DynBuf_Get(&gTcloUpdate);
864
 
   *resultLen = DynBuf_GetSize(&gTcloUpdate);
865
 
 
866
 
exit:
867
 
   DynBuf_Destroy(&windowPathUtf8);
868
 
   DynBuf_Destroy(&execPathUtf8);
869
 
   return ret;
870
 
}
871
 
 
872
 
 
873
 
/*
874
 
 *----------------------------------------------------------------------------
875
 
 *
876
 
 * UnityTcloWindowCommand --
877
 
 *
878
 
 *     RPC handler for 'unity.window.*' (excluding 'unity.window.settop')
879
 
 *
880
 
 * Results:
881
 
 *     TRUE if everything is successful.
882
 
 *     FALSE otherwise.
883
 
 *
884
 
 * Side effects:
885
 
 *     None.
886
 
 *
887
 
 *----------------------------------------------------------------------------
888
 
 */
889
 
 
890
 
static Bool
891
 
UnityTcloWindowCommand(char const **result,     // OUT
892
 
                       size_t *resultLen,       // OUT
893
 
                       const char *name,        // IN
894
 
                       const char *args,        // IN
895
 
                       size_t argsSize,         // ignored
896
 
                       void *clientData)        // ignored
897
 
{
898
 
   UnityWindowId window;
899
 
   unsigned int index = 0;
900
 
   unsigned int i;
901
 
 
902
 
   Debug("UnityTcloWindowCommand: name:%s args:'%s'\n", name, args);
903
 
 
904
 
   /* Parse the command & window id.*/
905
 
 
906
 
   if (!StrUtil_GetNextIntToken(&window, &index, args, " ")) {
907
 
      Debug("UnityTcloWindowCommand: Invalid RPC arguments.\n");
908
 
      return RpcIn_SetRetVals(result, resultLen,
909
 
                              "Invalid arguments. Expected \"windowId\"",
910
 
                              FALSE);
911
 
 
912
 
   }
913
 
 
914
 
   Debug("UnityTcloWindowCommand: %s window %d\n", name, window);
915
 
 
916
 
   for (i = 0; unityCommandTable[i].name != NULL; i++) {
917
 
      if (strcmp(unityCommandTable[i].name, name) == 0) {
918
 
         if (!unityCommandTable[i].exec(unity.up, window)) {
919
 
            Debug("Unity window command failed.\n");
920
 
            return RpcIn_SetRetVals(result, resultLen,
921
 
                                   "Could not execute window command",
922
 
                                   FALSE);
923
 
         } else {
924
 
            return RpcIn_SetRetVals(result, resultLen, "", TRUE);
925
 
         }
926
 
      }
927
 
   }
928
 
 
929
 
   return RpcIn_SetRetVals(result, resultLen, "Bad command", FALSE);
930
 
}
931
 
 
932
 
 
933
 
/*
934
 
 *----------------------------------------------------------------------------
935
 
 *
936
 
 * UnityTcloSetDesktopWorkArea --
937
 
 *
938
 
 *     RPC handler for 'unity.desktop.work_area.set'.
939
 
 *
940
 
 * Results:
941
 
 *     TRUE if everything is successful.
942
 
 *     FALSE otherwise.
943
 
 *
944
 
 * Side effects:
945
 
 *     None.
946
 
 *
947
 
 *----------------------------------------------------------------------------
948
 
 */
949
 
 
950
 
static Bool
951
 
UnityTcloSetDesktopWorkArea(char const **result,  // IN
952
 
                            size_t *resultLen,    // IN
953
 
                            const char *name,     // IN
954
 
                            const char *args,     // IN
955
 
                            size_t argsSize,      // IN
956
 
                            void *clientData)     // IN
957
 
{
958
 
   Bool success = FALSE;
959
 
   unsigned int count;
960
 
   unsigned int i;
961
 
   UnityRect *workAreas = NULL;
962
 
 
963
 
   /*
964
 
    * The argument string will look something like:
965
 
    *   <count> [ , <x> <y> <w> <h> ] * count.
966
 
    *
967
 
    * e.g.
968
 
    *    3 , 0 0 640 480 , 640 0 800 600 , 0 480 640 480
969
 
    */
970
 
 
971
 
   if (sscanf(args, "%u", &count) != 1) {
972
 
      return RpcIn_SetRetVals(result, resultLen,
973
 
                              "Invalid arguments. Expected \"count\"",
974
 
                              FALSE);
975
 
   }
976
 
 
977
 
   workAreas = (UnityRect *)malloc(sizeof *workAreas * count);
978
 
   if (!workAreas) {
979
 
      RpcIn_SetRetVals(result, resultLen,
980
 
                       "Failed to alloc buffer for work areas",
981
 
                       FALSE);
982
 
      goto out;
983
 
   }
984
 
 
985
 
   for (i = 0; i < count; i++) {
986
 
      args = strchr(args, ',');
987
 
      if (!args) {
988
 
         RpcIn_SetRetVals(result, resultLen,
989
 
                          "Expected comma separated display list",
990
 
                          FALSE);
991
 
         goto out;
992
 
      }
993
 
      args++; /* Skip past the , */
994
 
 
995
 
      if (sscanf(args, " %d %d %d %d ",
996
 
                 &workAreas[i].x, &workAreas[i].y,
997
 
                 &workAreas[i].width, &workAreas[i].height) != 4) {
998
 
         RpcIn_SetRetVals(result, resultLen,
999
 
                          "Expected x, y, w, h in display entry",
1000
 
                          FALSE);
1001
 
         goto out;
1002
 
      }
1003
 
 
1004
 
      if (workAreas[i].x < 0 || workAreas[i].y < 0 ||
1005
 
          workAreas[i].width <= 0 || workAreas[i].height <= 0) {
1006
 
         RpcIn_SetRetVals(result, resultLen, "Invalid argument", FALSE);
1007
 
         goto out;
1008
 
      }
1009
 
   }
1010
 
 
1011
 
   if (!UnityPlatformSetDesktopWorkAreas(unity.up, workAreas, count)) {
1012
 
      RpcIn_SetRetVals(result, resultLen,
1013
 
                       "UnityPlatformSetDesktopWorkAreas failed",
1014
 
                       FALSE);
1015
 
      goto out;
1016
 
   }
1017
 
 
1018
 
   success = RpcIn_SetRetVals(result, resultLen, "", TRUE);
1019
 
 
1020
 
out:
1021
 
   free(workAreas);
1022
 
   return success;
1023
 
}
1024
 
 
1025
 
 
1026
 
/*
1027
 
 *----------------------------------------------------------------------------
1028
 
 *
1029
 
 * UnityTcloSetTopWindowGroup --
1030
 
 *
1031
 
 *     RPC handler for 'unity.window.settop'.
1032
 
 *
1033
 
 * Results:
1034
 
 *     TRUE if everything is successful.
1035
 
 *     FALSE otherwise.
1036
 
 *
1037
 
 * Side effects:
1038
 
 *     None.
1039
 
 *
1040
 
 *----------------------------------------------------------------------------
1041
 
 */
1042
 
 
1043
 
static Bool
1044
 
UnityTcloSetTopWindowGroup(char const **result,     // OUT
1045
 
                           size_t *resultLen,       // OUT
1046
 
                           const char *name,        // IN
1047
 
                           const char *args,        // IN
1048
 
                           size_t argsSize,         // ignored
1049
 
                           void *clientData)        // ignored
1050
 
{
1051
 
   UnityWindowId window;
1052
 
   unsigned int index = 0;
1053
 
   unsigned int windowCount = 0;
1054
 
   UnityWindowId windows[UNITY_MAX_SETTOP_WINDOW_COUNT];
1055
 
 
1056
 
   Debug("%s: name:%s args:'%s'\n", __FUNCTION__, name, args);
1057
 
 
1058
 
   /* Parse the command & window ids.*/
1059
 
 
1060
 
   while (StrUtil_GetNextUintToken(&window, &index, args, " ")) {
1061
 
      windows[windowCount] = window;
1062
 
      windowCount++;
1063
 
      if (windowCount == UNITY_MAX_SETTOP_WINDOW_COUNT) {
1064
 
         Debug("%s: Too many windows.\n", __FUNCTION__);
1065
 
         return RpcIn_SetRetVals(result, resultLen,
1066
 
                                 "Invalid arguments. Too many windows",
1067
 
                                 FALSE);
1068
 
      }
1069
 
   }
1070
 
 
1071
 
   if (windowCount == 0) {
1072
 
      Debug("%s: Invalid RPC arguments.\n", __FUNCTION__);
1073
 
      return RpcIn_SetRetVals(result, resultLen,
1074
 
                              "Invalid arguments. Expected at least one windowId",
1075
 
                              FALSE);
1076
 
   }
1077
 
 
1078
 
   if (!UnityPlatformSetTopWindowGroup(unity.up, windows, windowCount)) {
1079
 
      return RpcIn_SetRetVals(result, resultLen,
1080
 
                              "Could not execute window command",
1081
 
                              FALSE);
1082
 
   }
1083
 
 
1084
 
   return RpcIn_SetRetVals(result, resultLen, "", TRUE);
1085
 
}
1086
 
 
1087
 
 
1088
 
/*
1089
 
 *----------------------------------------------------------------------------
1090
 
 *
1091
 
 * UnityTcloGetUpdate --
1092
 
 *
1093
 
 *     RPC handler for 'unity.get.update'.  Ask the unity window tracker
1094
 
 *     to give us an update (either incremental or non-incremental based
1095
 
 *     on whether the 'incremental' arg is present) and send the result
1096
 
 *     back to the VMX.
1097
 
 *
1098
 
 * Results:
1099
 
 *     None.
1100
 
 *
1101
 
 * Side effects:
1102
 
 *     Clearly.
1103
 
 *
1104
 
 *----------------------------------------------------------------------------
1105
 
 */
1106
 
 
1107
 
static Bool
1108
 
UnityTcloGetUpdate(char const **result,     // OUT
1109
 
                   size_t *resultLen,       // OUT
1110
 
                   const char *name,        // IN
1111
 
                   const char *args,        // IN
1112
 
                   size_t argsSize,         // ignored
1113
 
                   void *clientData)        // ignored
1114
 
{
1115
 
   Bool incremental = FALSE;
1116
 
 
1117
 
   Debug("UnityTcloGetUpdate name:%s args:'%s'", name, args);
1118
 
 
1119
 
   /*
1120
 
    * Specify incremental or non-incremetal updates based on whether or
1121
 
    * not the client set the "incremental" arg.
1122
 
    */
1123
 
   if (strstr(name, "incremental")) {
1124
 
      incremental = TRUE;
1125
 
   }
1126
 
 
1127
 
   /*
1128
 
    * Call into platform-specific implementation to gather and send updates
1129
 
    * back via RPCI.  (This is done to ensure all updates are sent to the
1130
 
    * Unity server in sequence via the same channel.)
1131
 
    */
1132
 
   UnityPlatformDoUpdate(unity.up, incremental);
1133
 
 
1134
 
   /*
1135
 
    * To maintain compatibility, we'll return a successful but empty response.
1136
 
    */
1137
 
   *result = "";
1138
 
   *resultLen = 0;
1139
 
 
1140
 
   /*
1141
 
    * Give the debugger a crack to do something interesting at this point
1142
 
    *
1143
 
    * XXX Not sure if this is worth keeping around since this routine no
1144
 
    * longer returns updates directly.
1145
 
    */
1146
 
   UnityDebug_OnUpdate();
1147
 
 
1148
 
   return TRUE;
1149
 
}
1150
 
 
1151
 
 
1152
 
/*
1153
 
 *----------------------------------------------------------------------------
1154
 
 *
1155
 
 * UnityTcloConfirmOperation --
1156
 
 *
1157
 
 *     RPC handler for 'unity.operation.confirm'.
1158
 
 *
1159
 
 * Results:
1160
 
 *     TRUE if the confirmation could be handled sucessfully.
1161
 
 *     FALSE otherwise.
1162
 
 *
1163
 
 * Side effects:
1164
 
 *     None.
1165
 
 *
1166
 
 *----------------------------------------------------------------------------
1167
 
 */
1168
 
 
1169
 
static Bool
1170
 
UnityTcloConfirmOperation(char const **result,     // OUT
1171
 
                          size_t *resultLen,       // OUT
1172
 
                          const char *name,        // IN
1173
 
                          const char *args,        // IN
1174
 
                          size_t argsSize,         // IN
1175
 
                          void *clientData)        // ignored
1176
 
{
1177
 
   UnityConfirmOperation unityConfirmOpMsg = {0};
1178
 
   UnityConfirmOperationV1 *confirmV1 = NULL;
1179
 
   Bool retVal = FALSE;
1180
 
   unsigned int ret;
1181
 
   Debug("%s: Enter.\n", __FUNCTION__);
1182
 
 
1183
 
   /*
1184
 
    * Deserialize the XDR data. Note that the data begins with args + 1 since
1185
 
    * there is a space between the RPC name and the XDR serialization.
1186
 
    */
1187
 
   if (!XdrUtil_Deserialize((char *)args + 1, argsSize - 1,
1188
 
                            xdr_UnityConfirmOperation, &unityConfirmOpMsg)) {
1189
 
      ret = RpcIn_SetRetVals(result, resultLen, "Failed to deserialize data", FALSE);
1190
 
      goto exit;
1191
 
   }
1192
 
 
1193
 
   confirmV1 = unityConfirmOpMsg.UnityConfirmOperation_u.unityConfirmOpV1;
1194
 
   if (MINIMIZE == confirmV1->details.op) {
1195
 
      retVal = UnityPlatformConfirmMinimizeOperation(unity.up,
1196
 
                                                     confirmV1->windowId,
1197
 
                                                     confirmV1->sequence,
1198
 
                                                     confirmV1->allow);
1199
 
   } else {
1200
 
      Debug("%s: Confirmation for unknown operation ID = %d\n", __FUNCTION__,
1201
 
            confirmV1->details.op);
1202
 
   }
1203
 
   /* Free any memory allocated by XDR - we're done with unityConfirmOpMsg */
1204
 
   VMX_XDR_FREE(xdr_UnityConfirmOperation, &unityConfirmOpMsg);
1205
 
   ret = RpcIn_SetRetVals(result, resultLen, "", retVal);
1206
 
 
1207
 
exit:
1208
 
   Debug("%s: Exit.\n", __FUNCTION__);
1209
 
   return ret;
1210
 
}
1211
 
 
1212
 
 
1213
 
/*
1214
 
 *----------------------------------------------------------------------------
1215
 
 *
1216
 
 * UnityGetUpdateCommon --
1217
 
 *
1218
 
 *     Get the unity window update and append it to the specified output buffer.
1219
 
 *     This function can be called from two different threads: either from
1220
 
 *     the main thread that is trying to execute a TCLO command (unity.get.update)
1221
 
 *     or from the unity update thread that is gathering periodic updates and
1222
 
 *     pushes them to the VMX as needed (by calling 'tools.unity.push.update RPC).
1223
 
 *     Since this function can be called from two different threads, protect
1224
 
 *     the global unity singleton with locks.
1225
 
 *
1226
 
 * Results:
1227
 
 *     None.
1228
 
 *
1229
 
 * Side effects:
1230
 
 *     None.
1231
 
 *
1232
 
 *----------------------------------------------------------------------------
1233
 
 */
1234
 
 
1235
 
void
1236
 
UnityGetUpdateCommon(int flags,     //  IN: unity update flags
1237
 
                     DynBuf *buf)   //  IN/OUT: unity update buffer
1238
 
{
1239
 
 
1240
 
   ASSERT(buf);
1241
 
 
1242
 
   UnityPlatformLock(unity.up);
1243
 
 
1244
 
   /*
1245
 
    * Ask the guest to crawl the windowing system and push updates
1246
 
    * into the unity window tracker.  If the guest backend isn't able to get
1247
 
    * notification of destroyed windows, UnityPlatformUpdateWindowState will
1248
 
    * return TRUE, which is are signal to set the UNITY_UPDATE_REMOVE_UNTOUCHED
1249
 
    * flag.  This make the unity window tracker generate remove events for
1250
 
    * windows that it hasn't seen an update for since the last update
1251
 
    * request.
1252
 
    */
1253
 
   if (UnityPlatformUpdateWindowState(unity.up, &unity.tracker)) {
1254
 
      flags |= UNITY_UPDATE_REMOVE_UNTOUCHED;
1255
 
   }
1256
 
 
1257
 
   /*
1258
 
    * Generate the update string.  We'll accumulate updates in the DynBuf
1259
 
    * buf via the callbacks registered in Unity_Init().  Each update will
1260
 
    * append a null terminated string to buf.
1261
 
    */
1262
 
   UnityWindowTracker_RequestUpdates(&unity.tracker, flags, buf);
1263
 
 
1264
 
   UnityPlatformUnlock(unity.up);
1265
 
 
1266
 
   /*
1267
 
    * Write the final '\0' to the DynBuf to signal that we're all out of
1268
 
    * updates.
1269
 
    */
1270
 
   DynBuf_AppendString(buf, "");
1271
 
 
1272
 
   return;
1273
 
}
1274
 
 
1275
 
 
1276
 
/*
1277
 
 *----------------------------------------------------------------------------
1278
 
 *
1279
 
 * UnityUpdateCallbackFn --
1280
 
 *
1281
 
 *     Callback from the unity window tracker indicating something's
1282
 
 *     changed.
1283
 
 *
1284
 
 *     Write the update string into our dynbuf accumlating the update
1285
 
 *     and return.
1286
 
 *
1287
 
 * Results:
1288
 
 *     None.
1289
 
 *
1290
 
 * Side effects:
1291
 
 *     Clearly.
1292
 
 *
1293
 
 *----------------------------------------------------------------------------
1294
 
 */
1295
 
 
1296
 
void
1297
 
UnityUpdateCallbackFn(void *param,          // IN: dynbuf
1298
 
                      UnityUpdate *update)  // IN
1299
 
{
1300
 
   DynBuf *buf = (DynBuf *)param;
1301
 
   char data[1024];
1302
 
   int i, n, count = 0;
1303
 
   RegionPtr region;
1304
 
   char *titleUtf8 = NULL;
1305
 
   char *windowPathUtf8 = "";
1306
 
   char *execPathUtf8 = "";
1307
 
 
1308
 
   switch (update->type) {
1309
 
 
1310
 
   case UNITY_UPDATE_ADD_WINDOW:
1311
 
      if (DynBuf_GetSize(&update->u.addWindow.windowPathUtf8) > 0) {
1312
 
         windowPathUtf8 = DynBuf_Get(&update->u.addWindow.windowPathUtf8);
1313
 
      }
1314
 
      if (DynBuf_GetSize(&update->u.addWindow.execPathUtf8) > 0) {
1315
 
         execPathUtf8 = DynBuf_Get(&update->u.addWindow.execPathUtf8);
1316
 
      }
1317
 
 
1318
 
      Str_Sprintf(data, sizeof data, "add %u windowPath=%s execPath=%s",
1319
 
                  update->u.addWindow.id,
1320
 
                  windowPathUtf8,
1321
 
                  execPathUtf8);
1322
 
      DynBuf_AppendString(buf, data);
1323
 
      break;
1324
 
 
1325
 
   case UNITY_UPDATE_MOVE_WINDOW:
1326
 
      Str_Sprintf(data, sizeof data, "move %u %d %d %d %d",
1327
 
                  update->u.moveWindow.id,
1328
 
                  update->u.moveWindow.rect.x1,
1329
 
                  update->u.moveWindow.rect.y1,
1330
 
                  update->u.moveWindow.rect.x2,
1331
 
                  update->u.moveWindow.rect.y2);
1332
 
      DynBuf_AppendString(buf, data);
1333
 
      break;
1334
 
 
1335
 
   case UNITY_UPDATE_REMOVE_WINDOW:
1336
 
      /*
1337
 
       * Let the platform know that this window has been removed. This is
1338
 
       * useful on platforms that must poll for window changes.
1339
 
       */
1340
 
      UnityPlatformWillRemoveWindow(unity.up, update->u.removeWindow.id);
1341
 
 
1342
 
      Str_Sprintf(data, sizeof data, "remove %u", update->u.removeWindow.id);
1343
 
      DynBuf_AppendString(buf, data);
1344
 
      break;
1345
 
 
1346
 
   case UNITY_UPDATE_CHANGE_WINDOW_REGION:
1347
 
      /*
1348
 
       * A null region indicates that the region should be deleted.
1349
 
       * Make sure we write "region <id> 0" for the reply.
1350
 
       */
1351
 
      region = update->u.changeWindowRegion.region;
1352
 
      if (region) {
1353
 
         count = REGION_NUM_RECTS(region);
1354
 
      }
1355
 
      Str_Sprintf(data, sizeof data, "region %u %d",
1356
 
                  update->u.changeWindowRegion.id, count);
1357
 
      DynBuf_AppendString(buf, data);
1358
 
 
1359
 
      for (i = 0; i < count; i++) {
1360
 
         BoxPtr p = REGION_RECTS(region) + i;
1361
 
         Str_Sprintf(data, sizeof data, "rect %d %d %d %d",
1362
 
                     p->x1, p->y1, p->x2, p->y2);
1363
 
         DynBuf_AppendString(buf, data);
1364
 
      }
1365
 
      break;
1366
 
 
1367
 
   case UNITY_UPDATE_CHANGE_WINDOW_TITLE:
1368
 
      titleUtf8 = DynBuf_Get(&update->u.changeWindowTitle.titleUtf8);
1369
 
 
1370
 
      if (titleUtf8 &&
1371
 
          (DynBuf_GetSize(&update->u.changeWindowTitle.titleUtf8) ==
1372
 
           strlen(titleUtf8) + 1)) {
1373
 
           Str_Sprintf(data, sizeof data, "title %u ",
1374
 
                       update->u.changeWindowTitle.id);
1375
 
           Str_Strncat(data, sizeof data, titleUtf8, sizeof data - strlen(data) - 1);
1376
 
           data[sizeof data - 1] = '\0';
1377
 
      } else {
1378
 
         Str_Sprintf(data, sizeof data, "title %u",
1379
 
                     update->u.changeWindowTitle.id);
1380
 
      }
1381
 
      DynBuf_AppendString(buf, data);
1382
 
      break;
1383
 
 
1384
 
   case UNITY_UPDATE_CHANGE_ZORDER:
1385
 
      n = Str_Snprintf(data, sizeof data, "zorder %d", update->u.zorder.count);
1386
 
      DynBuf_Append(buf, data, n);
1387
 
      for (i = 0; i < update->u.zorder.count; i++) {
1388
 
         n = Str_Snprintf(data, sizeof data, " %d", update->u.zorder.ids[i]);
1389
 
         DynBuf_Append(buf, data, n);
1390
 
      }
1391
 
      DynBuf_AppendString(buf, ""); // for appending NULL
1392
 
      break;
1393
 
 
1394
 
   case UNITY_UPDATE_CHANGE_WINDOW_STATE:
1395
 
      Str_Sprintf(data, sizeof data, "state %u %u",
1396
 
                  update->u.changeWindowState.id,
1397
 
                  update->u.changeWindowState.state);
1398
 
      DynBuf_AppendString(buf, data);
1399
 
      break;
1400
 
 
1401
 
   case UNITY_UPDATE_CHANGE_WINDOW_ATTRIBUTE:
1402
 
      Str_Sprintf(data, sizeof data, "attr %u %u %u",
1403
 
                  update->u.changeWindowAttribute.id,
1404
 
                  update->u.changeWindowAttribute.attr,
1405
 
                  update->u.changeWindowAttribute.value);
1406
 
      DynBuf_AppendString(buf, data);
1407
 
      break;
1408
 
 
1409
 
   case UNITY_UPDATE_CHANGE_WINDOW_TYPE:
1410
 
      Str_Sprintf(data, sizeof data, "type %u %d",
1411
 
                  update->u.changeWindowType.id,
1412
 
                  update->u.changeWindowType.winType);
1413
 
      DynBuf_AppendString(buf, data);
1414
 
      break;
1415
 
 
1416
 
   case UNITY_UPDATE_CHANGE_WINDOW_ICON:
1417
 
      Str_Sprintf(data, sizeof data, "icon %u %u",
1418
 
                  update->u.changeWindowIcon.id,
1419
 
                  update->u.changeWindowIcon.iconType);
1420
 
      DynBuf_AppendString(buf, data);
1421
 
      break;
1422
 
 
1423
 
   case UNITY_UPDATE_CHANGE_WINDOW_DESKTOP:
1424
 
      Str_Sprintf(data, sizeof data, "desktop %u %d",
1425
 
                  update->u.changeWindowDesktop.id,
1426
 
                  update->u.changeWindowDesktop.desktopId);
1427
 
      DynBuf_AppendString(buf, data);
1428
 
      break;
1429
 
 
1430
 
   case UNITY_UPDATE_CHANGE_ACTIVE_DESKTOP:
1431
 
      Str_Sprintf(data, sizeof data, "activedesktop %d",
1432
 
                  update->u.changeActiveDesktop.desktopId);
1433
 
      DynBuf_AppendString(buf, data);
1434
 
      break;
1435
 
 
1436
 
   default:
1437
 
      NOT_IMPLEMENTED();
1438
 
   }
1439
 
}
1440
 
 
1441
 
 
1442
 
/*
1443
 
 *-----------------------------------------------------------------------------
1444
 
 *
1445
 
 * UnityUpdateChannelInit --
1446
 
 *
1447
 
 *      Initialize the state for the update thread.
1448
 
 *
1449
 
 * Return value:
1450
 
 *      TRUE if all needed data was initialized.
1451
 
 *      FALSE otherwise
1452
 
 *
1453
 
 * Side effects:
1454
 
 *      RpcOut channel might be open.
1455
 
 *      Memory for the update buffer might be allocated.
1456
 
 *
1457
 
 *-----------------------------------------------------------------------------
1458
 
 */
1459
 
 
1460
 
Bool
1461
 
UnityUpdateChannelInit(UnityUpdateChannel *updateChannel) // IN
1462
 
{
1463
 
   ASSERT(updateChannel);
1464
 
 
1465
 
   updateChannel->rpcOut = NULL;
1466
 
   updateChannel->cmdSize = 0;
1467
 
 
1468
 
   DynBuf_Init(&updateChannel->updates);
1469
 
   DynBuf_AppendString(&updateChannel->updates, UNITY_RPC_PUSH_UPDATE_CMD " ");
1470
 
 
1471
 
   /* Exclude the null. */
1472
 
   updateChannel->cmdSize = DynBuf_GetSize(&updateChannel->updates) - 1;
1473
 
   DynBuf_SetSize(&updateChannel->updates, updateChannel->cmdSize);
1474
 
 
1475
 
   updateChannel->rpcOut = RpcOut_Construct();
1476
 
   if (updateChannel->rpcOut == NULL) {
1477
 
      goto error;
1478
 
   }
1479
 
 
1480
 
   if (!RpcOut_start(updateChannel->rpcOut)) {
1481
 
      RpcOut_Destruct(updateChannel->rpcOut);
1482
 
      goto error;
1483
 
   }
1484
 
 
1485
 
   return TRUE;
1486
 
 
1487
 
error:
1488
 
   DynBuf_Destroy(&updateChannel->updates);
1489
 
 
1490
 
   return FALSE;
1491
 
}
1492
 
 
1493
 
 
1494
 
/*
1495
 
 *-----------------------------------------------------------------------------
1496
 
 *
1497
 
 * UnityUpdateChannelCleanup --
1498
 
 *
1499
 
 *      Cleanup the unity update thread state.
1500
 
 *
1501
 
 * Return value:
1502
 
 *      None.
1503
 
 *
1504
 
 * Side effects:
1505
 
 *      RpcOut channel will be closed.
1506
 
 *      Memory will be freed.
1507
 
 *
1508
 
 *-----------------------------------------------------------------------------
1509
 
 */
1510
 
 
1511
 
void
1512
 
UnityUpdateChannelCleanup(UnityUpdateChannel *updateChannel) // IN
1513
 
{
1514
 
   if (updateChannel && updateChannel->rpcOut) {
1515
 
      RpcOut_stop(updateChannel->rpcOut);
1516
 
      RpcOut_Destruct(updateChannel->rpcOut);
1517
 
      updateChannel->rpcOut = NULL;
1518
 
 
1519
 
      DynBuf_Destroy(&updateChannel->updates); // Avoid double-free by guarding this as well
1520
 
   }
1521
 
}
1522
 
 
1523
 
 
1524
 
#ifdef VMX86_DEVEL
1525
 
/*
1526
 
 *-----------------------------------------------------------------------------
1527
 
 *
1528
 
 * DumpUpdate --
1529
 
 *
1530
 
 *      Prints a Unity update via debug output.  NUL is represented as '!'.
1531
 
 *
1532
 
 * Results:
1533
 
 *      None.
1534
 
 *
1535
 
 * Side effects:
1536
 
 *      None.
1537
 
 *
1538
 
 *-----------------------------------------------------------------------------
1539
 
 */
1540
 
 
1541
 
static void
1542
 
DumpUpdate(UnityUpdateChannel *updateChannel)   // IN
1543
 
{
1544
 
   int i, len;
1545
 
   char *buf = NULL;
1546
 
 
1547
 
   len = updateChannel->updates.size;
1548
 
   buf = Util_SafeMalloc(len + 1);
1549
 
   memcpy(buf, updateChannel->updates.data, len);
1550
 
   buf[len] = '\0';
1551
 
   for (i = 0 ; i < len; i++) {
1552
 
      if (buf[i] == '\0') {
1553
 
         buf[i] = '!';
1554
 
      }
1555
 
   }
1556
 
 
1557
 
   Debug("%s: Sending update: %s\n", __FUNCTION__, buf);
1558
 
 
1559
 
   free(buf);
1560
 
}
1561
 
#endif // ifdef VMX86_DEVEL
1562
 
 
1563
 
 
1564
 
/*
1565
 
 *-----------------------------------------------------------------------------
1566
 
 *
1567
 
 * UnitySendUpdates --
1568
 
 *
1569
 
 *      Gather and send a round of unity updates. The caller is responsible
1570
 
 *      for gathering updates into updateChannel->updates buffer prior to the
1571
 
 *      function call. This function should only be called if there's data
1572
 
 *      in the update buffer to avoid sending empty update string to the VMX.
1573
 
 *
1574
 
 * Return value:
1575
 
 *      TRUE if the update was sent,
1576
 
 *      FALSE if something went wrong (an invalid RPC channel, for example).
1577
 
 *
1578
 
 * Side effects:
1579
 
 *      None.
1580
 
 *
1581
 
 *-----------------------------------------------------------------------------
1582
 
 */
1583
 
 
1584
 
Bool
1585
 
UnitySendUpdates(UnityUpdateChannel *updateChannel) // IN
1586
 
{
1587
 
   char const *myReply;
1588
 
   size_t myRepLen;
1589
 
   Bool retry = FALSE;
1590
 
 
1591
 
   ASSERT(updateChannel);
1592
 
   ASSERT(updateChannel->rpcOut);
1593
 
 
1594
 
   /* Send 'tools.unity.push.update <updates>' to the VMX. */
1595
 
 
1596
 
#ifdef VMX86_DEVEL
1597
 
   DumpUpdate(updateChannel);
1598
 
#endif
1599
 
 
1600
 
retry_send:
1601
 
   if (!RpcOut_send(updateChannel->rpcOut,
1602
 
                    (char *)DynBuf_Get(&updateChannel->updates),
1603
 
                    DynBuf_GetSize(&updateChannel->updates),
1604
 
                    &myReply, &myRepLen)) {
1605
 
 
1606
 
      /*
1607
 
       * We could not send the RPC. If we haven't tried to reopen
1608
 
       * the channel, try to reopen and resend. If we already
1609
 
       * tried to resend, then it's time to give up. I hope that
1610
 
       * trying to resend once is enough.
1611
 
       */
1612
 
 
1613
 
      if (!retry) {
1614
 
         retry = TRUE;
1615
 
         Debug("%s: could not send rpc. Reopening channel.\n", __FUNCTION__);
1616
 
         RpcOut_stop(updateChannel->rpcOut);
1617
 
         if (!RpcOut_start(updateChannel->rpcOut)) {
1618
 
            Debug("%s: could not reopen rpc channel. Exiting...\n", __FUNCTION__);
1619
 
            return FALSE;
1620
 
         }
1621
 
         goto retry_send;
1622
 
 
1623
 
      } else {
1624
 
         Debug("%s: could not resend rpc. Giving up and exiting...\n", __FUNCTION__);
1625
 
         return FALSE;
1626
 
      }
1627
 
   }
1628
 
 
1629
 
   /*
1630
 
    * With the update queue sent, purge the DynBuf by trimming it to the length
1631
 
    * of the command preamble.
1632
 
    */
1633
 
   DynBuf_SetSize(&updateChannel->updates, updateChannel->cmdSize);
1634
 
 
1635
 
   return TRUE;
1636
 
}
1637
 
 
1638
 
 
1639
 
/*
1640
 
 *----------------------------------------------------------------------------
1641
 
 *
1642
 
 * UnityTcloGetWindowContents --
1643
 
 *
1644
 
 *     RPC handler for 'unity.get.window.contents'. Suck the bits off the
1645
 
 *     window and return a .png image over the backdoor.
1646
 
 *
1647
 
 * Results:
1648
 
 *     TRUE if everything is successful.
1649
 
 *     FALSE otherwise.
1650
 
 *
1651
 
 * Side effects:
1652
 
 *     None.
1653
 
 *
1654
 
 *----------------------------------------------------------------------------
1655
 
 */
1656
 
 
1657
 
static Bool
1658
 
UnityTcloGetWindowContents(char const **result,     // OUT
1659
 
                           size_t *resultLen,       // OUT
1660
 
                           const char *name,        // IN
1661
 
                           const char *args,        // IN
1662
 
                           size_t argsSize,         // ignored
1663
 
                           void *clientData)        // ignored
1664
 
{
1665
 
   unsigned int window;
1666
 
   unsigned int index = 0;
1667
 
   DynBuf *imageData = &gTcloUpdate;
1668
 
   uint32 width;
1669
 
   uint32 height;
1670
 
 
1671
 
   Debug("UnityTcloGetWindowContents: name:%s args:'%s'\n", name, args);
1672
 
 
1673
 
   /*
1674
 
    * Parse the command & window id.
1675
 
    */
1676
 
   if (!StrUtil_GetNextIntToken(&window, &index, args, " ")) {
1677
 
      Debug("UnityTcloGetWindowContents: Invalid RPC arguments.\n");
1678
 
      return RpcIn_SetRetVals(result, resultLen,
1679
 
                              "failed: arguments. Expected \"windowId\"",
1680
 
                              FALSE);
1681
 
 
1682
 
   }
1683
 
   Debug("UnityTcloGetWindowContents: window %d\n", window);
1684
 
 
1685
 
   /*
1686
 
    * Read the contents of the window, compress it as a .png and
1687
 
    * send the .png back to the vmx as the RPC result.
1688
 
    */
1689
 
   DynBuf_SetSize(imageData, 0);
1690
 
   if (!UnityPlatformGetWindowContents(unity.up, window, imageData, &width, &height)) {
1691
 
      return RpcIn_SetRetVals(result, resultLen,
1692
 
                              "failed: Could not read window contents",
1693
 
                              FALSE);
1694
 
   }
1695
 
 
1696
 
   *result = (char *)DynBuf_Get(imageData);
1697
 
   *resultLen = DynBuf_GetSize(imageData);
1698
 
 
1699
 
   return TRUE;
1700
 
}
1701
 
 
1702
 
 
1703
 
/*
1704
 
 *----------------------------------------------------------------------------
1705
 
 *
1706
 
 * UnityTcloGetIconData --
1707
 
 *
1708
 
 *     RPC handler for 'unity.get.icon.data'. Suck the bits off the
1709
 
 *     window and return a .png image over the backdoor.
1710
 
 *
1711
 
 * Results:
1712
 
 *     TRUE if everything is successful.
1713
 
 *     FALSE otherwise.
1714
 
 *
1715
 
 * Side effects:
1716
 
 *     None.
1717
 
 *
1718
 
 *----------------------------------------------------------------------------
1719
 
 */
1720
 
 
1721
 
static Bool
1722
 
UnityTcloGetIconData(char const **result,     // OUT
1723
 
                     size_t *resultLen,       // OUT
1724
 
                     const char *name,        // IN
1725
 
                     const char *args,        // IN
1726
 
                     size_t argsSize,         // ignored
1727
 
                     void *clientData)        // ignored
1728
 
{
1729
 
   UnityWindowId window;
1730
 
   UnityIconType iconType;
1731
 
   UnityIconSize iconSize;
1732
 
   unsigned int dataOffset, dataLength;
1733
 
   uint32 fullLength;
1734
 
   size_t retLength;
1735
 
   DynBuf *results = &gTcloUpdate, imageData;
1736
 
   char data[1024];
1737
 
 
1738
 
   Debug("UnityTcloGetIconData: name:%s args:'%s'\n", name, args);
1739
 
 
1740
 
   /*
1741
 
    * Parse the arguments.
1742
 
    */
1743
 
   if ((sscanf(args, "%u %u %u %u %u",
1744
 
               &window,
1745
 
               &iconType,
1746
 
               &iconSize,
1747
 
               &dataOffset,
1748
 
               &dataLength) != 5)
1749
 
       || (dataLength > UNITY_MAX_ICON_DATA_CHUNK)) {
1750
 
      Debug("UnityTcloGetIconData: Invalid RPC arguments.\n");
1751
 
      return RpcIn_SetRetVals(result, resultLen,
1752
 
                              "failed: arguments missing",
1753
 
                              FALSE);
1754
 
   }
1755
 
 
1756
 
   Debug("%s: window %u iconType %u" \
1757
 
         " iconSize %u dataOffset %u dataLength %u\n",
1758
 
         __FUNCTION__,
1759
 
         window, iconType, iconSize, dataOffset, dataLength);
1760
 
 
1761
 
   /*
1762
 
    * Retrieve part/all of the icon in PNG format.
1763
 
    */
1764
 
   DynBuf_Init(&imageData);
1765
 
   if (!UnityPlatformGetIconData(unity.up, window, iconType, iconSize,
1766
 
                                 dataOffset, dataLength, &imageData, &fullLength)) {
1767
 
      return RpcIn_SetRetVals(result, resultLen,
1768
 
                              "failed: Could not read icon data properly",
1769
 
                              FALSE);
1770
 
   }
1771
 
 
1772
 
 
1773
 
   DynBuf_SetSize(results, 0);
1774
 
   retLength = DynBuf_GetSize(&imageData);
1775
 
   retLength = MIN(retLength, UNITY_MAX_ICON_DATA_CHUNK);
1776
 
   DynBuf_Append(results, data, Str_Snprintf(data, sizeof data, "%u %" FMTSZ "u ",
1777
 
                                             fullLength, retLength));
1778
 
   DynBuf_Append(results, DynBuf_Get(&imageData), retLength);
1779
 
 
1780
 
   /*
1781
 
    * Guarantee that the results have a trailing \0 in case anything does a strlen...
1782
 
    */
1783
 
   DynBuf_AppendString(results, "");
1784
 
   *result = (char *)DynBuf_Get(results);
1785
 
   *resultLen = DynBuf_GetSize(results);
1786
 
   DynBuf_Destroy(&imageData);
1787
 
 
1788
 
   return TRUE;
1789
 
}
1790
 
 
1791
 
 
1792
 
/*
1793
 
 *----------------------------------------------------------------------------
1794
 
 *
1795
 
 * UnityTcloShowTaskbar --
1796
 
 *
1797
 
 *     RPC handler for 'unity.show.taskbar'.
1798
 
 *
1799
 
 * Results:
1800
 
 *     TRUE if everything is successful.
1801
 
 *     FALSE otherwise.
1802
 
 *
1803
 
 * Side effects:
1804
 
 *     None.
1805
 
 *
1806
 
 *----------------------------------------------------------------------------
1807
 
 */
1808
 
 
1809
 
static Bool
1810
 
UnityTcloShowTaskbar(char const **result,     // OUT
1811
 
                     size_t *resultLen,       // OUT
1812
 
                     const char *name,        // IN
1813
 
                     const char *args,        // IN
1814
 
                     size_t argsSize,         // IN: Size of args
1815
 
                     void *clientData)        // ignored
1816
 
{
1817
 
   uint32 command = 0;
1818
 
   unsigned int index = 0;
1819
 
 
1820
 
   Debug("%s: name:%s args:'%s'\n", __FUNCTION__, name, args);
1821
 
 
1822
 
   if (!StrUtil_GetNextUintToken(&command, &index, args, " ")) {
1823
 
      Debug("%s: Invalid RPC arguments.\n", __FUNCTION__);
1824
 
      return RpcIn_SetRetVals(result, resultLen,
1825
 
                              "Invalid arguments.",
1826
 
                              FALSE);
1827
 
   }
1828
 
 
1829
 
   Debug("%s: command %d\n", __FUNCTION__, command);
1830
 
 
1831
 
   UnityPlatformShowTaskbar(unity.up, (command == 0) ? FALSE : TRUE);
1832
 
 
1833
 
   return RpcIn_SetRetVals(result, resultLen, "", TRUE);
1834
 
}
1835
 
 
1836
 
 
1837
 
/*
1838
 
 *----------------------------------------------------------------------------
1839
 
 *
1840
 
 * UnityTcloMoveResizeWindow --
1841
 
 *
1842
 
 *     RPC handler for 'unity.window.move_resize'.
1843
 
 *
1844
 
 * Results:
1845
 
 *     TRUE if everything is successful.
1846
 
 *     FALSE otherwise.
1847
 
 *     If successful adds null terminated strings for each output coordinates.
1848
 
 *
1849
 
 * Side effects:
1850
 
 *     None.
1851
 
 *
1852
 
 *----------------------------------------------------------------------------
1853
 
 */
1854
 
 
1855
 
static Bool
1856
 
UnityTcloMoveResizeWindow(char const **result,     // OUT
1857
 
                          size_t *resultLen,       // OUT
1858
 
                          const char *name,        // IN
1859
 
                          const char *args,        // IN
1860
 
                          size_t argsSize,         // IN: Size of args
1861
 
                          void *clientData)        // ignored
1862
 
{
1863
 
   DynBuf *buf = &gTcloUpdate;
1864
 
   UnityWindowId window;
1865
 
   UnityRect moveResizeRect = {0};
1866
 
   char temp[1024];
1867
 
 
1868
 
   Debug("%s: name:%s args:'%s'\n", __FUNCTION__, name, args);
1869
 
 
1870
 
   if (sscanf(args, "%u %d %d %d %d",
1871
 
              &window,
1872
 
              &moveResizeRect.x,
1873
 
              &moveResizeRect.y,
1874
 
              &moveResizeRect.width,
1875
 
              &moveResizeRect.height) != 5) {
1876
 
      Debug("%s: Invalid RPC arguments.\n", __FUNCTION__);
1877
 
      return RpcIn_SetRetVals(result, resultLen,
1878
 
                              "Invalid arguments.",
1879
 
                              FALSE);
1880
 
   }
1881
 
 
1882
 
   if (!UnityPlatformMoveResizeWindow(unity.up, window, &moveResizeRect)) {
1883
 
      Debug("%s: Could not read window coordinates.\n", __FUNCTION__);
1884
 
      return RpcIn_SetRetVals(result, resultLen,
1885
 
                              "Could not read window coordinates",
1886
 
                              FALSE);
1887
 
   }
1888
 
 
1889
 
   /*
1890
 
    *  Send back the new (post move/resize operation) window coordinates.
1891
 
    */
1892
 
 
1893
 
   DynBuf_SetSize(buf, 0);
1894
 
   Str_Sprintf(temp, sizeof temp, "%d %d %d %d", moveResizeRect.x,
1895
 
               moveResizeRect.y, moveResizeRect.width, moveResizeRect.height);
1896
 
   DynBuf_AppendString(buf, temp);
1897
 
 
1898
 
   /*
1899
 
    * Write the final result into the result out parameters and return!
1900
 
    */
1901
 
 
1902
 
   *result = (char *)DynBuf_Get(buf);
1903
 
   *resultLen = DynBuf_GetSize(buf);
1904
 
 
1905
 
   return TRUE;
1906
 
}
1907
 
 
1908
 
 
1909
 
/*
1910
 
 *----------------------------------------------------------------------------
1911
 
 *
1912
 
 * UnityTcloSetDesktopConfig --
1913
 
 *
1914
 
 *     RPC handler for 'unity.set.desktop.config'. The RPC takes the form of:
1915
 
 *     {1,1} {1,2} {2,1} {2,2} 1
1916
 
 *     for a 2 x 2 virtual desktop where the upper right {1,2} is the currently
1917
 
 *     active desktop.
1918
 
 *
1919
 
 * Results:
1920
 
 *     TRUE if everything is successful.
1921
 
 *     FALSE otherwise.
1922
 
 *
1923
 
 * Side effects:
1924
 
 *     Might change virtual desktop configuration in the guest.
1925
 
 *
1926
 
 *----------------------------------------------------------------------------
1927
 
 */
1928
 
 
1929
 
static Bool
1930
 
UnityTcloSetDesktopConfig(char const **result,  // OUT
1931
 
                          size_t *resultLen,    // OUT
1932
 
                          const char *name,     // IN
1933
 
                          const char *args,     // IN
1934
 
                          size_t argsSize,      // IN
1935
 
                          void *clientData)     // IN: ignored
1936
 
{
1937
 
   unsigned int index = 0;
1938
 
   char *desktopStr = NULL;
1939
 
   char *errorMsg;
1940
 
   uint32 initialDesktopIndex = 0;
1941
 
 
1942
 
   Debug("%s: name:%s args:'%s'\n", __FUNCTION__, name, args);
1943
 
 
1944
 
   if (argsSize == 0) {
1945
 
      errorMsg = "Invalid arguments: desktop config is expected";
1946
 
      goto error;
1947
 
   }
1948
 
 
1949
 
   unity.virtDesktopArray.desktopCount = 0;
1950
 
   /* Read the virtual desktop configuration. */
1951
 
   while ((desktopStr = StrUtil_GetNextToken(&index, args, " ")) != NULL) {
1952
 
      UnityVirtualDesktop desktop;
1953
 
      uint32 desktopCount = unity.virtDesktopArray.desktopCount;
1954
 
 
1955
 
      if (sscanf(desktopStr, "{%d,%d}", &desktop.x, &desktop.y) == 2) {
1956
 
         if (desktopCount >= MAX_VIRT_DESK - 1) {
1957
 
            errorMsg = "Invalid arguments: too many desktops";
1958
 
            goto error;
1959
 
         }
1960
 
         unity.virtDesktopArray.desktops[desktopCount] = desktop;
1961
 
         unity.virtDesktopArray.desktopCount++;
1962
 
      } else if (sscanf(desktopStr, "%u", &initialDesktopIndex) == 1) {
1963
 
         if (initialDesktopIndex >= unity.virtDesktopArray.desktopCount) {
1964
 
            errorMsg = "Invalid arguments: current desktop is out of bounds";
1965
 
            goto error;
1966
 
         }
1967
 
         /* All done with arguments at this point - stop processing */
1968
 
         free(desktopStr);
1969
 
         break;
1970
 
      } else {
1971
 
         errorMsg = "Invalid arguments: invalid desktop config";
1972
 
         goto error;
1973
 
      }
1974
 
      free(desktopStr);
1975
 
      desktopStr = NULL;
1976
 
   }
1977
 
 
1978
 
   /*
1979
 
    * Call the platform specific function to set the desktop configuration.
1980
 
    */
1981
 
 
1982
 
   if (!UnityPlatformSetDesktopConfig(unity.up, &unity.virtDesktopArray)) {
1983
 
      errorMsg = "Could not set desktop configuration";
1984
 
      goto error;
1985
 
   }
1986
 
 
1987
 
   if (!UnityPlatformSetInitialDesktop(unity.up, initialDesktopIndex)) {
1988
 
      errorMsg = "Could not set initial desktop";
1989
 
      goto error;
1990
 
   }
1991
 
 
1992
 
   return RpcIn_SetRetVals(result, resultLen,
1993
 
                           "",
1994
 
                           TRUE);
1995
 
error:
1996
 
   free(desktopStr);
1997
 
   unity.virtDesktopArray.desktopCount = 0;
1998
 
   Debug("%s: %s\n", __FUNCTION__, errorMsg);
1999
 
 
2000
 
   return RpcIn_SetRetVals(result, resultLen,
2001
 
                           errorMsg,
2002
 
                           FALSE);
2003
 
}
2004
 
 
2005
 
 
2006
 
/*
2007
 
 *----------------------------------------------------------------------------
2008
 
 *
2009
 
 * UnityTcloSetDesktopActive --
2010
 
 *
2011
 
 *     RPC handler for 'unity.set.desktop.active'.
2012
 
 *
2013
 
 * Results:
2014
 
 *     TRUE if everything is successful.
2015
 
 *     FALSE otherwise.
2016
 
 *
2017
 
 * Side effects:
2018
 
 *     Might change the active virtual desktop in the guest.
2019
 
 *
2020
 
 *----------------------------------------------------------------------------
2021
 
 */
2022
 
 
2023
 
static Bool
2024
 
UnityTcloSetDesktopActive(char const **result,  // OUT
2025
 
                          size_t *resultLen,    // OUT
2026
 
                          const char *name,     // IN
2027
 
                          const char *args,     // IN
2028
 
                          size_t argsSize,      // IN
2029
 
                          void *clientData)     // IN: ignored
2030
 
{
2031
 
   UnityDesktopId desktopId = 0;
2032
 
   char *errorMsg;
2033
 
 
2034
 
   Debug("%s: name:%s args:'%s'\n", __FUNCTION__, name, args);
2035
 
 
2036
 
   if (unity.isEnabled == FALSE) {
2037
 
      errorMsg = "Unity not enabled - cannot change active desktop";
2038
 
      goto error;
2039
 
   }
2040
 
 
2041
 
   if (sscanf(args, " %d", &desktopId) != 1) {
2042
 
      errorMsg = "Invalid arguments: expected \"desktopId\"";
2043
 
      goto error;
2044
 
   }
2045
 
 
2046
 
   if (desktopId >= unity.virtDesktopArray.desktopCount) {
2047
 
      errorMsg = "Desktop does not exist in the guest";
2048
 
      goto error;
2049
 
   }
2050
 
 
2051
 
   /*
2052
 
    * Call the platform specific function to set the desktop active.
2053
 
    */
2054
 
 
2055
 
   if (!UnityPlatformSetDesktopActive(unity.up, desktopId)) {
2056
 
      errorMsg = "Could not set active desktop";
2057
 
      goto error;
2058
 
   }
2059
 
 
2060
 
   return RpcIn_SetRetVals(result, resultLen,
2061
 
                           "",
2062
 
                           TRUE);
2063
 
error:
2064
 
   Debug("%s: %s\n", __FUNCTION__, errorMsg);
2065
 
   return RpcIn_SetRetVals(result, resultLen,
2066
 
                           errorMsg,
2067
 
                           FALSE);
2068
 
}
2069
 
 
2070
 
 
2071
 
/*
2072
 
 *----------------------------------------------------------------------------
2073
 
 *
2074
 
 * UnityTcloSetWindowDesktop --
2075
 
 *
2076
 
 *     RPC handler for 'unity.set.window.desktop'.
2077
 
 *
2078
 
 * Results:
2079
 
 *     TRUE if everything is successful.
2080
 
 *     FALSE otherwise.
2081
 
 *
2082
 
 * Side effects:
2083
 
 *     Might change the active virtual desktop in the guest.
2084
 
 *
2085
 
 *----------------------------------------------------------------------------
2086
 
 */
2087
 
 
2088
 
static Bool
2089
 
UnityTcloSetWindowDesktop(char const **result,  // OUT
2090
 
                          size_t *resultLen,    // OUT
2091
 
                          const char *name,     // IN
2092
 
                          const char *args,     // IN
2093
 
                          size_t argsSize,      // IN
2094
 
                          void *clientData)     // IN: ignored
2095
 
{
2096
 
   UnityWindowId windowId;
2097
 
   uint32 desktopId = 0;
2098
 
   char *errorMsg;
2099
 
 
2100
 
   Debug("%s: name:%s args:'%s'\n", __FUNCTION__, name, args);
2101
 
 
2102
 
   if (unity.isEnabled == FALSE) {
2103
 
      errorMsg = "Unity not enabled - cannot set window desktop";
2104
 
      goto error;
2105
 
   }
2106
 
 
2107
 
   if (sscanf(args, " %u %d", &windowId, &desktopId) != 2) {
2108
 
      errorMsg = "Invalid arguments: expected \"windowId desktopId\"";
2109
 
      goto error;
2110
 
   }
2111
 
 
2112
 
   if (desktopId >= unity.virtDesktopArray.desktopCount) {
2113
 
      errorMsg = "The desktop does not exist in the guest";
2114
 
      goto error;
2115
 
   }
2116
 
 
2117
 
   /*
2118
 
    * Set the desktop id for this window in the tracker.
2119
 
    * We need to do this before moving the window since on MS Windows platforms
2120
 
    * moving the window will hide it and there's a danger that we may enumerate the
2121
 
    * hidden window before changing it's desktop ID. The Window tracker will ignore
2122
 
    * hidden windows on the current desktop - which ultimately can lead to this window
2123
 
    * being reaped from the tracker.
2124
 
    */
2125
 
   UnityWindowTracker_ChangeWindowDesktop(&unity.tracker, windowId, desktopId);
2126
 
 
2127
 
   /*
2128
 
    * Call the platform specific function to move the window to the
2129
 
    * specified desktop.
2130
 
    */
2131
 
 
2132
 
   if (!UnityPlatformSetWindowDesktop(unity.up, windowId, desktopId)) {
2133
 
      errorMsg = "Could not move the window to the desktop";
2134
 
      goto error;
2135
 
   }
2136
 
 
2137
 
   return RpcIn_SetRetVals(result, resultLen,
2138
 
                           "",
2139
 
                           TRUE);
2140
 
error:
2141
 
   Debug("%s: %s\n", __FUNCTION__, errorMsg);
2142
 
   return RpcIn_SetRetVals(result, resultLen,
2143
 
                           errorMsg,
2144
 
                           FALSE);
2145
 
}
2146
 
 
2147
 
 
2148
 
/*
2149
 
 *----------------------------------------------------------------------------
2150
 
 *
2151
 
 * UnityTcloSetUnityOptions --
2152
 
 *
2153
 
 *     Set the Unity options - must be be called before entering Unity mode.
2154
 
 *
2155
 
 * Results:
2156
 
 *     TRUE if RPC was succesfully handled.
2157
 
 *     FALSE otherwise.
2158
 
 *
2159
 
 * Side effects:
2160
 
 *     None.
2161
 
 *
2162
 
 *----------------------------------------------------------------------------
2163
 
 */
2164
 
 
2165
 
Bool
2166
 
UnityTcloSetUnityOptions(RpcInData *data)
2167
 
{
2168
 
   Bool ret = TRUE;
2169
 
   UnityOptions optionsMsg;
2170
 
   int featureIndex = 0;
2171
 
   uint32 featuresChanged;
2172
 
 
2173
 
   memset(&optionsMsg, 0, sizeof optionsMsg);
2174
 
 
2175
 
   /* Check our arguments. */
2176
 
   ASSERT(data);
2177
 
   ASSERT(data->name);
2178
 
   ASSERT(data->args);
2179
 
 
2180
 
   if (!(data && data->name && data->args)) {
2181
 
      Debug("%s: Invalid arguments.\n", __FUNCTION__);
2182
 
      ret = RPCIN_SETRETVALS(data, "Invalid arguments.", FALSE);
2183
 
      goto exit;
2184
 
   }
2185
 
 
2186
 
   Debug("%s: Got RPC, name: \"%s\", argument length: %"FMTSZ"u.\n",
2187
 
         __FUNCTION__, data->name, data->argsSize);
2188
 
 
2189
 
   /*
2190
 
    * Deserialize the XDR data. Note that the data begins with args + 1 since
2191
 
    * there is a space between the RPC name and the XDR serialization.
2192
 
    */
2193
 
   if (!XdrUtil_Deserialize((char *)data->args + 1, data->argsSize - 1,
2194
 
                            xdr_UnityOptions, &optionsMsg)) {
2195
 
      Debug("%s: Failed to deserialize data\n", __FUNCTION__);
2196
 
      ret = RPCIN_SETRETVALS(data, "Failed to deserialize data.", FALSE);
2197
 
      goto exit;
2198
 
   }
2199
 
 
2200
 
   /*
2201
 
    * For each potential feature bit XOR the current mask with the newly
2202
 
    * specified set, then if the bit has changed call the specific setter
2203
 
    * function with TRUE/FALSE according to the new state of the bit.
2204
 
    */
2205
 
   featuresChanged = optionsMsg.UnityOptions_u.unityOptionsV1->featureMask ^
2206
 
                     unity.currentOptions;
2207
 
   while (unityFeatureTable[featureIndex].featureBit != 0) {
2208
 
      if (featuresChanged & unityFeatureTable[featureIndex].featureBit) {
2209
 
         unityFeatureTable[featureIndex].setter(
2210
 
            (optionsMsg.UnityOptions_u.unityOptionsV1->featureMask &
2211
 
            unityFeatureTable[featureIndex].featureBit) != 0);
2212
 
      }
2213
 
      featureIndex++;
2214
 
   }
2215
 
 
2216
 
   unity.currentOptions = optionsMsg.UnityOptions_u.unityOptionsV1->featureMask;
2217
 
 
2218
 
   ret = RPCIN_SETRETVALS(data,
2219
 
                          "",
2220
 
                          TRUE);
2221
 
exit:
2222
 
   VMX_XDR_FREE(xdr_UnityOptions, &optionsMsg);
2223
 
 
2224
 
   return ret;
2225
 
}
2226
 
 
2227
 
 
2228
 
/*
2229
 
 *----------------------------------------------------------------------------
2230
 
 *
2231
 
 * UnityTcloRequestWindowContents --
2232
 
 *
2233
 
 *     Request the window contents for a set of windows.
2234
 
 *
2235
 
 * Results:
2236
 
 *     TRUE if all the window IDs are valid.
2237
 
 *     FALSE otherwise.
2238
 
 *
2239
 
 * Side effects:
2240
 
 *     None.
2241
 
 *
2242
 
 *----------------------------------------------------------------------------
2243
 
 */
2244
 
 
2245
 
Bool
2246
 
UnityTcloRequestWindowContents(RpcInData *data)    // IN
2247
 
{
2248
 
   Bool ret = TRUE;
2249
 
   UnityWindowContentsRequest requestMsg;
2250
 
   UnityWindowContentsRequestV1 *requestV1 = NULL;
2251
 
   memset(&requestMsg, 0, sizeof requestMsg);
2252
 
 
2253
 
   /* Check our arguments. */
2254
 
   ASSERT(data);
2255
 
   ASSERT(data->name);
2256
 
   ASSERT(data->args);
2257
 
 
2258
 
   if (!(data && data->name && data->args)) {
2259
 
      Debug("%s: Invalid arguments.\n", __FUNCTION__);
2260
 
      ret = RPCIN_SETRETVALS(data, "Invalid arguments.", FALSE);
2261
 
      goto exit;
2262
 
   }
2263
 
 
2264
 
   Debug("%s: Got RPC, name: \"%s\", argument length: %"FMTSZ"u.\n",
2265
 
         __FUNCTION__, data->name, data->argsSize);
2266
 
 
2267
 
   /*
2268
 
    * Deserialize the XDR data. Note that the data begins with args + 1 since
2269
 
    * there is a space between the RPC name and the XDR serialization.
2270
 
    */
2271
 
   if (!XdrUtil_Deserialize((char *)data->args + 1, data->argsSize - 1,
2272
 
                            xdr_UnityWindowContentsRequest, &requestMsg)) {
2273
 
      Debug("%s: Failed to deserialize data\n", __FUNCTION__);
2274
 
      ret = RPCIN_SETRETVALS(data, "Failed to deserialize data.", FALSE);
2275
 
      goto exit;
2276
 
   }
2277
 
 
2278
 
   if (requestMsg.ver != UNITY_WINDOW_CONTENTS_V1) {
2279
 
      Debug("%s: Unexpected XDR version = %d\n", __FUNCTION__, requestMsg.ver);
2280
 
      goto exit;
2281
 
   }
2282
 
 
2283
 
   requestV1 = requestMsg.UnityWindowContentsRequest_u.requestV1;
2284
 
 
2285
 
   /*
2286
 
    * Call the platform implementation of the RPC handler.
2287
 
    */
2288
 
   if (!UnityPlatformRequestWindowContents(unity.up,
2289
 
                                           requestV1->windowID.windowID_val,
2290
 
                                           requestV1->windowID.windowID_len)) {
2291
 
      ret = RPCIN_SETRETVALS(data, "Invalid list of windows.", FALSE);
2292
 
      goto exit;
2293
 
   }
2294
 
 
2295
 
   ret = RPCIN_SETRETVALS(data,
2296
 
                          "",
2297
 
                          TRUE);
2298
 
exit:
2299
 
   VMX_XDR_FREE(xdr_UnityWindowContentsRequest, &requestMsg);
2300
 
 
2301
 
   return ret;
2302
 
}
2303
 
 
2304
 
 
2305
 
/*
2306
 
 *----------------------------------------------------------------------------
2307
 
 *
2308
 
 * UnityUpdateState --
2309
 
 *
2310
 
 *     Communicate unity state changes to vmx.
2311
 
 *
2312
 
 * Results:
2313
 
 *     TRUE if everything is successful.
2314
 
 *     FALSE otherwise.
2315
 
 *
2316
 
 * Side effects:
2317
 
 *     None.
2318
 
 *
2319
 
 *----------------------------------------------------------------------------
2320
 
 */
2321
 
 
2322
 
static Bool
2323
 
UnityUpdateState(void)
2324
 
{
2325
 
   Bool ret = TRUE;
2326
 
   XDR xdrs;
2327
 
   UnityActiveProto message;
2328
 
   char *val;
2329
 
 
2330
 
   if (DynXdr_Create(&xdrs) == NULL) {
2331
 
      return FALSE;
2332
 
   }
2333
 
 
2334
 
   val = Str_Asprintf(NULL, "%s ", UNITY_RPC_UNITY_ACTIVE);
2335
 
   if (!val || !DynXdr_AppendRaw(&xdrs, val, strlen(val))) {
2336
 
      Debug("%s: Failed to create state string.\n", __FUNCTION__);
2337
 
      ret = FALSE;
2338
 
      goto out;
2339
 
   }
2340
 
   memset(&message, 0, sizeof message);
2341
 
   message.ver = UNITY_ACTIVE_V1;
2342
 
   message.UnityActiveProto_u.unityActive = unity.isEnabled;
2343
 
   if (!xdr_UnityActiveProto(&xdrs, &message)) {
2344
 
      Debug("%s: Failed to append message content.\n", __FUNCTION__);
2345
 
      ret = FALSE;
2346
 
      goto out;
2347
 
   }
2348
 
 
2349
 
   if (!RpcOut_SendOneRaw(DynXdr_Get(&xdrs), xdr_getpos(&xdrs), NULL, NULL)) {
2350
 
      Debug("%s: Failed to send Unity state RPC.\n", __FUNCTION__);
2351
 
      ret = FALSE;
2352
 
   } else {
2353
 
      Debug("%s: success\n", __FUNCTION__);
2354
 
   }
2355
 
out:
2356
 
   free(val);
2357
 
   DynXdr_Destroy(&xdrs, TRUE);
2358
 
   return ret;
2359
 
}
2360
 
 
2361
 
 
2362
 
/*
2363
 
 *----------------------------------------------------------------------------
2364
 
 *
2365
 
 * UnityXdrRequestOperation --
2366
 
 *
2367
 
 *    XDR encoder function for UnityRequestOperation.
2368
 
 *
2369
 
 *    See UnityXdrSendRpc().
2370
 
 *
2371
 
 * Results:
2372
 
 *    Returns true if the XDR struct was encoded successfully.
2373
 
 *
2374
 
 * Side-effects:
2375
 
 *    None.
2376
 
 *------------------------------------------------------------------------------
2377
 
 */
2378
 
 
2379
 
Bool
2380
 
UnityXdrRequestOperation(XDR *xdrs,    // IN
2381
 
                         void *arg)    // IN
2382
 
{
2383
 
   ASSERT(xdrs);
2384
 
   ASSERT(arg);
2385
 
   return xdr_UnityRequestOperation(xdrs, (UnityRequestOperation *) arg);
2386
 
}
2387
 
 
2388
 
 
2389
 
/*
2390
 
 *------------------------------------------------------------------------------
2391
 
 *
2392
 
 * UnitySendRequestMinimizeOperation --
2393
 
 *
2394
 
 *     Send a request for a minimize operation to the host.
2395
 
 *
2396
 
 * Results:
2397
 
 *     TRUE if everything is successful.
2398
 
 *     FALSE otherwise.
2399
 
 *
2400
 
 * Side effects:
2401
 
 *     None.
2402
 
 *
2403
 
 *----------------------------------------------------------------------------
2404
 
 */
2405
 
 
2406
 
Bool
2407
 
UnitySendRequestMinimizeOperation(UnityWindowId windowId,   // IN
2408
 
                                  uint32 sequence)          // IN
2409
 
{
2410
 
   Bool ret = FALSE;
2411
 
   UnityRequestOperation msg = { 0 };
2412
 
   UnityRequestOperationV1 v1 = { 0 };
2413
 
 
2414
 
   Debug("%s: Enter.\n", __FUNCTION__);
2415
 
 
2416
 
   v1.windowId = windowId;
2417
 
   v1.sequence = sequence;
2418
 
   v1.details.op = MINIMIZE;
2419
 
 
2420
 
   msg.ver = UNITY_OP_V1;
2421
 
   msg.UnityRequestOperation_u.unityRequestOpV1 = &v1;
2422
 
 
2423
 
   ret = UnityXdrSendRpc(UNITY_RPC_REQUEST_OPERATION,
2424
 
                         &UnityXdrRequestOperation,
2425
 
                         &msg);
2426
 
 
2427
 
   Debug("%s: Exit.\n", __FUNCTION__);
2428
 
   return ret;
2429
 
}
2430
 
 
2431
 
 
2432
 
/*
2433
 
 *----------------------------------------------------------------------------
2434
 
 *
2435
 
 * UnitySendWindowContents --
2436
 
 *
2437
 
 *     Sends the content of a window to the host, as a PNG encoded image. If the
2438
 
 *     image is larger than the maximum size of a GuestMsg, this function breaks
2439
 
 *     the image down into a number of chunks, then transfers each of the chunks
2440
 
 *     independently. See guest_msg_def.h and unity.x.
2441
 
 *
2442
 
 * Results:
2443
 
 *     Returns true if the image was transferred successfully.
2444
 
 *
2445
 
 * Side effects:
2446
 
 *     None.
2447
 
 *
2448
 
 *------------------------------------------------------------------------------
2449
 
 */
2450
 
 
2451
 
Bool
2452
 
UnitySendWindowContents(UnityWindowId windowID, // IN
2453
 
                        uint32 imageWidth,      // IN
2454
 
                        uint32 imageHeight,     // IN
2455
 
                        const char *imageData,  // IN
2456
 
                        uint32 imageLength)     // IN
2457
 
{
2458
 
   Bool ret = FALSE;
2459
 
   uint32 count = 0;                /* count of chunks sent */
2460
 
   uint32 len = 0;                  /* length of the next chunk */
2461
 
   const char *readptr = imageData; /* pointer to start of next chunk in imageData */
2462
 
 
2463
 
   ASSERT(imageWidth > 0);
2464
 
   ASSERT(imageHeight > 0);
2465
 
   ASSERT(imageLength > 0);
2466
 
   ASSERT(imageData);
2467
 
 
2468
 
   Debug("%s: Enter.\n", __FUNCTION__);
2469
 
   Debug("%s: Sending contents of window 0x%x.\n", __FUNCTION__, windowID);
2470
 
   Debug("%s: Contents are (%u x %u) image, %u bytes.\n", __FUNCTION__,
2471
 
         imageWidth, imageHeight, imageLength);
2472
 
 
2473
 
   /* Send the unity.window.contents.start RPC to the host. */
2474
 
   if (!UnitySendWindowContentsStart(windowID,
2475
 
                                     imageWidth,
2476
 
                                     imageHeight,
2477
 
                                     imageLength)) {
2478
 
      goto exit;
2479
 
   }
2480
 
 
2481
 
   /* Send the image data. */
2482
 
   while (imageLength > 0) {
2483
 
      /*
2484
 
       * Get the length of the next chunk to send, up to a maximum of
2485
 
       * UNITY_WINDOW_CONTENTS_MAX_CHUNK_SIZE bytes.
2486
 
       */
2487
 
      len = MIN(UNITY_WINDOW_CONTENTS_MAX_CHUNK_SIZE, imageLength);
2488
 
 
2489
 
      Debug("%s: Sending chunk %u at offset 0x%p, size %u.\n", __FUNCTION__,
2490
 
            count, readptr, len);
2491
 
 
2492
 
      /* Send the next chunk to the host. */
2493
 
      if (!UnitySendWindowContentsChunk(windowID, count, readptr, len)) {
2494
 
         goto exit;
2495
 
      }
2496
 
 
2497
 
      count++;
2498
 
      readptr += len;
2499
 
      imageLength -= len;
2500
 
   }
2501
 
 
2502
 
   /* Send the unity.window.contents.end RPC to the host. */
2503
 
   if (!UnitySendWindowContentsEnd(windowID)) {
2504
 
      goto exit;
2505
 
   }
2506
 
 
2507
 
   ret = TRUE;
2508
 
 
2509
 
exit:
2510
 
   return ret;
2511
 
}
2512
 
 
2513
 
 
2514
 
/*
2515
 
 *----------------------------------------------------------------------------
2516
 
 *
2517
 
 * UnitySetAddHiddenWindows --
2518
 
 *
2519
 
 *     Set (or unset) whether hidden windows should be added to the tracker.
2520
 
 *
2521
 
 * Results:
2522
 
 *     None.
2523
 
 *
2524
 
 * Side effects:
2525
 
 *     None.
2526
 
 *
2527
 
 *----------------------------------------------------------------------------
2528
 
 */
2529
 
 
2530
 
void
2531
 
UnitySetAddHiddenWindows(Bool enabled)
2532
 
{
2533
 
   /*
2534
 
    * Should we add hidden windows to the tracker (the host will use the trackers
2535
 
    * attribute field to display hidden windows in the appropriate manner.)
2536
 
    */
2537
 
   if (enabled) {
2538
 
      Debug("%s: Adding hidden windows to tracker\n", __FUNCTION__);
2539
 
   } else {
2540
 
      Debug("%s: Do not add hidden windows to tracker\n", __FUNCTION__);
2541
 
   }
2542
 
}
2543
 
 
2544
 
 
2545
 
/*
2546
 
 *----------------------------------------------------------------------------
2547
 
 *
2548
 
 * UnitySetInterlockMinimizeOperation --
2549
 
 *
2550
 
 *     Set (or unset) whether window operations should be denied/delayed and
2551
 
 *     relayed to the host for later confirmation.
2552
 
 *
2553
 
 * Results:
2554
 
 *     None.
2555
 
 *
2556
 
 * Side effects:
2557
 
 *     None.
2558
 
 *
2559
 
 *----------------------------------------------------------------------------
2560
 
 */
2561
 
 
2562
 
void
2563
 
UnitySetInterlockMinimizeOperation(Bool enabled)
2564
 
{
2565
 
   /*
2566
 
    * Should we interlock operations through the host. For example: instead of
2567
 
    * allowing minimize to occur immediately in the guest should we prevent the
2568
 
    * minimize of a window in the guest, then relay the minimize to the host and wait
2569
 
    * for the hosts confirmation before actually minimizing the window in the guest.
2570
 
    */
2571
 
   if (enabled) {
2572
 
      Debug("%s: Interlocking minimize operations through the host\n",
2573
 
            __FUNCTION__);
2574
 
   } else {
2575
 
      Debug("%s: Do not interlock minimize operations through the host\n",
2576
 
            __FUNCTION__);
2577
 
   }
2578
 
   UnityPlatformSetInterlockMinimizeOperation(unity.up, enabled);
2579
 
}
2580
 
 
2581
 
 
2582
 
/*
2583
 
 *----------------------------------------------------------------------------
2584
 
 *
2585
 
 * UnitySetSendWindowContents --
2586
 
 *
2587
 
 *     Set (or unset) whether window contents should be sent to the host.
2588
 
 *
2589
 
 * Results:
2590
 
 *     None.
2591
 
 *
2592
 
 * Side effects:
2593
 
 *     None.
2594
 
 *
2595
 
 *----------------------------------------------------------------------------
2596
 
 */
2597
 
 
2598
 
void
2599
 
UnitySetSendWindowContents(Bool enabled)
2600
 
{
2601
 
   /*
2602
 
    * Is the host prepared to receive scraped window contents at any time - even though
2603
 
    * it may not have previously requested the window contents. Explicit requests from
2604
 
    * the host will always be honored - this flag determines whether the guest will send
2605
 
    * the window contents directly after a qualifying operation (like changes in the
2606
 
    * z-order of a window).
2607
 
    */
2608
 
   if (enabled) {
2609
 
      Debug("%s: Sending window contents to the host on appropriate events\n",
2610
 
            __FUNCTION__);
2611
 
   } else {
2612
 
      Debug("%s: Do not send window contents to the host on appropriate events\n",
2613
 
            __FUNCTION__);
2614
 
   }
2615
 
}
2616
 
 
2617
 
 
2618
 
/*
2619
 
 *------------------------------------------------------------------------------
2620
 
 *
2621
 
 * UnityXdrEncodeWindowContentsStart --
2622
 
 *
2623
 
 *    XDR encoder function for UnityWindowContentsStart.
2624
 
 *
2625
 
 *    See UnityXdrSendRpc().
2626
 
 *
2627
 
 * Results:
2628
 
 *    Returns true if the XDR struct was encoded successfully.
2629
 
 *
2630
 
 * Side effects:
2631
 
 *    None.
2632
 
 *------------------------------------------------------------------------------
2633
 
 */
2634
 
 
2635
 
Bool
2636
 
UnityXdrEncodeWindowContentsStart(XDR *xdrs,
2637
 
                                  void *arg)
2638
 
{
2639
 
   ASSERT(xdrs);
2640
 
   ASSERT(arg);
2641
 
   return xdr_UnityWindowContentsStart(xdrs, (UnityWindowContentsStart *) arg);
2642
 
}
2643
 
 
2644
 
 
2645
 
/*
2646
 
 *------------------------------------------------------------------------------
2647
 
 *
2648
 
 * UnitySendWindowContentsStart --
2649
 
 *
2650
 
 *    Sends the unity.window.contents.start RPC to the host.
2651
 
 *
2652
 
 * Results:
2653
 
 *    Returns true if the RPC was sent successfully.
2654
 
 *
2655
 
 * Side effects:
2656
 
 *    None.
2657
 
 *
2658
 
 *------------------------------------------------------------------------------
2659
 
 */
2660
 
 
2661
 
Bool
2662
 
UnitySendWindowContentsStart(UnityWindowId windowID, // IN
2663
 
                             uint32 imageWidth,      // IN
2664
 
                             uint32 imageHeight,     // IN
2665
 
                             uint32 imageLength)     // IN
2666
 
{
2667
 
   Bool ret = FALSE;
2668
 
   UnityWindowContentsStart msg = { 0 };
2669
 
   UnityWindowContentsStartV1 v1 = { 0 };
2670
 
 
2671
 
   Debug("%s: Enter.\n", __FUNCTION__);
2672
 
 
2673
 
   v1.windowID = windowID;
2674
 
   v1.imageWidth  = imageWidth;
2675
 
   v1.imageHeight = imageHeight;
2676
 
   v1.imageLength = imageLength;
2677
 
 
2678
 
   msg.ver = UNITY_WINDOW_CONTENTS_V1;
2679
 
   msg.UnityWindowContentsStart_u.startV1 = &v1;
2680
 
 
2681
 
   ret = UnityXdrSendRpc(UNITY_RPC_WINDOW_CONTENTS_START,
2682
 
                         &UnityXdrEncodeWindowContentsStart,
2683
 
                         &msg);
2684
 
 
2685
 
   Debug("%s: Exit.\n", __FUNCTION__);
2686
 
   return ret;
2687
 
}
2688
 
 
2689
 
 
2690
 
/*
2691
 
 *------------------------------------------------------------------------------
2692
 
 *
2693
 
 * UnityXdrEncodeWindowContentsChunk --
2694
 
 *
2695
 
 *    XDR encoder function for UnityWindowContentsChunk.
2696
 
 *
2697
 
 *    See UnityXdrSendRpc().
2698
 
 *
2699
 
 * Results:
2700
 
 *    Returns true if the XDR struct was encoded successfully.
2701
 
 *
2702
 
 * Side-effects:
2703
 
 *    None.
2704
 
 *------------------------------------------------------------------------------
2705
 
 */
2706
 
 
2707
 
Bool
2708
 
UnityXdrEncodeWindowContentsChunk(XDR *xdrs,
2709
 
                                  void *arg)
2710
 
{
2711
 
   ASSERT(xdrs);
2712
 
   ASSERT(arg);
2713
 
   return xdr_UnityWindowContentsChunk(xdrs, (UnityWindowContentsChunk *) arg);
2714
 
}
2715
 
 
2716
 
 
2717
 
/*
2718
 
 *------------------------------------------------------------------------------
2719
 
 *
2720
 
 * UnitySendWindowContentsChunk --
2721
 
 *
2722
 
 *    Sends a unity.window.contents.chunk RPC to the host.
2723
 
 *
2724
 
 * Results:
2725
 
 *    Returns true if the RPC was sent successfully.
2726
 
 *
2727
 
 * Side effects:
2728
 
 *    None.
2729
 
 *
2730
 
 *------------------------------------------------------------------------------
2731
 
 */
2732
 
 
2733
 
Bool
2734
 
UnitySendWindowContentsChunk(UnityWindowId windowID,
2735
 
                             uint32 chunkID,
2736
 
                             const char *data,
2737
 
                             uint32 len)
2738
 
{
2739
 
   Bool ret = FALSE;
2740
 
   UnityWindowContentsChunk msg = { 0 };
2741
 
   UnityWindowContentsChunkV1 v1 = { 0 };
2742
 
 
2743
 
   Debug("%s: Enter.\n", __FUNCTION__);
2744
 
 
2745
 
   v1.windowID = windowID;
2746
 
   v1.chunkID = chunkID;
2747
 
   v1.data.data_val = (char *) data;
2748
 
   v1.data.data_len = len;
2749
 
 
2750
 
   msg.ver = UNITY_WINDOW_CONTENTS_V1;
2751
 
   msg.UnityWindowContentsChunk_u.chunkV1 = &v1;
2752
 
 
2753
 
   ret = UnityXdrSendRpc(UNITY_RPC_WINDOW_CONTENTS_CHUNK,
2754
 
                         &UnityXdrEncodeWindowContentsChunk,
2755
 
                         &msg);
2756
 
 
2757
 
   Debug("%s: Exit.\n", __FUNCTION__);
2758
 
   return ret;
2759
 
}
2760
 
 
2761
 
 
2762
 
/*
2763
 
 *------------------------------------------------------------------------------
2764
 
 *
2765
 
 * UnityXdrEncodeWindowContentsEnd --
2766
 
 *
2767
 
 *    XDR encoder function for UnityWindowContentsEnd.
2768
 
 *
2769
 
 * Results:
2770
 
 *    Returns true if the XDR struct was encoded successfully.
2771
 
 *
2772
 
 * Side effects:
2773
 
 *    None.
2774
 
 *------------------------------------------------------------------------------
2775
 
 */
2776
 
 
2777
 
Bool
2778
 
UnityXdrEncodeWindowContentsEnd(XDR *xdrs,
2779
 
                                void *arg)
2780
 
{
2781
 
   ASSERT(xdrs);
2782
 
   ASSERT(arg);
2783
 
   return xdr_UnityWindowContentsEnd(xdrs, (UnityWindowContentsEnd*) arg);
2784
 
}
2785
 
 
2786
 
 
2787
 
/*
2788
 
 *------------------------------------------------------------------------------
2789
 
 *
2790
 
 * UnitySendWindowContentsEnd --
2791
 
 *
2792
 
 *    Sends a unity.window.contents.end RPC to the host.
2793
 
 *
2794
 
 * Results:
2795
 
 *    Returns true if the RPC was sent successfully.
2796
 
 *
2797
 
 * Side effects:
2798
 
 *    None.
2799
 
 *
2800
 
 *------------------------------------------------------------------------------
2801
 
 */
2802
 
 
2803
 
Bool
2804
 
UnitySendWindowContentsEnd(UnityWindowId windowID)
2805
 
{
2806
 
   Bool ret = FALSE;
2807
 
   UnityWindowContentsEnd msg = { 0 };
2808
 
   UnityWindowContentsEndV1 v1 = { 0 };
2809
 
 
2810
 
   Debug("%s: Enter.\n", __FUNCTION__);
2811
 
 
2812
 
   v1.windowID = windowID;
2813
 
 
2814
 
   msg.ver = UNITY_WINDOW_CONTENTS_V1;
2815
 
   msg.UnityWindowContentsEnd_u.endV1 = &v1;
2816
 
 
2817
 
   ret = UnityXdrSendRpc(UNITY_RPC_WINDOW_CONTENTS_END,
2818
 
                         &UnityXdrEncodeWindowContentsEnd,
2819
 
                         &msg);
2820
 
 
2821
 
   Debug("%s: Exit.\n", __FUNCTION__);
2822
 
   return ret;
2823
 
}
2824
 
 
2825
 
 
2826
 
/*
2827
 
 *------------------------------------------------------------------------------
2828
 
 *
2829
 
 * UnityXdrSendRpc --
2830
 
 *
2831
 
 *    Sends an RPC with XDR-serialized arguments to the host. The provided
2832
 
 *    encodeFn will be called to perform XDR encoding of the RPC, with the XDR
2833
 
 *    struct and the provided data pointer as its parameters.
2834
 
 *
2835
 
 * Returns:
2836
 
 *    True if the RPC was sent successfully.
2837
 
 *
2838
 
 * Side effects:
2839
 
 *    None.
2840
 
 *
2841
 
 *------------------------------------------------------------------------------
2842
 
 */
2843
 
 
2844
 
Bool
2845
 
UnityXdrSendRpc(const char *rpcName,
2846
 
                UnityXdrEncodeFunc encodeFn,
2847
 
                void *data)
2848
 
{
2849
 
   Bool ret = FALSE;
2850
 
   XDR xdrs = { 0 };
2851
 
 
2852
 
   ASSERT(rpcName);
2853
 
 
2854
 
   Debug("%s: Enter.\n", __FUNCTION__);
2855
 
 
2856
 
   if (!DynXdr_Create(&xdrs)) {
2857
 
      Debug("%s: Failed to create DynXdr.\n", __FUNCTION__);
2858
 
      goto exit;
2859
 
   }
2860
 
 
2861
 
   if (!DynXdr_AppendRaw(&xdrs, rpcName, strlen(rpcName))) {
2862
 
      Debug("%s: Failed to append RPC name to DynXdr.\n", __FUNCTION__);
2863
 
      goto dynxdr_destroy;
2864
 
   }
2865
 
 
2866
 
   if (!DynXdr_AppendRaw(&xdrs, " ", 1)) {
2867
 
      Debug("%s: Failed to append space to DynXdr.\n", __FUNCTION__);
2868
 
      goto dynxdr_destroy;
2869
 
   }
2870
 
 
2871
 
   if (!(*encodeFn)(&xdrs, data)) {
2872
 
      Debug("%s: Failed to serialize RPC data.\n", __FUNCTION__);
2873
 
      goto dynxdr_destroy;
2874
 
   }
2875
 
 
2876
 
   if (!RpcOut_SendOneRaw(DynXdr_Get(&xdrs), xdr_getpos(&xdrs), NULL, NULL)) {
2877
 
      Debug("%s: Failed to send RPC.\n", __FUNCTION__);
2878
 
      goto dynxdr_destroy;
2879
 
   }
2880
 
 
2881
 
   ret = TRUE;
2882
 
 
2883
 
dynxdr_destroy:
2884
 
   DynXdr_Destroy(&xdrs, TRUE);
2885
 
 
2886
 
exit:
2887
 
   Debug("%s: Exit.\n", __FUNCTION__);
2888
 
   return ret;
2889
 
}