VirtualBox

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

Last change on this file since 43364 was 43364, checked in by vboxsync, 13 years ago

Haiku Additions: cleanup.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.3 KB
Line 
1/* $Id: VBoxClipboard.cpp 43364 2012-09-20 12:12:09Z vboxsync $ */
2/** @file
3 * VBoxClipboard; Haiku Guest Additions, implementation.
4 */
5
6/*
7 * Copyright (C) 2012 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 <mike@scgtrp.net>
23 * François Revol <revol@free.fr>
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#undef Log
70#define Log(x) printf x
71#undef LogRel
72#define LogRel(x) printf x
73#undef LogRelFlowFunc
74#define LogRelFlowFunc(x) printf x
75
76
77VBoxClipboardService::VBoxClipboardService()
78 : BHandler("VBoxClipboardService"),
79 fClientId(-1),
80 fServiceThreadID(-1),
81 fExiting(false)
82{
83}
84
85
86VBoxClipboardService::~VBoxClipboardService()
87{
88}
89
90
91status_t VBoxClipboardService::Connect()
92{
93 status_t err;
94 printf("VBoxClipboardService::%s()\n", __FUNCTION__);
95
96 int rc = VbglR3ClipboardConnect(&fClientId);
97 if (RT_SUCCESS(rc))
98 {
99 err = fServiceThreadID = spawn_thread(_ServiceThreadNub,
100 "VBoxClipboardService", B_NORMAL_PRIORITY, this);
101
102 if (err >= B_OK)
103 {
104 resume_thread(fServiceThreadID);
105
106 err = be_clipboard->StartWatching(BMessenger(this));
107 printf("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 if (!be_clipboard->Lock())
159 break;
160
161 be_clipboard->Clear();
162 BMessage *clip = be_clipboard->Data();
163 if (!clip)
164 {
165 be_clipboard->Unlock();
166 break;
167 }
168
169 if (formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
170 {
171 pv = _VBoxReadHostClipboard(VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, &cb);
172 if (pv)
173 {
174 char *text;
175 rc = RTUtf16ToUtf8((PCRTUTF16)pv, &text);
176 if (RT_SUCCESS(rc))
177 {
178 BString str(text);
179 // @todo use vboxClipboardUtf16WinToLin()
180 // convert Windows CRLF to LF
181 str.ReplaceAll("\r\n", "\n");
182 // don't include the \0
183 clip->AddData("text/plain", B_MIME_TYPE, str.String(), str.Length());
184 RTStrFree(text);
185 commit = true;
186 }
187 free(pv);
188 }
189 }
190
191 if (formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
192 {
193 pv = _VBoxReadHostClipboard(VBOX_SHARED_CLIPBOARD_FMT_BITMAP, &cb);
194 if (pv)
195 {
196 void *pBmp;
197 size_t cbBmp;
198 rc = vboxClipboardDibToBmp(pv, cb, &pBmp, &cbBmp);
199 if (RT_SUCCESS(rc))
200 {
201 BMemoryIO mio(pBmp, cbBmp);
202 BBitmap *bitmap = BTranslationUtils::GetBitmap(&mio);
203 if (bitmap)
204 {
205 BMessage bitmapArchive;
206 if (bitmap->IsValid() &&
207 bitmap->Archive(&bitmapArchive) == B_OK &&
208 clip->AddMessage("image/bitmap", &bitmapArchive) == B_OK)
209 {
210 commit = true;
211 }
212 delete bitmap;
213 }
214 RTMemFree(pBmp);
215 }
216 free(pv);
217 }
218 }
219
220 /* make sure we don't bounce this data back to the host,
221 * it's impolite.
222 * It can also be used as a hint to applications probably. */
223 clip->AddBool("FromVirtualBoxHost", true);
224
225 if (commit)
226 be_clipboard->Commit();
227 be_clipboard->Unlock();
228 break;
229 }
230
231 case VBOX_GUEST_CLIPBOARD_HOST_MSG_READ_DATA:
232 {
233 int rc;
234
235 if (message->FindInt32("Formats", (int32 *)&formats) != B_OK)
236 break;
237
238 if (!formats)
239 break;
240 if (!be_clipboard->Lock())
241 break;
242
243 BMessage *clip = be_clipboard->Data();
244 if (!clip)
245 {
246 be_clipboard->Unlock();
247 break;
248 }
249 clip->PrintToStream();
250
251 if (formats & VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT)
252 {
253 const char *text;
254 int32 textLen;
255 if (clip->FindData("text/plain", B_MIME_TYPE, (const void **)&text, &textLen) == B_OK)
256 {
257 // usually doesn't include the \0 so be safe
258 BString str(text, textLen);
259 // convert from LF to Windows CRLF
260 str.ReplaceAll("\n", "\r\n");
261 PRTUTF16 pwsz;
262 rc = RTStrToUtf16(str.String(), &pwsz);
263 if (RT_SUCCESS(rc))
264 {
265 uint32_t cb = (RTUtf16Len(pwsz) + 1) * sizeof(RTUTF16);
266
267 rc = VbglR3ClipboardWriteData(fClientId,
268 VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT, pwsz, cb);
269 //printf("VbglR3ClipboardWriteData: %d\n", rc);
270
271 RTUtf16Free(pwsz);
272 }
273 }
274 }
275 else if (formats & VBOX_SHARED_CLIPBOARD_FMT_BITMAP)
276 {
277 BMessage archivedBitmap;
278 if (clip->FindMessage("image/bitmap", &archivedBitmap) == B_OK ||
279 clip->FindMessage("image/x-be-bitmap", &archivedBitmap) == B_OK)
280 {
281 BBitmap *bitmap = new(std::nothrow) BBitmap(&archivedBitmap);
282 if (bitmap)
283 {
284 // Don't delete bitmap, BBitmapStream will.
285 BBitmapStream stream(bitmap);
286 BTranslatorRoster *roster = BTranslatorRoster::Default();
287 if (roster && bitmap->IsValid())
288 {
289 BMallocIO bmpStream;
290 if (roster->Translate(&stream, NULL, NULL, &bmpStream, B_BMP_FORMAT) == B_OK)
291 {
292 const void *pDib;
293 size_t cbDibSize;
294 /* Strip out the BM header */
295 rc = vboxClipboardBmpGetDib(bmpStream.Buffer(), bmpStream.BufferLength(), &pDib, &cbDibSize);
296 if (RT_SUCCESS(rc))
297 {
298 rc = VbglR3ClipboardWriteData(fClientId,
299 VBOX_SHARED_CLIPBOARD_FMT_BITMAP, (void *)pDib, cbDibSize);
300 }
301 }
302 }
303 }
304 }
305 }
306
307 be_clipboard->Unlock();
308 break;
309 }
310
311 case B_CLIPBOARD_CHANGED:
312 {
313 printf("B_CLIPBOARD_CHANGED\n");
314 const void *data;
315 int32 dataLen;
316 if (!be_clipboard->Lock())
317 break;
318
319 BMessage *clip = be_clipboard->Data();
320 if (!clip)
321 {
322 be_clipboard->Unlock();
323 break;
324 }
325
326 bool fromVBox;
327 if (clip->FindBool("FromVirtualBoxHost", &fromVBox) == B_OK && fromVBox)
328 {
329 // It already comes from the host, discard.
330 be_clipboard->Unlock();
331 break;
332 }
333
334 if (clip->FindData("text/plain", B_MIME_TYPE, &data, &dataLen) == B_OK)
335 formats |= VBOX_SHARED_CLIPBOARD_FMT_UNICODETEXT;
336 if (clip->HasMessage("image/bitmap") || clip->HasMessage("image/x-be-bitmap"))
337 formats |= VBOX_SHARED_CLIPBOARD_FMT_BITMAP;
338
339 be_clipboard->Unlock();
340
341 VbglR3ClipboardReportFormats(fClientId, formats);
342 break;
343 }
344
345 case B_QUIT_REQUESTED:
346 fExiting = true;
347 break;
348
349 default:
350 BHandler::MessageReceived(message);
351 }
352}
353
354
355status_t VBoxClipboardService::_ServiceThreadNub(void *_this)
356{
357 VBoxClipboardService *service = (VBoxClipboardService *)_this;
358 return service->_ServiceThread();
359}
360
361
362status_t VBoxClipboardService::_ServiceThread()
363{
364 printf("VBoxClipboardService::%s()\n", __FUNCTION__);
365
366 /* The thread waits for incoming messages from the host. */
367 for (;;)
368 {
369 uint32_t u32Msg;
370 uint32_t u32Formats;
371 int rc = VbglR3ClipboardGetHostMsg(fClientId, &u32Msg, &u32Formats);
372 if (RT_SUCCESS(rc))
373 {
374 switch (u32Msg)
375 {
376 case VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS:
377 {
378 /* The host has announced available clipboard formats.
379 * Forward the information to the handler. */
380 LogRelFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS u32Formats=%x\n", u32Formats));
381 BMessage msg(VBOX_GUEST_CLIPBOARD_HOST_MSG_FORMATS);
382 msg.AddInt32("Formats", (uint32)u32Formats);
383 Looper()->PostMessage(&msg, this);
384 break;
385 }
386
387 case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA:
388 {
389 /* The host needs data in the specified format. */
390 LogRelFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA u32Formats=%x\n", u32Formats));
391 BMessage msg(VBOX_GUEST_CLIPBOARD_HOST_MSG_READ_DATA);
392 msg.AddInt32("Formats", (uint32)u32Formats);
393 Looper()->PostMessage(&msg, this);
394 break;
395 }
396
397 case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT:
398 {
399 /* The host is terminating. */
400 LogRelFlowFunc(("VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT\n"));
401 fExiting = true;
402 return VERR_INTERRUPTED;
403 }
404
405 default:
406 Log(("VBoxClipboardService::%s: Unsupported message from host! Message = %u\n", __FUNCTION__, u32Msg));
407 }
408 }
409 else
410 fExiting = true;
411
412 LogRelFlow(("processed host event rc = %d\n", rc));
413
414 if (fExiting)
415 break;
416 }
417 return 0;
418}
419
420
421void* VBoxClipboardService::_VBoxReadHostClipboard(uint32_t format, uint32_t *pcb)
422{
423 uint32_t cb = 1024;
424 void *pv;
425 int rc;
426
427 pv = malloc(cb);
428 if (pv == NULL)
429 return NULL;
430
431 rc = VbglR3ClipboardReadData(fClientId, format, pv, cb, pcb);
432 if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW))
433 return pv;
434 if (rc == VINF_BUFFER_OVERFLOW)
435 {
436 free(pv);
437 cb = *pcb;
438 pv = malloc(cb);
439 if (pv == NULL)
440 return NULL;
441
442 rc = VbglR3ClipboardReadData(fClientId, format, pv, cb, pcb);
443 if (RT_SUCCESS(rc) && (rc != VINF_BUFFER_OVERFLOW))
444 return pv;
445
446 free(pv);
447 }
448 return NULL;
449}
450
Note: See TracBrowser for help on using the repository browser.

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