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[]) {
|
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);
|
||||||
|
|
|
@ -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];
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user