VirtualBox

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

Last change on this file since 106061 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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