~ubuntu-branches/ubuntu/precise/open-vm-tools/precise

« back to all changes in this revision

Viewing changes to services/plugins/dndcp/copyPasteCompatX11.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) 2005 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
 * copyPasteCompatX11.c --
 
21
 *
 
22
 *    Set of functions in guest side for copy/paste (both file and text).
 
23
 *    Currently there are 2 versions copy/paste. Version 1 only supports
 
24
 *    text copy/paste, and based on backdoor cmd. Version 2 supports both
 
25
 *    text and file copy/paste, and based on guestRPC.
 
26
 *
 
27
 *    G->H Text Copy/Paste (version 1)
 
28
 *    --------------------
 
29
 *    When Ungrab, CopyPaste_RequestSelection got called, which try to get
 
30
 *    selection text and send to backdoor.
 
31
 *
 
32
 *    H->G Text Copy/Paste (version 1)
 
33
 *    --------------------
 
34
 *    When grab, CopyPaste_GetBackdoorSelections got called, which first
 
35
 *    get host selection text, then claim as selection owner. If some app
 
36
 *    asks for selection, CopyPasteSelectionGetCB will reply with host
 
37
 *    selection text.
 
38
 */
 
39
 
 
40
#include "dndPluginIntX11.h"
 
41
#include <stdlib.h>
 
42
#include <string.h>
 
43
#include <sys/time.h>
 
44
#include <unistd.h>
 
45
#include <errno.h>
 
46
 
 
47
#include "vm_assert.h"
 
48
#include "str.h"
 
49
#include "strutil.h"
 
50
#include "eventManager.h"
 
51
#include "guestApp.h"
 
52
#include "dnd.h"
 
53
#include "util.h"
 
54
#include "cpName.h"
 
55
#include "cpNameUtil.h"
 
56
#include "vmblock.h"
 
57
#include "file.h"
 
58
#include "codeset.h"
 
59
#include "escape.h"
 
60
#include "hostinfo.h"
 
61
#include "wiper.h"
 
62
#include "vmware/guestrpc/tclodefs.h"
 
63
 
 
64
#include "vmware/tools/plugin.h"
 
65
 
 
66
/*
 
67
 * Gtk 1.2 doesn't know about the CLIPBOARD selection, but that doesn't matter, we
 
68
 * just create the atom we need directly in main().
 
69
 */
 
70
#ifndef GDK_SELECTION_CLIPBOARD
 
71
GdkAtom GDK_SELECTION_CLIPBOARD;
 
72
#endif
 
73
 
 
74
#ifndef GDK_SELECTION_TYPE_TIMESTAMP
 
75
GdkAtom GDK_SELECTION_TYPE_TIMESTAMP;
 
76
#endif
 
77
 
 
78
#ifndef GDK_SELECTION_TYPE_UTF8_STRING
 
79
GdkAtom GDK_SELECTION_TYPE_UTF8_STRING;
 
80
#endif
 
81
 
 
82
/*
 
83
 * Currently there are 2 versions copy/paste.
 
84
 * Key points in copy/paste version 1:
 
85
 * 1. Only text copy/paste
 
86
 * 2. copy/paste is based on backdoor directly
 
87
 *
 
88
 * Key points in copy/paste version 2:
 
89
 * 1. Support both file/text copy/paste
 
90
 * 2. Both file/text copy/paste are based on guestRPC
 
91
 */
 
92
static int32 gVmxCopyPasteVersion = 1;
 
93
 
 
94
/*
 
95
 * Getting a selection is an asyncronous event, so we have to keep track of both
 
96
 * selections globablly in order to decide which one to use.
 
97
 */
 
98
static Bool gWaitingOnGuestSelection = FALSE;
 
99
static char gGuestSelPrimaryBuf[MAX_SELECTION_BUFFER_LENGTH];
 
100
static char gGuestSelClipboardBuf[MAX_SELECTION_BUFFER_LENGTH];
 
101
static uint64 gGuestSelPrimaryTime = 0;
 
102
static uint64 gGuestSelClipboardTime = 0;
 
103
static char gHostClipboardBuf[MAX_SELECTION_BUFFER_LENGTH + 1];
 
104
 
 
105
static Bool gIsOwner;
 
106
static ToolsAppCtx *gCtx = NULL;
 
107
 
 
108
/*
 
109
 * Forward Declarations
 
110
 */
 
111
static gboolean IsCtxMainLoopActive(void);
 
112
static INLINE void CopyPasteStateInit(void);
 
113
static void CopyPasteSelectionReceivedCB(GtkWidget *widget,
 
114
                                         GtkSelectionData *selection_data,
 
115
                                         gpointer data);
 
116
static void CopyPasteSelectionGetCB(GtkWidget *widget,
 
117
                                    GtkSelectionData *selection_data,
 
118
                                    guint info,
 
119
                                    guint time_stamp,
 
120
                                    gpointer data);
 
121
static gint CopyPasteSelectionClearCB(GtkWidget *widget,
 
122
                                      GdkEventSelection *event,
 
123
                                      gpointer data);
 
124
 
 
125
static void CopyPasteSetBackdoorSelections(void);
 
126
 
 
127
/* This struct is only used by CopyPasteSelectionRemoveTarget. */
 
128
struct SelectionTargetList {
 
129
  GdkAtom selection;
 
130
  GtkTargetList *list;
 
131
};
 
132
 
 
133
 
 
134
/*
 
135
 *-----------------------------------------------------------------------------
 
136
 *
 
137
 * CopyPasteSelectionRemoveTarget --
 
138
 *
 
139
 *      To remove a target from a selection target list. The reason to develop
 
140
 *      this function is that in gtk there is only gtk_selection_add_target to
 
141
 *      add supported target to selection list, but no function to remove one.
 
142
 *
 
143
 * Results:
 
144
 *      None.
 
145
 *
 
146
 * Side effects:
 
147
 *      If no more target, the selection list will be removed too.
 
148
 *
 
149
 *-----------------------------------------------------------------------------
 
150
 */
 
151
 
 
152
void
 
153
CopyPasteSelectionRemoveTarget(GtkWidget *widget,
 
154
                               GdkAtom selection,
 
155
                               GdkAtom target)
 
156
{
 
157
   const char *selection_handler_key = "gtk-selection-handlers";
 
158
   struct SelectionTargetList *targetList;
 
159
   GList *tempList;
 
160
   GList *selectionLists;
 
161
 
 
162
   /* Get selection list. */
 
163
   selectionLists = gtk_object_get_data(GTK_OBJECT (widget), selection_handler_key);
 
164
   tempList = selectionLists;
 
165
   while (tempList) {
 
166
      /* Enumerate the list to find the selection. */
 
167
      targetList = tempList->data;
 
168
      if (targetList->selection == selection) {
 
169
         /* Remove target. */
 
170
         gtk_target_list_remove(targetList->list, target);
 
171
         /* If no more target, remove selection from list. */
 
172
         if (!targetList->list->list) {
 
173
            /* Free target list. */
 
174
            gtk_target_list_unref(targetList->list);
 
175
            g_free(targetList);
 
176
            /* Remove and free selection node. */
 
177
            selectionLists = g_list_remove_link(selectionLists, tempList);
 
178
            g_list_free_1(tempList);
 
179
         }
 
180
         break;
 
181
      }
 
182
      tempList = tempList->next;
 
183
   }
 
184
   /* Put new selection list back. */
 
185
   gtk_object_set_data (GTK_OBJECT (widget), selection_handler_key, selectionLists);
 
186
}
 
187
 
 
188
 
 
189
/*
 
190
 *-----------------------------------------------------------------------------
 
191
 *
 
192
 * CopyPaste_RequestSelection --
 
193
 *
 
194
 *      Request the guest's text clipboard (asynchronously), we'll give it to 
 
195
 *      the host when the request completes. For version 1 guest->host text
 
196
 *      copy/paste.
 
197
 *
 
198
 * Results:
 
199
 *      TRUE on success, FALSE otherwise.
 
200
 *
 
201
 * Side effects:
 
202
 *      The owner of the clipboard will get a request from our application.
 
203
 *
 
204
 *-----------------------------------------------------------------------------
 
205
 */
 
206
 
 
207
Bool
 
208
CopyPaste_RequestSelection(void)
 
209
{
 
210
   if (gVmxCopyPasteVersion > 1) {
 
211
      return FALSE;
 
212
   }
 
213
 
 
214
   /*
 
215
    * Ask for both the PRIMARY and CLIPBOARD selections.
 
216
    */
 
217
   gGuestSelPrimaryBuf[0] = '\0';
 
218
   gGuestSelClipboardBuf[0] = '\0';
 
219
 
 
220
   /* Only send out request if we are not the owner. */
 
221
   if (!gIsOwner) {
 
222
      /* Try to get timestamp for primary and clipboard. */
 
223
      gWaitingOnGuestSelection = TRUE;
 
224
      gtk_selection_convert(gUserMainWidget,
 
225
                            GDK_SELECTION_PRIMARY,
 
226
                            GDK_SELECTION_TYPE_TIMESTAMP,
 
227
                            GDK_CURRENT_TIME);
 
228
      while (IsCtxMainLoopActive() && gWaitingOnGuestSelection) {
 
229
         gtk_main_iteration();
 
230
      }
 
231
 
 
232
      gWaitingOnGuestSelection = TRUE;
 
233
      gtk_selection_convert(gUserMainWidget,
 
234
                            GDK_SELECTION_CLIPBOARD,
 
235
                            GDK_SELECTION_TYPE_TIMESTAMP,
 
236
                            GDK_CURRENT_TIME);
 
237
      while (IsCtxMainLoopActive() && gWaitingOnGuestSelection) {
 
238
         gtk_main_iteration();
 
239
      }
 
240
 
 
241
      /* Try to get utf8 text from primary and clipboard. */
 
242
      gWaitingOnGuestSelection = TRUE;
 
243
      gtk_selection_convert(gUserMainWidget,
 
244
                            GDK_SELECTION_PRIMARY,
 
245
                            GDK_SELECTION_TYPE_UTF8_STRING,
 
246
                            GDK_CURRENT_TIME);
 
247
      while (IsCtxMainLoopActive() && gWaitingOnGuestSelection) {
 
248
         gtk_main_iteration();
 
249
      }
 
250
 
 
251
      gWaitingOnGuestSelection = TRUE;
 
252
      gtk_selection_convert(gUserMainWidget,
 
253
                            GDK_SELECTION_CLIPBOARD,
 
254
                            GDK_SELECTION_TYPE_UTF8_STRING,
 
255
                            GDK_CURRENT_TIME);
 
256
      while (IsCtxMainLoopActive() && gWaitingOnGuestSelection) {
 
257
         gtk_main_iteration();
 
258
      }
 
259
 
 
260
      if (gGuestSelPrimaryBuf[0] == '\0' && gGuestSelClipboardBuf[0] == '\0') {
 
261
         /*
 
262
          * If we cannot get utf8 text, try to get localized text from primary
 
263
          * and clipboard.
 
264
          */
 
265
         gWaitingOnGuestSelection = TRUE;
 
266
         gtk_selection_convert(gUserMainWidget,
 
267
                               GDK_SELECTION_PRIMARY,
 
268
                               GDK_SELECTION_TYPE_STRING,
 
269
                               GDK_CURRENT_TIME);
 
270
         while (IsCtxMainLoopActive() && gWaitingOnGuestSelection) {
 
271
            gtk_main_iteration();
 
272
         }
 
273
 
 
274
         gWaitingOnGuestSelection = TRUE;
 
275
         gtk_selection_convert(gUserMainWidget,
 
276
                               GDK_SELECTION_CLIPBOARD,
 
277
                               GDK_SELECTION_TYPE_STRING,
 
278
                               GDK_CURRENT_TIME);
 
279
         while (IsCtxMainLoopActive() && gWaitingOnGuestSelection) {
 
280
            gtk_main_iteration();
 
281
         }
 
282
      }
 
283
   }
 
284
   /* Send text to host. */
 
285
   g_debug("CopyPaste_RequestSelection: Prim is [%s], Clip is [%s]\n",
 
286
         gGuestSelPrimaryBuf, gGuestSelClipboardBuf);
 
287
   CopyPasteSetBackdoorSelections();
 
288
   return TRUE;
 
289
}
 
290
 
 
291
 
 
292
/**
 
293
 * Check to see if we are running in tools main loop.
 
294
 *
 
295
 * @return TRUE if we are, FALSE if we are not running in main loop.
 
296
 */
 
297
 
 
298
static gboolean
 
299
IsCtxMainLoopActive(void)
 
300
{
 
301
   ASSERT(gCtx);
 
302
   return g_main_loop_is_running(gCtx->mainLoop);
 
303
}
 
304
 
 
305
 
 
306
/*
 
307
 *-----------------------------------------------------------------------------
 
308
 *
 
309
 * CopyPasteSelectionReceivedCB --
 
310
 *
 
311
 *      Callback for the gtk signal "selection_received".
 
312
 *      Called because we previously requested a copy/paste selection and
 
313
 *      finally got results of that asynchronous operation. After some basic
 
314
 *      sanity checks, send the result (in selection_data) thru the backdoor
 
315
 *      (version 1) or guestRPC (version 2) so the vmx can copy it to host
 
316
 *      clipboard.
 
317
 *
 
318
 *      We made several requests for selections, the string (actual data) and
 
319
 *      file list for each of PRIMARY and CLIPBOARD selections. So this funtion
 
320
 *      will get called several times, once for each request.
 
321
 *
 
322
 *      For guest->host copy/paste (both text and file).
 
323
 *
 
324
 * Results:
 
325
 *      None.
 
326
 *
 
327
 * Side effects:
 
328
 *      None.
 
329
 *
 
330
 *-----------------------------------------------------------------------------
 
331
 */
 
332
 
 
333
void
 
334
CopyPasteSelectionReceivedCB(GtkWidget *widget,                // IN: unused
 
335
                             GtkSelectionData *selection_data, // IN: requested data
 
336
                             gpointer data)                    // IN: unused
 
337
{
 
338
   char *target;
 
339
   char *utf8Str = NULL;
 
340
   size_t len;
 
341
   size_t aligned_len;
 
342
 
 
343
   if ((widget == NULL) || (selection_data == NULL)) {
 
344
      g_debug("CopyPasteSelectionReceivedCB: Error, widget or selection_data is invalid\n");
 
345
      goto exit;
 
346
   }
 
347
 
 
348
   if (selection_data->length < 0) {
 
349
      g_debug("CopyPasteSelectionReceivedCB: Error, length less than 0\n");
 
350
      goto exit;
 
351
   }
 
352
 
 
353
   /* Try to get clipboard or selection timestamp. */
 
354
   if (selection_data->target == GDK_SELECTION_TYPE_TIMESTAMP) {
 
355
      if (selection_data->selection == GDK_SELECTION_PRIMARY) {
 
356
         if (selection_data->length == 4) {
 
357
            gGuestSelPrimaryTime = *(uint32 *)selection_data->data;
 
358
            g_debug("CopyPasteSelectionReceivedCB: Got pri time [%"FMT64"u]\n",
 
359
                  gGuestSelPrimaryTime);
 
360
         } else if (selection_data->length == 8) {
 
361
            gGuestSelPrimaryTime = *(uint64 *)selection_data->data;
 
362
            g_debug("CopyPasteSelectionReceivedCB: Got pri time [%"FMT64"u]\n",
 
363
                  gGuestSelPrimaryTime);
 
364
         } else {
 
365
            g_debug("CopyPasteSelectionReceivedCB: Unknown pri time. Size %d\n",
 
366
                  selection_data->length);
 
367
         }
 
368
      }
 
369
      if (selection_data->selection == GDK_SELECTION_CLIPBOARD) {
 
370
         if (selection_data->length == 4) {
 
371
            gGuestSelClipboardTime = *(uint32 *)selection_data->data;
 
372
            g_debug("CopyPasteSelectionReceivedCB: Got clip time [%"FMT64"u]\n",
 
373
                  gGuestSelClipboardTime);
 
374
         } else if (selection_data->length == 8) {
 
375
            gGuestSelClipboardTime = *(uint64 *)selection_data->data;
 
376
            g_debug("CopyPasteSelectionReceivedCB: Got clip time [%"FMT64"u]\n",
 
377
                  gGuestSelClipboardTime);
 
378
         } else {
 
379
            g_debug("CopyPasteSelectionReceivedCB: Unknown clip time. Size %d\n",
 
380
                  selection_data->length);
 
381
         }
 
382
      }
 
383
      goto exit;
 
384
   }
 
385
 
 
386
   if (selection_data->selection == GDK_SELECTION_PRIMARY) {
 
387
      target = gGuestSelPrimaryBuf;
 
388
   } else if (selection_data->selection == GDK_SELECTION_CLIPBOARD) {
 
389
      target = gGuestSelClipboardBuf;
 
390
   } else {
 
391
      goto exit;
 
392
   }
 
393
 
 
394
   utf8Str = selection_data->data;
 
395
   len = strlen(selection_data->data);
 
396
 
 
397
   if (selection_data->target != GDK_SELECTION_TYPE_STRING &&
 
398
       selection_data->target != GDK_SELECTION_TYPE_UTF8_STRING) {
 
399
      /* It is a file list. */
 
400
      if (len >= MAX_SELECTION_BUFFER_LENGTH - 1) {
 
401
         Warning("CopyPasteSelectionReceivedCB file list too long\n");
 
402
      } else {
 
403
         memcpy(target, selection_data->data, len + 1);
 
404
      }
 
405
      goto exit;
 
406
   }
 
407
 
 
408
   /*
 
409
    * If target is GDK_SELECTION_TYPE_STRING, assume encoding is local code
 
410
    * set. Convert to utf8 before send to vmx.
 
411
    */
 
412
   if (selection_data->target == GDK_SELECTION_TYPE_STRING &&
 
413
       !CodeSet_CurrentToUtf8(selection_data->data,
 
414
                              selection_data->length,
 
415
                              &utf8Str,
 
416
                              &len)) {
 
417
      g_debug("CopyPasteSelectionReceivedCB: Couldn't convert to utf8 code set\n");
 
418
      gWaitingOnGuestSelection = FALSE;
 
419
      return;
 
420
   }
 
421
 
 
422
   /*
 
423
    * String in backdoor communication is 4 bytes by 4 bytes, so the len
 
424
    * should be aligned to 4;
 
425
    */
 
426
   aligned_len = (len + 4) & ~3;
 
427
   if (aligned_len >= MAX_SELECTION_BUFFER_LENGTH) {
 
428
      /* With alignment, len is still possible to be less than max. */
 
429
      if (len < (MAX_SELECTION_BUFFER_LENGTH - 1)) {
 
430
         memcpy(target, utf8Str, len + 1);
 
431
      } else {
 
432
         memcpy(target, utf8Str, MAX_SELECTION_BUFFER_LENGTH - 1);
 
433
         target[MAX_SELECTION_BUFFER_LENGTH - 1] ='\0';
 
434
      }
 
435
   } else {
 
436
      memcpy(target, utf8Str, len + 1);
 
437
   }
 
438
 
 
439
exit:
 
440
   if (selection_data->target == GDK_SELECTION_TYPE_STRING) {
 
441
      free(utf8Str);
 
442
   }
 
443
   gWaitingOnGuestSelection = FALSE;
 
444
}
 
445
 
 
446
 
 
447
/*
 
448
 *-----------------------------------------------------------------------------
 
449
 *
 
450
 * CopyPasteSelectionGetCB --
 
451
 *
 
452
 *      Callback for the gtk signal "selection_get".
 
453
 *      This is called when some other app requests the copy/paste selection,
 
454
 *      probably because we declare oursleves the selection owner on mouse
 
455
 *      grab. In text copy/paste case, we simply respond with contents of
 
456
 *      gHostClipboardBuf, which should have been set on mouse grab. In file
 
457
 *      copy/paste case, send file transfer request to host vmx, then return
 
458
 *      file list with right format according to different request.
 
459
 *      For host->guest copy/paste (both text and file).
 
460
 *
 
461
 * Results:
 
462
 *      None
 
463
 *
 
464
 * Side effects:
 
465
 *      An X message is sent to the requesting app containing the data, it
 
466
 *      will likely act on it in some way. In FCP case, may first start a
 
467
 *      host->guest file transfer. Add block if blocking driver is available,
 
468
 *      otherwise wait till file copy done.
 
469
 *
 
470
 *-----------------------------------------------------------------------------
 
471
 */
 
472
 
 
473
void
 
474
CopyPasteSelectionGetCB(GtkWidget        *widget,         // IN: unused
 
475
                        GtkSelectionData *selection_data, // IN: requested type
 
476
                                                          // OUT:the data to be sent
 
477
                        guint            info,            // IN: unused
 
478
                        guint            time_stamp,      // IN: unsued
 
479
                        gpointer         data)            // IN: unused
 
480
{
 
481
   if ((widget == NULL) || (selection_data == NULL)) {
 
482
      g_debug("CopyPasteSelectionGetCB: Error, widget or selection_data is invalid\n");
 
483
      return;
 
484
   }
 
485
 
 
486
   /* If it is text copy paste, return gHostClipboardBuf. */
 
487
   if (GDK_SELECTION_TYPE_STRING == selection_data->target ||
 
488
       GDK_SELECTION_TYPE_UTF8_STRING == selection_data->target) {
 
489
      char *outBuf = gHostClipboardBuf;
 
490
      size_t len = strlen(gHostClipboardBuf);
 
491
 
 
492
      /*
 
493
       * If target is GDK_SELECTION_TYPE_STRING, assume encoding is local code
 
494
       * set. Convert from utf8 to local one.
 
495
       */
 
496
      if (GDK_SELECTION_TYPE_STRING == selection_data->target &&
 
497
          !CodeSet_Utf8ToCurrent(gHostClipboardBuf,
 
498
                                 strlen(gHostClipboardBuf),
 
499
                                 &outBuf,
 
500
                                 &len)) {
 
501
         g_debug("CopyPasteSelectionGetCB: can not convert to current codeset\n");
 
502
         return;
 
503
      }
 
504
 
 
505
      gtk_selection_data_set(selection_data, selection_data->target, 8,
 
506
                             outBuf, len);
 
507
      g_debug("CopyPasteSelectionGetCB: Set text [%s]\n", outBuf);
 
508
 
 
509
      if (GDK_SELECTION_TYPE_STRING == selection_data->target) {
 
510
         free(outBuf);
 
511
      }
 
512
 
 
513
      return;
 
514
   }
 
515
}
 
516
 
 
517
 
 
518
/*
 
519
 *-----------------------------------------------------------------------------
 
520
 *
 
521
 * CopyPasteSelectionClearCB --
 
522
 *
 
523
 *      Callback for the gtk signal "selection_clear".
 
524
 *
 
525
 * Results:
 
526
 *      Always TRUE.
 
527
 *
 
528
 * Side effects:
 
529
 *      None
 
530
 *
 
531
 *-----------------------------------------------------------------------------
 
532
 */
 
533
 
 
534
static gint
 
535
CopyPasteSelectionClearCB(GtkWidget          *widget,         // IN: unused
 
536
                          GdkEventSelection  *event,          // IN: unused
 
537
                          gpointer           data)            // IN: unused
 
538
{
 
539
   g_debug("CopyPasteSelectionClearCB got clear signal\n");
 
540
   gIsOwner = FALSE;
 
541
   return TRUE;
 
542
}
 
543
 
 
544
 
 
545
/*
 
546
 *-----------------------------------------------------------------------------
 
547
 *
 
548
 * CopyPasteSetBackdoorSelections --
 
549
 *
 
550
 *      Set the clipboard one of two ways, the old way or the new way.
 
551
 *      The old way uses GuestApp_SetSel and there's only one selection.
 
552
 *      Set backdoor selection with either primary selection or clipboard.
 
553
 *      The primary selection is the first priority, then clipboard.
 
554
 *      If both unavailable, set backdoor selection length to be 0.
 
555
 *      This will be used by older VMXs or VMXs on Windows hosts (which
 
556
 *      has only one clipboard). Doing this gives us backwards
 
557
 *      compatibility.
 
558
 *
 
559
 *      The new way uses new sets both PRIMARY and CLIPBOARD. Newer Linux
 
560
 *      VMXs will use these rather than the above method and have the two
 
561
 *      selections set separately.
 
562
 *
 
563
 *      XXX: The "new way" doesn't exist yet, the vmx has no support for it.
 
564
 *
 
565
 * Results:
 
566
 *      None.
 
567
 *
 
568
 * Side effects:
 
569
 *      The VMX probably changes some string buffers.
 
570
 *
 
571
 *-----------------------------------------------------------------------------
 
572
 */
 
573
 
 
574
void
 
575
CopyPasteSetBackdoorSelections(void)
 
576
{
 
577
   uint32 const *p;
 
578
   size_t len;
 
579
   size_t aligned_len;
 
580
   size_t primaryLen;
 
581
   size_t clipboardLen;
 
582
   unsigned int i;
 
583
 
 
584
   primaryLen = strlen(gGuestSelPrimaryBuf);
 
585
   clipboardLen = strlen(gGuestSelClipboardBuf);
 
586
 
 
587
   if (primaryLen && clipboardLen) {
 
588
      /* Pick latest one if both are available. */
 
589
      p = gGuestSelPrimaryTime >= gGuestSelClipboardTime ?
 
590
         (uint32 const *)gGuestSelPrimaryBuf :
 
591
         (uint32 const *)gGuestSelClipboardBuf;
 
592
   } else if (primaryLen) {
 
593
      /*
 
594
       * Send primary selection to backdoor if it exists.
 
595
       */
 
596
      p = (uint32 const *)gGuestSelPrimaryBuf;
 
597
   } else if (clipboardLen) {
 
598
      /*
 
599
       * Otherwise send clipboard to backdoor if it exists.
 
600
       */
 
601
      p = (uint32 const *)gGuestSelClipboardBuf;
 
602
   } else {
 
603
      /*
 
604
       * Neither selection is set
 
605
       */
 
606
      p = NULL;
 
607
   }
 
608
 
 
609
   if (p == NULL) {
 
610
      GuestApp_SetSelLength(0);
 
611
      g_debug("CopyPasteSetBackdoorSelections Set empty text.\n");
 
612
   } else {
 
613
      len = strlen((char *)p);
 
614
      g_debug("CopyPasteSetBackdoorSelections Set text [%s].\n", (char *)p);
 
615
      aligned_len = (len + 4) & ~3;
 
616
 
 
617
      /* Here long string should already be truncated. */
 
618
      ASSERT(aligned_len <= MAX_SELECTION_BUFFER_LENGTH);
 
619
 
 
620
      GuestApp_SetSelLength(len);
 
621
      for (i = 0; i < len; i += 4, p++) {
 
622
         GuestApp_SetNextPiece(*p);
 
623
      }
 
624
   }
 
625
}
 
626
 
 
627
 
 
628
/*
 
629
 *-----------------------------------------------------------------------------
 
630
 *
 
631
 * CopyPaste_GetBackdoorSelections --
 
632
 *
 
633
 *      Get the clipboard "the old way".
 
634
 *      The old way uses GuestApp_SetSel and there's only one selection.
 
635
 *      We don't have to do anything for the "new way", since the host
 
636
 *      will just push PRIMARY and/or CLIPBOARD when they are available
 
637
 *      on the host.
 
638
 *
 
639
 *      XXX: the "new way" isn't availble yet because the vmx doesn't
 
640
 *           implement separate clipboards. Even when it does this
 
641
 *           function will still exist for backward compatibility
 
642
 *
 
643
 * Results:
 
644
 *      TRUE if selection length>=0, FALSE otherwise.
 
645
 *
 
646
 * Side effects:
 
647
 *      This application becomes the selection owner for PRIMARY and/or
 
648
        CLIPBOARD selections.
 
649
 *
 
650
 *-----------------------------------------------------------------------------
 
651
 */
 
652
 
 
653
Bool
 
654
CopyPaste_GetBackdoorSelections(void)
 
655
{
 
656
   int selLength;
 
657
 
 
658
   if (gVmxCopyPasteVersion > 1) {
 
659
      return TRUE;
 
660
   }
 
661
 
 
662
   selLength = GuestApp_GetHostSelectionLen();
 
663
   if (selLength < 0 || selLength > MAX_SELECTION_BUFFER_LENGTH) {
 
664
      return FALSE;
 
665
   } else if (selLength > 0) {
 
666
      GuestApp_GetHostSelection(selLength, gHostClipboardBuf);
 
667
      gHostClipboardBuf[selLength] = 0;
 
668
      g_debug("CopyPaste_GetBackdoorSelections Get text [%s].\n", gHostClipboardBuf);
 
669
      gtk_selection_owner_set(gUserMainWidget,
 
670
                              GDK_SELECTION_CLIPBOARD,
 
671
                              GDK_CURRENT_TIME);
 
672
      gtk_selection_owner_set(gUserMainWidget,
 
673
                              GDK_SELECTION_PRIMARY,
 
674
                              GDK_CURRENT_TIME);
 
675
      gIsOwner = TRUE;
 
676
   }
 
677
   return TRUE;
 
678
}
 
679
 
 
680
 
 
681
/*
 
682
 *-----------------------------------------------------------------------------
 
683
 *
 
684
 * CopyPaste_Register --
 
685
 *
 
686
 *      Setup callbacks, initialize.
 
687
 *
 
688
 * Results:
 
689
 *      Always TRUE.
 
690
 *
 
691
 * Side effects:
 
692
 *      None
 
693
 *
 
694
 *-----------------------------------------------------------------------------
 
695
 */
 
696
 
 
697
Bool
 
698
CopyPaste_Register(GtkWidget* mainWnd,   // IN
 
699
                   ToolsAppCtx *ctx)     // IN
 
700
{
 
701
   g_debug("%s: enter\n", __FUNCTION__);
 
702
   ASSERT(mainWnd);
 
703
   ASSERT(ctx);
 
704
 
 
705
   gCtx = ctx;
 
706
   /* Text copy/paste initialization for all versions. */
 
707
#ifndef GDK_SELECTION_CLIPBOARD
 
708
   GDK_SELECTION_CLIPBOARD = gdk_atom_intern("CLIPBOARD", FALSE);
 
709
#endif
 
710
 
 
711
#ifndef GDK_SELECTION_TYPE_TIMESTAMP
 
712
   GDK_SELECTION_TYPE_TIMESTAMP = gdk_atom_intern("TIMESTAMP", FALSE);
 
713
#endif
 
714
 
 
715
#ifndef GDK_SELECTION_TYPE_UTF8_STRING
 
716
   GDK_SELECTION_TYPE_UTF8_STRING = gdk_atom_intern("UTF8_STRING", FALSE);
 
717
#endif
 
718
 
 
719
   /*
 
720
    * String is always in supported list. FCP atoms will dynamically be
 
721
    * added and removed.
 
722
    */
 
723
   gtk_selection_add_target(mainWnd, GDK_SELECTION_PRIMARY,
 
724
                            GDK_SELECTION_TYPE_STRING, 0);
 
725
   gtk_selection_add_target(mainWnd, GDK_SELECTION_CLIPBOARD,
 
726
                            GDK_SELECTION_TYPE_STRING, 0);
 
727
   gtk_selection_add_target(mainWnd, GDK_SELECTION_PRIMARY,
 
728
                            GDK_SELECTION_TYPE_UTF8_STRING, 0);
 
729
   gtk_selection_add_target(mainWnd, GDK_SELECTION_CLIPBOARD,
 
730
                            GDK_SELECTION_TYPE_UTF8_STRING, 0);
 
731
 
 
732
   gtk_signal_connect(GTK_OBJECT(mainWnd), "selection_received",
 
733
                      GTK_SIGNAL_FUNC(CopyPasteSelectionReceivedCB), mainWnd);
 
734
   gtk_signal_connect(GTK_OBJECT(mainWnd), "selection_get",
 
735
                      GTK_SIGNAL_FUNC(CopyPasteSelectionGetCB), mainWnd);
 
736
   gtk_signal_connect(GTK_OBJECT(mainWnd), "selection_clear_event",
 
737
                      GTK_SIGNAL_FUNC(CopyPasteSelectionClearCB), mainWnd);
 
738
 
 
739
   CopyPasteStateInit();
 
740
 
 
741
   return TRUE;
 
742
}
 
743
 
 
744
 
 
745
/*
 
746
 *-----------------------------------------------------------------------------
 
747
 *
 
748
 * CopyPaste_Unregister --
 
749
 *
 
750
 *      Cleanup copy/paste related things.
 
751
 *
 
752
 * Results:
 
753
 *      None.
 
754
 *
 
755
 * Side effects:
 
756
 *      copy/paste is stopped, the rpc channel to the vmx is closed.
 
757
 *
 
758
 *-----------------------------------------------------------------------------
 
759
 */
 
760
 
 
761
void
 
762
CopyPaste_Unregister(GtkWidget* mainWnd)
 
763
{
 
764
   g_debug("%s: enter\n", __FUNCTION__);
 
765
   gtk_signal_disconnect_by_func(GTK_OBJECT(mainWnd),
 
766
                                 GTK_SIGNAL_FUNC(CopyPasteSelectionReceivedCB),
 
767
                                 mainWnd);
 
768
   gtk_signal_disconnect_by_func(GTK_OBJECT(mainWnd),
 
769
                                 GTK_SIGNAL_FUNC(CopyPasteSelectionGetCB),
 
770
                                 mainWnd);
 
771
   gtk_signal_disconnect_by_func(GTK_OBJECT(mainWnd),
 
772
                                 GTK_SIGNAL_FUNC(CopyPasteSelectionClearCB),
 
773
                                 mainWnd);
 
774
}
 
775
 
 
776
 
 
777
/*
 
778
 *----------------------------------------------------------------------------
 
779
 *
 
780
 * CopyPaste_IsRpcCPSupported --
 
781
 *
 
782
 *    Check if RPC copy/paste is supported by vmx or not.
 
783
 *
 
784
 * Results:
 
785
 *    FALSE always.
 
786
 *
 
787
 * Side effects:
 
788
 *    None.
 
789
 *
 
790
 *-----------------------------------------------------------------------------
 
791
 */
 
792
 
 
793
Bool
 
794
CopyPaste_IsRpcCPSupported(void)
 
795
{
 
796
   return gVmxCopyPasteVersion > 1;
 
797
}
 
798
 
 
799
 
 
800
/*
 
801
 *----------------------------------------------------------------------------
 
802
 *
 
803
 * CopyPasteStateInit --
 
804
 *
 
805
 *    Initalialize CopyPaste State.
 
806
 *
 
807
 * Results:
 
808
 *    None.
 
809
 *
 
810
 * Side effects:
 
811
 *    None.
 
812
 *
 
813
 *----------------------------------------------------------------------------
 
814
 */
 
815
 
 
816
void
 
817
CopyPasteStateInit(void)
 
818
{
 
819
   g_debug("%s: enter\n", __FUNCTION__);
 
820
   gHostClipboardBuf[0] = '\0';
 
821
   gGuestSelPrimaryBuf[0] = '\0';
 
822
   gGuestSelClipboardBuf[0] = '\0';
 
823
   gIsOwner = FALSE;
 
824
}
 
825
 
 
826
 
 
827
/**
 
828
 * Set the copy paste version.
 
829
 *
 
830
 * @param[in] version version to set.
 
831
 */
 
832
 
 
833
void
 
834
CopyPaste_SetVersion(int version)
 
835
{
 
836
   g_debug("%s: enter version %d\n", __FUNCTION__, version);
 
837
   gVmxCopyPasteVersion = version;
 
838
}