chiark / gitweb /
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 -------------------------------------------------*/