Add new program `xwarpptr'.
[xtoys] / xwarpptr.c
CommitLineData
7f25aae9
MW
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
44static void version(void)
45 { pquis(stdout, "$ version " VERSION "\n"); }
46
47static void usage(FILE *fp)
48 { pquis(fp, "Usage: $ [-d DISPLAY] X Y\n"); }
49
50static void help(void)
51{
52 version(); putchar('\n');
53 usage(stdout);
54 fputs("\n\
55Warp mouse pointer to position X, Y on the screen.\n\
56\n\
57Command-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
69static 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
81bad:
82 die(1, "bad integer `%s'", p);
83}
84
85int 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 -------------------------------------------------*/