Add more EWMH methods and helper methods.

Simplify dragging support code.


git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/trunk@25389 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
fredkiefer 2007-08-14 22:44:40 +00:00
parent 57a2036e59
commit cda1672a5c
3 changed files with 1198 additions and 783 deletions

View file

@ -1,3 +1,9 @@
2007-08-15 Fred Kiefer <FredKiefer@gmx.de>
* Source/x11/XGServerWindow.m: Add more EWMH methods and helper
methods for them.
* Tools/xpbs.m: Simplify dragging support code.
2007-08-13 Fred Kiefer <FredKiefer@gmx.de>
* Source/art/ftfont.m (-coveredCharacterSet): Correct code.

File diff suppressed because it is too large Load diff

View file

@ -34,7 +34,7 @@
/*
* Non-predefined atoms that are used in the X selection mechanism
*/
static char* atom_names[] = {
static char *atom_names[] = {
"CHARACTER_POSITION",
"CLIENT_WINDOW",
"HOST_NAME",
@ -54,7 +54,17 @@ static char* atom_names[] = {
"UTF8_STRING",
"MULTIPLE",
"COMPOUND_TEXT",
"INCR"
"INCR",
// MIME types
"text/plain",
"text/uri-list",
"application/postscript",
"text/tab-separated-values",
"text/richtext",
"image/tiff",
"application/octet-stream",
"application/x-rootwindow-drop"
};
static Atom atoms[sizeof(atom_names)/sizeof(char*)];
@ -82,6 +92,8 @@ static Atom atoms[sizeof(atom_names)/sizeof(char*)];
#define XG_MULTIPLE atoms[17]
#define XG_COMPOUND_TEXT atoms[18]
#define XG_INCR atoms[19]
#define XG_MIME_PLAIN atoms[20]
#define XG_MIME_URI atoms[21]
@ -274,38 +286,38 @@ static NSString *xWaitMode = @"XPasteboardWaitMode";
while ((count = XPending(xDisplay)) > 0)
{
while (count-- > 0)
{
XEvent xEvent;
{
XEvent xEvent;
XNextEvent(xDisplay, &xEvent);
XNextEvent(xDisplay, &xEvent);
switch (xEvent.type)
{
case PropertyNotify:
[self xPropertyNotify: (XPropertyEvent*)&xEvent];
NSDebugLLog(@"Pbs", @"PropertyNotify.");
break;
case SelectionNotify:
[self xSelectionNotify: (XSelectionEvent*)&xEvent];
NSDebugLLog(@"Pbs", @"SelectionNotify.");
break;
switch (xEvent.type)
{
case PropertyNotify:
[self xPropertyNotify: (XPropertyEvent*)&xEvent];
NSDebugLLog(@"Pbs", @"PropertyNotify.");
break;
case SelectionClear:
[self xSelectionClear: (XSelectionClearEvent*)&xEvent];
NSDebugLLog(@"Pbs", @"SelectionClear.");
break;
case SelectionNotify:
[self xSelectionNotify: (XSelectionEvent*)&xEvent];
NSDebugLLog(@"Pbs", @"SelectionNotify.");
break;
case SelectionRequest:
[self xSelectionRequest: (XSelectionRequestEvent*)&xEvent];
NSDebugLLog(@"Pbs", @"SelectionRequest.");
break;
case SelectionClear:
[self xSelectionClear: (XSelectionClearEvent*)&xEvent];
NSDebugLLog(@"Pbs", @"SelectionClear.");
break;
case SelectionRequest:
[self xSelectionRequest: (XSelectionRequestEvent*)&xEvent];
NSDebugLLog(@"Pbs", @"SelectionRequest.");
break;
default:
NSDebugLLog(@"Pbs", @"Unexpected X event.");
break;
}
}
default:
NSDebugLLog(@"Pbs", @"Unexpected X event.");
break;
}
}
}
}
@ -332,7 +344,7 @@ static NSString *xWaitMode = @"XPasteboardWaitMode";
char *name = XGetAtomName(xDisplay, xEvent->selection);
NSDebugLLog(@"Pbs", @"Selection clear for unknown selection - '%s'.",
name);
name);
XFree(name);
return;
}
@ -355,7 +367,7 @@ static NSString *xWaitMode = @"XPasteboardWaitMode";
{
char *name = XGetAtomName(xDisplay, xEvent->atom);
NSDebugLLog(@"Pbs", @"Property notify for unknown property - '%s'.",
name);
name);
XFree(name);
return;
}
@ -374,14 +386,14 @@ static NSString *xWaitMode = @"XPasteboardWaitMode";
+ (void) xSelectionNotify: (XSelectionEvent*)xEvent
{
XPbOwner *o;
XPbOwner *o;
o = [self ownerByXPb: xEvent->selection];
if (o == nil)
{
char *name = XGetAtomName(xDisplay, xEvent->selection);
NSDebugLLog(@"Pbs", @"Selection notify for unknown selection - '%s'.",
name);
name);
XFree(name);
return;
}
@ -393,19 +405,19 @@ static NSString *xWaitMode = @"XPasteboardWaitMode";
}
else
{
char *sel_name = XGetAtomName(xDisplay, xEvent->selection);
char *pro_name;
char *sel_name = XGetAtomName(xDisplay, xEvent->selection);
char *pro_name;
if (xEvent->property == None)
pro_name = NULL;
else
pro_name = XGetAtomName(xDisplay, xEvent->property);
if (xEvent->property == None)
pro_name = NULL;
else
pro_name = XGetAtomName(xDisplay, xEvent->property);
NSDebugLLog(@"Pbs", @"Selection (%s) notify - '%s'.", sel_name,
pro_name? pro_name : "None");
XFree(sel_name);
if (pro_name)
XFree(pro_name);
NSDebugLLog(@"Pbs", @"Selection (%s) notify - '%s'.", sel_name,
pro_name? pro_name : "None");
XFree(sel_name);
if (pro_name)
XFree(pro_name);
}
[o xSelectionNotify: xEvent];
@ -420,7 +432,7 @@ static NSString *xWaitMode = @"XPasteboardWaitMode";
{
char *name = XGetAtomName(xDisplay, xEvent->selection);
NSDebugLLog(@"Pbs", @"Selection request for unknown selection - '%s'.",
name);
name);
XFree(name);
return;
}
@ -505,7 +517,7 @@ static NSString *xWaitMode = @"XPasteboardWaitMode";
- (void) requestData: (Atom)xType
{
Time whenRequested;
Time whenRequested;
/*
* Do a nul append to a property to get a timestamp, if it returns the
@ -514,7 +526,7 @@ static NSString *xWaitMode = @"XPasteboardWaitMode";
whenRequested = [self xTimeByAppending];
if (whenRequested != CurrentTime)
{
NSDate *limit;
NSDate *limit;
/*
* Ok - we got a timestamp, so we can ask the selection system for
@ -523,7 +535,7 @@ static NSString *xWaitMode = @"XPasteboardWaitMode";
* appropriate property of our application root window.
*/
XConvertSelection(xDisplay, [self xPb], xType,
[self xPb], xAppWin, whenRequested);
[self xPb], xAppWin, whenRequested);
XFlush(xDisplay);
/*
@ -534,19 +546,19 @@ static NSString *xWaitMode = @"XPasteboardWaitMode";
[self setWaitingForSelection: whenRequested];
while ([self waitingForSelection] == whenRequested)
{
[[NSRunLoop currentRunLoop] runMode: xWaitMode
beforeDate: limit];
if ([limit timeIntervalSinceNow] <= 0.0)
break; /* Timeout */
}
[[NSRunLoop currentRunLoop] runMode: xWaitMode
beforeDate: limit];
if ([limit timeIntervalSinceNow] <= 0.0)
break; /* Timeout */
}
if ([self waitingForSelection] != 0)
{
char *name = XGetAtomName(xDisplay, xType);
char *name = XGetAtomName(xDisplay, xType);
[self setWaitingForSelection: 0];
NSLog(@"Timed out waiting for X selection '%s'", name);
XFree(name);
}
[self setWaitingForSelection: 0];
NSLog(@"Timed out waiting for X selection '%s'", name);
XFree(name);
}
}
}
@ -563,8 +575,13 @@ static NSString *xWaitMode = @"XPasteboardWaitMode";
{
[self requestData: XG_UTF8_STRING];
if ([self data] == nil)
[self requestData: XA_STRING];
[self requestData: XA_STRING];
}
else if ([type isEqual: NSFilenamesPboardType])
{
[self requestData: XG_FILE_NAME];
}
// FIXME: Support more types
else
{
NSLog(@"Request for non-string info from X pasteboard: %@", type);
@ -630,7 +647,7 @@ xErrorHandler(Display *d, XErrorEvent *e)
}
- (NSMutableData*) getSelectionData: (XSelectionEvent*)xEvent
type: (Atom*)type
type: (Atom*)type
{
int status;
unsigned char *data;
@ -649,51 +666,51 @@ xErrorHandler(Display *d, XErrorEvent *e)
do
{
status = XGetWindowProperty(xDisplay,
xEvent->requestor,
xEvent->property,
long_offset, // offset
long_length,
True, // Delete prop when read.
req_type,
&actual_type,
&actual_format,
&number_items,
&bytes_remaining,
&data);
xEvent->requestor,
xEvent->property,
long_offset, // offset
long_length,
True, // Delete prop when read.
req_type,
&actual_type,
&actual_format,
&number_items,
&bytes_remaining,
&data);
if ((status == Success) && (number_items > 0))
{
long count = number_items * actual_format / 8;
if (md == nil)
{
md = [[NSMutableData alloc] initWithBytes: (void *)data
length: count];
req_type = actual_type;
}
else
{
if (req_type != actual_type)
{
char *req_name = XGetAtomName(xDisplay, req_type);
char *act_name = XGetAtomName(xDisplay, actual_type);
NSLog(@"Selection changed type from %s to %s.",
req_name, act_name);
XFree(req_name);
XFree(act_name);
RELEASE(md);
return nil;
}
[md appendBytes: (void *)data length: count];
}
long_offset += count / 4;
if (data)
{
XFree(data);
}
}
long count = number_items * actual_format / 8;
if (md == nil)
{
md = [[NSMutableData alloc] initWithBytes: (void *)data
length: count];
req_type = actual_type;
}
else
{
if (req_type != actual_type)
{
char *req_name = XGetAtomName(xDisplay, req_type);
char *act_name = XGetAtomName(xDisplay, actual_type);
NSLog(@"Selection changed type from %s to %s.",
req_name, act_name);
XFree(req_name);
XFree(act_name);
RELEASE(md);
return nil;
}
[md appendBytes: (void *)data length: count];
}
long_offset += count / 4;
if (data)
{
XFree(data);
}
}
}
while ((status == Success) && (bytes_remaining > 0));
@ -733,79 +750,99 @@ xErrorHandler(Display *d, XErrorEvent *e)
if (md != nil)
{
if (actual_type == XG_INCR)
{
XEvent event;
NSMutableData *imd = nil;
BOOL wait = YES;
md = nil;
while (wait)
{
XNextEvent(xDisplay, &event);
if (event.type == PropertyNotify)
{
if (event.xproperty.state != PropertyNewValue) continue;
imd = [self getSelectionData: xEvent type: &actual_type];
if (imd != nil)
{
if (md == nil)
{
md = imd;
}
else
{
[md appendData: imd];
}
}
else
{
wait = NO;
}
}
}
}
{
XEvent event;
NSMutableData *imd = nil;
BOOL wait = YES;
md = nil;
while (wait)
{
XNextEvent(xDisplay, &event);
if (event.type == PropertyNotify)
{
if (event.xproperty.state != PropertyNewValue) continue;
imd = [self getSelectionData: xEvent type: &actual_type];
if (imd != nil)
{
if (md == nil)
{
md = imd;
}
else
{
[md appendData: imd];
}
}
else
{
wait = NO;
}
}
}
}
}
if (md != nil)
{
// Convert data to text string.
if (actual_type == XG_UTF8_STRING)
{
NSString *s;
NSData *d;
s = [[NSString alloc] initWithData: md
encoding: NSUTF8StringEncoding];
if (s != nil)
{
d = [NSSerializer serializePropertyList: s];
RELEASE(s);
[self setData: d];
}
}
{
NSString *s;
NSData *d;
s = [[NSString alloc] initWithData: md
encoding: NSUTF8StringEncoding];
if (s != nil)
{
d = [NSSerializer serializePropertyList: s];
RELEASE(s);
[self setData: d];
}
}
else if (actual_type == XA_STRING)
{
NSString *s;
NSData *d;
{
NSString *s;
NSData *d;
s = [[NSString alloc] initWithData: md
encoding: NSISOLatin1StringEncoding];
if (s != nil)
{
d = [NSSerializer serializePropertyList: s];
RELEASE(s);
[self setData: d];
}
}
else if (actual_type == XG_FILE_NAME)
{
NSArray *names;
NSData *d;
NSString *s;
NSURL *url;
s = [[NSString alloc] initWithData: md
encoding: NSISOLatin1StringEncoding];
if (s != nil)
{
d = [NSSerializer serializePropertyList: s];
RELEASE(s);
[self setData: d];
}
}
s = [[NSString alloc] initWithData: md
encoding: NSUTF8StringEncoding];
url = [[NSURL alloc] initWithString: s];
RELEASE(s);
if ([url isFileURL])
{
s = [url path];
names = [NSArray arrayWithObject: s];
d = [NSSerializer serializePropertyList: names];
[self setData: d];
}
RELEASE(url);
}
else
{
char *name = XGetAtomName(xDisplay, actual_type);
NSLog(@"Unsupported data type '%s' from X selection.", name);
XFree(name);
}
{
char *name = XGetAtomName(xDisplay, actual_type);
NSLog(@"Unsupported data type '%s' from X selection.", name);
XFree(name);
}
}
}
@ -873,16 +910,16 @@ xErrorHandler(Display *d, XErrorEvent *e)
if ([types containsObject: NSStringPboardType])
{
xTypes[numTypes++] = XG_UTF8_STRING;
xTypes[numTypes++] = XG_COMPOUND_TEXT;
xTypes[numTypes++] = XA_STRING;
xTypes[numTypes++] = XG_TEXT;
}
xTypes[numTypes++] = XG_UTF8_STRING;
xTypes[numTypes++] = XG_COMPOUND_TEXT;
xTypes[numTypes++] = XA_STRING;
xTypes[numTypes++] = XG_TEXT;
}
if ([types containsObject: NSFilenamesPboardType])
{
xTypes[numTypes++] = XG_FILE_NAME;
}
xTypes[numTypes++] = XG_FILE_NAME;
}
xType = XA_ATOM;
format = 32;
@ -906,59 +943,59 @@ xErrorHandler(Display *d, XErrorEvent *e)
*/
if ([types containsObject: NSStringPboardType])
{
xEvent->target = XG_UTF8_STRING;
[self xProvideSelection: xEvent];
}
xEvent->target = XG_UTF8_STRING;
[self xProvideSelection: xEvent];
}
else if ([types containsObject: NSFilenamesPboardType])
{
xEvent->target = XG_FILE_NAME;
[self xProvideSelection: xEvent];
}
xEvent->target = XG_FILE_NAME;
[self xProvideSelection: xEvent];
}
}
else if (xEvent->target == XG_MULTIPLE)
{
if (xEvent->property != None)
{
Atom *multipleAtoms= NULL;
int actual_format;
Atom actual_type;
unsigned long number_items, bytes_remaining;
int status;
Atom *multipleAtoms= NULL;
int actual_format;
Atom actual_type;
unsigned long number_items, bytes_remaining;
int status;
status = XGetWindowProperty(xDisplay,
xEvent->requestor,
xEvent->property,
0,
100,
False,
AnyPropertyType,
&actual_type,
&actual_format,
&number_items,
&bytes_remaining,
(unsigned char **)&multipleAtoms);
if ((status == Success) && (bytes_remaining == 0) &&
(actual_format == 32) && (actual_type == XA_ATOM))
{
int i;
XSelectionRequestEvent requestEvent;
memcpy(&requestEvent, xEvent, sizeof(XSelectionRequestEvent));
for (i = 0; i < number_items; i += 2)
{
requestEvent.target= multipleAtoms[i];
requestEvent.property= multipleAtoms[i+1];
if (requestEvent.target != None)
{
// Recursive call to this method for each pair.
if (![self xProvideSelection: &requestEvent])
{
multipleAtoms[i+1]= None;
}
}
}
// FIXME: Should we call XChangeProperty to set the invalid types?
}
status = XGetWindowProperty(xDisplay,
xEvent->requestor,
xEvent->property,
0,
100,
False,
AnyPropertyType,
&actual_type,
&actual_format,
&number_items,
&bytes_remaining,
(unsigned char **)&multipleAtoms);
if ((status == Success) && (bytes_remaining == 0) &&
(actual_format == 32) && (actual_type == XA_ATOM))
{
int i;
XSelectionRequestEvent requestEvent;
memcpy(&requestEvent, xEvent, sizeof(XSelectionRequestEvent));
for (i = 0; i < number_items; i += 2)
{
requestEvent.target= multipleAtoms[i];
requestEvent.property= multipleAtoms[i+1];
if (requestEvent.target != None)
{
// Recursive call to this method for each pair.
if (![self xProvideSelection: &requestEvent])
{
multipleAtoms[i+1]= None;
}
}
}
// FIXME: Should we call XChangeProperty to set the invalid types?
}
}
}
else if ((xEvent->target == XG_COMPOUND_TEXT) &&
@ -973,25 +1010,25 @@ xErrorHandler(Display *d, XErrorEvent *e)
d = [s cString];
if (d)
{
char *list[]= {(char *)d, NULL};
XTextProperty textProperty;
status = XmbTextListToTextProperty(xEvent->display, list, 1,
XCompoundTextStyle, &textProperty);
if (status == Success)
{
NSAssert(textProperty.format == 8, @"textProperty.format == 8");
numItems = textProperty.nitems;
data = malloc(numItems + 1);
memcpy(data, textProperty.value, numItems + 1);
XFree((void *)textProperty.value);
}
}
char *list[]= {(char *)d, NULL};
XTextProperty textProperty;
status = XmbTextListToTextProperty(xEvent->display, list, 1,
XCompoundTextStyle, &textProperty);
if (status == Success)
{
NSAssert(textProperty.format == 8, @"textProperty.format == 8");
numItems = textProperty.nitems;
data = malloc(numItems + 1);
memcpy(data, textProperty.value, numItems + 1);
XFree((void *)textProperty.value);
}
}
}
else if (((xEvent->target == XG_UTF8_STRING) ||
(xEvent->target == XA_STRING) ||
(xEvent->target == XG_TEXT)) &&
[types containsObject: NSStringPboardType])
(xEvent->target == XA_STRING) ||
(xEvent->target == XG_TEXT)) &&
[types containsObject: NSStringPboardType])
{
NSString *s = [_pb stringForType: NSStringPboardType];
NSData *d = nil;
@ -1005,24 +1042,43 @@ xErrorHandler(Display *d, XErrorEvent *e)
*/
if (xType == XG_UTF8_STRING)
{
d = [s dataUsingEncoding: NSUTF8StringEncoding];
}
d = [s dataUsingEncoding: NSUTF8StringEncoding];
}
else if ((xType == XA_STRING) || (xType == XG_TEXT))
{
d = [s dataUsingEncoding: NSISOLatin1StringEncoding];
}
d = [s dataUsingEncoding: NSISOLatin1StringEncoding];
}
if (d != nil)
{
numItems = [d length];
data = malloc(numItems + 1);
if (data)
[d getBytes: data];
}
numItems = [d length];
data = malloc(numItems + 1);
if (data)
[d getBytes: data];
}
}
else if ((xEvent->target == XG_FILE_NAME) &&
[types containsObject: NSFilenamesPboardType])
{
NSArray *names = [_pb propertyListForType: NSFilenamesPboardType];
NSString *file = [[names lastObject] stringByStandardizingPath];
NSURL *url = [[NSURL alloc] initWithScheme: NSURLFileScheme
host: @"localhost"
path: file];
NSString *s = [url absoluteString];
NSData *d;
xType = xEvent->target;
format = 8;
RELEASE(url);
d = [s dataUsingEncoding: NSISOLatin1StringEncoding];
if (d != nil)
{
numItems = [d length];
data = malloc(numItems + 1);
if (data)
[d getBytes: data];
}
}
else
{
@ -1034,12 +1090,12 @@ xErrorHandler(Display *d, XErrorEvent *e)
}
return [self xSendData: data format: format items: numItems type: xType
to: xEvent->requestor property: xEvent->property];
to: xEvent->requestor property: xEvent->property];
}
- (BOOL) xSendData: (unsigned char*) data format: (int) format
items: (int) numItems type: (Atom) xType
to: (Window) window property: (Atom) property
items: (int) numItems type: (Atom) xType
to: (Window) window property: (Atom) property
{
BOOL status = NO;
@ -1061,23 +1117,23 @@ xErrorHandler(Display *d, XErrorEvent *e)
oldHandler = XSetErrorHandler(xErrorHandler);
while (appendFailure == NO && pos < numItems)
{
if (pos + maxItems > numItems)
{
maxItems = numItems - pos;
}
XChangeProperty(xDisplay, window, property,
xType, format, mode, &data[pos*format/8], maxItems);
mode = PropModeAppend;
pos += maxItems;
XSync(xDisplay, False);
}
{
if (pos + maxItems > numItems)
{
maxItems = numItems - pos;
}
XChangeProperty(xDisplay, window, property,
xType, format, mode, &data[pos*format/8], maxItems);
mode = PropModeAppend;
pos += maxItems;
XSync(xDisplay, False);
}
free(data);
XSetErrorHandler(oldHandler);
if (appendFailure == NO)
{
status = YES;
}
{
status = YES;
}
}
return status;
}
@ -1125,7 +1181,7 @@ xErrorHandler(Display *d, XErrorEvent *e)
[[NSRunLoop currentRunLoop] runMode: xWaitMode
beforeDate: limit];
if ([limit timeIntervalSinceNow] <= 0.0)
break; /* Timeout */
break; /* Timeout */
}
if ((whenRequested = [self timeOfLastAppend]) == 0)
{
@ -1204,12 +1260,7 @@ static DndClass dnd;
NSArray *types;
Atom *typelist;
// Some GNUstep application did grap the drag pasteboard. Report this to X.
if (xdnd_set_selection_owner(&dnd, xAppWin, None))
{
NSLog(@"Failed to set X drag selection owner to the pasteboard server.");
}
[self setOwnedByOpenStep: YES];
[super pasteboardChangedOwner: sender];
// We also have to set the supported types for our window
types = [_pb types];
@ -1237,35 +1288,9 @@ static DndClass dnd;
{
NSString *mime = [NSPasteboard mimeTypeForPasteboardType: type];
Atom mType = XInternAtom(xDisplay, [mime cString], False);
Window window;
Time whenRequested = CurrentTime;
NSDate *limit;
[self setData: nil];
// How can we get the selection owner?
window = XGetSelectionOwner(xDisplay, dnd.XdndSelection);
xdnd_convert_selection(&dnd, window, xAppWin, mType);
XFlush(xDisplay);
/*
* Run an event loop to read X events until we have aquired the
* pasteboard data we need.
*/
limit = [NSDate dateWithTimeIntervalSinceNow: 20.0];
[self setWaitingForSelection: whenRequested];
while ([self waitingForSelection] == whenRequested)
{
[[NSRunLoop currentRunLoop] runMode: xWaitMode
beforeDate: limit];
if ([limit timeIntervalSinceNow] <= 0.0)
break; /* Timeout */
}
if ([self waitingForSelection] != 0)
{
[self setWaitingForSelection: 0];
NSLog(@"Timed out waiting for X selection");
}
[self requestData: mType];
[pb setData: [self data] forType: type];
}