XQuartz: xpbproxy: Support some of the preference toggles from X11.app, cleaned up CLIPBOARD_MANAGER atom management.

This commit is contained in:
Jeremy Huddleston 2008-10-04 18:54:15 -07:00
parent 3a6898f487
commit f7673bb4de
6 changed files with 144 additions and 115 deletions

View File

@ -15,8 +15,10 @@ static void signal_handler (int sig) {
} }
int main (int argc, const char *argv[]) { int main (int argc, const char *argv[]) {
#ifdef TEST
printf("pid: %u\n", getpid()); printf("pid: %u\n", getpid());
#endif
x_init (); x_init ();
signal (SIGINT, signal_handler); signal (SIGINT, signal_handler);

View File

@ -55,10 +55,6 @@ void x_init (void) {
_selection_object = [[x_selection alloc] init]; _selection_object = [[x_selection alloc] init];
x_input_register (); x_input_register ();
[_selection_object set_clipboard_manager];
[_selection_object claim_clipboard];
x_input_run (); x_input_run ();
[pool release]; [pool release];

View File

@ -12,7 +12,9 @@
#include <X11/extensions/shape.h> #include <X11/extensions/shape.h>
#undef Cursor #undef Cursor
#ifndef DEBUG
#define DEBUG 0 #define DEBUG 0
#endif
/* from main.m */ /* from main.m */
extern void x_set_is_active (BOOL state); extern void x_set_is_active (BOOL state);
@ -27,7 +29,7 @@ extern int x_apple_wm_event_base, x_apple_wm_error_base;
/* from x-input.m */ /* from x-input.m */
extern void x_input_register (void); extern void x_input_register (void);
extern void x_input_run (void); extern void x_input_run (void);
#if DEBUG == 0 #if DEBUG == 0
# define DB(msg, args...) do {} while (0) # define DB(msg, args...) do {} while (0)
#else #else

View File

@ -21,29 +21,35 @@ static CFRunLoopSourceRef x_dpy_source;
static Time last_activation_time; static Time last_activation_time;
static void x_event_apple_wm_notify(XAppleWMNotifyEvent *e) { static void x_event_apple_wm_notify(XAppleWMNotifyEvent *e) {
int type = e->type - x_apple_wm_event_base;
int kind = e->kind;
switch (e->type - x_apple_wm_event_base) { /* We want to reload prefs even if we're not active */
if(type == AppleWMActivationNotify &&
kind == AppleWMReloadPreferences)
[x_selection_object() reload_preferences];
if(![x_selection_object() is_active])
return;
switch (type) {
case AppleWMActivationNotify: case AppleWMActivationNotify:
switch (e->kind) { switch (kind) {
case AppleWMIsActive: case AppleWMIsActive:
last_activation_time = e->time; last_activation_time = e->time;
[x_selection_object () x_active:e->time]; [x_selection_object() x_active:e->time];
break; break;
case AppleWMIsInactive: case AppleWMIsInactive:
[x_selection_object () x_inactive:e->time]; [x_selection_object() x_inactive:e->time];
break; break;
case AppleWMReloadPreferences:
[x_selection_object () reload_preferences];
break;
} }
break; break;
case AppleWMPasteboardNotify: case AppleWMPasteboardNotify:
switch (e->kind) { switch (kind) {
case AppleWMCopyToPasteboard: case AppleWMCopyToPasteboard:
[x_selection_object () x_copy:e->time]; [x_selection_object() x_copy:e->time];
} }
break; break;
} }
@ -54,22 +60,18 @@ void x_input_run (void) {
if (nil == pool) if (nil == pool)
{ {
fprintf(stderr, "unable to allocate/init auto release pool!\n"); fprintf(stderr, "unable to allocate/init auto release pool!\n");
return; return;
} }
while (XPending (x_dpy) != 0) { while (XPending (x_dpy) != 0) {
XEvent e; XEvent e;
XNextEvent (x_dpy, &e); XNextEvent (x_dpy, &e);
/* If pbproxy isn't active (in the preferences), then don't do anything. */
if (![x_selection_object() is_active])
continue;
switch (e.type) { switch (e.type) {
case SelectionClear: case SelectionClear:
[x_selection_object () clear_event:&e.xselectionclear]; if([x_selection_object() is_active])
[x_selection_object () clear_event:&e.xselectionclear];
break; break;
case SelectionRequest: case SelectionRequest:
@ -80,10 +82,10 @@ void x_input_run (void) {
[x_selection_object () notify_event:&e.xselection]; [x_selection_object () notify_event:&e.xselection];
break; break;
case PropertyNotify: case PropertyNotify:
[x_selection_object () property_event:&e.xproperty]; [x_selection_object () property_event:&e.xproperty];
break; break;
default: default:
if (e.type - x_apple_wm_event_base >= 0 if (e.type - x_apple_wm_event_base >= 0
&& e.type - x_apple_wm_event_base < AppleWMNumberEvents) { && e.type - x_apple_wm_event_base < AppleWMNumberEvents) {
@ -91,10 +93,10 @@ void x_input_run (void) {
} }
break; break;
} }
XFlush(x_dpy); XFlush(x_dpy);
} }
[pool release]; [pool release];
} }

View File

@ -97,7 +97,7 @@ struct atom_list {
- (void) property_event:(XPropertyEvent *)e; - (void) property_event:(XPropertyEvent *)e;
- (void) handle_selection:(Atom)selection type:(Atom)type propdata:(struct propdata *)pdata; - (void) handle_selection:(Atom)selection type:(Atom)type propdata:(struct propdata *)pdata;
- (void) claim_clipboard; - (void) claim_clipboard;
- (void) set_clipboard_manager; - (BOOL) set_clipboard_manager_status:(BOOL)value;
- (void) own_clipboard; - (void) own_clipboard;
- (void) copy_completed:(Atom)selection; - (void) copy_completed:(Atom)selection;

View File

@ -56,22 +56,36 @@
/* /*
* TODO: * TODO:
* 1. finish handling these pbproxy control knobs. * 1. handle primary_on_grab
* 2. handle MULTIPLE - I need to study the ICCCM further. * 2. handle MULTIPLE - I need to study the ICCCM further.
* 3. Handle PICT images properly. * 3. Handle PICT images properly.
* 4. Handle NSPasteboard updates immediately, not on active/inactive
* - Open xterm, run 'cat readme.txt | pbcopy'
* 5. Detect if CLIPBOARD_MANAGER atom belongs to a dead client rather than just None
*/ */
// These will be set by X11Controller.m once this is integrated into a server thread static struct {
BOOL pbproxy_active = YES; BOOL active ;
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 primary_on_grab; // 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 clipboard_to_pasteboard;
BOOL pbproxy_pasteboard_to_primary = YES; BOOL pasteboard_to_primary;
BOOL pbproxy_pasteboard_to_clipboard = YES; BOOL pasteboard_to_clipboard;
} pbproxy_prefs = { YES, NO, YES, YES, YES };
@implementation x_selection @implementation x_selection
static struct propdata null_propdata = {NULL, 0}; static struct propdata null_propdata = {NULL, 0};
#define APP_PREFS "org.x.X11"
static BOOL prefs_get_bool (CFStringRef key, BOOL def) {
int ret;
Boolean ok;
ret = CFPreferencesGetAppBooleanValue (key, CFSTR (APP_PREFS), &ok);
return ok ? (BOOL) ret : def;
}
static void static void
init_propdata (struct propdata *pdata) init_propdata (struct propdata *pdata)
{ {
@ -321,19 +335,17 @@ get_property(Window win, Atom property, struct propdata *pdata, Bool delete, Ato
if (countNow != changeCount) if (countNow != changeCount)
{ {
DB ("changed pasteboard!\n"); DB ("changed pasteboard!\n");
changeCount = countNow; changeCount = countNow;
if (pbproxy_pasteboard_to_primary) if (pbproxy_prefs.pasteboard_to_primary)
{ {
XSetSelectionOwner (x_dpy, atoms->primary, _selection_window, CurrentTime);
XSetSelectionOwner (x_dpy, atoms->primary, _selection_window, CurrentTime); }
}
if (pbproxy_prefs.pasteboard_to_clipboard) {
if (pbproxy_pasteboard_to_clipboard) [self own_clipboard];
{ }
[self own_clipboard];
}
} }
#if 0 #if 0
@ -395,23 +407,36 @@ get_property(Window win, Atom property, struct propdata *pdata, Bool delete, Ato
} }
} }
/* /* Set pbproxy as owner of the SELECTION_MANAGER selection.
* Set pbproxy as owner of the SELECTION_MANAGER selection.
* This prevents tools like xclipboard from causing havoc. * This prevents tools like xclipboard from causing havoc.
* Returns TRUE on success
*/ */
- (void) set_clipboard_manager - (BOOL) set_clipboard_manager_status:(BOOL)value
{ {
TRACE (); TRACE ();
if (None != XGetSelectionOwner (x_dpy, atoms->clipboard_manager)) Window owner = 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, if(value) {
CurrentTime); if(owner == _selection_window)
return TRUE;
// if(None != _selection_window) {
// fprintf (stderr, "A clipboard manager is already running. pbproxy will not sync clipboard to pasteboard.\n");
// return FALSE;
// }
XSetSelectionOwner(x_dpy, atoms->clipboard_manager, _selection_window, CurrentTime);
return (_selection_window == XGetSelectionOwner(x_dpy, atoms->clipboard_manager));
} else {
if(owner != _selection_window)
return TRUE;
XSetSelectionOwner(x_dpy, atoms->clipboard_manager, None, CurrentTime);
return(None == XGetSelectionOwner(x_dpy, atoms->clipboard_manager));
}
return FALSE;
} }
/* /*
@ -423,28 +448,25 @@ get_property(Window win, Atom property, struct propdata *pdata, Bool delete, Ato
TRACE (); TRACE ();
DB ("e->selection %s\n", XGetAtomName (x_dpy, e->selection)); DB ("e->selection %s\n", XGetAtomName (x_dpy, e->selection));
if (atoms->clipboard == e->selection) if(e->selection == atoms->clipboard) {
{ /*
/* * We lost ownership of the CLIPBOARD.
* We lost ownership of the CLIPBOARD. */
*/ ++pending_clipboard;
++pending_clipboard;
if (1 == pending_clipboard) {
if (1 == pending_clipboard) /* Claim the clipboard contents from the new owner. */
{ [self claim_clipboard];
/* Claim the clipboard contents from the new owner. */ }
[self claim_clipboard]; } else if(e->selection == atoms->clipboard_manager) {
} if(pbproxy_prefs.clipboard_to_pasteboard) {
} /* Another CLIPBOARD_MANAGER has set itself as owner. Disable syncing
else if (atoms->clipboard_manager == e->selection) * to avoid a race.
{ */
/* Another CLIPBOARD_MANAGER has set itself as owner. fprintf(stderr, "Another clipboard manager was started! xpbproxy is disabling syncing with clipboard.\n");
* a) we can call [self set_clipboard_manager] here and risk a war. pbproxy_prefs.clipboard_to_pasteboard = NO;
* 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);
} }
} }
@ -456,32 +478,29 @@ get_property(Window win, Atom property, struct propdata *pdata, Bool delete, Ato
Window owner; Window owner;
TRACE (); TRACE ();
if (!pbproxy_clipboard_to_pasteboard) if (!pbproxy_prefs.clipboard_to_pasteboard)
return; return;
owner = XGetSelectionOwner (x_dpy, atoms->clipboard); owner = XGetSelectionOwner (x_dpy, atoms->clipboard);
if (None == owner) if (None == owner) {
{ /*
/* * The owner probably died or we are just starting up pbproxy.
* The owner probably died or we are just starting up pbproxy. * Set pbproxy's _selection_window as the owner, and continue.
* Set pbproxy's _selection_window as the owner, and continue. */
*/ DB ("No clipboard owner.\n");
DB ("No clipboard owner.\n"); [self copy_completed:atoms->clipboard];
[self copy_completed:atoms->clipboard]; return;
return; } else if (owner == _selection_window) {
} [self copy_completed:atoms->clipboard];
else if (owner == _selection_window) return;
{
[self copy_completed:atoms->clipboard];
return;
} }
DB ("requesting targets\n"); DB ("requesting targets\n");
request_atom = atoms->targets; request_atom = atoms->targets;
XConvertSelection (x_dpy, atoms->clipboard, atoms->targets, XConvertSelection (x_dpy, atoms->clipboard, atoms->targets,
atoms->clipboard, _selection_window, CurrentTime); atoms->clipboard, _selection_window, CurrentTime);
XFlush (x_dpy); XFlush (x_dpy);
/* Now we will get a SelectionNotify event in the future. */ /* Now we will get a SelectionNotify event in the future. */
} }
@ -1236,18 +1255,25 @@ get_property(Window win, Atom property, struct propdata *pdata, Bool delete, Ato
- (void) reload_preferences - (void) reload_preferences
{ {
if (pbproxy_clipboard_to_pasteboard) pbproxy_prefs.active = prefs_get_bool(CFSTR("sync_pasteboard"), pbproxy_prefs.active);
{ pbproxy_prefs.primary_on_grab = prefs_get_bool(CFSTR("sync_primary_on_select"), pbproxy_prefs.primary_on_grab);
[self claim_clipboard]; pbproxy_prefs.clipboard_to_pasteboard = prefs_get_bool(CFSTR("sync_clibpoard_to_pasteboard"), pbproxy_prefs.clipboard_to_pasteboard);
} pbproxy_prefs.pasteboard_to_primary = prefs_get_bool(CFSTR("sync_pasteboard_to_primary"), pbproxy_prefs.pasteboard_to_primary);
pbproxy_prefs.pasteboard_to_clipboard = prefs_get_bool(CFSTR("sync_pasteboard_to_clipboard"), pbproxy_prefs.pasteboard_to_clipboard);
/* Claim or release the CLIPBOARD_MANAGER atom */
if(![self set_clipboard_manager_status:(pbproxy_prefs.active && pbproxy_prefs.clipboard_to_pasteboard)])
pbproxy_prefs.clipboard_to_pasteboard = NO;
if(pbproxy_prefs.active && pbproxy_prefs.clipboard_to_pasteboard)
[self claim_clipboard];
} }
- (BOOL) is_active - (BOOL) is_active
{ {
return pbproxy_active; return pbproxy_prefs.active;
} }
/* NSPasteboard-required methods */ /* NSPasteboard-required methods */
- (void) paste:(id)sender - (void) paste:(id)sender
@ -1267,7 +1293,6 @@ get_property(Window win, Atom property, struct propdata *pdata, Bool delete, Ato
/* Right now we don't care with this. */ /* Right now we don't care with this. */
} }
/* Allocation */ /* Allocation */
- init - init
@ -1310,6 +1335,8 @@ get_property(Window win, Atom property, struct propdata *pdata, Bool delete, Ato
pending_copy = 0; pending_copy = 0;
pending_clipboard = 0; pending_clipboard = 0;
[self reload_preferences];
return self; return self;
} }