XQuartz: xpbproxy: Support some of the preference toggles from X11.app, cleaned up CLIPBOARD_MANAGER atom management.
This commit is contained in:
parent
3a6898f487
commit
f7673bb4de
|
@ -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);
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user