1/* x-input.m -- event handling 2 * 3 * Copyright (c) 2002-2012 Apple Inc. All rights reserved. 4 * 5 * Permission is hereby granted, free of charge, to any person 6 * obtaining a copy of this software and associated documentation files 7 * (the "Software"), to deal in the Software without restriction, 8 * including without limitation the rights to use, copy, modify, merge, 9 * publish, distribute, sublicense, and/or sell copies of the Software, 10 * and to permit persons to whom the Software is furnished to do so, 11 * subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be 14 * included in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT 20 * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 * 25 * Except as contained in this notice, the name(s) of the above 26 * copyright holders shall not be used in advertising or otherwise to 27 * promote the sale, use or other dealings in this Software without 28 * prior written authorization. 29 */ 30 31#include "pbproxy.h" 32#import "x-selection.h" 33 34#include <CoreFoundation/CFSocket.h> 35#include <CoreFoundation/CFRunLoop.h> 36 37#include <X11/Xatom.h> 38#include <X11/keysym.h> 39#include <X11/extensions/applewm.h> 40 41#include <unistd.h> 42 43static CFRunLoopSourceRef xpbproxy_dpy_source; 44 45#ifdef STANDALONE_XPBPROXY 46BOOL xpbproxy_prefs_reload = NO; 47#endif 48 49/* Timestamp when the X server last told us it's active */ 50static Time last_activation_time; 51 52static void 53x_event_apple_wm_notify(XAppleWMNotifyEvent *e) 54{ 55 int type = e->type - xpbproxy_apple_wm_event_base; 56 int kind = e->kind; 57 58 /* We want to reload prefs even if we're not active */ 59 if (type == AppleWMActivationNotify && 60 kind == AppleWMReloadPreferences) 61 [xpbproxy_selection_object ()reload_preferences]; 62 63 if (![xpbproxy_selection_object ()is_active]) 64 return; 65 66 switch (type) { 67 case AppleWMActivationNotify: 68 switch (kind) { 69 case AppleWMIsActive: 70 last_activation_time = e->time; 71 [xpbproxy_selection_object () x_active:e->time]; 72 break; 73 74 case AppleWMIsInactive: 75 [xpbproxy_selection_object () x_inactive:e->time]; 76 break; 77 } 78 break; 79 80 case AppleWMPasteboardNotify: 81 switch (kind) { 82 case AppleWMCopyToPasteboard: 83 [xpbproxy_selection_object () x_copy:e->time]; 84 } 85 break; 86 } 87} 88 89static void 90xpbproxy_process_xevents(void) 91{ 92 while (XPending(xpbproxy_dpy) != 0) { @autoreleasepool { 93 XEvent e; 94 95 XNextEvent(xpbproxy_dpy, &e); 96 97 switch (e.type) { 98 case SelectionClear: 99 if ([xpbproxy_selection_object ()is_active]) 100 [xpbproxy_selection_object () clear_event:&e.xselectionclear]; 101 break; 102 103 case SelectionRequest: 104 [xpbproxy_selection_object () request_event:&e.xselectionrequest]; 105 break; 106 107 case SelectionNotify: 108 [xpbproxy_selection_object () notify_event:&e.xselection]; 109 break; 110 111 case PropertyNotify: 112 [xpbproxy_selection_object () property_event:&e.xproperty]; 113 break; 114 115 default: 116 if (e.type >= xpbproxy_apple_wm_event_base && 117 e.type < xpbproxy_apple_wm_event_base + 118 AppleWMNumberEvents) { 119 x_event_apple_wm_notify((XAppleWMNotifyEvent *)&e); 120 } 121 else if (e.type == xpbproxy_xfixes_event_base + 122 XFixesSelectionNotify) { 123 [xpbproxy_selection_object () xfixes_selection_notify:( 124 XFixesSelectionNotifyEvent *)&e]; 125 } 126 break; 127 } 128 129 XFlush(xpbproxy_dpy); 130 }} 131} 132 133static BOOL 134add_input_socket(int sock, CFOptionFlags callback_types, 135 CFSocketCallBack callback, const CFSocketContext *ctx, 136 CFRunLoopSourceRef *cf_source) 137{ 138 CFSocketRef cf_sock; 139 140 cf_sock = CFSocketCreateWithNative(kCFAllocatorDefault, sock, 141 callback_types, callback, ctx); 142 if (cf_sock == NULL) { 143 close(sock); 144 return FALSE; 145 } 146 147 *cf_source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, 148 cf_sock, 0); 149 CFRelease(cf_sock); 150 151 if (*cf_source == NULL) 152 return FALSE; 153 154 CFRunLoopAddSource(CFRunLoopGetCurrent(), 155 *cf_source, kCFRunLoopDefaultMode); 156 return TRUE; 157} 158 159static void 160x_input_callback(CFSocketRef sock, CFSocketCallBackType type, 161 CFDataRef address, const void *data, void *info) 162{ 163 164#ifdef STANDALONE_XPBPROXY 165 if (xpbproxy_prefs_reload) { 166 [xpbproxy_selection_object ()reload_preferences]; 167 xpbproxy_prefs_reload = NO; 168 } 169#endif 170 171 xpbproxy_process_xevents(); 172} 173 174BOOL 175xpbproxy_input_register(void) 176{ 177 return add_input_socket(ConnectionNumber( 178 xpbproxy_dpy), kCFSocketReadCallBack, 179 x_input_callback, NULL, &xpbproxy_dpy_source); 180} 181