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[]) {
#ifdef TEST
printf("pid: %u\n", getpid());
#endif
x_init ();
signal (SIGINT, signal_handler);

View File

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

View File

@ -12,7 +12,9 @@
#include <X11/extensions/shape.h>
#undef Cursor
#ifndef DEBUG
#define DEBUG 0
#endif
/* from main.m */
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 */
extern void x_input_register (void);
extern void x_input_run (void);
#if DEBUG == 0
# define DB(msg, args...) do {} while (0)
#else

View File

@ -21,29 +21,35 @@ static CFRunLoopSourceRef x_dpy_source;
static Time last_activation_time;
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:
switch (e->kind) {
switch (kind) {
case AppleWMIsActive:
last_activation_time = e->time;
[x_selection_object () x_active:e->time];
[x_selection_object() x_active:e->time];
break;
case AppleWMIsInactive:
[x_selection_object () x_inactive:e->time];
[x_selection_object() x_inactive:e->time];
break;
case AppleWMReloadPreferences:
[x_selection_object () reload_preferences];
break;
}
break;
case AppleWMPasteboardNotify:
switch (e->kind) {
case AppleWMCopyToPasteboard:
[x_selection_object () x_copy:e->time];
switch (kind) {
case AppleWMCopyToPasteboard:
[x_selection_object() x_copy:e->time];
}
break;
}
@ -54,22 +60,18 @@ void x_input_run (void) {
if (nil == pool)
{
fprintf(stderr, "unable to allocate/init auto release pool!\n");
return;
fprintf(stderr, "unable to allocate/init auto release pool!\n");
return;
}
while (XPending (x_dpy) != 0) {
XEvent e;
XEvent 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) {
case SelectionClear:
[x_selection_object () clear_event:&e.xselectionclear];
if([x_selection_object() is_active])
[x_selection_object () clear_event:&e.xselectionclear];
break;
case SelectionRequest:
@ -80,10 +82,10 @@ void x_input_run (void) {
[x_selection_object () notify_event:&e.xselection];
break;
case PropertyNotify:
[x_selection_object () property_event:&e.xproperty];
break;
case PropertyNotify:
[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) {
@ -91,10 +93,10 @@ void x_input_run (void) {
}
break;
}
XFlush(x_dpy);
XFlush(x_dpy);
}
[pool release];
}

View File

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

View File

@ -56,22 +56,36 @@
/*
* TODO:
* 1. finish handling these pbproxy control knobs.
* 1. handle primary_on_grab
* 2. handle MULTIPLE - I need to study the ICCCM further.
* 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
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;
static struct {
BOOL active ;
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 clipboard_to_pasteboard;
BOOL pasteboard_to_primary;
BOOL pasteboard_to_clipboard;
} pbproxy_prefs = { YES, NO, YES, YES, YES };
@implementation x_selection
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
init_propdata (struct propdata *pdata)
{
@ -321,19 +335,17 @@ get_property(Window win, Atom property, struct propdata *pdata, Bool delete, Ato
if (countNow != changeCount)
{
DB ("changed pasteboard!\n");
changeCount = countNow;
if (pbproxy_pasteboard_to_primary)
{
XSetSelectionOwner (x_dpy, atoms->primary, _selection_window, CurrentTime);
}
if (pbproxy_pasteboard_to_clipboard)
{
[self own_clipboard];
}
DB ("changed pasteboard!\n");
changeCount = countNow;
if (pbproxy_prefs.pasteboard_to_primary)
{
XSetSelectionOwner (x_dpy, atoms->primary, _selection_window, CurrentTime);
}
if (pbproxy_prefs.pasteboard_to_clipboard) {
[self own_clipboard];
}
}
#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.
* Returns TRUE on success
*/
- (void) set_clipboard_manager
- (BOOL) set_clipboard_manager_status:(BOOL)value
{
TRACE ();
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);
}
Window owner = XGetSelectionOwner (x_dpy, atoms->clipboard_manager);
XSetSelectionOwner (x_dpy, atoms->clipboard_manager, _selection_window,
CurrentTime);
if(value) {
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 ();
DB ("e->selection %s\n", XGetAtomName (x_dpy, e->selection));
if (atoms->clipboard == e->selection)
{
/*
* We lost ownership of the CLIPBOARD.
*/
++pending_clipboard;
if (1 == pending_clipboard)
{
/* Claim the clipboard contents from the new owner. */
[self claim_clipboard];
}
}
else if (atoms->clipboard_manager == e->selection)
{
/* 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. Ideally we would popup a message box.
*/
fprintf (stderr, "error: another clipboard manager was started!\n");
//exit (EXIT_FAILURE);
if(e->selection == atoms->clipboard) {
/*
* We lost ownership of the CLIPBOARD.
*/
++pending_clipboard;
if (1 == pending_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
* to avoid a race.
*/
fprintf(stderr, "Another clipboard manager was started! xpbproxy is disabling syncing with clipboard.\n");
pbproxy_prefs.clipboard_to_pasteboard = NO;
}
}
}
@ -456,32 +478,29 @@ get_property(Window win, Atom property, struct propdata *pdata, Bool delete, Ato
Window owner;
TRACE ();
if (!pbproxy_clipboard_to_pasteboard)
return;
if (!pbproxy_prefs.clipboard_to_pasteboard)
return;
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.
*/
DB ("No clipboard owner.\n");
[self copy_completed:atoms->clipboard];
return;
}
else if (owner == _selection_window)
{
[self copy_completed:atoms->clipboard];
return;
if (None == owner) {
/*
* 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");
[self copy_completed:atoms->clipboard];
return;
} else if (owner == _selection_window) {
[self copy_completed:atoms->clipboard];
return;
}
DB ("requesting targets\n");
request_atom = atoms->targets;
XConvertSelection (x_dpy, atoms->clipboard, atoms->targets,
atoms->clipboard, _selection_window, CurrentTime);
atoms->clipboard, _selection_window, CurrentTime);
XFlush (x_dpy);
/* 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
{
if (pbproxy_clipboard_to_pasteboard)
{
[self claim_clipboard];
}
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);
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
{
return pbproxy_active;
return pbproxy_prefs.active;
}
/* NSPasteboard-required methods */
- (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. */
}
/* Allocation */
- init
@ -1310,6 +1335,8 @@ get_property(Window win, Atom property, struct propdata *pdata, Bool delete, Ato
pending_copy = 0;
pending_clipboard = 0;
[self reload_preferences];
return self;
}