1 |
|
/* |
2 |
|
* clip_unix.cpp - Clipboard handling, Unix implementation |
3 |
|
* |
4 |
< |
* SheepShaver (C) 1997-2003 Christian Bauer and Marc Hellwig |
4 |
> |
* SheepShaver (C) 1997-2004 Christian Bauer and Marc Hellwig |
5 |
|
* |
6 |
|
* This program is free software; you can redistribute it and/or modify |
7 |
|
* it under the terms of the GNU General Public License as published by |
45 |
|
* For safety purposes, we lock the X11 display in the emulator |
46 |
|
* thread during the whole GetScrap/PutScrap execution. Of course, we |
47 |
|
* temporarily release the lock when waiting for SelectioNotify. |
48 |
+ |
* |
49 |
+ |
* TODO: |
50 |
+ |
* - handle 'PICT' to image/png, image/ppm, PIXMAP (prefs order) |
51 |
+ |
* - handle 'styl' to text/richtext (OOo Writer) |
52 |
+ |
* - patch ZeroScrap so that we know when cached 'styl' is stale? |
53 |
|
*/ |
54 |
|
|
55 |
|
#include "sysdeps.h" |
74 |
|
#endif |
75 |
|
|
76 |
|
|
72 |
– |
// Do we replace PutScrap()? |
73 |
– |
#define REPLACE_PUTSCRAP 1 |
74 |
– |
|
75 |
– |
// Do we replace GetScrap()? |
76 |
– |
#define REPLACE_GETSCRAP 1 |
77 |
– |
|
78 |
– |
// Do we want PutScrap() to ignore requests from klipper? |
79 |
– |
#define PUTSCRAP_IGNORES_KLIPPER 0 |
80 |
– |
|
77 |
|
// Do we want GetScrap() to check for TIMESTAMP and optimize out clipboard syncs? |
78 |
|
#define GETSCRAP_REQUESTS_TIMESTAMP 0 |
79 |
|
|
127 |
|
// Flag: Don't convert clipboard text |
128 |
|
static bool no_clip_conversion; |
129 |
|
|
130 |
< |
// Flag for PutScrap(): the data was put by GetScrap(), don't bounce it back to the Be side |
130 |
> |
// Flag for PutScrap(): the data was put by GetScrap(), don't bounce it back to the Unix side |
131 |
|
static bool we_put_this_data = false; |
132 |
|
|
133 |
|
// X11 variables |
142 |
|
// Define a byte array (rewrite if it's a bottleneck) |
143 |
|
struct ByteArray : public vector<uint8> { |
144 |
|
void resize(int size) { reserve(size); vector<uint8>::resize(size); } |
145 |
< |
uint8 *data() { return &at(0); } |
145 |
> |
uint8 *data() { return &(*this)[0]; } |
146 |
|
}; |
147 |
|
|
148 |
|
// Clipboard data for requestors |
266 |
|
|
267 |
|
|
268 |
|
/* |
273 |
– |
* Check for a "klipper" window which, in older versions (3.1), was |
274 |
– |
* polling and retrieving clipboard data several times per second. |
275 |
– |
*/ |
276 |
– |
|
277 |
– |
static bool is_klipper_window_probe(Window w); |
278 |
– |
static bool is_klipper_window_check(Window w); |
279 |
– |
static bool (*is_klipper_window)(Window w) = is_klipper_window_probe; |
280 |
– |
static Window klipper_win = None; |
281 |
– |
|
282 |
– |
static bool is_klipper_window_probe(Window w) |
283 |
– |
{ |
284 |
– |
// We expect "klipper" to be within the first clients to request |
285 |
– |
// data from our clipboard |
286 |
– |
static int clients_countdown = 2; |
287 |
– |
|
288 |
– |
bool found = false; |
289 |
– |
char *window_name; |
290 |
– |
if (XFetchName(x_display, w, &window_name) && !strcmp(window_name, "klipper")) { |
291 |
– |
D(bug(" found and ignore clipboard requests from klipper window id: 0x%08x\n", w)); |
292 |
– |
klipper_win = w; |
293 |
– |
found = true; |
294 |
– |
} |
295 |
– |
|
296 |
– |
if (found || --clients_countdown <= 0) |
297 |
– |
is_klipper_window = is_klipper_window_check; |
298 |
– |
} |
299 |
– |
|
300 |
– |
static bool is_klipper_window_check(Window w) |
301 |
– |
{ |
302 |
– |
return w == klipper_win; |
303 |
– |
} |
304 |
– |
|
305 |
– |
|
306 |
– |
/* |
269 |
|
* Initialization |
270 |
|
*/ |
271 |
|
|
307 |
|
void PutScrap(uint32 type, void *scrap, int32 length) |
308 |
|
{ |
309 |
|
D(bug("PutScrap type %08lx, data %p, length %ld\n", type, scrap, length)); |
348 |
– |
if (!REPLACE_PUTSCRAP) |
349 |
– |
return; |
310 |
|
if (we_put_this_data) { |
311 |
|
we_put_this_data = false; |
312 |
|
return; |
323 |
|
{ |
324 |
|
clip_data.type = None; |
325 |
|
switch (type) { |
326 |
< |
case FOURCC('T','E','X','T'): |
326 |
> |
case FOURCC('T','E','X','T'): { |
327 |
|
D(bug(" clipping TEXT\n")); |
328 |
|
clip_data.type = XA_STRING; |
329 |
|
clip_data.data.clear(); |
343 |
|
break; |
344 |
|
} |
345 |
|
|
346 |
+ |
case FOURCC('s','t','y','l'): { |
347 |
+ |
D(bug(" clipping styl\n")); |
348 |
+ |
uint16 *p = (uint16 *)scrap; |
349 |
+ |
uint16 n = ntohs(*p++); |
350 |
+ |
D(bug(" %d styles (%d bytes)\n", n, length)); |
351 |
+ |
for (int i = 0; i < n; i++) { |
352 |
+ |
uint32 offset = ntohl(*(uint32 *)p); p += 2; |
353 |
+ |
uint16 line_height = ntohs(*p++); |
354 |
+ |
uint16 font_ascent = ntohs(*p++); |
355 |
+ |
uint16 font_family = ntohs(*p++); |
356 |
+ |
uint16 style_code = ntohs(*p++); |
357 |
+ |
uint16 char_size = ntohs(*p++); |
358 |
+ |
uint16 r = ntohs(*p++); |
359 |
+ |
uint16 g = ntohs(*p++); |
360 |
+ |
uint16 b = ntohs(*p++); |
361 |
+ |
D(bug(" offset=%d, height=%d, font ascent=%d, id=%d, style=%x, size=%d, RGB=%x/%x/%x\n", |
362 |
+ |
offset, line_height, font_ascent, font_family, style_code, char_size, r, g, b)); |
363 |
+ |
} |
364 |
+ |
break; |
365 |
+ |
} |
366 |
+ |
} |
367 |
+ |
|
368 |
|
// Acquire selection ownership |
369 |
|
if (clip_data.type != None) { |
370 |
|
clip_data.time = CurrentTime; |
381 |
|
void GetScrap(void **handle, uint32 type, int32 offset) |
382 |
|
{ |
383 |
|
D(bug("GetScrap handle %p, type %08x, offset %d\n", handle, type, offset)); |
402 |
– |
if (!REPLACE_GETSCRAP) |
403 |
– |
return; |
384 |
|
|
385 |
|
XDisplayLock(); |
386 |
|
do_getscrap(handle, type, offset); |
430 |
|
long *atoms = (long *)data.data(); |
431 |
|
for (int i = 0; i < n_atoms; i++) { |
432 |
|
Atom target = atoms[i]; |
433 |
+ |
D(bug(" target %08x (%s)\n", target, XGetAtomName(x_display, target))); |
434 |
|
switch (type) { |
435 |
|
case FOURCC('T','E','X','T'): |
436 |
|
D(bug(" clipping TEXT\n")); |
487 |
|
} |
488 |
|
|
489 |
|
// Add new data to clipboard |
490 |
< |
static uint8 proc[] = { |
491 |
< |
0x59, 0x8f, // subq.l #4,sp |
492 |
< |
0xa9, 0xfc, // ZeroScrap() |
493 |
< |
0x2f, 0x3c, 0, 0, 0, 0, // move.l #length,-(sp) |
494 |
< |
0x2f, 0x3c, 0, 0, 0, 0, // move.l #type,-(sp) |
495 |
< |
0x2f, 0x3c, 0, 0, 0, 0, // move.l #outbuf,-(sp) |
496 |
< |
0xa9, 0xfe, // PutScrap() |
497 |
< |
0x58, 0x8f, // addq.l #4,sp |
498 |
< |
M68K_RTS >> 8, M68K_RTS |
490 |
> |
static uint16 proc[] = { |
491 |
> |
PW(0x598f), // subq.l #4,sp |
492 |
> |
PW(0xa9fc), // ZeroScrap() |
493 |
> |
PW(0x2f3c), 0, 0, // move.l #length,-(sp) |
494 |
> |
PW(0x2f3c), 0, 0, // move.l #type,-(sp) |
495 |
> |
PW(0x2f3c), 0, 0, // move.l #outbuf,-(sp) |
496 |
> |
PW(0xa9fe), // PutScrap() |
497 |
> |
PW(0x588f), // addq.l #4,sp |
498 |
> |
PW(M68K_RTS) |
499 |
|
}; |
500 |
< |
uint32 proc_area = (uint32)proc; // FIXME: make sure 32-bit relocs are used |
500 |
> |
uint32 proc_area = (uint32)proc; |
501 |
|
WriteMacInt32(proc_area + 6, data.size()); |
502 |
|
WriteMacInt32(proc_area + 12, type); |
503 |
|
WriteMacInt32(proc_area + 18, scrap_area); |
556 |
|
// Change requestor property |
557 |
|
XChangeProperty(x_display, req->requestor, req->property, |
558 |
|
xa_targets, 32, |
559 |
< |
PropModeReplace, (uint8 *)&targets.at(0), targets.size()); |
559 |
> |
PropModeReplace, (uint8 *)&targets[0], targets.size()); |
560 |
|
|
561 |
|
return true; |
562 |
|
} |
658 |
|
if (req->requestor == clip_win || req->selection != xa_clipboard) |
659 |
|
return; |
660 |
|
|
680 |
– |
#if PUTSCRAP_IGNORES_KLIPPER |
681 |
– |
if (is_klipper_window(req->requestor)) |
682 |
– |
return; |
683 |
– |
#endif |
684 |
– |
|
661 |
|
D(bug("Selection requested from 0x%lx to 0x%lx (%s) 0x%lx (%s)\n", |
662 |
|
req->requestor, |
663 |
|
req->selection, |