14642e01fSmrg/* x-input.m -- event handling
235c4bbdfSmrg *
335c4bbdfSmrg * Copyright (c) 2002-2012 Apple Inc. All rights reserved.
435c4bbdfSmrg *
535c4bbdfSmrg * Permission is hereby granted, free of charge, to any person
635c4bbdfSmrg * obtaining a copy of this software and associated documentation files
735c4bbdfSmrg * (the "Software"), to deal in the Software without restriction,
835c4bbdfSmrg * including without limitation the rights to use, copy, modify, merge,
935c4bbdfSmrg * publish, distribute, sublicense, and/or sell copies of the Software,
1035c4bbdfSmrg * and to permit persons to whom the Software is furnished to do so,
1135c4bbdfSmrg * subject to the following conditions:
1235c4bbdfSmrg *
1335c4bbdfSmrg * The above copyright notice and this permission notice shall be
1435c4bbdfSmrg * included in all copies or substantial portions of the Software.
1535c4bbdfSmrg *
1635c4bbdfSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1735c4bbdfSmrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1835c4bbdfSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1935c4bbdfSmrg * NONINFRINGEMENT.  IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT
2035c4bbdfSmrg * HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
2135c4bbdfSmrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2235c4bbdfSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2335c4bbdfSmrg * DEALINGS IN THE SOFTWARE.
2435c4bbdfSmrg *
2535c4bbdfSmrg * Except as contained in this notice, the name(s) of the above
2635c4bbdfSmrg * copyright holders shall not be used in advertising or otherwise to
2735c4bbdfSmrg * promote the sale, use or other dealings in this Software without
2835c4bbdfSmrg * prior written authorization.
294642e01fSmrg */
304642e01fSmrg
314642e01fSmrg#include "pbproxy.h"
324642e01fSmrg#import "x-selection.h"
334642e01fSmrg
344642e01fSmrg#include <CoreFoundation/CFSocket.h>
354642e01fSmrg#include <CoreFoundation/CFRunLoop.h>
364642e01fSmrg
374642e01fSmrg#include <X11/Xatom.h>
384642e01fSmrg#include <X11/keysym.h>
394642e01fSmrg#include <X11/extensions/applewm.h>
404642e01fSmrg
414642e01fSmrg#include <unistd.h>
424642e01fSmrg
434642e01fSmrgstatic CFRunLoopSourceRef xpbproxy_dpy_source;
444642e01fSmrg
454642e01fSmrg#ifdef STANDALONE_XPBPROXY
464642e01fSmrgBOOL xpbproxy_prefs_reload = NO;
474642e01fSmrg#endif
484642e01fSmrg
494642e01fSmrg/* Timestamp when the X server last told us it's active */
504642e01fSmrgstatic Time last_activation_time;
514642e01fSmrg
5235c4bbdfSmrgstatic void
5335c4bbdfSmrgx_event_apple_wm_notify(XAppleWMNotifyEvent *e)
5435c4bbdfSmrg{
554642e01fSmrg    int type = e->type - xpbproxy_apple_wm_event_base;
564642e01fSmrg    int kind = e->kind;
574642e01fSmrg
584642e01fSmrg    /* We want to reload prefs even if we're not active */
5935c4bbdfSmrg    if (type == AppleWMActivationNotify &&
6035c4bbdfSmrg        kind == AppleWMReloadPreferences)
6135c4bbdfSmrg        [xpbproxy_selection_object ()reload_preferences];
624642e01fSmrg
6335c4bbdfSmrg    if (![xpbproxy_selection_object ()is_active])
644642e01fSmrg        return;
654642e01fSmrg
6635c4bbdfSmrg    switch (type) {
6735c4bbdfSmrg    case AppleWMActivationNotify:
6835c4bbdfSmrg        switch (kind) {
6935c4bbdfSmrg        case AppleWMIsActive:
7035c4bbdfSmrg            last_activation_time = e->time;
7135c4bbdfSmrg            [xpbproxy_selection_object () x_active:e->time];
724642e01fSmrg            break;
7335c4bbdfSmrg
7435c4bbdfSmrg        case AppleWMIsInactive:
7535c4bbdfSmrg            [xpbproxy_selection_object () x_inactive:e->time];
764642e01fSmrg            break;
7735c4bbdfSmrg        }
7835c4bbdfSmrg        break;
7935c4bbdfSmrg
8035c4bbdfSmrg    case AppleWMPasteboardNotify:
8135c4bbdfSmrg        switch (kind) {
8235c4bbdfSmrg        case AppleWMCopyToPasteboard:
8335c4bbdfSmrg            [xpbproxy_selection_object () x_copy:e->time];
8435c4bbdfSmrg        }
8535c4bbdfSmrg        break;
864642e01fSmrg    }
874642e01fSmrg}
884642e01fSmrg
8935c4bbdfSmrgstatic void
9035c4bbdfSmrgxpbproxy_process_xevents(void)
9135c4bbdfSmrg{
92c8548ba8Smrg    while (XPending(xpbproxy_dpy) != 0) { @autoreleasepool {
936747b715Smrg        XEvent e;
9435c4bbdfSmrg
9535c4bbdfSmrg        XNextEvent(xpbproxy_dpy, &e);
9635c4bbdfSmrg
9735c4bbdfSmrg        switch (e.type) {
9835c4bbdfSmrg        case SelectionClear:
9935c4bbdfSmrg            if ([xpbproxy_selection_object ()is_active])
10035c4bbdfSmrg                [xpbproxy_selection_object () clear_event:&e.xselectionclear];
10135c4bbdfSmrg            break;
10235c4bbdfSmrg
10335c4bbdfSmrg        case SelectionRequest:
10435c4bbdfSmrg            [xpbproxy_selection_object () request_event:&e.xselectionrequest];
10535c4bbdfSmrg            break;
10635c4bbdfSmrg
10735c4bbdfSmrg        case SelectionNotify:
10835c4bbdfSmrg            [xpbproxy_selection_object () notify_event:&e.xselection];
10935c4bbdfSmrg            break;
11035c4bbdfSmrg
11135c4bbdfSmrg        case PropertyNotify:
11235c4bbdfSmrg            [xpbproxy_selection_object () property_event:&e.xproperty];
11335c4bbdfSmrg            break;
11435c4bbdfSmrg
11535c4bbdfSmrg        default:
11635c4bbdfSmrg            if (e.type >= xpbproxy_apple_wm_event_base &&
11735c4bbdfSmrg                e.type < xpbproxy_apple_wm_event_base +
11835c4bbdfSmrg                AppleWMNumberEvents) {
11935c4bbdfSmrg                x_event_apple_wm_notify((XAppleWMNotifyEvent *)&e);
12035c4bbdfSmrg            }
12135c4bbdfSmrg            else if (e.type == xpbproxy_xfixes_event_base +
12235c4bbdfSmrg                     XFixesSelectionNotify) {
12335c4bbdfSmrg                [xpbproxy_selection_object () xfixes_selection_notify:(
12435c4bbdfSmrg                     XFixesSelectionNotifyEvent *)&e];
12535c4bbdfSmrg            }
12635c4bbdfSmrg            break;
1274642e01fSmrg        }
12835c4bbdfSmrg
1296747b715Smrg        XFlush(xpbproxy_dpy);
130c8548ba8Smrg    }}
1314642e01fSmrg}
1324642e01fSmrg
13335c4bbdfSmrgstatic BOOL
13435c4bbdfSmrgadd_input_socket(int sock, CFOptionFlags callback_types,
13535c4bbdfSmrg                 CFSocketCallBack callback, const CFSocketContext *ctx,
13635c4bbdfSmrg                 CFRunLoopSourceRef *cf_source)
13735c4bbdfSmrg{
1384642e01fSmrg    CFSocketRef cf_sock;
13935c4bbdfSmrg
14035c4bbdfSmrg    cf_sock = CFSocketCreateWithNative(kCFAllocatorDefault, sock,
14135c4bbdfSmrg                                       callback_types, callback, ctx);
1424642e01fSmrg    if (cf_sock == NULL) {
14335c4bbdfSmrg        close(sock);
1444642e01fSmrg        return FALSE;
1454642e01fSmrg    }
14635c4bbdfSmrg
14735c4bbdfSmrg    *cf_source = CFSocketCreateRunLoopSource(kCFAllocatorDefault,
14835c4bbdfSmrg                                             cf_sock, 0);
14935c4bbdfSmrg    CFRelease(cf_sock);
15035c4bbdfSmrg
1514642e01fSmrg    if (*cf_source == NULL)
1524642e01fSmrg        return FALSE;
15335c4bbdfSmrg
15435c4bbdfSmrg    CFRunLoopAddSource(CFRunLoopGetCurrent(),
15535c4bbdfSmrg                       *cf_source, kCFRunLoopDefaultMode);
1564642e01fSmrg    return TRUE;
1574642e01fSmrg}
1584642e01fSmrg
15935c4bbdfSmrgstatic void
16035c4bbdfSmrgx_input_callback(CFSocketRef sock, CFSocketCallBackType type,
16135c4bbdfSmrg                 CFDataRef address, const void *data, void *info)
16235c4bbdfSmrg{
1634642e01fSmrg
1644642e01fSmrg#ifdef STANDALONE_XPBPROXY
16535c4bbdfSmrg    if (xpbproxy_prefs_reload) {
16635c4bbdfSmrg        [xpbproxy_selection_object ()reload_preferences];
1674642e01fSmrg        xpbproxy_prefs_reload = NO;
1684642e01fSmrg    }
1694642e01fSmrg#endif
17035c4bbdfSmrg
1716747b715Smrg    xpbproxy_process_xevents();
1724642e01fSmrg}
1734642e01fSmrg
17435c4bbdfSmrgBOOL
17535c4bbdfSmrgxpbproxy_input_register(void)
17635c4bbdfSmrg{
17735c4bbdfSmrg    return add_input_socket(ConnectionNumber(
17835c4bbdfSmrg                                xpbproxy_dpy), kCFSocketReadCallBack,
1794642e01fSmrg                            x_input_callback, NULL, &xpbproxy_dpy_source);
1804642e01fSmrg}
181