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

« back to all changes in this revision

Viewing changes to vmware-user/copyPasteUI.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Daniel Baumann
  • Date: 2009-03-20 10:19:00 UTC
  • mfrom: (1.1.4 upstream) (2.4.3 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090320101900-1o604camiubq2de8
Tags: 2009.03.18-154848-2
Correcting patch system depends (Closes: #520493).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*********************************************************
 
2
 * Copyright (C) 2009 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
 * copyPasteUI.cpp --
 
21
 *
 
22
 *    This class implements the methods that allows CopyPaste between host
 
23
 *    and guest.
 
24
 *
 
25
 *    For a perspective on X copy/paste, see
 
26
 *    http://www.jwz.org/doc/x-cut-and-paste.html
 
27
 */
 
28
 
 
29
#include <sys/time.h>
 
30
#include <time.h>
 
31
#include "copyPasteUI.h"
 
32
#include "dndFileList.hh"
 
33
 
 
34
extern "C" {
 
35
   #include "vmwareuserInt.h"
 
36
   #include "vmblock.h"
 
37
   #include "vm_app.h"
 
38
   #include "file.h"
 
39
   #include "dnd.h"
 
40
   #include "dndMsg.h"
 
41
   #include "dndClipboard.h"
 
42
   #include "cpName.h"
 
43
   #include "debug.h"
 
44
   #include "cpNameUtil.h"
 
45
   #include "rpcout.h"
 
46
   #include "eventManager.h"
 
47
}
 
48
 
 
49
/*
 
50
 *-----------------------------------------------------------------------------
 
51
 *
 
52
 * CopyPasteUI::CopyPasteUI --
 
53
 *
 
54
 *    Constructor.
 
55
 *
 
56
 * Results:
 
57
 *    None
 
58
 *
 
59
 * Side effects:
 
60
 *    None
 
61
 *
 
62
 *-----------------------------------------------------------------------------
 
63
 */
 
64
 
 
65
CopyPasteUI::CopyPasteUI()
 
66
 : mClipboardEmpty(true),
 
67
   mHGStagingDir(""),
 
68
   mIsClipboardOwner(false),
 
69
   mClipTimePrev(0),
 
70
   mPrimTimePrev(0),
 
71
   mHGGetFilesInitiated(false),
 
72
   mFileTransferDone(false),
 
73
   mBlockAdded(false),
 
74
   mBlockFd(-1),
 
75
   mInited(false)
 
76
{
 
77
}
 
78
 
 
79
 
 
80
/*
 
81
 *-----------------------------------------------------------------------------
 
82
 *
 
83
 * CopyPasteUI::Init --
 
84
 *
 
85
 *    Initialize copy paste UI class and register for V3 or greater copy
 
86
 *    paste.
 
87
 *
 
88
 * Results:
 
89
 *    None
 
90
 *
 
91
 * Side effects:
 
92
 *    None
 
93
 *
 
94
 *-----------------------------------------------------------------------------
 
95
 */
 
96
 
 
97
void
 
98
CopyPasteUI::Init()
 
99
{
 
100
 
 
101
   if (mInited) {
 
102
      return;
 
103
   }
 
104
 
 
105
   mInited = true;
 
106
   CPClipboard_Init(&mClipboard);
 
107
 
 
108
   Gtk::TargetEntry gnome(FCP_TARGET_NAME_GNOME_COPIED_FILES);
 
109
   Gtk::TargetEntry kde(FCP_TARGET_NAME_URI_LIST);
 
110
   gnome.set_info(FCP_TARGET_INFO_GNOME_COPIED_FILES);
 
111
   kde.set_info(FCP_TARGET_INFO_URI_LIST);
 
112
 
 
113
   mListTargets.push_back(gnome);
 
114
   mListTargets.push_back(kde);
 
115
 
 
116
   /* Tell the VMX about the copyPaste version we support. */
 
117
   if (!RpcOut_sendOne(NULL, NULL, "tools.capability.copypaste_version 3")) {
 
118
      Debug("%s: could not set guest copypaste version capability\n",
 
119
            __FUNCTION__);
 
120
      return;
 
121
   }
 
122
   Debug("%s: set copypaste version 3\n", __FUNCTION__);
 
123
 
 
124
   mCP.newClipboard.connect(
 
125
      sigc::mem_fun(this, &CopyPasteUI::GetRemoteClipboardCB));
 
126
   mCP.localGetClipboard.connect(
 
127
      sigc::mem_fun(this, &CopyPasteUI::GetLocalClipboard));
 
128
   mCP.localGetFilesDoneChanged.connect(
 
129
      sigc::mem_fun(this, &CopyPasteUI::GetLocalFilesDone));
 
130
}
 
131
 
 
132
 
 
133
/*
 
134
 *-----------------------------------------------------------------------------
 
135
 *
 
136
 * CopyPasteUI::~CopyPaste --
 
137
 *
 
138
 *    Destructor.
 
139
 *
 
140
 * Results:
 
141
 *    None.
 
142
 *
 
143
 * Side effects:
 
144
 *    None.
 
145
 *
 
146
 *-----------------------------------------------------------------------------
 
147
 */
 
148
 
 
149
CopyPasteUI::~CopyPasteUI()
 
150
{
 
151
   CPClipboard_Destroy(&mClipboard);
 
152
}
 
153
 
 
154
 
 
155
/*
 
156
 *-----------------------------------------------------------------------------
 
157
 *
 
158
 * CopyPasteUI::VmxCopyPasteVersionChanged --
 
159
 *
 
160
 *      Update version information in mCP.
 
161
 *
 
162
 * Results:
 
163
 *      None.
 
164
 *
 
165
 * Side effects:
 
166
 *      None.
 
167
 *
 
168
 *-----------------------------------------------------------------------------
 
169
 */
 
170
 
 
171
void
 
172
CopyPasteUI::VmxCopyPasteVersionChanged(struct RpcIn *rpcIn, // IN
 
173
                                        uint32 version)      // IN
 
174
{
 
175
   Debug("%s: new version is %d\n", __FUNCTION__, version);
 
176
   mCP.VmxCopyPasteVersionChanged(rpcIn, version);
 
177
}
 
178
 
 
179
 
 
180
/*
 
181
 *-----------------------------------------------------------------------------
 
182
 *
 
183
 * CopyPasteUI::GetLocalClipboard --
 
184
 *
 
185
 *    Retrives the data from local clipboard and sends it to host. Send empty
 
186
 *    data back if there is no data or can not get data successfully. For 
 
187
 *    guest->host copy/paste.
 
188
 *
 
189
 * Results:
 
190
 *    None.
 
191
 *
 
192
 * Side effects:
 
193
 *    None.
 
194
 *
 
195
 *-----------------------------------------------------------------------------
 
196
 */
 
197
 
 
198
bool
 
199
CopyPasteUI::GetLocalClipboard(CPClipboard *clip) // OUT
 
200
{
 
201
   Debug("%s: enter.\n", __FUNCTION__);
 
202
 
 
203
   if (mIsClipboardOwner) {
 
204
      Debug("%s: is clipboard owner, set changed to false and return.\n", __FUNCTION__);
 
205
      CPClipboard_SetChanged(clip, FALSE);
 
206
      return true;
 
207
   }
 
208
 
 
209
   if (!mCP.IsCopyPasteAllowed()) {
 
210
      Debug("%s: copyPaste is not allowed\n", __FUNCTION__);
 
211
      return true;
 
212
   }
 
213
 
 
214
   Glib::RefPtr<Gtk::Clipboard> refClipboard =
 
215
      Gtk::Clipboard::get(GDK_SELECTION_CLIPBOARD);
 
216
 
 
217
   mClipTime = 0;
 
218
   mPrimTime = 0;
 
219
   mGHSelection = GDK_SELECTION_CLIPBOARD;
 
220
   Debug("%s: retrieving timestamps\n", __FUNCTION__);
 
221
   refClipboard->request_contents(TARGET_NAME_TIMESTAMP,
 
222
      sigc::mem_fun(this, &CopyPasteUI::LocalClipboardTimestampCB));
 
223
   return false;
 
224
}
 
225
 
 
226
 
 
227
/*
 
228
 *-----------------------------------------------------------------------------
 
229
 *
 
230
 * CopyPasteUI::GetCurrentTime --
 
231
 *
 
232
 *    Get current time in microseconds. 
 
233
 *
 
234
 * Results:
 
235
 *    Time in microseconds.
 
236
 *
 
237
 * Side effects:
 
238
 *    None.
 
239
 *
 
240
 *-----------------------------------------------------------------------------
 
241
 */
 
242
 
 
243
VmTimeType
 
244
CopyPasteUI::GetCurrentTime(void)
 
245
{
 
246
   struct timeval tv;
 
247
   VmTimeType curTime;
 
248
 
 
249
   if (gettimeofday(&tv, NULL) != 0) {
 
250
      Debug("%s: gettimeofday failed!\n", __FUNCTION__);
 
251
      return (VmTimeType) 0;
 
252
   }
 
253
   curTime = (tv.tv_sec * 1000000 + tv.tv_usec);
 
254
   return curTime;
 
255
}
 
256
 
 
257
 
 
258
/*
 
259
 *-----------------------------------------------------------------------------
 
260
 *
 
261
 * CopyPasteUI::LocalGetFileRequestCB --
 
262
 *
 
263
 *      Callback from a file paste request from another guest application.
 
264
 *      Begins copying the files from host to guest and return the file list.
 
265
 *
 
266
 * Results:
 
267
 *      None.
 
268
 *
 
269
 * Side effects:
 
270
 *      None.
 
271
 *
 
272
 *-----------------------------------------------------------------------------
 
273
 */
 
274
 
 
275
void
 
276
CopyPasteUI::LocalGetFileRequestCB(Gtk::SelectionData& sd,        // IN:
 
277
                                   guint info)                    // IN:
 
278
{
 
279
   Debug("%s: enter.\n", __FUNCTION__);
 
280
   mHGCopiedUriList = "";
 
281
   VmTimeType curTime;
 
282
   mBlockAdded = false;
 
283
 
 
284
   curTime = GetCurrentTime();
 
285
 
 
286
   /*
 
287
    * Some applications may ask for clipboard contents right after clipboard
 
288
    * owner changed. So HG FCP will return nothing for some time after switch
 
289
    * from guest OS to host OS.
 
290
    */
 
291
   if ((curTime - mHGGetListTime) < FCP_COPY_DELAY) {
 
292
      Debug("%s: time delta less than FCP_COPY_DELAY, returning.\n",
 
293
            __FUNCTION__);
 
294
      return;
 
295
   }
 
296
 
 
297
   if (!mIsClipboardOwner || !mCP.IsCopyPasteAllowed()) {
 
298
      Debug("%s: not clipboard ownder, or copy paste not allowed, returning.\n",
 
299
            __FUNCTION__);
 
300
      return;
 
301
   }
 
302
 
 
303
   Debug("%s: Got paste request, target is %s\n", __FUNCTION__,
 
304
         sd.get_target().c_str());
 
305
 
 
306
   /* Copy the files. */
 
307
   if (!mHGGetFilesInitiated) {
 
308
      utf::string str;
 
309
      utf::string hgStagingDir;
 
310
      utf::string stagingDirName;
 
311
      utf::string pre;
 
312
      utf::string post;
 
313
      size_t index = 0;
 
314
      mFileTransferDone = false;
 
315
 
 
316
      hgStagingDir = static_cast<utf::string>(mCP.GetFiles());
 
317
      Debug("%s: Getting files. Staging dir: %s", __FUNCTION__,
 
318
            hgStagingDir.c_str());
 
319
 
 
320
      if (0 == hgStagingDir.bytes()) {
 
321
         Debug("%s: Can not create staging directory\n", __FUNCTION__);
 
322
         return;
 
323
      }
 
324
      mHGGetFilesInitiated = true;
 
325
 
 
326
      if (DnD_AddBlock(mBlockFd, hgStagingDir.c_str())) {
 
327
         Debug("%s: add block mBlockFd %d.\n", __FUNCTION__, mBlockFd);
 
328
         mHGStagingDir = hgStagingDir;
 
329
         mBlockAdded = true;
 
330
      } else {
 
331
         Debug("%s: unable to add block fd %d dir %s.\n",
 
332
                __FUNCTION__, mBlockFd, hgStagingDir.c_str());
 
333
      }
 
334
 
 
335
      /* Provide URIs for each path in the guest's file list. */
 
336
      if (FCP_TARGET_INFO_GNOME_COPIED_FILES == info) {
 
337
         mHGCopiedUriList = "copy\n";
 
338
         pre = FCP_GNOME_LIST_PRE;
 
339
         post = FCP_GNOME_LIST_POST;
 
340
      } else if (FCP_TARGET_INFO_URI_LIST == info) {
 
341
         pre = DND_URI_LIST_PRE_KDE;
 
342
         post = DND_URI_LIST_POST;
 
343
      } else {
 
344
         Debug("%s: Unknown request target: %s\n", __FUNCTION__,
 
345
               sd.get_target().c_str());
 
346
         return;
 
347
      }
 
348
 
 
349
      /* Provide path within vmblock file system instead of actual path. */
 
350
      stagingDirName = GetLastDirName(hgStagingDir);
 
351
      if (0 == stagingDirName.bytes()) {
 
352
         Debug("%s: Can not get staging directory name\n", __FUNCTION__);
 
353
         return;
 
354
      }
 
355
 
 
356
      while ((str = GetNextPath(mHGFCPData, index).c_str()).bytes() != 0) {
 
357
         Debug("%s: Path: %s", __FUNCTION__, str.c_str());
 
358
         mHGCopiedUriList += pre;
 
359
         mHGCopiedUriList += VMBLOCK_MOUNT_POINT;
 
360
         mHGCopiedUriList += DIRSEPS + stagingDirName + DIRSEPS + str + post;
 
361
      }
 
362
 
 
363
      /* Nautilus does not expect FCP_GNOME_LIST_POST after the last uri. See bug 143147. */
 
364
      if (FCP_TARGET_INFO_GNOME_COPIED_FILES == info) {
 
365
         mHGCopiedUriList.erase(mHGCopiedUriList.size() - 1, 1);
 
366
      }
 
367
   }
 
368
 
 
369
   if (0 == mHGCopiedUriList.bytes()) {
 
370
      Debug("%s: Can not get uri list\n", __FUNCTION__);
 
371
      return;
 
372
   }
 
373
 
 
374
   if (!mBlockAdded) {
 
375
      /*
 
376
       * If there is no blocking driver, wait here till file copy is done.
 
377
       * 2 reasons to keep this:
 
378
       * 1. If run vmware-user stand-alone as non-root, blocking driver can
 
379
       *    not be opened. Debug purpose only.
 
380
       * 2. Other platforms (Solaris, etc) may also use this code,
 
381
       *    and there is no blocking driver yet.
 
382
       *
 
383
       * Polling here will not be sufficient for large files (experiments
 
384
       * showed it was sufficient for a 256MB file, and failed for a 1GB
 
385
       * file, but those numbers are of course context-sensitive and so YMMV).
 
386
       * The reason is we are executing in the context of gtkmm callback, and
 
387
       * apparently it only has so much patience regarding how quickly we
 
388
       * return.
 
389
       */
 
390
      Debug("%s no blocking driver, waiting for "
 
391
            "HG file copy done ...\n", __FUNCTION__);
 
392
      while (mFileTransferDone == false) {
 
393
         struct timeval tv;
 
394
         int nr;
 
395
 
 
396
         tv.tv_sec = 0;
 
397
         nr = EventManager_ProcessNext(gEventQueue, (uint64 *)&tv.tv_usec);
 
398
         if (nr != 1) {
 
399
            Debug("%s: unexpected end of loop: returned "
 
400
                  "value is %d.\n", __FUNCTION__, nr);
 
401
            return;
 
402
         }
 
403
         if (select(0, NULL, NULL, NULL, &tv) == -1) {
 
404
            Debug("%s: error in select (%s).\n", __FUNCTION__,
 
405
                  strerror(errno));
 
406
            return;
 
407
         }
 
408
      }
 
409
      Debug("%s: file transfer done!\n", __FUNCTION__);
 
410
   }
 
411
 
 
412
   Debug("%s: providing file list [%s]\n", __FUNCTION__,
 
413
         mHGCopiedUriList.c_str());
 
414
 
 
415
   sd.set(sd.get_target().c_str(), mHGCopiedUriList.c_str());
 
416
}
 
417
 
 
418
 
 
419
/*
 
420
 *-----------------------------------------------------------------------------
 
421
 *
 
422
 * CopyPaste::LocalClearClipboardCB --
 
423
 *
 
424
 *      Clear clipboard request from another host application.
 
425
 *
 
426
 * Results:
 
427
 *      None.
 
428
 *
 
429
 * Side effects:
 
430
 *      None.
 
431
 *
 
432
 *-----------------------------------------------------------------------------
 
433
 */
 
434
 
 
435
void
 
436
CopyPasteUI::LocalClearClipboardCB(void)
 
437
{
 
438
   Debug("%s: got clear callback\n", __FUNCTION__);
 
439
   mIsClipboardOwner = FALSE;
 
440
}
 
441
 
 
442
 
 
443
/*
 
444
 *----------------------------------------------------------------------
 
445
 *
 
446
 * CopyPasteUI::LocalClipboardTimestampCB --
 
447
 *
 
448
 *      Got the local clipboard timestamp. Ask for the primary timestamp.
 
449
 *
 
450
 * Results:
 
451
 *      None.
 
452
 *
 
453
 * Side effects:
 
454
 *      None.
 
455
 *
 
456
 *----------------------------------------------------------------------
 
457
 */
 
458
 
 
459
void
 
460
CopyPasteUI::LocalClipboardTimestampCB(const Gtk::SelectionData& sd)  // IN
 
461
{
 
462
   int length = sd.get_length();
 
463
   Debug("%s: enter sd.get_length() %d.\n", __FUNCTION__,
 
464
         length);
 
465
   if (length == 4) {
 
466
      mClipTime = ((uint32*) sd.get_data())[0];
 
467
      Debug("%s: mClipTime: %"FMT64"u.", __FUNCTION__, mClipTime);
 
468
   } else if (length == 8) {
 
469
      mClipTime = ((uint64*) sd.get_data())[0];
 
470
      Debug("%s: mClipTime: %"FMT64"u.", __FUNCTION__, mClipTime);
 
471
   } else {
 
472
      Debug("%s: Unable to get mClipTime.", __FUNCTION__);
 
473
   }
 
474
 
 
475
   Glib::RefPtr<Gtk::Clipboard> refClipboard
 
476
      = Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
 
477
   refClipboard->request_contents(TARGET_NAME_TIMESTAMP,
 
478
      sigc::mem_fun(this, &CopyPasteUI::LocalPrimTimestampCB));
 
479
}
 
480
 
 
481
 
 
482
/*
 
483
 *----------------------------------------------------------------------
 
484
 *
 
485
 * CopyPasteUI::LocalPrimTimestampCB --
 
486
 *
 
487
 *      Got the local primary timestamp. Choose the most recently changed
 
488
 *      clipboard and get the selection from it.
 
489
 *
 
490
 * Results:
 
491
 *      None.
 
492
 *
 
493
 * Side effects:
 
494
 *      None.
 
495
 *
 
496
 *----------------------------------------------------------------------
 
497
 */
 
498
 
 
499
void
 
500
CopyPasteUI::LocalPrimTimestampCB(const Gtk::SelectionData& sd)  // IN
 
501
{
 
502
   bool unchanged = FALSE;
 
503
   int length = sd.get_length();
 
504
   Debug("%s: enter sd.get_length() is %d.\n", __FUNCTION__, length);
 
505
   if (length == 4) {
 
506
      mPrimTime = ((uint32*) sd.get_data())[0];
 
507
      Debug("%s: mPrimTime: %"FMT64"u.", __FUNCTION__, mPrimTime);
 
508
   } else if (length == 8) {
 
509
      mPrimTime = ((uint64*) sd.get_data())[0];
 
510
      Debug("%s: mPrimTime: %"FMT64"u.", __FUNCTION__, mPrimTime);
 
511
   } else {
 
512
      Debug("%s: Unable to get mPrimTime.", __FUNCTION__);
 
513
   }
 
514
 
 
515
   /* After got both timestamp, choose latest one as active selection. */
 
516
   mGHSelection = GDK_SELECTION_PRIMARY;
 
517
   if (mClipTime > mPrimTime) {
 
518
      mGHSelection = GDK_SELECTION_CLIPBOARD;
 
519
      Debug("%s: mClipTimePrev: %"FMT64"u.", __FUNCTION__, mClipTimePrev);
 
520
      unchanged = mClipTime <= mClipTimePrev;
 
521
   } else {
 
522
      Debug("%s: mPrimTimePrev: %"FMT64"u.", __FUNCTION__, mPrimTimePrev);
 
523
      unchanged = mPrimTime <= mPrimTimePrev;
 
524
   }
 
525
 
 
526
   if (unchanged) {
 
527
      Debug("%s: clipboard is unchanged, get out\n", __FUNCTION__);
 
528
      CPClipboard_SetChanged(&mClipboard, FALSE);
 
529
      return;
 
530
   }
 
531
 
 
532
   mPrimTimePrev = mPrimTime;
 
533
   mClipTimePrev = mClipTime;
 
534
 
 
535
   /* Ask for available targets from active selection. */
 
536
   Glib::RefPtr<Gtk::Clipboard> refClipboard =
 
537
      Gtk::Clipboard::get(mGHSelection);
 
538
 
 
539
   refClipboard->request_targets(
 
540
      sigc::mem_fun(this, &CopyPasteUI::LocalReceivedTargetsCB));
 
541
}
 
542
 
 
543
 
 
544
/*
 
545
 *----------------------------------------------------------------------
 
546
 *
 
547
 * CopyPasteUI::LocalReceivedTargetsCB --
 
548
 *
 
549
 *      Received targets. Check if any desired target available. If so,
 
550
 *      ask for all supported contents.
 
551
 *
 
552
 * Results:
 
553
 *      None.
 
554
 *
 
555
 * Side effects:
 
556
 *      Clipboard owner may send us file list.
 
557
 *
 
558
 *----------------------------------------------------------------------
 
559
 */
 
560
 
 
561
void
 
562
CopyPasteUI::LocalReceivedTargetsCB(const Glib::StringArrayHandle& targetsArray)  // IN
 
563
{
 
564
   std::list<utf::string> targets = targetsArray;
 
565
   Glib::RefPtr<Gtk::Clipboard> refClipboard = Gtk::Clipboard::get(mGHSelection);
 
566
 
 
567
   Debug("%s: enter", __FUNCTION__);
 
568
   CPClipboard_Clear(&mClipboard);
 
569
 
 
570
   if (std::find(targets.begin(),
 
571
                 targets.end(),
 
572
                 FCP_TARGET_NAME_GNOME_COPIED_FILES) != targets.end()) {
 
573
      Debug("%s: gnome copy file list available\n", __FUNCTION__);
 
574
      refClipboard->request_contents(FCP_TARGET_NAME_GNOME_COPIED_FILES,
 
575
                                     sigc::mem_fun(this,
 
576
                                                   &CopyPasteUI::LocalReceivedFileListCB));
 
577
      return;
 
578
   }
 
579
 
 
580
   if (std::find(targets.begin(),
 
581
                 targets.end(),
 
582
                 FCP_TARGET_NAME_URI_LIST) != targets.end()) {
 
583
      Debug("%s: KDE copy file list available\n", __FUNCTION__);
 
584
      refClipboard->request_contents(FCP_TARGET_NAME_URI_LIST,
 
585
                                     sigc::mem_fun(this,
 
586
                                                   &CopyPasteUI::LocalReceivedFileListCB));
 
587
      return;
 
588
   }
 
589
 
 
590
   Debug("%s: ask for text\n", __FUNCTION__);
 
591
   refClipboard->request_text(sigc::mem_fun(this,
 
592
                                            &CopyPasteUI::LocalReceivedTextCB));
 
593
}
 
594
 
 
595
 
 
596
/*
 
597
 *----------------------------------------------------------------------
 
598
 *
 
599
 * CopyPasteUI::LocalReceivedFileListCB --
 
600
 *
 
601
 *      Got clipboard or primary selection file list. Parse it and add
 
602
 *      it to the crossplaform clipboard. Send clipboard to the host.
 
603
 *
 
604
 * Results:
 
605
 *      None.
 
606
 *
 
607
 * Side effects:
 
608
 *      None.
 
609
 *
 
610
 *----------------------------------------------------------------------
 
611
 */
 
612
 
 
613
void
 
614
CopyPasteUI::LocalReceivedFileListCB(const Gtk::SelectionData& sd)        // IN
 
615
{
 
616
   Debug("%s: enter", __FUNCTION__);
 
617
   const utf::string target = sd.get_target().c_str();
 
618
 
 
619
   if (target == FCP_TARGET_NAME_GNOME_COPIED_FILES ||
 
620
       target == FCP_TARGET_NAME_URI_LIST) {
 
621
      LocalGetSelectionFileList(sd);
 
622
      mCP.SetRemoteClipboard(&mClipboard);
 
623
   }
 
624
}
 
625
 
 
626
 
 
627
/*
 
628
 *----------------------------------------------------------------------
 
629
 *
 
630
 * CopyPasteUI::LocalReceivedTextCB --
 
631
 *
 
632
 *      Got clipboard (or primary selection) text, add to local clipboard
 
633
 *      cache and send clipboard to host.
 
634
 *
 
635
 * Results:
 
636
 *      None.
 
637
 *
 
638
 * Side effects:
 
639
 *      None.
 
640
 *
 
641
 *----------------------------------------------------------------------
 
642
 */
 
643
 
 
644
void
 
645
CopyPasteUI::LocalReceivedTextCB(const Glib::ustring& text)        // IN
 
646
{
 
647
   Debug("%s: enter", __FUNCTION__);
 
648
   utf::string source = text;
 
649
 
 
650
   /*
 
651
    * With 'cut' operation OpenOffice will put data into clipboard but
 
652
    * set same timestamp for both clipboard and primary selection.
 
653
    * If primary timestamp is same as clipboard timestamp, we should try
 
654
    * clipboard again if primary selection is empty. For details please
 
655
    * refer to bug 300780.
 
656
    */
 
657
   if (0 == source.bytes() &&
 
658
       mClipTime == mPrimTime &&
 
659
       mClipTime != 0) {
 
660
      mClipTime = 0;
 
661
      mPrimTime = 0;
 
662
      mGHSelection = GDK_SELECTION_CLIPBOARD;
 
663
 
 
664
      /* Ask for available targets from active selection. */
 
665
      Glib::RefPtr<Gtk::Clipboard> refClipboard =
 
666
         Gtk::Clipboard::get(mGHSelection);
 
667
 
 
668
      refClipboard->request_targets(
 
669
         sigc::mem_fun(this, &CopyPasteUI::LocalReceivedTargetsCB));
 
670
      return;
 
671
   }
 
672
 
 
673
   Debug("%s: Got text: %s", __FUNCTION__, source.c_str());
 
674
 
 
675
   /* Add NUL terminator. */
 
676
   CPClipboard_SetItem(&mClipboard, CPFORMAT_TEXT, source.c_str(),
 
677
                       source.bytes() + 1);
 
678
   mCP.SetRemoteClipboard(&mClipboard);
 
679
}
 
680
 
 
681
 
 
682
/*
 
683
 *-----------------------------------------------------------------------------
 
684
 *
 
685
 * CopyPasteUI::LocalGetSelectionFileList --
 
686
 *
 
687
 *      Construct local file list and remote file list from selection data.
 
688
 *      Called by both DnD and FCP.
 
689
 *
 
690
 * Results:
 
691
 *      None.
 
692
 *
 
693
 * Side effects:
 
694
 *      None.
 
695
 *
 
696
 *-----------------------------------------------------------------------------
 
697
 */
 
698
 
 
699
void
 
700
CopyPasteUI::LocalGetSelectionFileList(const Gtk::SelectionData& sd)      // IN
 
701
{
 
702
   utf::string source;
 
703
   char *newPath;
 
704
   char *newRelPath;
 
705
   size_t newPathLen;
 
706
   size_t index = 0;
 
707
   DnDFileList fileList;
 
708
   DynBuf buf;
 
709
   uint64 totalSize = 0;
 
710
   int64 size;
 
711
 
 
712
   /*
 
713
    * Turn the uri list into two \0  delimited lists. One for full paths and
 
714
    * one for just the last path component.
 
715
    */
 
716
   source = sd.get_data_as_string().c_str();
 
717
   Debug("%s: Got file list: [%s]\n", __FUNCTION__, source.c_str());
 
718
 
 
719
   /*
 
720
    * In gnome, before file list there may be a extra line indicating it
 
721
    * is a copy or cut.
 
722
    */
 
723
   if (source.startsWith("copy\n")) {
 
724
      source = source.erase(0, 5);
 
725
   }
 
726
 
 
727
   if (source.startsWith("cut\n")) {
 
728
      source = source.erase(0, 4);
 
729
   }
 
730
 
 
731
   while (source.bytes() > 0 &&
 
732
          (source[0] == '\n' || source[0] == '\r' || source[0] == ' ')) {
 
733
      source = source.erase(0, 1);
 
734
   }
 
735
 
 
736
   while ((newPath = DnD_UriListGetNextFile(source.c_str(),
 
737
                                            &index,
 
738
                                            &newPathLen)) != NULL) {
 
739
 
 
740
      /*
 
741
       * Parse relative path.
 
742
       */
 
743
      newRelPath = Str_Strrchr(newPath, DIRSEPC) + 1; // Point to char after '/'
 
744
 
 
745
      /*
 
746
       * XXX For directory, value is -1, so if there is any directory,
 
747
       * total size is not accurate.
 
748
       */
 
749
      if ((size = File_GetSize(newPath)) >= 0) {
 
750
         totalSize += size;
 
751
      } else {
 
752
         Debug("%s: Unable to get file size for %s\n", __FUNCTION__, newPath);
 
753
      }
 
754
 
 
755
      Debug("%s: Adding newPath '%s' newRelPath '%s'\n", __FUNCTION__,
 
756
            newPath, newRelPath);
 
757
      fileList.AddFile(newPath, newRelPath);
 
758
      free(newPath);
 
759
   }
 
760
 
 
761
   DynBuf_Init(&buf);
 
762
   fileList.SetFileSize(totalSize);
 
763
   Debug("%s: totalSize is %"FMT64"u\n", __FUNCTION__, totalSize);
 
764
   fileList.ToCPClipboard(&buf, false);
 
765
   CPClipboard_SetItem(&mClipboard, CPFORMAT_FILELIST, DynBuf_Get(&buf),
 
766
                       DynBuf_GetSize(&buf));
 
767
   DynBuf_Destroy(&buf);
 
768
}
 
769
 
 
770
 
 
771
/*
 
772
 *----------------------------------------------------------------------------
 
773
 *
 
774
 * CopyPasteUI::GetNextPath --
 
775
 *
 
776
 *      Provides a substring containing the next path from the provided
 
777
 *      NUL-delimited string starting at the provided index.
 
778
 *
 
779
 * Results:
 
780
 *      A string with the next path or "" if there are no more paths.
 
781
 *
 
782
 * Side effects:
 
783
 *      None.
 
784
 *
 
785
 *----------------------------------------------------------------------------
 
786
 */
 
787
 
 
788
utf::utf8string
 
789
CopyPasteUI::GetNextPath(utf::utf8string& str,    // IN: NUL-delimited path list
 
790
                         size_t& index)           // IN/OUT: current index into string
 
791
{
 
792
   utf::utf8string ret;
 
793
   size_t start;
 
794
 
 
795
   if (index >= str.length()) {
 
796
      return "";
 
797
   }
 
798
 
 
799
   for (start = index; str[index] != '\0' && index < str.length(); index++) {
 
800
      /*
 
801
       * Escape reserved characters according to RFC 1630.  We'd use
 
802
       * Escape_Do() if this wasn't a utf::string, but let's use the same table
 
803
       * replacement approach.
 
804
       */
 
805
      static char const Dec2Hex[] = {
 
806
         '0', '1', '2', '3', '4', '5', '6', '7',
 
807
         '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
 
808
      };
 
809
 
 
810
      unsigned char ubyte = str[index];
 
811
 
 
812
      if (ubyte == '#' ||   /* Fragment identifier delimiter */
 
813
          ubyte == '?' ||   /* Query string delimiter */
 
814
          ubyte == '*' ||   /* "Special significance within specific schemes" */
 
815
          ubyte == '!' ||   /* "Special significance within specific schemes" */
 
816
          ubyte == '%' ||   /* Escape character */
 
817
          ubyte >= 0x80) {  /* UTF-8 encoding bytes */
 
818
         str.replace(index, 1, "%");
 
819
         str.insert(index + 1, 1, Dec2Hex[ubyte >> 4]);
 
820
         str.insert(index + 2, 1, Dec2Hex[ubyte & 0xF]);
 
821
         index += 2;
 
822
      }
 
823
   }
 
824
 
 
825
   ret = str.substr(start, index - start);
 
826
   Debug("%s: nextpath: %s", __FUNCTION__, ret.c_str());
 
827
   index++;
 
828
   return ret;
 
829
}
 
830
 
 
831
 
 
832
/*
 
833
 *-----------------------------------------------------------------------------
 
834
 *
 
835
 * CopyPasteUI::GetLastDirName --
 
836
 *
 
837
 *      Try to get last directory name from a full path name.
 
838
 *
 
839
 * Results:
 
840
 *      Last dir name in the full path name if sucess, empty str otherwise
 
841
 *
 
842
 * Side effects:
 
843
 *      None.
 
844
 *
 
845
 *-----------------------------------------------------------------------------
 
846
 */
 
847
 
 
848
utf::string
 
849
CopyPasteUI::GetLastDirName(const utf::string &str)     // IN
 
850
{
 
851
   utf::string ret;
 
852
   size_t start;
 
853
   size_t end;
 
854
 
 
855
   end = str.bytes() - 1;
 
856
   if (end >= 0 && DIRSEPC == str[end]) {
 
857
      end--;
 
858
   }
 
859
 
 
860
   if (end <= 0 || str[0] != DIRSEPC) {
 
861
      return "";
 
862
   }
 
863
 
 
864
   start = end;
 
865
 
 
866
   while (str[start] != DIRSEPC) {
 
867
      start--;
 
868
   }
 
869
 
 
870
   return str.substr(start + 1, end - start);
 
871
}
 
872
 
 
873
/*
 
874
 *-----------------------------------------------------------------------------
 
875
 *
 
876
 * CopyPasteUI::GetRemoteClipboardCB --
 
877
 *
 
878
 *    Invoked when got data from host. Update the internal data to get the file
 
879
 *    names or the text that needs to be transferred.
 
880
 *
 
881
 *    Method for copy and paste from host to guest.
 
882
 *
 
883
 * Results:
 
884
 *    None
 
885
 *
 
886
 * Side effects:
 
887
 *    None.
 
888
 *
 
889
 *-----------------------------------------------------------------------------
 
890
 */
 
891
 
 
892
void
 
893
CopyPasteUI::GetRemoteClipboardCB(const CPClipboard *clip) // IN
 
894
{
 
895
   Glib::RefPtr<Gtk::Clipboard> refClipboard =
 
896
      Gtk::Clipboard::get(GDK_SELECTION_CLIPBOARD);
 
897
   Glib::RefPtr<Gtk::Clipboard> refPrimary =
 
898
      Gtk::Clipboard::get(GDK_SELECTION_PRIMARY);
 
899
   void *buf;
 
900
   size_t sz;
 
901
 
 
902
   Debug("%s: enter\n", __FUNCTION__);
 
903
   if (!clip) {
 
904
      Debug("%s: No clipboard contents.", __FUNCTION__);
 
905
      return;
 
906
   }
 
907
 
 
908
   /* Clear the clipboard contents if we are the owner. */
 
909
   if (mIsClipboardOwner) {
 
910
      refClipboard->clear();
 
911
      refPrimary->clear();
 
912
      mIsClipboardOwner = FALSE;
 
913
      Debug("%s: Cleared local clipboard", __FUNCTION__);
 
914
   }
 
915
 
 
916
   if (CPClipboard_GetItem(clip, CPFORMAT_TEXT, &buf, &sz)) {
 
917
      Debug("%s: Text data: %s.\n", __FUNCTION__, (char *)buf);
 
918
      refClipboard->set_text((const char *) buf);
 
919
      refPrimary->set_text((const char *) buf);
 
920
   }
 
921
   if (CPClipboard_GetItem(clip, CPFORMAT_FILELIST, &buf, &sz)) {
 
922
      Debug("%s: File data.\n", __FUNCTION__);
 
923
      DnDFileList flist;
 
924
      flist.FromCPClipboard(buf, sz);
 
925
      mHGFCPData = flist.GetRelPathsStr();
 
926
 
 
927
      refClipboard->set(mListTargets,
 
928
                        sigc::mem_fun(this, &CopyPasteUI::LocalGetFileRequestCB),
 
929
                        sigc::mem_fun(this, &CopyPasteUI::LocalClearClipboardCB));
 
930
      refPrimary->set(mListTargets,
 
931
                      sigc::mem_fun(this, &CopyPasteUI::LocalGetFileRequestCB),
 
932
                      sigc::mem_fun(this, &CopyPasteUI::LocalClearClipboardCB));
 
933
 
 
934
      mIsClipboardOwner = TRUE;
 
935
      mHGGetListTime = GetCurrentTime();
 
936
      mHGGetFilesInitiated = false;
 
937
      mHGCopiedUriList = "";
 
938
   }
 
939
}
 
940
 
 
941
 
 
942
/*
 
943
 *-----------------------------------------------------------------------------
 
944
 *
 
945
 * CopyPasteUI::GetLocalFilesDone --
 
946
 *
 
947
 *    Callback when CopyPasteUI::GetLocalFiles is done, which finishes the file
 
948
 *    copying from host to guest staging directory. This function notifies
 
949
 *    the Copy/Paste data object and end its waiting state in order to continue
 
950
 *    the file copying from local staging directory to local target directory.
 
951
 *
 
952
 * Results:
 
953
 *    None
 
954
 *
 
955
 * Side effects:
 
956
 *    None
 
957
 *
 
958
 *-----------------------------------------------------------------------------
 
959
 */
 
960
 
 
961
void
 
962
CopyPasteUI::GetLocalFilesDone(bool success)
 
963
{
 
964
   Debug("%s: enter success %d\n", __FUNCTION__, success);
 
965
 
 
966
   if (mBlockAdded) {
 
967
      Debug("%s: removing block mBlockFd %d\n", __FUNCTION__, mBlockFd);
 
968
      DnD_RemoveBlock(mBlockFd, mHGStagingDir.c_str());
 
969
      mBlockAdded = false;
 
970
   }
 
971
 
 
972
   mFileTransferDone = true;
 
973
   if (success) {
 
974
      /*
 
975
       * Mark current staging dir to be deleted on next reboot for FCP. The
 
976
       * file will not be deleted after reboot if it is moved to another
 
977
       * location by target application.
 
978
       */
 
979
      DnD_DeleteStagingFiles(mHGStagingDir.c_str(), TRUE);
 
980
   } else {
 
981
      /* Copied files are already removed in common layer. */
 
982
      mHGStagingDir.clear();
 
983
   }
 
984
   mHGGetFilesInitiated = false;
 
985
}
 
986
 
 
987
 
 
988
/*
 
989
 *-----------------------------------------------------------------------------
 
990
 *
 
991
 * CopyPasteUI::Reset --
 
992
 *
 
993
 *
 
994
 * Results:
 
995
 *    None
 
996
 *
 
997
 * Side effects:
 
998
 *    None
 
999
 *
 
1000
 *-----------------------------------------------------------------------------
 
1001
 */
 
1002
 
 
1003
void
 
1004
CopyPasteUI::Reset(void)
 
1005
{
 
1006
   Debug("%s: enter\n", __FUNCTION__);
 
1007
   /* Cancel any pending file transfer. */
 
1008
}
 
1009