From 56ba61e0617cf1e3bed8fa27a8fe78e12e3f6501 Mon Sep 17 00:00:00 2001 From: jfreegman Date: Tue, 24 Nov 2020 19:31:51 -0500 Subject: [PATCH] Cleanup and refactor x11 code - Deleted X11 code for an unfinished/broken feature - Rename xtra -> x11focus - Cleanup the remaining code a bit --- cfg/checks/x11.mk | 2 +- src/notify.c | 2 +- src/toxic.c | 24 +-- src/x11focus.c | 87 ++++++++ src/{xtra.h => x11focus.h} | 24 +-- src/xtra.c | 426 ------------------------------------- 6 files changed, 101 insertions(+), 464 deletions(-) create mode 100644 src/x11focus.c rename src/{xtra.h => x11focus.h} (67%) delete mode 100644 src/xtra.c diff --git a/cfg/checks/x11.mk b/cfg/checks/x11.mk index ba36831..b5b2ed9 100644 --- a/cfg/checks/x11.mk +++ b/cfg/checks/x11.mk @@ -1,7 +1,7 @@ # Variables for X11 support X11_LIBS = x11 X11_CFLAGS = -DX11 -X11_OBJ = xtra.o +X11_OBJ = x11focus.o # Check if we can build X11 support CHECK_X11_LIBS = $(shell $(PKG_CONFIG) --exists $(X11_LIBS) || echo -n "error") diff --git a/src/notify.c b/src/notify.c index 6298783..c8b2ed8 100644 --- a/src/notify.c +++ b/src/notify.c @@ -35,7 +35,7 @@ #include "misc_tools.h" #include "notify.h" #include "settings.h" -#include "xtra.h" +#include "x11focus.h" #if defined(AUDIO) || defined(SOUND_NOTIFY) #ifdef __APPLE__ diff --git a/src/toxic.c b/src/toxic.c index 92c0321..0d88527 100644 --- a/src/toxic.c +++ b/src/toxic.c @@ -66,7 +66,7 @@ #include "windows.h" #ifdef X11 -#include "xtra.h" +#include "x11focus.h" #endif #ifdef AUDIO @@ -205,10 +205,7 @@ void exit_toxic_success(Tox *m) curl_global_cleanup(); #ifdef X11 - /* We have to terminate xtra last coz reasons - * Please don't call this anywhere else coz trust me - */ - terminate_xtra(); + terminate_x11focus(); #endif /* X11 */ exit(EXIT_SUCCESS); @@ -1350,21 +1347,6 @@ static void init_default_data_files(void) free(user_config_dir); } -// this doesn't do anything (yet) -#ifdef X11 -void DnD_callback(const char *asdv, DropType dt) -{ - UNUSED_VAR(asdv); - UNUSED_VAR(dt); - // if (dt != DT_plain) - // return; - - // pthread_mutex_lock(&Winthread.lock); - // line_info_add(prompt, NULL, NULL, NULL, SYS_MSG, 0, 0, asdv); - // pthread_mutex_unlock(&Winthread.lock); -} -#endif /* X11 */ - int main(int argc, char **argv) { /* Make sure all written files are read/writeable only by the current user. */ @@ -1422,7 +1404,7 @@ int main(int argc, char **argv) #ifdef X11 - if (init_xtra(DnD_callback) == -1) { + if (init_x11focus() == -1) { queue_init_message("X failed to initialize"); } diff --git a/src/x11focus.c b/src/x11focus.c new file mode 100644 index 0000000..0c4b1af --- /dev/null +++ b/src/x11focus.c @@ -0,0 +1,87 @@ +/* x11focus.c + * + * + * Copyright (C) 2020 Toxic All Rights Reserved. + * + * This file is part of Toxic. + * + * Toxic is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Toxic is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Toxic. If not, see . + * + */ + +#include "x11focus.h" + +#ifndef __APPLE__ + +#include + +static struct Focus { + Display *display; + Window terminal_window; +} Focus; + +static long unsigned int focused_window_id(void) +{ + if (!Focus.display) { + return 0; + } + + Window focus; + int revert; + + XLockDisplay(Focus.display); + XGetInputFocus(Focus.display, &focus, &revert); + XUnlockDisplay(Focus.display); + + return focus; +} + +bool is_focused(void) +{ + if (!Focus.display) { + return false; + } + + return Focus.terminal_window == focused_window_id(); +} + +int init_x11focus(void) +{ + if (XInitThreads() == 0) { + return -1; + } + + Focus.display = XOpenDisplay(NULL); + + if (!Focus.display) { + return -1; + } + + Focus.terminal_window = focused_window_id(); + + return 0; +} + +void terminate_x11focus(void) +{ + if (!Focus.display || !Focus.terminal_window) { + return; + } + + XLockDisplay(Focus.display); + XCloseDisplay(Focus.display); + XUnlockDisplay(Focus.display); +} + +#endif /* !__APPLE__ */ diff --git a/src/xtra.h b/src/x11focus.h similarity index 67% rename from src/xtra.h rename to src/x11focus.h index 7b423af..565168d 100644 --- a/src/xtra.h +++ b/src/x11focus.h @@ -1,7 +1,7 @@ /* xtra.h * * - * Copyright (C) 2014 Toxic All Rights Reserved. + * Copyright (C) 2020 Toxic All Rights Reserved. * * This file is part of Toxic. * @@ -20,21 +20,15 @@ * */ -#ifndef XTRA_H -#define XTRA_H +#ifndef X11FOCUS_H +#define X11FOCUS_H + +#include /* NOTE: If no xlib present don't compile */ -typedef enum { - DT_plain, - DT_file_list -} -DropType; +int init_x11focus(void); +void terminate_x11focus(void); +bool is_focused(void); -typedef void (*drop_callback)(const char *, DropType); - -int init_xtra(drop_callback d); -void terminate_xtra(void); -int is_focused(void); /* returns bool */ - -#endif /* XTRA_H */ +#endif /* X11FOCUS */ diff --git a/src/xtra.c b/src/xtra.c deleted file mode 100644 index 6a3e890..0000000 --- a/src/xtra.c +++ /dev/null @@ -1,426 +0,0 @@ -/* xtra.c - * - * - * Copyright (C) 2014 Toxic All Rights Reserved. - * - * This file is part of Toxic. - * - * Toxic is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Toxic is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Toxic. If not, see . - * - */ - -#include "misc_tools.h" -#include "xtra.h" - -#ifndef __APPLE__ - -#include -#include - -#include -#include -#include -#include -#include - - -const Atom XtraTerminate = 1; -const Atom XtraNil = 0; - -static Atom XdndAware; -static Atom XdndEnter; -static Atom XdndLeave; -static Atom XdndPosition; -static Atom XdndStatus; -static Atom XdndDrop; -static Atom XdndSelection; -static Atom XdndDATA; -static Atom XdndTypeList; -static Atom XdndActionCopy; -static Atom XdndFinished; - -struct Xtra { - drop_callback on_drop; - Display *display; - Window terminal_window; - Window proxy_window; - Window source_window; /* When we have a drop */ - Atom handling_version; - Atom expecting_type; -} Xtra; - -typedef struct Property { - unsigned char *data; - int read_format; - unsigned long read_num; - Atom read_type; -} Property; - -static Property read_property(Window s, Atom p) -{ - Atom read_type; - int read_format; - unsigned long read_num; - unsigned long left_bytes; - unsigned char *data = NULL; - - int read_bytes = 1024; - - /* Keep trying to read the property until there are no bytes unread */ - do { - if (data) { - XFree(data); - } - - XGetWindowProperty(Xtra.display, s, - p, 0, - read_bytes, - False, AnyPropertyType, - &read_type, &read_format, - &read_num, &left_bytes, - &data); - - read_bytes *= 2; - } while (left_bytes != 0); - - Property property = {data, read_format, read_num, read_type}; - return property; -} - -static Atom get_dnd_type(long *a, int l) -{ - int i = 0; - - for (; i < l; i ++) { - if (a[i] != XtraNil) { - return a[i]; /* Get first valid */ - } - } - - return XtraNil; -} - -/* TODO maybe support only certain types in the future */ -static void handle_xdnd_enter(XClientMessageEvent *e) -{ - Xtra.handling_version = (e->data.l[1] >> 24); - - if ((e->data.l[1] & 1)) { - // Fetch the list of possible conversions - Property p = read_property(e->data.l[0], XdndTypeList); - Xtra.expecting_type = get_dnd_type((long *)p.data, p.read_num); - XFree(p.data); - } else { - // Use the available list - Xtra.expecting_type = get_dnd_type(e->data.l + 2, 3); - } -} - -static void handle_xdnd_position(XClientMessageEvent *e) -{ - XEvent ev = { - .xclient = { - .type = ClientMessage, - .display = e->display, - .window = e->data.l[0], - .message_type = XdndStatus, - .format = 32, - .data = { - .l = { - Xtra.proxy_window, - (Xtra.expecting_type != XtraNil), - 0, 0, - XdndActionCopy - } - } - } - }; - - XSendEvent(Xtra.display, e->data.l[0], False, NoEventMask, &ev); - XFlush(Xtra.display); -} - -static void handle_xdnd_drop(XClientMessageEvent *e) -{ - /* Not expecting any type */ - if (Xtra.expecting_type == XtraNil) { - XEvent ev = { - .xclient = { - .type = ClientMessage, - .display = e->display, - .window = e->data.l[0], - .message_type = XdndFinished, - .format = 32, - .data = { - .l = {Xtra.proxy_window, 0, 0} - } - } - }; - - XSendEvent(Xtra.display, e->data.l[0], False, NoEventMask, &ev); - } else { - Xtra.source_window = e->data.l[0]; - XConvertSelection(Xtra.display, - XdndSelection, - Xtra.expecting_type, - XdndSelection, - Xtra.proxy_window, - Xtra.handling_version >= 1 ? e->data.l[2] : CurrentTime); - } -} - -static void handle_xdnd_selection(XSelectionEvent *e) -{ - UNUSED_VAR(e); - - /* DnD succesfully finished, send finished and call callback */ - XEvent ev = { - .xclient = { - .type = ClientMessage, - .display = Xtra.display, - .window = Xtra.source_window, - .message_type = XdndFinished, - .format = 32, - .data = { - .l = {Xtra.proxy_window, 1, XdndActionCopy} - } - } - }; - XSendEvent(Xtra.display, Xtra.source_window, False, NoEventMask, &ev); - - Property p = read_property(Xtra.proxy_window, XdndSelection); - DropType dt; - - if (strcmp(XGetAtomName(Xtra.display, p.read_type), "text/uri-list") == 0) { - dt = DT_file_list; - } else { /* text/uri-list */ - dt = DT_plain; - } - - - /* Call callback for every entry */ - if (Xtra.on_drop && p.read_num) { - char *sptr; - char *str = strtok_r((char *) p.data, "\n\r", &sptr); - - if (str) { - Xtra.on_drop(str, dt); - } - - while ((str = strtok_r(NULL, "\n\r", &sptr))) { - Xtra.on_drop(str, dt); - } - } - - if (p.data) { - XFree(p.data); - } -} - -void *event_loop(void *p) -{ - /* Handle events like a real nigga */ - - UNUSED_VAR(p); /* DINDUNOTHIN */ - - XEvent event; - - while (Xtra.display) { - /* NEEDMOEVENTSFODEMPROGRAMS */ - - int pending = 0; - - XLockDisplay(Xtra.display); - - if ((pending = XPending(Xtra.display))) { - XNextEvent(Xtra.display, &event); - } - - if (!pending) { - XUnlockDisplay(Xtra.display); - sleep_thread(10000L); - continue; - } - - if (event.type == ClientMessage) { - Atom type = event.xclient.message_type; - - if (type == XdndEnter) { - handle_xdnd_enter(&event.xclient); - } else if (type == XdndPosition) { - handle_xdnd_position(&event.xclient); - } else if (type == XdndDrop) { - handle_xdnd_drop(&event.xclient); - } else if (type == XtraTerminate) { - break; - } - } else if (event.type == SelectionNotify) { - handle_xdnd_selection(&event.xselection); - } - /* AINNOBODYCANHANDLEDEMEVENTS*/ - else { - XSendEvent(Xtra.display, Xtra.terminal_window, 0, 0, &event); - } - - XUnlockDisplay(Xtra.display); - } - - /* Actual XTRA termination - * Please call xtra_terminate() at exit - * otherwise HEWUSAGUDBOI happens - */ - if (Xtra.display) { - XCloseDisplay(Xtra.display); - } - - return (Xtra.display = NULL); -} - -static long unsigned int focused_window_id(void) -{ - if (!Xtra.display) { - return 0; - } - - Window focus; - int revert; - XLockDisplay(Xtra.display); - XGetInputFocus(Xtra.display, &focus, &revert); - XUnlockDisplay(Xtra.display); - return focus; -} - -int is_focused(void) -{ - return Xtra.display && (Xtra.proxy_window == focused_window_id() || Xtra.terminal_window == focused_window_id()); -} - -int init_xtra(drop_callback d) -{ - if (!d) { - return -1; - } else { - Xtra.on_drop = d; - } - - XInitThreads(); - - if (!(Xtra.display = XOpenDisplay(NULL))) { - return -1; - } - - Xtra.terminal_window = focused_window_id(); - - /* OSX: if focused window is 0, it means toxic is ran from - * native terminal and not X11 terminal window, silently exit */ - if (!Xtra.terminal_window) { - return 0; - } - - { - /* Create an invisible window which will act as proxy for the DnD operation. */ - XSetWindowAttributes attr = {0}; - attr.event_mask = EnterWindowMask | - LeaveWindowMask | - ButtonMotionMask | - ButtonPressMask | - ButtonReleaseMask | - ResizeRedirectMask; - - attr.do_not_propagate_mask = NoEventMask; - - Window root; - int x, y; - unsigned int wht, hht, b, d; - - /* Since we cannot capture resize events for parent window we will have to create - * this window to have maximum size as defined in root window - */ - XGetGeometry(Xtra.display, - XDefaultRootWindow(Xtra.display), - &root, &x, &y, &wht, &hht, &b, &d); - - if (!(Xtra.proxy_window = XCreateWindow - (Xtra.display, Xtra.terminal_window, /* Parent */ - 0, 0, /* Position */ - wht, hht, /* Width + height */ - 0, /* Border width */ - CopyFromParent, /* Depth */ - InputOnly, /* Class */ - CopyFromParent, /* Visual */ - CWEventMask | CWCursor, /* Value mask */ - &attr))) { /* Attributes for value mask */ - return -1; - } - } - - XMapWindow(Xtra.display, Xtra.proxy_window); /* Show window (sandwich) */ - XLowerWindow(Xtra.display, Xtra.proxy_window); /* Don't interfere with parent lmao */ - - XdndAware = XInternAtom(Xtra.display, "XdndAware", False); - XdndEnter = XInternAtom(Xtra.display, "XdndEnter", False); - XdndLeave = XInternAtom(Xtra.display, "XdndLeave", False); - XdndPosition = XInternAtom(Xtra.display, "XdndPosition", False); - XdndStatus = XInternAtom(Xtra.display, "XdndStatus", False); - XdndDrop = XInternAtom(Xtra.display, "XdndDrop", False); - XdndSelection = XInternAtom(Xtra.display, "XdndSelection", False); - XdndDATA = XInternAtom(Xtra.display, "XdndDATA", False); - XdndTypeList = XInternAtom(Xtra.display, "XdndTypeList", False); - XdndActionCopy = XInternAtom(Xtra.display, "XdndActionCopy", False); - XdndFinished = XInternAtom(Xtra.display, "XdndFinished", False); - - /* Inform my nigga windows that we are aware of dnd */ - Atom XdndVersion = 3; - XChangeProperty(Xtra.display, - Xtra.proxy_window, - XdndAware, - XA_ATOM, - 32, - PropModeReplace, - (unsigned char *)&XdndVersion, 1); - - pthread_t id; - - if (pthread_create(&id, NULL, event_loop, NULL) != 0) { - return -1; - } - - pthread_detach(id); - - return 0; -} - -void terminate_xtra(void) -{ - if (!Xtra.display || !Xtra.terminal_window) { - return; - } - - XEvent terminate = { - .xclient = { - .type = ClientMessage, - .display = Xtra.display, - .message_type = XtraTerminate, - } - }; - - XLockDisplay(Xtra.display); - XDeleteProperty(Xtra.display, Xtra.proxy_window, XdndAware); - XSendEvent(Xtra.display, Xtra.proxy_window, 0, NoEventMask, &terminate); - XUnlockDisplay(Xtra.display); - - while (Xtra.display); /* Wait for termination */ -} - -#endif /* !__APPLE__ */