xserver: Branch 'xorg-server-1.5-apple' - 19 commits

Jeremy Huddleston jeremyhu at kemper.freedesktop.org
Sun Sep 21 17:40:46 PDT 2008


 hw/xquartz/X11Application.h                                         |    6 
 hw/xquartz/X11Application.m                                         |   11 
 hw/xquartz/X11Controller.h                                          |    8 
 hw/xquartz/X11Controller.m                                          |   51 
 hw/xquartz/bundle/Resources/English.lproj/main.nib/designable.nib   |  828 ++++--
 hw/xquartz/bundle/Resources/English.lproj/main.nib/keyedobjects.nib |binary
 hw/xquartz/darwin.c                                                 |    7 
 hw/xquartz/darwin.h                                                 |    6 
 hw/xquartz/doc/Xquartz.man.pre                                      |   15 
 hw/xquartz/pbproxy/main.m                                           |   30 
 hw/xquartz/pbproxy/pbproxy.h                                        |    2 
 hw/xquartz/pbproxy/x-input.m                                        |   15 
 hw/xquartz/pbproxy/x-selection.h                                    |   42 
 hw/xquartz/pbproxy/x-selection.m                                    | 1210 ++++++++--
 hw/xquartz/xpr/xprEvent.c                                           |    2 
 hw/xquartz/xpr/xprScreen.c                                          |    3 
 16 files changed, 1758 insertions(+), 478 deletions(-)

New commits:
commit 0a55ed3965a9249df14c2e6f6ffb2545ba651a41
Author: Jeremy Huddleston <jeremyhu at freedesktop.org>
Date:   Sat Sep 20 19:41:46 2008 -0700

    XQuartz: 64bit crash fix ... don't pass pointers through xe.
    (cherry picked from commit 5f1265b82edead8f15f2affc79c2782519502fa2)

diff --git a/hw/xquartz/xpr/xprEvent.c b/hw/xquartz/xpr/xprEvent.c
index 617d6e1..08581c0 100644
--- a/hw/xquartz/xpr/xprEvent.c
+++ b/hw/xquartz/xpr/xprEvent.c
@@ -73,7 +73,7 @@ static void xprEventHandler(int screenNum, xEventPtr xe, DeviceIntPtr dev, int n
                 
             case kXquartzWindowMoved:
                 DEBUG_LOG("kXquartzWindowMoved\n");
-                RootlessNativeWindowMoved ((WindowPtr)xe[i].u.clientMessage.u.l.longs0);
+                RootlessNativeWindowMoved(xprGetXWindow(xe[i].u.clientMessage.u.l.longs0));
                 break;
                 
             case kXquartzBringAllToFront:
diff --git a/hw/xquartz/xpr/xprScreen.c b/hw/xquartz/xpr/xprScreen.c
index d8eb72a..7d5303b 100644
--- a/hw/xquartz/xpr/xprScreen.c
+++ b/hw/xquartz/xpr/xprScreen.c
@@ -88,8 +88,7 @@ static void eventHandler(unsigned int type, const void *arg,
             DEBUG_LOG("XP_EVENT_WINDOW_MOVED\n");
             if (arg_size == sizeof(xp_window_id))  {
                 xp_window_id id = * (xp_window_id *) arg;
-                WindowPtr pWin = xprGetXWindow(id);
-                DarwinSendDDXEvent(kXquartzWindowMoved, 1, pWin);
+                DarwinSendDDXEvent(kXquartzWindowMoved, 1, id);
             }
             break;
             
commit 98066a09e42ce8dbe9ebc1119024a280f4dc0041
Author: George Peter Staplin <gps at Georges-Workstation.local>
Date:   Sat Sep 20 17:49:16 2008 -0600

    XQuartz: pbproxy: Add an X error handler that returns 0.
    
    Move the struct atom_list into the x-selection class, so that it's
    no longer a global variable named atoms.  This may ease pthread
    integration and reduce the chances of symbols conflicting.
    (cherry picked from commit c1403c713ca80104ae3736bd2ed1eb6ffa5192b6)

diff --git a/hw/xquartz/pbproxy/main.m b/hw/xquartz/pbproxy/main.m
index 7577f7a..6d49070 100644
--- a/hw/xquartz/pbproxy/main.m
+++ b/hw/xquartz/pbproxy/main.m
@@ -14,9 +14,6 @@
 Display *x_dpy;
 int x_apple_wm_event_base, x_apple_wm_error_base;
 
-struct atom_list atom_list_inst;
-struct atom_list *atoms = &atom_list_inst;
-
 static int x_grab_count;
 static Bool x_grab_synced;
 
@@ -57,6 +54,10 @@ static int x_io_error_handler (Display *dpy) {
     return 0;
 }
 
+static int x_error_handler (Display *dpy, XErrorEvent *errevent) {
+    return 0;
+}
+
 static void x_init (void) {
     x_dpy = XOpenDisplay (NULL);
     if (x_dpy == NULL) {
@@ -65,21 +66,8 @@ static void x_init (void) {
     }
     
     XSetIOErrorHandler (x_io_error_handler);
-    atoms->primary = XInternAtom (x_dpy, "PRIMARY", False);
-    atoms->clipboard = XInternAtom (x_dpy, "CLIPBOARD", False);
-    atoms->text = XInternAtom (x_dpy, "TEXT", False);
-    atoms->utf8_string = XInternAtom (x_dpy, "UTF8_STRING", False);
-    atoms->targets = XInternAtom (x_dpy, "TARGETS", False);
-    atoms->multiple = XInternAtom (x_dpy, "MULTIPLE", False);
-    atoms->cstring = XInternAtom (x_dpy, "CSTRING", False);
-    atoms->image_png = XInternAtom (x_dpy, "image/png", False);
-    atoms->image_jpeg = XInternAtom (x_dpy, "image/jpeg", False);
-    atoms->incr = XInternAtom (x_dpy, "INCR", False);
-    atoms->atom = XInternAtom (x_dpy, "ATOM", 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);
-
+    XSetErrorHandler (x_error_handler);
+    
     if (!XAppleWMQueryExtension (x_dpy, &x_apple_wm_event_base,
                                  &x_apple_wm_error_base)) {
         fprintf (stderr, "can't open AppleWM server extension\n");
diff --git a/hw/xquartz/pbproxy/pbproxy.h b/hw/xquartz/pbproxy/pbproxy.h
index 098e309..56111f9 100644
--- a/hw/xquartz/pbproxy/pbproxy.h
+++ b/hw/xquartz/pbproxy/pbproxy.h
@@ -23,14 +23,6 @@ extern Time x_current_timestamp (void);
 extern Display *x_dpy;
 extern int x_apple_wm_event_base, x_apple_wm_error_base;
 
-struct atom_list {
-    Atom primary, clipboard, text, utf8_string, string, targets, multiple,
-	cstring, image_png, image_jpeg, incr, atom, clipboard_manager,
-	compound_text, atom_pair;
-};
-
-extern struct atom_list *atoms;
-
 /* from x-input.m */
 extern void x_input_register (void);
 extern void x_input_run (void);
diff --git a/hw/xquartz/pbproxy/x-selection.h b/hw/xquartz/pbproxy/x-selection.h
index 5e23398..06910b4 100644
--- a/hw/xquartz/pbproxy/x-selection.h
+++ b/hw/xquartz/pbproxy/x-selection.h
@@ -40,6 +40,13 @@ struct propdata {
 	size_t length;
 };
 
+struct atom_list {
+    Atom primary, clipboard, text, utf8_string, string, targets, multiple,
+        cstring, image_png, image_jpeg, incr, atom, clipboard_manager,
+        compound_text, atom_pair;
+};
+
+
 @interface x_selection : NSObject
 {
 @private
@@ -79,6 +86,8 @@ struct propdata {
      * CLIPBOARD.  It also prevents a race with INCR transfers.
      */
     int pending_clipboard; 
+    
+    struct atom_list atoms[1];
 }
 
 - (void) x_active:(Time)timestamp;
diff --git a/hw/xquartz/pbproxy/x-selection.m b/hw/xquartz/pbproxy/x-selection.m
index 2f35fcd..350b347 100644
--- a/hw/xquartz/pbproxy/x-selection.m
+++ b/hw/xquartz/pbproxy/x-selection.m
@@ -85,80 +85,6 @@ free_propdata (struct propdata *pdata)
     *pdata = null_propdata;
 }
 
-/* Return True if this is an INCR-style transfer. */
-static Bool
-is_incr_type (XSelectionEvent *e)
-{
-    Atom seltype;
-    int format;
-    unsigned long numitems = 0UL, bytesleft = 0UL;
-    unsigned char *chunk;
-       
-    TRACE ();
-
-    if (Success != XGetWindowProperty (x_dpy, e->requestor, e->property,
-				       /*offset*/ 0L, /*length*/ 4UL,
-				       /*Delete*/ False,
-				       AnyPropertyType, &seltype, &format,
-				       &numitems, &bytesleft, &chunk))
-    {
-	return False;
-    }
-
-    if(chunk)
-	XFree(chunk);
-
-    return (seltype == atoms->incr) ? True : False;
-}
-
-/* This finds the preferred type from a TARGETS list.*/
-static Atom 
-find_preferred (struct propdata *pdata)
-{
-    Atom a = None;
-    size_t i;
-    Bool png = False, utf8 = False, string = False;
-
-    TRACE ();
-
-    if (pdata->length % sizeof (a))
-    {
-	fprintf(stderr, "Atom list is not a multiple of the size of an atom!\n");
-	return None;
-    }
-
-    for (i = 0; i < pdata->length; i += sizeof (a))
-    {
-	memcpy (&a, pdata->data + i, sizeof (a));
-	
-	if (a == atoms->image_png)
-	{
-	    png = True;
-	} 
-	else if (a == atoms->utf8_string)
-	{
-	    utf8 = True;
-        } 
-	else if (a == atoms->string)
-	{
-	    string = True;
-	}
-    }
-
-    /*We prefer PNG over strings, and UTF8 over a Latin-1 string.*/
-    if (png)
-	return atoms->image_png;
-
-    if (utf8)
-	return atoms->utf8_string;
-
-    if (string)
-	return atoms->string;
-
-    /* This is evidently something we don't know how to handle.*/
-    return None;
-}
-
 /*
  * Return True if an error occurs.  Return False if pdata has data 
  * and we finished. 
@@ -268,6 +194,80 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
     return (unsigned long *) data;
 }
 
+/* Implementation methods */
+
+/* This finds the preferred type from a TARGETS list.*/
+- (Atom) find_preferred:(struct propdata *)pdata
+{
+    Atom a = None;
+    size_t i;
+    Bool png = False, utf8 = False, string = False;
+
+    TRACE ();
+
+    if (pdata->length % sizeof (a))
+    {
+	fprintf(stderr, "Atom list is not a multiple of the size of an atom!\n");
+	return None;
+    }
+
+    for (i = 0; i < pdata->length; i += sizeof (a))
+    {
+	memcpy (&a, pdata->data + i, sizeof (a));
+	
+	if (a == atoms->image_png)
+	{
+	    png = True;
+	} 
+	else if (a == atoms->utf8_string)
+	{
+	    utf8 = True;
+        } 
+	else if (a == atoms->string)
+	{
+	    string = True;
+	}
+    }
+
+    /*We prefer PNG over strings, and UTF8 over a Latin-1 string.*/
+    if (png)
+	return atoms->image_png;
+
+    if (utf8)
+	return atoms->utf8_string;
+
+    if (string)
+	return atoms->string;
+
+    /* This is evidently something we don't know how to handle.*/
+    return None;
+}
+
+/* Return True if this is an INCR-style transfer. */
+- (Bool) is_incr_type:(XSelectionEvent *)e
+{
+    Atom seltype;
+    int format;
+    unsigned long numitems = 0UL, bytesleft = 0UL;
+    unsigned char *chunk;
+       
+    TRACE ();
+
+    if (Success != XGetWindowProperty (x_dpy, e->requestor, e->property,
+				       /*offset*/ 0L, /*length*/ 4UL,
+				       /*Delete*/ False,
+				       AnyPropertyType, &seltype, &format,
+				       &numitems, &bytesleft, &chunk))
+    {
+	return False;
+    }
+
+    if(chunk)
+	XFree(chunk);
+
+    return (seltype == atoms->incr) ? True : False;
+}
+
 /* 
  * This should be called after a selection has been copied, 
  * or when the selection is unfinished before a transfer completes. 
@@ -870,7 +870,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
     DB ("e->selection %s\n", XGetAtomName (x_dpy, e->selection));
     DB ("e->property %s\n", XGetAtomName (x_dpy, e->property));
 
-    if (is_incr_type (e)) 
+    if ([self is_incr_type:e]) 
     {
 	/*
 	 * This is an INCR-style transfer, which means that we 
@@ -956,7 +956,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 
     TRACE ();
 
-    preferred = find_preferred (pdata);
+    preferred = [self find_preferred:pdata];
     
     if (None == preferred) 
     {
@@ -1195,6 +1195,21 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
     if (self == nil)
 	return nil;
 
+    atoms->primary = XInternAtom (x_dpy, "PRIMARY", False);
+    atoms->clipboard = XInternAtom (x_dpy, "CLIPBOARD", False);
+    atoms->text = XInternAtom (x_dpy, "TEXT", False);
+    atoms->utf8_string = XInternAtom (x_dpy, "UTF8_STRING", False);
+    atoms->targets = XInternAtom (x_dpy, "TARGETS", False);
+    atoms->multiple = XInternAtom (x_dpy, "MULTIPLE", False);
+    atoms->cstring = XInternAtom (x_dpy, "CSTRING", False);
+    atoms->image_png = XInternAtom (x_dpy, "image/png", False);
+    atoms->image_jpeg = XInternAtom (x_dpy, "image/jpeg", False);
+    atoms->incr = XInternAtom (x_dpy, "INCR", False);
+    atoms->atom = XInternAtom (x_dpy, "ATOM", 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);
+
     _pasteboard = [[NSPasteboard generalPasteboard] retain];
 
     _known_types = [[NSArray arrayWithObject:NSStringPboardType] retain];
commit e1b5c9a3396dfbcb9ab78d554ff7de8054971965
Author: George Peter Staplin <gps at Georges-Workstation.local>
Date:   Fri Sep 19 21:28:46 2008 -0600

    XQuartz: pbproxy: Fix a bug that occured when a PICT format was available.
    We may need another branch to convert a PICT to a PNG or JPEG.  For now
    TIFF works well in all of the test image copying apps when converted to
    PNG or JPEG with an NSBitmapImageRep class.
    (cherry picked from commit adf339d8f948fc1e308dbcae38fcfce504b5b0ab)

diff --git a/hw/xquartz/pbproxy/x-selection.m b/hw/xquartz/pbproxy/x-selection.m
index fec67c8..2f35fcd 100644
--- a/hw/xquartz/pbproxy/x-selection.m
+++ b/hw/xquartz/pbproxy/x-selection.m
@@ -58,6 +58,7 @@
  * TODO:
  * 1. finish handling these pbproxy control knobs.
  * 2. handle  MULTIPLE - I need to study the ICCCM further.
+ * 3. Handle PICT images properly.
  */
 
 // These will be set by X11Controller.m once this is integrated into a server thread
@@ -550,11 +551,14 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 	    ++count;
 	}
 
-	if ([pbtypes containsObject:NSTIFFPboardType] 
-	    || [pbtypes containsObject:NSPICTPboardType])
+	/* TODO add the NSPICTPboardType back again, once we have conversion
+	 * functionality in send_image.
+	 */
+
+	if ([pbtypes containsObject:NSTIFFPboardType]) 
 	{
-	    /* We can convert a TIFF or PICT to a PNG or JPEG. */
-	    DB ("NSTIFFPboardType or NSPICTPboardType\n");
+	    /* We can convert a TIFF to a PNG or JPEG. */
+	    DB ("NSTIFFPboardType\n");
 	    list[count] = atoms->image_png;
 	    ++count;
 	    list[count] = atoms->image_jpeg;
@@ -702,6 +706,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
     NSArray *pbtypes;
     NSString *type = nil;
     NSBitmapImageFileType imagetype = /*quiet warning*/ NSPNGFileType; 
+    NSData *data;
 
     TRACE ();
 
@@ -714,8 +719,11 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 	if ([pbtypes containsObject:NSTIFFPboardType])
 	    type = NSTIFFPboardType;
 
-	if ([pbtypes containsObject:NSPICTPboardType])
+	/* PICT is not yet supported by pbproxy. 
+	 * The NSBitmapImageRep doesn't support it. 
+	else if ([pbtypes containsObject:NSPICTPboardType])
 	    type  = NSPICTPboardType;
+	*/
     }
 
     if (e->target == atoms->image_png)
@@ -724,40 +732,55 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 	imagetype = NSJPEGFileType;
         
 
-    if (type)
+    if (nil == type) 
     {
-	NSData *data;
-	data = [_pasteboard dataForType:type];
+	[self send_reply:&reply];
+	return;
+    }
 
-	if (data)
+    data = [_pasteboard dataForType:type];
+
+    if (nil == data)
+    {
+	[self send_reply:&reply];
+	return;
+    }
+	 
+    if (NSTIFFPboardType == type)
+    {
+	NSBitmapImageRep *bmimage = [[NSBitmapImageRep alloc] initWithData:data];
+	NSDictionary *dict;
+	NSData *encdata;
+
+	if (nil == bmimage) 
 	{
-	    NSBitmapImageRep *bmimage = [[NSBitmapImageRep alloc] initWithData:data];
+	    [self send_reply:&reply];
+	    return;
+	}
+
+	DB ("have valid bmimage\n");
+	
+	dict = [[NSDictionary alloc] init];
+	encdata = [bmimage representationUsingType:imagetype properties:dict];
+	if (encdata)
+	{
+	    NSUInteger length;
+	    const void *bytes;
 	    
-	    if (bmimage) 
-	    {
-		NSDictionary *dict;
-		NSData *encdata;
-		
-		dict = [[NSDictionary alloc] init];
-		encdata = [bmimage representationUsingType:imagetype properties:dict];
-		if (encdata)
-		{
-		    NSUInteger length;
-		    const void *bytes;
-
-		    length = [encdata length];
-		    bytes = [encdata bytes];
-		    		    
-		    XChangeProperty (x_dpy, e->requestor, e->property, e->target,
-				     8, PropModeReplace, bytes, length);
+	    length = [encdata length];
+	    bytes = [encdata bytes];
 		
-		    reply.xselection.property = e->property;
-		    
-		    DB ("changed property for %s\n", XGetAtomName (x_dpy, e->target));
-		}
-	    }
+	    XChangeProperty (x_dpy, e->requestor, e->property, e->target,
+				 8, PropModeReplace, bytes, length);
+	    
+	    reply.xselection.property = e->property;
+	    
+	    DB ("changed property for %s\n", XGetAtomName (x_dpy, e->target));
 	}
-    }
+	[dict release];
+	[bmimage release];
+    } 
+
     [self send_reply:&reply];
 }
 
commit 8b66db54be7a3024f830020eed34c4d19828e0ff
Author: George Peter Staplin <gps at Georges-Workstation.local>
Date:   Fri Sep 19 14:29:37 2008 -0600

    XQuartz: pbproxy: Make the proxy handle copy request races, and PRIMARY
    INCR transfers mixed with a CLIPBOARD change.
    
    Fix a bug with some UTF-8 transfers.  I can only guess that my UTF-8
    tests before were inadequate.  I can now copy/paste any characters between
    uxterm and Textedit.app.
    (cherry picked from commit 7ca1532e8e6e2c733c9c508eee0de73d09ecb947)

diff --git a/hw/xquartz/pbproxy/x-selection.h b/hw/xquartz/pbproxy/x-selection.h
index 4ef265d..5e23398 100644
--- a/hw/xquartz/pbproxy/x-selection.h
+++ b/hw/xquartz/pbproxy/x-selection.h
@@ -67,6 +67,18 @@ struct propdata {
         Window requestor;
         Atom selection;
     } pending;
+
+    /* 
+     * This is the number of times the user has requested a copy.
+     * Once the copy is completed, we --pending_copy, and if the 
+     * pending_copy is > 0 we do it again.
+     */
+    int pending_copy;
+    /* 
+     * This is used for the same purpose as pending_copy, but for the 
+     * CLIPBOARD.  It also prevents a race with INCR transfers.
+     */
+    int pending_clipboard; 
 }
 
 - (void) x_active:(Time)timestamp;
@@ -82,7 +94,7 @@ struct propdata {
 - (void) claim_clipboard;
 - (void) set_clipboard_manager;
 - (void) own_clipboard;
-
+- (void) copy_completed:(Atom)selection;
 @end
 
 #endif /* X_SELECTION_H */
diff --git a/hw/xquartz/pbproxy/x-selection.m b/hw/xquartz/pbproxy/x-selection.m
index 789e801..fec67c8 100644
--- a/hw/xquartz/pbproxy/x-selection.m
+++ b/hw/xquartz/pbproxy/x-selection.m
@@ -58,8 +58,6 @@
  * TODO:
  * 1. finish handling these pbproxy control knobs.
  * 2. handle  MULTIPLE - I need to study the ICCCM further.
- * 3. handle COMPOUND_TEXT (if possible) - it's a variant of iso2022 from 
- * what I've read.
  */
 
 // These will be set by X11Controller.m once this is integrated into a server thread
@@ -331,9 +329,8 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 	DB ("changed pasteboard!\n");
 	changeCount = countNow;
 
-	/*HMM should we pass CurrentTime instead?*/
-	XSetSelectionOwner (x_dpy, atoms->primary, _selection_window, timestamp);
-	XSetSelectionOwner (x_dpy, atoms->clipboard, _selection_window, timestamp);
+	XSetSelectionOwner (x_dpy, atoms->primary, _selection_window, CurrentTime);
+	[self own_clipboard];
     }
 
 #if 0
@@ -357,23 +354,17 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 /* Called when X11 loses key focus */
 - (void) x_inactive:(Time)timestamp
 {
-    Window w;
-
     TRACE ();
-#if 0
-    if (_proxied_selection == XA_PRIMARY)
-      return;
-
-    w = XGetSelectionOwner (x_dpy, atoms->clipboard);
+}
 
-    if (w != None && w != _selection_window)
-    {
-	/* An X client has the selection, proxy it to the pasteboard */
+/* This requests the TARGETS list from the PRIMARY selection owner. */
+- (void) x_copy_request_targets
+{
+    TRACE ();
 
-	_my_last_change = [_pasteboard declareTypes:_known_types owner:self];
-	_proxied_selection = atoms->clipboard;
-    }
-#endif
+    request_atom = atoms->targets;
+    XConvertSelection (x_dpy, atoms->primary, atoms->targets,
+		       atoms->primary, _selection_window, CurrentTime);
 }
 
 /* Called when the Edit/Copy item on the main X11 menubar is selected
@@ -388,10 +379,15 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 
     if (None != w)
     {
-	DB ("requesting targets\n");
-	request_atom = atoms->targets;
-	XConvertSelection (x_dpy, atoms->primary, atoms->targets,
-			   atoms->primary, _selection_window, CurrentTime);
+	++pending_copy;
+	
+	if (1 == pending_copy) {
+	    /*
+	     * There are no other copy operations in progress, so we
+	     * can proceed safely.
+	     */	    
+	    [self x_copy_request_targets];
+	}
     }
     else
     {
@@ -432,9 +428,13 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 	/* 
 	 * We lost ownership of the CLIPBOARD.
 	 */
-	
+	++pending_clipboard;
 
-	[self claim_clipboard];
+	if (1 == pending_clipboard) 
+	{
+	    /* Claim the clipboard contents from the new owner. */
+	    [self claim_clipboard];
+	}
     } 
     else if (atoms->clipboard_manager == e->selection)
     {
@@ -443,7 +443,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 	 * b) we can print a message and exit.  Ideally we would popup a message box.
 	 */
 	fprintf (stderr, "error: another clipboard manager was started!\n"); 
-	exit (EXIT_FAILURE);
+	//exit (EXIT_FAILURE);
     }
 }
 
@@ -458,7 +458,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 
     if (NO == pbproxy_clipboard_to_pasteboard)
 	return;
-
+    
     owner = XGetSelectionOwner (x_dpy, atoms->clipboard);
     if (None == owner)
     {
@@ -467,7 +467,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 	 * Set pbproxy's _selection_window as the owner, and continue.
 	 */
 	DB ("No clipboard owner.\n");
-	[self own_clipboard];
+	[self copy_completed:atoms->clipboard];
 	return;
     }
     
@@ -511,7 +511,10 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
      * We are supposed to use an empty event mask, and not propagate
      * the event, according to the ICCCM.
      */
+    DB ("reply->xselection.requestor 0x%lx\n", reply->xselection.requestor);
+  
     XSendEvent (x_dpy, reply->xselection.requestor, False, 0, reply);
+    XFlush (x_dpy);
 }
 
 /* 
@@ -598,22 +601,26 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 		 * We don't want the UTF-8 string length here.  
 		 * We want the length in bytes.
 		 */
-		length = [data lengthOfBytesUsingEncoding:NSASCIIStringEncoding];
-		DB ("UTF-8\n");
+		length = strlen (bytes);
+
+		if (length < 50) {
+		    DB ("UTF-8: %s\n", bytes);
+		    DB ("UTF-8 length: %u\n", length); 
+		}
 	    } 
 	    else 
 	    {
 		DB ("Latin-1\n");
 		bytes = [data cStringUsingEncoding:NSISOLatin1StringEncoding];
-		length = [data lengthOfBytesUsingEncoding:NSASCIIStringEncoding];
+		length = strlen (bytes);
 	    }
 
+	    DB ("e->target %s\n", XGetAtomName (x_dpy, e->target));
+
 	    XChangeProperty (x_dpy, e->requestor, e->property, e->target,
 			     8, PropModeReplace, (unsigned char *) bytes, length);
 	    
 	    reply.xselection.property = e->property;
-
-	    /*Should we [data release] here?*/
  	}
     }
 
@@ -671,6 +678,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
     [self send_reply:&reply];
 }
 
+/* Finding a test application that uses MULTIPLE has proven to be difficult. */
 - (void) send_multiple:(XSelectionRequestEvent *)e
 {
     XEvent reply;
@@ -831,10 +839,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
  
     if (None == e->property) {
 	DB ("e->property is None.\n");
-
-	if (pbproxy_clipboard_to_pasteboard && e->selection == atoms->clipboard)
-	    [self own_clipboard];
-	
+	[self copy_completed:e->selection];
 	/* Nothing is selected. */
 	return;
     }
@@ -853,13 +858,10 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 	if (get_property (e->requestor, e->property, &pdata, /*Delete*/ True, &type)) 
 	{
 	    /* 
-	     * The get_property error could have occured with the clipboard atom.
-	     * Greedily own the clipboard again.
+	     * An error occured, so we should invoke the copy_completed:, but
+	     * not handle_selection:type:propdata:
 	     */
-
-	    if (pbproxy_clipboard_to_pasteboard && e->selection == atoms->clipboard)
-		[self own_clipboard];
-	    
+	    [self copy_completed:e->selection];
 	    return;
 	}
 
@@ -867,26 +869,21 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 
 	pending.requestor = e->requestor;
 	pending.selection = e->selection;
+
+	DB ("set pending.requestor to 0x%lx\n", pending.requestor);
     }
     else
     {
 	if (get_property (e->requestor, e->property, &pdata, /*Delete*/ True, &type))
 	{
+	    [self copy_completed:e->selection];
 	    return;
 	}
 
 	/* We have the complete selection data.*/
-	[self handle_selection: e->selection type:type propdata:&pdata];
-
+	[self handle_selection:e->selection type:type propdata:&pdata];
+	
 	DB ("handled selection with the first notify_event\n");
-
-	/* 
-	 * This may have been the end of the clipboard request from [self claim_clipboard].
-	 * If so, then we should own the contents now.
-	 */
-
-	if (pbproxy_clipboard_to_pasteboard && e->selection == atoms->clipboard)
-	    [self own_clipboard];
     }
 }
 
@@ -909,9 +906,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 
 	if (get_property (e->window, e->atom, &pdata, /*Delete*/ True, &type))
         {
-	    if (pbproxy_clipboard_to_pasteboard && pending.selection == atoms->clipboard)
-		[self own_clipboard];
-    
+	    [self copy_completed:pending.selection];
 	    [self release_pending];
 	    return;
 	}
@@ -920,19 +915,15 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 	{
 	    /* We completed the transfer. */
 	    [self handle_selection:pending.selection type:type propdata:&pending.propdata];
-	   
-	    if (pbproxy_clipboard_to_pasteboard && pending.selection == atoms->clipboard)
-		[self own_clipboard];
-
 	    pending.propdata = null_propdata;
 	    pending.requestor = None;
 	    pending.selection = None;
 	} 
 	else 
 	{
-	    [self append_to_pending: &pdata requestor: e->window];
+	    [self append_to_pending:&pdata requestor:e->window];
 	}       
-    } 
+    }
 }
 
 - (void) handle_targets: (Atom)selection propdata:(struct propdata *)pdata
@@ -1056,6 +1047,8 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
     NSString *string; 
     NSArray *pbtypes;
 
+    TRACE ();
+
     string = [[NSString alloc] initWithBytes:pdata->data length:pdata->length encoding:NSISOLatin1StringEncoding];
     
     if (nil == string)
@@ -1074,9 +1067,11 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 }
 
 /* This is called when the selection is completely retrieved from another client. */
-/* Warning: this frees the propdata in most cases. */
+/* Warning: this frees the propdata. */
 - (void) handle_selection:(Atom)selection type:(Atom)type propdata:(struct propdata *)pdata
 {
+    TRACE ();
+
     if (request_atom == atoms->targets && type == atoms->atom)
     {
 	[self handle_targets:selection propdata:pdata];
@@ -1100,28 +1095,66 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
  
     free_propdata(pdata);
     
-    if (selection == atoms->clipboard)
+    [self copy_completed:selection];
+}
+
+- (void) copy_completed:(Atom)selection
+{
+    TRACE ();
+    
+    DB ("copy_completed: %s\n", XGetAtomName (x_dpy, selection));
+
+    if (selection == atoms->primary && pending_copy > 0)
     {
-	/* We greedily take the CLIPBOARD selection whenever it changes. */
-	XSetSelectionOwner (x_dpy, atoms->clipboard, _selection_window,
-			    CurrentTime);
+	--pending_copy;
+	if (pending_copy > 0)
+	{
+	    /* Copy PRIMARY again. */
+	    [self x_copy_request_targets];
+	    return;
+	}
+    }
+    else if (selection == atoms->clipboard && pending_clipboard > 0) 
+    {
+	--pending_clipboard;
+	if (pending_clipboard > 0) 
+	{
+	    /* Copy CLIPBOARD. */
+	    [self claim_clipboard];
+	    return;
+	} 
+	else 
+	{
+	    /* We got the final data.  Now set pbproxy as the owner. */
+	    [self own_clipboard];
+	    return;
+	}
+    }
+    
+    /* 
+     * We had 1 or more primary in progress, and the clipboard arrived
+     * while we were busy. 
+     */
+    if (pending_clipboard > 0)
+    {
+	[self claim_clipboard];
     }
 }
 
 
 /* NSPasteboard-required methods */
 
-- (void)paste:(id)sender
+- (void) paste:(id)sender
 {
     TRACE ();
 }
 
-- (void)pasteboard:(NSPasteboard *)pb provideDataForType:(NSString *)type
+- (void) pasteboard:(NSPasteboard *)pb provideDataForType:(NSString *)type
 {
     TRACE ();
 }
 
-- (void)pasteboardChangedOwner:(NSPasteboard *)pb
+- (void) pasteboardChangedOwner:(NSPasteboard *)pb
 {
     TRACE ();
 
@@ -1156,6 +1189,9 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
     pending.requestor = None;
     pending.selection = None;
 
+    pending_copy = 0;
+    pending_clipboard = 0;
+
     return self;
 }
 
commit d5ba8a5ca16840177cedca67206a890942e4457a
Author: Jeremy Huddleston <jeremyhu at freedesktop.org>
Date:   Fri Sep 19 13:15:07 2008 -0700

    XQuartz: "Disable" the text when syncing is disabled.
    (cherry picked from commit 7713d7ab66e74b212a6c0d634a3ad82373e178db)

diff --git a/hw/xquartz/X11Controller.m b/hw/xquartz/X11Controller.m
index db7ca2d..bbc5fd1 100644
--- a/hw/xquartz/X11Controller.m
+++ b/hw/xquartz/X11Controller.m
@@ -641,9 +641,9 @@ objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
     [sync_clipboard_to_pasteboard setEnabled:pbproxy_active];
     [sync_primary_immediately setEnabled:pbproxy_active];
 
-    // This doesn't seem to work.
-    [sync_text1 setEnabled:pbproxy_active];
-    [sync_text2 setEnabled:pbproxy_active];
+    // setEnabled doesn't do this...
+    [sync_text1 setTextColor:pbproxy_active ? [NSColor controlTextColor] : [NSColor disabledControlTextColor]];
+    [sync_text2 setTextColor:pbproxy_active ? [NSColor controlTextColor] : [NSColor disabledControlTextColor]];
     
     /* after adding prefs here, also add to [X11Application read_defaults]
      and prefs_show */
@@ -696,9 +696,9 @@ objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
     [sync_clipboard_to_pasteboard setEnabled:pbproxy_active];
     [sync_primary_immediately setEnabled:pbproxy_active];
 
-    // This doesn't seem to work.
-    [sync_text1 setEnabled:pbproxy_active];
-    [sync_text2 setEnabled:pbproxy_active];
+    // setEnabled doesn't do this...
+    [sync_text1 setTextColor:pbproxy_active ? [NSColor controlTextColor] : [NSColor disabledControlTextColor]];
+    [sync_text2 setTextColor:pbproxy_active ? [NSColor controlTextColor] : [NSColor disabledControlTextColor]];
 
     [enable_fullscreen setIntValue:!quartzEnableRootless];
     // TODO: Add fullscreen support
commit a3095771ea6b09cb2b5734efad9ca0a18936a08f
Author: Jeremy Huddleston <jeremyhu at freedesktop.org>
Date:   Sun Sep 21 17:39:30 2008 -0700

    XQuartz: Added a preferences UI for pbproxy options.
    (cherry picked from commit d76cca5e1eae86450aa236e49a2024881d0bac01)

diff --git a/hw/xquartz/X11Application.h b/hw/xquartz/X11Application.h
index 3d06a45..ce3fa7b 100644
--- a/hw/xquartz/X11Application.h
+++ b/hw/xquartz/X11Application.h
@@ -100,4 +100,10 @@ extern int quartzHasRoot, quartzEnableRootless;
 #define PREFS_FFM                   "wm_ffm"
 #define PREFS_FOCUS_ON_NEW_WINDOW   "wm_focus_on_new_window"
 
+#define PREFS_SYNC_PB                "sync_pasteboard"
+#define PREFS_SYNC_PB_TO_CLIPBOARD   "sync_pasteboard_to_clipboard"
+#define PREFS_SYNC_PB_TO_PRIMARY     "sync_pasteboard_to_primary"
+#define PREFS_SYNC_CLIPBOARD_TO_PB   "sync_clipboard_to_pasteboard"
+#define PREFS_SYNC_PRIMARY_ON_SELECT "sync_primary_on_select"
+
 #endif /* X11APPLICATION_H */
diff --git a/hw/xquartz/X11Application.m b/hw/xquartz/X11Application.m
index 0ce4951..213d9ed 100644
--- a/hw/xquartz/X11Application.m
+++ b/hw/xquartz/X11Application.m
@@ -673,6 +673,17 @@ static NSMutableArray * cfarray_to_nsarray (CFArrayRef in) {
 	
 //    enable_stereo = [self prefs_get_boolean:@PREFS_ENABLE_STEREO
 //                     default:false];
+    
+    pbproxy_active = [self prefs_get_boolean:@PREFS_SYNC_PB
+                                     default:pbproxy_active];
+    pbproxy_pasteboard_to_clipboard = [self prefs_get_boolean:@PREFS_SYNC_PB_TO_CLIPBOARD
+                                                      default:pbproxy_pasteboard_to_clipboard];
+    pbproxy_pasteboard_to_primary = [self prefs_get_boolean:@PREFS_SYNC_PB_TO_PRIMARY
+                                                    default:pbproxy_pasteboard_to_primary];
+    pbproxy_clipboard_to_pasteboard = [self prefs_get_boolean:@PREFS_SYNC_CLIPBOARD_TO_PB
+                                                      default:pbproxy_clipboard_to_pasteboard];
+    pbproxy_primary_on_grab = [self prefs_get_boolean:@PREFS_SYNC_PRIMARY_ON_SELECT
+                                              default:pbproxy_primary_on_grab];
 }
 
 /* This will end up at the end of the responder chain. */
diff --git a/hw/xquartz/X11Controller.h b/hw/xquartz/X11Controller.h
index c6c7194..a3e2086 100644
--- a/hw/xquartz/X11Controller.h
+++ b/hw/xquartz/X11Controller.h
@@ -49,6 +49,13 @@
     IBOutlet NSButton *focus_on_new_window;
     IBOutlet NSButton *enable_auth;
     IBOutlet NSButton *enable_tcp;
+    IBOutlet NSButton *sync_pasteboard;
+    IBOutlet NSButton *sync_pasteboard_to_clipboard;
+    IBOutlet NSButton *sync_pasteboard_to_primary;
+    IBOutlet NSButton *sync_clipboard_to_pasteboard;
+    IBOutlet NSButton *sync_primary_immediately;
+    IBOutlet NSTextField *sync_text1;
+    IBOutlet NSTextField *sync_text2;
     IBOutlet NSPopUpButton *depth;
 
     IBOutlet NSMenuItem *x11_about_item;
@@ -56,6 +63,7 @@
     IBOutlet NSMenuItem *dock_window_separator;
     IBOutlet NSMenuItem *apps_separator;
     IBOutlet NSMenuItem *toggle_fullscreen_item;
+    IBOutlet NSMenuItem *copy_menu_item;
     IBOutlet NSMenu *dock_apps_menu;
     IBOutlet NSTableView *apps_table;
 
diff --git a/hw/xquartz/X11Controller.m b/hw/xquartz/X11Controller.m
index 3c12ea7..db7ca2d 100644
--- a/hw/xquartz/X11Controller.m
+++ b/hw/xquartz/X11Controller.m
@@ -54,6 +54,13 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 
+// This will live in pbproxy/x-selection.m when we integrage that into a server thread... for now, living here for testing the UI.
+int pbproxy_active = YES;
+int pbproxy_primary_on_grab = NO; // This is provided as an option for people who want it and has issues that won't ever be addressed to make it *always* work
+int pbproxy_clipboard_to_pasteboard = YES;
+int pbproxy_pasteboard_to_primary = YES;
+int pbproxy_pasteboard_to_clipboard = YES;
+
 @implementation X11Controller
 
 - (void) awakeFromNib
@@ -622,9 +629,24 @@ objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
     quartzUseSysBeep = [use_sysbeep intValue];
     X11EnableKeyEquivalents = [enable_keyequivs intValue];
     darwinSyncKeymap = [sync_keymap intValue];
+
+    pbproxy_active = [sync_pasteboard intValue];
+    pbproxy_pasteboard_to_clipboard = [sync_pasteboard_to_clipboard intValue];
+    pbproxy_pasteboard_to_primary = [sync_pasteboard_to_primary intValue];
+    pbproxy_clipboard_to_pasteboard = [sync_clipboard_to_pasteboard intValue];
+    pbproxy_primary_on_grab = [sync_primary_immediately intValue];
+
+    [sync_pasteboard_to_clipboard setEnabled:pbproxy_active];
+    [sync_pasteboard_to_primary setEnabled:pbproxy_active];
+    [sync_clipboard_to_pasteboard setEnabled:pbproxy_active];
+    [sync_primary_immediately setEnabled:pbproxy_active];
+
+    // This doesn't seem to work.
+    [sync_text1 setEnabled:pbproxy_active];
+    [sync_text2 setEnabled:pbproxy_active];
     
     /* after adding prefs here, also add to [X11Application read_defaults]
-     and below */
+     and prefs_show */
 	
     [NSApp prefs_set_boolean:@PREFS_FAKEBUTTONS value:darwinFakeButtons];
     [NSApp prefs_set_boolean:@PREFS_SYSBEEP value:quartzUseSysBeep];
@@ -636,6 +658,12 @@ objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
     [NSApp prefs_set_boolean:@PREFS_NO_AUTH value:![enable_auth intValue]];
     [NSApp prefs_set_boolean:@PREFS_NO_TCP value:![enable_tcp intValue]];
     [NSApp prefs_set_integer:@PREFS_DEPTH value:[depth selectedTag]];
+
+    [NSApp prefs_set_integer:@PREFS_SYNC_PB value:pbproxy_active];
+    [NSApp prefs_set_integer:@PREFS_SYNC_PB_TO_CLIPBOARD value:pbproxy_pasteboard_to_clipboard];
+    [NSApp prefs_set_integer:@PREFS_SYNC_PB_TO_PRIMARY value:pbproxy_pasteboard_to_primary];
+    [NSApp prefs_set_integer:@PREFS_SYNC_CLIPBOARD_TO_PB value:pbproxy_clipboard_to_pasteboard];
+    [NSApp prefs_set_integer:@PREFS_SYNC_PRIMARY_ON_SELECT value:pbproxy_primary_on_grab];
     
     system("killall -HUP quartz-wm");
 	
@@ -656,7 +684,22 @@ objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
     [enable_tcp setIntValue:![NSApp prefs_get_boolean:@PREFS_NO_TCP default:NO]];
 
     [depth selectItemAtIndex:[depth indexOfItemWithTag:[NSApp prefs_get_integer:@PREFS_DEPTH default:-1]]];
-	
+    
+    [sync_pasteboard setIntValue:pbproxy_active];
+    [sync_pasteboard_to_clipboard setIntValue:pbproxy_pasteboard_to_clipboard];
+    [sync_pasteboard_to_primary setIntValue:pbproxy_pasteboard_to_primary];
+    [sync_clipboard_to_pasteboard setIntValue:pbproxy_clipboard_to_pasteboard];
+    [sync_primary_immediately setIntValue:pbproxy_primary_on_grab];
+
+    [sync_pasteboard_to_clipboard setEnabled:pbproxy_active];
+    [sync_pasteboard_to_primary setEnabled:pbproxy_active];
+    [sync_clipboard_to_pasteboard setEnabled:pbproxy_active];
+    [sync_primary_immediately setEnabled:pbproxy_active];
+
+    // This doesn't seem to work.
+    [sync_text1 setEnabled:pbproxy_active];
+    [sync_text2 setEnabled:pbproxy_active];
+
     [enable_fullscreen setIntValue:!quartzEnableRootless];
     // TODO: Add fullscreen support
     [enable_fullscreen setEnabled:NO];
@@ -677,9 +720,11 @@ objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row
 - (OSX_BOOL) validateMenuItem:(NSMenuItem *)item
 {
   NSMenu *menu = [item menu];
-	
+    
   if (item == toggle_fullscreen_item)
     return !quartzEnableRootless;
+  else   if (item == copy_menu_item) // For some reason, this isn't working...
+      return NO;
   else if (menu == [window_separator menu] || menu == dock_menu
 	   || (menu == [x11_about_item menu] && [item tag] == 42))
     return (AppleWMSelectedEvents () & AppleWMControllerNotifyMask) != 0;
diff --git a/hw/xquartz/bundle/Resources/English.lproj/main.nib/designable.nib b/hw/xquartz/bundle/Resources/English.lproj/main.nib/designable.nib
index 76148da..7490e0f 100644
--- a/hw/xquartz/bundle/Resources/English.lproj/main.nib/designable.nib
+++ b/hw/xquartz/bundle/Resources/English.lproj/main.nib/designable.nib
@@ -1,19 +1,29 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.02">
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.03">
 	<data>
 		<int key="IBDocument.SystemTarget">1050</int>
-		<string key="IBDocument.SystemVersion">9F30</string>
-		<string key="IBDocument.InterfaceBuilderVersion">670</string>
+		<string key="IBDocument.SystemVersion">9F33</string>
+		<string key="IBDocument.InterfaceBuilderVersion">674</string>
 		<string key="IBDocument.AppKitVersion">949.34</string>
 		<string key="IBDocument.HIToolboxVersion">352.00</string>
 		<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
 			<bool key="EncodedWithXMLCoder">YES</bool>
-			<integer value="286"/>
+			<integer value="57"/>
+			<integer value="348"/>
 		</object>
 		<object class="NSArray" key="IBDocument.PluginDependencies">
 			<bool key="EncodedWithXMLCoder">YES</bool>
 			<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 		</object>
+		<object class="NSMutableDictionary" key="IBDocument.Metadata">
+			<bool key="EncodedWithXMLCoder">YES</bool>
+			<object class="NSArray" key="dict.sortedKeys">
+				<bool key="EncodedWithXMLCoder">YES</bool>
+			</object>
+			<object class="NSMutableArray" key="dict.values">
+				<bool key="EncodedWithXMLCoder">YES</bool>
+			</object>
+		</object>
 		<object class="NSMutableArray" key="IBDocument.RootObjects" id="904585544">
 			<bool key="EncodedWithXMLCoder">YES</bool>
 			<object class="NSCustomObject" id="815810918">
@@ -230,44 +240,6 @@
 							<string key="NSTitle">Edit</string>
 							<object class="NSMutableArray" key="NSMenuItems">
 								<bool key="EncodedWithXMLCoder">YES</bool>
-								<object class="NSMenuItem" id="1010221707">
-									<reference key="NSMenu" ref="526778998"/>
-									<string key="NSTitle">Undo</string>
-									<string key="NSKeyEquiv">z</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="531645050"/>
-									<reference key="NSMixedImage" ref="351811234"/>
-								</object>
-								<object class="NSMenuItem" id="535038564">
-									<reference key="NSMenu" ref="526778998"/>
-									<string key="NSTitle">Redo</string>
-									<string key="NSKeyEquiv">Z</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="531645050"/>
-									<reference key="NSMixedImage" ref="351811234"/>
-								</object>
-								<object class="NSMenuItem" id="839739619">
-									<reference key="NSMenu" ref="526778998"/>
-									<bool key="NSIsDisabled">YES</bool>
-									<bool key="NSIsSeparator">YES</bool>
-									<string key="NSTitle"/>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="531645050"/>
-									<reference key="NSMixedImage" ref="351811234"/>
-								</object>
-								<object class="NSMenuItem" id="581727829">
-									<reference key="NSMenu" ref="526778998"/>
-									<string key="NSTitle">Cut</string>
-									<string key="NSKeyEquiv">x</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="531645050"/>
-									<reference key="NSMixedImage" ref="351811234"/>
-								</object>
 								<object class="NSMenuItem" id="185296989">
 									<reference key="NSMenu" ref="526778998"/>
 									<string key="NSTitle">Copy</string>
@@ -277,33 +249,6 @@
 									<reference key="NSOnImage" ref="531645050"/>
 									<reference key="NSMixedImage" ref="351811234"/>
 								</object>
-								<object class="NSMenuItem" id="924678073">
-									<reference key="NSMenu" ref="526778998"/>
-									<string key="NSTitle">Paste</string>
-									<string key="NSKeyEquiv">v</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="531645050"/>
-									<reference key="NSMixedImage" ref="351811234"/>
-								</object>
-								<object class="NSMenuItem" id="994817848">
-									<reference key="NSMenu" ref="526778998"/>
-									<string key="NSTitle">Delete</string>
-									<string key="NSKeyEquiv"/>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="531645050"/>
-									<reference key="NSMixedImage" ref="351811234"/>
-								</object>
-								<object class="NSMenuItem" id="322866464">
-									<reference key="NSMenu" ref="526778998"/>
-									<string key="NSTitle">Select All</string>
-									<string key="NSKeyEquiv">a</string>
-									<int key="NSKeyEquivModMask">1048576</int>
-									<int key="NSMnemonicLoc">2147483647</int>
-									<reference key="NSOnImage" ref="531645050"/>
-									<reference key="NSMixedImage" ref="351811234"/>
-								</object>
 							</object>
 						</object>
 					</object>
@@ -447,7 +392,7 @@
 			<object class="NSWindowTemplate" id="124913468">
 				<int key="NSWindowStyleMask">3</int>
 				<int key="NSWindowBacking">2</int>
-				<string key="NSWindowRect">{{266, 392}, {484, 280}}</string>
+				<string key="NSWindowRect">{{266, 364}, {484, 308}}</string>
 				<int key="NSWTFlags">1350041600</int>
 				<string key="NSWindowTitle">X11 Preferences</string>
 				<string key="NSWindowClass">NSPanel</string>
@@ -457,14 +402,14 @@
 				<string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string>
 				<string key="NSWindowContentMinSize">{320, 240}</string>
 				<object class="NSView" key="NSWindowView" id="941366957">
-					<nil key="NSNextResponder"/>
+					<reference key="NSNextResponder"/>
 					<int key="NSvFlags">256</int>
 					<object class="NSMutableArray" key="NSSubviews">
 						<bool key="EncodedWithXMLCoder">YES</bool>
 						<object class="NSTabView" id="448510093">
 							<reference key="NSNextResponder" ref="941366957"/>
 							<int key="NSvFlags">256</int>
-							<string key="NSFrame">{{13, 10}, {458, 264}}</string>
+							<string key="NSFrame">{{13, 10}, {458, 292}}</string>
 							<reference key="NSSuperview" ref="941366957"/>
 							<object class="NSMutableArray" key="NSTabViewItems">
 								<bool key="EncodedWithXMLCoder">YES</bool>
@@ -480,7 +425,7 @@
 											<object class="NSButton" id="119157981">
 												<reference key="NSNextResponder" ref="596750588"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{18, 182}, {402, 18}}</string>
+												<string key="NSFrame">{{18, 210}, {402, 18}}</string>
 												<reference key="NSSuperview" ref="596750588"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSButtonCell" key="NSCell" id="990762273">
@@ -507,7 +452,7 @@
 											<object class="NSTextField" id="443008216">
 												<reference key="NSNextResponder" ref="596750588"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{36, 32}, {385, 31}}</string>
+												<string key="NSFrame">{{36, 60}, {385, 31}}</string>
 												<reference key="NSSuperview" ref="596750588"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSTextFieldCell" key="NSCell" id="391919450">
@@ -543,7 +488,7 @@
 											<object class="NSTextField" id="282885445">
 												<reference key="NSNextResponder" ref="596750588"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{36, 134}, {385, 42}}</string>
+												<string key="NSFrame">{{36, 162}, {385, 42}}</string>
 												<reference key="NSSuperview" ref="596750588"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSTextFieldCell" key="NSCell" id="649334366">
@@ -560,7 +505,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSButton" id="842100515">
 												<reference key="NSNextResponder" ref="596750588"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{18, 69}, {402, 18}}</string>
+												<string key="NSFrame">{{18, 97}, {402, 18}}</string>
 												<reference key="NSSuperview" ref="596750588"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSButtonCell" key="NSCell" id="940564599">
@@ -581,7 +526,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSTextField" id="31160162">
 												<reference key="NSNextResponder" ref="596750588"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{36, 98}, {385, 14}}</string>
+												<string key="NSFrame">{{36, 126}, {385, 14}}</string>
 												<reference key="NSSuperview" ref="596750588"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSTextFieldCell" key="NSCell" id="666057093">
@@ -597,7 +542,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSButton" id="179949713">
 												<reference key="NSNextResponder" ref="596750588"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{18, 118}, {402, 18}}</string>
+												<string key="NSFrame">{{18, 146}, {402, 18}}</string>
 												<reference key="NSSuperview" ref="596750588"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSButtonCell" key="NSCell" id="967619578">
@@ -616,7 +561,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 												</object>
 											</object>
 										</object>
-										<string key="NSFrame">{{10, 33}, {438, 218}}</string>
+										<string key="NSFrame">{{10, 33}, {438, 246}}</string>
 										<reference key="NSSuperview" ref="448510093"/>
 									</object>
 									<string key="NSLabel">Input</string>
@@ -635,7 +580,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSButton" id="418227126">
 												<reference key="NSNextResponder" ref="515308735"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{18, 55}, {402, 18}}</string>
+												<string key="NSFrame">{{18, 83}, {402, 18}}</string>
 												<reference key="NSSuperview" ref="515308735"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSButtonCell" key="NSCell" id="1016069354">
@@ -656,7 +601,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSTextField" id="1039016593">
 												<reference key="NSNextResponder" ref="515308735"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{36, 21}, {385, 28}}</string>
+												<string key="NSFrame">{{36, 49}, {385, 28}}</string>
 												<reference key="NSSuperview" ref="515308735"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSTextFieldCell" key="NSCell" id="624655599">
@@ -672,7 +617,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSPopUpButton" id="709074847">
 												<reference key="NSNextResponder" ref="515308735"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{74, 174}, {128, 26}}</string>
+												<string key="NSFrame">{{74, 202}, {128, 26}}</string>
 												<reference key="NSSuperview" ref="515308735"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSPopUpButtonCell" key="NSCell" id="633115429">
@@ -763,7 +708,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSTextField" id="201731424">
 												<reference key="NSNextResponder" ref="515308735"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{17, 177}, {55, 20}}</string>
+												<string key="NSFrame">{{17, 205}, {55, 20}}</string>
 												<reference key="NSSuperview" ref="515308735"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSTextFieldCell" key="NSCell" id="930265681">
@@ -779,7 +724,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSTextField" id="86150604">
 												<reference key="NSNextResponder" ref="515308735"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{36, 155}, {392, 14}}</string>
+												<string key="NSFrame">{{36, 183}, {392, 14}}</string>
 												<reference key="NSSuperview" ref="515308735"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSTextFieldCell" key="NSCell" id="311969422">
@@ -795,7 +740,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSButton" id="477203622">
 												<reference key="NSNextResponder" ref="515308735"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{18, 121}, {409, 23}}</string>
+												<string key="NSFrame">{{18, 149}, {409, 23}}</string>
 												<reference key="NSSuperview" ref="515308735"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSButtonCell" key="NSCell" id="631531164">
@@ -816,7 +761,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSTextField" id="298603383">
 												<reference key="NSNextResponder" ref="515308735"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{36, 84}, {385, 31}}</string>
+												<string key="NSFrame">{{36, 112}, {385, 31}}</string>
 												<reference key="NSSuperview" ref="515308735"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSTextFieldCell" key="NSCell" id="761107402">
@@ -830,12 +775,183 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 												</object>
 											</object>
 										</object>
-										<string key="NSFrame">{{10, 33}, {438, 218}}</string>
+										<string key="NSFrame">{{10, 33}, {438, 246}}</string>
 									</object>
 									<string key="NSLabel">Output</string>
 									<reference key="NSColor" ref="57160303"/>
 									<reference key="NSTabView" ref="448510093"/>
 								</object>
+								<object class="NSTabViewItem" id="723450037">
+									<object class="NSMutableString" key="NSIdentifier">
+										<characters key="NS.bytes">2</characters>
+									</object>
+									<object class="NSView" key="NSView" id="408298283">
+										<nil key="NSNextResponder"/>
+										<int key="NSvFlags">256</int>
+										<object class="NSMutableArray" key="NSSubviews">
+											<bool key="EncodedWithXMLCoder">YES</bool>
+											<object class="NSButton" id="878106058">
+												<reference key="NSNextResponder" ref="408298283"/>
+												<int key="NSvFlags">256</int>
+												<string key="NSFrame">{{18, 222}, {409, 23}}</string>
+												<reference key="NSSuperview" ref="408298283"/>
+												<bool key="NSEnabled">YES</bool>
+												<object class="NSButtonCell" key="NSCell" id="718083688">
+													<int key="NSCellFlags">67239424</int>
+													<int key="NSCellFlags2">0</int>
+													<string key="NSContents">Enable syncing</string>
+													<reference key="NSSupport" ref="463863101"/>
+													<reference key="NSControlView" ref="878106058"/>
+													<int key="NSButtonFlags">1211912703</int>
+													<int key="NSButtonFlags2">2</int>
+													<reference key="NSAlternateImage" ref="391434389"/>
+													<string key="NSAlternateContents"/>
+													<string key="NSKeyEquivalent"/>
+													<int key="NSPeriodicDelay">200</int>
+													<int key="NSPeriodicInterval">25</int>
+												</object>
+											</object>
+											<object class="NSTextField" id="386152084">
+												<reference key="NSNextResponder" ref="408298283"/>
+												<int key="NSvFlags">256</int>
+												<string key="NSFrame">{{36, 188}, {385, 28}}</string>
+												<reference key="NSSuperview" ref="408298283"/>
+												<bool key="NSEnabled">YES</bool>
+												<object class="NSTextFieldCell" key="NSCell" id="572508492">
+													<int key="NSCellFlags">67239424</int>
+													<int key="NSCellFlags2">4194304</int>
+													<string type="base64-UTF8" key="NSContents">RW5hYmxlcyB0aGUgImNvcHkiIG1lbnUgaXRlbSBhbmQgYWxsb3dzIGZvciBzeW5jaW5nIGJldHdlZW4g
+dGhlIE9TWCBQYXN0ZWJvYXJkIGFuZCB0aGUgWDExIENMSVBCT0FSRCBhbmQgUFJJTUFSWSBidWZmZXJz
+Lg</string>
+													<reference key="NSSupport" ref="26"/>
+													<reference key="NSControlView" ref="386152084"/>
+													<reference key="NSBackgroundColor" ref="57160303"/>
+													<reference key="NSTextColor" ref="930815747"/>
+												</object>
+											</object>
+											<object class="NSButton" id="477050998">
+												<reference key="NSNextResponder" ref="408298283"/>
+												<int key="NSvFlags">256</int>
+												<string key="NSFrame">{{34, 96}, {409, 23}}</string>
+												<reference key="NSSuperview" ref="408298283"/>
+												<bool key="NSEnabled">YES</bool>
+												<object class="NSButtonCell" key="NSCell" id="501304422">
+													<int key="NSCellFlags">67239424</int>
+													<int key="NSCellFlags2">0</int>
+													<string key="NSContents">Update CLIPBOARD when Pasteboard changes.</string>
+													<reference key="NSSupport" ref="463863101"/>
+													<reference key="NSControlView" ref="477050998"/>
+													<int key="NSButtonFlags">1211912703</int>
+													<int key="NSButtonFlags2">2</int>
+													<reference key="NSAlternateImage" ref="391434389"/>
+													<string key="NSAlternateContents"/>
+													<string key="NSKeyEquivalent"/>
+													<int key="NSPeriodicDelay">200</int>
+													<int key="NSPeriodicInterval">25</int>
+												</object>
+											</object>
+											<object class="NSButton" id="765780304">
+												<reference key="NSNextResponder" ref="408298283"/>
+												<int key="NSvFlags">256</int>
+												<string key="NSFrame">{{34, 71}, {409, 23}}</string>
+												<reference key="NSSuperview" ref="408298283"/>
+												<bool key="NSEnabled">YES</bool>
+												<object class="NSButtonCell" key="NSCell" id="510771323">
+													<int key="NSCellFlags">67239424</int>
+													<int key="NSCellFlags2">0</int>
+													<string key="NSContents">Update PRIMARY (middle-click) when Pasteboard changes.</string>
+													<reference key="NSSupport" ref="463863101"/>
+													<reference key="NSControlView" ref="765780304"/>
+													<int key="NSButtonFlags">1211912703</int>
+													<int key="NSButtonFlags2">2</int>
+													<reference key="NSAlternateImage" ref="391434389"/>
+													<string key="NSAlternateContents"/>
+													<string key="NSKeyEquivalent"/>
+													<int key="NSPeriodicDelay">200</int>
+													<int key="NSPeriodicInterval">25</int>
+												</object>
+											</object>
+											<object class="NSButton" id="1002778833">
+												<reference key="NSNextResponder" ref="408298283"/>
+												<int key="NSvFlags">256</int>
+												<string key="NSFrame">{{34, 46}, {409, 23}}</string>
+												<reference key="NSSuperview" ref="408298283"/>
+												<bool key="NSEnabled">YES</bool>
+												<object class="NSButtonCell" key="NSCell" id="897099877">
+													<int key="NSCellFlags">67239424</int>
+													<int key="NSCellFlags2">0</int>
+													<string key="NSContents">Update Pasteboard immediately when new text is selected.</string>
+													<reference key="NSSupport" ref="463863101"/>
+													<reference key="NSControlView" ref="1002778833"/>
+													<int key="NSButtonFlags">1211912703</int>
+													<int key="NSButtonFlags2">2</int>
+													<reference key="NSAlternateImage" ref="391434389"/>
+													<string key="NSAlternateContents"/>
+													<string key="NSKeyEquivalent"/>
+													<int key="NSPeriodicDelay">200</int>
+													<int key="NSPeriodicInterval">25</int>
+												</object>
+											</object>
+											<object class="NSButton" id="487809555">
+												<reference key="NSNextResponder" ref="408298283"/>
+												<int key="NSvFlags">256</int>
+												<string key="NSFrame">{{34, 159}, {409, 23}}</string>
+												<reference key="NSSuperview" ref="408298283"/>
+												<bool key="NSEnabled">YES</bool>
+												<object class="NSButtonCell" key="NSCell" id="619977658">
+													<int key="NSCellFlags">67239424</int>
+													<int key="NSCellFlags2">0</int>
+													<string key="NSContents">Update Pasteboard when CLIPBOARD changes.</string>
+													<reference key="NSSupport" ref="463863101"/>
+													<reference key="NSControlView" ref="487809555"/>
+													<int key="NSButtonFlags">1211912703</int>
+													<int key="NSButtonFlags2">2</int>
+													<reference key="NSAlternateImage" ref="391434389"/>
+													<string key="NSAlternateContents"/>
+													<string key="NSKeyEquivalent"/>
+													<int key="NSPeriodicDelay">200</int>
+													<int key="NSPeriodicInterval">25</int>
+												</object>
+											</object>
+											<object class="NSTextField" id="620944856">
+												<reference key="NSNextResponder" ref="408298283"/>
+												<int key="NSvFlags">256</int>
+												<string key="NSFrame">{{48, 125}, {385, 28}}</string>
+												<reference key="NSSuperview" ref="408298283"/>
+												<bool key="NSEnabled">YES</bool>
+												<object class="NSTextFieldCell" key="NSCell" id="461823902">
+													<int key="NSCellFlags">67239424</int>
+													<int key="NSCellFlags2">4194304</int>
+													<string key="NSContents">Disable this option if you want to use xclipboard, klipper, or any other X11 clipboard manager.</string>
+													<reference key="NSSupport" ref="26"/>
+													<reference key="NSControlView" ref="620944856"/>
+													<reference key="NSBackgroundColor" ref="57160303"/>
+													<reference key="NSTextColor" ref="930815747"/>
+												</object>
+											</object>
+											<object class="NSTextField" id="522511724">
+												<reference key="NSNextResponder" ref="408298283"/>
+												<int key="NSvFlags">256</int>
+												<string key="NSFrame">{{48, 14}, {370, 28}}</string>
+												<reference key="NSSuperview" ref="408298283"/>
+												<bool key="NSEnabled">YES</bool>
+												<object class="NSTextFieldCell" key="NSCell" id="994587858">
+													<int key="NSCellFlags">67239424</int>
+													<int key="NSCellFlags2">4194304</int>
+													<string key="NSContents">Due to limitations in the X11 protocol, this option may not always work in some applications.</string>
+													<reference key="NSSupport" ref="26"/>
+													<reference key="NSControlView" ref="522511724"/>
+													<reference key="NSBackgroundColor" ref="57160303"/>
+													<reference key="NSTextColor" ref="930815747"/>
+												</object>
+											</object>
+										</object>
+										<string key="NSFrame">{{10, 33}, {438, 246}}</string>
+									</object>
+									<string key="NSLabel">Pasteboard</string>
+									<reference key="NSColor" ref="57160303"/>
+									<reference key="NSTabView" ref="448510093"/>
+								</object>
 								<object class="NSTabViewItem" id="10973343">
 									<object class="NSMutableString" key="NSIdentifier">
 										<characters key="NS.bytes">2</characters>
@@ -848,7 +964,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSButton" id="657659108">
 												<reference key="NSNextResponder" ref="184765684"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{15, 184}, {402, 18}}</string>
+												<string key="NSFrame">{{15, 212}, {402, 18}}</string>
 												<reference key="NSSuperview" ref="184765684"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSButtonCell" key="NSCell" id="259618205">
@@ -869,7 +985,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSTextField" id="290578835">
 												<reference key="NSNextResponder" ref="184765684"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{23, 147}, {385, 31}}</string>
+												<string key="NSFrame">{{23, 175}, {385, 31}}</string>
 												<reference key="NSSuperview" ref="184765684"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSTextFieldCell" key="NSCell" id="399127858">
@@ -885,7 +1001,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSButton" id="992839333">
 												<reference key="NSNextResponder" ref="184765684"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{15, 123}, {402, 18}}</string>
+												<string key="NSFrame">{{15, 151}, {402, 18}}</string>
 												<reference key="NSSuperview" ref="184765684"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSButtonCell" key="NSCell" id="959555182">
@@ -906,7 +1022,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSTextField" id="138261120">
 												<reference key="NSNextResponder" ref="184765684"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{23, 100}, {385, 17}}</string>
+												<string key="NSFrame">{{23, 128}, {385, 17}}</string>
 												<reference key="NSSuperview" ref="184765684"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSTextFieldCell" key="NSCell" id="183409141">
@@ -922,7 +1038,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSButton" id="128352289">
 												<reference key="NSNextResponder" ref="184765684"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{15, 79}, {402, 18}}</string>
+												<string key="NSFrame">{{15, 107}, {402, 18}}</string>
 												<reference key="NSSuperview" ref="184765684"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSButtonCell" key="NSCell" id="556463187">
@@ -943,7 +1059,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSTextField" id="57161931">
 												<reference key="NSNextResponder" ref="184765684"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{23, 45}, {385, 28}}</string>
+												<string key="NSFrame">{{23, 73}, {385, 28}}</string>
 												<reference key="NSSuperview" ref="184765684"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSTextFieldCell" key="NSCell" id="989804990">
@@ -957,7 +1073,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 												</object>
 											</object>
 										</object>
-										<string key="NSFrame">{{10, 33}, {438, 218}}</string>
+										<string key="NSFrame">{{10, 33}, {438, 246}}</string>
 									</object>
 									<string key="NSLabel">Windows</string>
 									<reference key="NSColor" ref="57160303"/>
@@ -972,7 +1088,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSButton" id="989050925">
 												<reference key="NSNextResponder" ref="300811574"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{18, 182}, {402, 18}}</string>
+												<string key="NSFrame">{{18, 210}, {402, 18}}</string>
 												<reference key="NSSuperview" ref="300811574"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSButtonCell" key="NSCell" id="189594322">
@@ -993,7 +1109,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSButton" id="700826966">
 												<reference key="NSNextResponder" ref="300811574"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{18, 105}, {402, 18}}</string>
+												<string key="NSFrame">{{18, 133}, {402, 18}}</string>
 												<reference key="NSSuperview" ref="300811574"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSButtonCell" key="NSCell" id="489340979">
@@ -1014,7 +1130,7 @@ IG9yIHJpZ2h0IG1vdXNlIGJ1dHRvbnMuCg</string>
 											<object class="NSTextField" id="168436707">
 												<reference key="NSNextResponder" ref="300811574"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{36, 134}, {385, 42}}</string>
+												<string key="NSFrame">{{36, 162}, {385, 42}}</string>
 												<reference key="NSSuperview" ref="300811574"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSTextFieldCell" key="NSCell" id="53243865">
@@ -1032,7 +1148,7 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 											<object class="NSTextField" id="363817195">
 												<reference key="NSNextResponder" ref="300811574"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{36, 57}, {385, 42}}</string>
+												<string key="NSFrame">{{36, 85}, {385, 42}}</string>
 												<reference key="NSSuperview" ref="300811574"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSTextFieldCell" key="NSCell" id="390084685">
@@ -1048,7 +1164,7 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 											<object class="NSTextField" id="223835729">
 												<reference key="NSNextResponder" ref="300811574"/>
 												<int key="NSvFlags">256</int>
-												<string key="NSFrame">{{20, -44}, {404, 14}}</string>
+												<string key="NSFrame">{{20, -16}, {404, 14}}</string>
 												<reference key="NSSuperview" ref="300811574"/>
 												<bool key="NSEnabled">YES</bool>
 												<object class="NSTextFieldCell" key="NSCell" id="283628678">
@@ -1062,7 +1178,7 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 												</object>
 											</object>
 										</object>
-										<string key="NSFrame">{{10, 33}, {438, 218}}</string>
+										<string key="NSFrame">{{10, 33}, {438, 246}}</string>
 									</object>
 									<string key="NSLabel">Security</string>
 									<reference key="NSColor" ref="57160303"/>
@@ -1080,10 +1196,11 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 							</object>
 						</object>
 					</object>
-					<string key="NSFrameSize">{484, 280}</string>
+					<string key="NSFrameSize">{484, 308}</string>
+					<reference key="NSSuperview"/>
 				</object>
 				<string key="NSScreenRect">{{0, 0}, {1280, 938}}</string>
-				<string key="NSMinSize">{213, 129}</string>
+				<string key="NSMinSize">{320, 262}</string>
 				<string key="NSMaxSize">{3.40282e+38, 3.40282e+38}</string>
 				<string key="NSFrameAutosaveName">x11_prefs</string>
 			</object>
@@ -1100,7 +1217,7 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 				<string key="NSWindowContentMaxSize">{3.40282e+38, 3.40282e+38}</string>
 				<string key="NSWindowContentMinSize">{320, 240}</string>
 				<object class="NSView" key="NSWindowView" id="85544634">
-					<reference key="NSNextResponder"/>
+					<nil key="NSNextResponder"/>
 					<int key="NSvFlags">256</int>
 					<object class="NSMutableArray" key="NSSubviews">
 						<bool key="EncodedWithXMLCoder">YES</bool>
@@ -1394,7 +1511,6 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 						</object>
 					</object>
 					<string key="NSFrameSize">{454, 271}</string>
-					<reference key="NSSuperview"/>
 				</object>
 				<string key="NSScreenRect">{{0, 0}, {1280, 938}}</string>
 				<string key="NSMinSize">{320, 262}</string>
@@ -1461,46 +1577,6 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 				<bool key="EncodedWithXMLCoder">YES</bool>
 				<object class="IBConnectionRecord">
 					<object class="IBActionConnection" key="connection">
-						<string key="label">cut:</string>
-						<reference key="source" ref="941939442"/>
-						<reference key="destination" ref="581727829"/>
-					</object>
-					<int key="connectionID">175</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">paste:</string>
-						<reference key="source" ref="941939442"/>
-						<reference key="destination" ref="924678073"/>
-					</object>
-					<int key="connectionID">176</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">redo:</string>
-						<reference key="source" ref="941939442"/>
-						<reference key="destination" ref="535038564"/>
-					</object>
-					<int key="connectionID">178</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">selectAll:</string>
-						<reference key="source" ref="941939442"/>
-						<reference key="destination" ref="322866464"/>
-					</object>
-					<int key="connectionID">179</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
-						<string key="label">undo:</string>
-						<reference key="source" ref="941939442"/>
-						<reference key="destination" ref="1010221707"/>
-					</object>
-					<int key="connectionID">180</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
 						<string key="label">copy:</string>
 						<reference key="source" ref="941939442"/>
 						<reference key="destination" ref="185296989"/>
@@ -1509,14 +1585,6 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 				</object>
 				<object class="IBConnectionRecord">
 					<object class="IBActionConnection" key="connection">
-						<string key="label">delete:</string>
-						<reference key="source" ref="941939442"/>
-						<reference key="destination" ref="994817848"/>
-					</object>
-					<int key="connectionID">195</int>
-				</object>
-				<object class="IBConnectionRecord">
-					<object class="IBActionConnection" key="connection">
 						<string key="label">minimize_window:</string>
 						<reference key="source" ref="485884620"/>
 						<reference key="destination" ref="677652931"/>
@@ -1939,6 +2007,110 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 					</object>
 					<int key="connectionID">300394</int>
 				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBOutletConnection" key="connection">
+						<string key="label">copy_menu_item</string>
+						<reference key="source" ref="485884620"/>
+						<reference key="destination" ref="185296989"/>
+					</object>
+					<int key="connectionID">300443</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBOutletConnection" key="connection">
+						<string key="label">sync_pasteboard</string>
+						<reference key="source" ref="485884620"/>
+						<reference key="destination" ref="878106058"/>
+					</object>
+					<int key="connectionID">300444</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBOutletConnection" key="connection">
+						<string key="label">sync_clipboard_to_pasteboard</string>
+						<reference key="source" ref="485884620"/>
+						<reference key="destination" ref="487809555"/>
+					</object>
+					<int key="connectionID">300461</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBOutletConnection" key="connection">
+						<string key="label">sync_pasteboard_to_clipboard</string>
+						<reference key="source" ref="485884620"/>
+						<reference key="destination" ref="477050998"/>
+					</object>
+					<int key="connectionID">300462</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBOutletConnection" key="connection">
+						<string key="label">sync_pasteboard_to_primary</string>
+						<reference key="source" ref="485884620"/>
+						<reference key="destination" ref="765780304"/>
+					</object>
+					<int key="connectionID">300463</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBOutletConnection" key="connection">
+						<string key="label">sync_primary_immediately</string>
+						<reference key="source" ref="485884620"/>
+						<reference key="destination" ref="1002778833"/>
+					</object>
+					<int key="connectionID">300464</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">prefs_changed:</string>
+						<reference key="source" ref="485884620"/>
+						<reference key="destination" ref="878106058"/>
+					</object>
+					<int key="connectionID">300465</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">prefs_changed:</string>
+						<reference key="source" ref="485884620"/>
+						<reference key="destination" ref="487809555"/>
+					</object>
+					<int key="connectionID">300466</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">prefs_changed:</string>
+						<reference key="source" ref="485884620"/>
+						<reference key="destination" ref="477050998"/>
+					</object>
+					<int key="connectionID">300467</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">prefs_changed:</string>
+						<reference key="source" ref="485884620"/>
+						<reference key="destination" ref="765780304"/>
+					</object>
+					<int key="connectionID">300468</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBActionConnection" key="connection">
+						<string key="label">prefs_changed:</string>
+						<reference key="source" ref="485884620"/>
+						<reference key="destination" ref="1002778833"/>
+					</object>
+					<int key="connectionID">300469</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBOutletConnection" key="connection">
+						<string key="label">sync_text1</string>
+						<reference key="source" ref="485884620"/>
+						<reference key="destination" ref="620944856"/>
+					</object>
+					<int key="connectionID">300470</int>
+				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBOutletConnection" key="connection">
+						<string key="label">sync_text2</string>
+						<reference key="source" ref="485884620"/>
+						<reference key="destination" ref="522511724"/>
+					</object>
+					<int key="connectionID">300471</int>
+				</object>
 			</object>
 			<object class="IBMutableOrderedSet" key="objectRecords">
 				<object class="NSArray" key="orderedObjects">
@@ -2161,58 +2333,16 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 						<reference key="object" ref="526778998"/>
 						<object class="NSMutableArray" key="children">
 							<bool key="EncodedWithXMLCoder">YES</bool>
-							<reference ref="839739619"/>
 							<reference ref="185296989"/>
-							<reference ref="1010221707"/>
-							<reference ref="581727829"/>
-							<reference ref="994817848"/>
-							<reference ref="924678073"/>
-							<reference ref="322866464"/>
-							<reference ref="535038564"/>
 						</object>
 						<reference key="parent" ref="200491363"/>
 					</object>
 					<object class="IBObjectRecord">
-						<int key="objectID">156</int>
-						<reference key="object" ref="839739619"/>
-						<reference key="parent" ref="526778998"/>
-					</object>
-					<object class="IBObjectRecord">
 						<int key="objectID">157</int>
 						<reference key="object" ref="185296989"/>
 						<reference key="parent" ref="526778998"/>
 					</object>
 					<object class="IBObjectRecord">
-						<int key="objectID">158</int>
-						<reference key="object" ref="1010221707"/>
-						<reference key="parent" ref="526778998"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">160</int>
-						<reference key="object" ref="581727829"/>
-						<reference key="parent" ref="526778998"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">164</int>
-						<reference key="object" ref="994817848"/>
-						<reference key="parent" ref="526778998"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">171</int>
-						<reference key="object" ref="924678073"/>
-						<reference key="parent" ref="526778998"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">172</int>
-						<reference key="object" ref="322866464"/>
-						<reference key="parent" ref="526778998"/>
-					</object>
-					<object class="IBObjectRecord">
-						<int key="objectID">173</int>
-						<reference key="object" ref="535038564"/>
-						<reference key="parent" ref="526778998"/>
-					</object>
-					<object class="IBObjectRecord">
 						<int key="objectID">269</int>
 						<reference key="object" ref="868031522"/>
 						<object class="NSMutableArray" key="children">
@@ -2298,6 +2428,7 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 							<reference ref="960678392"/>
 							<reference ref="348328898"/>
 							<reference ref="10973343"/>
+							<reference ref="723450037"/>
 						</object>
 						<reference key="parent" ref="941366957"/>
 					</object>
@@ -2959,6 +3090,143 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 						<reference key="object" ref="989804990"/>
 						<reference key="parent" ref="57161931"/>
 					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">300421</int>
+						<reference key="object" ref="723450037"/>
+						<object class="NSMutableArray" key="children">
+							<bool key="EncodedWithXMLCoder">YES</bool>
+							<reference ref="408298283"/>
+						</object>
+						<reference key="parent" ref="448510093"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">300422</int>
+						<reference key="object" ref="408298283"/>
+						<object class="NSMutableArray" key="children">
+							<bool key="EncodedWithXMLCoder">YES</bool>
+							<reference ref="878106058"/>
+							<reference ref="386152084"/>
+							<reference ref="487809555"/>
+							<reference ref="620944856"/>
+							<reference ref="477050998"/>
+							<reference ref="765780304"/>
+							<reference ref="1002778833"/>
+							<reference ref="522511724"/>
+						</object>
+						<reference key="parent" ref="723450037"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">300423</int>
+						<reference key="object" ref="386152084"/>
+						<object class="NSMutableArray" key="children">
+							<bool key="EncodedWithXMLCoder">YES</bool>
+							<reference ref="572508492"/>
+						</object>
+						<reference key="parent" ref="408298283"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">300424</int>
+						<reference key="object" ref="878106058"/>
+						<object class="NSMutableArray" key="children">
+							<bool key="EncodedWithXMLCoder">YES</bool>
+							<reference ref="718083688"/>
+						</object>
+						<reference key="parent" ref="408298283"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">300440</int>
+						<reference key="object" ref="718083688"/>
+						<reference key="parent" ref="878106058"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">300441</int>
+						<reference key="object" ref="572508492"/>
+						<reference key="parent" ref="386152084"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">300447</int>
+						<reference key="object" ref="477050998"/>
+						<object class="NSMutableArray" key="children">
+							<bool key="EncodedWithXMLCoder">YES</bool>
+							<reference ref="501304422"/>
+						</object>
+						<reference key="parent" ref="408298283"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">300450</int>
+						<reference key="object" ref="501304422"/>
+						<reference key="parent" ref="477050998"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">300451</int>
+						<reference key="object" ref="765780304"/>
+						<object class="NSMutableArray" key="children">
+							<bool key="EncodedWithXMLCoder">YES</bool>
+							<reference ref="510771323"/>
+						</object>
+						<reference key="parent" ref="408298283"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">300452</int>
+						<reference key="object" ref="510771323"/>
+						<reference key="parent" ref="765780304"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">300453</int>
+						<reference key="object" ref="487809555"/>
+						<object class="NSMutableArray" key="children">
+							<bool key="EncodedWithXMLCoder">YES</bool>
+							<reference ref="619977658"/>
+						</object>
+						<reference key="parent" ref="408298283"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">300454</int>
+						<reference key="object" ref="619977658"/>
+						<reference key="parent" ref="487809555"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">300455</int>
+						<reference key="object" ref="620944856"/>
+						<object class="NSMutableArray" key="children">
+							<bool key="EncodedWithXMLCoder">YES</bool>
+							<reference ref="461823902"/>
+						</object>
+						<reference key="parent" ref="408298283"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">300456</int>
+						<reference key="object" ref="461823902"/>
+						<reference key="parent" ref="620944856"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">300457</int>
+						<reference key="object" ref="1002778833"/>
+						<object class="NSMutableArray" key="children">
+							<bool key="EncodedWithXMLCoder">YES</bool>
+							<reference ref="897099877"/>
+						</object>
+						<reference key="parent" ref="408298283"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">300458</int>
+						<reference key="object" ref="897099877"/>
+						<reference key="parent" ref="1002778833"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">300459</int>
+						<reference key="object" ref="522511724"/>
+						<object class="NSMutableArray" key="children">
+							<bool key="EncodedWithXMLCoder">YES</bool>
+							<reference ref="994587858"/>
+						</object>
+						<reference key="parent" ref="408298283"/>
+					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">300460</int>
+						<reference key="object" ref="994587858"/>
+						<reference key="parent" ref="522511724"/>
+					</object>
 				</object>
 			</object>
 			<object class="NSMutableDictionary" key="flattenedProperties">
@@ -2969,7 +3237,29 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 					<string>-2.IBPluginDependency</string>
 					<string>-3.IBPluginDependency</string>
 					<string>-3.ImportedFromIB2</string>
+					<string>100292.IBPluginDependency</string>
+					<string>100293.IBPluginDependency</string>
+					<string>100295.IBPluginDependency</string>
 					<string>100295.IBShouldRemoveOnLegacySave</string>
+					<string>100310.IBPluginDependency</string>
+					<string>100363.IBPluginDependency</string>
+					<string>100364.IBPluginDependency</string>
+					<string>100365.IBPluginDependency</string>
+					<string>100368.IBPluginDependency</string>
+					<string>100369.IBPluginDependency</string>
+					<string>100370.IBPluginDependency</string>
+					<string>100371.IBPluginDependency</string>
+					<string>100372.IBPluginDependency</string>
+					<string>100374.IBPluginDependency</string>
+					<string>100375.IBPluginDependency</string>
+					<string>100376.IBPluginDependency</string>
+					<string>100377.IBPluginDependency</string>
+					<string>100379.IBPluginDependency</string>
+					<string>100382.IBPluginDependency</string>
+					<string>100385.IBPluginDependency</string>
+					<string>100386.IBPluginDependency</string>
+					<string>100541.IBPluginDependency</string>
+					<string>100543.IBPluginDependency</string>
 					<string>129.IBPluginDependency</string>
 					<string>129.ImportedFromIB2</string>
 					<string>130.IBPluginDependency</string>
@@ -2990,31 +3280,19 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 					<string>149.ImportedFromIB2</string>
 					<string>150.IBPluginDependency</string>
 					<string>150.ImportedFromIB2</string>
-					<string>156.IBPluginDependency</string>
-					<string>156.ImportedFromIB2</string>
 					<string>157.IBPluginDependency</string>
 					<string>157.ImportedFromIB2</string>
-					<string>158.IBPluginDependency</string>
-					<string>158.ImportedFromIB2</string>
-					<string>160.IBPluginDependency</string>
-					<string>160.ImportedFromIB2</string>
 					<string>163.IBPluginDependency</string>
 					<string>163.ImportedFromIB2</string>
-					<string>164.IBPluginDependency</string>
-					<string>164.ImportedFromIB2</string>
+					<string>169.IBEditorWindowLastContentRect</string>
 					<string>169.IBPluginDependency</string>
 					<string>169.ImportedFromIB2</string>
 					<string>169.editorWindowContentRectSynchronizationRect</string>
-					<string>171.IBPluginDependency</string>
-					<string>171.ImportedFromIB2</string>
-					<string>172.IBPluginDependency</string>
-					<string>172.ImportedFromIB2</string>
-					<string>173.IBPluginDependency</string>
-					<string>173.ImportedFromIB2</string>
 					<string>19.IBPluginDependency</string>
 					<string>19.ImportedFromIB2</string>
 					<string>196.IBPluginDependency</string>
 					<string>196.ImportedFromIB2</string>
+					<string>200295.IBPluginDependency</string>
 					<string>200295.IBShouldRemoveOnLegacySave</string>
 					<string>203.IBPluginDependency</string>
 					<string>203.ImportedFromIB2</string>
@@ -3022,11 +3300,11 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 					<string>204.ImportedFromIB2</string>
 					<string>23.IBPluginDependency</string>
 					<string>23.ImportedFromIB2</string>
+					<string>24.IBEditorWindowLastContentRect</string>
 					<string>24.IBPluginDependency</string>
 					<string>24.ImportedFromIB2</string>
 					<string>24.editorWindowContentRectSynchronizationRect</string>
 					<string>244.IBEditorWindowLastContentRect</string>
-					<string>244.IBPluginDependency</string>
 					<string>244.IBWindowTemplateEditedContentRect</string>
 					<string>244.ImportedFromIB2</string>
 					<string>244.editorWindowContentRectSynchronizationRect</string>
@@ -3038,13 +3316,13 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 					<string>245.ImportedFromIB2</string>
 					<string>269.IBPluginDependency</string>
 					<string>269.ImportedFromIB2</string>
+					<string>270.IBEditorWindowLastContentRect</string>
 					<string>270.IBPluginDependency</string>
 					<string>270.ImportedFromIB2</string>
 					<string>270.editorWindowContentRectSynchronizationRect</string>
 					<string>272.IBPluginDependency</string>
 					<string>272.ImportedFromIB2</string>
 					<string>285.IBEditorWindowLastContentRect</string>
-					<string>285.IBPluginDependency</string>
 					<string>285.IBViewEditorWindowController.showingBoundsRectangles</string>
 					<string>285.IBViewEditorWindowController.showingLayoutRectangles</string>
 					<string>285.IBWindowTemplateEditedContentRect</string>
@@ -3072,6 +3350,7 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 					<string>297.ImportedFromIB2</string>
 					<string>298.IBPluginDependency</string>
 					<string>298.ImportedFromIB2</string>
+					<string>300295.IBPluginDependency</string>
 					<string>300295.IBShouldRemoveOnLegacySave</string>
 					<string>300330.IBPluginDependency</string>
 					<string>300330.ImportedFromIB2</string>
@@ -3083,14 +3362,48 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 					<string>300358.ImportedFromIB2</string>
 					<string>300359.IBPluginDependency</string>
 					<string>300359.ImportedFromIB2</string>
+					<string>300360.IBPluginDependency</string>
+					<string>300361.IBPluginDependency</string>
 					<string>300362.IBPluginDependency</string>
 					<string>300362.ImportedFromIB2</string>
+					<string>300363.IBPluginDependency</string>
 					<string>300364.IBPluginDependency</string>
 					<string>300364.ImportedFromIB2</string>
+					<string>300365.IBPluginDependency</string>
 					<string>300368.IBPluginDependency</string>
 					<string>300368.ImportedFromIB2</string>
+					<string>300369.IBPluginDependency</string>
 					<string>300370.IBPluginDependency</string>
 					<string>300370.ImportedFromIB2</string>
+					<string>300371.IBPluginDependency</string>
+					<string>300421.IBPluginDependency</string>
+					<string>300421.ImportedFromIB2</string>
+					<string>300422.IBPluginDependency</string>
+					<string>300422.ImportedFromIB2</string>
+					<string>300423.IBPluginDependency</string>
+					<string>300423.ImportedFromIB2</string>
+					<string>300424.IBPluginDependency</string>
+					<string>300424.ImportedFromIB2</string>
+					<string>300440.IBPluginDependency</string>
+					<string>300441.IBPluginDependency</string>
+					<string>300447.IBPluginDependency</string>
+					<string>300447.ImportedFromIB2</string>
+					<string>300450.IBPluginDependency</string>
+					<string>300451.IBPluginDependency</string>
+					<string>300451.ImportedFromIB2</string>
+					<string>300452.IBPluginDependency</string>
+					<string>300453.IBPluginDependency</string>
+					<string>300453.ImportedFromIB2</string>
+					<string>300454.IBPluginDependency</string>
+					<string>300455.IBPluginDependency</string>
+					<string>300455.ImportedFromIB2</string>
+					<string>300456.IBPluginDependency</string>
+					<string>300457.IBPluginDependency</string>
+					<string>300457.ImportedFromIB2</string>
+					<string>300458.IBPluginDependency</string>
+					<string>300459.IBPluginDependency</string>
+					<string>300459.ImportedFromIB2</string>
+					<string>300460.IBPluginDependency</string>
 					<string>305.IBPluginDependency</string>
 					<string>305.ImportedFromIB2</string>
 					<string>310.IBPluginDependency</string>
@@ -3210,21 +3523,29 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<integer value="1" id="9"/>
-					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
-					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
-					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
-					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
-					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
-					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
-					<reference ref="9"/>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
@@ -3245,17 +3566,19 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
-					<string>{{202, 626}, {154, 153}}</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
+					<string>{{168, 821}, {113, 23}}</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
+					<string>{{202, 626}, {154, 153}}</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
@@ -3263,29 +3586,29 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
+					<string>{{204, 683}, {315, 153}}</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>{{271, 666}, {301, 153}}</string>
-					<string>{{423, 622}, {484, 280}}</string>
-					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
-					<string>{{423, 622}, {484, 280}}</string>
+					<string>{{437, 749}, {484, 308}}</string>
+					<string>{{437, 749}, {484, 308}}</string>
 					<reference ref="9"/>
 					<string>{{184, 290}, {481, 345}}</string>
-					<reference ref="9"/>
+					<boolean value="NO"/>
 					<reference ref="9"/>
 					<string>{3.40282e+38, 3.40282e+38}</string>
-					<string>{213, 107}</string>
+					<string>{320, 240}</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
+					<string>{{58, 803}, {155, 33}}</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>{{100, 746}, {155, 33}}</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>{{68, 585}, {454, 271}}</string>
-					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<reference ref="9"/>
 					<string>{{68, 585}, {454, 271}}</string>
@@ -3297,7 +3620,7 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 					<string>{320, 240}</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
-					<string>{{0, 836}, {336, 20}}</string>
+					<string>{{8, 844}, {336, 20}}</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>{{67, 819}, {336, 20}}</string>
@@ -3313,6 +3636,7 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
@@ -3325,14 +3649,20 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
@@ -3341,18 +3671,26 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
@@ -3430,7 +3768,27 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 					<reference ref="9"/>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
-					<string>{{12, 633}, {218, 203}}</string>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<reference ref="9"/>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<reference ref="9"/>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<reference ref="9"/>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<reference ref="9"/>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<reference ref="9"/>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<reference ref="9"/>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<reference ref="9"/>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<reference ref="9"/>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<reference ref="9"/>
+					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+					<reference ref="9"/>
+					<string>{{20, 641}, {218, 203}}</string>
 					<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
 					<reference ref="9"/>
 					<string>{{79, 616}, {218, 203}}</string>
@@ -3466,7 +3824,7 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 				</object>
 			</object>
 			<nil key="sourceID"/>
-			<int key="maxID">300420</int>
+			<int key="maxID">300471</int>
 		</object>
 		<object class="IBClassDescriber" key="IBDocument.Classes">
 			<object class="NSMutableArray" key="referencedPartialClassDescriptions">
@@ -3551,6 +3909,7 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 							<string>apps_separator</string>
 							<string>apps_table</string>
 							<string>click_through</string>
+							<string>copy_menu_item</string>
 							<string>depth</string>
 							<string>dock_apps_menu</string>
 							<string>dock_menu</string>
@@ -3563,7 +3922,14 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 							<string>focus_follows_mouse</string>
 							<string>focus_on_new_window</string>
 							<string>prefs_panel</string>
+							<string>sync_clipboard_to_pasteboard</string>
 							<string>sync_keymap</string>
+							<string>sync_pasteboard</string>
+							<string>sync_pasteboard_to_clipboard</string>
+							<string>sync_pasteboard_to_primary</string>
+							<string>sync_primary_immediately</string>
+							<string>sync_text1</string>
+							<string>sync_text2</string>
 							<string>toggle_fullscreen_item</string>
 							<string>use_sysbeep</string>
 							<string>window_separator</string>
@@ -3574,6 +3940,7 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 							<string>NSMenuItem</string>
 							<string>NSTableView</string>
 							<string>NSButton</string>
+							<string>NSMenuItem</string>
 							<string>NSPopUpButton</string>
 							<string>NSMenu</string>
 							<string>NSMenu</string>
@@ -3587,6 +3954,13 @@ d2hpY2ggbWF5IHByZXZlbnQgWDExIGFwcGxpY2F0aW9ucyBmcm9tIGxhdW5jaGluZy4</string>
 							<string>NSButton</string>
 							<string>NSPanel</string>
 							<string>NSButton</string>
+							<string>NSButton</string>
+							<string>NSButton</string>
+							<string>NSButton</string>
+							<string>NSButton</string>
+							<string>NSButton</string>
+							<string>NSTextField</string>
+							<string>NSTextField</string>
 							<string>NSMenuItem</string>
 							<string>NSButton</string>
 							<string>NSMenuItem</string>
diff --git a/hw/xquartz/bundle/Resources/English.lproj/main.nib/keyedobjects.nib b/hw/xquartz/bundle/Resources/English.lproj/main.nib/keyedobjects.nib
index 197c1be..c549568 100644
Binary files a/hw/xquartz/bundle/Resources/English.lproj/main.nib/keyedobjects.nib and b/hw/xquartz/bundle/Resources/English.lproj/main.nib/keyedobjects.nib differ
diff --git a/hw/xquartz/darwin.h b/hw/xquartz/darwin.h
index da5ad74..e45ab19 100644
--- a/hw/xquartz/darwin.h
+++ b/hw/xquartz/darwin.h
@@ -89,6 +89,12 @@ extern unsigned int     darwinDesiredWidth, darwinDesiredHeight;
 extern int              darwinDesiredDepth;
 extern int              darwinDesiredRefresh;
 
+extern int              pbproxy_active;
+extern int              pbproxy_primary_on_grab;
+extern int              pbproxy_clipboard_to_pasteboard;
+extern int              pbproxy_pasteboard_to_primary;
+extern int              pbproxy_pasteboard_to_clipboard;
+
 // location of X11's (0,0) point in global screen coordinates
 extern int              darwinMainScreenX;
 extern int              darwinMainScreenY;
diff --git a/hw/xquartz/doc/Xquartz.man.pre b/hw/xquartz/doc/Xquartz.man.pre
index 100589e..a9f9a58 100644
--- a/hw/xquartz/doc/Xquartz.man.pre
+++ b/hw/xquartz/doc/Xquartz.man.pre
@@ -56,6 +56,21 @@ defaults to the depth of the main display.
 .TP 8
 .B defaults write org.x.X11 sync_keymap -boolean true
 Keep the X11 keymap up to date with the OSX system keymap.
+.TP 8
+.B defaults write org.x.X11 sync_pasteboard -boolean true
+Enable syncing between the OSX pasteboard and clipboard/primary selection buffers in X11.  This option needs to be true for any of the other pasteboard sync options to have an effect.
+.TP 8
+.B defaults write org.x.X11 sync_pasteboard_to_clipboard -boolean true
+Update the X11 CLIPBOARD when the OSX NSPasteboard is updated.
+.TP 8
+.B defaults write org.x.X11 sync_pasteboard_to_primary -boolean true
+Update the the X11 PRIMARY buffer when the OSX NSPasteboard is updated.
+.TP 8
+.B defaults write org.x.X11 sync_clipboard_to_pasteboard -boolean true
+Update the the OSX NSPasteboard when the X11 CLIPBOARD is updated.  Note that enabling this option causes the clipboard synchronization to act as a clipboard manager in X11.  This makes it impossible to use xclipboard, klipper, or any other such clipboard managers.  If you want to use any of these programs, you must disable this option.
+.TP 8
+.B defaults write org.x.X11 sync_primary_on_select -boolean true
+This option defaults to false and is provided only "for experts."  It updates the NSPasteboard whenever a new X11 selection is made (rather than requiring you to hit cmd-c to copy the selection to the NSPasteboard).  Since the X11 protocol does not require applications to send notification when they change selection, this might not work in all cases (if you run into this problem, try selecting text in another application first, then selecting the text you want).
 .SH OPTIONS
 .PP
 In addition to the normal server options described in the \fIXserver(1)\fP
commit e58a1d1d270a04b9406e2019247403ba1ee601fe
Author: George Peter Staplin <gps at Georges-Workstation.local>
Date:   Fri Sep 19 00:18:44 2008 -0600

    XQuartz: pbproxy: Add a missing include of Xutil.h.  Another header
    seems to have done this before, but correctness matters.
    (cherry picked from commit 1b4987e779d97b90669bac2405a4672085677f7c)

diff --git a/hw/xquartz/pbproxy/x-selection.m b/hw/xquartz/pbproxy/x-selection.m
index 1b660ab..789e801 100644
--- a/hw/xquartz/pbproxy/x-selection.m
+++ b/hw/xquartz/pbproxy/x-selection.m
@@ -33,6 +33,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <X11/Xatom.h>
+#include <X11/Xutil.h>
 #import <AppKit/NSBitmapImageRep.h>
 
 
commit f8f5d753035ad7eae2f6fde77a6a27a15da1bed7
Author: George Peter Staplin <gps at Georges-Workstation.local>
Date:   Fri Sep 19 00:02:48 2008 -0600

    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 1e9460abdf5bafe46215966bbef3e796cb1c33e0)

diff --git a/hw/xquartz/pbproxy/main.m b/hw/xquartz/pbproxy/main.m
index 4b1dac1..7577f7a 100644
--- a/hw/xquartz/pbproxy/main.m
+++ b/hw/xquartz/pbproxy/main.m
@@ -77,6 +77,8 @@ static void x_init (void) {
     atoms->incr = XInternAtom (x_dpy, "INCR", False);
     atoms->atom = XInternAtom (x_dpy, "ATOM", 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,
                                  &x_apple_wm_error_base)) {
diff --git a/hw/xquartz/pbproxy/pbproxy.h b/hw/xquartz/pbproxy/pbproxy.h
index ad8f2e4..098e309 100644
--- a/hw/xquartz/pbproxy/pbproxy.h
+++ b/hw/xquartz/pbproxy/pbproxy.h
@@ -25,7 +25,8 @@ extern int x_apple_wm_event_base, x_apple_wm_error_base;
 
 struct atom_list {
     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;
diff --git a/hw/xquartz/pbproxy/x-selection.m b/hw/xquartz/pbproxy/x-selection.m
index 9eca6c7..1b660ab 100644
--- a/hw/xquartz/pbproxy/x-selection.m
+++ b/hw/xquartz/pbproxy/x-selection.m
@@ -338,6 +338,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 #if 0
     if ([_pasteboard changeCount] != _my_last_change)
     {
+	/*gstaplin: we should perhaps investigate something like this branch above...*/
 	if ([_pasteboard availableTypeFromArray: _known_types] != nil)
 	{
 	    /* 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));
 }
 
+- (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.
  * 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;
     NSArray *pbtypes;
 
-    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;    
+    [self init_reply:&reply request:e];
 
     pbtypes = [_pasteboard types];
     if (pbtypes)
     {
-	long list[5];
+	long list[6];
         long count = 0;
 	
 	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");
 	    list[count] = atoms->utf8_string;
 	    ++count;
 	    list[count] = atoms->string;
 	    ++count;
+	    list[count] = atoms->compound_text;
+	    ++count;
 	}
 
 	if ([pbtypes containsObject:NSTIFFPboardType] 
@@ -540,7 +557,6 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 	    ++count;
 	} 
 
-
 	if (count)
 	{
 	    /* We have a list of ATOMs to send. */
@@ -551,46 +567,10 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 	}
     }
 
-    /*
-     * 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);
+    [self send_reply:&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
 {
     XEvent reply;
@@ -598,12 +578,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
     
     TRACE ();
 
-    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; 
+    [self init_reply:&reply request:e];
 
     pbtypes = [_pasteboard types];
 
@@ -615,7 +590,8 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 	    const char *bytes;
 	    NSUInteger length;
 
-	    if (utf8) {
+	    if (utf8) 
+	    {
 		bytes = [data UTF8String];
 		/*
 		 * 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];
 		DB ("UTF-8\n");
-	    } else {
+	    } 
+	    else 
+	    {
 		DB ("Latin-1\n");
 		bytes = [data cStringUsingEncoding:NSISOLatin1StringEncoding];
 		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. */
-    XSendEvent (x_dpy, e->requestor, False, 0, &reply);
+    [self send_reply:&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
 {
     XEvent reply;
@@ -651,12 +696,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 
     TRACE ();
 
-    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; 
+    [self init_reply:&reply request:e];
 
     pbtypes = [_pasteboard types];
 
@@ -678,7 +718,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
     if (type)
     {
 	NSData *data;
-	data = [_pasteboard dataForType: type];
+	data = [_pasteboard dataForType:type];
 
 	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. */
-    XSendEvent (x_dpy, e->requestor, False, 0, &reply);
+    [self send_reply:&reply];
 }
 
 - (void)send_none:(XSelectionRequestEvent *)e
@@ -719,15 +758,8 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 
     TRACE ();
 
-    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;
-
-    /* Always send a response, even if the property value is None. */
-    XSendEvent (x_dpy, e->requestor, False, 0, &reply);
+    [self init_reply:&reply request:e];
+    [self send_reply:&reply];
 }
 
 
@@ -746,7 +778,8 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
      * 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));
 
@@ -766,7 +799,15 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
     else if (e->target == atoms->string)
     {
 	[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)
     {
 	[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). */
 /* 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;
     NSUInteger length;
@@ -1041,11 +1082,11 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
     } 
     else if (type == atoms->image_png)
     {
-	[self handle_image:pdata extension:@".png"];
+	[self handle_image:pdata];
     } 
     else if (type == atoms->image_jpeg)
     {
-	[self handle_image:pdata extension:@".jpeg"];
+	[self handle_image:pdata];
     }
     else if (type == atoms->utf8_string) 
     {
commit 9fdf04b675df92cd04971fbade889d8b773b4005
Author: George Peter Staplin <gps at Georges-Workstation.local>
Date:   Thu Sep 18 13:10:41 2008 -0600

    XQuartz: pbproxy: pbproxy now responds to selection request events.
    
    We can now copy and paste images to and from X11.  Text copying and
    pasting works as well.
    
    The NSPasteboard can contain TIFF or PICT images, and pbproxy will
    translate to an image/png or image/jpeg request, and list those in the
    TARGETS.
    
    I added a description of the basic design at the top of x-selection.m.
    
    I removed the request_data x_selection class struct.  It's not needed.
    (cherry picked from commit 4a8daf884694c9c420c45d427f1f84e608e7e48f)

diff --git a/hw/xquartz/pbproxy/x-selection.h b/hw/xquartz/pbproxy/x-selection.h
index 8b27312..4ef265d 100644
--- a/hw/xquartz/pbproxy/x-selection.h
+++ b/hw/xquartz/pbproxy/x-selection.h
@@ -67,16 +67,6 @@ struct propdata {
         Window requestor;
         Atom selection;
     } pending;
- 
-    /* This may not be needed.*/
-    /* If we can have the Apple clipboard translate to PNG or JPEG we can
-     * do away with this.   Otherwise we could use libjpeg and libpng
-     * to convert some raw clipboard format to the proper format.
-     */
-    struct {
-	struct propdata propdata;
-	Atom type;
-    } request_data;
 }
 
 - (void) x_active:(Time)timestamp;
diff --git a/hw/xquartz/pbproxy/x-selection.m b/hw/xquartz/pbproxy/x-selection.m
index eea6124..9eca6c7 100644
--- a/hw/xquartz/pbproxy/x-selection.m
+++ b/hw/xquartz/pbproxy/x-selection.m
@@ -35,6 +35,32 @@
 #include <X11/Xatom.h>
 #import <AppKit/NSBitmapImageRep.h>
 
+
+/*
+ * The basic design of the pbproxy code is as follows.
+ *
+ * When a client selects text, say from an xterm - we only copy it when the
+ * X11 Edit->Copy menu item is pressed or the shortcut activated.  In this
+ * case we take the PRIMARY selection, and set it as the NSPasteboard data.
+ *
+ * When an X11 client copies something to the CLIPBOARD, pbproxy greedily grabs
+ * the data, sets it as the NSPasteboard data, and finally sets itself as 
+ * owner of the CLIPBOARD.
+ * 
+ * When an X11 window is activated we check to see if the NSPasteboard has
+ * changed.  If the NSPasteboard has changed, then we set pbproxy as owner
+ * of the PRIMARY and CLIPBOARD and respond to requests for text and images.
+ *
+ */
+
+/*
+ * TODO:
+ * 1. finish handling these pbproxy control knobs.
+ * 2. handle  MULTIPLE - I need to study the ICCCM further.
+ * 3. handle COMPOUND_TEXT (if possible) - it's a variant of iso2022 from 
+ * what I've read.
+ */
+
 // These will be set by X11Controller.m once this is integrated into a server thread
 BOOL pbproxy_active = YES;
 BOOL pbproxy_primary_on_grab = NO; // This is provided as an option for people who want it and has issues that won't ever be addressed to make it *always* work
@@ -292,8 +318,23 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 /* Called when X11 becomes active (i.e. has key focus) */
 - (void) x_active:(Time)timestamp
 {
+    static NSInteger changeCount;
+    NSInteger countNow;
+
     TRACE ();
 
+    countNow = [_pasteboard changeCount];
+
+    if (countNow != changeCount)
+    {
+	DB ("changed pasteboard!\n");
+	changeCount = countNow;
+
+	/*HMM should we pass CurrentTime instead?*/
+	XSetSelectionOwner (x_dpy, atoms->primary, _selection_window, timestamp);
+	XSetSelectionOwner (x_dpy, atoms->clipboard, _selection_window, timestamp);
+    }
+
 #if 0
     if ([_pasteboard changeCount] != _my_last_change)
     {
@@ -452,58 +493,18 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 						      atoms->clipboard));
 }
 
-
-/* The preference should be for UTF8_STRING before the XA_STRING*/
-/* This should NOT be used for Atom transfers, because it uses 8 bits. */
-/* This was previously used for Atom transfers (incorrectly). */
-static Atom
-convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
-{
-    Atom ret = None;
-
-    if (data == nil)
-	return ret;
-
-    if (target == atoms->text)
-	target = atoms->utf8_string;
-
-    if (target == XA_STRING
-	|| target == atoms->cstring
-	|| target == atoms->utf8_string)
-    {
-	const char *bytes;
-
-	if (target == XA_STRING)
-	    bytes = [data cStringUsingEncoding:NSISOLatin1StringEncoding];
-	else
-	    bytes = [data UTF8String];
-
-	if (bytes != NULL)
-	{
-	    XChangeProperty (x_dpy, e->requestor, prop, target,
-			     8, PropModeReplace, (unsigned char *) bytes,
-			     strlen (bytes));
-	    ret = prop;
-	}
-    }
-    /* FIXME: handle COMPOUND_TEXT target */
-    [data release];
-
-    return ret;
-}
-
 /* 
  * 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
  * for a selection.  
  * For instance an application might provide a UTF8_STRING and a STRING
  * (in Latin-1 encoding).  The requestor can then make the choice based on
- * the targets list.
+ * the list.
  */
 - (void) send_targets:(XSelectionRequestEvent *)e
 {
     XEvent reply;
-    long list[2];
+    NSArray *pbtypes;
 
     reply.xselection.type = SelectionNotify;
     reply.xselection.selection = e->selection;
@@ -512,21 +513,44 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     reply.xselection.time = e->time;
     reply.xselection.property = None;    
 
-    /*
-    Todo
-    if (clipboard_data is an image) {
-      list[0] = atoms->image_jpeg;  or some such thing.
+    pbtypes = [_pasteboard types];
+    if (pbtypes)
+    {
+	long list[5];
+        long count = 0;
+	
+	if ([pbtypes containsObject:NSStringPboardType])
+	{
+	    /* We have a string type that we can convert to a UTF8 or Latin-1 string. */
+	    DB ("NSStringPboardType\n");
+	    list[count] = atoms->utf8_string;
+	    ++count;
+	    list[count] = atoms->string;
+	    ++count;
+	}
+
+	if ([pbtypes containsObject:NSTIFFPboardType] 
+	    || [pbtypes containsObject:NSPICTPboardType])
+	{
+	    /* We can convert a TIFF or PICT to a PNG or JPEG. */
+	    DB ("NSTIFFPboardType or NSPICTPboardType\n");
+	    list[count] = atoms->image_png;
+	    ++count;
+	    list[count] = atoms->image_jpeg;
+	    ++count;
+	} 
+
+
+	if (count)
+	{
+	    /* We have a list of ATOMs to send. */
+	    XChangeProperty (x_dpy, e->requestor, e->property, atoms->atom, 32,
+			 PropModeReplace, (unsigned char *) list, count);
+	    
+	    reply.xselection.property = e->property;
+	}
     }
-    ...
-    */
-
-    list[0] = atoms->utf8_string;
-    list[1] = XA_STRING;
-     
-    XChangeProperty (x_dpy, e->requestor, e->property, e->target,
-		     32, PropModeReplace, (unsigned char *) list,
-		     sizeof (list) / sizeof (Atom));
-    reply.xselection.property = e->property;
+
     /*
      * We are supposed to use an empty event mask, and not propagate
      * the event, according to the ICCCM.
@@ -598,7 +622,9 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 		 * We want the length in bytes.
 		 */
 		length = [data lengthOfBytesUsingEncoding:NSASCIIStringEncoding];
+		DB ("UTF-8\n");
 	    } else {
+		DB ("Latin-1\n");
 		bytes = [data cStringUsingEncoding:NSISOLatin1StringEncoding];
 		length = [data lengthOfBytesUsingEncoding:NSASCIIStringEncoding];
 	    }
@@ -608,20 +634,107 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 	    
 	    reply.xselection.property = e->property;
 
-	    [data release];
+	    /*Should we [data release] here?*/
+ 	}
+    }
+
+    /* Always send a response, even if the property value is None. */
+    XSendEvent (x_dpy, e->requestor, False, 0, &reply);
+}
+
+- (void) send_image:(XSelectionRequestEvent *)e
+{
+    XEvent reply;
+    NSArray *pbtypes;
+    NSString *type = nil;
+    NSBitmapImageFileType imagetype = /*quiet warning*/ NSPNGFileType; 
+
+    TRACE ();
+
+    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; 
+
+    pbtypes = [_pasteboard types];
+
+    if (pbtypes) 
+    {
+	if ([pbtypes containsObject:NSTIFFPboardType])
+	    type = NSTIFFPboardType;
+
+	if ([pbtypes containsObject:NSPICTPboardType])
+	    type  = NSPICTPboardType;
+    }
+
+    if (e->target == atoms->image_png)
+	imagetype = NSPNGFileType;
+    else if (e->target == atoms->image_jpeg)
+	imagetype = NSJPEGFileType;
+        
+
+    if (type)
+    {
+	NSData *data;
+	data = [_pasteboard dataForType: type];
+
+	if (data)
+	{
+	    NSBitmapImageRep *bmimage = [[NSBitmapImageRep alloc] initWithData:data];
+	    
+	    if (bmimage) 
+	    {
+		NSDictionary *dict;
+		NSData *encdata;
+		
+		dict = [[NSDictionary alloc] init];
+		encdata = [bmimage representationUsingType:imagetype properties:dict];
+		if (encdata)
+		{
+		    NSUInteger length;
+		    const void *bytes;
+
+		    length = [encdata length];
+		    bytes = [encdata bytes];
+		    		    
+		    XChangeProperty (x_dpy, e->requestor, e->property, e->target,
+				     8, PropModeReplace, bytes, length);
+		
+		    reply.xselection.property = e->property;
+		    
+		    DB ("changed property for %s\n", XGetAtomName (x_dpy, e->target));
+		}
+	    }
 	}
     }
     /* Always send a response, even if the property value is None. */
     XSendEvent (x_dpy, e->requestor, False, 0, &reply);
 }
 
-- (void) request_event:(XSelectionRequestEvent *)e
+- (void)send_none:(XSelectionRequestEvent *)e
 {
-    /* Someone's asking us for the data on the pasteboard */
+    XEvent reply;
+
     TRACE ();
 
-    /*NOT YET*/
-    return;
+    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;
+
+    /* Always send a response, even if the property value is None. */
+    XSendEvent (x_dpy, e->requestor, False, 0, &reply);
+}
+
+
+/* Another client requested the data or targets of data available from the clipboard. */
+- (void)request_event:(XSelectionRequestEvent *)e
+{
+    TRACE ();
 
     /* TODO We should also keep track of the time of the selection, and 
      * according to the ICCCM "refuse the request" if the event timestamp
@@ -633,6 +746,8 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
      * Perhaps we should just punt and ignore races.
      */
 
+    /*TODO handle COMPOUND_STRING... We need a test app*/
+
     DB ("e->target %s\n", XGetAtomName (x_dpy, e->target));
 
     if (e->target == atoms->targets) 
@@ -652,9 +767,13 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     {
 	[self send_string:e utf8:NO];
     } 
+    else if (e->target == atoms->image_png || e->target == atoms->image_jpeg)
+    {
+	[self send_image:e];
+    }
     else 
     {
-	//[self send_null:e];
+	[self send_none:e];
     }
 }
 
@@ -889,7 +1008,7 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     DB ("done handling utf8 string\n");
 }
 
-/* This handles the XA_STRING type, which should be in Latin-1. */
+/* This handles the STRING type, which should be in Latin-1. */
 - (void) handle_string: (struct propdata *)pdata
 {
     NSString *string; 
@@ -936,28 +1055,15 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     {
 	[self handle_string:pdata];
     } 
-    else
-    {
-	free_propdata(pdata);
-    }
+ 
+    free_propdata(pdata);
     
-    if (selection == atoms->clipboard && pdata->data)
+    if (selection == atoms->clipboard)
     {
-	/* This may not be used. 
-	 * We should really pull from the data in the NSPasteboard.
-	 */
-	free_propdata(&request_data.propdata);
-	request_data.propdata = *pdata;
-	request_data.type = type;
-	
 	/* We greedily take the CLIPBOARD selection whenever it changes. */
 	XSetSelectionOwner (x_dpy, atoms->clipboard, _selection_window,
 			    CurrentTime);
     }
-    else
-    {
-	free_propdata(pdata);
-    }
 }
 
 
@@ -973,7 +1079,7 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     TRACE ();
 }
 
-- (void) pasteboardChangedOwner:(NSPasteboard *)sender
+- (void)pasteboardChangedOwner:(NSPasteboard *)pb
 {
     TRACE ();
 
@@ -1008,14 +1114,12 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     pending.requestor = None;
     pending.selection = None;
 
-    init_propdata (&request_data.propdata);
-    request_data.type = None;
-    
     return self;
 }
 
 - (void) dealloc
 {
+
     [_pasteboard releaseGlobally];
     [_pasteboard release];
     _pasteboard = nil;
@@ -1030,7 +1134,6 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     }
 
     free_propdata (&pending.propdata);
-    free_propdata (&request_data.propdata);
 
     [super dealloc];
 }
commit dc7af1b000aff6ad117ea258c2a78c4adbb159c9
Author: George Peter Staplin <gps at Georges-Workstation.local>
Date:   Wed Sep 17 11:59:36 2008 -0600

    XQuartz: pbproxy: Use an NSBitmapImageRep to convert an "image/png" selection
    to a TIFFRepresentation for use with NSPasteboard.
    
    This has been tested with the Gimp and works with some minor quartz-wm changes.
    The Finder clipboard shows the image updates after an Edit -> Copy.
    (cherry picked from commit 12912adaeea759d30f96d8ae51a84fd1659ea0ac)

diff --git a/hw/xquartz/pbproxy/x-selection.m b/hw/xquartz/pbproxy/x-selection.m
index 0feb4fd..eea6124 100644
--- a/hw/xquartz/pbproxy/x-selection.m
+++ b/hw/xquartz/pbproxy/x-selection.m
@@ -33,6 +33,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <X11/Xatom.h>
+#import <AppKit/NSBitmapImageRep.h>
 
 // These will be set by X11Controller.m once this is integrated into a server thread
 BOOL pbproxy_active = YES;
@@ -797,55 +798,66 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 		       _selection_window, CurrentTime);    
 }
 
-/*TODO I think this should convert to a standard NSPasteboard format, 
- * such as TIFF or PICT with a NSBitmapImageRep class.  */
 /* This handles the image type of selection (typically in CLIPBOARD). */
+/* We convert to a TIFF, so that other applications can paste more easily. */
 - (void) handle_image: (struct propdata *)pdata extension:(NSString *)fileext
 {
-    NSString *pbtype;
     NSArray *pbtypes;
     NSUInteger length;
-    NSData *data;
+    NSData *data, *tiff;
+    NSBitmapImageRep *bmimage;
 
     TRACE ();
 
-    pbtype = NSCreateFileContentsPboardType (fileext);
-    if (nil == pbtype) 
+    length = pdata->length;
+    data = [[NSData alloc] initWithBytes:pdata->data length:length];
+
+    if (nil == data)
     {
-	fprintf (stderr, "unknown extension or unable to create PboardType\n");
+	DB ("unable to create NSData object!\n");
 	return;
     }
-    
-    DB ("%s\n", [pbtype cStringUsingEncoding:NSISOLatin1StringEncoding]); 
-    
-    pbtypes = [NSArray arrayWithObjects: pbtype, nil];
-    if (nil == pbtypes) 
+
+    bmimage = [[NSBitmapImageRep alloc] initWithData:data];
+
+    if (nil == bmimage)
     {
-       DB ("error creating NSArray\n");
-       [pbtype release];
-       return;
+	DB ("unable to create NSBitmapImageRep!\n");
+	return;
     }
-    
-    length = pdata->length;
-    data = [[NSData alloc] initWithBytes:pdata->data length:length];
-    if (nil == data)
+
+    @try 
     {
-	[pbtype release];
-	[pbtypes release];
+	tiff = [bmimage TIFFRepresentation];
+    }
+
+    @catch (NSException *e) 
+    {
+	DB ("NSTIFFException!\n");
+	[data release];
+	[bmimage release];
 	return;
     }
+    
+    pbtypes = [NSArray arrayWithObjects:NSTIFFPboardType, nil];
+
+    if (nil == pbtypes)
+    {
+	[tiff release];
+	[data release];
+	[bmimage release];
+    }
 
     [_pasteboard declareTypes:pbtypes owner:self];
-    if (YES != [_pasteboard setData:data forType:pbtype])
+    if (YES != [_pasteboard setData:data forType:NSTIFFPboardType])
     {
 	DB ("writing pasteboard data failed!\n");
     }
 
-    [pbtype release];
     [pbtypes release];
     [data release];
-    
-    DB ("handled image\n");
+    [tiff release];
+    [bmimage release];
 }
 
 /* This handles the UTF8_STRING type of selection. */
commit f706f88e4f228135c253b0f5b66702bb27faefca
Author: Jeremy Huddleston <jeremyhu at freedesktop.org>
Date:   Wed Sep 17 10:11:00 2008 -0700

    XQuartz: Don't enable 8bit visuals in the TrueColor server, since it's not working yet
    (cherry picked from commit 1317c8ff94c4bd32617a5398e929f667bd87da58)

diff --git a/hw/xquartz/darwin.c b/hw/xquartz/darwin.c
index 98e3755..c571ee3 100644
--- a/hw/xquartz/darwin.c
+++ b/hw/xquartz/darwin.c
@@ -216,9 +216,10 @@ static Bool DarwinAddScreen(int index, ScreenPtr pScreen, int argc, char **argv)
                                  dfb->greenMask, dfb->blueMask)) {
         return FALSE;
     }
-    
-    if(dfb->depth > 8)
-        miSetVisualTypesAndMasks(8, PseudoColorMask, 8, PseudoColor, 0, 0, 0);
+  
+// TODO: Make PseudoColor visuals not suck in TrueColor mode  
+//    if(dfb->depth > 8)
+//        miSetVisualTypesAndMasks(8, PseudoColorMask, 8, PseudoColor, 0, 0, 0);
     if(dfb->depth > 15)
         miSetVisualTypesAndMasks(15, LARGE_VISUALS, 5, TrueColor, 0x7c00, 0x03e0, 0x001f);
     if(dfb->depth > 24)
commit a59c231559c1e7020ccc1feee98fe3759016d9eb
Author: George Peter Staplin <gps at Georges-Workstation.local>
Date:   Tue Sep 16 21:09:22 2008 -0600

    XQuartz: pbproxy: The greedy CLIPBOARD handling now works for text.
    
    This change adds some [self own_clipboard] calls in the necessary places to get the proper greedy behavior.
    
    UTF8_STRING and STRING properties seem to work well now with the test cases (PRIMARY, and CLIPBOARD).  I can copy from several different X apps, and have the behavior be correct when pasting.  I also verified that quartz-wm isn't doing the copying, by disabling the quartz-wm paths.
    (cherry picked from commit 934669f732c28f07b9d934d8f8f0b63ccfebd900)

diff --git a/hw/xquartz/pbproxy/x-input.m b/hw/xquartz/pbproxy/x-input.m
index f720af5..5261212 100644
--- a/hw/xquartz/pbproxy/x-input.m
+++ b/hw/xquartz/pbproxy/x-input.m
@@ -21,12 +21,7 @@ CFRunLoopSourceRef x_dpy_source;
 /* Timestamp when the X server last told us it's active */
 static Time last_activation_time;
 
-static FILE *getSelectionLog(void) {
-    return fopen("/tmp/selection.log", "a");
-}
-
 static void x_event_apple_wm_notify(XAppleWMNotifyEvent *e) {
-    FILE *fp = getSelectionLog();
 
     switch (e->type - x_apple_wm_event_base) {              
         case AppleWMActivationNotify:
@@ -45,19 +40,15 @@ static void x_event_apple_wm_notify(XAppleWMNotifyEvent *e) {
             break;
             
         case AppleWMPasteboardNotify:
-	    fprintf(fp, "AppleWMPasteboardNotify\n");
-	   
             switch (e->kind) {
                 case AppleWMCopyToPasteboard:
                     [x_selection_object () x_copy:e->time];
             }
             break;
     }
-    fclose(fp);
 }
 
 void x_input_run (void) {
-    FILE *fp = getSelectionLog();
 
     while (XPending (x_dpy) != 0) {
         XEvent e;       
@@ -66,23 +57,18 @@ void x_input_run (void) {
         
         switch (e.type) {                
             case SelectionClear:
-		fprintf(fp, "SelectionClear\n");
-
 	        [x_selection_object () clear_event:&e.xselectionclear];
                 break;
                 
             case SelectionRequest:
-		fprintf(fp, "SelectionRequest\n");
                 [x_selection_object () request_event:&e.xselectionrequest];
                 break;
                 
             case SelectionNotify:
-		fprintf(fp, "SelectionNotify\n");
                 [x_selection_object () notify_event:&e.xselection];
                 break;
                 
 	    case PropertyNotify:
-		fprintf(fp, "PropertyNotify\n");
 		[x_selection_object () property_event:&e.xproperty];
 		break;
 
@@ -96,7 +82,6 @@ void x_input_run (void) {
 
 	XFlush(x_dpy);
     }
-    fclose(fp);
 }
 
 static int add_input_socket (int sock, CFOptionFlags callback_types,
diff --git a/hw/xquartz/pbproxy/x-selection.m b/hw/xquartz/pbproxy/x-selection.m
index 49f7455..0feb4fd 100644
--- a/hw/xquartz/pbproxy/x-selection.m
+++ b/hw/xquartz/pbproxy/x-selection.m
@@ -619,6 +619,9 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     /* Someone's asking us for the data on the pasteboard */
     TRACE ();
 
+    /*NOT YET*/
+    return;
+
     /* TODO We should also keep track of the time of the selection, and 
      * according to the ICCCM "refuse the request" if the event timestamp
      * is before we owned it.
@@ -628,7 +631,9 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
      * may be set to CurrentTime or a time, so that makes it a bit different.
      * Perhaps we should just punt and ignore races.
      */
-    
+
+    DB ("e->target %s\n", XGetAtomName (x_dpy, e->target));
+
     if (e->target == atoms->targets) 
     {
 	/* The paste requestor wants to know what TARGETS we support. */
@@ -661,14 +666,20 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     TRACE ();
 
     [self release_pending];
-    
-    DB ("notify_event\n");
+ 
     if (None == e->property) {
 	DB ("e->property is None.\n");
+
+	if (pbproxy_clipboard_to_pasteboard && e->selection == atoms->clipboard)
+	    [self own_clipboard];
+	
 	/* Nothing is selected. */
 	return;
     }
 
+    DB ("e->selection %s\n", XGetAtomName (x_dpy, e->selection));
+    DB ("e->property %s\n", XGetAtomName (x_dpy, e->property));
+
     if (is_incr_type (e)) 
     {
 	/*
@@ -679,6 +690,14 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 
 	if (get_property (e->requestor, e->property, &pdata, /*Delete*/ True, &type)) 
 	{
+	    /* 
+	     * The get_property error could have occured with the clipboard atom.
+	     * Greedily own the clipboard again.
+	     */
+
+	    if (pbproxy_clipboard_to_pasteboard && e->selection == atoms->clipboard)
+		[self own_clipboard];
+	    
 	    return;
 	}
 
@@ -697,18 +716,30 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 	/* We have the complete selection data.*/
 	[self handle_selection: e->selection type:type propdata:&pdata];
 
+	DB ("handled selection with the first notify_event\n");
+
+	/* 
+	 * This may have been the end of the clipboard request from [self claim_clipboard].
+	 * If so, then we should own the contents now.
+	 */
+
 	if (pbproxy_clipboard_to_pasteboard && e->selection == atoms->clipboard)
 	    [self own_clipboard];
     }
 }
 
 /* This is used for INCR transfers.  See the ICCCM for the details. */
+/* This is used to retrieve PRIMARY and CLIPBOARD selections. */
 - (void) property_event:(XPropertyEvent *)e
 {
     struct propdata pdata;
     Atom type;
 
     TRACE ();
+    
+    if (None != e->atom)
+	DB ("e->atom %s\n", XGetAtomName (x_dpy, e->atom));
+
 
     if (None != pending.requestor && PropertyNewValue == e->state) 
     {
@@ -726,10 +757,11 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 	if (0 == pdata.length) 
 	{
 	    /* We completed the transfer. */
-	    [self handle_selection: pending.selection type: type propdata: &pending.propdata];
+	    [self handle_selection:pending.selection type:type propdata:&pending.propdata];
 	   
 	    if (pbproxy_clipboard_to_pasteboard && pending.selection == atoms->clipboard)
 		[self own_clipboard];
+
 	    pending.propdata = null_propdata;
 	    pending.requestor = None;
 	    pending.selection = None;
@@ -738,7 +770,7 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 	{
 	    [self append_to_pending: &pdata requestor: e->window];
 	}       
-    }
+    } 
 }
 
 - (void) handle_targets: (Atom)selection propdata:(struct propdata *)pdata
@@ -786,7 +818,7 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     
     DB ("%s\n", [pbtype cStringUsingEncoding:NSISOLatin1StringEncoding]); 
     
-    pbtypes = [NSArray arrayWithObject: pbtype];
+    pbtypes = [NSArray arrayWithObjects: pbtype, nil];
     if (nil == pbtypes) 
     {
        DB ("error creating NSArray\n");
@@ -823,22 +855,26 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     NSArray *pbtypes;
 
     TRACE ();
-    
+
     string = [[NSString alloc] initWithBytes:pdata->data length:pdata->length encoding:NSUTF8StringEncoding];
  
     if (nil == string)
 	return;
 
-    pbtypes = [NSArray arrayWithObject:NSStringPboardType];
+    pbtypes = [NSArray arrayWithObjects:NSStringPboardType, nil];
 
     if (nil != pbtypes)
     {
 	[_pasteboard declareTypes:pbtypes owner:self];
-	[_pasteboard setString:string forType:NSStringPboardType];
+
+	if (YES != [_pasteboard setString:string forType:NSStringPboardType]) {
+	    DB ("_pasteboard setString:forType: failed!\n");
+	}
 	[pbtypes release];
     }
-
     [string release];
+
+    DB ("done handling utf8 string\n");
 }
 
 /* This handles the XA_STRING type, which should be in Latin-1. */
@@ -852,7 +888,7 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     if (nil == string)
 	return;
 
-    pbtypes = [NSArray arrayWithObject:NSStringPboardType];
+    pbtypes = [NSArray arrayWithObjects:NSStringPboardType, nil];
 
     if (nil != pbtypes)
     {
@@ -915,6 +951,16 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 
 /* NSPasteboard-required methods */
 
+- (void)paste:(id)sender
+{
+    TRACE ();
+}
+
+- (void)pasteboard:(NSPasteboard *)pb provideDataForType:(NSString *)type
+{
+    TRACE ();
+}
+
 - (void) pasteboardChangedOwner:(NSPasteboard *)sender
 {
     TRACE ();
@@ -978,4 +1024,3 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 }
 
 @end
-
commit 8f663ab452022de8fd443fc972653c24f5452042
Author: George Peter Staplin <gps at Georges-Workstation.local>
Date:   Tue Sep 16 15:21:18 2008 -0600

    XQuartz: pbproxy: return the TARGETS list as a 32-bit list to fix a bug that was in the original.
    
    Add TRACE() calls where appropriate to try to figure out why we are losing CLIPBOARD at times, after transferring PRIMARY to the NSPasteboard.
    
    Use the new pbproxy_clipboard_to_pasteboard where appropriate.
    (cherry picked from commit 40190675a6c1889cca3574e5d1a9c16ab74315a7)

diff --git a/hw/xquartz/pbproxy/x-selection.h b/hw/xquartz/pbproxy/x-selection.h
index d27b3fa..8b27312 100644
--- a/hw/xquartz/pbproxy/x-selection.h
+++ b/hw/xquartz/pbproxy/x-selection.h
@@ -91,6 +91,7 @@ struct propdata {
 - (void) handle_selection:(Atom)selection type:(Atom)type propdata:(struct propdata *)pdata;
 - (void) claim_clipboard;
 - (void) set_clipboard_manager;
+- (void) own_clipboard;
 
 @end
 
diff --git a/hw/xquartz/pbproxy/x-selection.m b/hw/xquartz/pbproxy/x-selection.m
index c2d2bcd..49f7455 100644
--- a/hw/xquartz/pbproxy/x-selection.m
+++ b/hw/xquartz/pbproxy/x-selection.m
@@ -34,8 +34,6 @@
 #include <stdlib.h>
 #include <X11/Xatom.h>
 
-#include <unistd.h> /*GPS may not be needed now */
-
 // These will be set by X11Controller.m once this is integrated into a server thread
 BOOL pbproxy_active = YES;
 BOOL pbproxy_primary_on_grab = NO; // This is provided as an option for people who want it and has issues that won't ever be addressed to make it *always* work
@@ -69,6 +67,8 @@ is_incr_type (XSelectionEvent *e)
     unsigned long numitems = 0UL, bytesleft = 0UL;
     unsigned char *chunk;
        
+    TRACE ();
+
     if (Success != XGetWindowProperty (x_dpy, e->requestor, e->property,
 				       /*offset*/ 0L, /*length*/ 4UL,
 				       /*Delete*/ False,
@@ -92,6 +92,8 @@ find_preferred (struct propdata *pdata)
     size_t i;
     Bool png = False, utf8 = False, string = False;
 
+    TRACE ();
+
     if (pdata->length % sizeof (a))
     {
 	fprintf(stderr, "Atom list is not a multiple of the size of an atom!\n");
@@ -149,6 +151,8 @@ get_property(Window win, Atom property, struct propdata *pdata, Bool delete, Ato
     unsigned char *buf = NULL, *chunk = NULL;
     size_t buflen = 0, chunkbytesize = 0;
     int format;
+
+    TRACE ();
     
     if(None == property)
 	return True;
@@ -243,6 +247,8 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
  */
 - (void) release_pending
 {
+    TRACE ();
+
     free_propdata (&pending.propdata);
     pending.requestor = None;
     pending.selection = None;
@@ -255,6 +261,8 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
     unsigned char *newdata;
     size_t newlength;
     
+    TRACE ();
+    
     if (requestor != pending.requestor)
     {
 	[self release_pending];
@@ -330,6 +338,8 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 {
     Window w;
 
+    TRACE ();
+
     w = XGetSelectionOwner (x_dpy, atoms->primary);
 
     if (None != w)
@@ -350,6 +360,8 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
  */
 - (void) set_clipboard_manager
 {
+    TRACE ();
+
     if (None != XGetSelectionOwner (x_dpy, atoms->clipboard_manager))
     {
 	fprintf (stderr, "A clipboard manager is already running!\n"
@@ -368,20 +380,23 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 - (void) clear_event:(XSelectionClearEvent *)e
 {
     TRACE ();
+    
+    DB ("e->selection %s\n", XGetAtomName (x_dpy, e->selection));
  
     if (atoms->clipboard == e->selection)
     {
 	/* 
 	 * We lost ownership of the CLIPBOARD.
 	 */
+	
+
 	[self claim_clipboard];
     } 
     else if (atoms->clipboard_manager == e->selection)
     {
-	/*TODO/HMM  What should we do here? */
 	/* Another CLIPBOARD_MANAGER has set itself as owner.
          * a) we can call [self set_clipboard_manager] here and risk a war.
-	 * b) we can print a message and exit.
+	 * b) we can print a message and exit.  Ideally we would popup a message box.
 	 */
 	fprintf (stderr, "error: another clipboard manager was started!\n"); 
 	exit (EXIT_FAILURE);
@@ -395,6 +410,11 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 {
     Window owner;
     
+    TRACE ();
+
+    if (NO == pbproxy_clipboard_to_pasteboard)
+	return;
+
     owner = XGetSelectionOwner (x_dpy, atoms->clipboard);
     if (None == owner)
     {
@@ -403,14 +423,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 	 * Set pbproxy's _selection_window as the owner, and continue.
 	 */
 	DB ("No clipboard owner.\n");
-
-	do 
-	{
-	    XSetSelectionOwner (x_dpy, atoms->clipboard, _selection_window,
-				CurrentTime);
-	} while (_selection_window != XGetSelectionOwner (x_dpy,
-							  atoms->clipboard));
-
+	[self own_clipboard];
 	return;
     }
     
@@ -419,10 +432,29 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
     request_atom = atoms->targets;
     XConvertSelection (x_dpy, atoms->clipboard, atoms->targets,
 		       atoms->clipboard, _selection_window, CurrentTime);
+    XFlush (x_dpy);
     /* Now we will get a SelectionNotify event in the future. */
 }
 
+/* Greedily acquire the clipboard. */
+- (void) own_clipboard
+{
+
+    TRACE ();
+
+    /* We should perhaps have a boundary limit on the number of iterations... */
+    do 
+    {
+	XSetSelectionOwner (x_dpy, atoms->clipboard, _selection_window,
+			    CurrentTime);
+    } while (_selection_window != XGetSelectionOwner (x_dpy,
+						      atoms->clipboard));
+}
+
+
 /* The preference should be for UTF8_STRING before the XA_STRING*/
+/* This should NOT be used for Atom transfers, because it uses 8 bits. */
+/* This was previously used for Atom transfers (incorrectly). */
 static Atom
 convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 {
@@ -454,80 +486,170 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 	}
     }
     /* FIXME: handle COMPOUND_TEXT target */
-    /*gstaplin: should we [data release]? */
     [data release];
 
     return ret;
 }
 
-- (void) request_event:(XSelectionRequestEvent *)e
+/* 
+ * This responds to a TARGETS request.
+ * The result is a list of a Atoms that correspond to the types available
+ * for a selection.  
+ * For instance an application might provide a UTF8_STRING and a STRING
+ * (in Latin-1 encoding).  The requestor can then make the choice based on
+ * the targets list.
+ */
+- (void) send_targets:(XSelectionRequestEvent *)e
 {
-    /* Someone's asking us for the data on the pasteboard */
     XEvent reply;
-    NSString *data;
-    Atom target;
-
-    TRACE ();
+    long list[2];
 
     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;
+    reply.xselection.property = None;    
+
+    /*
+    Todo
+    if (clipboard_data is an image) {
+      list[0] = atoms->image_jpeg;  or some such thing.
+    }
+    ...
+    */
+
+    list[0] = atoms->utf8_string;
+    list[1] = XA_STRING;
+     
+    XChangeProperty (x_dpy, e->requestor, e->property, e->target,
+		     32, PropModeReplace, (unsigned char *) list,
+		     sizeof (list) / sizeof (Atom));
+    reply.xselection.property = e->property;
+    /*
+     * 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);
+}
 
-    target = e->target;
-    
-    if (target == atoms->targets) 
-    {
-	/* This is where we respond to the TARGETS request. */
-	long data[2];
 
-	data[0] = atoms->utf8_string;
-	data[1] = XA_STRING;
+/*TODO finish this - it's flawed. */
+- (void) send_multiple:(XSelectionRequestEvent *)e
+{
+#if 0
+    XEvent reply;
+    int i, nitems;
+    unsigned long *atoms;
 
-	/*TODO add handling for when the data can be represented as an image. */
+    if (None == e->property)
+	return;
 
-	XChangeProperty (x_dpy, e->requestor, e->property, target,
-			 8, PropModeReplace, (unsigned char *) &data,
-			 sizeof (data));
-	reply.xselection.property = e->property;
-    }
-    else if (target == atoms->multiple)
+    atoms = read_prop_32 (e->requestor, e->property, &nitems);
+    
+    if (atoms != NULL)
     {
-	if (e->property != None)
-	{
-	    int i, nitems;
-	    unsigned long *atoms;
+	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);
+	}
 
-	    atoms = read_prop_32 (e->requestor, e->property, &nitems);
+	XChangeProperty (x_dpy, e->requestor, e->property, target,
+			 32, PropModeReplace, (unsigned char *) atoms,
+			 nitems);
+	XFree (atoms);
+    }
+#endif
+}
 
-	    if (atoms != NULL)
-	    {
-		data = [_pasteboard stringForType:NSStringPboardType];
+- (void) send_string:(XSelectionRequestEvent *)e utf8:(BOOL)utf8
+{
+    XEvent reply;
+    NSArray *pbtypes;
+    
+    TRACE ();
 
-		for (i = 0; i < nitems; i += 2)
-		{
-		    Atom target = atoms[i], prop = atoms[i+1];
+    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; 
 
-		    atoms[i+1] = convert_1 (e, data, target, prop);
-		}
+    pbtypes = [_pasteboard types];
 
-		XChangeProperty (x_dpy, e->requestor, e->property, target,
-				 32, PropModeReplace, (unsigned char *) atoms,
-				 nitems);
-		XFree (atoms);
+    if ([pbtypes containsObject: NSStringPboardType])
+    {
+	NSString *data = [_pasteboard stringForType:NSStringPboardType];
+	if (nil != data)
+	{
+	    const char *bytes;
+	    NSUInteger length;
+
+	    if (utf8) {
+		bytes = [data UTF8String];
+		/*
+		 * We don't want the UTF-8 string length here.  
+		 * We want the length in bytes.
+		 */
+		length = [data lengthOfBytesUsingEncoding:NSASCIIStringEncoding];
+	    } else {
+		bytes = [data cStringUsingEncoding:NSISOLatin1StringEncoding];
+		length = [data lengthOfBytesUsingEncoding:NSASCIIStringEncoding];
 	    }
+
+	    XChangeProperty (x_dpy, e->requestor, e->property, e->target,
+			     8, PropModeReplace, (unsigned char *) bytes, length);
+	    
+	    reply.xselection.property = e->property;
+
+	    [data release];
 	}
     }
+    /* Always send a response, even if the property value is None. */
+    XSendEvent (x_dpy, e->requestor, False, 0, &reply);
+}
+
+- (void) request_event:(XSelectionRequestEvent *)e
+{
+    /* Someone's asking us for the data on the pasteboard */
+    TRACE ();
 
-    data = [_pasteboard stringForType:NSStringPboardType];
-    if (data != nil)
+    /* TODO We should also keep track of the time of the selection, and 
+     * according to the ICCCM "refuse the request" if the event timestamp
+     * is before we owned it.
+     * What should we base the time on?  How can we get the current time just
+     * before an XSetSelectionOwner?  Is it the server's time, or the clients?
+     * According to the XSelectionRequestEvent manual page, the Time value
+     * may be set to CurrentTime or a time, so that makes it a bit different.
+     * Perhaps we should just punt and ignore races.
+     */
+    
+    if (e->target == atoms->targets) 
     {
-	reply.xselection.property = convert_1 (e, data, target, e->property);
+	/* The paste requestor wants to know what TARGETS we support. */
+	[self send_targets:e];
+    }
+    else if (e->target == atoms->multiple)
+    {
+	[self send_multiple:e];
+    } 
+    else if (e->target == atoms->utf8_string)
+    {
+	[self send_string:e utf8:YES];
+    } 
+    else if (e->target == atoms->string)
+    {
+	[self send_string:e utf8:NO];
+    } 
+    else 
+    {
+	//[self send_null:e];
     }
-
-    XSendEvent (x_dpy, e->requestor, False, 0, &reply);
 }
 
 /* This handles the events resulting from an XConvertSelection request. */
@@ -536,6 +658,8 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     Atom type;
     struct propdata pdata;
 	
+    TRACE ();
+
     [self release_pending];
     
     DB ("notify_event\n");
@@ -551,7 +675,6 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 	 * This is an INCR-style transfer, which means that we 
 	 * will get the data after a series of PropertyNotify events.
 	 */
-
 	DB ("is INCR\n");
 
 	if (get_property (e->requestor, e->property, &pdata, /*Delete*/ True, &type)) 
@@ -573,6 +696,9 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 
 	/* We have the complete selection data.*/
 	[self handle_selection: e->selection type:type propdata:&pdata];
+
+	if (pbproxy_clipboard_to_pasteboard && e->selection == atoms->clipboard)
+	    [self own_clipboard];
     }
 }
 
@@ -582,10 +708,18 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     struct propdata pdata;
     Atom type;
 
+    TRACE ();
+
     if (None != pending.requestor && PropertyNewValue == e->state) 
     {
+	DB ("pending.requestor 0x%lx\n", pending.requestor);
+
 	if (get_property (e->window, e->atom, &pdata, /*Delete*/ True, &type))
-	{
+        {
+	    if (pbproxy_clipboard_to_pasteboard && pending.selection == atoms->clipboard)
+		[self own_clipboard];
+    
+	    [self release_pending];
 	    return;
 	}
 
@@ -593,6 +727,9 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 	{
 	    /* We completed the transfer. */
 	    [self handle_selection: pending.selection type: type propdata: &pending.propdata];
+	   
+	    if (pbproxy_clipboard_to_pasteboard && pending.selection == atoms->clipboard)
+		[self own_clipboard];
 	    pending.propdata = null_propdata;
 	    pending.requestor = None;
 	    pending.selection = None;
@@ -607,8 +744,12 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 - (void) handle_targets: (Atom)selection propdata:(struct propdata *)pdata
 {
     /* Find a type we can handle and prefer from the list of ATOMs. */
-    Atom preferred = find_preferred (pdata);
+    Atom preferred;
+
+    TRACE ();
 
+    preferred = find_preferred (pdata);
+    
     if (None == preferred) 
     {
 	/* 
@@ -624,6 +765,8 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 		       _selection_window, CurrentTime);    
 }
 
+/*TODO I think this should convert to a standard NSPasteboard format, 
+ * such as TIFF or PICT with a NSBitmapImageRep class.  */
 /* This handles the image type of selection (typically in CLIPBOARD). */
 - (void) handle_image: (struct propdata *)pdata extension:(NSString *)fileext
 {
@@ -632,6 +775,8 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     NSUInteger length;
     NSData *data;
 
+    TRACE ();
+
     pbtype = NSCreateFileContentsPboardType (fileext);
     if (nil == pbtype) 
     {
@@ -674,22 +819,48 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 /* This handles the UTF8_STRING type of selection. */
 - (void) handle_utf8_string: (struct propdata *)pdata
 {
-    NSString *string = [[NSString alloc] initWithBytes:pdata->data length:pdata->length encoding:NSUTF8StringEncoding];
+    NSString *string;
+    NSArray *pbtypes;
+
+    TRACE ();
+    
+    string = [[NSString alloc] initWithBytes:pdata->data length:pdata->length encoding:NSUTF8StringEncoding];
+ 
     if (nil == string)
 	return;
 
-    [_pasteboard setString:string forType:NSStringPboardType];
+    pbtypes = [NSArray arrayWithObject:NSStringPboardType];
+
+    if (nil != pbtypes)
+    {
+	[_pasteboard declareTypes:pbtypes owner:self];
+	[_pasteboard setString:string forType:NSStringPboardType];
+	[pbtypes release];
+    }
+
     [string release];
 }
 
 /* This handles the XA_STRING type, which should be in Latin-1. */
 - (void) handle_string: (struct propdata *)pdata
 {
-    NSString *string = [[NSString alloc] initWithBytes:pdata->data length:pdata->length encoding:NSISOLatin1StringEncoding];
+    NSString *string; 
+    NSArray *pbtypes;
+
+    string = [[NSString alloc] initWithBytes:pdata->data length:pdata->length encoding:NSISOLatin1StringEncoding];
+    
     if (nil == string)
 	return;
 
-    [_pasteboard setString:string forType:NSStringPboardType];
+    pbtypes = [NSArray arrayWithObject:NSStringPboardType];
+
+    if (nil != pbtypes)
+    {
+	[_pasteboard declareTypes:pbtypes owner:self];
+	[_pasteboard setString:string forType:NSStringPboardType];
+	[pbtypes release];
+    }
+
     [string release];
 }
 
@@ -724,6 +895,9 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     
     if (selection == atoms->clipboard && pdata->data)
     {
+	/* This may not be used. 
+	 * We should really pull from the data in the NSPasteboard.
+	 */
 	free_propdata(&request_data.propdata);
 	request_data.propdata = *pdata;
 	request_data.type = type;
@@ -745,8 +919,6 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 {
     TRACE ();
 
-    DB ("PB changed owner");
-
     /* Right now we don't care with this. */
 }
 
@@ -806,3 +978,4 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 }
 
 @end
+
commit 7c2178963380fdbae7a6ad92879e580046e3f9ae
Author: George Peter Staplin <gps at Georges-Workstation.local>
Date:   Mon Sep 15 13:35:46 2008 -0600

    Rename reclaim_clipboard to claim_clipboard.
    
    Convert the puts usage to use DB().
    
    Add the initial handle_image method.
    
    Check for nil in the NSString instantiation in various places.
    
    Add some commentary to enhance the clarity of why I did some things.
    (cherry picked from commit 37361567b65241eab64e8b30cd9729d0e71a86d2)

diff --git a/hw/xquartz/pbproxy/x-selection.m b/hw/xquartz/pbproxy/x-selection.m
index 514f3ce..c2d2bcd 100644
--- a/hw/xquartz/pbproxy/x-selection.m
+++ b/hw/xquartz/pbproxy/x-selection.m
@@ -334,10 +334,8 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 
     if (None != w)
     {
+	DB ("requesting targets\n");
 	request_atom = atoms->targets;
-
-	puts("Asking for targets");
-
 	XConvertSelection (x_dpy, atoms->primary, atoms->targets,
 			   atoms->primary, _selection_window, CurrentTime);
     }
@@ -376,7 +374,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 	/* 
 	 * We lost ownership of the CLIPBOARD.
 	 */
-	[self reclaim_clipboard];
+	[self claim_clipboard];
     } 
     else if (atoms->clipboard_manager == e->selection)
     {
@@ -393,7 +391,7 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 /* 
  * We greedily acquire the clipboard after it changes, and on startup.
  */
-- (void) reclaim_clipboard
+- (void) claim_clipboard
 {
     Window owner;
     
@@ -404,6 +402,8 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 	 * The owner probably died or we are just starting up pbproxy.
 	 * Set pbproxy's _selection_window as the owner, and continue.
 	 */
+	DB ("No clipboard owner.\n");
+
 	do 
 	{
 	    XSetSelectionOwner (x_dpy, atoms->clipboard, _selection_window,
@@ -414,6 +414,8 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
 	return;
     }
     
+    DB ("requesting targets\n");
+
     request_atom = atoms->targets;
     XConvertSelection (x_dpy, atoms->clipboard, atoms->targets,
 		       atoms->clipboard, _selection_window, CurrentTime);
@@ -439,7 +441,7 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 	const char *bytes;
 
 	if (target == XA_STRING)
-	    bytes = [data lossyCString];
+	    bytes = [data cStringUsingEncoding:NSISOLatin1StringEncoding];
 	else
 	    bytes = [data UTF8String];
 
@@ -452,6 +454,8 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 	}
     }
     /* FIXME: handle COMPOUND_TEXT target */
+    /*gstaplin: should we [data release]? */
+    [data release];
 
     return ret;
 }
@@ -482,6 +486,8 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 	data[0] = atoms->utf8_string;
 	data[1] = XA_STRING;
 
+	/*TODO add handling for when the data can be represented as an image. */
+
 	XChangeProperty (x_dpy, e->requestor, e->property, target,
 			 8, PropModeReplace, (unsigned char *) &data,
 			 sizeof (data));
@@ -532,9 +538,9 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 	
     [self release_pending];
     
-    puts ("NOTIFY EVENT");
+    DB ("notify_event\n");
     if (None == e->property) {
-	puts("Nothing");
+	DB ("e->property is None.\n");
 	/* Nothing is selected. */
 	return;
     }
@@ -546,7 +552,7 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 	 * will get the data after a series of PropertyNotify events.
 	 */
 
-	puts("IS INCR");
+	DB ("is INCR\n");
 
 	if (get_property (e->requestor, e->property, &pdata, /*Delete*/ True, &type)) 
 	{
@@ -565,13 +571,12 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 	    return;
 	}
 
-	puts("HANDLING NOW");
-	
 	/* We have the complete selection data.*/
 	[self handle_selection: e->selection type:type propdata:&pdata];
     }
 }
 
+/* This is used for INCR transfers.  See the ICCCM for the details. */
 - (void) property_event:(XPropertyEvent *)e
 {
     struct propdata pdata;
@@ -601,6 +606,7 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 
 - (void) handle_targets: (Atom)selection propdata:(struct propdata *)pdata
 {
+    /* Find a type we can handle and prefer from the list of ATOMs. */
     Atom preferred = find_preferred (pdata);
 
     if (None == preferred) 
@@ -612,30 +618,66 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 	preferred = XA_STRING;
     }
 
+    DB ("requesting %s\n", XGetAtomName (x_dpy, preferred));
     request_atom = preferred;
     XConvertSelection (x_dpy, selection, preferred, selection,
 		       _selection_window, CurrentTime);    
 }
 
-/* This handles the image/png type of selection (typically in CLIPBOARD). */
-- (void) handle_png: (struct propdata *)pdata
+/* This handles the image type of selection (typically in CLIPBOARD). */
+- (void) handle_image: (struct propdata *)pdata extension:(NSString *)fileext
 {
-    /* TODO Use the NSPasteboard code I wrote that may work... */
+    NSString *pbtype;
+    NSArray *pbtypes;
+    NSUInteger length;
+    NSData *data;
+
+    pbtype = NSCreateFileContentsPboardType (fileext);
+    if (nil == pbtype) 
+    {
+	fprintf (stderr, "unknown extension or unable to create PboardType\n");
+	return;
+    }
+    
+    DB ("%s\n", [pbtype cStringUsingEncoding:NSISOLatin1StringEncoding]); 
+    
+    pbtypes = [NSArray arrayWithObject: pbtype];
+    if (nil == pbtypes) 
+    {
+       DB ("error creating NSArray\n");
+       [pbtype release];
+       return;
+    }
+    
+    length = pdata->length;
+    data = [[NSData alloc] initWithBytes:pdata->data length:length];
+    if (nil == data)
+    {
+	[pbtype release];
+	[pbtypes release];
+	return;
+    }
+
+    [_pasteboard declareTypes:pbtypes owner:self];
+    if (YES != [_pasteboard setData:data forType:pbtype])
+    {
+	DB ("writing pasteboard data failed!\n");
+    }
+
+    [pbtype release];
+    [pbtypes release];
+    [data release];
+    
+    DB ("handled image\n");
 }
 
 /* This handles the UTF8_STRING type of selection. */
 - (void) handle_utf8_string: (struct propdata *)pdata
 {
-    size_t i;
-    unsigned char *p = pdata->data;
-
-    puts("HANDLE UTF8_STRING");
-    for (i = 0; i < pdata->length; ++i) {
-	printf("%c", p[i]);
-    }
-    puts("");
-
     NSString *string = [[NSString alloc] initWithBytes:pdata->data length:pdata->length encoding:NSUTF8StringEncoding];
+    if (nil == string)
+	return;
+
     [_pasteboard setString:string forType:NSStringPboardType];
     [string release];
 }
@@ -643,13 +685,15 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 /* This handles the XA_STRING type, which should be in Latin-1. */
 - (void) handle_string: (struct propdata *)pdata
 {
-    puts("STRING");
-
     NSString *string = [[NSString alloc] initWithBytes:pdata->data length:pdata->length encoding:NSISOLatin1StringEncoding];
+    if (nil == string)
+	return;
+
     [_pasteboard setString:string forType:NSStringPboardType];
     [string release];
 }
 
+/* This is called when the selection is completely retrieved from another client. */
 /* Warning: this frees the propdata in most cases. */
 - (void) handle_selection:(Atom)selection type:(Atom)type propdata:(struct propdata *)pdata
 {
@@ -659,8 +703,12 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     } 
     else if (type == atoms->image_png)
     {
-	[self handle_png:pdata];
+	[self handle_image:pdata extension:@".png"];
     } 
+    else if (type == atoms->image_jpeg)
+    {
+	[self handle_image:pdata extension:@".jpeg"];
+    }
     else if (type == atoms->utf8_string) 
     {
 	[self handle_utf8_string:pdata];
@@ -674,7 +722,7 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 	free_propdata(pdata);
     }
     
-    if (selection == atoms->clipboard)
+    if (selection == atoms->clipboard && pdata->data)
     {
 	free_propdata(&request_data.propdata);
 	request_data.propdata = *pdata;
@@ -697,7 +745,7 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 {
     TRACE ();
 
-    puts("PB changed owner");
+    DB ("PB changed owner");
 
     /* Right now we don't care with this. */
 }
@@ -721,6 +769,7 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     _selection_window = XCreateSimpleWindow (x_dpy, DefaultRootWindow (x_dpy),
 					     0, 0, 1, 1, 0, pixel, pixel);
 
+    /* This is used to get PropertyNotify events when doing INCR transfers. */
     XSelectInput (x_dpy, _selection_window, PropertyChangeMask);
 
     request_atom = None;
commit adbe6881c83090c39484877613fab5f15f4da14d
Author: George Peter Staplin <gps at Georges-Workstation.local>
Date:   Mon Sep 15 13:31:19 2008 -0600

    Add an image_jpeg Atom.
    (cherry picked from commit ea9dc27977c5eab666f2aa2d914e4e28d36758c7)

diff --git a/hw/xquartz/pbproxy/pbproxy.h b/hw/xquartz/pbproxy/pbproxy.h
index 3682421..ad8f2e4 100644
--- a/hw/xquartz/pbproxy/pbproxy.h
+++ b/hw/xquartz/pbproxy/pbproxy.h
@@ -25,7 +25,7 @@ extern int x_apple_wm_event_base, x_apple_wm_error_base;
 
 struct atom_list {
     Atom primary, clipboard, text, utf8_string, string, targets, multiple,
-	cstring, image_png, incr, atom, clipboard_manager;
+	cstring, image_png, image_jpeg, incr, atom, clipboard_manager;
 };
 
 extern struct atom_list *atoms;
commit 61354ea80de1ac3e1142b134491ae343010a0349
Author: George Peter Staplin <gps at Georges-Workstation.local>
Date:   Mon Sep 15 13:28:50 2008 -0600

    Rename reclaim_clipboard to claim_clipboard.
    (cherry picked from commit d333a8e2b5514b8b76a78c6a13a3f5149ea8de27)

diff --git a/hw/xquartz/pbproxy/x-selection.h b/hw/xquartz/pbproxy/x-selection.h
index 88408bf..d27b3fa 100644
--- a/hw/xquartz/pbproxy/x-selection.h
+++ b/hw/xquartz/pbproxy/x-selection.h
@@ -89,7 +89,7 @@ struct propdata {
 - (void) notify_event:(XSelectionEvent *)e;
 - (void) property_event:(XPropertyEvent *)e;
 - (void) handle_selection:(Atom)selection type:(Atom)type propdata:(struct propdata *)pdata;
-- (void) reclaim_clipboard;
+- (void) claim_clipboard;
 - (void) set_clipboard_manager;
 
 @end
commit 05db9d60228617b44465ca98c3ab2c32d4a648f5
Author: George Peter Staplin <gps at Georges-Workstation.local>
Date:   Mon Sep 15 13:27:08 2008 -0600

    Add image/jpeg type, and rename reclaim_clipboard to claim_clipboard.
    (cherry picked from commit 32b175ef62b68a971784e51e937e358cb10e20ac)

diff --git a/hw/xquartz/pbproxy/main.m b/hw/xquartz/pbproxy/main.m
index f259726..4b1dac1 100644
--- a/hw/xquartz/pbproxy/main.m
+++ b/hw/xquartz/pbproxy/main.m
@@ -20,7 +20,8 @@ struct atom_list *atoms = &atom_list_inst;
 static int x_grab_count;
 static Bool x_grab_synced;
 
-static BOOL _is_active = YES;		/* FIXME: should query server */ /*GPS why? Is there a race?*/
+static BOOL _is_active = YES;		/* FIXME: should query server */ 
+/*gstaplin: why? Is there a race?*/
 
 static x_selection *_selection_object;
 
@@ -72,6 +73,7 @@ static void x_init (void) {
     atoms->multiple = XInternAtom (x_dpy, "MULTIPLE", False);
     atoms->cstring = XInternAtom (x_dpy, "CSTRING", False);
     atoms->image_png = XInternAtom (x_dpy, "image/png", False);
+    atoms->image_jpeg = XInternAtom (x_dpy, "image/jpeg", False);
     atoms->incr = XInternAtom (x_dpy, "INCR", False);
     atoms->atom = XInternAtom (x_dpy, "ATOM", False);
     atoms->clipboard_manager = XInternAtom (x_dpy, "CLIPBOARD_MANAGER", False);
@@ -91,20 +93,19 @@ static void x_init (void) {
     x_input_run ();
 
     [_selection_object set_clipboard_manager];
-    [_selection_object reclaim_clipboard];
+    [_selection_object claim_clipboard];
 }
 
 static void x_shutdown (void) {
-    /*GPS: signal_handler() calls this, and I don't think these are async-signal safe. */
-    /*TODO use a socketpair() to trigger a cleanup.  This is totally unsafe according to Jordan. */
+    /*gstaplin: signal_handler() calls this, and I don't think these are async-signal safe. */
+    /*TODO use a socketpair() to trigger a cleanup.  This is totally unsafe according to Jordan.  It's a segfault waiting to happen on a signal*/
 
     [_selection_object release];
     _selection_object = nil;
 
-
     XCloseDisplay (x_dpy);
     x_dpy = NULL;
-    exit(0); //GPS this is almost certainly unsafe (sigaction(2) doesn't list it).
+    exit(0); 
 }
 
 static void x_error_shutdown (void) {
commit 981fddf2bfd87ecb3b3c182091ddec5baf3e8ad1
Author: Jeremy Huddleston <jeremyhu at freedesktop.org>
Date:   Mon Sep 15 09:33:55 2008 -0700

    XQuartz: pbproxy: Added global variables to customize how pbproxy behaves
    (cherry picked from commit 21a2d0b8d03faf1c66ec0c5c11fbd2ab24547727)

diff --git a/hw/xquartz/pbproxy/x-selection.m b/hw/xquartz/pbproxy/x-selection.m
index e390dc0..514f3ce 100644
--- a/hw/xquartz/pbproxy/x-selection.m
+++ b/hw/xquartz/pbproxy/x-selection.m
@@ -36,6 +36,13 @@
 
 #include <unistd.h> /*GPS may not be needed now */
 
+// These will be set by X11Controller.m once this is integrated into a server thread
+BOOL pbproxy_active = YES;
+BOOL pbproxy_primary_on_grab = NO; // This is provided as an option for people who want it and has issues that won't ever be addressed to make it *always* work
+BOOL pbproxy_clipboard_to_pasteboard = YES;
+BOOL pbproxy_pasteboard_to_primary = YES;
+BOOL pbproxy_pasteboard_to_clipboard = YES;
+
 @implementation x_selection
 
 static struct propdata null_propdata = {NULL, 0};
commit 290e3432812511c98caaf7f74f248c4481599d42
Author: Jeremy Huddleston <jeremyhu at freedesktop.org>
Date:   Sun Sep 14 09:23:17 2008 -0700

    XQuartz: pbproxy: First round of updates to pbproxy from George.
    (cherry picked from commit 5c8b956f8f3f17e8d577d97cb66424954be72684)

diff --git a/hw/xquartz/pbproxy/main.m b/hw/xquartz/pbproxy/main.m
index eaf14a7..f259726 100644
--- a/hw/xquartz/pbproxy/main.m
+++ b/hw/xquartz/pbproxy/main.m
@@ -14,14 +14,13 @@
 Display *x_dpy;
 int x_apple_wm_event_base, x_apple_wm_error_base;
 
-Atom x_atom_wm_state, x_atom_wm_protocols, x_atom_wm_delete_window;
-Atom x_atom_clipboard, x_atom_text, x_atom_utf8_string;
-Atom x_atom_targets, x_atom_multiple, x_atom_cstring;
+struct atom_list atom_list_inst;
+struct atom_list *atoms = &atom_list_inst;
 
 static int x_grab_count;
 static Bool x_grab_synced;
 
-static BOOL _is_active = YES;		/* FIXME: should query server */
+static BOOL _is_active = YES;		/* FIXME: should query server */ /*GPS why? Is there a race?*/
 
 static x_selection *_selection_object;
 
@@ -65,19 +64,24 @@ static void x_init (void) {
     }
     
     XSetIOErrorHandler (x_io_error_handler);
-    x_atom_clipboard = XInternAtom (x_dpy, "CLIPBOARD", False);
-    x_atom_text = XInternAtom (x_dpy, "TEXT", False);
-    x_atom_utf8_string = XInternAtom (x_dpy, "UTF8_STRING", False);
-    x_atom_targets = XInternAtom (x_dpy, "TARGETS", False);
-    x_atom_multiple = XInternAtom (x_dpy, "MULTIPLE", False);
-    x_atom_cstring = XInternAtom (x_dpy, "CSTRING", False);
-        
+    atoms->primary = XInternAtom (x_dpy, "PRIMARY", False);
+    atoms->clipboard = XInternAtom (x_dpy, "CLIPBOARD", False);
+    atoms->text = XInternAtom (x_dpy, "TEXT", False);
+    atoms->utf8_string = XInternAtom (x_dpy, "UTF8_STRING", False);
+    atoms->targets = XInternAtom (x_dpy, "TARGETS", False);
+    atoms->multiple = XInternAtom (x_dpy, "MULTIPLE", False);
+    atoms->cstring = XInternAtom (x_dpy, "CSTRING", False);
+    atoms->image_png = XInternAtom (x_dpy, "image/png", False);
+    atoms->incr = XInternAtom (x_dpy, "INCR", False);
+    atoms->atom = XInternAtom (x_dpy, "ATOM", False);
+    atoms->clipboard_manager = XInternAtom (x_dpy, "CLIPBOARD_MANAGER", False);
+
     if (!XAppleWMQueryExtension (x_dpy, &x_apple_wm_event_base,
                                  &x_apple_wm_error_base)) {
         fprintf (stderr, "can't open AppleWM server extension\n");
         exit (1);
     }
-        
+    
     XAppleWMSelectInput (x_dpy, AppleWMActivationNotifyMask |
                          AppleWMPasteboardNotifyMask);
     
@@ -85,15 +89,22 @@ static void x_init (void) {
     
     x_input_register ();
     x_input_run ();
+
+    [_selection_object set_clipboard_manager];
+    [_selection_object reclaim_clipboard];
 }
 
 static void x_shutdown (void) {
+    /*GPS: signal_handler() calls this, and I don't think these are async-signal safe. */
+    /*TODO use a socketpair() to trigger a cleanup.  This is totally unsafe according to Jordan. */
+
     [_selection_object release];
     _selection_object = nil;
 
+
     XCloseDisplay (x_dpy);
     x_dpy = NULL;
-    exit(0);
+    exit(0); //GPS this is almost certainly unsafe (sigaction(2) doesn't list it).
 }
 
 static void x_error_shutdown (void) {
diff --git a/hw/xquartz/pbproxy/pbproxy.h b/hw/xquartz/pbproxy/pbproxy.h
index ddadbb3..3682421 100644
--- a/hw/xquartz/pbproxy/pbproxy.h
+++ b/hw/xquartz/pbproxy/pbproxy.h
@@ -22,8 +22,13 @@ extern Time x_current_timestamp (void);
 
 extern Display *x_dpy;
 extern int x_apple_wm_event_base, x_apple_wm_error_base;
-extern Atom x_atom_clipboard, x_atom_text, x_atom_utf8_string;
-extern Atom x_atom_targets, x_atom_multiple, x_atom_cstring;
+
+struct atom_list {
+    Atom primary, clipboard, text, utf8_string, string, targets, multiple,
+	cstring, image_png, incr, atom, clipboard_manager;
+};
+
+extern struct atom_list *atoms;
 
 /* from x-input.m */
 extern void x_input_register (void);
diff --git a/hw/xquartz/pbproxy/x-input.m b/hw/xquartz/pbproxy/x-input.m
index 2e77250..f720af5 100644
--- a/hw/xquartz/pbproxy/x-input.m
+++ b/hw/xquartz/pbproxy/x-input.m
@@ -21,7 +21,13 @@ CFRunLoopSourceRef x_dpy_source;
 /* Timestamp when the X server last told us it's active */
 static Time last_activation_time;
 
+static FILE *getSelectionLog(void) {
+    return fopen("/tmp/selection.log", "a");
+}
+
 static void x_event_apple_wm_notify(XAppleWMNotifyEvent *e) {
+    FILE *fp = getSelectionLog();
+
     switch (e->type - x_apple_wm_event_base) {              
         case AppleWMActivationNotify:
             switch (e->kind) {
@@ -39,33 +45,47 @@ static void x_event_apple_wm_notify(XAppleWMNotifyEvent *e) {
             break;
             
         case AppleWMPasteboardNotify:
+	    fprintf(fp, "AppleWMPasteboardNotify\n");
+	   
             switch (e->kind) {
                 case AppleWMCopyToPasteboard:
                     [x_selection_object () x_copy:e->time];
             }
             break;
     }
+    fclose(fp);
 }
 
 void x_input_run (void) {
+    FILE *fp = getSelectionLog();
+
     while (XPending (x_dpy) != 0) {
-        XEvent e;
-        
+        XEvent e;       
+
         XNextEvent (x_dpy, &e);
         
         switch (e.type) {                
             case SelectionClear:
-                [x_selection_object () clear_event:&e.xselectionclear];
+		fprintf(fp, "SelectionClear\n");
+
+	        [x_selection_object () clear_event:&e.xselectionclear];
                 break;
                 
             case SelectionRequest:
+		fprintf(fp, "SelectionRequest\n");
                 [x_selection_object () request_event:&e.xselectionrequest];
                 break;
                 
             case SelectionNotify:
+		fprintf(fp, "SelectionNotify\n");
                 [x_selection_object () notify_event:&e.xselection];
                 break;
                 
+	    case PropertyNotify:
+		fprintf(fp, "PropertyNotify\n");
+		[x_selection_object () property_event:&e.xproperty];
+		break;
+
             default:
                 if (e.type - x_apple_wm_event_base >= 0
                     && e.type - x_apple_wm_event_base < AppleWMNumberEvents) {
@@ -73,7 +93,10 @@ void x_input_run (void) {
                 }
                 break;
         }
+
+	XFlush(x_dpy);
     }
+    fclose(fp);
 }
 
 static int add_input_socket (int sock, CFOptionFlags callback_types,
@@ -111,3 +134,4 @@ void x_input_register(void) {
         exit (1);
     }
 }
+
diff --git a/hw/xquartz/pbproxy/x-selection.h b/hw/xquartz/pbproxy/x-selection.h
index b31bf63..88408bf 100644
--- a/hw/xquartz/pbproxy/x-selection.h
+++ b/hw/xquartz/pbproxy/x-selection.h
@@ -34,6 +34,12 @@
 #include "pbproxy.h"
 #include <AppKit/NSPasteboard.h>
 
+/* This stores image data or text. */
+struct propdata {
+	unsigned char *data;
+	size_t length;
+};
+
 @interface x_selection : NSObject
 {
 @private
@@ -53,6 +59,24 @@
 
     /* When true, we're expecting a SelectionNotify event. */
     unsigned int _pending_notify :1;
+ 
+    Atom request_atom;
+    
+    struct {
+        struct propdata propdata;
+        Window requestor;
+        Atom selection;
+    } pending;
+ 
+    /* This may not be needed.*/
+    /* If we can have the Apple clipboard translate to PNG or JPEG we can
+     * do away with this.   Otherwise we could use libjpeg and libpng
+     * to convert some raw clipboard format to the proper format.
+     */
+    struct {
+	struct propdata propdata;
+	Atom type;
+    } request_data;
 }
 
 - (void) x_active:(Time)timestamp;
@@ -63,6 +87,10 @@
 - (void) clear_event:(XSelectionClearEvent *)e;
 - (void) request_event:(XSelectionRequestEvent *)e;
 - (void) notify_event:(XSelectionEvent *)e;
+- (void) property_event:(XPropertyEvent *)e;
+- (void) handle_selection:(Atom)selection type:(Atom)type propdata:(struct propdata *)pdata;
+- (void) reclaim_clipboard;
+- (void) set_clipboard_manager;
 
 @end
 
diff --git a/hw/xquartz/pbproxy/x-selection.m b/hw/xquartz/pbproxy/x-selection.m
index 5b2ba9c..e390dc0 100644
--- a/hw/xquartz/pbproxy/x-selection.m
+++ b/hw/xquartz/pbproxy/x-selection.m
@@ -30,12 +30,172 @@
 
 #import "x-selection.h"
 
+#include <stdio.h>
+#include <stdlib.h>
 #include <X11/Xatom.h>
 
-#include <unistd.h>
+#include <unistd.h> /*GPS may not be needed now */
 
 @implementation x_selection
 
+static struct propdata null_propdata = {NULL, 0};
+
+static void
+init_propdata (struct propdata *pdata)
+{
+    *pdata = null_propdata;
+}
+
+static void
+free_propdata (struct propdata *pdata)
+{
+    free (pdata->data);
+    *pdata = null_propdata;
+}
+
+/* Return True if this is an INCR-style transfer. */
+static Bool
+is_incr_type (XSelectionEvent *e)
+{
+    Atom seltype;
+    int format;
+    unsigned long numitems = 0UL, bytesleft = 0UL;
+    unsigned char *chunk;
+       
+    if (Success != XGetWindowProperty (x_dpy, e->requestor, e->property,
+				       /*offset*/ 0L, /*length*/ 4UL,
+				       /*Delete*/ False,
+				       AnyPropertyType, &seltype, &format,
+				       &numitems, &bytesleft, &chunk))
+    {
+	return False;
+    }
+
+    if(chunk)
+	XFree(chunk);
+
+    return (seltype == atoms->incr) ? True : False;
+}
+
+/* This finds the preferred type from a TARGETS list.*/
+static Atom 
+find_preferred (struct propdata *pdata)
+{
+    Atom a = None;
+    size_t i;
+    Bool png = False, utf8 = False, string = False;
+
+    if (pdata->length % sizeof (a))
+    {
+	fprintf(stderr, "Atom list is not a multiple of the size of an atom!\n");
+	return None;
+    }
+
+    for (i = 0; i < pdata->length; i += sizeof (a))
+    {
+	memcpy (&a, pdata->data + i, sizeof (a));
+	
+	if (a == atoms->image_png)
+	{
+	    png = True;
+	} 
+	else if (a == atoms->utf8_string)
+	{
+	    utf8 = True;
+        } 
+	else if (a == atoms->string)
+	{
+	    string = True;
+	}
+    }
+
+    /*We prefer PNG over strings, and UTF8 over a Latin-1 string.*/
+    if (png)
+	return atoms->image_png;
+
+    if (utf8)
+	return atoms->utf8_string;
+
+    if (string)
+	return atoms->string;
+
+    /* This is evidently something we don't know how to handle.*/
+    return None;
+}
+
+/*
+ * Return True if an error occurs.  Return False if pdata has data 
+ * and we finished. 
+ * The property is only deleted when bytesleft is 0 if delete is True.
+ */
+static Bool
+get_property(Window win, Atom property, struct propdata *pdata, Bool delete, Atom *type) 
+{
+    long offset = 0;
+    unsigned long numitems, bytesleft = 0;
+#ifdef TEST
+    /* This is used to test the growth handling. */
+    unsigned long length = 4UL;
+#else
+    unsigned long length = (100000UL + 3) / 4; 
+#endif
+    unsigned char *buf = NULL, *chunk = NULL;
+    size_t buflen = 0, chunkbytesize = 0;
+    int format;
+    
+    if(None == property)
+	return True;
+    
+    do {
+	unsigned long newbuflen;
+	unsigned char *newbuf;
+	
+	if (Success != XGetWindowProperty (x_dpy, win, property,
+					   offset, length, delete, 
+					   AnyPropertyType,
+					   type, &format, &numitems, 
+					   &bytesleft, &chunk)) {
+	    free (buf);
+	    return True;
+	}
+	
+#ifdef TEST
+	printf("format %d numitems %lu bytesleft %lu\n",
+	       format, numitems, bytesleft);
+	
+	printf("type %s\n", XGetAtomName(dis, *type));
+#endif
+	
+	/* Format is the number of bits. */
+	chunkbytesize = numitems * (format / 8);
+
+#ifdef TEST
+	printf("chunkbytesize %zu\n", chunkbytesize);
+#endif
+	
+	newbuflen = buflen + chunkbytesize;
+	newbuf = realloc (buf, newbuflen);
+	if (NULL == newbuf) {
+	    XFree (chunk);
+	    free (buf);
+	    return True;
+	}
+	
+	memcpy (newbuf + buflen, chunk, chunkbytesize);
+	XFree (chunk);
+	buf = newbuf;
+	buflen = newbuflen;
+	/* offset is a multiple of 32 bits*/
+	offset += chunkbytesize / 4;
+    } while (bytesleft > 0);
+    
+    pdata->data = buf;
+    pdata->length = buflen;
+
+    return /*success*/ False;
+}
+
+
 static unsigned long *
 read_prop_32 (Window id, Atom prop, int *nitems_ret)
 {
@@ -70,50 +230,55 @@ read_prop_32 (Window id, Atom prop, int *nitems_ret)
     return (unsigned long *) data;
 }
 
-float
-get_time (void)
+/* 
+ * This should be called after a selection has been copied, 
+ * or when the selection is unfinished before a transfer completes. 
+ */
+- (void) release_pending
 {
-  extern void Microseconds ();
-  UnsignedWide usec;
-  long long ll;
-
-  Microseconds (&usec);
-  ll = ((long long) usec.hi << 32) | usec.lo;
-
-  return ll / 1e6;
+    free_propdata (&pending.propdata);
+    pending.requestor = None;
+    pending.selection = None;
 }
 
-static Bool
-IfEventWithTimeout (Display *dpy, XEvent *e, int timeout,
-		    Bool (*pred) (Display *, XEvent *, XPointer),
-		    XPointer arg)
+/* Return True if an error occurs during an append.*/
+/* Return False if the append succeeds. */
+- (Bool) append_to_pending:(struct propdata *)pdata requestor:(Window)requestor
 {
-    float start = get_time ();
-    fd_set fds;
-    struct timeval tv;
-
-    do {
-	if (XCheckIfEvent (x_dpy, e, pred, arg))
-	    return True;
-
-	FD_ZERO (&fds);
-	FD_SET (ConnectionNumber (x_dpy), &fds);
-	tv.tv_usec = 0;
-	tv.tv_sec = timeout;
-
-	if (select (FD_SETSIZE, &fds, NULL, NULL, &tv) != 1)
-	    break;
+    unsigned char *newdata;
+    size_t newlength;
+    
+    if (requestor != pending.requestor)
+    {
+	[self release_pending];
+	pending.requestor = requestor;
+    }
+	
+    newlength = pending.propdata.length + pdata->length;
+    newdata = realloc(pending.propdata.data, newlength);
 
-    } while (start + timeout > get_time ());
+    if(NULL == newdata) 
+    {
+	perror("realloc propdata");
+	[self release_pending];
+        return True;
+    }
 
+    memcpy(newdata + pending.propdata.length, pdata->data, pdata->length);
+    pending.propdata.data = newdata;
+    pending.propdata.length = newlength;
+	
     return False;
 }
 
+
+
 /* Called when X11 becomes active (i.e. has key focus) */
 - (void) x_active:(Time)timestamp
 {
     TRACE ();
 
+#if 0
     if ([_pasteboard changeCount] != _my_last_change)
     {
 	if ([_pasteboard availableTypeFromArray: _known_types] != nil)
@@ -121,12 +286,13 @@ IfEventWithTimeout (Display *dpy, XEvent *e, int timeout,
 	    /* Pasteboard has data we should proxy; I think it makes
 	       sense to put it on both CLIPBOARD and PRIMARY */
 
-	    XSetSelectionOwner (x_dpy, x_atom_clipboard,
+	    XSetSelectionOwner (x_dpy, atoms->clipboard,
 				_selection_window, timestamp);
 	    XSetSelectionOwner (x_dpy, XA_PRIMARY,
 				_selection_window, timestamp);
 	}
     }
+#endif
 }
 
 /* Called when X11 loses key focus */
@@ -135,19 +301,20 @@ IfEventWithTimeout (Display *dpy, XEvent *e, int timeout,
     Window w;
 
     TRACE ();
-
+#if 0
     if (_proxied_selection == XA_PRIMARY)
       return;
 
-    w = XGetSelectionOwner (x_dpy, x_atom_clipboard);
+    w = XGetSelectionOwner (x_dpy, atoms->clipboard);
 
     if (w != None && w != _selection_window)
     {
 	/* An X client has the selection, proxy it to the pasteboard */
 
 	_my_last_change = [_pasteboard declareTypes:_known_types owner:self];
-	_proxied_selection = x_atom_clipboard;
+	_proxied_selection = atoms->clipboard;
     }
+#endif
 }
 
 /* Called when the Edit/Copy item on the main X11 menubar is selected
@@ -156,16 +323,16 @@ IfEventWithTimeout (Display *dpy, XEvent *e, int timeout,
 {
     Window w;
 
-    /* Lazily copies the PRIMARY selection to the pasteboard. */
-
-    w = XGetSelectionOwner (x_dpy, XA_PRIMARY);
+    w = XGetSelectionOwner (x_dpy, atoms->primary);
 
-    if (w != None && w != _selection_window)
+    if (None != w)
     {
-	XSetSelectionOwner (x_dpy, x_atom_clipboard,
-			    _selection_window, timestamp);
-	_my_last_change = [_pasteboard declareTypes:_known_types owner:self];
-	_proxied_selection = XA_PRIMARY;
+	request_atom = atoms->targets;
+
+	puts("Asking for targets");
+
+	XConvertSelection (x_dpy, atoms->primary, atoms->targets,
+			   atoms->primary, _selection_window, CurrentTime);
     }
     else
     {
@@ -173,16 +340,80 @@ IfEventWithTimeout (Display *dpy, XEvent *e, int timeout,
     }
 }
 
-
-/* X events */
+/*
+ *
+ */
+- (void) set_clipboard_manager
+{
+    if (None != XGetSelectionOwner (x_dpy, atoms->clipboard_manager))
+    {
+	fprintf (stderr, "A clipboard manager is already running!\n"
+		 "pbproxy can not continue!\n");
+	exit (EXIT_FAILURE);
+    }
 
+    XSetSelectionOwner (x_dpy, atoms->clipboard_manager, _selection_window,
+			CurrentTime);
+}
+
+/*
+ * This occurs when we previously owned a selection, 
+ * and then lost it from another client.
+ */
 - (void) clear_event:(XSelectionClearEvent *)e
 {
     TRACE ();
+ 
+    if (atoms->clipboard == e->selection)
+    {
+	/* 
+	 * We lost ownership of the CLIPBOARD.
+	 */
+	[self reclaim_clipboard];
+    } 
+    else if (atoms->clipboard_manager == e->selection)
+    {
+	/*TODO/HMM  What should we do here? */
+	/* Another CLIPBOARD_MANAGER has set itself as owner.
+         * a) we can call [self set_clipboard_manager] here and risk a war.
+	 * b) we can print a message and exit.
+	 */
+	fprintf (stderr, "error: another clipboard manager was started!\n"); 
+	exit (EXIT_FAILURE);
+    }
+}
+
+/* 
+ * We greedily acquire the clipboard after it changes, and on startup.
+ */
+- (void) reclaim_clipboard
+{
+    Window owner;
+    
+    owner = XGetSelectionOwner (x_dpy, atoms->clipboard);
+    if (None == owner)
+    {
+	/*
+	 * The owner probably died or we are just starting up pbproxy.
+	 * Set pbproxy's _selection_window as the owner, and continue.
+	 */
+	do 
+	{
+	    XSetSelectionOwner (x_dpy, atoms->clipboard, _selection_window,
+				CurrentTime);
+	} while (_selection_window != XGetSelectionOwner (x_dpy,
+							  atoms->clipboard));
 
-    /* Right now we don't care about this. */
+	return;
+    }
+    
+    request_atom = atoms->targets;
+    XConvertSelection (x_dpy, atoms->clipboard, atoms->targets,
+		       atoms->clipboard, _selection_window, CurrentTime);
+    /* Now we will get a SelectionNotify event in the future. */
 }
 
+/* The preference should be for UTF8_STRING before the XA_STRING*/
 static Atom
 convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 {
@@ -191,12 +422,12 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     if (data == nil)
 	return ret;
 
-    if (target == x_atom_text)
-	target = x_atom_utf8_string;
+    if (target == atoms->text)
+	target = atoms->utf8_string;
 
     if (target == XA_STRING
-	|| target == x_atom_cstring
-	|| target == x_atom_utf8_string)
+	|| target == atoms->cstring
+	|| target == atoms->utf8_string)
     {
 	const char *bytes;
 
@@ -221,7 +452,6 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 - (void) request_event:(XSelectionRequestEvent *)e
 {
     /* Someone's asking us for the data on the pasteboard */
-
     XEvent reply;
     NSString *data;
     Atom target;
@@ -236,12 +466,13 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     reply.xselection.property = None;
 
     target = e->target;
-
-    if (target == x_atom_targets)
+    
+    if (target == atoms->targets) 
     {
+	/* This is where we respond to the TARGETS request. */
 	long data[2];
 
-	data[0] = x_atom_utf8_string;
+	data[0] = atoms->utf8_string;
 	data[1] = XA_STRING;
 
 	XChangeProperty (x_dpy, e->requestor, e->property, target,
@@ -249,7 +480,7 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
 			 sizeof (data));
 	reply.xselection.property = e->property;
     }
-    else if (target == x_atom_multiple)
+    else if (target == atoms->multiple)
     {
 	if (e->property != None)
 	{
@@ -286,165 +517,181 @@ convert_1 (XSelectionRequestEvent *e, NSString *data, Atom target, Atom prop)
     XSendEvent (x_dpy, e->requestor, False, 0, &reply);
 }
 
+/* This handles the events resulting from an XConvertSelection request. */
 - (void) notify_event:(XSelectionEvent *)e
 {
-    /* Someone sent us data we're waiting for. */
-
     Atom type;
-    int format, r, offset;
-    unsigned long nitems, bytes_after;
-    unsigned char *data, *buf;
-    NSString *string;
-
-    TRACE ();
+    struct propdata pdata;
+	
+    [self release_pending];
+    
+    puts ("NOTIFY EVENT");
+    if (None == e->property) {
+	puts("Nothing");
+	/* Nothing is selected. */
+	return;
+    }
 
-    if (e->target == x_atom_targets)
+    if (is_incr_type (e)) 
     {
-	/* Was trying to fetch the TARGETS property; it lists the
-	   formats supported by the selection owner. */
+	/*
+	 * This is an INCR-style transfer, which means that we 
+	 * will get the data after a series of PropertyNotify events.
+	 */
 
-	unsigned long *atoms;
-	int natoms;
-	int i, utf8_i = -1, string_i = -1;
+	puts("IS INCR");
 
-	if (e->property != None
-	    && (atoms = read_prop_32 (e->requestor,
-				      e->property, &natoms)) != NULL)
+	if (get_property (e->requestor, e->property, &pdata, /*Delete*/ True, &type)) 
 	{
-	    for (i = 0; i < natoms; i++)
-	    {
-		if (atoms[i] == XA_STRING)
-		    string_i = i;
-		else if (atoms[i] == x_atom_utf8_string)
-		    utf8_i = i;
-	    }
-	    XFree (atoms);
+	    return;
 	}
 
-	/* May as well try as STRING if nothing else, it can only
-	   fail, and it will help broken clients who don't support
-	   the TARGETS selection.. */
-
-	if (utf8_i >= 0)
-	    type = x_atom_utf8_string;
-	else
-	    type = XA_STRING;
+	free_propdata (&pdata);
 
-	XConvertSelection (x_dpy, e->selection, type,
-			   e->selection, e->requestor, e->time);
-	_pending_notify = YES;
-	return;
+	pending.requestor = e->requestor;
+	pending.selection = e->selection;
     }
+    else
+    {
+	if (get_property (e->requestor, e->property, &pdata, /*Delete*/ True, &type))
+	{
+	    return;
+	}
 
-    if (e->property == None)
-	return;				/* FIXME: notify pasteboard? */
-
-    /* Should be the data. Find out how big it is and what format it's in. */
-
-    r = XGetWindowProperty (x_dpy, e->requestor, e->property,
-			    0, 0, False, AnyPropertyType, &type,
-			    &format, &nitems, &bytes_after, &data);
-    if (r != Success)
-	return;
-
-    XFree (data);
-    if (type == None || format != 8)
-	return;
-
-    bytes_after += nitems;
-    
-    /* Read it into a buffer. */
+	puts("HANDLING NOW");
+	
+	/* We have the complete selection data.*/
+	[self handle_selection: e->selection type:type propdata:&pdata];
+    }
+}
 
-    buf = malloc (bytes_after + 1);
-    if (buf == NULL)
-	return;
+- (void) property_event:(XPropertyEvent *)e
+{
+    struct propdata pdata;
+    Atom type;
 
-    for (offset = 0; bytes_after > 0; offset += nitems)
+    if (None != pending.requestor && PropertyNewValue == e->state) 
     {
-	r = XGetWindowProperty (x_dpy, e->requestor, e->property,
-				offset / 4, (bytes_after / 4) + 1,
-				False, AnyPropertyType, &type,
-				&format, &nitems, &bytes_after, &data);
-	if (r != Success)
+	if (get_property (e->window, e->atom, &pdata, /*Delete*/ True, &type))
 	{
-	    free (buf);
 	    return;
 	}
 
-	memcpy (buf + offset, data, nitems);
-	XFree (data);
+	if (0 == pdata.length) 
+	{
+	    /* We completed the transfer. */
+	    [self handle_selection: pending.selection type: type propdata: &pending.propdata];
+	    pending.propdata = null_propdata;
+	    pending.requestor = None;
+	    pending.selection = None;
+	} 
+	else 
+	{
+	    [self append_to_pending: &pdata requestor: e->window];
+	}       
     }
-    buf[offset] = 0;
-    XDeleteProperty (x_dpy, e->requestor, e->property);
-
-    /* Convert to an NSString and write to the pasteboard. */
+}
 
-    if (type == XA_STRING)
-	string = [NSString stringWithCString:(char *) buf];
-    else /* if (type == x_atom_utf8_string) */
-	string = [NSString stringWithUTF8String:(char *) buf];
+- (void) handle_targets: (Atom)selection propdata:(struct propdata *)pdata
+{
+    Atom preferred = find_preferred (pdata);
 
-    free (buf);
+    if (None == preferred) 
+    {
+	/* 
+	 * This isn't required by the ICCCM, but some apps apparently 
+	 * don't respond to TARGETS properly.
+	 */
+	preferred = XA_STRING;
+    }
 
-    [_pasteboard setString:string forType:NSStringPboardType];
+    request_atom = preferred;
+    XConvertSelection (x_dpy, selection, preferred, selection,
+		       _selection_window, CurrentTime);    
 }
 
-
-/* NSPasteboard-required methods */
-
-static Bool
-selnotify_pred (Display *dpy, XEvent *e, XPointer arg)
+/* This handles the image/png type of selection (typically in CLIPBOARD). */
+- (void) handle_png: (struct propdata *)pdata
 {
-    return e->type == SelectionNotify;
+    /* TODO Use the NSPasteboard code I wrote that may work... */
 }
 
-- (void) pasteboard:(NSPasteboard *)sender provideDataForType:(NSString *)type
+/* This handles the UTF8_STRING type of selection. */
+- (void) handle_utf8_string: (struct propdata *)pdata
 {
-    XEvent e;
-    Atom request;
+    size_t i;
+    unsigned char *p = pdata->data;
 
-    TRACE ();
-
-    /* Don't ask for the data yet, first find out which formats
-       the selection owner supports. */
-
-    request = x_atom_targets;
+    puts("HANDLE UTF8_STRING");
+    for (i = 0; i < pdata->length; ++i) {
+	printf("%c", p[i]);
+    }
+    puts("");
 
-again:
-    XConvertSelection (x_dpy, _proxied_selection, request,
-		       _proxied_selection, _selection_window, CurrentTime);
+    NSString *string = [[NSString alloc] initWithBytes:pdata->data length:pdata->length encoding:NSUTF8StringEncoding];
+    [_pasteboard setString:string forType:NSStringPboardType];
+    [string release];
+}
 
-    _pending_notify = YES;
+/* This handles the XA_STRING type, which should be in Latin-1. */
+- (void) handle_string: (struct propdata *)pdata
+{
+    puts("STRING");
 
-    /* Seems like we need to be synchronous here.. Actually, this really
-       sucks, since it means we could get deadlocked if people don't
-       respond to our request. So we need to implement our own timeout
-       code.. */
+    NSString *string = [[NSString alloc] initWithBytes:pdata->data length:pdata->length encoding:NSISOLatin1StringEncoding];
+    [_pasteboard setString:string forType:NSStringPboardType];
+    [string release];
+}
 
-    while (_pending_notify
-	   && IfEventWithTimeout (x_dpy, &e, 1, selnotify_pred, NULL))
+/* Warning: this frees the propdata in most cases. */
+- (void) handle_selection:(Atom)selection type:(Atom)type propdata:(struct propdata *)pdata
+{
+    if (request_atom == atoms->targets && type == atoms->atom)
+    {
+	[self handle_targets:selection propdata:pdata];
+    } 
+    else if (type == atoms->image_png)
     {
-	_pending_notify = NO;
-	[self notify_event:&e.xselection];
+	[self handle_png:pdata];
+    } 
+    else if (type == atoms->utf8_string) 
+    {
+	[self handle_utf8_string:pdata];
+    } 
+    else if (type == atoms->string)
+    {
+	[self handle_string:pdata];
+    } 
+    else
+    {
+	free_propdata(pdata);
     }
-
-    if (_pending_notify && request == x_atom_targets)
+    
+    if (selection == atoms->clipboard)
     {
-	/* App didn't respond to request for TARGETS selection. Let's
-	   try the STRING selection as a last resort.. Helps broken
-	   applications (e.g. nedit, see #3199867) */
-
-	request = XA_STRING;
-	goto again;
+	free_propdata(&request_data.propdata);
+	request_data.propdata = *pdata;
+	request_data.type = type;
+	
+	/* We greedily take the CLIPBOARD selection whenever it changes. */
+	XSetSelectionOwner (x_dpy, atoms->clipboard, _selection_window,
+			    CurrentTime);
+    }
+    else
+    {
+	free_propdata(pdata);
     }
-
-    _pending_notify = NO;
 }
 
+
+/* NSPasteboard-required methods */
+
 - (void) pasteboardChangedOwner:(NSPasteboard *)sender
 {
     TRACE ();
 
+    puts("PB changed owner");
+
     /* Right now we don't care with this. */
 }
 
@@ -467,6 +714,17 @@ again:
     _selection_window = XCreateSimpleWindow (x_dpy, DefaultRootWindow (x_dpy),
 					     0, 0, 1, 1, 0, pixel, pixel);
 
+    XSelectInput (x_dpy, _selection_window, PropertyChangeMask);
+
+    request_atom = None;
+
+    init_propdata (&pending.propdata);
+    pending.requestor = None;
+    pending.selection = None;
+
+    init_propdata (&request_data.propdata);
+    request_data.type = None;
+    
     return self;
 }
 
@@ -479,12 +737,15 @@ again:
     [_known_types release];
     _known_types = nil;
 
-    if (_selection_window != 0)
+    if (None != _selection_window)
     {
 	XDestroyWindow (x_dpy, _selection_window);
-	_selection_window = 0;
+	_selection_window = None;
     }
 
+    free_propdata (&pending.propdata);
+    free_propdata (&request_data.propdata);
+
     [super dealloc];
 }
 


More information about the xorg-commit mailing list