/* * xwarp - simple program to warp the pointer. * * Run with no args and it prints where the pointer is, relative to the * root window origin. * * Run with two args and it warps the pointer to those (X,Y) * coordinates. * * Either form also supports -display DISP to specify the display. * * Build with -llx -laio. * * This program is in the public domain. */ /* * Include files. is obvious. is almost as obvious; we * have to initialize libaio. because we want to print * things. Finally, because we use a few functions from * it, such as atoi() and exit(). */ #include #include #include #include // The command name, used for printing error messages. extern const char *__progname; /* * Command-line arguments, nil if not (yet) specified. */ static const char *displaystr = 0; static const char *xstr = 0; static const char *ystr = 0; // Our connection to the X server. static LX_CONN *disp; // The number of the screen we're using. static int scr; // The root window ID. static LX_XID rootwin; // The return struct for QueryPointer operations. static LX_QUERYPOINTER_STATUS qps; /* * In C, we have to declare functions before we can call them (or pass * pointers to them as callbacks). This means either a bunch of * forward declarations or code organized with the higher-level (in * terms of the call graph) code later in the file. I do the latter. * This is relevant mostly in that it means you might want to read * this file starting at the end and working upwards instead of * starting at the beginning and working downwards. */ /* * Crack the comamnd-line arglist. When done, we make sure we don't * have an X coordinate but no Y coordinate. */ static void handleargs(int ac, char **av) { int skip; int errs; skip = 0; errs = 0; for (ac--,av++;ac;ac--,av++) { if (skip > 0) { skip --; continue; } if (**av != '-') { if (! xstr) { xstr = *av; } else if (! ystr) { ystr = *av; } else { fprintf(stderr,"%s: extra argument `%s'\n",__progname,*av); errs = 1; } continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs a following argument\n",__progname,*av); errs = 1; continue; } #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0) if (!strcmp(*av,"-display")) { WANTARG(); displaystr = av[skip]; continue; } #undef WANTARG fprintf(stderr,"%s: unrecognized option `%s'\n",__progname,*av); errs = 1; } if (xstr && !ystr) { fprintf(stderr,"%s: must have either zero or two coordinate arguments\n",__progname); errs = 1; } if (errs) exit(1); } /* * Callback indicating we've finished a QueryPointer operation and have * the pointer location ready to print. Just print it (and then exit, * because that's all we have to do). */ static void qps_done(void *arg __attribute__((__unused__))) { printf("%d %d\n",qps.rootx,qps.rooty); exit(0); } /* * Callback indicating the WarpPointer call is done. WarpPointer is an * open-loop call, so we do a GetInputFocus after it, which calls * this. (We can't just exit as soon as we do the WarpPointer, or it * won't get pushed to the server and thus won't actually happen.) * * All there is to do here is exit, because if we're warping then we * have nothing more to do once the warp happens. */ static void warp_done(void *arg __attribute__((__unused__))) { exit(0); } /* * Called once the X connection opens. We just save the connection in * the `disp' global, look up which screen we're using, and then get * its root window. We need the root window regardless of whether * we're warping or querying, so that much is unconditional. * * Then, we check whether we have a warp-to location or whether we're * just querying. If we're querying, we do a QueryPointer, passing * the resulting op to lx_op_callback, telling it to call qps_done * (see above) when it finishes. If not, we convert the args to * numbers, do the WarpPointer, and then do a GetInputFocus to ensure * that the warp has actually happened before we exit. Again, the * resulting op (from lx_GetInputFocus) is told to call us back, * warp_done in this case, when it finishes. We pass nil pointers to * lx_GetInputFocus because we don't actually care about the keyboard * focus settings. */ static void X_open_done(LX_CONN *conn, void *arg __attribute__((__unused__))) { disp = conn; scr = lx_default_screen(disp); rootwin = lx_root(disp,scr); if (! xstr) { lx_op_callback(lx_QueryPointer_status(disp,rootwin,&qps),&qps_done,0,0); } else { int x; int y; x = atoi(xstr); y = atoi(ystr); lx_WarpPointer(disp,rootwin,rootwin,0,0,0,0,x,y); lx_op_callback(lx_GetInputFocus(disp,0,0),&warp_done,0,0); } } /* * Start everything off. Just open the display and do the rest once * it's opened. We pass a nil error handler, to get the default * cough-and-die error behaviour and a nil loop pointer to use the * global loop. The callback arg is nil; we don't use it, so it * doesn't matter what we pass. And, finally, we use no non-default * flags. */ static void start_X(void) { lx_open(displaystr,0,&X_open_done,0,0,0); } /* * This is simple enough: crack the arglist, init libaio, kickstart X * interaction, and drop into the event loop. If-and-when it returns * (not very likely), return 1. */ int main(int, char **); int main(int ac, char **av) { handleargs(ac,av); aio_poll_init(); start_X(); aio_event_loop(); return(1); }