chiark / gitweb /
xduplic-copier: as found on chiark
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Fri, 29 Nov 2013 18:41:32 +0000 (18:41 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Fri, 29 Nov 2013 18:41:32 +0000 (18:41 +0000)
cprogs/xduplic-copier.c [new file with mode: 0644]

diff --git a/cprogs/xduplic-copier.c b/cprogs/xduplic-copier.c
new file mode 100644 (file)
index 0000000..ff0830d
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2002 Ian Jackson <ian@chiark.greenend.org.uk>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2,
+ * or (at your option) any later version.
+ *
+ * This is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <X11/cursorfont.h>
+#include <X11/cursorfont.h>
+#include <X11/Xmu/WinUtil.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+
+static Display *display;
+static int selecting, l1_x, l1_y;
+static char stringbuf[20];
+static unsigned long c_black, c_white, c_red, c_yellow;
+static Window w, root;
+static Cursor cursor;
+static GC gc;
+static Colormap cmap;
+
+struct wnode {
+  struct wnode *next;
+  Window w;
+} *headwn;
+
+static unsigned long getcolour(const char *name, int def) {
+  Status st;
+  XColor screen_def, exact_def;
+  st= XAllocNamedColor(display,cmap,name,&screen_def,&exact_def);
+  fprintf(stdout,"name %s pixel %lu\n",name,screen_def.pixel);
+  return st ? screen_def.pixel : def;
+}
+
+static void beep(void) { XBell(display,100); }
+
+/*
+ *  While selecting:
+ *                   Left                         Right
+ *    application     select                       deselect
+ *    root            start typing                 deselect all
+ *    xduplic         start typing                 quit
+ *
+ *  While typing:
+ *                   Left                         Right
+ *    xduplic         start selecting              quit
+ *
+ *  Colours:
+ *
+ *    While typing:                   yellow on black
+ *    While selecting:                white on black
+ *    Idle (typing into nowhere):     red on black
+ */
+
+static void redisplay(void) {
+  XClearWindow(display,w);
+  XDrawString(display,w,gc, l1_x,l1_y, stringbuf,strlen(stringbuf));
+}
+
+static void restatus(void) {
+  XGCValues v;
+  int count;
+  struct wnode *own;
+
+  v.foreground= (selecting ? c_white :
+                headwn ? c_yellow :
+                c_red);
+  
+  XChangeGC(display,gc,
+           GCForeground,
+           &v);
+  XClearWindow(display,w);
+
+  for (count=0, own=headwn; own; own=own->next) count++;
+  snprintf(stringbuf,sizeof(stringbuf),
+          "%c %d",
+          selecting ? 'S' :
+          headwn ? 'T' : 'i',
+          count);
+  redisplay();
+}
+
+static void stopselecting(void) {
+  XUngrabPointer(display,CurrentTime);
+  selecting= 0;
+  restatus();
+}
+
+static void startselecting(void) {
+  Status st;
+  st= XGrabPointer(display,root,True,
+                  ButtonPressMask,GrabModeAsync,
+                  GrabModeAsync,None,cursor,CurrentTime);
+  if (st != Success) beep();
+  else selecting= 1;
+  restatus();
+}
+
+static void buttonpress(XButtonEvent *e) {
+  struct wnode *own, **ownp, *ownn;
+  int rightbutton;
+  Window sw;
+
+  switch (e->button) {
+  case Button1: rightbutton=0; break;
+  case Button3: rightbutton=1; break;
+  default: return;
+  }
+
+  fprintf(stdout,"button right=%d in=%lx sub=%lx (w=%lx root=%lx)\n",
+         rightbutton, (unsigned long)e->window, (unsigned long)e->subwindow,
+         (unsigned long)w, (unsigned long)e->root);
+
+  if (e->window == w) {
+    if (rightbutton) _exit(0);
+    if (selecting) {
+      stopselecting();
+      /* move pointer to where it already is, just in case wm is confused */
+      XWarpPointer(display,None,root, 0,0,0,0, e->x_root,e->y_root);
+    } else {
+      startselecting();
+    }
+    return;
+  }
+
+  if (!selecting) return;
+
+  if (e->window != e->root) return;
+
+  sw= XmuClientWindow(display, e->subwindow);
+  if (!sw) {
+    if (!rightbutton) {
+      stopselecting();
+    } else {
+      if (!headwn) { beep(); return; }
+      for (own=headwn; own; own=ownn) {
+       ownn= own->next;
+       free(own);
+      }
+      headwn= 0;
+      restatus();
+    }
+    return;
+  }
+
+  if (sw == w) { beep(); return; }
+
+  for (ownp=&headwn;
+       (own=(*ownp)) && own->w != sw;
+       ownp= &(*ownp)->next);
+  
+  if (!rightbutton) {
+    
+    if (own) { beep(); return; }
+    own= malloc(sizeof(*own)); if (!own) { perror("malloc"); exit(-1); }
+    own->w= sw;
+    own->next= headwn;
+    headwn= own;
+
+  } else {
+
+    if (!own) { beep(); return; }
+    *ownp= own->next;
+    free(own);
+
+  }
+
+  restatus();
+}
+
+static void keypress(XKeyEvent *e) {
+  Status st;
+  struct wnode *own;
+  unsigned long mask;
+  
+  if (selecting) {
+    fprintf(stdout,"key type %d serial %lu (send %d) "
+           "window %lx root %lx sub %lx time %lx @%dx%d (%dx%dabs) "
+           "state %x keycode %u same %d\n",
+           e->type, e->serial, (int)e->send_event,
+           (unsigned long)e->window,
+           (unsigned long)e->root,
+           (unsigned long)e->subwindow,
+           (unsigned long)e->time,
+           e->x,e->y, e->x_root,e->y_root,
+           e->state, e->keycode, (int)e->same_screen);
+    if (XKeycodeToKeysym(display, e->keycode, 0) == XK_q) _exit(1);
+    beep(); return;
+  }
+  for (own=headwn; own; own=own->next) {
+    mask= (e->type == KeyPress ? KeyPressMask :
+          e->type == KeyRelease ? KeyReleaseMask :
+          KeyPressMask|KeyReleaseMask);
+    e->window= own->w;
+    e->subwindow= None;
+    e->send_event= True;
+    st= XSendEvent(display,own->w,True,mask,(XEvent*)e);
+    if (st != Success) {
+      fprintf(stdout,"sendevent to %lx %d mask %lx\n",
+             (unsigned long)own->w, st, mask);
+    }
+  }
+}
+
+static void expose(XExposeEvent *e) {
+  if (e->count) return;
+  redisplay();
+}
+
+int main(int argc, const char **argv) {
+  XEvent e;
+  XGCValues gcv;
+  XSetWindowAttributes wv;
+  int screen, direction, ascent, descent, l1_width, l1_height;
+  XCharStruct overall;
+  Font font;
+
+  display= XOpenDisplay(0);
+  screen= DefaultScreen(display);
+  cmap= DefaultColormap(display,screen);
+  root= DefaultRootWindow(display);
+  
+  c_black=   getcolour("black",  0);
+  c_white=   getcolour("white",  1);
+  c_yellow=  getcolour("yellow", c_white);
+  c_red=     getcolour("red",    c_white);
+
+  cursor= XCreateFontCursor(display,XC_crosshair);
+
+  wv.event_mask= KeyPressMask|KeyReleaseMask|ButtonPressMask|ExposureMask;
+  w= XCreateWindow(display, root,
+                  0,0, 50,21, 0,DefaultDepth(display,screen),
+                  InputOutput, DefaultVisual(display,screen),
+                  CWEventMask, &wv);
+
+  font= XLoadFont(display,"fixed");
+
+  gcv.background= c_black;
+  gcv.font=       font;
+  gc= XCreateGC(display,w,GCBackground|GCFont,&gcv);
+
+  XQueryTextExtents(display,font, "SIT 0689", 8,
+                   &direction,&ascent,&descent,&overall);
+  l1_width= overall.lbearing + overall.rbearing;
+  l1_x= overall.lbearing;
+  l1_y= ascent;
+  l1_height= descent+ascent;
+
+  XResizeWindow(display,w, l1_width,l1_height);
+  XSetWindowBackground(display,w,c_black);
+  
+  XMapWindow(display,w);
+  restatus();
+  
+  for (;;) {
+    XNextEvent(display,&e);
+    fprintf(stdout,"selecting = %d; event type = %lu\n",
+           selecting, (unsigned long)e.type);
+    switch (e.type) {
+    case Expose:                     expose(&e.xexpose);       break;
+    case ButtonPress:                buttonpress(&e.xbutton);  break;
+    case KeyPress: case KeyRelease:  keypress(&e.xkey);        break;
+    }
+  }
+}