#include /* this is just for fork/exec maybe they should go? */ #include #include #include "nawm.h" #include "bindings.h" #include "inform.h" #ifdef USE_CACHE #include "cache.h" #endif #define XK_MISCELLANY #include #include /* I have no idea what i'm doing with this stuff, here goes nothing */ /* XTestStopInput openwin,xfree86 XTestFakeInput openwin,xfree86 XTestQueryInputSize openwin,xfree86 XTestPressButton openwin,xfree86 XTestMovePointer openwin,xfree86 XTestGetInput openwin,xfree86 XTestPressKey openwin,xfree86 XTestFlush openwin,xfree86 XTestReset openwin,xfree86 relevant docs: /afs/athena/astaff/project/x11r5/src/mit/doc/extensions/xtest1.mm /afs/athena/astaff/project/x11r5/src/mit/extensions/include/xtestext1.h */ #if HAVE_XTEST_EXTENSION #include #include #include #endif extern int current_mode; extern Window current_window; extern Window focus_window; extern BindInfo bind_list; extern unsigned bind_cnt; int screen_shift_x = 0; int screen_shift_y = 0; int marker_x = 0; int marker_y = 0; static void move_all_windows (); #define check_x_coord(x) check_coord(x) #define check_y_coord(x) check_coord(x) int check_coord(def) int def; { if(def == USE_DXMARKER || def == USE_DYMARKER || def == USE_X || def == USE_Y ) { Window w1, w2; int x, y; unsigned int k; int rx, ry; XQueryPointer(dpy, root, &w1, &w2, &rx, &ry, &x, &y, &k); return ((def == USE_X) ? rx : (def == USE_Y) ? ry : (def == USE_DXMARKER) ? rx - marker_x : (def == USE_DYMARKER) ? ry - marker_y : def); } else return((def == USE_MARKERX) ? marker_x : (def == USE_MARKERY) ? marker_y : def ); } void lower_cmd(bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { if (current_window) XLowerWindow(dpy, current_window); } void raise_cmd(bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { if (current_window) XRaiseWindow(dpy, current_window); } void warp_to_cmd(bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { XWarpPointer(dpy, None, root, 0,0,0,0, check_x_coord(bi->data.warpto.x), check_y_coord(bi->data.warpto.y)); } void warp_cmd(bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { XWarpPointer(dpy, None, None, 0,0,0,0, check_x_coord(bi->data.warp.dx), check_y_coord(bi->data.warp.dy)); } void map_cmd(bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { if(!current_window) return; XMapWindow(dpy, current_window); } void unmap_cmd(bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { if(!current_window) return; XUnmapWindow(dpy, current_window); } void find_cmd(bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { current_window = getwindowbyname(bi->data.find.win_name); if (!current_window) { XBell(dpy, 100); return; } } void warp_to_window_cmd(bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { XWindowAttributes attr; if (!current_window) return; deiconify_window(current_window); if (!XGetWindowAttributes(dpy, current_window, &attr)) return; /* Oops, no such window */ if (attr.x+attr.width < 0 || attr.x > DisplayWidth(dpy, screen) || attr.y+attr.height < 0 || attr.y > DisplayHeight(dpy, screen)) { move_all_windows ((DisplayWidth(dpy, screen) - attr.width)/2 - attr.x, (DisplayHeight(dpy, screen) - attr.height)/2 - attr.y, NULL, 0); } XWarpPointer(dpy, None, current_window, 0,0,0,0, attr.width/2, attr.height/2); } void goto_window_cmd(bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { error_mode = BEEP_ON_ERROR; current_window = bi->data.goto_window.window_id; XRaiseWindow(dpy, current_window); warp_to_window_cmd(bi, ev); XSync (dpy, False); error_mode = SPEW_ON_ERROR; } void move_cmd(bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { XWindowAttributes attr; inform_user(5, "move_cmd"); if (!current_window) return; XGetWindowAttributes(dpy, current_window, &attr); XMoveWindow(dpy, current_window, attr.x + check_x_coord(bi->data.move.dx), attr.y + check_y_coord(bi->data.move.dy)); } void move_to_cmd(bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { if (!current_window) return; XMoveWindow(dpy, current_window, check_x_coord(bi->data.moveto.x), check_y_coord(bi->data.moveto.y)); } typedef struct _move_window_stuff { int dx,dy; char *except_list; Window except_one; } move_window_stuff; static void move_one_window (k,d,stuff) cache_key k; cache_data *d; move_window_stuff *stuff; { if ((stuff->except_list && d->name && strstr(stuff->except_list,d->name)) || (stuff->except_one == k)) return; XMoveWindow(dpy, k, d->x + stuff->dx, d->y + stuff->dy); } static void move_all_windows (dx, dy, except_list, except_one) int dx, dy; char* except_list; Window except_one; { if (dx == 0 && dy == 0) return; #ifdef USE_CACHE if (use_cache) { move_window_stuff stuff; stuff.dx = dx; stuff.dy = dy; stuff.except_list = except_list; stuff.except_one = except_one; cache_iter(move_one_window,&stuff); } else #endif USE_CACHE { Window *children; unsigned int numchildren, n; Window rootret; Window parent; char *windowname=NULL; XWindowAttributes attr; if(!XQueryTree (dpy, root, &rootret, &parent, &children, &numchildren)) return; for (n = 0; n < numchildren; n++) { if (children[n] == except_one) continue; if (except_list && XFetchName(dpy,children[n],&windowname) && strstr(except_list,windowname)) { if (windowname) XFree(windowname); windowname=NULL; continue; } else { if (windowname) XFree(windowname); windowname=NULL; } XGetWindowAttributes(dpy, children[n], &attr); XMoveWindow(dpy, children[n], attr.x + dx, attr.y + dy); } XFree ((char *) children); } screen_shift_x -= dx; screen_shift_y -= dy; } void screen_cmd (bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { move_all_windows (-bi->data.screen.dx, -bi->data.screen.dy, NULL, (Window) 0); } void screen_to_cmd (bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { move_all_windows (screen_shift_x - bi->data.screento.x, screen_shift_y - bi->data.screento.y, NULL, (Window) 0); } void screen_except_cmd (bi, ev) BindInfo bi; XEvent *ev; { move_all_windows (-bi->data.screen_except.dx, -bi->data.screen_except.dy, bi->data.screen_except.except_list, (Window)0); } void screen_to_except_cmd (bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { move_all_windows (screen_shift_x - bi->data.screento_except.x, screen_shift_y - bi->data.screento_except.y, bi->data.screento_except.except_list, (Window) 0); } void carry_cmd (bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { move_all_windows (-bi->data.carry.dx, -bi->data.carry.dy, NULL, current_window); } void carry_to_cmd (bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { move_all_windows (screen_shift_x - bi->data.carryto.x, screen_shift_y - bi->data.carryto.y, NULL, current_window); } void size_cmd(bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { int w, h; int use_dx; int use_dy; XWindowAttributes attr; if (!current_window) return; use_dx = check_x_coord(bi->data.size.dx); use_dy = check_y_coord(bi->data.size.dy); XGetWindowAttributes(dpy, current_window, &attr); if(use_dx < 0 && attr.width <= -use_dx ) w = attr.width; else w = attr.width + use_dx; if(use_dy < 0 && attr.height <= -use_dy ) h = attr.height; else h = attr.height + use_dy; XResizeWindow(dpy, current_window, w,h); } void size_to_cmd(bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { if (!current_window) return; XResizeWindow(dpy, current_window, bi->data.sizeto.x, bi->data.sizeto.y); } void set_mode_cmd (bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { int new; inform_user(5, "set_mode_cmd"); new = (current_mode == bi->data.setmode.mode) ? DEFAULT_MODE : bi->data.setmode.mode; set_mode (new); } void iconify_cmd(bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { if (current_window) { XUnmapWindow(dpy, current_window); make_icon(current_window); } } void deiconify_cmd(bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { if (current_window) { deiconify_icon(current_window); } } static void prev_next_cmd(dir) int dir; { Window rootret; Window parent; Window *children; int numchildren; XWindowAttributes attr; int me, found, n; if(!XQueryTree (dpy, root, &rootret, &parent, &children, &numchildren)) return; for (n = 0; n < numchildren && children[n] != current_window; n++); me = n; found = (n < numchildren); do { n += dir; if (n >= numchildren) n = 0; if (n < 0) n = numchildren - 1; if (found) { if (n == me) break; } else { found = 1; me = n; } XGetWindowAttributes(dpy, children[n], &attr); if (attr.map_state != IsUnmapped) { current_window = children[n]; break; } } while (1); XFree ((char *) children); } void prev_cmd (bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { prev_next_cmd(-1); } void next_cmd (bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { prev_next_cmd(1); } void bell_cmd(bi, ev) BindInfo bi; XEvent *ev; { XBell(dpy, 100); } void set_marker_cmd (bi, ev) BindInfo bi; XEvent *ev; { Window w1, w2; int x, y; unsigned int k; XQueryPointer(dpy, root, &w1, &w2, &marker_x, &marker_y, &x, &y, &k); } void exch_mark_cmd(bi, ev) BindInfo bi; XEvent *ev; { Window w1, w2; int x, y; int oldx, oldy; unsigned int k; oldx = marker_x; oldy = marker_y; XQueryPointer(dpy, root, &w1, &w2, &marker_x, &marker_y, &x, &y, &k); XWarpPointer(dpy, None, root, 0,0,0,0, oldx, oldy); } void set_x_cmd( bi, ev) BindInfo bi; XEvent *ev; { marker_x = check_x_coord(bi->data.setx.x); } void set_y_cmd( bi, ev) BindInfo bi; XEvent *ev; { marker_y = check_y_coord(bi->data.sety.y); } void kill_cmd(bi, ev) BindInfo bi; XEvent *ev; { XKillClient(dpy, current_window); } void event_window_cmd (bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { current_window = focus_window; } void bind_cmd (bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { BindInfo new, bnd; BindInfo_S key; unsigned int i; if (!current_window) { XBell(dpy, 100); return; } ungrab_things(); get_key_combo (&key); new = NULL; for(i = 0, bnd = bind_list; i < bind_cnt; bnd++, i++) if ((bnd->type == key.type) && (bnd->whatmode == ANY_MODE || bnd->whatmode == current_mode) && (bnd->modifiers == key.modifiers) && ((bnd->type == KeyPress) ? (bnd->keycode == key.keycode) : (bnd->button == key.button)) && (bnd->func == goto_window_cmd)) { new = bnd; break; } if (!new) { new = realloc_binding(); new->func = goto_window_cmd; new->whatmode = bi->whatmode; new->type = key.type; new->keycode = key.keycode; new->modifiers = key.modifiers; new->button = key.button; } new->data.goto_window.window_id = current_window; grab_things(); } unbind_cmd (bi, ev) /*ARGSUSED*/ BindInfo bi; XEvent *ev; { XBell(dpy, 100); } get_key_combo (bi) BindInfo bi; { XEvent ev; KeySym ksym; int done = 0; Window win; int x, y; int ig_int; unsigned int ig_uint; Window ig_w; XSizeHints hints; XQueryPointer (dpy, root, &ig_w, &ig_w, &x, &y, &ig_int, &ig_int, &ig_uint); hints.x = x-5; hints.y = y-5; hints.width = 10; hints.height = 10; hints.flags = USPosition | USSize; win = XCreateSimpleWindow (dpy, root, hints.x, hints.y, hints.width, hints.height, 0, 0, 0); XSelectInput (dpy, win, KeyPressMask | ButtonPressMask | ExposureMask | ButtonReleaseMask); XSetNormalHints(dpy, win, &hints); XMapWindow(dpy, win); while (!done) { XNextEvent (dpy, &ev); switch (ev.type) { case Expose: XGrabPointer (dpy, win, False, ButtonPressMask | ButtonReleaseMask, GrabModeAsync, GrabModeAsync, win, None, CurrentTime); break; case KeyPress: ksym = keycode_to_keysym(ev.xkey.keycode); if ((ksym < XK_Shift_L || /* Trust me, they're all in here. */ ksym > XK_Hyper_R) /* Hey, this is *sample* code from O'Reilly.. */ && (ksym != XK_Multi_key)) { /* ...Well, except for this one... */ bi->type = KeyPress; bi->keycode = ev.xkey.keycode; bi->modifiers = ev.xkey.state; done = 1; } break; case ButtonPress: bi->type = ButtonPress; bi->button = ev.xbutton.button; bi->modifiers = ev.xbutton.state; done = 1; break; } } XUngrabPointer (dpy, CurrentTime); XDestroyWindow (dpy, win); } void grab_pointer_cmd (bi, ev) BindInfo bi; XEvent *ev; { inform_user(5, "grab_pointer_cmd"); if(current_window) XGrabPointer (dpy, root, False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); } void ungrab_pointer_cmd (bi, ev) BindInfo bi; XEvent *ev; { inform_user(5, "ungrab_pointer_cmd"); XUngrabPointer(dpy, CurrentTime); } #if HAVE_XTEST_EXTENSION static void new_mouseclick_cmd(bi, ev) BindInfo bi; XEvent *ev; { int destx = check_x_coord(bi->data.mouseclick.x); int desty = check_y_coord(bi->data.mouseclick.y); int delay = 10; Window w1, w2; int x, y; unsigned int k; int rx, ry; XQueryPointer(dpy, root, &w1, &w2, &rx, &ry, &x, &y, &k); /* set_modifier_state(ev->state, bi->data.mouseclick.state); */ XTestMovePointer(dpy, 0, &delay, &destx,&desty, 1); XTestPressButton(dpy, 0, 10, bi->data.mouseclick.button, XTestSTROKE); XTestMovePointer(dpy, 0, &delay, &x,&y, 1); /* set_modifier_stat(bi->data.mouseclick.state, ev->state); */ XTestFlush(dpy); } static void set_modifier_state(old,new) unsigned int old,new; { /* this function can't be properly implemented */ } #endif static void old_mouseclick_cmd(bi, ev) BindInfo bi; XEvent *ev; { XEvent send; Window junk, cwin, *list; XWindowAttributes attr; unsigned int length; int i, x, y, buttonMask=0; XGrabServer(dpy); if(!XQueryTree(dpy, RootWindow(dpy, screen), &junk, &junk, &list, &length)) return; x = check_x_coord(bi->data.mouseclick.x); y = check_y_coord(bi->data.mouseclick.y); for (i = length - 1; i >= 0; i--) { if (!XGetWindowAttributes(dpy, list[i], &attr)) continue ; if (x > attr.x && x < (attr.x + attr.width) && y > attr.y && y < (attr.y + attr.height) && attr.map_state == IsViewable) { break; } } if (i >= 0) { cwin = nawmClientWindow(dpy, list[i]); memcpy(&send, ev, sizeof(XEvent)); send.type = ButtonPress; send.xbutton.window = cwin; send.xbutton.subwindow = None; send.xbutton.x_root = x; send.xbutton.y_root = y; send.xbutton.x = x - attr.x; send.xbutton.y = y - attr.y; switch(bi->data.mouseclick.button) { case 1: send.xbutton.button = Button1; buttonMask = Button1Mask; break; case 2: send.xbutton.button = Button2; buttonMask = Button2Mask; break; case 3: send.xbutton.button = Button3; buttonMask = Button3Mask; break; case 4: send.xbutton.button = Button4; buttonMask = Button4Mask; break; case 5: send.xbutton.button = Button5; buttonMask = Button5Mask; break; } send.xbutton.state = bi->data.mouseclick.modifiers; XSendEvent(dpy, cwin, True, ButtonPressMask, &send); send.type = ButtonRelease; send.xbutton.time += 10; send.xbutton.state |= buttonMask; /* button being released is down right? */ XSendEvent(dpy, cwin, True, ButtonReleaseMask, &send); } XFree((char *)list); XUngrabServer(dpy); } void mouseclick_cmd(bi, ev) BindInfo bi; XEvent *ev; { #if HAVE_XTEST_EXTENSION if (use_xtest_extension) new_mouseclick_cmd(bi,ev); else #endif old_mouseclick_cmd(bi,ev); } void break_cmd(bi, env) BindInfo bi; XEvent *env; { inform_user(5, "break_cmd"); XSetInputFocus(dpy, PointerRoot, None, CurrentTime); } /* XXX This doesn't avoid zombie's yet, I'm leaning towards giving up and using system() for simplicity XXX well now if you #define DOUBLE_FORK it avoids zombies (?) but that means it will background itself when it does an exec argh, I'm really leaning towards using system(), but then the user has to remember to use & in his commands or else he'll lock up his nawm. */ #define DOUBLE_FORK 1 /* This seems to work, and it's half-way reasonable */ void system_cmd(bi,env) BindInfo bi; XEvent *env; { inform_user(5, "system_cmd"); switch (fork()) { case -1: /* error */ perror("nawm: fork"); return; case 0: /* child */ execl("/bin/sh", "/bin/sh", "-c", bi->data.system.cmd, (char*)0); perror("nawm: exec"); exit(2); default: /* parent */ #if DOUBLE_FORK switch (fork()) { case -1: /* error */ perror("nawm: second fork (will cause zombie)"); return; case 0: /* child (new nawm) */ return; default: /* parent (old nawm) */ exit(0); } #endif } } void exit_cmd(bi,env) BindInfo bi; XEvent *env; { inform_user(5, "exit_cmd"); exit(0); abort(); return; }