XQuartz: pbproxy: Add COMPOUND_TEXT handling. Do misc. cleanups with testing
to verify that the behavior didn't change.
main.m: XInternAtom compound_text, and atom_pair.
pbproxy.h: Add compound_text and atom_pair to the struct atom_list.
x-selection.m: Add an #include of Xutil.h. Refactor the reply struct
initialization to be done in a common place. Add send_reply: to simplify
the code a bit more. Add send_compound_text: which handles the
COMPOUND_TEXT type. Add the beginnings of a send_multiple:. Change
handle_image:extension: to handle_image:. The extension: message isn't
needed anymore.
(cherry picked from commit 1e9460abdf
)
This commit is contained in:
parent
00bfbee59f
commit
749bdf19b2
|
@ -77,6 +77,8 @@ static void x_init (void) {
|
||||||
atoms->incr = XInternAtom (x_dpy, "INCR", False);
|
atoms->incr = XInternAtom (x_dpy, "INCR", False);
|
||||||
atoms->atom = XInternAtom (x_dpy, "ATOM", False);
|
atoms->atom = XInternAtom (x_dpy, "ATOM", False);
|
||||||
atoms->clipboard_manager = XInternAtom (x_dpy, "CLIPBOARD_MANAGER", False);
|
atoms->clipboard_manager = XInternAtom (x_dpy, "CLIPBOARD_MANAGER", False);
|
||||||
|
atoms->compound_text = XInternAtom (x_dpy, "COMPOUND_TEXT", False);
|
||||||
|
atoms->atom_pair = XInternAtom (x_dpy, "ATOM_PAIR", False);
|
||||||
|
|
||||||
if (!XAppleWMQueryExtension (x_dpy, &x_apple_wm_event_base,
|
if (!XAppleWMQueryExtension (x_dpy, &x_apple_wm_event_base,
|
||||||
&x_apple_wm_error_base)) {
|
&x_apple_wm_error_base)) {
|
||||||
|
|
|
@ -25,7 +25,8 @@ extern int x_apple_wm_event_base, x_apple_wm_error_base;
|
||||||
|
|
||||||
struct atom_list {
|
struct atom_list {
|
||||||
Atom primary, clipboard, text, utf8_string, string, targets, multiple,
|
Atom primary, clipboard, text, utf8_string, string, targets, multiple,
|
||||||
cstring, image_png, image_jpeg, incr, atom, clipboard_manager;
|
cstring, image_png, image_jpeg, incr, atom, clipboard_manager,
|
||||||
|
compound_text, atom_pair;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct atom_list *atoms;
|
extern struct atom_list *atoms;
|
||||||
|
|
|
@ -338,6 +338,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
|
||||||
#if 0
|
#if 0
|
||||||
if ([_pasteboard changeCount] != _my_last_change)
|
if ([_pasteboard changeCount] != _my_last_change)
|
||||||
{
|
{
|
||||||
|
/*gstaplin: we should perhaps investigate something like this branch above...*/
|
||||||
if ([_pasteboard availableTypeFromArray: _known_types] != nil)
|
if ([_pasteboard availableTypeFromArray: _known_types] != nil)
|
||||||
{
|
{
|
||||||
/* Pasteboard has data we should proxy; I think it makes
|
/* Pasteboard has data we should proxy; I think it makes
|
||||||
|
@ -493,6 +494,25 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
|
||||||
atoms->clipboard));
|
atoms->clipboard));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) init_reply:(XEvent *)reply request:(XSelectionRequestEvent *)e
|
||||||
|
{
|
||||||
|
reply->xselection.type = SelectionNotify;
|
||||||
|
reply->xselection.selection = e->selection;
|
||||||
|
reply->xselection.target = e->target;
|
||||||
|
reply->xselection.requestor = e->requestor;
|
||||||
|
reply->xselection.time = e->time;
|
||||||
|
reply->xselection.property = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) send_reply:(XEvent *)reply
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We are supposed to use an empty event mask, and not propagate
|
||||||
|
* the event, according to the ICCCM.
|
||||||
|
*/
|
||||||
|
XSendEvent (x_dpy, reply->xselection.requestor, False, 0, reply);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This responds to a TARGETS request.
|
* This responds to a TARGETS request.
|
||||||
* The result is a list of a ATOMs that correspond to the types available
|
* The result is a list of a ATOMs that correspond to the types available
|
||||||
|
@ -506,27 +526,24 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
|
||||||
XEvent reply;
|
XEvent reply;
|
||||||
NSArray *pbtypes;
|
NSArray *pbtypes;
|
||||||
|
|
||||||
reply.xselection.type = SelectionNotify;
|
[self init_reply:&reply request:e];
|
||||||
reply.xselection.selection = e->selection;
|
|
||||||
reply.xselection.target = e->target;
|
|
||||||
reply.xselection.requestor = e->requestor;
|
|
||||||
reply.xselection.time = e->time;
|
|
||||||
reply.xselection.property = None;
|
|
||||||
|
|
||||||
pbtypes = [_pasteboard types];
|
pbtypes = [_pasteboard types];
|
||||||
if (pbtypes)
|
if (pbtypes)
|
||||||
{
|
{
|
||||||
long list[5];
|
long list[6];
|
||||||
long count = 0;
|
long count = 0;
|
||||||
|
|
||||||
if ([pbtypes containsObject:NSStringPboardType])
|
if ([pbtypes containsObject:NSStringPboardType])
|
||||||
{
|
{
|
||||||
/* We have a string type that we can convert to a UTF8 or Latin-1 string. */
|
/* We have a string type that we can convert to UTF8, or Latin-1... */
|
||||||
DB ("NSStringPboardType\n");
|
DB ("NSStringPboardType\n");
|
||||||
list[count] = atoms->utf8_string;
|
list[count] = atoms->utf8_string;
|
||||||
++count;
|
++count;
|
||||||
list[count] = atoms->string;
|
list[count] = atoms->string;
|
||||||
++count;
|
++count;
|
||||||
|
list[count] = atoms->compound_text;
|
||||||
|
++count;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([pbtypes containsObject:NSTIFFPboardType]
|
if ([pbtypes containsObject:NSTIFFPboardType]
|
||||||
|
@ -540,7 +557,6 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
|
||||||
++count;
|
++count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (count)
|
if (count)
|
||||||
{
|
{
|
||||||
/* We have a list of ATOMs to send. */
|
/* We have a list of ATOMs to send. */
|
||||||
|
@ -551,46 +567,10 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
[self send_reply:&reply];
|
||||||
* We are supposed to use an empty event mask, and not propagate
|
|
||||||
* the event, according to the ICCCM.
|
|
||||||
*/
|
|
||||||
XSendEvent (x_dpy, e->requestor, False, 0, &reply);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*TODO finish this - it's flawed. */
|
|
||||||
- (void) send_multiple:(XSelectionRequestEvent *)e
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
XEvent reply;
|
|
||||||
int i, nitems;
|
|
||||||
unsigned long *atoms;
|
|
||||||
|
|
||||||
if (None == e->property)
|
|
||||||
return;
|
|
||||||
|
|
||||||
atoms = read_prop_32 (e->requestor, e->property, &nitems);
|
|
||||||
|
|
||||||
if (atoms != NULL)
|
|
||||||
{
|
|
||||||
data = [_pasteboard stringForType:NSStringPboardType];
|
|
||||||
|
|
||||||
for (i = 0; i < nitems; i += 2)
|
|
||||||
{
|
|
||||||
Atom target = atoms[i], prop = atoms[i+1];
|
|
||||||
|
|
||||||
atoms[i+1] = convert_1 (e, data, target, prop);
|
|
||||||
}
|
|
||||||
|
|
||||||
XChangeProperty (x_dpy, e->requestor, e->property, target,
|
|
||||||
32, PropModeReplace, (unsigned char *) atoms,
|
|
||||||
nitems);
|
|
||||||
XFree (atoms);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) send_string:(XSelectionRequestEvent *)e utf8:(BOOL)utf8
|
- (void) send_string:(XSelectionRequestEvent *)e utf8:(BOOL)utf8
|
||||||
{
|
{
|
||||||
XEvent reply;
|
XEvent reply;
|
||||||
|
@ -598,12 +578,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
|
||||||
|
|
||||||
TRACE ();
|
TRACE ();
|
||||||
|
|
||||||
reply.xselection.type = SelectionNotify;
|
[self init_reply:&reply request:e];
|
||||||
reply.xselection.selection = e->selection;
|
|
||||||
reply.xselection.target = e->target;
|
|
||||||
reply.xselection.requestor = e->requestor;
|
|
||||||
reply.xselection.time = e->time;
|
|
||||||
reply.xselection.property = None;
|
|
||||||
|
|
||||||
pbtypes = [_pasteboard types];
|
pbtypes = [_pasteboard types];
|
||||||
|
|
||||||
|
@ -615,7 +590,8 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
|
||||||
const char *bytes;
|
const char *bytes;
|
||||||
NSUInteger length;
|
NSUInteger length;
|
||||||
|
|
||||||
if (utf8) {
|
if (utf8)
|
||||||
|
{
|
||||||
bytes = [data UTF8String];
|
bytes = [data UTF8String];
|
||||||
/*
|
/*
|
||||||
* We don't want the UTF-8 string length here.
|
* We don't want the UTF-8 string length here.
|
||||||
|
@ -623,7 +599,9 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
|
||||||
*/
|
*/
|
||||||
length = [data lengthOfBytesUsingEncoding:NSASCIIStringEncoding];
|
length = [data lengthOfBytesUsingEncoding:NSASCIIStringEncoding];
|
||||||
DB ("UTF-8\n");
|
DB ("UTF-8\n");
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
DB ("Latin-1\n");
|
DB ("Latin-1\n");
|
||||||
bytes = [data cStringUsingEncoding:NSISOLatin1StringEncoding];
|
bytes = [data cStringUsingEncoding:NSISOLatin1StringEncoding];
|
||||||
length = [data lengthOfBytesUsingEncoding:NSASCIIStringEncoding];
|
length = [data lengthOfBytesUsingEncoding:NSASCIIStringEncoding];
|
||||||
|
@ -638,10 +616,77 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Always send a response, even if the property value is None. */
|
[self send_reply:&reply];
|
||||||
XSendEvent (x_dpy, e->requestor, False, 0, &reply);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) send_compound_text:(XSelectionRequestEvent *)e
|
||||||
|
{
|
||||||
|
XEvent reply;
|
||||||
|
NSArray *pbtypes;
|
||||||
|
|
||||||
|
TRACE ();
|
||||||
|
|
||||||
|
[self init_reply:&reply request:e];
|
||||||
|
|
||||||
|
pbtypes = [_pasteboard types];
|
||||||
|
|
||||||
|
if ([pbtypes containsObject: NSStringPboardType])
|
||||||
|
{
|
||||||
|
NSString *data = [_pasteboard stringForType:NSStringPboardType];
|
||||||
|
if (nil != data)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Cast to (void *) to avoid a const warning.
|
||||||
|
* AFAIK Xutf8TextListToTextProperty does not modify the input memory.
|
||||||
|
*/
|
||||||
|
void *utf8 = (void *)[data UTF8String];
|
||||||
|
char *list[] = { utf8, NULL };
|
||||||
|
XTextProperty textprop;
|
||||||
|
|
||||||
|
textprop.value = NULL;
|
||||||
|
|
||||||
|
if (Success == Xutf8TextListToTextProperty (x_dpy, list, 1,
|
||||||
|
XCompoundTextStyle,
|
||||||
|
&textprop))
|
||||||
|
{
|
||||||
|
|
||||||
|
if (8 != textprop.format)
|
||||||
|
DB ("textprop.format is unexpectedly not 8 - it's %d instead\n",
|
||||||
|
textprop.format);
|
||||||
|
|
||||||
|
XChangeProperty (x_dpy, e->requestor, e->property,
|
||||||
|
atoms->compound_text, textprop.format,
|
||||||
|
PropModeReplace, textprop.value,
|
||||||
|
textprop.nitems);
|
||||||
|
|
||||||
|
reply.xselection.property = e->property;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (textprop.value)
|
||||||
|
XFree (textprop.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[self send_reply:&reply];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) send_multiple:(XSelectionRequestEvent *)e
|
||||||
|
{
|
||||||
|
XEvent reply;
|
||||||
|
|
||||||
|
TRACE ();
|
||||||
|
|
||||||
|
[self init_reply:&reply request:e];
|
||||||
|
|
||||||
|
if (None != e->property)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
[self send_reply:&reply];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void) send_image:(XSelectionRequestEvent *)e
|
- (void) send_image:(XSelectionRequestEvent *)e
|
||||||
{
|
{
|
||||||
XEvent reply;
|
XEvent reply;
|
||||||
|
@ -651,12 +696,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
|
||||||
|
|
||||||
TRACE ();
|
TRACE ();
|
||||||
|
|
||||||
reply.xselection.type = SelectionNotify;
|
[self init_reply:&reply request:e];
|
||||||
reply.xselection.selection = e->selection;
|
|
||||||
reply.xselection.target = e->target;
|
|
||||||
reply.xselection.requestor = e->requestor;
|
|
||||||
reply.xselection.time = e->time;
|
|
||||||
reply.xselection.property = None;
|
|
||||||
|
|
||||||
pbtypes = [_pasteboard types];
|
pbtypes = [_pasteboard types];
|
||||||
|
|
||||||
|
@ -678,7 +718,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
|
||||||
if (type)
|
if (type)
|
||||||
{
|
{
|
||||||
NSData *data;
|
NSData *data;
|
||||||
data = [_pasteboard dataForType: type];
|
data = [_pasteboard dataForType:type];
|
||||||
|
|
||||||
if (data)
|
if (data)
|
||||||
{
|
{
|
||||||
|
@ -709,8 +749,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Always send a response, even if the property value is None. */
|
[self send_reply:&reply];
|
||||||
XSendEvent (x_dpy, e->requestor, False, 0, &reply);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)send_none:(XSelectionRequestEvent *)e
|
- (void)send_none:(XSelectionRequestEvent *)e
|
||||||
|
@ -719,15 +758,8 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
|
||||||
|
|
||||||
TRACE ();
|
TRACE ();
|
||||||
|
|
||||||
reply.xselection.type = SelectionNotify;
|
[self init_reply:&reply request:e];
|
||||||
reply.xselection.selection = e->selection;
|
[self send_reply:&reply];
|
||||||
reply.xselection.target = e->target;
|
|
||||||
reply.xselection.requestor = e->requestor;
|
|
||||||
reply.xselection.time = e->time;
|
|
||||||
reply.xselection.property = None;
|
|
||||||
|
|
||||||
/* Always send a response, even if the property value is None. */
|
|
||||||
XSendEvent (x_dpy, e->requestor, False, 0, &reply);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -746,7 +778,8 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
|
||||||
* Perhaps we should just punt and ignore races.
|
* Perhaps we should just punt and ignore races.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*TODO handle COMPOUND_STRING... We need a test app*/
|
/*TODO we need a COMPOUND_TEXT test app*/
|
||||||
|
/*TODO we need a MULTIPLE test app*/
|
||||||
|
|
||||||
DB ("e->target %s\n", XGetAtomName (x_dpy, e->target));
|
DB ("e->target %s\n", XGetAtomName (x_dpy, e->target));
|
||||||
|
|
||||||
|
@ -767,6 +800,14 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
|
||||||
{
|
{
|
||||||
[self send_string:e utf8:NO];
|
[self send_string:e utf8:NO];
|
||||||
}
|
}
|
||||||
|
else if (e->target == atoms->compound_text)
|
||||||
|
{
|
||||||
|
[self send_compound_text:e];
|
||||||
|
}
|
||||||
|
else if (e->target == atoms->multiple)
|
||||||
|
{
|
||||||
|
[self send_multiple:e];
|
||||||
|
}
|
||||||
else if (e->target == atoms->image_png || e->target == atoms->image_jpeg)
|
else if (e->target == atoms->image_png || e->target == atoms->image_jpeg)
|
||||||
{
|
{
|
||||||
[self send_image:e];
|
[self send_image:e];
|
||||||
|
@ -919,7 +960,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
|
||||||
|
|
||||||
/* This handles the image type of selection (typically in CLIPBOARD). */
|
/* This handles the image type of selection (typically in CLIPBOARD). */
|
||||||
/* We convert to a TIFF, so that other applications can paste more easily. */
|
/* We convert to a TIFF, so that other applications can paste more easily. */
|
||||||
- (void) handle_image: (struct propdata *)pdata extension:(NSString *)fileext
|
- (void) handle_image: (struct propdata *)pdata
|
||||||
{
|
{
|
||||||
NSArray *pbtypes;
|
NSArray *pbtypes;
|
||||||
NSUInteger length;
|
NSUInteger length;
|
||||||
|
@ -1041,11 +1082,11 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
|
||||||
}
|
}
|
||||||
else if (type == atoms->image_png)
|
else if (type == atoms->image_png)
|
||||||
{
|
{
|
||||||
[self handle_image:pdata extension:@".png"];
|
[self handle_image:pdata];
|
||||||
}
|
}
|
||||||
else if (type == atoms->image_jpeg)
|
else if (type == atoms->image_jpeg)
|
||||||
{
|
{
|
||||||
[self handle_image:pdata extension:@".jpeg"];
|
[self handle_image:pdata];
|
||||||
}
|
}
|
||||||
else if (type == atoms->utf8_string)
|
else if (type == atoms->utf8_string)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user