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

Reply via email to