Default style (Cherry Eve). Switch styles (Capricorn). XML Feed Calendar
All | General | Programming | Shell
20050127 Thursday January 27, 2005

playing around with mice and windows

Updated: 2005/02/03 - it didn't build so well on Linux.
This is a bit of code for Solaris which allows you to:

Build instructions
SolarisLinux (mandrake 10 tested)
cc -v -I/usr/openwin/include -L/usr/openwin/lib -R/usr/openwin/lib -o movemouse movemouse.c -lX11 -lXmu gcc -DLINUX -W -I/usr/X11R6/include -L/usr/X11R6/lib -o movemouse movemouse.c -lX11 -lXmu

The meaning of the -R/usr/openwin/lib for solaris is to set the run-time linker lookup to try the /usr/openwin/lib path for libraries, as part of the symbol resolution step. Otherwise it relies on either the LD_LIBRARY_PATH (It is evil), or the crle path (man crle - it is neat).

For Linux you normally have the /etc/ld.so.conf file, which typically has /usr/X11R6/lib in there (and if you've got qt, probably has /usr/lib/qt3/lib as well). If you want to find out more abou tthis then look at the info/man page for ldconfig.

I have this code for window managers that don't have mouse/window movement shaping hotkeys of their own (e.g. fvwm). It makes the gnome window managers almost useful. It should be portable to other X based OS's.
It comes with the usual preamble - use it at your own risk, if it eats your cat then it's not mine (or Sun's) fault.

#include <alloca.h>
#include <libgen.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#if defined(LINUX)
#include <string.h>
#include <stdint.h>
#endif
#include <sys/types.h>
#include <unistd.h>
#include <X11/X.h>
#include <X11/Xlib.h>

static char *appname;

struct systeminfo {
        int rootx;
        int rooty;
        int width;
        int height;
        int winx;
        int winy;
        Display *display;
        Window rootwin;
        Window undermouse;
        XWindowAttributes childattr;
};

static char *actionhelp();

static void
usage(int exitcode)
{
        (void) printf("usage: %s {<action> [+-]<valx>[%%] [+-]<valy>[%%] }+ \n",
            appname);
        (void) printf("\tif you use +- it is taken as a delta, otherwise it is"
                      " absolute\n");
        (void) printf("Where action is one of %s\n", actionhelp());
        (void) printf("\tFor example %s mm 0 0 would move the mouse to the "
                      "\n\ttop left of the screen\n", appname);
        exit(exitcode);
}

static int
XError(Display *disp, XErrorEvent *code)
{
        char buffer[2000];
        XGetErrorText(disp, code->error_code, buffer, 1999);
        (void) printf("Error: %s\n", buffer);
        return (0);
}

static int isdelta(const char *value) {
        return ((*value == '-') || (*value == '+'));
}

static int isperc(const char *value) {
        return ((strrchr(value, '%') - value) == (strlen(value) - 1));
}

static int transform(const char *val, int start, int maxMetric) {
        int av = atoi(val);
        /*(void) printf("%s %d %d %d\n", val, av, start, maxMetric);*/
        if (isdelta(val) && isperc(val))
                return (start + (int)(maxMetric * av / 100));
        if (isdelta(val))
                return (start + av);
        if (isperc(val))
                return ((int)(maxMetric * av / 100));
        return (av);
}

static void getxy(struct systeminfo *info, const char *xarg,
        const char *yarg, int *xval, int *yval, uintptr_t offx,
        uintptr_t offy) {
        /*LINTED*/
        *xval = transform(xarg, *((int *)((char *)info + offx)),
                isperc(xarg) && isdelta(xarg) ? info->width :
                WidthOfScreen(DefaultScreenOfDisplay(info->display)));
        /*LINTED*/
        *yval = transform(yarg, *((int *)((char *)info + offy)),
                isperc(yarg) && isdelta(yarg) ? info->height :
                HeightOfScreen(DefaultScreenOfDisplay(info->display)));
        /* (void) printf("%d %d\n", *xval, *yval); */
}

static void MoveMouse(struct systeminfo *info, int xarg, int yarg) {
        XWarpPointer(info->display, None, info->rootwin, 0, 0, 0, 0,
                xarg, yarg);
}

static void ResizeWindow(struct systeminfo *info, int xarg, int yarg) {
        XResizeWindow(info->display, info->undermouse, xarg, yarg);
}

static void MoveWindow(struct systeminfo *info, int xarg, int yarg) {
        XMoveWindow(info->display, info->undermouse, xarg, yarg);
}

#define funtostring(FV) #FV, FV

static struct activity {
        char *action;
        char *helpstring;
        void (*function)(struct systeminfo *, int, int);
        uintptr_t offsetx;
        uintptr_t offsety;
} activitylist[] = {
        { "mm", funtostring(MoveMouse),
                offsetof(struct systeminfo, rootx),
                offsetof(struct systeminfo, rooty) },
        { "rw", funtostring(ResizeWindow),
                offsetof(struct systeminfo, width),
                offsetof(struct systeminfo, height) },
        { "mw", funtostring(MoveWindow),
                offsetof(struct systeminfo, winx),
                offsetof(struct systeminfo, winy) },
        { NULL, NULL, NULL }
};

static char *actionhelp(void) {
        static char *buffer = NULL;
        char *stribo;
        struct activity *ack = activitylist;

        stribo = alloca(1024);

        if (buffer != NULL)
                return (buffer);
        buffer = calloc(1, getpagesize());
        while (ack->action != NULL) {
                (void) sprintf(stribo, "%s(%s) ", ack->action, ack->helpstring);
                (void) strcat(buffer, stribo);
                ack++;
        }
        return (buffer);
}

extern Window XmuClientWindow(Display *, Window);

static void InitializeWinfoid(struct systeminfo *winfoid) {
        unsigned int mask;
        winfoid->rootwin = XDefaultRootWindow(winfoid->display);
        XQueryPointer(winfoid->display, winfoid->rootwin,
                &winfoid->rootwin, &winfoid->undermouse,
                &winfoid->rootx, &winfoid->rooty,
                &winfoid->winx, &winfoid->winy, &mask);
        XGetWindowAttributes(winfoid->display, winfoid->undermouse,
                &winfoid->childattr);
        winfoid->winx = winfoid->childattr.x;
        winfoid->winy = winfoid->childattr.y;
        winfoid->undermouse = XmuClientWindow(winfoid->display,
                winfoid->undermouse);
        XGetWindowAttributes(winfoid->display, winfoid->undermouse,
                &winfoid->childattr);
        winfoid->width = winfoid->childattr.width;
        winfoid->height = winfoid->childattr.height;
}

int
main(int argc, char **argv)
{
        struct systeminfo winfoid;
        int atarg;
        int thisx, thisy;

        char *disp;

        appname = basename(strdup(argv[0]));

        XSetErrorHandler(XError);

        if ((argc < 3) || ((argc - 1) % 3)) usage(1);

        disp = XDisplayName(NULL);
        if (disp == NULL) disp = ":0.0";
        winfoid.display = XOpenDisplay(disp);
        if (winfoid.display == NULL) {
                (void) fprintf(stderr, "Can't open display %s\n", disp);
                exit(2);
        }
        InitializeWinfoid(&winfoid);
        /* handle arguments */
        for (atarg = 1; atarg < argc; atarg += 3) {
                struct activity *atac = activitylist;
                while (atac->action != NULL) {
                        if (strncmp(atac->action, argv[atarg], 2) == 0)
                                break;
                        atac++;
                }
                if (atac->action != NULL) {
                        getxy(&winfoid, argv[atarg+1], argv[atarg+2],
                                &thisx, &thisy, atac->offsetx, atac->offsety);
                        atac->function(&winfoid, thisx, thisy);
                }
        }

        XCloseDisplay(winfoid.display);
        return (0);
}
January 27, 2005 05:03 PM GMT Permalink

fuser trickiness

I encountered this one a bit over a year ago while having a conversation with Ed in MPK (or is it a year and a half?). The fuser command is used to list the processes using a file system - fuser /home/bubba would list all the users of /home/bubba; and you can kill them too, using the -k option. So far so good.
What happens, though when you want to do something with the output?

haiiro[64i]~% fuser /home/bubba
/home/bubba:     6780c    6760c    6758c    6756c    6502c    6422c    6404c   6368c    6332c
6331c    6330c    6322c    6308c    6301c    6206c    6081c    5951c    5879c    5756c    5251c
5247c    5201c    5092c    5004c    4992c    4987c    4985c    4982c    4980c    4968c    4952c
4920c    4672c    4080c    4079c    3990c    3989c    3987c    3985c    3983c    3981c    3979c
3975c    3973c    3969c    3963c    3943c    3939c    3937c    3935c    3898c    3896c    3893c
3891c    3882c    3880c    3836c    3834c    3831c    3769c    3726c
it's a bit hard to parse? not so! What you can do is redirect stderr to /dev/null and magic happens
haiiro[64i]~% fuser /home/bubba 2>/dev/null
6781    6760    6758    6756    6502    6422    6404    6368    6332    6331    6330
6322    6308    6301    6206    6081    5951    5879    5756    5251    5247    5201
5092    5004    4992    4987    4985    4982    4980    4968    4952    4920    4672
4080    4079    3990    3989    3987    3985    3983    3981    3979    3975    3973
3969    3963    3943    3939    3937    3935    3898    3896    3893    3891    3882
3880    3836    3834    3831    3769
No parse issues there. Then you can get full process information on each of the processes using a small bit of shell:
haiiro[64i]~% ps -o pid,args -p "$(fuser /home/bubba 2>/dev/null)"
  PID COMMAND
 6206 /usr/openwin/bin/xterm -geom 80x25 -e /bin/zsh
 3943 /usr/lib/evolution/1.4/evolution-alarm-notify --sm-config-prefix /evolution-ala
 3939 nautilus --sm-config-prefix /nautilus-udaGgf/ --sm-client-id 11819cee2200010909
 3935 metacity --sm-save-file 1106677632-2610-3195804027.ms
 3880 /bin/ksh /usr/dt/config/Xsession2.jds
 3834 /usr/dt/bin/sdt_shell -c      unset DT;     DISPLAY=:0;       /usr/dt/bin/dt
:
:
:
Just what the doctor ordered for a sysadmin. January 27, 2005 10:38 AM GMT Permalink