Control: tags 877455 + patch Control: tags 877455 + pending Dear maintainer,
I've prepared an NMU for xdo (versioned as 0.5.7-1.1) and uploaded it to DELAYED/15. Please feel free to tell me if I should delay it longer. Sorry if anything is wrong about this upload, I haven't done anything like it before. I'm not sure if the package actually made it to DELAYED, let me know if you cannot see it. All I needed to do was run the uupdate script to update the package, and verify the new version worked as expected. Regards. -Jay
diff -Nru xdo-0.5.2/debian/changelog xdo-0.5.7/debian/changelog --- xdo-0.5.2/debian/changelog 2016-05-15 17:00:12.000000000 -0700 +++ xdo-0.5.7/debian/changelog 2018-05-23 23:14:22.000000000 -0700 @@ -1,3 +1,10 @@ +xdo (0.5.7-1.1) unstable; urgency=medium + + * Non-maintainer upload. + * New upstream release (Closes: #877455) + + -- Jay Kamat <jaygka...@gmail.com> Wed, 23 May 2018 23:14:22 -0700 + xdo (0.5.2-1) unstable; urgency=medium * Initial release (Closes: #816024) diff -Nru xdo-0.5.2/doc/xdo.1 xdo-0.5.7/doc/xdo.1 --- xdo-0.5.2/doc/xdo.1 2016-04-11 07:19:37.000000000 -0700 +++ xdo-0.5.7/doc/xdo.1 2017-09-18 05:00:07.000000000 -0700 @@ -1,13 +1,13 @@ '\" t .\" Title: xdo .\" Author: [FIXME: author] [see http://docbook.sf.net/el/author] -.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/> -.\" Date: 03/23/2016 +.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/> +.\" Date: 09/18/2017 .\" Manual: Xdo Manual -.\" Source: Xdo 0.5.2 +.\" Source: Xdo 0.5.7 .\" Language: English .\" -.TH "XDO" "1" "03/23/2016" "Xdo 0\&.5\&.2" "Xdo Manual" +.TH "XDO" "1" "09/18/2017" "Xdo 0\&.5\&.7" "Xdo Manual" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- @@ -106,16 +106,21 @@ Print the window\(cqs pid\&. .RE .PP -\fBkey\fR +\fBkey_press\fR, \fBkey_release\fR .RS 4 Simulate a key press/release event\&. .RE .PP -\fBbutton\fR +\fBbutton_press\fR, \fBbutton_release\fR .RS 4 Simulate a button press/release event\&. .RE .PP +\fBpointer_motion\fR +.RS 4 +Simulate a pointer motion event\&. +.RE +.PP \fB\-h\fR .RS 4 Print the synopsis and exit\&. @@ -186,9 +191,11 @@ \fB\-k\fR \fICODE\fR .RS 4 Use the given code for the -\fBkey\fR +\fBkey_press\fR, +\fBkey_release\fR, +\fBbutton_press\fR and -\fBbutton\fR +\fBbutton_release\fR actions\&. .RE .PP @@ -196,6 +203,8 @@ .RS 4 Window x coordinate (or delta) for the \fBmove\fR +and +\fBpointer_motion\fR action\&. .RE .PP @@ -203,6 +212,8 @@ .RS 4 Window y coordinate (or delta) for the \fBmove\fR +and +\fBpointer_motion\fR action\&. .RE .PP @@ -220,6 +231,11 @@ action\&. .RE .PP +\fB\-m\fR +.RS 4 +Wait for the existence of a matching window\&. +.RE +.PP \fB\-s\fR .RS 4 Handle symbolic desktop numbers\&. @@ -274,13 +290,13 @@ .RE .\} .sp -Send fake key press/release events with keycode 24 to the focused window: +Send fake key press/release events with keycode 46 to the focused window: .sp .if n \{\ .RS 4 .\} .nf -xdo key \-k 24 +xdo key_press \-k 46; sleep 0\&.2; xdo key_release \-k 46 .fi .if n \{\ .RE diff -Nru xdo-0.5.2/doc/xdo.1.txt xdo-0.5.7/doc/xdo.1.txt --- xdo-0.5.2/doc/xdo.1.txt 2016-04-11 07:19:37.000000000 -0700 +++ xdo-0.5.7/doc/xdo.1.txt 2017-09-18 05:00:07.000000000 -0700 @@ -64,12 +64,17 @@ *pid*:: Print the window's pid. -*key*:: +*key_press*:: +*key_release*:: Simulate a key press/release event. -*button*:: +*button_press*:: +*button_release*:: Simulate a button press/release event. +*pointer_motion*:: + Simulate a pointer motion event. + *-h*:: Print the synopsis and exit. @@ -112,13 +117,13 @@ The window has the given pid. *-k* 'CODE':: - Use the given code for the *key* and *button* actions. + Use the given code for the *key_press*, *key_release*, *button_press* and *button_release* actions. *-x* '[±]PIXELS':: - Window x coordinate (or delta) for the *move* action. + Window x coordinate (or delta) for the *move* and *pointer_motion* action. *-y* '[±]PIXELS':: - Window y coordinate (or delta) for the *move* action. + Window y coordinate (or delta) for the *move* and *pointer_motion* action. *-w* '[±]PIXELS':: Window width (or delta) for the *resize* action. @@ -126,6 +131,9 @@ *-h* '[±]PIXELS':: Window height (or delta) for the *resize* action. +*-m*:: + Wait for the existence of a matching window. + *-s*:: Handle symbolic desktop numbers. @@ -156,10 +164,10 @@ xdo activate 0x00800109 ---- -Send fake key press/release events with keycode 24 to the focused window: +Send fake key press/release events with keycode 46 to the focused window: ---- -xdo key -k 24 +xdo key_press -k 46; sleep 0.2; xdo key_release -k 46 ---- //// diff -Nru xdo-0.5.2/helpers.c xdo-0.5.7/helpers.c --- xdo-0.5.2/helpers.c 2016-04-11 07:19:37.000000000 -0700 +++ xdo-0.5.7/helpers.c 2017-09-18 05:00:07.000000000 -0700 @@ -5,18 +5,18 @@ void warn(char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); } __attribute__((noreturn)) void err(char *fmt, ...) { - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - exit(EXIT_FAILURE); + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(EXIT_FAILURE); } diff -Nru xdo-0.5.2/Makefile xdo-0.5.7/Makefile --- xdo-0.5.2/Makefile 2016-04-11 07:19:37.000000000 -0700 +++ xdo-0.5.7/Makefile 2017-09-18 05:00:07.000000000 -0700 @@ -2,9 +2,9 @@ VERCMD ?= git describe 2> /dev/null VERSION := $(shell $(VERCMD) || cat VERSION) -CPPFLAGS += -D_POSIX_C_SOURCE=200112L -DVERSION=\"$(VERSION)\" +CPPFLAGS += -D_POSIX_C_SOURCE=200809L -DVERSION=\"$(VERSION)\" CFLAGS += -std=c99 -pedantic -Wall -Wextra -LDLIBS := -lxcb -lxcb-icccm -lxcb-ewmh -lxcb-xtest +LDLIBS := -lxcb -lxcb-util -lxcb-icccm -lxcb-ewmh -lxcb-xtest PREFIX ?= /usr/local BINPREFIX ?= $(PREFIX)/bin diff -Nru xdo-0.5.2/README.asciidoc xdo-0.5.7/README.asciidoc --- xdo-0.5.2/README.asciidoc 2016-04-11 07:19:37.000000000 -0700 +++ xdo-0.5.7/README.asciidoc 2017-09-18 05:00:07.000000000 -0700 @@ -64,12 +64,17 @@ *pid*:: Print the window's pid. -*key*:: +*key_press*:: +*key_release*:: Simulate a key press/release event. -*button*:: +*button_press*:: +*button_release*:: Simulate a button press/release event. +*pointer_motion*:: + Simulate a pointer motion event. + *-h*:: Print the synopsis and exit. @@ -112,13 +117,13 @@ The window has the given pid. *-k* 'CODE':: - Use the given code for the *key* and *button* actions. + Use the given code for the *key_press*, *key_release*, *button_press* and *button_release* actions. *-x* '[±]PIXELS':: - Window x coordinate (or delta) for the *move* action. + Window x coordinate (or delta) for the *move* and *pointer_motion* action. *-y* '[±]PIXELS':: - Window y coordinate (or delta) for the *move* action. + Window y coordinate (or delta) for the *move* and *pointer_motion* action. *-w* '[±]PIXELS':: Window width (or delta) for the *resize* action. @@ -126,6 +131,9 @@ *-h* '[±]PIXELS':: Window height (or delta) for the *resize* action. +*-m*:: + Wait for the existence of a matching window. + *-s*:: Handle symbolic desktop numbers. @@ -156,10 +164,10 @@ xdo activate 0x00800109 ---- -Send fake key press/release events with keycode 24 to the focused window: +Send fake key press/release events with keycode 46 to the focused window: ---- -xdo key -k 24 +xdo key_press -k 46; sleep 0.2; xdo key_release -k 46 ---- //// diff -Nru xdo-0.5.2/VERSION xdo-0.5.7/VERSION --- xdo-0.5.2/VERSION 2016-04-11 07:19:37.000000000 -0700 +++ xdo-0.5.7/VERSION 2017-09-18 05:00:07.000000000 -0700 @@ -1 +1 @@ -0.5.2 \ No newline at end of file +0.5.7 \ No newline at end of file diff -Nru xdo-0.5.2/xdo.c xdo-0.5.7/xdo.c --- xdo-0.5.2/xdo.c 2016-04-11 07:19:37.000000000 -0700 +++ xdo-0.5.7/xdo.c 2017-09-18 05:00:07.000000000 -0700 @@ -3,328 +3,396 @@ #include <stdbool.h> #include <string.h> #include <unistd.h> +#include <time.h> +#include <signal.h> #include <errno.h> #include <xcb/xcb_icccm.h> #include <xcb/xcb_ewmh.h> +#include <xcb/xcb_aux.h> #include <xcb/xtest.h> #include "helpers.h" #include "xdo.h" int main(int argc, char *argv[]) { - if (argc < 2) - err("No arguments given.\n"); - - void (*action) (xcb_window_t win); - - if (strcmp(argv[1], "id") == 0) - action = window_id; - else if (strcmp(argv[1], "pid") == 0) - action = window_pid; - else if (strcmp(argv[1], "activate") == 0) - action = window_activate; - else if (strcmp(argv[1], "hide") == 0) - action = window_hide; - else if (strcmp(argv[1], "show") == 0) - action = window_show; - else if (strcmp(argv[1], "move") == 0) - action = window_move; - else if (strcmp(argv[1], "resize") == 0) - action = window_resize; - else if (strcmp(argv[1], "close") == 0) - action = window_close; - else if (strcmp(argv[1], "kill") == 0) - action = window_kill; - else if (strcmp(argv[1], "raise") == 0) - action = window_raise; - else if (strcmp(argv[1], "lower") == 0) - action = window_lower; - else if (strcmp(argv[1], "below") == 0) - action = window_below; - else if (strcmp(argv[1], "above") == 0) - action = window_above; - else if (strcmp(argv[1], "key") == 0) - action = key_press_release; - else if (strcmp(argv[1], "button") == 0) - action = button_press_release; - else if (strcmp(argv[1], "-h") == 0) - return usage(); - else if (strcmp(argv[1], "-v") == 0) - return version(); - else - err("Unknown action: '%s'.\n", argv[1]); - - init(); - argc--, argv++; - int opt; - while ((opt = getopt(argc, argv, "rcCdDsn:N:a:p:k:t:x:y:h:w:")) != -1) { - switch (opt) { - case 'r': - cfg.wid = VALUE_DIFFERENT; - break; - case 'c': - cfg.class = VALUE_SAME; - break; - case 'C': - cfg.class = VALUE_DIFFERENT; - break; - case 'd': - cfg.desktop = VALUE_SAME; - break; - case 'D': - cfg.desktop = VALUE_DIFFERENT; - break; - case 'n': - cfg.instance_name = optarg; - break; - case 'N': - cfg.class_name = optarg; - break; - case 'a': - cfg.wm_name = optarg; - break; - case 'p': - cfg.pid = atoi(optarg); - break; - case 't': - cfg.target = strtol(optarg, NULL, 0); - break; - case 'k': - cfg.evt_code = atoi(optarg); - break; - case 's': - cfg.symb_desks = true; - break; - case 'x': - cfg.x = optarg; - break; - case 'y': - cfg.y = optarg; - break; - case 'w': - cfg.width = optarg; - break; - case 'h': - cfg.height = optarg; - break; - } - } - - int num = argc - optind; - char **args = argv + optind; - - setup(); - - int hits = 0; - xcb_window_t win = XCB_NONE; - char class[MAXLEN] = {0}; - uint32_t desktop = 0; - if (cfg.wid != VALUE_IGNORE || cfg.class != VALUE_IGNORE) - get_active_window(&win); - if (cfg.class != VALUE_IGNORE) - get_class(win, class, sizeof(class)); - if (cfg.desktop != VALUE_IGNORE) - get_current_desktop(&desktop); - - if (num > 0) { - char *end; - for (int i = 0; i < num; i++) { - errno = 0; - long int w = strtol(args[i], &end, 0); - if (errno != 0 || *end != '\0') { - warn("Invalid window ID: '%s'.\n", args[i]); - } else if (match(w, win, desktop, class)) { - (*action)(w); - hits++; - } - } - } else { - if (cfg.class == VALUE_IGNORE - && cfg.desktop == VALUE_IGNORE - && cfg.class_name == NULL - && cfg.instance_name == NULL - && cfg.wm_name == NULL - && cfg.pid == 0) { - xcb_window_t win; - get_active_window(&win); - if (win != XCB_NONE) { - (*action)(win); - hits++; - } - } else { - xcb_query_tree_reply_t *qtr = xcb_query_tree_reply(dpy, xcb_query_tree(dpy, root), NULL); - if (qtr == NULL) - err("Failed to query the window tree.\n"); - int len = xcb_query_tree_children_length(qtr); - xcb_window_t *wins = xcb_query_tree_children(qtr); - for (int i = 0; i < len; i++) { - xcb_window_t w = wins[i]; - if (match(w, win, desktop, class)) { - (*action)(w); - hits++; - } - } - free(qtr); - } - } - - finish(); - if (hits > 0) - return EXIT_SUCCESS; - else - return EXIT_FAILURE; + if (argc < 2) { + err("No arguments given.\n"); + } + + void (*action) (xcb_window_t win); + + if (strcmp(argv[1], "id") == 0) { + action = window_id; + } else if (strcmp(argv[1], "pid") == 0) { + action = window_pid; + } else if (strcmp(argv[1], "activate") == 0) { + action = window_activate; + } else if (strcmp(argv[1], "hide") == 0) { + action = window_hide; + } else if (strcmp(argv[1], "show") == 0) { + action = window_show; + } else if (strcmp(argv[1], "move") == 0) { + action = window_move; + } else if (strcmp(argv[1], "resize") == 0) { + action = window_resize; + } else if (strcmp(argv[1], "close") == 0) { + action = window_close; + } else if (strcmp(argv[1], "kill") == 0) { + action = window_kill; + } else if (strcmp(argv[1], "raise") == 0) { + action = window_raise; + } else if (strcmp(argv[1], "lower") == 0) { + action = window_lower; + } else if (strcmp(argv[1], "below") == 0) { + action = window_below; + } else if (strcmp(argv[1], "above") == 0) { + action = window_above; + } else if (strcmp(argv[1], "key_press") == 0) { + action = key_press; + } else if (strcmp(argv[1], "key_release") == 0) { + action = key_release; + } else if (strcmp(argv[1], "button_press") == 0) { + action = button_press; + } else if (strcmp(argv[1], "button_release") == 0) { + action = button_release; + } else if (strcmp(argv[1], "pointer_motion") == 0) { + action = pointer_motion; + } else if (strcmp(argv[1], "-h") == 0) { + return usage(); + } else if (strcmp(argv[1], "-v") == 0) { + return version(); + } else { + err("Unknown action: '%s'.\n", argv[1]); + } + + init(); + argc--, argv++; + int opt; + while ((opt = getopt(argc, argv, "rcCdDsmn:N:a:p:k:t:x:y:h:w:")) != -1) { + switch (opt) { + case 'r': + cfg.wid = VALUE_DIFFERENT; + break; + case 'c': + cfg.class = VALUE_SAME; + break; + case 'C': + cfg.class = VALUE_DIFFERENT; + break; + case 'd': + cfg.desktop = VALUE_SAME; + break; + case 'D': + cfg.desktop = VALUE_DIFFERENT; + break; + case 'n': + cfg.instance_name = optarg; + break; + case 'N': + cfg.class_name = optarg; + break; + case 'a': + cfg.wm_name = optarg; + break; + case 'p': + cfg.pid = atoi(optarg); + break; + case 't': + cfg.target = strtol(optarg, NULL, 0); + break; + case 'k': + cfg.evt_code = atoi(optarg); + break; + case 's': + cfg.symb_desks = true; + break; + case 'm': + cfg.wait_match = true; + break; + case 'x': + cfg.x = optarg; + break; + case 'y': + cfg.y = optarg; + break; + case 'w': + cfg.width = optarg; + break; + case 'h': + cfg.height = optarg; + break; + } + } + + int num = argc - optind; + char **args = argv + optind; + + setup(); + + struct sigaction sa; + sa.sa_handler = &handle_signal; + sa.sa_flags = SA_RESTART; + sigfillset(&sa.sa_mask); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); + + int hits = 0; + xcb_window_t win = XCB_NONE; + + if (action == key_press || + action == key_release || + action == button_press || + action == button_release || + action == pointer_motion) { + hits = 1; + (*action)(win); + goto end; + } + + char class[MAXLEN] = {0}; + uint32_t desktop = 0; + if (cfg.wid != VALUE_IGNORE || cfg.class != VALUE_IGNORE) { + get_active_window(&win); + } + if (cfg.class != VALUE_IGNORE) { + get_class(win, class, sizeof(class)); + } + if (cfg.desktop != VALUE_IGNORE) { + get_current_desktop(&desktop); + } + + running = true; + + while (running) { + if (num > 0) { + char *end; + for (int i = 0; i < num; i++) { + errno = 0; + long int w = strtol(args[i], &end, 0); + if (errno != 0 || *end != '\0') { + warn("Invalid window ID: '%s'.\n", args[i]); + } else if (match(w, win, desktop, class)) { + (*action)(w); + hits++; + } + } + } else { + if (cfg.wid == VALUE_IGNORE && + cfg.class == VALUE_IGNORE && + cfg.desktop == VALUE_IGNORE && + cfg.class_name == NULL && + cfg.instance_name == NULL && + cfg.wm_name == NULL && + cfg.pid == 0) { + xcb_window_t win; + get_active_window(&win); + if (win != XCB_NONE) { + (*action)(win); + hits++; + } + } else { + apply(action, root, win, desktop, class, &hits); + } + } + + if (cfg.wait_match && hits == 0) { + nanosleep(&wait_interval, NULL); + } else { + break; + } + } + +end: + finish(); + if (hits > 0) { + return EXIT_SUCCESS; + } else { + return EXIT_FAILURE; + } +} + +void apply(void (*action)(xcb_window_t), xcb_window_t parent, xcb_window_t win, uint32_t desktop, char* class, int* hits) +{ + xcb_query_tree_reply_t *qtr = xcb_query_tree_reply(dpy, xcb_query_tree(dpy, parent), NULL); + if (qtr == NULL) { + warn("Failed to query the window tree.\n"); + return; + } + int len = xcb_query_tree_children_length(qtr); + xcb_window_t *wins = xcb_query_tree_children(qtr); + for (int i = 0; i < len; i++) { + xcb_window_t w = wins[i]; + if (match(w, win, desktop, class)) { + (*action)(w); + (*hits)++; + } + apply(action, w, win, desktop, class, hits); + } + free(qtr); } bool match(xcb_window_t w, xcb_window_t win, uint32_t desktop, char* class) { - char c[MAXLEN] = {0}, i[MAXLEN] = {0}, n[MAXLEN] = {0}; - uint32_t d, p; - return (cfg.wid == VALUE_IGNORE || (cfg.wid == VALUE_DIFFERENT && w != win)) && - (cfg.class == VALUE_IGNORE || - (get_class(w, c, sizeof(c)) && - ((cfg.class == VALUE_SAME && strcmp(class, c) == 0) || - (cfg.class == VALUE_DIFFERENT && strcmp(class, c) != 0)))) && - (cfg.class_name == NULL || (get_class(w, c, sizeof(c)) - && strcmp(cfg.class_name, c) == 0)) && - (cfg.instance_name == NULL || (get_instance(w, i, sizeof(i)) - && strcmp(cfg.instance_name, i) == 0)) && - (cfg.wm_name == NULL || (get_wm_name(w, n, sizeof(n)) - && strcmp(cfg.wm_name, n) == 0)) && - (cfg.pid == 0 || (get_pid(w, &p) && p == cfg.pid)) && - (cfg.desktop == VALUE_IGNORE || - (get_desktop(w, &d) && - ((cfg.desktop == VALUE_SAME && DESKEQ(desktop, d)) || - (cfg.desktop == VALUE_DIFFERENT && !DESKEQ(desktop, d))))); + char c[MAXLEN] = {0}, i[MAXLEN] = {0}, n[MAXLEN] = {0}; + uint32_t d, p; + return (cfg.wid == VALUE_IGNORE || (cfg.wid == VALUE_DIFFERENT && w != win)) && + (cfg.class == VALUE_IGNORE || + (get_class(w, c, sizeof(c)) && + ((cfg.class == VALUE_SAME && strcmp(class, c) == 0) || + (cfg.class == VALUE_DIFFERENT && strcmp(class, c) != 0)))) && + (cfg.class_name == NULL || (get_class(w, c, sizeof(c)) && + strcmp(cfg.class_name, c) == 0)) && + (cfg.instance_name == NULL || (get_instance(w, i, sizeof(i)) && + strcmp(cfg.instance_name, i) == 0)) && + (cfg.wm_name == NULL || (get_wm_name(w, n, sizeof(n)) && + strcmp(cfg.wm_name, n) == 0)) && + (cfg.pid == 0 || (get_pid(w, &p) && p == cfg.pid)) && + (cfg.desktop == VALUE_IGNORE || + (get_desktop(w, &d) && + ((cfg.desktop == VALUE_SAME && DESKEQ(desktop, d)) || + (cfg.desktop == VALUE_DIFFERENT && !DESKEQ(desktop, d))))); } void init(void) { - cfg.class = cfg.desktop = cfg.wid = VALUE_IGNORE; - cfg.class_name = cfg.instance_name = NULL; - cfg.x = cfg.y = cfg.width = cfg.height = NULL; - cfg.pid = 0; - cfg.evt_code = XCB_NONE; - cfg.symb_desks = false; + cfg.class = cfg.desktop = cfg.wid = VALUE_IGNORE; + cfg.class_name = cfg.instance_name = NULL; + cfg.x = cfg.y = cfg.width = cfg.height = NULL; + cfg.pid = 0; + cfg.evt_code = XCB_NONE; + cfg.symb_desks = cfg.wait_match = false; } int usage(void) { - printf("xdo ACTION [OPTIONS] [WID ...]\n"); - return EXIT_SUCCESS; + printf("xdo ACTION [OPTIONS] [WID ...]\n"); + return EXIT_SUCCESS; } int version(void) { - printf("%s\n", VERSION); - return EXIT_SUCCESS; + printf("%s\n", VERSION); + return EXIT_SUCCESS; } void setup(void) { - dpy = xcb_connect(NULL, &default_screen); - if (xcb_connection_has_error(dpy)) - err("Can't open display.\n"); - xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(dpy)).data; - if (screen == NULL) - err("Can't acquire screen.\n"); - root = screen->root; - ewmh = malloc(sizeof(xcb_ewmh_connection_t)); - if (xcb_ewmh_init_atoms_replies(ewmh, xcb_ewmh_init_atoms(dpy, ewmh), NULL) == 0) - err("Can't initialize EWMH atoms.\n"); + dpy = xcb_connect(NULL, &default_screen); + if (xcb_connection_has_error(dpy)) { + err("Can't open display.\n"); + } + xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(dpy)).data; + if (screen == NULL) { + err("Can't acquire screen.\n"); + } + root = screen->root; + ewmh = malloc(sizeof(xcb_ewmh_connection_t)); + if (xcb_ewmh_init_atoms_replies(ewmh, xcb_ewmh_init_atoms(dpy, ewmh), NULL) == 0) { + err("Can't initialize EWMH atoms.\n"); + } } void finish(void) { - xcb_flush(dpy); - xcb_ewmh_connection_wipe(ewmh); - free(ewmh); - xcb_disconnect(dpy); + xcb_aux_sync(dpy); + xcb_ewmh_connection_wipe(ewmh); + free(ewmh); + xcb_disconnect(dpy); +} + +void handle_signal(int sig) +{ + if (sig == SIGTERM || sig == SIGINT || sig == SIGHUP) { + running = false; + } } void get_active_window(xcb_window_t *win) { - if (xcb_ewmh_get_active_window_reply(ewmh, xcb_ewmh_get_active_window(ewmh, default_screen), win, NULL) != 1) - err("Can't determine the active window.\n"); + if (xcb_ewmh_get_active_window_reply(ewmh, xcb_ewmh_get_active_window(ewmh, default_screen), win, NULL) != 1) { + err("Can't determine the active window.\n"); + } } bool get_class(xcb_window_t win, char *class, size_t len) { - xcb_icccm_get_wm_class_reply_t icr; - if (xcb_icccm_get_wm_class_reply(dpy, xcb_icccm_get_wm_class(dpy, win), &icr, NULL) == 1) { - strncpy(class, icr.class_name, len); - return true; - } else { - return false; - } + xcb_icccm_get_wm_class_reply_t icr; + if (xcb_icccm_get_wm_class_reply(dpy, xcb_icccm_get_wm_class(dpy, win), &icr, NULL) == 1) { + strncpy(class, icr.class_name, len); + return true; + } else { + return false; + } } bool get_instance(xcb_window_t win, char *instance, size_t len) { - xcb_icccm_get_wm_class_reply_t icr; - if (xcb_icccm_get_wm_class_reply(dpy, xcb_icccm_get_wm_class(dpy, win), &icr, NULL) == 1) { - strncpy(instance, icr.instance_name, len); - return true; - } else { - return false; - } + xcb_icccm_get_wm_class_reply_t icr; + if (xcb_icccm_get_wm_class_reply(dpy, xcb_icccm_get_wm_class(dpy, win), &icr, NULL) == 1) { + strncpy(instance, icr.instance_name, len); + return true; + } else { + return false; + } } bool get_wm_name(xcb_window_t win, char *wm_name, size_t len) { xcb_icccm_get_text_property_reply_t itr; - if (xcb_icccm_get_wm_name_reply(dpy, xcb_icccm_get_wm_name(dpy, win), &itr, NULL) == 1) { - strncpy(wm_name, itr.name, len); - return true; - } else { - return false; - } + if (xcb_icccm_get_wm_name_reply(dpy, xcb_icccm_get_wm_name(dpy, win), &itr, NULL) == 1) { + strncpy(wm_name, itr.name, MIN(len, itr.name_len)); + return true; + } else { + return false; + } } bool get_pid(xcb_window_t win, uint32_t *pid) { - return (xcb_ewmh_get_wm_pid_reply(ewmh, xcb_ewmh_get_wm_pid(ewmh, win), pid, NULL) == 1); + return (xcb_ewmh_get_wm_pid_reply(ewmh, xcb_ewmh_get_wm_pid(ewmh, win), pid, NULL) == 1); } bool get_desktop(xcb_window_t win, uint32_t *desktop) { - return (xcb_ewmh_get_wm_desktop_reply(ewmh, xcb_ewmh_get_wm_desktop(ewmh, win), desktop, NULL) == 1 && (*desktop != ALL_DESKS || cfg.symb_desks)); + return (xcb_ewmh_get_wm_desktop_reply(ewmh, xcb_ewmh_get_wm_desktop(ewmh, win), desktop, NULL) == 1 && (*desktop != ALL_DESKS || cfg.symb_desks)); } bool get_current_desktop(uint32_t *desktop) { - return (xcb_ewmh_get_current_desktop_reply(ewmh, xcb_ewmh_get_current_desktop(ewmh, default_screen), desktop, NULL) == 1); + return (xcb_ewmh_get_current_desktop_reply(ewmh, xcb_ewmh_get_current_desktop(ewmh, default_screen), desktop, NULL) == 1); } void window_close(xcb_window_t win) { - xcb_ewmh_request_close_window(ewmh, default_screen, win, XCB_CURRENT_TIME, XCB_EWMH_CLIENT_SOURCE_TYPE_OTHER); + xcb_ewmh_request_close_window(ewmh, default_screen, win, XCB_CURRENT_TIME, XCB_EWMH_CLIENT_SOURCE_TYPE_OTHER); } void window_kill(xcb_window_t win) { - xcb_kill_client(dpy, win); + xcb_kill_client(dpy, win); } void window_hide(xcb_window_t win) { - xcb_unmap_window(dpy, win); + xcb_unmap_window(dpy, win); } void window_show(xcb_window_t win) { - xcb_map_window(dpy, win); + xcb_map_window(dpy, win); } void window_raise(xcb_window_t win) { - uint32_t values[] = {XCB_STACK_MODE_ABOVE}; - xcb_configure_window(dpy, win, XCB_CONFIG_WINDOW_STACK_MODE, values); + uint32_t values[] = {XCB_STACK_MODE_ABOVE}; + xcb_configure_window(dpy, win, XCB_CONFIG_WINDOW_STACK_MODE, values); } void window_lower(xcb_window_t win) { - uint32_t values[] = {XCB_STACK_MODE_BELOW}; - xcb_configure_window(dpy, win, XCB_CONFIG_WINDOW_STACK_MODE, values); + uint32_t values[] = {XCB_STACK_MODE_BELOW}; + xcb_configure_window(dpy, win, XCB_CONFIG_WINDOW_STACK_MODE, values); } void window_stack(xcb_window_t win, uint32_t mode) @@ -345,72 +413,96 @@ } #define SETGEOM(v) \ - if (cfg.v != NULL) { \ - uint32_t v = atoi(cfg.v); \ - if (ISRELA(cfg.v)) \ - values[i] += v; \ - else \ - values[i] = v; \ - } \ - i++; + if (cfg.v != NULL) { \ + uint32_t v = atoi(cfg.v); \ + if (ISRELA(cfg.v)) { \ + values[i] += v; \ + } else { \ + values[i] = v; \ + } \ + } \ + i++; void window_move(xcb_window_t win) { - xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply(dpy, xcb_get_geometry(dpy, win), NULL); - if (geo == NULL) - return; - uint32_t values[2] = {geo->x, geo->y}; - int i = 0; - SETGEOM(x) - SETGEOM(y) - xcb_configure_window(dpy, win, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values); + xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply(dpy, xcb_get_geometry(dpy, win), NULL); + if (geo == NULL) { + return; + } + uint32_t values[2] = {geo->x, geo->y}; + int i = 0; + SETGEOM(x) + SETGEOM(y) + xcb_configure_window(dpy, win, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values); } void window_resize(xcb_window_t win) { - xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply(dpy, xcb_get_geometry(dpy, win), NULL); - if (geo == NULL) - return; - uint32_t values[2] = {geo->width, geo->height}; - int i = 0; - SETGEOM(width) - SETGEOM(height) - xcb_configure_window(dpy, win, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values); + xcb_get_geometry_reply_t *geo = xcb_get_geometry_reply(dpy, xcb_get_geometry(dpy, win), NULL); + if (geo == NULL) { + return; + } + uint32_t values[2] = {geo->width, geo->height}; + int i = 0; + SETGEOM(width) + SETGEOM(height) + xcb_configure_window(dpy, win, XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT, values); } #undef SETGEOM void window_activate(xcb_window_t win) { - xcb_ewmh_request_change_active_window(ewmh, default_screen, win, XCB_EWMH_CLIENT_SOURCE_TYPE_OTHER, XCB_CURRENT_TIME, XCB_NONE); + xcb_ewmh_request_change_active_window(ewmh, default_screen, win, XCB_EWMH_CLIENT_SOURCE_TYPE_OTHER, XCB_CURRENT_TIME, XCB_NONE); } void window_id(xcb_window_t win) { - printf("0x%08X\n", win); + printf("0x%08X\n", win); } void window_pid(xcb_window_t win) { - uint32_t pid; - if (get_pid(win, &pid)) - printf("%i\n", pid); + uint32_t pid; + if (get_pid(win, &pid)) { + printf("%i\n", pid); + } } void fake_input(xcb_window_t win, uint8_t evt, uint8_t code) { - xcb_test_fake_input(dpy, evt, code, XCB_CURRENT_TIME, win, 0, 0, 0); + xcb_test_fake_input(dpy, evt, code, XCB_CURRENT_TIME, win, 0, 0, 0); +} + +void fake_motion(xcb_window_t win, uint8_t rel, uint16_t x, uint16_t y) +{ + xcb_test_fake_input(dpy, XCB_MOTION_NOTIFY, rel, XCB_CURRENT_TIME, win, x, y, 0); +} + +void key_press(xcb_window_t win) +{ + fake_input(win, XCB_KEY_PRESS, cfg.evt_code); +} + +void key_release(xcb_window_t win) +{ + fake_input(win, XCB_KEY_RELEASE, cfg.evt_code); +} + +void button_press(xcb_window_t win) +{ + fake_input(win, XCB_BUTTON_PRESS, cfg.evt_code); } -void key_press_release(xcb_window_t win) +void button_release(xcb_window_t win) { - fake_input(win, XCB_KEY_PRESS, cfg.evt_code); - fake_input(win, XCB_KEY_RELEASE, cfg.evt_code); + fake_input(win, XCB_BUTTON_RELEASE, cfg.evt_code); } -void button_press_release(xcb_window_t win) +void pointer_motion(xcb_window_t win) { - fake_input(win, XCB_BUTTON_PRESS, cfg.evt_code); - fake_input(win, XCB_BUTTON_RELEASE, cfg.evt_code); + uint16_t x = atoi(cfg.x); + uint16_t y = atoi(cfg.y); + fake_motion(win, ISRELA(cfg.x) || ISRELA(cfg.y), x, y); } diff -Nru xdo-0.5.2/xdo.h xdo-0.5.7/xdo.h --- xdo-0.5.2/xdo.h 2016-04-11 07:19:37.000000000 -0700 +++ xdo-0.5.7/xdo.h 2017-09-18 05:00:07.000000000 -0700 @@ -6,40 +6,46 @@ #define ISRELA(s) (s[0] == '+' || s[0] == '-') typedef enum { - VALUE_IGNORE, - VALUE_SAME, - VALUE_DIFFERENT + VALUE_IGNORE, + VALUE_SAME, + VALUE_DIFFERENT } value_cmp_t; typedef struct { - value_cmp_t wid; - value_cmp_t class; - value_cmp_t desktop; - char *class_name; - char *instance_name; - char *wm_name; - char *x; - char *y; - char *width; - char *height; - uint32_t pid; - uint8_t evt_code; - bool symb_desks; - long int target; + value_cmp_t wid; + value_cmp_t class; + value_cmp_t desktop; + char *class_name; + char *instance_name; + char *wm_name; + char *x; + char *y; + char *width; + char *height; + uint32_t pid; + uint8_t evt_code; + bool symb_desks; + bool wait_match; + long int target; } config_t; +const struct timespec wait_interval = {0, 1e8}; // 100 ms + xcb_connection_t *dpy; int default_screen; xcb_window_t root; xcb_ewmh_connection_t *ewmh; config_t cfg; +bool running; +void apply(void (*action)(xcb_window_t), xcb_window_t parent, xcb_window_t win, uint32_t desktop, char* class, int* hits); bool match(xcb_window_t w, xcb_window_t win, uint32_t desktop, char* class); void init(void); int usage(void); int version(void); void setup(void); void finish(void); +void handle_signal(int sig); void get_active_window(xcb_window_t *win); bool get_class(xcb_window_t win, char *class, size_t len); bool get_instance(xcb_window_t win, char *instance, size_t len); @@ -62,7 +68,11 @@ void window_id(xcb_window_t win); void window_pid(xcb_window_t win); void fake_input(xcb_window_t win, uint8_t evt, uint8_t code); -void key_press_release(xcb_window_t win); -void button_press_release(xcb_window_t win); +void fake_motion(xcb_window_t win, uint8_t rel, uint16_t x, uint16_t y); +void key_press(xcb_window_t win); +void key_release(xcb_window_t win); +void button_press(xcb_window_t win); +void button_release(xcb_window_t win); +void pointer_motion(xcb_window_t win); #endif