xqueryptr.c: Add new program to interrogate the pointer position.
[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: $ [-r] [-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 -r, --relative Move relative to its current position\n",
65 stdout);
66 }
67
68 /*----- Main program ------------------------------------------------------*/
69
70 static int parse_int(const char *p)
71 {
72 char *q;
73 int err;
74 long i;
75
76 err = errno; errno = 0;
77 if (!*p || ISSPACE(*p)) goto bad;
78 i = strtol(p, &q, 0);
79 if (err || *q || i < INT_MIN || i > INT_MAX) goto bad;
80 return ((int)i);
81
82 bad:
83 die(1, "bad integer `%s'", p);
84 }
85
86 int main(int argc, char *argv[])
87 {
88 const char *display = 0;
89 Display *dpy = 0;
90 int sc;
91 Window w;
92 char **fixups; int nfixups, i;
93 int x, y, xmin, xmax, ymin, ymax, wd, ht;
94
95 unsigned f = 0;
96 #define f_bogus 1u
97 #define f_relative 2u
98 #define f_neg 4u
99
100 ego(argv[0]);
101
102 /* An initial pass over the argument vector.
103 *
104 * Negative numbers look like options, but we don't want them treated that
105 * way. So we're going to hide them from the option parser for a bit.
106 */
107 fixups = xmalloc(argc*sizeof(char *));
108 for (i = 0, nfixups = 0; i < argc; i++)
109 if (argv[i][0] == '-' && ISDIGIT(argv[i][1]))
110 { fixups[nfixups++] = argv[i]; argv[i][0] = '?'; }
111
112 /* Parse arguments. */
113 for (;;) {
114 static struct option opt[] = {
115 { "help", 0, 0, 'h' },
116 { "usage", 0, 0, 'u' },
117 { "version", 0, 0, 'v' },
118 { "display", OPTF_ARGREQ, 0, 'd' },
119 { "relative", 0, 0, 'r' },
120 { 0, 0, 0, 0 }
121 };
122
123 i = mdwopt(argc, argv, "huvd:r", opt, 0, 0, 0); if (i < 0) break;
124 switch (i) {
125 case 'h': help(); exit(0);
126 case 'u': usage(stdout); exit(0);
127 case 'v': version(); exit(0);
128 case 'd': display = optarg; break;
129 case 'r': f |= f_relative; break;
130 default: f |= f_bogus; break;
131 }
132 }
133 if ((f&f_bogus) || argc - optind != 2) {
134 usage(stderr);
135 exit(EXIT_FAILURE);
136 }
137
138 /* Undo the fixups and fish out the numbers. */
139 for (i = 0; i < nfixups; i++) *fixups[i] = '-';
140 x = parse_int(argv[optind]);
141 y = parse_int(argv[optind + 1]);
142
143 /* Open the display and the screen size. */
144 if ((dpy = XOpenDisplay(display)) == 0)
145 die(EXIT_FAILURE, "couldn't open display");
146 sc = DefaultScreen(dpy);
147 wd = DisplayWidth(dpy, sc);
148 ht = DisplayHeight(dpy, sc);
149
150 /* Interpret the coordinates and check that they're in range. */
151 if (f&f_relative) {
152 w = None;
153 xmin = -wd + 1; ymin = -ht + 1; xmax = wd - 1; ymax = ht - 1;
154 } else {
155 if (x < 0) x += wd;
156 if (y < 0) y += ht;
157 w = RootWindow(dpy, sc);
158 xmin = ymin = 0; xmax = wd - 1; ymax = ht - 1;
159 }
160 if (x < xmin || x > xmax || y < ymin || y > ymax)
161 die(1, "coordinates out of range");
162
163 /* Do the work. */
164 XWarpPointer(dpy, None, w, 0, 0, 0, 0, x, y);
165
166 /* Done. */
167 XCloseDisplay(dpy);
168 return (0);
169
170 #undef f_bogus
171 #undef f_relative
172 }
173
174 /*----- That's all, folks -------------------------------------------------*/