VirtualBox

source: vbox/trunk/src/VBox/Additions/haiku/VBoxTray/VBoxClipboard.cpp@ 76690

Last change on this file since 76690 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.6 KB
Line 
1/* $Id: VBoxClipboard.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * VBoxClipboard; Haiku Guest Additions, implementation.
4 */
5
6/*
7 * Copyright (C) 2012-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*
19 * This code is based on:
20 *
21 * VirtualBox Guest Additions for Haiku.
22 * Copyright (c) 2011 Mike Smith <[email protected]>
23 * François Revol <[email protected]>
24 *
25 * Permission is hereby granted, free of charge, to any person
26 * obtaining a copy of this software and associated documentation
27 * files (the "Software"), to deal in the Software without
28 * restriction, including without limitation the rights to use,
29 * copy, modify, merge, publish, distribute, sublicense, and/or sell
30 * copies of the Software, and to permit persons to whom the
31 * Software is furnished to do so, subject to the following
32 * conditions:
33 *
34 * The above copyright notice and this permission notice shall be
35 * included in all copies or substantial portions of the Software.
36 *
37 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
38 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
39 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
40 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
41 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
42 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
43 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
44 * OTHER DEALINGS IN THE SOFTWARE.
45 */
46
47#include <stdio.h>
48#include <stdlib.h>
49#include <new>
50#include <Bitmap.h>
51#include <BitmapStream.h>
52#include <Clipboard.h>
53#include <DataIO.h>
54#include <Message.h>
55#include <TranslationUtils.h>
56#include <TranslatorFormats.h>
57#include <TranslatorRoster.h>
58#include <String.h>
59
60#include "VBoxGuestApplication.h"
61#include "VBoxClipboard.h"
62#include <VBoxGuestInternal.h>
63
64#include <iprt/mem.h>
65#include <VBox/GuestHost/clipboard-helper.h>
66#include <VBox/HostServices/VBoxClipboardSvc.h>
67#include <VBox/log.h>
68
69/** @todo r=ramshankar: this hack should go eventually. */
70#ifdef DEBUG_ramshankar
71# undef Log
72# define Log(x) printf x
73# undef LogRel
74# define LogRel(x) printf x
75# undef LogRelFlowFunc
76# define LogRelFlowFunc(x) printf x
77#endif
78
79
80VBoxClipboardService::VBoxClipboardService()
81 : BHandler("VBoxClipboardService"),
82 fClientId(-1),
83 fServiceThreadID(-1),
84 fExiting(false)
85{
86}
87
88
89VBoxClipboardService::~VBoxClipboardService()
90{
91}
92
93
94status_t VBoxClipboardService::Connect()
95{
96 status_t err;
97 LogFlowFunc(("Connect\n"));
98
99 int rc = VbglR3ClipboardConnect(&fClientId);
100 if (RT_SUCCESS(rc))
101 {
102 err = fServiceThreadID = spawn_thread(_ServiceThreadNub, "VBoxClipboardService", B_NORMAL_PRIORITY, this);
103 if (err >= B_OK)
104 {
105 resume_thread(fServiceThreadID);
106 err = be_clipboard->StartWatching(BMessenger(this));
107 LogFlow(("be_clipboard->StartWatching: %ld\n", err));
108 if (err == B_OK)
109 return B_OK;
110 else
111 LogRel(("VBoxClipboardService: Error watching the system clipboard: %ld\n", err));
112 }
113 else
114 LogRel(("VBoxClipboardService: Error starting service thread: %ld\n", err));
115
116 //rc = RTErrConvertFromErrno(err);
117 VbglR3ClipboardDisconnect(fClientId);
118 }
119 else
120 LogRel(("VBoxClipboardService: Error starting service thread: %d\n", rc));
121 return B_ERROR;
122}
123
124
125status_t VBoxClipboardService::Disconnect()
126{
127 status_t status;
128
129 be_clipboard->StopWatching(BMessenger(this));
130
131 fExiting = true;
132
133 VbglR3ClipboardDisconnect(fClientId);
134
135 wait_for_thread(fServiceThreadID, &status);
136 return B_OK;
137}
138
139
140void VBoxClipboardService::MessageReceived(BMessage *message)
141{
142 uint32_t formats = 0;
143 message->PrintToStream();
144 switch (message->what)
145 {
146 case VBOX_GUEST_CLIPBOARD_HOST_MSG_FORMATS:
147 {
148 int rc;
149 uint32_t cb;
150 void *pv;
151 bool commit = false;
152
153 if (message->FindInt32("Formats", (int32 *)&formats) != B_OK)
154 break;
155
156 if (!formats)
157 break;
158
159 if (!be_clipboard->Lock())
160 break;
161
162 be_clipboard->Clear();
163 BMessage *clip = be_clipboard->Data();
164 if (!clip)
165 {
166 be_clipboard->Unlock();
167 break;
168 }
169
170 if (formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
171 {
172 pv = _VBoxReadHostClipboard(VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &cb);
173 if (pv)
174 {
175 char *text;
176 rc = RTUtf16ToUtf8((PCRTUTF16)pv, &text);
177 if (RT_SUCCESS(rc))
178 {
179 BString str(text);
180 /** @todo user vboxClipboardUtf16WinToLin() */
181 // convert Windows CRLF to LF
182 str.ReplaceAll("\r\n", "\n");
183 // don't include the \0
184 clip->AddData("text/plain", B_MIME_TYPE, str.String(), str.Length());
185 RTStrFree(text);
186 commit = true;
187 }
188 free(pv);
189 }
190 }
191
192 if (formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
193 {
194 pv = _VBoxReadHostClipboard(VBOX_SHARED_CLIPBOARD_FMT_BITMAP, &cb);
195 if (pv)
196 {
197 void *pBmp = NULL;
198 size_t cbBmp = 0;
199 rc = vboxClipboardDibToBmp(pv, cb, &pBmp, &cbBmp);
200 if (RT_SUCCESS(rc))
201 {
202 BMemoryIO mio(pBmp, cbBmp);
203 BBitmap *bitmap = BTranslationUtils::GetBitmap(&mio);
204 if (bitmap)
205 {
206 BMessage bitmapArchive;
207
208 /** @todo r=ramshankar: split this into functions with error checking as
209 * neccessary. */
210 if ( bitmap->IsValid()
211 && bitmap->Archive(&bitmapArchive) == B_OK
212 && clip->AddMessage("image/bitmap", &bitmapArchive) == B_OK)
213 {
214 commit = true;
215 }
216 delete bitmap;
217 }
218 RTMemFree(pBmp);
219 }
220 free(pv);
221 }
222 }
223
224 /*
225 * Make sure we don't bounce this data back to the host, it's impolite. It can also
226 * be used as a hint to applications probably.
227 */
228 clip->AddBool("FromVirtualBoxHost", true);
229 if (commit)
230 be_clipboard->Commit();
231 be_clipboard->Unlock();
232 break;
233 }
234
235 case VBOX_GUEST_CLIPBOARD_HOST_MSG_READ_DATA:
236 {
237 int rc;
238
239 if (message->FindInt32("Formats", (int32 *)&formats) != B_OK)
240 break;
241
242 if (!formats)
243 break;
244 if (!be_clipboard->Lock())
245 break;
246
247 BMessage *clip = be_clipboard->Data();
248 if (!clip)
249 {
250 be_clipboard->Unlock();
251 break;
252 }
253 clip->PrintToStream();
254
255 if (formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
256 {
257 const char *text;
258 int32 textLen;
259 if (clip->FindData("text/plain", B_MIME_TYPE, (const void **)&text, &textLen) == B_OK)
260 {
261 // usually doesn't include the \0 so be safe
262 BString str(text, textLen);
263 // convert from LF to Windows CRLF
264 str.ReplaceAll("\n", "\r\n");
265 PRTUTF16 pwsz;
266 rc = RTStrToUtf16(str.String(), &pwsz);
267 if (RT_SUCCESS(rc))
268 {
269 uint32_t cb = (RTUtf16Len(pwsz) + 1) * sizeof(RTUTF16);
270
271 rc = VbglR3ClipboardWriteData(fClientId, VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, pwsz, cb);
272 //printf("VbglR3ClipboardWriteData: %d\n", rc);
273 RTUtf16Free(pwsz);
274 }
275 }
276 }
277 else if (formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
278 {
279 BMessage archivedBitmap;
280 if (clip->FindMessage("image/bitmap", &archivedBitmap) == B_OK ||
281 clip->FindMessage("image/x-be-bitmap", &archivedBitmap) == B_OK)
282 {
283 BBitmap *bitmap = new(std::nothrow) BBitmap(&archivedBitmap);
284 if (bitmap)
285 {
286 // Don't delete bitmap, BBitmapStream will.
287 BBitmapStream stream(bitmap);
288 BTranslatorRoster *roster = BTranslatorRoster::Default();
289 if (roster && bitmap->IsValid())
290 {
291 BMallocIO bmpStream;
292 if (roster->Translate(&stream, NULL, NULL, &bmpStream, B_BMP_FORMAT) == B_OK)
293 {
294 const void *pDib;
295 size_t cbDibSize;
296 /* Strip out the BM header */
297 rc = vboxClipboardBmpGetDib(bmpStream.Buffer(), bmpStream.BufferLength(), &pDib, &cbDibSize);
298 if (RT_SUCCESS(rc))
299 {
300 rc = VbglR3ClipboardWriteData(fClientId, VBOX_SHARED_CLIPBOARD_FMT_BITMAP, (void *)pDib,
301 cbDibSize);
302 }
303 }
304 }
305 }
306 }
307 }
308
309 be_clipboard->Unlock();
310 break;
311 }
312
313 case B_CLIPBOARD_CHANGED:
314 {
315 printf("B_CLIPBOARD_CHANGED\n");
316 const void *data;
317 int32 dataLen;
318 if (!be_clipboard->Lock())
319 break;
320
321 BMessage *clip = be_clipboard->Data();
322 if (!clip)
323 {
324 be_clipboard->Unlock();
325 break;
326 }
327
328 bool fromVBox;
329 if (clip->FindBool("FromVirtualBoxHost", &fromVBox) == B_OK && fromVBox)
330 {
331 // It already comes from the host, discard.
332 be_clipboard->Unlock();
333 break;
334 }
335
336 if (clip->FindData("text/plain", B_MIME_TYPE, &data, &dataLen) == B_OK)
337 formats |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
338
339 if ( clip->HasMessage("image/bitmap")
340 || clip->HasMessage("image/x-be-bitmap"))
341 {
342 formats |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
343 }
344
345 be_clipboard->Unlock();
346
347 VbglR3ClipboardReportFormats(fClientId, formats);
348 break;
349 }
350
351 case B_QUIT_REQUESTED:
352 fExiting = true;
353 break;
354
355 default:
356 BHandler::MessageReceived(message);
357 }
358}
359
360
361status_t VBoxClipboardService::_ServiceThreadNub(void *_this)
362{
363 VBoxClipboardService *service = (VBoxClipboardService *)_this;
364 return service->_ServiceThread();
365}
366
367
368status_t VBoxClipboardService::_ServiceThread()
369{
370 printf("VBoxClipboardService::%s()\n", __FUNCTION__);
371
372 /* The thread waits for incoming messages from the host. */
373 for (;;)
374 {
375 uint32_t u32Msg;
376 uint32_t u32Formats;
377 int rc = VbglR3ClipboardGetHostMsg(fClientId, &u32Msg, &u32Formats);
378 if (RT_SUCCESS(rc))
379 {
380 switch (u32Msg)
381 {
382 case VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS:
383 {
384 /*
385 * The host has announced available clipboard formats. Forward
386 * the information to the handler.
387 */
388 LogRelFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS u32Formats=%x\n", u32Formats));
389 BMessage msg(VBOX_GUEST_CLIPBOARD_HOST_MSG_FORMATS);
390 msg.AddInt32("Formats", (uint32)u32Formats);
391 Looper()->PostMessage(&msg, this);
392 break;
393 }
394
395 case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA:
396 {
397 /* The host needs data in the specified format. */
398 LogRelFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA u32Formats=%x\n", u32Formats));
399 BMessage msg(VBOX_GUEST_CLIPBOARD_HOST_MSG_READ_DATA);
400 msg.AddInt32("Formats", (uint32)u32Formats);
401 Looper()->PostMessage(&msg, this);
402 break;
403 }
404
405 case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT:
406 {
407 /* The host is terminating. */
408 LogRelFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT\n"));
409 fExiting = true;
410 return VERR_INTERRUPTED;
411 }
412
413 default:
414 Log(("VBoxClipboardService::%s: Unsupported message from host! Message = %u\n", __FUNCTION__, u32Msg));
415 }
416 }
417 else
418 fExiting = true;
419
420 LogRelFlow(("processed host event rc = %d\n", rc));
421
422 if (fExiting)
423 break;
424 }
425 return 0;
426}
427
428
429void* VBoxClipboardService::_VBoxReadHostClipboard(uint32_t format, uint32_t *pcb)
430{
431 uint32_t cb = 1024;
432 void *pv;
433 int rc;
434
435 pv = malloc(cb);
436 if (pv == NULL)
437 return NULL;
438
439 rc = VbglR3ClipboardReadData(fClientId, format, pv, cb, pcb);
440 if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW))
441 return pv;
442 if (rc == VINF_BUFFER_OVERFLOW)
443 {
444 free(pv);
445 cb = *pcb;
446 pv = malloc(cb);
447 if (pv == NULL)
448 return NULL;
449
450 rc = VbglR3ClipboardReadData(fClientId, format, pv, cb, pcb);
451 if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW))
452 return pv;
453
454 free(pv);
455 }
456 return NULL;
457}
458
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette