mirror of
https://github.com/gnustep/libs-back.git
synced 2025-02-24 04:11:28 +00:00
Reworked the X interaction so that both STRING and UTF8_STRING are
supported both ways. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/trunk@17460 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
5c6acf120f
commit
afe960e235
1 changed files with 98 additions and 124 deletions
222
Tools/xpbs.m
222
Tools/xpbs.m
|
@ -58,9 +58,7 @@ static char* atom_names[] = {
|
||||||
"NULL",
|
"NULL",
|
||||||
"FILE_NAME",
|
"FILE_NAME",
|
||||||
"CLIPBOARD",
|
"CLIPBOARD",
|
||||||
#ifdef X_HAVE_UTF8_STRING
|
|
||||||
"UTF8_STRING"
|
"UTF8_STRING"
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
static Atom atoms[sizeof(atom_names)/sizeof(char*)];
|
static Atom atoms[sizeof(atom_names)/sizeof(char*)];
|
||||||
|
|
||||||
|
@ -84,9 +82,7 @@ static Atom atoms[sizeof(atom_names)/sizeof(char*)];
|
||||||
#define XG_NULL atoms[13]
|
#define XG_NULL atoms[13]
|
||||||
#define XG_FILE_NAME atoms[14]
|
#define XG_FILE_NAME atoms[14]
|
||||||
#define XA_CLIPBOARD atoms[15]
|
#define XA_CLIPBOARD atoms[15]
|
||||||
#ifdef X_HAVE_UTF8_STRING
|
|
||||||
#define XG_UTF8_STRING atoms[16]
|
#define XG_UTF8_STRING atoms[16]
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -130,13 +126,9 @@ osTypeToX(NSString *t)
|
||||||
static NSString*
|
static NSString*
|
||||||
xTypeToOs(Atom t)
|
xTypeToOs(Atom t)
|
||||||
{
|
{
|
||||||
#ifdef X_HAVE_UTF8_STRING
|
if ((t == XG_UTF8_STRING) ||
|
||||||
if (t == XG_UTF8_STRING)
|
(t == XG_TEXT) ||
|
||||||
#else
|
(t == XA_STRING))
|
||||||
if (t == XA_STRING)
|
|
||||||
#endif
|
|
||||||
return NSStringPboardType;
|
|
||||||
else if (t == XG_TEXT)
|
|
||||||
return NSStringPboardType;
|
return NSStringPboardType;
|
||||||
else if (t == XG_FILE_NAME)
|
else if (t == XG_FILE_NAME)
|
||||||
return NSFilenamesPboardType;
|
return NSFilenamesPboardType;
|
||||||
|
@ -146,41 +138,6 @@ xTypeToOs(Atom t)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static Bool xAppendProperty(Display* display,
|
|
||||||
Window window,
|
|
||||||
Atom property,
|
|
||||||
Atom target,
|
|
||||||
int format,
|
|
||||||
unsigned char* data,
|
|
||||||
int number_items)
|
|
||||||
{
|
|
||||||
// Ensure that the error handler is set up.
|
|
||||||
// xSetErrorHandler();
|
|
||||||
|
|
||||||
// Any routine that appends properties can generate a BadAlloc error.
|
|
||||||
// xResetErrorFlag();
|
|
||||||
|
|
||||||
if (number_items > 0)
|
|
||||||
{
|
|
||||||
XChangeProperty(display,
|
|
||||||
window,
|
|
||||||
property,
|
|
||||||
target,
|
|
||||||
format,
|
|
||||||
PropModeAppend,
|
|
||||||
data,
|
|
||||||
number_items);
|
|
||||||
|
|
||||||
XSync(display, False);
|
|
||||||
|
|
||||||
// Check if our write to a property generated an X error.
|
|
||||||
// if (xError())
|
|
||||||
// return False;
|
|
||||||
}
|
|
||||||
|
|
||||||
return True;
|
|
||||||
}
|
|
||||||
|
|
||||||
@interface XPbOwner : NSObject
|
@interface XPbOwner : NSObject
|
||||||
{
|
{
|
||||||
NSPasteboard *_pb;
|
NSPasteboard *_pb;
|
||||||
|
@ -223,7 +180,7 @@ static Bool xAppendProperty(Display* display,
|
||||||
- (void) xSelectionNotify: (XSelectionEvent*)xEvent;
|
- (void) xSelectionNotify: (XSelectionEvent*)xEvent;
|
||||||
- (void) xSelectionRequest: (XSelectionRequestEvent*)xEvent;
|
- (void) xSelectionRequest: (XSelectionRequestEvent*)xEvent;
|
||||||
- (BOOL) xProvideSelection: (XSelectionRequestEvent*)xEvent;
|
- (BOOL) xProvideSelection: (XSelectionRequestEvent*)xEvent;
|
||||||
- (Time) xTimeByAppending;
|
- (Time) xTimeByAppending: (Atom) defaultType;
|
||||||
- (BOOL) xSendData: (unsigned char*) data format: (int) format
|
- (BOOL) xSendData: (unsigned char*) data format: (int) format
|
||||||
items: (int) numItems type: (Atom) xType
|
items: (int) numItems type: (Atom) xType
|
||||||
to: (Window) window property: (Atom) property;
|
to: (Window) window property: (Atom) property;
|
||||||
|
@ -483,12 +440,6 @@ static NSString *xWaitMode = @"XPasteboardWaitMode";
|
||||||
NSDebugLLog(@"Pbs", @"Selection notify for wrong (not our) window.");
|
NSDebugLLog(@"Pbs", @"Selection notify for wrong (not our) window.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (xEvent->property == (Atom)None)
|
|
||||||
{
|
|
||||||
NSLog(@"Owning program failed to convert data.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NSDebugLLog(@"Pbs", @"Selection (%s) notify - '%s'.",
|
NSDebugLLog(@"Pbs", @"Selection (%s) notify - '%s'.",
|
||||||
|
@ -575,13 +526,67 @@ static NSString *xWaitMode = @"XPasteboardWaitMode";
|
||||||
* so we must tell the X server that we have the current selection.
|
* so we must tell the X server that we have the current selection.
|
||||||
* To conform to ICCCM we need to specify an up-to-date timestamp.
|
* To conform to ICCCM we need to specify an up-to-date timestamp.
|
||||||
*/
|
*/
|
||||||
XSetSelectionOwner(xDisplay, _xPb, xAppWin, [self xTimeByAppending]);
|
#ifdef X_HAVE_UTF8_STRING
|
||||||
|
Atom defaultType = XG_UTF8_STRING;
|
||||||
|
#else // X_HAVE_UTF8_STRING not defined
|
||||||
|
Atom defaultType = XA_STRING;
|
||||||
|
#endif // X_HAVE_UTF8_STRING not defined
|
||||||
|
|
||||||
|
XSetSelectionOwner(xDisplay, _xPb, xAppWin,
|
||||||
|
[self xTimeByAppending: defaultType]);
|
||||||
w = XGetSelectionOwner(xDisplay, _xPb);
|
w = XGetSelectionOwner(xDisplay, _xPb);
|
||||||
if (w != xAppWin)
|
if (w != xAppWin)
|
||||||
{
|
{
|
||||||
NSLog(@"Failed to set X selection owner to the pasteboard server.");
|
NSLog(@"Failed to set X selection owner to the pasteboard server.");
|
||||||
}
|
}
|
||||||
[self setOwnedByOpenStep: YES];
|
else
|
||||||
|
{
|
||||||
|
[self setOwnedByOpenStep: YES];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) requestData: (Atom)xType
|
||||||
|
{
|
||||||
|
Time whenRequested;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Do a nul append to a property to get a timestamp, if it returns the
|
||||||
|
* 'CurrentTime' constant then we haven't been able to get one.
|
||||||
|
*/
|
||||||
|
whenRequested = [self xTimeByAppending: xType];
|
||||||
|
if (whenRequested != CurrentTime)
|
||||||
|
{
|
||||||
|
NSDate *limit;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ok - we got a timestamp, so we can ask the selection system for
|
||||||
|
* the pasteboard data that was/is valid for theat time.
|
||||||
|
* Ask the X system to provide the pasteboard data in the
|
||||||
|
* appropriate property of our application root window.
|
||||||
|
*/
|
||||||
|
XConvertSelection(xDisplay, [self xPb], xType,
|
||||||
|
[self xPb], xAppWin, whenRequested);
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) pasteboard: (NSPasteboard*)pb provideDataForType: (NSString*)type
|
- (void) pasteboard: (NSPasteboard*)pb provideDataForType: (NSString*)type
|
||||||
|
@ -595,51 +600,11 @@ static NSString *xWaitMode = @"XPasteboardWaitMode";
|
||||||
*/
|
*/
|
||||||
if ([type isEqual: NSStringPboardType])
|
if ([type isEqual: NSStringPboardType])
|
||||||
{
|
{
|
||||||
Time whenRequested;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Do a nul append to a property to get a timestamp, if it returns the
|
|
||||||
* 'CurrentTime' constant then we haven't been able to get one.
|
|
||||||
*/
|
|
||||||
whenRequested = [self xTimeByAppending];
|
|
||||||
if (whenRequested != CurrentTime)
|
|
||||||
{
|
|
||||||
NSDate *limit;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Ok - we got a timestamp, so we can ask the selection system for
|
|
||||||
* the pasteboard data that was/is valid for theat time.
|
|
||||||
* Ask the X system to provide the pasteboard data in the
|
|
||||||
* appropriate property of our application root window.
|
|
||||||
*/
|
|
||||||
#ifdef X_HAVE_UTF8_STRING
|
#ifdef X_HAVE_UTF8_STRING
|
||||||
XConvertSelection(xDisplay, [self xPb], XG_UTF8_STRING,
|
[self requestData: XG_UTF8_STRING];
|
||||||
[self xPb], xAppWin, whenRequested);
|
if ([self data] == nil)
|
||||||
#else // X_HAVE_UTF8_STRING not defined
|
|
||||||
XConvertSelection(xDisplay, [self xPb], XA_STRING,
|
|
||||||
[self xPb], xAppWin, whenRequested);
|
|
||||||
#endif // X_HAVE_UTF8_STRING not defined
|
#endif // X_HAVE_UTF8_STRING not defined
|
||||||
XFlush(xDisplay);
|
[self requestData: XA_STRING];
|
||||||
|
|
||||||
/*
|
|
||||||
* 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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -710,15 +675,17 @@ xErrorHandler(Display *d, XErrorEvent *e)
|
||||||
int status;
|
int status;
|
||||||
unsigned char *data;
|
unsigned char *data;
|
||||||
Atom actual_target;
|
Atom actual_target;
|
||||||
#ifdef X_HAVE_UTF8_STRING
|
|
||||||
Atom new_target = XG_UTF8_STRING;
|
|
||||||
#else // X_HAVE_UTF8_STRING not defined
|
|
||||||
Atom new_target = XA_STRING;
|
|
||||||
#endif // X_HAVE_UTF8_STRING
|
|
||||||
int actual_format;
|
int actual_format;
|
||||||
unsigned long bytes_remaining;
|
unsigned long bytes_remaining;
|
||||||
unsigned long number_items;
|
unsigned long number_items;
|
||||||
|
|
||||||
|
if (xEvent->property == (Atom)None)
|
||||||
|
{
|
||||||
|
NSDebugLLog(@"Pbs", @"Owning program failed to convert data.");
|
||||||
|
[self setWaitingForSelection: 0];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ([self waitingForSelection] > xEvent->time)
|
if ([self waitingForSelection] > xEvent->time)
|
||||||
{
|
{
|
||||||
NSLog(@"Unexpected selection notify - time %u.", xEvent->time);
|
NSLog(@"Unexpected selection notify - time %u.", xEvent->time);
|
||||||
|
@ -735,7 +702,7 @@ xErrorHandler(Display *d, XErrorEvent *e)
|
||||||
0L, // offset
|
0L, // offset
|
||||||
FULL_LENGTH,
|
FULL_LENGTH,
|
||||||
True, // Delete prop when read.
|
True, // Delete prop when read.
|
||||||
new_target,
|
AnyPropertyType,
|
||||||
&actual_target,
|
&actual_target,
|
||||||
&actual_format,
|
&actual_format,
|
||||||
&number_items,
|
&number_items,
|
||||||
|
@ -744,10 +711,7 @@ xErrorHandler(Display *d, XErrorEvent *e)
|
||||||
|
|
||||||
if ((status == Success) && (number_items > 0))
|
if ((status == Success) && (number_items > 0))
|
||||||
{
|
{
|
||||||
// Convert data to text string.
|
// Convert data to text string.
|
||||||
// string = PropertyToString(xDisplay,new_target,number_items,(char*)data);
|
|
||||||
|
|
||||||
#ifdef X_HAVE_UTF8_STRING
|
|
||||||
if (actual_target == XG_UTF8_STRING)
|
if (actual_target == XG_UTF8_STRING)
|
||||||
{
|
{
|
||||||
NSData *d;
|
NSData *d;
|
||||||
|
@ -762,8 +726,7 @@ xErrorHandler(Display *d, XErrorEvent *e)
|
||||||
RELEASE(s);
|
RELEASE(s);
|
||||||
[self setData: d];
|
[self setData: d];
|
||||||
}
|
}
|
||||||
#else // X_HAVE_UTF8_STRING not defined
|
else if (actual_target == XA_STRING)
|
||||||
if (new_target == XA_STRING)
|
|
||||||
{
|
{
|
||||||
NSData *d;
|
NSData *d;
|
||||||
NSString *s;
|
NSString *s;
|
||||||
|
@ -777,7 +740,6 @@ xErrorHandler(Display *d, XErrorEvent *e)
|
||||||
RELEASE(s);
|
RELEASE(s);
|
||||||
[self setData: d];
|
[self setData: d];
|
||||||
}
|
}
|
||||||
#endif // X_HAVE_UTF8_STRING not defined
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NSLog(@"Unsupported data type from X selection.");
|
NSLog(@"Unsupported data type from X selection.");
|
||||||
|
@ -902,6 +864,8 @@ xErrorHandler(Display *d, XErrorEvent *e)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// A fixed type was requested.
|
||||||
|
xType = xEvent->target;
|
||||||
/*
|
/*
|
||||||
* Find an available OpenStep pasteboard type that corresponds
|
* Find an available OpenStep pasteboard type that corresponds
|
||||||
* to the requested X type.
|
* to the requested X type.
|
||||||
|
@ -911,13 +875,22 @@ xErrorHandler(Display *d, XErrorEvent *e)
|
||||||
NSString *type = [types objectAtIndex: i];
|
NSString *type = [types objectAtIndex: i];
|
||||||
Atom t = osTypeToX(type);
|
Atom t = osTypeToX(type);
|
||||||
|
|
||||||
if (t == xEvent->target)
|
if (t == xType)
|
||||||
{
|
{
|
||||||
osType = type;
|
osType = type;
|
||||||
xType = t;
|
xType = t;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If UTF8 is the default we have to handle the case where the target
|
||||||
|
// applciaiton cannot handle this.
|
||||||
|
if ((osType == nil) &&
|
||||||
|
[types containsObject: NSStringPboardType] &&
|
||||||
|
((xType == XA_STRING) || (xType == XG_TEXT)))
|
||||||
|
{
|
||||||
|
osType = NSStringPboardType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -929,11 +902,16 @@ xErrorHandler(Display *d, XErrorEvent *e)
|
||||||
if ([osType isEqualToString: NSStringPboardType])
|
if ([osType isEqualToString: NSStringPboardType])
|
||||||
{
|
{
|
||||||
NSString *s = [_pb stringForType: NSStringPboardType];
|
NSString *s = [_pb stringForType: NSStringPboardType];
|
||||||
#ifdef X_HAVE_UTF8_STRING
|
NSData *d;
|
||||||
NSData *d = [s dataUsingEncoding: NSUTF8StringEncoding];
|
|
||||||
#else // X_HAVE_UTF8_STRING not defined
|
if (xType == XG_UTF8_STRING)
|
||||||
NSData *d = [s dataUsingEncoding: NSISOLatin1StringEncoding];
|
{
|
||||||
#endif // X_HAVE_UTF8_STRING not defined
|
d = [s dataUsingEncoding: NSUTF8StringEncoding];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d = [s dataUsingEncoding: NSISOLatin1StringEncoding];
|
||||||
|
}
|
||||||
|
|
||||||
format = 8;
|
format = 8;
|
||||||
if (d != nil)
|
if (d != nil)
|
||||||
|
@ -1000,7 +978,7 @@ xErrorHandler(Display *d, XErrorEvent *e)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (Time) xTimeByAppending
|
- (Time) xTimeByAppending: (Atom)defaultType
|
||||||
{
|
{
|
||||||
NSDate *limit;
|
NSDate *limit;
|
||||||
Time whenRequested;
|
Time whenRequested;
|
||||||
|
@ -1025,16 +1003,12 @@ xErrorHandler(Display *d, XErrorEvent *e)
|
||||||
* The property doesn't exist - so we will be creating a new (empty)
|
* The property doesn't exist - so we will be creating a new (empty)
|
||||||
* property.
|
* property.
|
||||||
*/
|
*/
|
||||||
#ifdef X_HAVE_UTF8_STRING
|
actualType = defaultType;
|
||||||
actualType = XG_UTF8_STRING;
|
|
||||||
#else // X_HAVE_UTF8_STRING not defined
|
|
||||||
actualType = XA_STRING;
|
|
||||||
#endif // X_HAVE_UTF8_STRING not defined
|
|
||||||
actualFormat = 8;
|
actualFormat = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
XChangeProperty(xDisplay, xAppWin, [self xPb], actualType, actualFormat,
|
XChangeProperty(xDisplay, xAppWin, [self xPb], actualType, actualFormat,
|
||||||
PropModeAppend, 0, 0);
|
PropModeReplace, 0, 0);
|
||||||
XFlush(xDisplay);
|
XFlush(xDisplay);
|
||||||
limit = [NSDate dateWithTimeIntervalSinceNow: 3.0];
|
limit = [NSDate dateWithTimeIntervalSinceNow: 3.0];
|
||||||
[self setTimeOfLastAppend: 0];
|
[self setTimeOfLastAppend: 0];
|
||||||
|
|
Loading…
Reference in a new issue