xtbinit.c - sam - An updated version of the sam text editor.
 (HTM) git clone git://vernunftzentrum.de/sam.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
       xtbinit.c (18637B)
       ---
            1 /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */
            2 #include <u.h>
            3 #include <libg.h>
            4 #include <stdio.h>
            5 #include <stdlib.h>
            6 #include <string.h>
            7 #include <sys/types.h>
            8 #include <sys/socket.h>
            9 #include "libgint.h"
           10 
           11 #define Font xFont
           12 #define Event xEvent
           13 
           14 #include <X11/Intrinsic.h>
           15 #include <X11/StringDefs.h>
           16 #include <X11/Shell.h>
           17 #include <X11/XKBlib.h>
           18 #include <X11/extensions/XInput.h>
           19 #include "Gwin.h"
           20 
           21 #undef Font
           22 #undef Event
           23 
           24 /* default colors */
           25 #ifndef MAX_BACKGROUNDS
           26     #define MAX_BACKGROUNDS 20
           27 #endif
           28 
           29 #ifndef DEFAULT_FOREGROUND
           30     #define DEFAULT_FOREGROUND "#000000"
           31 #endif
           32 
           33 #ifndef DEFAULT_BACKGROUND
           34     #define DEFAULT_BACKGROUND "#ffffff"
           35 #endif
           36 
           37 #ifndef DEFAULT_BORDER
           38     #define DEFAULT_BORDER "#000000"
           39 #endif
           40 
           41 /* libg globals */
           42 XIM xim;
           43 XIC xic;
           44 Bitmap  screen;
           45 XftFont *font;
           46 XftColor fontcolor;
           47 char fontspec[1024] = {0};
           48 char foregroundspec[1024] = {0};
           49 char backgroundspec[1024] = {0};
           50 char borderspec[1024] = {0};
           51 
           52 /* implementation globals */
           53 extern char *machine;
           54 Display     *_dpy;
           55 Widget      _toplevel;
           56 Window _topwindow;
           57 uint64_t _bgpixels[MAX_BACKGROUNDS];
           58 int _nbgs;
           59 uint64_t   _fgpixel, _bgpixel, _borderpixel;
           60 XColor      _fgcolor, _bgcolor, _bordercolor;
           61 int     _ld2d[6] = { 1, 2, 4, 8, 16, 24 };
           62 uint64_t   _ld2dmask[6] = { 0x1, 0x3, 0xF, 0xFF, 0xFFFF, 0x00FFFFFF };
           63 Colormap    _libg_cmap;
           64 int     _cmap_installed;
           65 
           66 /* xbinit implementation globals */
           67 static XtAppContext app;
           68 static Widget widg;
           69 static bool exposed = 0;
           70 static Atom wm_take_focus;
           71 static Mouse lastmouse;
           72 
           73 typedef struct Ebuf {
           74     struct Ebuf *next;
           75     int     n;
           76     unsigned char   buf[4];
           77 } Ebuf;
           78 
           79 typedef struct Esrc {
           80     bool issocket;
           81     bool inuse;
           82     int size;
           83     int count;
           84     Ebuf    *head;
           85     Ebuf    *tail;
           86 } Esrc;
           87 
           88 #define MAXINPUT    1024        /* number of queued input events */
           89 #define MAXSRC      10
           90 
           91 static Esrc esrc[MAXSRC];
           92 static int  nsrc;
           93 
           94 
           95 static int einitcalled = 0;
           96 static int Smouse = -1;
           97 static int Skeyboard = -1;
           98 
           99 
          100 static void reshaped(int, int, int, int);
          101 static void gotchar(int, int, int, int, int, const char *);
          102 static void gotmouse(Gwinmouse *);
          103 static int  ilog2(int);
          104 
          105 static Ebuf *ebread(Esrc *);
          106 static Ebuf *ebadd(Esrc *, bool);
          107 static void focinit(Widget);
          108 static void wmproto(Widget, XEvent *, String *, Cardinal *);
          109 static void waitevent(void);
          110 
          111 static Errfunc  onerr;
          112 
          113 String _fallbacks[] = {
          114     "*gwin.width: 400",
          115     "*gwin.height: 400",
          116     NULL
          117 };
          118 
          119 static char *shelltrans = 
          120     "<ClientMessage> WM_PROTOCOLS : WMProtocolAction()";
          121 static XtActionsRec wmpactions[] = {
          122     {"WMProtocolAction", wmproto}
          123 };
          124 
          125 Bitmap  *darkgrey;
          126 
          127 static uint8_t darkgreybits[] = {
          128     0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77,
          129     0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77,
          130     0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77,
          131     0xDD, 0xDD, 0x77, 0x77, 0xDD, 0xDD, 0x77, 0x77,
          132 };
          133 
          134 void
          135 freefont(void)
          136 {
          137     if (font)
          138         XftFontClose(_dpy, font);
          139 }
          140 
          141 void
          142 xtbinit(Errfunc f, char *class, int *pargc, char **argv, char **fallbacks)
          143 {
          144     int n;
          145     char *p;
          146     int compose;
          147 
          148     if(!class && argv[0]){
          149         p = strrchr(argv[0], '/');
          150         if(p)
          151             class = XtNewString(p+1);
          152         else
          153             class = XtNewString(argv[0]);
          154         if(class[0] >= 'a' && class[0] <= 'z')
          155             class[0] += 'A' - 'a';
          156     }
          157     onerr = f;
          158     if (!fallbacks)
          159         fallbacks = _fallbacks;
          160 
          161     char name[512] = {0};
          162     snprintf(name, sizeof(name) - 1, "samterm on %s", machine);
          163     Arg args[] ={
          164         {XtNinput, true},
          165         {XtNtitle, (XtArgVal)name},
          166         {XtNiconName, (XtArgVal)name},
          167     };
          168     _toplevel = XtAppInitialize(&app, class,
          169             NULL, 0,
          170             pargc, argv, fallbacks, args, XtNumber(args));
          171 
          172     n = 0;
          173     XtSetArg(args[n], XtNreshaped, reshaped);   n++;
          174     XtSetArg(args[n], XtNgotchar, gotchar);     n++;
          175     XtSetArg(args[n], XtNgotmouse, gotmouse);   n++;
          176     widg = XtCreateManagedWidget("gwin", gwinWidgetClass, _toplevel, args, n);
          177 
          178     _dpy = XtDisplay(widg);
          179     XAllocNamedColor(_dpy, DefaultColormap(_dpy, DefaultScreen(_dpy)),
          180                      foregroundspec[0] ? foregroundspec : getenv("FOREGROUND") ? getenv("FOREGROUND") : DEFAULT_FOREGROUND, &_fgcolor, &_fgcolor);
          181     XAllocNamedColor(_dpy, DefaultColormap(_dpy, DefaultScreen(_dpy)),
          182                      borderspec[0] ? borderspec : getenv("BORDER") ? getenv("BORDER") : DEFAULT_BORDER, &_bordercolor, &_bordercolor);
          183     char bgspec[1024] = {0};
          184     strncpy(bgspec, backgroundspec[0] ? backgroundspec : getenv("BACKGROUND") ? getenv("BACKGROUND") : DEFAULT_BACKGROUND, sizeof(bgspec) - 1);
          185 
          186     char *bgc = NULL;
          187     for (bgc = strtok(bgspec, ":"); bgc != NULL && _nbgs < MAX_BACKGROUNDS; bgc = strtok(NULL, ":")){
          188         XColor xc = {0};
          189         if (XAllocNamedColor(_dpy, DefaultColormap(_dpy, DefaultScreen(_dpy)), bgc, &xc, &xc))
          190             _bgpixels[_nbgs++] = xc.pixel;
          191     }
          192 
          193     if (_nbgs == 0)
          194         _bgpixels[_nbgs++] = ~_fgcolor.pixel;
          195 
          196     _bgpixel = _bgpixels[0];
          197 
          198     n = 0;
          199     XtSetArg(args[n], XtNcomposeMod, &compose); n++;
          200     XtGetValues(widg, args, n);
          201 
          202     if (compose < 0 || compose > 5) {
          203         n = 0;
          204         XtSetArg(args[n], XtNcomposeMod, 0);    n++;
          205         XtSetValues(widg, args, n);
          206     }
          207 
          208     initcursors();
          209     atexit(freebindings);
          210     atexit(freechords);
          211 
          212     if ((xim = XOpenIM(_dpy, NULL, NULL, NULL)) == NULL) {
          213         XSetLocaleModifiers("@im=local");
          214         if ((xim =  XOpenIM(_dpy, NULL, NULL, NULL)) == NULL) {
          215             XSetLocaleModifiers("@im=");
          216             if ((xim = XOpenIM(_dpy, NULL, NULL, NULL)) == NULL) {
          217                 fprintf(stderr, "could not open input method\n");
          218                 exit(EXIT_FAILURE);
          219             }
          220         }
          221     }
          222 
          223     font = XftFontOpenName(_dpy, DefaultScreen(_dpy), fontspec[0] ? fontspec : getenv("FONT") ? getenv("FONT") : "monospace");
          224     screen.id = 0;
          225     XtRealizeWidget(_toplevel);
          226     _topwindow = XtWindow(_toplevel);
          227     atexit(freefont);
          228 
          229     pid_t pid = getpid();
          230     XChangeProperty(_dpy, XtWindow(_toplevel), XInternAtom(_dpy, "_NET_WM_PID", False), XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&pid, 1);
          231 
          232     _fgpixel = _fgcolor.pixel;
          233     _borderpixel = _bordercolor.pixel;
          234 
          235     XRenderColor xrcolor = {0};
          236     xrcolor.red = _fgcolor.red;
          237     xrcolor.green = _fgcolor.green;
          238     xrcolor.blue = _fgcolor.blue;
          239     xrcolor.alpha = 65535;
          240     XftColorAllocValue(_dpy, DefaultVisual(_dpy, DefaultScreen(_dpy)), DefaultColormap(_dpy, DefaultScreen(_dpy)), &xrcolor, &fontcolor);
          241 
          242     screen.id = (int) XtWindow(widg);
          243     screen.ldepth = ilog2(DefaultDepth(_dpy, DefaultScreen(_dpy)));
          244     screen.flag = SCR;
          245     if(_fgpixel != 0)
          246         screen.flag |= BL1;
          247     /* leave screen rect at all zeros until reshaped() sets it */
          248     while(!exposed) {
          249         XFlush(_dpy);
          250         XtAppProcessEvent(app, XtIMXEvent);
          251     }
          252 
          253     darkgrey = balloc(Rect(0, 0, 16, 16), 0);
          254     wrbitmap(darkgrey, 0, 16, darkgreybits);
          255 
          256     XFlush(_dpy);
          257     focinit(_toplevel);
          258 }
          259 
          260 static void
          261 focinit(Widget w)
          262 {
          263     XrmValue src, dst;
          264 
          265     src.addr = "WM_TAKE_FOCUS";
          266     src.size = strlen((char *)src.addr)+1;
          267     dst.addr = (XtPointer) &wm_take_focus;
          268     dst.size = sizeof(Atom);
          269     XtConvertAndStore(w, XtRString, &src, XtRAtom, &dst);
          270     XSetWMProtocols(XtDisplay(w), XtWindow(w), &wm_take_focus, 1);
          271     XtAppAddActions(app, wmpactions, XtNumber(wmpactions));
          272     XtAugmentTranslations(w, XtParseTranslationTable(shelltrans));
          273 }
          274 
          275 static void
          276 wmproto(Widget w, XEvent *e , String *p, Cardinal *np)
          277 {
          278     Time t;
          279 
          280     if(e->type == ClientMessage &&
          281           (Atom)(e->xclient.data.l[0]) == wm_take_focus) {
          282         t = (Time) e->xclient.data.l[1];
          283         XtCallAcceptFocus(widg, &t);
          284     }
          285 }
          286 
          287 static void
          288 reshaped(int minx, int miny, int maxx, int maxy)
          289 {
          290     Ebuf *eb;
          291 
          292     screen.r = Rect(minx, miny, maxx, maxy);
          293     screen.clipr = screen.r;
          294     if (screen.id) {
          295         exposed = true;
          296         ereshaped(screen.r);
          297     }
          298     if(einitcalled){
          299         /*
          300          * Cause a mouse event, so programs like sam
          301          * will get out of eread and REALLY do the reshape
          302          */
          303         eb = ebadd(&esrc[Smouse], false);
          304         if (eb == 0)
          305             berror("eballoc can't malloc");
          306         memcpy((void*)eb->buf, (void*)&lastmouse, sizeof lastmouse);
          307         esrc[Smouse].count++;
          308     }
          309 }
          310 
          311 static void
          312 gotchar(int c, int kind, int target, int x, int y, const char *arg)
          313 {
          314     Ebuf *eb;
          315     Keystroke k;
          316 
          317     if(!einitcalled || Skeyboard == -1)
          318         return;
          319     eb = ebadd(&esrc[Skeyboard], false);
          320     if (eb == NULL)
          321         berror("eballoc can't malloc");
          322     k.c = c;
          323     k.k = kind;
          324     k.t = target;
          325     k.p = Pt(x, y);
          326     k.a = arg;
          327     memcpy(eb->buf, &k, sizeof(Keystroke));
          328     esrc[Skeyboard].count++;
          329 }
          330 
          331 static void
          332 gotmouse(Gwinmouse *gm)
          333 {
          334     Ebuf *eb;
          335     Mouse m;
          336 
          337     if(!einitcalled || Smouse == -1)
          338         return;
          339     m.buttons = gm->buttons;
          340     m.xy.x = gm->xy.x;
          341     m.xy.y = gm->xy.y;
          342     m.msec = gm->msec;
          343     lastmouse = m;
          344     eb = ebadd(&esrc[Smouse], false);
          345     if (eb == 0)
          346         berror("eballoc can't malloc");
          347     memcpy((void*)eb->buf, (void*)&m, sizeof m);
          348     esrc[Smouse].count++;
          349 }
          350 
          351 static void
          352 gotinput(XtPointer cldata, int *pfd, XtInputId *id)
          353 {
          354     Ebuf *eb, *lasttail, *newe;
          355     Esrc *es;
          356     int n;
          357 
          358     if(!einitcalled)
          359         return;
          360     es = (Esrc *)cldata;
          361     if (es->count >= MAXINPUT)
          362         return;
          363     lasttail = es->tail;
          364     eb = ebadd(es, false);
          365     if (eb == 0)
          366         return;
          367     if(es->size){
          368         if (es->issocket){
          369             struct sockaddr addr;
          370             socklen_t len;
          371             int fd = accept(*pfd, &addr, &len);
          372             n = read(fd, (char *)eb->buf, es->size);
          373             close(fd);
          374         } else
          375             n = read(*pfd, (char *)eb->buf, es->size);
          376         if (n < 0)
          377             n = 0;
          378         if(n < es->size) {
          379             newe = realloc(eb, sizeof(Ebuf)+n);
          380             newe->n = n;
          381             if (es->head == eb)
          382                 es->head = newe;
          383             else
          384                 lasttail->next = newe;
          385             es->tail = newe;
          386         }
          387     }
          388     es->count++;
          389 }
          390 
          391 static int
          392 ilog2(int n)
          393 {
          394     int i, v;
          395 
          396     for(i=0, v=1; i < 6; i++, v<<=1)
          397         if(n <= v)
          398             break;
          399     return i;
          400 }
          401 
          402 
          403 void
          404 rdcolmap(Bitmap *b, RGB *map)
          405 {
          406     XColor cols[256];
          407     int i, n, depth;
          408     Colormap cmap;
          409     Arg args[2];
          410 
          411     if (_cmap_installed) {
          412         cmap = _libg_cmap;
          413     } else {
          414         i = 0;
          415         XtSetArg(args[i], XtNcolormap, &cmap);  i++;
          416         XtGetValues(_toplevel, args, i);
          417     }
          418 
          419     depth = _ld2d[screen.ldepth];
          420     n = 1 << depth;
          421     if (depth == 1) {
          422         map[0].red = map[0].green = map[0].blue = ~0;
          423         map[1].red = map[1].green = map[1].blue = 0;
          424     }
          425     else {
          426         if (n > 256) {
          427             berror("rdcolmap bitmap too deep");
          428             return;
          429         }
          430         for (i = 0; i < n; i++)
          431             cols[i].pixel = i;
          432         XQueryColors(_dpy, cmap, cols, n);
          433         for (i = 0; i < n; i++) {
          434             map[i].red = (cols[i].red << 16) | cols[i].red;
          435             map[i].green = (cols[i].green << 16) | cols[i].green;
          436             map[i].blue = (cols[i].blue << 16) | cols[i].blue;
          437         }
          438     }
          439 }
          440 
          441 void
          442 wrcolmap(Bitmap *b, RGB *map)
          443 {
          444     int i, n, depth;
          445     Screen *scr;
          446     XColor cols[256];
          447     Arg args[2];
          448     XVisualInfo vi;
          449     Window w;
          450 
          451     scr = XtScreen(_toplevel);
          452     depth = _ld2d[screen.ldepth];
          453     n = 1 << depth;
          454     if (n > 256) {
          455         berror("wrcolmap bitmap too deep");
          456         return;
          457     } else if (depth > 1) {
          458         for (i = 0; i < n; i++) {
          459             cols[i].red = map[i].red >> 16;
          460             cols[i].green = map[i].green >> 16;
          461             cols[i].blue = map[i].blue >> 16;
          462             cols[i].pixel = i;
          463             cols[i].flags = DoRed|DoGreen|DoBlue;
          464         }
          465         if (!XMatchVisualInfo(_dpy, XScreenNumberOfScreen(scr),
          466                     depth, PseudoColor, &vi)) {
          467             berror("wrcolmap can't get visual");
          468             return;
          469         }
          470         w = XtWindow(_toplevel);
          471         _libg_cmap = XCreateColormap(_dpy, w, vi.visual, AllocAll);
          472         XStoreColors(_dpy, _libg_cmap, cols, n);
          473 
          474         i = 0;
          475         XtSetArg(args[i], XtNcolormap, _libg_cmap); i++;
          476         XtSetValues(_toplevel, args, i);
          477         _cmap_installed = 1;
          478     }
          479 }
          480 
          481 void
          482 einit(uint64_t keys)
          483 {
          484     /*
          485      * Make sure Smouse = ilog2(Emouse) and Skeyboard == ilog2(Ekeyboard)
          486      */
          487     nsrc = 0;
          488     if(keys&Emouse){
          489         Smouse = 0;
          490         esrc[Smouse].inuse = true;
          491         esrc[Smouse].size = sizeof(Mouse);
          492         esrc[Smouse].count = 0;
          493         nsrc = Smouse+1;
          494     }
          495     if(keys&Ekeyboard){
          496         Skeyboard = 1;
          497         esrc[Skeyboard].inuse = true;
          498         esrc[Skeyboard].size = sizeof(Keystroke);
          499         esrc[Skeyboard].count = 0;
          500         if(Skeyboard >= nsrc)
          501             nsrc = Skeyboard+1;
          502     }
          503     einitcalled = 1;
          504 }
          505 
          506 uint64_t
          507 estart(uint64_t key, int fd, size_t n, bool issocket)
          508 {
          509     int i;
          510 
          511     if(fd < 0)
          512         berror("bad fd to estart");
          513     if(n <= 0 || n > EMAXMSG)
          514         n = EMAXMSG;
          515     for(i=0; i<MAXSRC; i++)
          516         if((key & ~(1<<i)) == 0 && !esrc[i].inuse){
          517             if(nsrc <= i)
          518                 nsrc = i+1;
          519             esrc[i].inuse = true;
          520             esrc[i].issocket = issocket;
          521             esrc[i].size = n;
          522             esrc[i].count = 0;
          523             XtAppAddInput(app, fd, (XtPointer)XtInputReadMask,
          524                 gotinput, (XtPointer) &esrc[i]);
          525             return 1<<i;
          526         }
          527     return 0;
          528 }
          529 
          530 uint64_t
          531 event(Event *e)
          532 {
          533     return eread(~0L, e);
          534 }
          535 
          536 uint64_t
          537 eread(uint64_t keys, Event *e)
          538 {
          539     Ebuf *eb;
          540     int i;
          541 
          542     if(keys == 0)
          543         return 0;
          544         /* Give Priority to X events */
          545     if (XtAppPending(app) & XtIMXEvent)
          546         XtAppProcessEvent(app, XtIMXEvent);
          547 
          548     for(;;){
          549         for(i=0; i<nsrc; i++)
          550             if((keys & (1<<i)) && esrc[i].head){
          551                 if(i == Smouse)
          552                     e->mouse = emouse();
          553                 else if(i == Skeyboard)
          554                     e->keystroke = ekbd();
          555                 else {
          556                     eb = ebread(&esrc[i]);
          557                     e->n = eb->n;
          558                     if(e->n > 0)
          559                         memcpy((void*)e->data, (void*)eb->buf, e->n);
          560                     free(eb);
          561                 }
          562                 return 1<<i;
          563             }
          564         waitevent();
          565     }
          566 }
          567 
          568 Mouse
          569 emouse(void)
          570 {
          571     Mouse m;
          572     Ebuf *eb;
          573 
          574     if(!esrc[Smouse].inuse)
          575         berror("mouse events not selected");
          576     eb = ebread(&esrc[Smouse]);
          577     memcpy((void*)&m, (void*)eb->buf, sizeof(Mouse));
          578     free(eb);
          579     return m;
          580 }
          581 
          582 Keystroke
          583 ekbd(void)
          584 {
          585     Ebuf *eb;
          586     Keystroke k;
          587 
          588     if(!esrc[Skeyboard].inuse)
          589         berror("keyboard events not selected");
          590     eb = ebread(&esrc[Skeyboard]);
          591     memcpy(&k, eb->buf, sizeof(Keystroke));
          592     free(eb);
          593     return k;
          594 }
          595 
          596 void
          597 pushkbd(int c)
          598 {
          599     Ebuf *eb;
          600     Keystroke k;
          601 
          602     if(!einitcalled || Skeyboard == -1)
          603         return;
          604     eb = ebadd(&esrc[Skeyboard], true);
          605     if (eb == 0)
          606         berror("eballoc can't malloc");
          607     k.c = c;
          608     k.k = Kraw;
          609     memcpy(eb->buf, &k, sizeof(Keystroke));
          610     esrc[Skeyboard].count++;
          611 }
          612 
          613 int
          614 ecanread(uint64_t keys)
          615 {
          616     int i;
          617 
          618     for(;;){
          619         for(i=0; i<nsrc; i++){
          620             if((keys & (1<<i)) && esrc[i].head)
          621                 return 1<<i;
          622         }
          623         if(XtAppPending(app))
          624             waitevent();
          625         else
          626             return 0;
          627     }
          628 }
          629 
          630 int
          631 ecanmouse(void)
          632 {
          633     if(Smouse == -1)
          634         berror("mouse events not selected");
          635     return ecanread(Emouse);
          636 }
          637 
          638 int
          639 ecankbd(void)
          640 {
          641     if(Skeyboard == -1)
          642         berror("keyboard events not selected");
          643     return ecanread(Ekeyboard);
          644 }
          645 
          646 static Ebuf*
          647 ebread(Esrc *s)
          648 {
          649     Ebuf *eb;
          650 
          651     while(s->head == 0)
          652         waitevent();
          653     eb = s->head;
          654     if(s == &esrc[Smouse]) {
          655         while(eb->next) {
          656             s->head = eb->next;
          657             s->count--;
          658             free(eb);
          659             eb = s->head;
          660         }
          661     }
          662     s->head = s->head->next;
          663     if(s->head == 0) {
          664         s->tail = 0;
          665         s->count = 0;
          666     } else
          667         s->count--;
          668     return eb;
          669 }
          670 
          671 static inline void
          672 ebappend(Ebuf *b, Esrc *s)
          673 {
          674     if (s->tail){
          675         s->tail->next = b;
          676         s->tail = b;
          677     } else
          678         s->head = s->tail = b;
          679 }
          680 
          681 static inline void
          682 ebprepend(Ebuf *b, Esrc *s)
          683 {
          684     b->next = s->head;
          685     s->head = b;
          686 }
          687 
          688 static Ebuf*
          689 ebadd(Esrc *s, bool prepend)
          690 {
          691     Ebuf *eb;
          692     int m;
          693 
          694     m = sizeof(Ebuf);
          695     if(s->size > 1)
          696         m += (s->size-1);   /* overestimate, because of alignment */
          697     eb = (Ebuf *)malloc(m);
          698     if(eb) {
          699         eb->next = 0;
          700         eb->n = s->size;
          701         if (prepend)
          702             ebprepend(eb, s);
          703         else
          704             ebappend(eb, s);
          705     }
          706     return eb;
          707 }
          708 
          709 void
          710 berror(char *s)
          711 {
          712     if(onerr)
          713         (*onerr)(s);
          714     else{
          715         fprintf(stderr, "libg error: %s:\n", s);
          716         exit(1);
          717     }
          718 }
          719 
          720 void
          721 bflush(void)
          722 {
          723     while(XtAppPending(app) & XtIMXEvent)
          724         waitevent();
          725 }
          726 
          727 static void
          728 waitevent(void)
          729 {
          730     XFlush(_dpy);
          731     if (XtAppPending(app) & XtIMXEvent)
          732         XtAppProcessEvent(app, XtIMXEvent);
          733     else
          734         XtAppProcessEvent(app, XtIMAll);
          735 }
          736         
          737 int
          738 snarfswap(char *s, int n, char **t)
          739 {
          740     *t = GwinSelectionSwap(widg, s);
          741     if (*t)
          742         return strlen(*t);
          743     return 0;
          744 }
          745 
          746 int scrpix(int *w, int *h)
          747 {
          748     if (w)
          749         *w = WidthOfScreen(XtScreen(_toplevel));
          750     if (h)
          751         *h = HeightOfScreen(XtScreen(_toplevel));
          752     return 1;
          753 }
          754 
          755 #ifdef DEBUG
          756 /* for debugging */
          757 printgc(char *msg, GC g)
          758 {
          759     XGCValues v;
          760 
          761     XGetGCValues(_dpy, g, GCFunction|GCForeground|GCBackground|GCFont|
          762             GCTile|GCFillStyle|GCStipple, &v);
          763     fprintf(stderr, "%s: gc %x\n", msg, g);
          764     fprintf(stderr, "  fg %d bg %d func %d fillstyle %d font %x tile %x stipple %x\n",
          765         v.foreground, v.background, v.function, v.fill_style,
          766         v.font, v.tile, v.stipple);
          767 }
          768 #endif
          769 
          770 void
          771 raisewindow(void)
          772 {
          773     XEvent e;
          774     Atom a = XInternAtom(_dpy, "_NET_ACTIVE_WINDOW", True);
          775 
          776     XRaiseWindow(_dpy, _topwindow);
          777 
          778     if (a != None){
          779         memset(&e, 0, sizeof(XEvent));
          780         e.type = ClientMessage;
          781         e.xclient.window = _topwindow;
          782         e.xclient.message_type = a;
          783         e.xclient.format = 32;
          784         e.xclient.data.l[0] = 1;
          785         e.xclient.data.l[1] = CurrentTime;
          786         e.xclient.data.l[2] = None;
          787         e.xclient.data.l[3] = 0;
          788         e.xclient.data.l[4] = 0;
          789 
          790         XSendEvent(_dpy, DefaultRootWindow(_dpy), False,
          791                    SubstructureRedirectMask | SubstructureNotifyMask, &e);
          792     }
          793 
          794     XFlush(_dpy);
          795 }
          796 
          797 uint64_t
          798 getbg(void)
          799 {
          800     static int i = 0;
          801 
          802     if (i >= _nbgs)
          803         i = 0;
          804 
          805     return _bgpixels[i++];
          806 }
          807