xlax2.4/000075000010170000036000000000001104441702100121415ustar00finehead00000000000002xlax2.4/Imakefile000064000010170000036000000004211104441702100137500ustar00finehead00000000000002#Imakefile for xlax # EXTRA_LOAD_FLAGS = -Bstatic # CDEBUGFLAGS = -g # DEFINES = -DDEBUG DEPLIBS = XawClientDepLibs LOCAL_LIBRARIES = XawClientLibs SRCS = xlax.c OBJS = xlax.o ComplexProgramTarget(xlax) xlax2.4/mkxlax000075000010170000036000000071341104441702100134000ustar00finehead00000000000002#!/usr/bin/perl #it doesn't make senes to use both -wrapx and -wrapy, and you always use # the opposite axis in the -wrapd? option if ($#ARGV == -1) { &usage; exit(0); } if (-e "$ENV{'HOME'}/.mkxlax") { &loadconfig("$ENV{'HOME'}/.mkxlax"); } $opts{"group"}="mkxlax"; $opts{"x"}=0; $opts{"y"}=0; $opts{"dx"}=0; $opts{"dy"}=0; $opts{"wrapx"}=0; $opts{"wrapy"}=0; $opts{"wrapdx"}=0; $opts{"wrapdy"}=0; $opts{"termsize"}="80x24"; $opts{"termopts"}=""; $opts{"geometry"}="+2-2"; @ARGV = &parse_option_array(@ARGV); $xlax_group=$opts{"group"}; $ix=$opts{"x"}; $iy=$opts{"y"}; $dx=$opts{"dx"}; $dy=$opts{"dy"}; $wrapx=$opts{"wrapx"}; $wrapy=$opts{"wrapy"}; $wrapdx=$opts{"wrapdx"}; $wrapdy=$opts{"wrapdy"}; $termsize=$opts{"termsize"}; $termopts=$opts{"termopts"}; if ($dx == 0 && $dy == 0) { $dx=40; $dy=80; if ($wrapx == 0 && $wrapy == 0) { $wrapy=750; $wrapdx=200; } } $x=$ix; $y=$iy; for ($i=0; $i<=$#ARGV; ++$i) { system("xterm -geometry $termsize+$x+$y -name \"$xlax_group:$ARGV[$i]\" -xrm 'XTerm*allowSendEvents: true' $termopts &"); sleep(1); $x+=$dx; if ($wrapx && $x>$wrapx) { $x=$ix; $y+=$wrapdy; } $y+=$dy; if ($wrapy && $y>$wrapy) { $y=$iy; $x+=$wrapdx; } } sleep(2); $x=(0)+2; system("xlax -geometry $opts{'geometry'} -prefix $xlax_group: -find &"); # # END OF MAIN # sub loadconfig { my $file=shift(@_); my $prev=""; my $lay=""; if (! open (CONF,$file)) { print STDERR "Can't open config file $file: $!\n"; return; } while() { next if (/^[ \t]*#/); #skip comment lines next if (/^[ \t]*$/); #skip blank lines chomp; if (/\\ *$/) { $cont=1; s/\\ *$//; } else { $cont=0; } if ($prev ne "") { $layout{$prev} .= " $_"; $prev=""; } else { @words=split(' '); if ($words[0] =~ /:$/) { $lay=shift(@words); $lay =~ s/:$//; $layout{$lay} = join(" ",@words); } else { print STDERR "Warning: bad config file!\n"; } } if ($cont) { $prev=$lay; } } close($file); } sub parse_option_array { my @args=@_; my $o; my $lname; while (substr($args[0],0,1) eq "-") { $o=shift(@args); last if ($o eq "--"); $o=substr($o,1); if ($o eq "layout") { $lname=shift(@args); if (defined($layout{$lname})) { my @tmp=split(' ',$layout{$lname}); push (@args, &parse_option_array(@tmp)); } next; } if (! defined($opts{$o})) { print "unknown option: -$o\n"; &usage; exit(1); } $opts{$o}=shift(@args); } return(@args); } sub usage { print "Usage: mkxlax [options] string [more strings]\n"; print "Options:\n"; print " -group name the prefix to use in xlax\n"; print " -x N the initial x position of first window\n"; print " -y N the initial x position of first window\n"; print " -dx N the offset in x for additional windows\n"; print " -dy N the offset in y for additional windows\n"; print " -wrapx N wrap x back to initial value when if >= N\n"; print " -wrapy N wrap y back to initial value when if >= N\n"; print " -wrapdx N when wrapping (either x or y) add N to x\n"; print " -wrapdy N when wrapping (either x or y) add N to y\n"; print " -termsize WxH size of the terminals to create\n"; print " -termopts options additional xterm options\n"; print " -geometry geom X11 geometry string for xlax window\n"; print " -- stop option processing here\n"; print " (in case a window string needs to start with a dash)\n"; } xlax2.4/xlax.c000064000010170000036000000724531104441702100132750ustar00finehead00000000000002/* * Copyright © 1992 by Frank Adelstein. All Rights Reserved. * Version 2.0 modifications Copyright © 2007 by Thomas A. Fine. * All Rights Reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the authors name not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. The author makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* * Neat program to send typed text to multiple windows. * * by Frank Adelstein * */ #include "xlax.h" #include "vroot.h" XtAppContext Appcon; Widget Toplevel, Popup; GC drawGC, xorGC; Windows_t Windows[50]; XKeyEvent tmpevents[MAXEVENTS]; int tmpeventindex; int tmpwindex; int WindowIndex; char *prefix="xlax:"; char findname[16]; void DoNothing() { /* stupid, but used to override button click default actions */ return; } int ErrorHandler(mydisp, myerr) Display *mydisp; XErrorEvent *myerr; { char msg[80]; XGetErrorText(mydisp, myerr->error_code, msg, 80); (void) fprintf(stderr, "%s\n", msg); if (myerr->error_code == BadWindow) { fprintf(stderr, "Removing window %d\n", myerr->resourceid); Remove_Window(myerr->resourceid); return 0; } else { (void) fprintf(stderr, "Fatal!! We got errors: error [%d] request [%d] minor [%d]\n", myerr->error_code, myerr->request_code, myerr->minor_code); exit(1); } } int main (argc, argv) int argc; char **argv; { int i, find=0; void DoNothing(); static XtActionsRec TextActions[] = { {"DoNothing", DoNothing}, {NULL, NULL} }; /* xlax [-find] [-prefix name] */ /* initialize toolkit */ Toplevel = XtAppInitialize (&Appcon, TITLE, NULL, 0, &argc, argv, NULL, NULL, 0); XtAppAddActions(Appcon, TextActions, XtNumber(TextActions)); XSetErrorHandler(ErrorHandler); if (argc > 1) { for (i=1; i=argc) { fprintf(stderr,"usage: %s [-prefix string] [-find]\n",argv[0]); exit(0); } prefix=argv[++i]; } else { fprintf(stderr,"usage: %s [-prefix string] [-find]\n",argv[0]); exit(0); } } } /* do all the dirty work */ SetupInterface(find); /* sit back and process events */ XtAppMainLoop(Appcon); exit(0); } void SetupInterface(dofind) int dofind; { int cnt; Arg args[15]; Widget Frame, thing, find, quit, sendit, paste, view, draw, popfoo, poplabel, popstring, popclear, popcancel, popok; Display *display; XtTranslations text_trans; static String text_trans_str = ": DoNothing() \n\ : DoNothing() \n\ : DoNothing() \n\ Return: insert-string(\"^M\") \n\ BackSpace: insert-string(\"^H\") \n\ Delete: insert-string(\"^?\")"; /* create a frame widget to hold things */ cnt = 0; Frame = XtCreateManagedWidget ("Frame", formWidgetClass, Toplevel, args, cnt); XtAddEventHandler (Frame, KeyPressMask, False, keyboardCB, NULL); cnt = 0; XtSetArg (args[cnt], XtNborder, 2); cnt++; XtSetArg (args[cnt], XtNlabel, "Add Windows"); cnt++; thing = XtCreateManagedWidget ("addbutton", commandWidgetClass, Frame, args, cnt); XtAddCallback (thing, XtNcallback, selectCB, NULL); strcpy(findname,"Find "); strlcpy(findname+5,prefix,11); if (strlen(prefix)<6) { for (cnt=5+strlen(prefix); cnt<11; ++cnt) { findname[cnt]=' '; } findname[cnt]='\0'; } cnt = 0; XtSetArg (args[cnt], XtNborder, 2); cnt++; XtSetArg (args[cnt], XtNfromVert, thing); cnt++; XtSetArg (args[cnt], XtNlabel, findname); cnt++; find = XtCreateManagedWidget ("findbutton", commandWidgetClass, Frame, args, cnt); XtAddCallback (find, XtNcallback, findCB, NULL); cnt = 0; XtSetArg (args[cnt], XtNborder, 2); cnt++; XtSetArg (args[cnt], XtNfromVert, find); cnt++; XtSetArg (args[cnt], XtNlabel, "Send String"); cnt++; sendit = XtCreateManagedWidget ("senditbutton", commandWidgetClass, Frame, args, cnt); XtAddCallback (sendit, XtNcallback, senditCB, NULL); cnt = 0; XtSetArg (args[cnt], XtNborder, 2); cnt++; XtSetArg (args[cnt], XtNlabel, "Paste"); cnt++; XtSetArg (args[cnt], XtNfromVert, sendit); cnt++; paste = XtCreateManagedWidget ("pastebutton", commandWidgetClass, Frame, args, cnt); XtAddCallback (paste, XtNcallback, pasteCB, NULL); cnt = 0; XtSetArg (args[cnt], XtNborder, 2); cnt++; XtSetArg (args[cnt], XtNlabel, "Kill Window"); cnt++; XtSetArg (args[cnt], XtNfromVert, paste); cnt++; thing = XtCreateManagedWidget ("killbutton", commandWidgetClass, Frame, args, cnt); XtAddCallback (thing, XtNcallback, killCB, NULL); cnt = 0; XtSetArg (args[cnt], XtNborder, 2); cnt++; XtSetArg (args[cnt], XtNfromVert, thing); cnt++; XtSetArg (args[cnt], XtNlabel, "Quit"); cnt++; quit = XtCreateManagedWidget ("quitbutton", commandWidgetClass, Frame, args, cnt); XtAddCallback (quit, XtNcallback, quitCB, NULL); /* create a viewport widget and a frame widget to hold things */ cnt = 0; XtSetArg (args[cnt], XtNfromHoriz, find); cnt++; XtSetArg (args[cnt], XtNborder, 2); cnt++; XtSetArg(args[cnt], XtNwidth, 400); cnt++; XtSetArg(args[cnt], XtNheight, 150); cnt++; XtSetArg(args[cnt], XtNallowHoriz, True); cnt++; XtSetArg(args[cnt], XtNallowVert, True); cnt++; view = XtCreateManagedWidget("View", viewportWidgetClass, Frame, args, cnt); /* I don't understand why I need to do this, but...*/ cnt = 0; XtSetArg(args[cnt], XtNwidth, 10); cnt++; XtSetArg(args[cnt], XtNheight, 10); cnt++; XtSetValues(XtNameToWidget(Toplevel, "*clip"), args, cnt); cnt = 0; XtSetArg (args[cnt], XtNborder, 2); cnt++; XtSetArg(args[cnt], XtNwidth, 200); cnt++; XtSetArg(args[cnt], XtNheight, 150); cnt++; draw = XtCreateWidget ("drawingarea", formWidgetClass, view, args, cnt); /* popup for entering sendstrings */ cnt = 0; XtSetArg (args[cnt], XtNtitle, "Set send string"); cnt++; XtSetArg (args[cnt], XtNiconName, "Set send string"); cnt++; Popup = XtCreatePopupShell("sendstring", topLevelShellWidgetClass, Toplevel, args, cnt); cnt = 0; XtSetArg (args[cnt], XtNborder, 2); cnt++; XtSetArg (args[cnt], XtNwidth, 200); cnt++; XtSetArg(args[cnt], XtNheight, 150); cnt++; popfoo = XtCreateManagedWidget ("popfoo", formWidgetClass, Popup, args, cnt); cnt = 0; XtSetArg (args[cnt], XtNborder, 2); cnt++; XtSetArg (args[cnt], XtNborderWidth, 0); cnt++; XtSetArg (args[cnt], XtNwidth, 200); cnt++; poplabel = XtCreateManagedWidget ("poplabel", labelWidgetClass, popfoo, args, cnt); cnt = 0; XtSetArg (args[cnt], XtNborder, 2); cnt++; XtSetArg (args[cnt], XtNwidth, 200); cnt++; XtSetArg (args[cnt], XtNfromVert, poplabel); cnt++; XtSetArg (args[cnt], XtNeditType, XawtextEdit); cnt++; popstring = XtCreateManagedWidget ("sendtext", asciiTextWidgetClass, popfoo, args, cnt); text_trans = XtParseTranslationTable(text_trans_str); XtOverrideTranslations(popstring, text_trans); XtAddEventHandler (popstring, KeyPressMask, False, stringinputCB, NULL); cnt = 0; XtSetArg (args[cnt], XtNborder, 2); cnt++; XtSetArg (args[cnt], XtNfromVert, popstring); cnt++; XtSetArg (args[cnt], XtNlabel, "Clear"); cnt++; popclear = XtCreateManagedWidget ("clearbutton", commandWidgetClass, popfoo, args, cnt); XtAddCallback (popclear, XtNcallback, clearCB, NULL); cnt = 0; XtSetArg (args[cnt], XtNborder, 2); cnt++; XtSetArg (args[cnt], XtNfromVert, popstring); cnt++; XtSetArg (args[cnt], XtNfromHoriz, popclear); cnt++; XtSetArg (args[cnt], XtNlabel, "Cancel"); cnt++; popcancel = XtCreateManagedWidget ("cancelbutton", commandWidgetClass, popfoo, args, cnt); XtAddCallback (popcancel, XtNcallback, cancelCB, NULL); cnt = 0; XtSetArg (args[cnt], XtNborder, 2); cnt++; XtSetArg (args[cnt], XtNfromVert, popstring); cnt++; XtSetArg (args[cnt], XtNfromHoriz, popcancel); cnt++; XtSetArg (args[cnt], XtNlabel, "OK"); cnt++; popok = XtCreateManagedWidget ("okbutton", commandWidgetClass, popfoo, args, cnt); XtAddCallback (popok, XtNcallback, okCB, NULL); XtRealizeWidget (Toplevel); XtRealizeWidget (Popup); /* set up keyboard mappings */ display = XtDisplay(find); BuildCharToKeyMap(display); if (dofind) { findCB(find,NULL,NULL); } return; } /* * Routine to let user select a window using the mouse * (taken from dsimple.c from xwd) */ Window Select_Window(dpy) Display *dpy; { int status; Cursor cursor; XEvent event; Window target_win = None, root = RootWindow(dpy,DefaultScreen(dpy)); int buttons = 0; /* Make the target cursor */ cursor = XCreateFontCursor(dpy, XC_crosshair); /* Grab the pointer using target cursor, letting it room all over */ status = XGrabPointer(dpy, root, False, ButtonPressMask|ButtonReleaseMask, GrabModeSync, GrabModeAsync, root, cursor, CurrentTime); if (status != GrabSuccess) { fprintf(stderr, "Can't grab the mouse."); exit (2); } /* Let the user select a window... */ while ((target_win == None) || (buttons != 0)) { /* allow one more event */ XAllowEvents(dpy, SyncPointer, CurrentTime); XWindowEvent(dpy, root, ButtonPressMask|ButtonReleaseMask, &event); switch (event.type) { case ButtonPress: if (target_win == None) { target_win = event.xbutton.subwindow; /* window selected */ if (target_win == None) { fprintf(stderr, "target win = None\n"); target_win = root; } } buttons++; break; case ButtonRelease: if (buttons > 0) /* there may have been some down before we started */ buttons--; break; } } XUngrabPointer(dpy, CurrentTime); /* Done with pointer */ return(target_win); } void findCB (w,client_data, call_data) Widget w; caddr_t client_data; caddr_t call_data; { Display *dpy = XtDisplay(w); Window root = RootWindow(dpy,DefaultScreen(dpy)); int cnt; Arg args[15]; cnt = 0; XtSetArg (args[cnt], XtNlabel, "Searching..."); cnt++; XtSetValues(w, args, cnt); Find_Xlax (dpy, root); cnt = 0; XtSetArg (args[cnt], XtNlabel, findname); cnt++; XtSetValues(w, args, cnt); } void Find_Xlax (dpy, top) Display *dpy; Window top; { Window *children, dummy; unsigned int nchildren; int i, x; Window w=0; XClassHint class_hint; if (XGetClassHint(dpy, top, &class_hint)) { if (strncmp(class_hint.res_name,prefix,strlen(prefix))==0) { /* found one, see if we have it yet. If not, parse sendstring and add */ for (x = 0; x < WindowIndex; x++) { if (Windows[x].wind == top) { break; } } if (x>=WindowIndex) { /* not found, add it */ Add_Window(dpy,top,class_hint.res_name); /* fprintf(stderr, "Adding window %d\n", top); */ } /* and don't bother searching children? */ return; } } if (!XQueryTree(dpy, top, &dummy, &dummy, &children, &nchildren)) return; for (i=0; i"); cnt++; XtSetArg (args[cnt], XtNfromVert, (WindowIndex)?Windows[WindowIndex - 1].text:NULL); cnt++; XtSetArg (args[cnt], XtNfromHoriz, Windows[WindowIndex].button); cnt++; XtSetArg (args[cnt], XtNtop, XtChainTop); cnt++; XtSetArg (args[cnt], XtNbottom, XtChainTop); cnt++; XtSetArg (args[cnt], XtNleft, XtChainLeft); cnt++; XtSetArg (args[cnt], XtNright, XtChainLeft); cnt++; XtSetArg (args[cnt], XtNwidth, 190); cnt++; XtSetArg (args[cnt], XtNheight, 20); cnt++; Windows[WindowIndex].text = XtCreateManagedWidget ("toggletext", labelWidgetClass, frame, args, cnt); XtAddCallback (Windows[WindowIndex].button, XtNcallback, toggleCB, (XtPointer *) WindowIndex); XtAddEventHandler (Windows[WindowIndex].text, ButtonPressMask, False, togglestringCB, (XtPointer *) WindowIndex); XtUnmanageChild(frame); XtManageChild(frame); Windows[WindowIndex].wind = w; Windows[WindowIndex].eventindex = 0; if (hint) { /* only preset the string if it is not zero length */ if (*(hint+strlen(prefix))) { presetString(dpy,WindowIndex,hint+strlen(prefix)); } } Windows[WindowIndex++].active = 1; } int Remove_Window(w) Window w; { Widget frame; int x, length, removed=0; Arg args[10]; int cnt; /* check to see if window is in our list */ for (x = 0; x < WindowIndex; x++) { if (Windows[x].wind == w) { /* remove it from our list then */ XtDestroyWidget(Windows[x].button); XtDestroyWidget(Windows[x].text); frame = XtNameToWidget (Toplevel, "*drawingarea"); if (x+1 < WindowIndex) { cnt = 0; XtSetArg(args[cnt], XtNfromVert, (x) ? Windows[x-1].button : NULL); cnt++; XtSetValues(Windows[x+1].button, args, cnt); cnt = 0; XtSetArg(args[cnt], XtNfromVert, (x) ? Windows[x-1].text : NULL); cnt++; XtSetValues(Windows[x+1].text, args, cnt); length = sizeof(Windows_t) * (WindowIndex-x-1); bcopy(&Windows[x+1], &Windows[x], length); } WindowIndex--; XtUnmanageChild(frame); XtManageChild(frame); removed=1; break; } } return(removed); } void killCB (w, client_data, call_data) Widget w; caddr_t client_data; caddr_t call_data; { Display *dpy; Window target; Widget frame; int x, length; Arg args[10]; int cnt; dpy = XtDisplay(w); /* get the selection */ target = Select_Window(XtDisplay(w)); /* check to see if it is us, in one of the client control toggles */ /* doesn't work ... for (x = 0; x < WindowIndex; x++) { fprintf(stderr,"t=%d, butt=%d, text=%d\n", target, XtWindow(Windows[x].button), XtWindow(Windows[x].text)); if (target == XtWindow(Windows[x].button)) { Remove_Window(Windows[x].wind); return; } if (target == XtWindow(Windows[x].text)) { Remove_Window(Windows[x].wind); return; } } */ /* tell me what that really means */ target = XmuClientWindow(dpy, target); if (target == XmuClientWindow(dpy, XtWindow(Toplevel))) { /* it's us.. nothing else to do */ return; } /* otherwise see if that window is in our list */ Remove_Window(target); } void keyboardCB (w, client_data, event) Widget w; caddr_t client_data; XKeyEvent *event; { int x; /* send the keys to every active window that's been selected */ for (x = 0; x < WindowIndex; x++) { if (Windows[x].active == 1) { event->window = Windows[x].wind; XSendEvent(XtDisplay(w), Windows[x].wind, True, KeyPressMask, (XEvent *) event); } } return; } void presetString (dpy,wi,str) Display *dpy; int wi; char *str; { int i; long m; Window root = RootWindow(dpy,DefaultScreen(dpy)); Arg args[10]; int cnt; if (strlen(str) >= MAXEVENTS) { fprintf(stderr,"Warning: preset string %s will be truncated!\n",str); } for (i=0; i=0; --m) { evt.state=states[m]; len=XLookupString(&evt, out, 32, NULL, NULL); if (len == 1) { kcmap[out[0]] = i; modmap[out[0]] = states[m]; } } } } KeyCode CharToKeycodeMod(disp, c, m) Display *disp; unsigned char c; long *m; { KeySym ks, ksr; KeyCode kc; XKeyEvent evt; long mr, len; char str[2], out[32]; str[0]=c; str[1]='\0'; evt.type=2; evt.serial=1; evt.send_event=0; evt.display=disp; /* the next two values are not "correct" but seem to work */ evt.window=0; evt.root=0; evt.subwindow=0; evt.x=0; evt.y=0; evt.x_root=0; evt.y_root=0; evt.same_screen=1; if (c < 32) { str[0]+=64; /* Assume keysym is same as character. This seems to be true, but it seems like the wrong approach. It does work better than the older broken method */ ks=c; kc=XKeysymToKeycode(disp,ks); evt.keycode=kc; evt.state=0; len=XLookupString(&evt, out, 32, NULL, NULL); if (len == 1 && out[0] == str[0]) { *m = ControlMask; return(kc); } evt.keycode=kc; evt.state=ShiftMask; len=XLookupString(&evt, out, 32, NULL, NULL); if (len == 1 && out[0] == str[0]) { *m = ShiftMask | ControlMask; return(kc); } fprintf(stderr, "Didn't resolve keycode! (c=%d, ks=%d,kc=%d\n",c,ks,kc); *m = ControlMask; return(0); } else if (c>127) { fprintf(stderr, "Didn't resolve keycode! (c=%d, ks=%d,kc=%d\n",c,ks,kc); *m = 0; return(0); } else { ks=c; kc=XKeysymToKeycode(disp,ks); evt.keycode=kc; evt.state=0; len=XLookupString(&evt, out, 32, NULL, NULL); if (len == 1 && out[0] == c) { *m = 0; return(kc); } evt.keycode=kc; evt.state=ShiftMask; len=XLookupString(&evt, out, 32, NULL, NULL); if (len == 1 && out[0] == c) { *m = ShiftMask; return(kc); } fprintf(stderr, "Didn't resolve keycode! (c=%d, ks=%d,kc=%d\n",c,ks,kc); *m = 0; return(0); } } KeyCode _old_CharToKeycodeMod(disp, c, m) Display *disp; unsigned char c; long *m; { KeySym ks, ksr; KeyCode kc; XKeyEvent evt; long mr, len; char str[2], out[32]; str[0]=c; str[1]='\0'; evt.type=2; evt.serial=1; evt.send_event=0; evt.display=disp; /* the next two values are not "correct" but seem to work */ evt.window=0; evt.root=0; evt.subwindow=0; evt.x=0; evt.y=0; evt.x_root=0; evt.y_root=0; evt.same_screen=1; if (c < 32) { str[0]+=64; /* This was wrong. This function converts from the string keysym name, not the character string. So "A" works because the name and character are the same, but ":" doesn't, because the name is "colon". XStringToKeysym can only look up "colon" */ ks=XStringToKeysym(str); kc=XKeysymToKeycode(disp,ks); evt.keycode=kc; evt.state=0; len=XLookupString(&evt, out, 32, NULL, NULL); if (len == 1 && out[0] == str[0]) { *m = ControlMask; return(kc); } evt.keycode=kc; evt.state=ShiftMask; len=XLookupString(&evt, out, 32, NULL, NULL); if (len == 1 && out[0] == str[0]) { *m = ShiftMask | ControlMask; return(kc); } fprintf(stderr, "Didn't resolve keycode! (c=%d, ks=%d,kc=%d\n",c,ks,kc); *m = ControlMask; return(0); } else { ks=XStringToKeysym(str); kc=XKeysymToKeycode(disp,ks); evt.keycode=kc; evt.state=0; len=XLookupString(&evt, out, 32, NULL, NULL); if (len == 1 && out[0] == c) { *m = 0; return(kc); } evt.keycode=kc; evt.state=ShiftMask; len=XLookupString(&evt, out, 32, NULL, NULL); if (len == 1 && out[0] == c) { *m = ShiftMask; return(kc); } fprintf(stderr, "Didn't resolve keycode! (c=%d, ks=%d,kc=%d\n",c,ks,kc); *m = 0; return(0); } } void cancelCB (w, client_data, call_data) Widget w; caddr_t client_data; caddr_t call_data; { XtSetKeyboardFocus(Popup,None); XtPopdown(Popup); } void okCB (w, client_data, call_data) Widget w; caddr_t client_data; caddr_t call_data; { int i, len, offset; char text[500]; Arg args[10]; int cnt; bcopy (tmpevents, Windows[tmpwindex].events, tmpeventindex * (sizeof (XKeyEvent))); Windows[tmpwindex].eventindex=tmpeventindex; offset=0; for (i=0; i #include #include #include #include #include #include #include #include #include #include #include #define XK_MISCELLANY 1 #define XK_LATIN1 1 #include #include #include #include #include #include /*************/ /* DEFINES */ /*************/ #define TITLE "xlax" #define CLASS "Xlax" #define MAXEVENTS 150 /*************/ /* types */ /*************/ typedef struct { Window wind; int active; XKeyEvent events[MAXEVENTS]; int eventindex; Widget button; Widget text; } Windows_t; /*************/ /* GLOBALS */ /*************/ void SetupInterface(); void selectCB(); void findCB(); void killCB(); void keyboardCB(); void toggleCB(); void quitCB(); void pasteCB(); void senditCB(); void togglestringCB(); void stringinputCB(); void okCB(); void clearCB(); void cancelCB(); void Find_Xlax(); void Add_Window(); void presetString(); KeyCode CharToKeycodeMod(); int Remove_Window(); void BuildCharToKeyMap(); int kcmap[256]; int modmap[256]; xlax2.4/vroot.h000064000010170000036000000117001104441702100134630ustar00finehead00000000000002/*****************************************************************************/ /** Copyright 1991 by Andreas Stolcke **/ /** Copyright 1990 by Solbourne Computer Inc. **/ /** Longmont, Colorado **/ /** **/ /** All Rights Reserved **/ /** **/ /** Permission to use, copy, modify, and distribute this software and **/ /** its documentation for any purpose and without fee is hereby **/ /** granted, provided that the above copyright notice appear in all **/ /** copies and that both that copyright notice and this permis- **/ /** sion notice appear in supporting documentation, and that the **/ /** name of Solbourne not be used in advertising **/ /** in publicity pertaining to distribution of the software without **/ /** specific, written prior permission. **/ /** **/ /** ANDREAS STOLCKE AND SOLBOURNE COMPUTER INC. DISCLAIMS ALL WARRANTIES **/ /** WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF **/ /** MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ANDREAS STOLCKE **/ /** OR SOLBOURNE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL **/ /** DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/ /** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/ /** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/ /** OR PERFORMANCE OF THIS SOFTWARE. **/ /*****************************************************************************/ /* * vroot.h -- Virtual Root Window handling header file * * This header file redefines the X11 macros RootWindow and DefaultRootWindow, * making them look for a virtual root window as provided by certain `virtual' * window managers like swm and tvtwm. If none is found, the ordinary root * window is returned, thus retaining backward compatibility with standard * window managers. * The function implementing the virtual root lookup remembers the result of * its last invocation to avoid overhead in the case of repeated calls * on the same display and screen arguments. * The lookup code itself is taken from Tom LaStrange's ssetroot program. * * Most simple root window changing X programs can be converted to using * virtual roots by just including * * #include * * after all the X11 header files. It has been tested on such popular * X clients as xphoon, xfroot, xloadimage, and xaqua. * It also works with the core clients xprop, xwininfo, xwd, and editres * (and is necessary to get those clients working under tvtwm). * It does NOT work with xsetroot; get the xsetroot replacement included in * the tvtwm distribution instead. * * Andreas Stolcke , 9/7/90 * - replaced all NULL's with properly cast 0's, 5/6/91 * - free children list (suggested by Mark Martin ), 5/16/91 * - include X11/Xlib.h and support RootWindowOfScreen, too 9/17/91 */ #ifndef _VROOT_H_ #define _VROOT_H_ #if !defined(lint) && !defined(SABER) static char vroot_rcsid[] = "$Id: vroot.h,v 1.1 92/02/25 11:41:45 frank Exp $"; #endif #include #include #include static Window VirtualRootWindowOfScreen(screen) Screen *screen; { static Screen *save_screen = (Screen *)0; static Window root = (Window)0; if (screen != save_screen) { Display *dpy = DisplayOfScreen(screen); Atom __SWM_VROOT = None; int i; Window rootReturn, parentReturn, *children; unsigned int numChildren; root = RootWindowOfScreen(screen); /* go look for a virtual root */ __SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False); if (XQueryTree(dpy, root, &rootReturn, &parentReturn, &children, &numChildren)) { for (i = 0; i < numChildren; i++) { Atom actual_type; int actual_format; unsigned long nitems, bytesafter; Window *newRoot = (Window *)0; if (XGetWindowProperty(dpy, children[i], __SWM_VROOT, 0, 1, False, XA_WINDOW, &actual_type, &actual_format, &nitems, &bytesafter, (unsigned char **) &newRoot) == Success && newRoot) { root = *newRoot; break; } } if (children) XFree((char *)children); } save_screen = screen; } return root; } #undef RootWindowOfScreen #define RootWindowOfScreen(s) VirtualRootWindowOfScreen(s) #undef RootWindow #define RootWindow(dpy,screen) VirtualRootWindowOfScreen(ScreenOfDisplay(dpy,screen)) #undef DefaultRootWindow #define DefaultRootWindow(dpy) VirtualRootWindowOfScreen(DefaultScreenOfDisplay(dpy)) #endif /* _VROOT_H_ */ xlax2.4/xlax.man000064000010170000036000000074671104441702100136310ustar00finehead00000000000002.TH XLAX 1 "Release 5" "X Version 11" .SH NAME xlax - X window system program to send keyboard input to multiple windows .SH SYNOPSIS .B "xlax" [-find] [-prefix \fIstring\fP] [-\fItoolkit options\fP] .SH DESCRIPTION .PP .I Xlax is an X Window System program that will send keyboard input it receives to multiple selected windows. When run, .I Xlax will bring up its main window. There will be six buttons on it, "Quit", "Add Windows", "Find xlax:", "Send String", "Paste", and "Kill Window." "Quit" will terminate .I xlax and "Add windows" will change the cursor to a cross-hair and allow the user to select any window on the screen by pressing a mouse button. The user will be able to continue selecting windows until either the .I xlax window or a window that has already been selected, is selected. When a window is selected, its name will appear in the .I xlax window. Clicking the mouse on the window name will toggle whether that window should receive input. When the user types anywhere in the .I xlax window, those keystrokes will be sent to all selected windows. "Kill Window" will allow the user to select a window and remove it from .I xlax's list (note: the user must click on the actual window, not the name that appears in .I xlax). There is a window to the right of each name, which may display text assigned to this window name. When "Send String" is selected, the specific string associated with each window will be sent to those windows. Clicking the first mouse button in this area will bring up a popup window that allows you to change the assigned text. Up to 150 characters are allowed. The software records all characters including backspace and carriage return, so there is no editing this field -- if you make a mistake, click on "Clear" to start over. The "Paste" button sends the currently (or most recently) selected text to all active windows. The "Find xlax:" button searches all X11 windows for those with a class hint that begins with "xlax:" (or alternately, a string specifed by the user with the -prefix option). These windows are added automatically, and their sendstring is automatically set to whatever follows "xlax:" (or the alternate prefix value). This tool tends to be useful for system administration tasks that require almost the same thing to be done in several different windows, but require some human intervention (e.g. some tape backups or building multiple servers). The string area is useful for machine or platform specific strings (such as machine names or machine type). .SH EXAMPLES This starts up three xterms, and then xlax automatically finds them. .RS .\" .LP .nf example% xterm -xrm 'XTerm*allowSendEvents: true' -name xlax:string1 & [1] 555 example% xterm -xrm 'XTerm*allowSendEvents: true' -name xlax:string2 & [2] 556 example% xterm -xrm 'XTerm*allowSendEvents: true' -name xlax:string3 & [3] 557 example% xlax -find \f1 .fi .RE If you want more than one xlax, to automatically find different windows, specify a different prefix: .RS .\" .LP .nf example% xterm -xrm 'XTerm*allowSendEvents: true' -name foo:string1 & [1] 555 example% xterm -xrm 'XTerm*allowSendEvents: true' -name foo:string2 & [2] 556 example% xterm -xrm 'XTerm*allowSendEvents: true' -name bar:string3 & [3] 557 example% xterm -xrm 'XTerm*allowSendEvents: true' -name bar:string3 & [4] 558 example% xlax -prefix foo: -find & [5] 559 example% xlax -prefix bar: -find & [6] 560 \f1 .fi .RE .SH ENVIRONMENT .PP .TP 8 .B DISPLAY To get default host and display number. .SH CAVEATS For .I xlax to work on an xterm, "allowSendEvents" must be enabled on the xterm. Note that this means that anyone can send keystrokes to that xterm, so this should not be run in an insecure or unmonitored environment. .SH BUGS Probably something, but nothing that comes to mind. .SH SEE ALSO xterm(1) .SH COPYRIGHT Copyright 1992, Frank Adelstein. .br xlax2.4/mkxlax.man000064000010170000036000000113521104441702100141450ustar00finehead00000000000002.TH MKXLAX 1 "Release 5" "X Version 11" .SH NAME mkxlax - xlax and xterm startup program .SH SYNOPSIS .B "mkxlax" [options] \fIsendString\fP [\fImore sendStrings\fP ...] .SH DESCRIPTION .PP .I Mkxlax is an perl script that will start up a number of xterms configured to work together with xlax, and then start up an xlax to communicate with the xterms. .I Mkxlax will start an xterm for each argument (send string) provided. Each xterm will have it's name hint (the `-name' option) set to xlax:sendString, where the sendString is the argument provided to .I mkxlax. The xterms will all be started with send events enabled (required for xlax). The xterms will be arranged in a cascasde from upper left to lower right. Other arrangements are possible based on the provided options. .SH OPTIONS .TP 8 .BI \-group " name" An alternate prefix should be used with xlax instead of `xlax:'. This allows multiple groups of xlax windows to be run at the same time without interfering with each other. .TP 8 .BI \-layout " name" Selects a predefined, named layout screen (from your $HOME/.mkxlax file), and uses that layout information (and group name, if given) for the created windows. .TP 8 .BI \-x " num" The starting x location of the first xterm .TP 8 .BI \-y " num" The starting y location of the first xterm .TP 8 .BI \-dx " num" The amount to add in x to the position of each additional xterm .TP 8 .BI \-dy " num" The amount to add in y to the position of each additional xterm .TP 8 .BI \-wrapx " num" If x is greater than this value, x wraps back around to it's starting value. .TP 8 .BI \-wrapy " num" If y is greater than this value, y wraps back around to it's starting value. .TP 8 .BI \-wrapdx " num" If a wrap occurs, add this value to x. Typically this is used together with `-wrapy', so that when y returns to zero, x is shifted. .TP 8 .BI \-wrapdy " num" If a wrap occurs, add this value to y. Typically this is used together with `-wrapx', so that when x returns to zero, y is shifted. .TP 8 .BI \-termsize " WIDTHxHEIGHT" The width and height (columns and rows) for the xterm that will be started. Note that this is not a full geometry specifcation, as mkxlax handles the window positioning. Default is "80x24" .TP 8 .BI \-termopts " optionstring" Additional options to pass on to the xterm. String must be quoted if it contains spaces. Also, you can not use geometry or name options here. .TP 8 .BI \-geometry " geometrystring" geometry for the xlax window (NOT the xterms). This is a standard format X11 geometry, e.g. WIDTHxHEIGHT+XOFFSET+YOFFSET. .TP 8 .B \-- Ends option processing (in case a sendString needs to start with a dash). .PP If no options are given, the defaults are `-x 0 -y 0 -dx 20 -dy 50 -wrapy 750 -wrapdx 200' It's possible to provide options that probably don't make any sense. The EXAMPLES section shows a few reasonable usages. .SH LAYOUT CONFIGURATION Custom layouts can be added by putting them in the configuration file .I .mkxlax in your home directory. The file contains lines with a layout name followed by a colon, and then command line options to set for that layout. For example: .RS .\" .LP .nf tile: -group tilexlax -dx 510 -wrapx 1000 -wrapdy 345 -geometry +740-2 \f1 .fi .RE This creates a layout called "tile", with those options set. Once this is in your .I .mkxlax file, you can then run: .RS .\" .LP .nf mkxlax -layout tile host1 host2 ... \f1 .fi .RE And all of the options associated with "tile" will apply. Note that the config file will override any command-line options which are before the "-layout"; command-line options after the "-layout" will override those in the config file. You can also list sendStrings after the options in the layout configuration, so a frequently used list of strings can be accessed with a simple layout. Any additional sendStrings provided on the command line will be added to those found in the layout. .SH EXAMPLES This starts up five xterms with the default cascade positioning. .RS .\" .LP .nf example% mkxlax host1 host2 host3 host4 host5 \f1 .fi .RE If you run more than one group of .I mkxlax windows, you need different group names, otherwise later xlaxes will find windows from earlier .I mkxlax commands. .RS .\" .LP .nf example% mkxlax -group foo: host1 host2 host3 \f1 .fi .RE To lay out tiled, by row: .RS .\" .LP .nf example% mkxlax -dx 400 -wrapx 1000 -wrapdy 300 host1 host2 ... \f1 .fi .RE To lay out tiled, by column: .RS .\" .LP .nf example% mkxlax -dy 300 -wrapy 700 -wrapdx 400 host1 host2 ... \f1 .fi .RE .SH ENVIRONMENT .PP .TP 8 .B DISPLAY To get default host and display number. .SH FILES .PD 0 .TP .I $HOME/.mkxlax Layout customization information .PD .SH BUGS Probably something, but nothing that comes to mind. .SH SEE ALSO xterm(1), xlax(1) .SH COPYRIGHT Copyright 2007, Thomas A. Fine .br xlax2.4/dot-mkxlax000064000010170000036000000011511104441702100141530ustar00finehead00000000000002# # .mkxlax - config file for mkxlax # # Distriubition sample file. # # tile: -group tilexlax -dx 510 -wrapx 1000 -wrapdy 345 -geometry +740-2 # use this layout by running: "mkxlax -layout tile" # # tile # tile standard 80x24 xterms (with the author's default font) across one # monitor of width 1280, and place xlax at lower right corner tile: -group tilexlax -dx 510 -wrapx 1000 -wrapdy 345 -geometry -2-2 # # This example cascades a set of five windows, with preset sendstrings # use this layout by running: "mkxlax -layout myhosts" # myhosts: -group myhosts -dx 10 -dy 100 host1 host2 host3 host4 host5 xlax2.4/README000064000010170000036000000025051104441702100130240ustar00finehead00000000000002xlax is a program that allows output to be sent to several windows (via SendEvent()). It can be useful for some tasks that require almost the same thing to be done on different machines. Send questions, comments or whatever to fine@head.cfa.harvard.edu Author: Frank Adelstein, with code for window selection taken from "dsimple" in MIT clients, and "vroot.h" used so it'll work under tvtwm. Version2.0 Author: Thomas A. Fine, added code for finding windows based on the name hint, also improved "send string" setting, and automatic dropping of dead windows. To compile: #go to the directory where you untarred the distiribution xmkmf make #then hand-install xlax, mkxlax, xlax.man, and mkxlax.man For more information, see the accompanying man page, distributed as "xlax.man", and also see: http://hea-www.harvard.edu/~fine/Tech/xlax.html Also included is the perl script mkxlax, which is documented in "mkxlax.man". This comes with a sample (optional) configuration file, "dot-mkxlax", which (if used) belongs in your home directory as ".mkxlax". The first line of the perl-script may need to be hand-edited to the proper location for perl, if it is not installed as "/usr/bin/perl". Standard X copying policies apply (see the copyright notice at the beginning of code for full details). --Frank Adelstein. --Thomas A. Fine. xlax2.4/LICENSE000064000010170000036000000023271104441702100131530ustar00finehead00000000000002/* * Copyright 1992 by Frank Adelstein. All Rights Reserved. * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the authors name not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. The author makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ All subsequent changes made by Thomas A. Fine fall under the above license. xlax2.4/TODO000064000010170000036000000031271104441702100126350ustar00finehead00000000000002Future plans The paste implementation is simplistic. It uses XFetchBuffer, which is kinda funky. It's not well documented but it seems to get the current PRIMARY selection, or if there is no PRIMARY selection, it find the last one somewhere. This seems to be the same behaviour as pasting in xterms. At any rate, it might be better to grab the PRIMARY if it exists, otherwise grab the CLIPBOARD if it exists, otherwise fall back to XFetchBuffer. It would also be nice if you could see what you are about to paste somewhere. Multiple "send string" sets? It would nice to be able to re-sort the order of listed windows. Would it be useful if mousing over the window titles raised the window to the top? The big change desired is to merge mkxlax functionality into xlax. The advantage of doing this is that since xlax can tell when windows die, it could be used to respawn dead windows automatically. This could be helpful in cases where the windows are started remotely and have the habit of vanishing when the remote end reboots. After that is done, then consider a graphical way of laying out windows and saving layouts. xlax should be able to get the location of the windows you've added and automatically learn where you want them to go, and save that as a layout. Note that updating the interface style is not in the cards. Yes, the antique athena widgets are ugly, but it's a lightweight implementation that works just fine, so I'm not making the program bloat just for aesthetics. Send feature requests to fine@head.cfa.harvard.edu, with "xlax" in the subject (so I can grep through my spam for it).