Add new program `xwarpptr'.
[xtoys] / xwarpptr.c
1 /* -*-c-*-
2 *
3 * Warp pointer to a specific location
4 *
5 * (c) 2022 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of the Edgeware X tools collection.
11 *
12 * X tools is free software: you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version.
16 *
17 * X tools is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with X tools. If not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27 /*----- Header files ------------------------------------------------------*/
28
29 #include <errno.h>
30 #include <limits.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33
34 #include <X11/Xlib.h>
35
36 #include <mLib/alloc.h>
37 #include <mLib/macros.h>
38 #include <mLib/mdwopt.h>
39 #include <mLib/quis.h>
40 #include <mLib/report.h>
41
42 /*----- Help and version information --------------------------------------*/
43
44 static void version(void)
45 { pquis(stdout, "$ version " VERSION "\n"); }
46
47 static void usage(FILE *fp)
48 { pquis(fp, "Usage: $ [-d DISPLAY] X Y\n"); }
49
50 static void help(void)
51 {
52 version(); putchar('\n');
53 usage(stdout);
54 fputs("\n\
55 Warp mouse pointer to position X, Y on the screen.\n\
56 \n\
57 Command-line options:\n\
58 \n\
59 -h, --help Display this help.\n\
60 -v, --version Display program's version number.\n\
61 -u, --usage Display short usage summary.\n\
62 \n\
63 -d, --display=DISPLAY Connect to X DISPLAY.\n",
64 stdout);
65 }
66
67 /*----- Main program ------------------------------------------------------*/
68
69 static int parse_int(const char *p)
70 {
71 char *q;
72 int err;
73 long i;
74
75 err = errno; errno = 0;
76 if (!*p || ISSPACE(*p)) goto bad;
77 i = strtol(p, &q, 0);
78 if (err || *q || i < INT_MIN || i > INT_MAX) goto bad;
79 return ((int)i);
80
81 bad:
82 die(1, "bad integer `%s'", p);
83 }
84
85 int main(int argc, char *argv[])
86 {
87 const char *display = 0;
88 Display *dpy = 0;
89 int sc;
90 Window w;
91 char **fixups; int nfixups, i;
92 int x, y, xmin, xmax, ymin, ymax, wd, ht;
93
94 unsigned f = 0;
95 #define f_bogus 1u
96 #define f_relative 2u
97 #define f_neg 4u
98
99 ego(argv[0]);
100
101 /* An initial pass over the argument vector.
102 *
103 * Negative numbers look like options, but we don't want them treated that
104 * way. So we're going to hide them from the option parser for a bit.
105 */
106 fixups = xmalloc(argc*sizeof(char *));
107 for (i = 0, nfixups = 0; i < argc; i++)
108 if (argv[i][0] == '-' && ISDIGIT(argv[i][1]))
109 { fixups[nfixups++] = argv[i]; argv[i][0] = '?'; }
110
111 /* Parse arguments. */
112 for (;;) {
113 static struct option opt[] = {
114 { "help", 0, 0, 'h' },
115 { "usage", 0, 0, 'u' },
116 { "version", 0, 0, 'v' },
117 { "display", OPTF_ARGREQ, 0, 'd' },
118 { "relative", 0, 0, 'r' },
119 { 0, 0, 0, 0 }
120 };
121
122 i = mdwopt(argc, argv, "huvd:r", opt, 0, 0, 0); if (i < 0) break;
123 switch (i) {
124 case 'h': help(); exit(0);
125 case 'u': usage(stdout); exit(0);
126 case 'v': version(); exit(0);
127 case 'd': display = optarg; break;
128 case 'r': f |= f_relative; break;
129 default: f |= f_bogus; break;
130 }
131 }
132 if ((f&f_bogus) || argc - optind != 2) {
133 usage(stderr);
134 exit(EXIT_FAILURE);
135 }
136
137 /* Undo the fixups and fish out the numbers. */
138 for (i = 0; i < nfixups; i++) *fixups[i] = '-';
139 x = parse_int(argv[optind]);
140 y = parse_int(argv[optind + 1]);
141
142 /* Open the display and the screen size. */
143 if ((dpy = XOpenDisplay(display)) == 0)
144 die(EXIT_FAILURE, "couldn't open display");
145 sc = DefaultScreen(dpy);
146 wd = DisplayWidth(dpy, sc);
147 ht = DisplayHeight(dpy, sc);
148
149 /* Interpret the coordinates and check that they're in range. */
150 if (f&f_relative) {
151 w = None;
152 xmin = -wd + 1; ymin = -ht + 1; xmax = wd - 1; ymax = ht - 1;
153 } else {
154 if (x < 0) x += wd;
155 if (y < 0) y += ht;
156 w = RootWindow(dpy, sc);
157 xmin = ymin = 0; xmax = wd - 1; ymax = ht - 1;
158 }
159 if (x < xmin || x > xmax || y < ymin || y > ymax)
160 die(1, "coordinates out of range");
161
162 /* Do the work. */
163 XWarpPointer(dpy, None, w, 0, 0, 0, 0, x, y);
164
165 /* Done. */
166 XCloseDisplay(dpy);
167 return (0);
168
169 #undef f_bogus
170 #undef f_relative
171 }
172
173 /*----- That's all, folks -------------------------------------------------*/