xtbinit.c - sam - An updated version of the sam text editor. | |
git clone git://vernunftzentrum.de/sam.git | |
Log | |
Files | |
Refs | |
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 **fallback… | |
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, arg… | |
177 | |
178 _dpy = XtDisplay(widg); | |
179 XAllocNamedColor(_dpy, DefaultColormap(_dpy, DefaultScreen(_dpy)), | |
180 foregroundspec[0] ? foregroundspec : getenv("FOREGR… | |
181 XAllocNamedColor(_dpy, DefaultColormap(_dpy, DefaultScreen(_dpy)), | |
182 borderspec[0] ? borderspec : getenv("BORDER") ? get… | |
183 char bgspec[1024] = {0}; | |
184 strncpy(bgspec, backgroundspec[0] ? backgroundspec : getenv("BACKGRO… | |
185 | |
186 char *bgc = NULL; | |
187 for (bgc = strtok(bgspec, ":"); bgc != NULL && _nbgs < MAX_BACKGROUN… | |
188 XColor xc = {0}; | |
189 if (XAllocNamedColor(_dpy, DefaultColormap(_dpy, DefaultScreen(_… | |
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] ? font… | |
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_W… | |
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)), D… | |
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 … | |
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 |