1 /*
2  * Copyright (C) 1997-2009, Michael Jennings
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies of the Software, its documentation and marketing & publicity
13  * materials, and acknowledgment shall be given in the documentation, materials
14  * and software packages that this Software was used.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 
24 static const char cvs_ident[] = "$Id: buttons.c 51650 2010-08-26 01:34:13Z lucas $";
25 
26 #include "config.h"
27 #include "feature.h"
28 
29 #include <X11/cursorfont.h>
30 
31 #include "buttons.h"
32 #include "command.h"
33 #include "draw.h"
34 #include "e.h"
35 #include "events.h"
36 #include "font.h"
37 #include "startup.h"
38 #include "menus.h"
39 #include "misc.h"
40 #include "options.h"
41 #include "pixmap.h"
42 #include "screen.h"
43 #include "script.h"
44 #include "term.h"
45 #include "windows.h"
46 #ifdef ESCREEN
47 #  include "screamcfg.h"
48 #endif
49 
50 static inline void draw_string(buttonbar_t *, Drawable, GC, int, int, char *, size_t);
51 
52 buttonbar_t *buttonbar = NULL;
53 
54 #ifdef ESCREEN
55 button_t *drag = NULL;
56 #endif
57 long bbar_total_h = -1;
58 
59 static inline void
draw_string(buttonbar_t * bbar,Drawable d,GC gc,int x,int y,char * str,size_t len)60 draw_string(buttonbar_t *bbar, Drawable d, GC gc, int x, int y, char *str, size_t len)
61 {
62 
63     D_BBAR(("Writing string \"%s\" (length %lu) using font 0x%08x onto drawable 0x%08x at %d, %d\n",
64             str, len, bbar->font, d, x, y));
65     REQUIRE(bbar != NULL);
66     REQUIRE(d != None);
67     REQUIRE(gc != None);
68 
69 #ifdef MULTI_CHARSET
70     if (bbar->fontset && encoding_method != LATIN1)
71         XmbDrawString(Xdisplay, d, bbar->fontset, gc, x, y, str, len);
72     else
73 #endif
74         XDrawString(Xdisplay, d, gc, x, y, str, len);
75     return;
76 }
77 
bbar_create(void)78 buttonbar_t *bbar_create(void)
79 {
80     buttonbar_t *bbar;
81     Cursor cursor;
82     long mask;
83     XGCValues gcvalue;
84     XSetWindowAttributes xattr;
85 
86     bbar = (buttonbar_t *) MALLOC(sizeof(buttonbar_t));
87     MEMSET(bbar, 0, sizeof(buttonbar_t));
88 
89     xattr.border_pixel = BlackPixel(Xdisplay, Xscreen);
90     xattr.save_under = FALSE;
91     xattr.override_redirect = TRUE;
92     xattr.colormap = cmap;
93 
94     cursor = XCreateFontCursor(Xdisplay, XC_left_ptr);
95     mask = KeyPressMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask
96         | ButtonMotionMask | ButtonPressMask | ButtonReleaseMask;
97     gcvalue.foreground = xattr.border_pixel;
98 
99     bbar->font = load_font(etfonts[def_font_idx], "fixed", FONT_TYPE_X);
100     bbar->fwidth = bbar->font->max_bounds.width;
101     bbar->fheight = bbar->font->ascent + bbar->font->descent;
102     bbar->h = 1;
103     bbar->w = 1;
104     gcvalue.font = bbar->font->fid;
105 
106     bbar->win = XCreateWindow(Xdisplay, Xroot, bbar->x, bbar->y, bbar->w, bbar->h, 0, Xdepth, InputOutput, CopyFromParent,
107                               CWOverrideRedirect | CWSaveUnder | CWBorderPixel | CWColormap, &xattr);
108     XDefineCursor(Xdisplay, bbar->win, cursor);
109     XSelectInput(Xdisplay, bbar->win, mask);
110     XStoreName(Xdisplay, bbar->win, "Eterm Button Bar");
111 
112     bbar->gc = LIBAST_X_CREATE_GC(GCForeground | GCFont, &gcvalue);
113     bbar_set_docked(bbar, BBAR_DOCKED_TOP);
114     bbar_set_visible(bbar, 1);
115     bbar->image_state = IMAGE_STATE_CURRENT;
116 
117     D_BBAR(("bbar created:  Window 0x%08x, dimensions %dx%d\n", bbar->win, bbar->w, bbar->h));
118     return bbar;
119 }
120 
121 void
bbar_free(buttonbar_t * bbar)122 bbar_free(buttonbar_t *bbar)
123 {
124     if (bbar->next) {
125         bbar_free(bbar->next);
126     }
127     if (bbar->rbuttons) {
128         button_free(bbar->rbuttons);
129     }
130     if (bbar->buttons) {
131         button_free(bbar->buttons);
132     }
133 #ifdef MULTI_CHARSET
134     if (bbar->fontset) {
135         XFreeFontSet(Xdisplay, bbar->fontset);
136     }
137 #endif
138     if (bbar->font) {
139         free_font(bbar->font);
140     }
141     if (bbar->gc != None) {
142         LIBAST_X_FREE_GC(bbar->gc);
143     }
144     if (bbar->win != None) {
145         XDestroyWindow(Xdisplay, bbar->win);
146     }
147     FREE(bbar);
148 }
149 
150 void
bbar_init(buttonbar_t * bbar,int width)151 bbar_init(buttonbar_t *bbar, int width)
152 {
153     event_register_dispatcher(bbar_dispatch_event, bbar_event_init_dispatcher);
154     for (; bbar; bbar = bbar->next) {
155         XSetForeground(Xdisplay, bbar->gc, images[image_bbar].norm->fg);
156         bbar_redock(bbar);
157         if (bbar_is_visible(bbar)) {
158             bbar_set_visible(bbar, 0);
159             bbar_show(bbar, 1);
160         }
161         bbar_resize(bbar, -width);
162         bbar_reset_total_height();
163     }
164 }
165 
166 void
bbar_event_init_dispatcher(void)167 bbar_event_init_dispatcher(void)
168 {
169     buttonbar_t *bbar;
170 
171     /* FIXME:  The event subsystem needs to be able to pass a pointer to the event data structure. */
172     EVENT_DATA_ADD_HANDLER(buttonbar->event_data, EnterNotify, bbar_handle_enter_notify);
173     EVENT_DATA_ADD_HANDLER(buttonbar->event_data, LeaveNotify, bbar_handle_leave_notify);
174     EVENT_DATA_ADD_HANDLER(buttonbar->event_data, ButtonPress, bbar_handle_button_press);
175     EVENT_DATA_ADD_HANDLER(buttonbar->event_data, ButtonRelease, bbar_handle_button_release);
176     EVENT_DATA_ADD_HANDLER(buttonbar->event_data, MotionNotify, bbar_handle_motion_notify);
177 
178     for (bbar = buttonbar; bbar; bbar = bbar->next) {
179         event_data_add_mywin(&buttonbar->event_data, bbar->win);
180     }
181 }
182 
183 unsigned char
bbar_handle_enter_notify(event_t * ev)184 bbar_handle_enter_notify(event_t *ev)
185 {
186     buttonbar_t *bbar;
187     button_t *b;
188     Window unused_root, unused_child;
189     int unused_root_x, unused_root_y;
190     unsigned int unused_mask;
191 
192     D_EVENTS(("bbar_handle_enter_notify(ev [%8p] on window 0x%08x)\n", ev, ev->xany.window));
193 
194     REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &buttonbar->event_data), 0);
195 
196     if (!(bbar = find_bbar_by_window(ev->xany.window))) {
197         return 0;
198     }
199     bbar_draw(bbar, IMAGE_STATE_SELECTED, 0);
200     XQueryPointer(Xdisplay, bbar->win, &unused_root, &unused_child, &unused_root_x, &unused_root_y, &(ev->xbutton.x),
201                   &(ev->xbutton.y), &unused_mask);
202     b = find_button_by_coords(bbar, ev->xbutton.x, ev->xbutton.y);
203     if (b) {
204         bbar_select_button(bbar, b);
205     }
206     return 1;
207 }
208 
209 unsigned char
bbar_handle_leave_notify(event_t * ev)210 bbar_handle_leave_notify(event_t *ev)
211 {
212     buttonbar_t *bbar;
213 
214     D_EVENTS(("bbar_handle_leave_notify(ev [%8p] on window 0x%08x)\n", ev, ev->xany.window));
215 
216     REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &buttonbar->event_data), 0);
217 
218     if (!(bbar = find_bbar_by_window(ev->xany.window))) {
219         return 0;
220     }
221     bbar_draw(bbar, IMAGE_STATE_NORMAL, 0);
222     if (bbar->current) {
223         bbar_deselect_button(bbar, bbar->current);
224     }
225     return 1;
226 }
227 
228 unsigned char
bbar_handle_button_press(event_t * ev)229 bbar_handle_button_press(event_t *ev)
230 {
231     buttonbar_t *bbar;
232 
233     D_EVENTS(("bbar_handle_button_press(ev [%8p] on window 0x%08x)\n", ev, ev->xany.window));
234 
235     REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &buttonbar->event_data), 0);
236 
237     if (!(bbar = find_bbar_by_window(ev->xany.window))) {
238         D_EVENTS((" -> No buttonbar found for this window.\n"));
239         return 0;
240     }
241     if (bbar->current) {
242         bbar_click_button(bbar, bbar->current);
243         button_check_action(bbar, bbar->current, ev->xbutton.button, ev->xbutton.time);
244 #ifdef ESCREEN
245         drag = bbar->current;
246 #endif
247     }
248     return 1;
249 }
250 
251 unsigned char
bbar_handle_button_release(event_t * ev)252 bbar_handle_button_release(event_t *ev)
253 {
254     buttonbar_t *bbar;
255     button_t *b;
256     Window unused_root, unused_child;
257     int unused_root_x, unused_root_y;
258     unsigned int unused_mask;
259 
260     D_EVENTS(("bbar_handle_button_release(ev [%8p] on window 0x%08x)\n", ev, ev->xany.window));
261 
262 #ifdef ESCREEN
263     if (drag && TermWin.screen && TermWin.screen->backend && TermWin.screen->userdef) {
264         buttonbar_t *bbar = (buttonbar_t *) TermWin.screen->userdef;
265         button_t *b;
266         int fm = 0, to = 0;
267 
268         D_ESCREEN(("Checking for dragged button.\n"));
269         if (bbar && (b = bbar->buttons) && (drag != bbar->current)) {
270             while (b && (b != drag)) {
271                 b = b->next;
272                 fm++;
273             }
274             if (!b) {
275                 D_ESCREEN((" -> Dragged button is not on the Escreen buttonbar.\n"));
276                 drag = NULL;
277             } else {
278 
279                 if (bbar->current) {
280                     b = bbar->buttons;
281                     while (b && (b != bbar->current)) {
282                         b = b->next;
283                         to++;
284                     }
285                     if (!b) {
286                         D_ESCREEN((" -> Target button is not on the Escreen buttonbar.\n"));
287                         drag = NULL;
288                     }
289                 }
290             }
291         } else {
292             drag = NULL;
293         }
294 
295         if (drag) {
296             if (!bbar->current) {
297                 char *u = ns_get_url(TermWin.screen, fm);
298 
299                 D_ESCREEN(("Button for display %d dragged off.\n", fm));
300                 if (u) {
301                     char *c;
302                     size_t l = strlen(orig_argv0) + strlen(u) + 7;
303 
304                     if ((c = MALLOC(l))) {
305                         snprintf(c, l, "%s%s -U %s", ((orig_argv0[0] == '/')
306                                                       || ((orig_argv0[0] == '.')
307                                                           && (orig_argv0[1] == '/'))) ? "" : "./", orig_argv0, u);
308                         D_ESCREEN(("(experimental) creating other frame using \"%s\"\n", c));
309                         (void) ns_run(TermWin.screen->efuns, c);
310                         FREE(c);
311                     }
312                     FREE(u);
313                 }
314                 return 1;
315             } else if (bbar->current != drag) {
316                 D_ESCREEN(("Button for display %d dragged to display %d\n", fm, to));
317                 ns_mov_disp(TermWin.screen, fm, to);
318                 bbar->current = drag = NULL;
319                 return 1;
320             }
321         }
322     }
323     D_ESCREEN(("No drag detected.  Proceeding with normal handling.\n"));
324     drag = NULL;
325 #endif
326 
327     REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &buttonbar->event_data), 0);
328 
329     if (!(bbar = find_bbar_by_window(ev->xany.window))) {
330         D_EVENTS((" -> No buttonbar found for this window.\n"));
331         return 0;
332     }
333 
334     XQueryPointer(Xdisplay, bbar->win, &unused_root, &unused_child, &unused_root_x, &unused_root_y, &(ev->xbutton.x),
335                   &(ev->xbutton.y), &unused_mask);
336 
337     b = find_button_by_coords(bbar, ev->xbutton.x, ev->xbutton.y);
338     if (b) {
339         D_EVENTS(("Event in buttonbar %8p, button %8p (%s)\n", bbar, b, NONULL(b->text)));
340         if (bbar->current && (b != bbar->current)) {
341             D_EVENTS(("Current button %8p (%s) doesn't match event button %8p (%s)\n", bbar->current, NONULL(bbar->current->text),
342                       b, NONULL(b->text)));
343             bbar_deselect_button(bbar, bbar->current);
344         } else {
345             bbar_select_button(bbar, b);
346             button_check_action(bbar, b, 0, ev->xbutton.time);
347         }
348     } else {
349         D_EVENTS(("Event in buttonbar %8p but no button.\n", bbar));
350     }
351     return 1;
352 }
353 
354 unsigned char
bbar_handle_motion_notify(event_t * ev)355 bbar_handle_motion_notify(event_t *ev)
356 {
357     buttonbar_t *bbar;
358     button_t *b;
359     Window unused_root, unused_child;
360     int unused_root_x, unused_root_y;
361     unsigned int mask;
362 
363     D_EVENTS(("bbar_handle_motion_notify(ev [%8p] on window 0x%08x)\n", ev, ev->xany.window));
364 
365     REQUIRE_RVAL(XEVENT_IS_MYWIN(ev, &buttonbar->event_data), 0);
366 
367     if (!(bbar = find_bbar_by_window(ev->xany.window))) {
368         return 0;
369     }
370     while (XCheckTypedWindowEvent(Xdisplay, ev->xany.window, MotionNotify, ev));
371     XQueryPointer(Xdisplay, bbar->win, &unused_root, &unused_child, &unused_root_x, &unused_root_y, &(ev->xbutton.x),
372                   &(ev->xbutton.y), &mask);
373     D_BBAR((" -> Pointer is at %d, %d with mask 0x%08x\n", ev->xbutton.x, ev->xbutton.y, mask));
374 
375     b = find_button_by_coords(bbar, ev->xbutton.x, ev->xbutton.y);
376     if (b != bbar->current) {
377         if (bbar->current) {
378             bbar_deselect_button(bbar, bbar->current);
379         }
380         if (b) {
381             if (mask & (Button1Mask | Button2Mask | Button3Mask)) {
382                 bbar_click_button(bbar, b);
383             } else {
384                 bbar_select_button(bbar, b);
385             }
386         }
387     }
388 
389     return 1;
390 }
391 
392 unsigned char
bbar_dispatch_event(event_t * ev)393 bbar_dispatch_event(event_t *ev)
394 {
395     if (buttonbar->event_data.handlers[ev->type]) {
396         return ((buttonbar->event_data.handlers[ev->type]) (ev));
397     }
398     return (0);
399 }
400 
find_bbar_by_window(Window win)401 buttonbar_t *find_bbar_by_window(Window win)
402 {
403     buttonbar_t *bbar;
404 
405     for (bbar = buttonbar; bbar; bbar = bbar->next) {
406         if (bbar->win == win) {
407             return bbar;
408         }
409     }
410     return ((buttonbar_t *) NULL);
411 }
412 
413 void
bbar_add(buttonbar_t * bbar)414 bbar_add(buttonbar_t *bbar)
415 {
416     if (buttonbar) {
417         buttonbar_t *bb;
418 
419         for (bb = buttonbar; bb->next; bb = bb->next);
420         bb->next = bbar;
421     } else {
422         buttonbar = bbar;
423     }
424     bbar->next = NULL;
425     bbar_reset_total_height();
426     event_data_add_mywin(&buttonbar->event_data, bbar->win);
427 }
428 
429 unsigned short
bbar_calc_height(buttonbar_t * bbar)430 bbar_calc_height(buttonbar_t *bbar)
431 {
432     button_t *b;
433     Imlib_Border *bbord, *bord;
434 
435     D_BBAR(("bbar_calc_height(%8p):  font ascent == %d, font descent == %d, h == %d\n",
436             bbar, bbar->font->ascent, bbar->font->descent, bbar->h));
437 
438     if (image_mode_is(image_bbar, MODE_MASK)) {
439         bbord = images[image_bbar].norm->iml->border;
440     } else if (images[image_bbar].norm->iml->bevel) {
441         bbord = images[image_bbar].norm->iml->bevel->edges;
442     } else {
443         bbord = NULL;
444     }
445     if (image_mode_is(image_button, MODE_MASK)) {
446         bord = images[image_button].norm->iml->border;
447     } else if (images[image_button].norm->iml->bevel) {
448         bord = images[image_button].norm->iml->bevel->edges;
449     } else {
450         bord = NULL;
451     }
452 
453     bbar->h = bbar->fheight + 1;
454     if (bord) {
455         bbar->h += bord->top + bord->bottom;
456     }
457 
458     for (b = bbar->buttons; b; b = b->next) {
459         if (b->h != bbar->h) {
460             b->h = bbar->h;
461             button_calc_size(bbar, b);
462         }
463     }
464     for (b = bbar->rbuttons; b; b = b->next) {
465         if (b->h != bbar->h) {
466             b->h = bbar->h;
467             button_calc_size(bbar, b);
468         }
469     }
470     if (bbord) {
471         bbar->h += bbord->top + bbord->bottom;
472     }
473     D_BBAR(("Final height is %d\n", bbar->h));
474     return bbar->h;
475 }
476 
477 void
bbar_calc_button_sizes(buttonbar_t * bbar)478 bbar_calc_button_sizes(buttonbar_t *bbar)
479 {
480     button_t *b;
481 
482     D_BBAR(("bbar == %8p\n", bbar));
483 
484     for (b = bbar->buttons; b; b = b->next) {
485         button_calc_size(bbar, b);
486     }
487     for (b = bbar->rbuttons; b; b = b->next) {
488         button_calc_size(bbar, b);
489     }
490 }
491 
492 void
bbar_calc_button_positions(buttonbar_t * bbar)493 bbar_calc_button_positions(buttonbar_t *bbar)
494 {
495     button_t *b;
496     unsigned short x, y;
497     Imlib_Border *border;
498 
499     D_BBAR(("bbar == %8p\n", bbar));
500 
501     if (image_mode_is(image_bbar, MODE_MASK)) {
502         border = images[image_bbar].norm->iml->border;
503     } else if (images[image_bbar].norm->iml->bevel) {
504         border = images[image_bbar].norm->iml->bevel->edges;
505     } else {
506         border = NULL;
507     }
508 
509     y = ((border) ? (border->top) : 0);
510     if (bbar->buttons) {
511         x = ((border) ? (border->left) : 0) + MENU_HGAP;
512         for (b = bbar->buttons; b; b = b->next) {
513             b->x = x;
514             b->y = y;
515             D_BBAR(("Set button \"%s\" (%8p, width %d) to coordinates %d, %d\n", b->text, b, b->w, x, y));
516             x += b->w + MENU_HGAP;
517             button_calc_rel_coords(bbar, b);
518         }
519     }
520     if (bbar->rbuttons) {
521         x = bbar->w - ((border) ? (border->right) : 0);
522         for (b = bbar->rbuttons; b; b = b->next) {
523             x -= b->w + MENU_HGAP;
524             b->x = x;
525             b->y = y;
526             button_calc_rel_coords(bbar, b);
527             D_BBAR(("Set rbutton \"%s\" (%8p, width %d) to coordinates %d, %d\n", b->text, b, b->w, x, y));
528         }
529     }
530 }
531 
532 void
button_calc_size(buttonbar_t * bbar,button_t * button)533 button_calc_size(buttonbar_t *bbar, button_t *button)
534 {
535     Imlib_Border *bord;
536     int ascent, descent, direction;
537     XCharStruct chars;
538 
539     D_BBAR(("button_calc_size(%8p, %8p):  XTextExtents(%8p, %s, %d, ...)\n", bbar, button, bbar->font, button->text, button->len));
540 
541     if (image_mode_is(image_button, MODE_MASK)) {
542         bord = images[image_button].norm->iml->border;
543     } else if (images[image_button].norm->iml->bevel) {
544         bord = images[image_button].norm->iml->bevel->edges;
545     } else {
546         bord = NULL;
547     }
548 
549     button->w = 0;
550     if (button->len) {
551         XTextExtents(bbar->font, button->text, button->len, &direction, &ascent, &descent, &chars);
552         button->w += chars.width;
553     }
554     if (bord) {
555         button->w += bord->left + bord->right;
556     }
557     if (button->h == 0) {
558         button->h = bbar->font->ascent + bbar->font->descent + 1;
559         if (bord) {
560             button->h += bord->top + bord->bottom;
561         }
562     }
563 #ifdef PIXMAP_SUPPORT
564     if (button->icon) {
565         unsigned short b;
566 
567         if (bord) {
568             b = button->h - bord->top - bord->bottom;
569         } else {
570             b = button->h;
571         }
572         imlib_context_set_image(button->icon->iml->im);
573         button->icon_w = imlib_image_get_width();
574         button->icon_h = imlib_image_get_height();
575         D_BBAR((" -> Initial icon dimensions are %hux%hu\n", button->icon_w, button->icon_h));
576         if (button->icon_h > b) {
577             button->icon_w = (unsigned short) ((float) button->icon_w / button->icon_h * b);
578             button->icon_h = b;
579         }
580         button->w += button->icon_w;
581         if (button->len) {
582             button->w += MENU_HGAP;
583         }
584         D_BBAR((" -> Final icon dimensions are %hux%hu\n", button->icon_w, button->icon_h));
585     }
586 #endif
587     D_BBAR((" -> Set button to %dx%d at %d, %d and icon to %dx%d\n", button->w, button->h, button->x, button->y, button->icon_w,
588             button->icon_h));
589 }
590 
591 void
button_calc_rel_coords(buttonbar_t * bbar,button_t * button)592 button_calc_rel_coords(buttonbar_t *bbar, button_t *button)
593 {
594     Imlib_Border *bord;
595 
596     D_BBAR(("bbar == %8p, button == %8p\n", bbar, button));
597 
598     if (image_mode_is(image_button, MODE_MASK)) {
599         bord = images[image_button].norm->iml->border;
600     } else if (images[image_button].norm->iml->bevel) {
601         bord = images[image_button].norm->iml->bevel->edges;
602     } else {
603         bord = NULL;
604     }
605 
606 #ifdef PIXMAP_SUPPORT
607     if (button->icon) {
608         unsigned short b = 0;
609 
610         if (bord) {
611             b = button->h - bord->top - bord->bottom - 2;
612         }
613         if (button->icon_h == button->h) {
614             button->icon_y = button->y + ((bord) ? (bord->top) : 0);
615         } else {
616             button->icon_y = button->y + ((b - button->icon_h) / 2) + ((bord) ? (bord->top) : 0);
617         }
618         button->icon_x = button->x + ((bord) ? (bord->left) : 0);
619     }
620 #endif
621 
622     if (button->len) {
623         button->text_x = button->x + ((button->icon_w) ? (button->icon_w + MENU_HGAP) : 0) + ((bord) ? (bord->left) : (0));
624         button->text_y = button->y + button->h - ((bord) ? (bord->bottom) : (0)) - bbar->font->descent;
625     }
626     D_BBAR((" -> Text is at %d, %d and icon is at %d, %d\n", button->text_x, button->text_y, button->icon_x, button->icon_y));
627 }
628 
629 void
bbar_add_button(buttonbar_t * bbar,button_t * button)630 bbar_add_button(buttonbar_t *bbar, button_t *button)
631 {
632     button_t *b;
633 
634     D_BBAR(("bbar_add_button(%8p, %8p):  Adding button \"%s\".\n", bbar, button, button->text));
635 
636     ASSERT(bbar != NULL);
637 
638     if (bbar->buttons) {
639         for (b = bbar->buttons; b->next; b = b->next);
640         b->next = button;
641     } else {
642         bbar->buttons = button;
643     }
644     button->next = NULL;
645 }
646 
647 void
bbar_add_rbutton(buttonbar_t * bbar,button_t * button)648 bbar_add_rbutton(buttonbar_t *bbar, button_t *button)
649 {
650     button_t *b;
651 
652     D_BBAR(("bbar_add_rbutton(%8p, %8p):  Adding right-justified button \"%s\".\n", bbar, button, button->text));
653 
654     b = ((bbar->rbuttons) ? (bbar->rbuttons) : NULL);
655     bbar->rbuttons = button;
656     button->next = b;
657 }
658 
659 unsigned char
bbar_set_font(buttonbar_t * bbar,const char * fontname)660 bbar_set_font(buttonbar_t *bbar, const char *fontname)
661 {
662     XFontStruct *font;
663 
664     ASSERT_RVAL(fontname != NULL, 0);
665 
666     D_BBAR(("bbar_set_font(%8p, \"%s\"):  Current font is %8p, dimensions %d/%d/%d\n", bbar, fontname, bbar->font, bbar->fwidth,
667             bbar->fheight, bbar->h));
668     if (bbar->font) {
669         free_font(bbar->font);
670     }
671 #ifdef MULTI_CHARSET
672     if (bbar->fontset) {
673         XFreeFontSet(Xdisplay, bbar->fontset);
674     }
675 #endif
676 
677     font = (XFontStruct *) load_font(fontname, "fixed", FONT_TYPE_X);
678 #ifdef MULTI_CHARSET
679     bbar->fontset = create_fontset(fontname, etmfonts[def_font_idx]);
680 #endif
681 
682     bbar->font = font;
683     bbar->fwidth = font->max_bounds.width;
684     bbar->fheight = font->ascent + font->descent;
685     XSetFont(Xdisplay, bbar->gc, font->fid);
686     bbar_reset_total_height();
687     D_BBAR(("Font is \"%s\" (0x%08x).  New dimensions are %d/%d/%d\n", NONULL(fontname), font, bbar->fwidth, bbar->fheight,
688             bbar->h));
689 
690     bbar_calc_height(bbar);
691     return 1;
692 }
693 
find_button_by_text(buttonbar_t * bbar,char * text)694 button_t *find_button_by_text(buttonbar_t *bbar, char *text)
695 {
696     register button_t *b;
697 
698     REQUIRE_RVAL(text != NULL, NULL);
699 
700     for (b = bbar->buttons; b; b = b->next) {
701         if (!strcasecmp(b->text, text)) {
702             return (b);
703         }
704     }
705     for (b = bbar->rbuttons; b; b = b->next) {
706         if (!strcasecmp(b->text, text)) {
707             return (b);
708         }
709     }
710     return NULL;
711 }
712 
find_button_by_index(buttonbar_t * bbar,long idx)713 button_t *find_button_by_index(buttonbar_t *bbar, long idx)
714 {
715     register button_t *b;
716     long i;
717 
718     if (idx < 0) {
719         idx = -idx;
720         b = bbar->rbuttons;
721     } else {
722         b = bbar->buttons;
723     }
724     for (i = 0; (b) && (i < idx); b = b->next, i++);
725     return ((i == idx) ? (b) : (NULL));
726 }
727 
find_button_by_coords(buttonbar_t * bbar,int x,int y)728 button_t *find_button_by_coords(buttonbar_t *bbar, int x, int y)
729 {
730     register button_t *b;
731 
732     ASSERT_RVAL(bbar != NULL, NULL);
733 
734     for (b = bbar->buttons; b; b = b->next) {
735         if ((x >= b->x) && (y >= b->y) && (x < b->x + b->w) && (y < b->y + b->h)) {
736             return (b);
737         }
738     }
739     for (b = bbar->rbuttons; b; b = b->next) {
740         if ((x >= b->x) && (y >= b->y) && (x < b->x + b->w) && (y < b->y + b->h)) {
741             return (b);
742         }
743     }
744     return NULL;
745 }
746 
button_create(char * text)747 button_t *button_create(char *text)
748 {
749     button_t *button;
750 
751     button = (button_t *) MALLOC(sizeof(button_t));
752     MEMSET(button, 0, sizeof(button_t));
753 
754     if (text) {
755         button->text = STRDUP(text);
756         button->len = strlen(text);
757     } else {
758         button->text = STRDUP("");
759         button->len = 0;
760     }
761     return button;
762 }
763 
764 void
button_free(button_t * button)765 button_free(button_t *button)
766 {
767     if (button->next) {
768         button_free(button->next);
769     }
770     if (button->text) {
771         FREE(button->text);
772     }
773     if (button->type == ACTION_STRING || button->type == ACTION_ECHO) {
774         FREE(button->action.string);
775     }
776     if (button->icon) {
777         free_simage(button->icon);
778     }
779     FREE(button);
780 }
781 
782 unsigned char
button_set_text(button_t * button,const char * text)783 button_set_text(button_t *button, const char *text)
784 {
785     ASSERT_RVAL(button != NULL, 0);
786 
787     if (button->text) {
788         FREE(button->text);
789     }
790     if (text) {
791         button->text = STRDUP(text);
792         button->len = strlen(text);
793     } else {
794         button->text = STRDUP("");
795         button->len = 0;
796     }
797     return 1;
798 }
799 
800 unsigned char
button_set_icon(button_t * button,simage_t * icon)801 button_set_icon(button_t *button, simage_t *icon)
802 {
803     ASSERT_RVAL(button != NULL, 0);
804     ASSERT_RVAL(icon != NULL, 0);
805 
806     button->icon = icon;
807     return 1;
808 }
809 
810 unsigned char
button_set_action(button_t * button,action_type_t type,char * action)811 button_set_action(button_t *button, action_type_t type, char *action)
812 {
813     ASSERT_RVAL(button != NULL, 0);
814 
815     button->type = type;
816     switch (type) {
817         case ACTION_MENU:
818             button->action.menu = find_menu_by_title(menu_list, action);
819             return ((!button->action.menu) ? (0) : (1));
820             break;
821         case ACTION_STRING:
822         case ACTION_ECHO:
823             button->action.string = (char *) MALLOC(strlen(action) + 2);
824             strcpy(button->action.string, action);
825             parse_escaped_string(button->action.string);
826             return ((!button->action.string) ? (0) : (1));
827             break;
828         case ACTION_SCRIPT:
829             button->action.script = (char *) MALLOC(strlen(action) + 2);
830             strcpy(button->action.script, action);
831             return ((!button->action.script) ? (0) : (1));
832             break;
833         default:
834             break;
835     }
836     return 0;
837 }
838 
839 void
bbar_select_button(buttonbar_t * bbar,button_t * button)840 bbar_select_button(buttonbar_t *bbar, button_t *button)
841 {
842     bbar->current = button;
843     if (image_mode_is(image_button, MODE_MASK)) {
844         paste_simage(images[image_button].selected, image_button, bbar->win, bbar->win, button->x, button->y, button->w, button->h);
845     } else {
846         Pixel p1, p2;
847 
848         p1 = get_top_shadow_color(images[image_button].selected->bg, "");
849         p2 = get_bottom_shadow_color(images[image_button].selected->bg, "");
850         XSetForeground(Xdisplay, bbar->gc, images[image_button].selected->bg);
851         XFillRectangle(Xdisplay, bbar->win, bbar->gc, button->x, button->y, button->w, button->h);
852         draw_shadow_from_colors(bbar->win, p1, p2, button->x, button->y, button->w, button->h, 2);
853     }
854     if (image_mode_is(image_button, MODE_AUTO)) {
855         enl_ipc_sync();
856     }
857     if (button->icon) {
858         paste_simage(button->icon, image_max, bbar->win, bbar->win, button->icon_x, button->icon_y, button->icon_w, button->icon_h);
859     }
860     if (button->len) {
861         XSetForeground(Xdisplay, bbar->gc, images[image_bbar].selected->fg);
862         draw_string(bbar, bbar->win, bbar->gc, button->text_x, button->text_y, button->text, button->len);
863         XSetForeground(Xdisplay, bbar->gc, images[image_bbar].norm->fg);
864     }
865 }
866 
867 void
bbar_deselect_button(buttonbar_t * bbar,button_t * button)868 bbar_deselect_button(buttonbar_t *bbar, button_t *button)
869 {
870     XClearArea(Xdisplay, bbar->win, button->x, button->y, button->w, button->h, False);
871     bbar->current = NULL;
872 }
873 
874 void
bbar_click_button(buttonbar_t * bbar,button_t * button)875 bbar_click_button(buttonbar_t *bbar, button_t *button)
876 {
877     REQUIRE(button != NULL);
878 
879     D_BBAR(("Drawing clicked button %8p (%s) on buttonbar %8p\n", button, NONULL(button->text), bbar));
880 
881     bbar->current = button;
882     if (image_mode_is(image_button, MODE_MASK)) {
883         paste_simage(images[image_button].clicked, image_button, bbar->win, bbar->win, button->x, button->y, button->w, button->h);
884     } else {
885         draw_shadow_from_colors(bbar->win, PixColors[menuBottomShadowColor], PixColors[menuTopShadowColor], button->x, button->y,
886                                 button->w, button->h, 2);
887     }
888     if (image_mode_is(image_button, MODE_AUTO)) {
889         enl_ipc_sync();
890     }
891     if (button->icon) {
892         paste_simage(button->icon, image_max, bbar->win, bbar->win, button->icon_x, button->icon_y, button->icon_w, button->icon_h);
893     }
894     if (button->len) {
895         XSetForeground(Xdisplay, bbar->gc, images[image_bbar].clicked->fg);
896         draw_string(bbar, bbar->win, bbar->gc, button->text_x, button->text_y, button->text, button->len);
897         XSetForeground(Xdisplay, bbar->gc, images[image_bbar].norm->fg);
898     }
899 }
900 
901 void
button_check_action(buttonbar_t * bbar,button_t * button,unsigned char press,Time t)902 button_check_action(buttonbar_t *bbar, button_t *button, unsigned char press, Time t)
903 {
904     static unsigned char prvs = 0;
905 
906     REQUIRE(button != NULL);
907 
908     D_BBAR(("Checking action for button %8p (%s) on buttonbar %8p, press %d, prvs %d, time %lu\n", button, NONULL(button->text),
909             bbar, (int) press, (int) prvs, (unsigned long) t));
910 
911     switch (button->type) {
912         case ACTION_MENU:
913             D_BBAR((" -> Menu button found.\n"));
914             if (press) {
915                 menu_invoke(button->x, button->y + button->h, bbar->win, button->action.menu, t);
916             }
917             break;
918         case ACTION_STRING:
919             D_BBAR((" -> String button found.\n"));
920             if (!press) {
921                 size_t len;
922 
923                 len = strlen(button->action.string);
924                 D_BBAR(("Writing \"%s\" to command buffer.\n", safe_print_string(button->action.string, len)));
925                 cmd_write((unsigned char *) button->action.string, strlen(button->action.string));
926             }
927             break;
928         case ACTION_ECHO:
929             D_BBAR((" -> Echo button found.\n"));
930             if (!press) {
931                 size_t len;
932 
933 #ifdef ESCREEN
934                 if (TermWin.screen && TermWin.screen->backend) {        /* translate escapes */
935                     button_t *b = bbar->buttons;
936                     _ns_disp *d2 = TermWin.screen->dsps;
937                     int n = (button->action.string)[1] - '0';
938 
939                     if (b && (b->flags & NS_SCREAM_BUTTON)) {
940                         D_ESCREEN(("Looking for active display, n == %d, press == %d, prvs == %d\n", n, (int) press, (int) prvs));
941                         if (prvs != 1) {
942                             /* find active disp */
943                             for (; b && !(b->flags & NS_SCREAM_CURR); b = b->next);
944 
945                             if (b && b != button) {
946                                 D_ESCREEN((" -> Found button %8p (%s) for current display.\n", b, NONULL(b->text)));
947 
948                                 /* when trying to change name of non- */
949                                 /* active display, make that disp active */
950                                 button->flags |= NS_SCREAM_CURR;
951                                 b->flags &= ~NS_SCREAM_CURR;
952                                 bbar_draw(bbar, IMAGE_STATE_CURRENT, MODE_MASK);
953                                 button->flags &= ~NS_SCREAM_CURR;
954                                 b->flags |= NS_SCREAM_CURR;
955 
956                                 for (; d2 && d2->index != n; d2 = d2->next);
957                                 if (d2) {
958                                     /* pre-adjust curr ptr */
959                                     TermWin.screen->curr = d2;
960                                 } else {
961                                     D_ESCREEN(("no display %d in this session : (\n", n));
962                                 }
963                                 ns_go2_disp(TermWin.screen, n);
964                             }
965 
966                             if (prvs == 2) {
967                                 /* middle button -- kill */
968                                 D_ESCREEN((" -> Remove display %d\n", n));
969                                 ns_rem_disp(TermWin.screen, n, TRUE);
970                             } else {
971                                 /* right button -- rename */
972                                 D_ESCREEN((" -> Rename display %d\n", n));
973                                 ns_ren_disp(TermWin.screen, n, NULL);
974                             }
975                         } else {
976                             /* left button -- select */
977                             D_ESCREEN((" -> Go to display %d\n", n));
978                             ns_go2_disp(TermWin.screen, n);
979                         }
980                         break;
981                     } else {
982                         D_ESCREEN(("Non-screen button, handling normally.\n"));
983                     }
984                 }
985 #endif
986 
987                 /* not in screen-mode, use normal facilities */
988                 len = strlen(button->action.string);
989                 D_BBAR(("Writing \"%s\" to subprocess.\n", safe_print_string(button->action.string, len)));
990                 tt_write((unsigned char *) button->action.string, len);
991             }
992             break;
993         case ACTION_SCRIPT:
994             D_BBAR((" -> Script button found.\n"));
995             if (!press) {
996                 script_parse((char *) button->action.script);
997             }
998             break;
999         default:
1000             D_BBAR((" -> Unknown button type 0x%08x?!\n", button->type));
1001             break;
1002     }
1003     prvs = press;
1004 }
1005 
1006 unsigned char
bbar_show(buttonbar_t * bbar,unsigned char visible)1007 bbar_show(buttonbar_t *bbar, unsigned char visible)
1008 {
1009     unsigned char changed = 0;
1010 
1011     D_BBAR(("bbar_show(%8p, %d) called.\n", bbar, visible));
1012     if (visible && !bbar_is_visible(bbar)) {
1013         D_BBAR((" -> Making bbar visible.\n"));
1014         bbar_set_visible(bbar, 1);
1015         XMapWindow(Xdisplay, bbar->win);
1016         bbar_draw(bbar, IMAGE_STATE_CURRENT, MODE_MASK);
1017         changed = 1;
1018     } else if (!visible && bbar_is_visible(bbar)) {
1019         D_BBAR((" -> Making bbar invisible.\n"));
1020         bbar_set_visible(bbar, 0);
1021         XUnmapWindow(Xdisplay, bbar->win);
1022         changed = 1;
1023     }
1024     return changed;
1025 }
1026 
1027 void
bbar_show_all(signed char visible)1028 bbar_show_all(signed char visible)
1029 {
1030     buttonbar_t *bbar;
1031 
1032     D_BBAR(("visible == %d\n", (int) visible));
1033     for (bbar = buttonbar; bbar; bbar = bbar->next) {
1034         bbar_show(bbar, ((visible == -1) ? (!bbar_is_visible(bbar)) : visible));
1035     }
1036 }
1037 
1038 void
bbar_resize(buttonbar_t * bbar,int w)1039 bbar_resize(buttonbar_t *bbar, int w)
1040 {
1041     D_BBAR(("bbar_resize(%8p, %d) called.\n", bbar, w));
1042     if ((w >= 0) && !bbar_is_visible(bbar)) {
1043         D_BBAR((" -> Buttonbar is not visible, returning."));
1044         return;
1045     }
1046     if (w < 0) {
1047         bbar_calc_button_sizes(bbar);
1048         bbar_calc_height(bbar);
1049         bbar_reset_total_height();
1050         w = -w;
1051     }
1052     if (bbar->w != w) {
1053         bbar->w = w;
1054         bbar_calc_button_positions(bbar);
1055         D_BBAR(("Resizing window 0x%08x to %dx%d\n", bbar->win, bbar->w, bbar->h));
1056         XResizeWindow(Xdisplay, bbar->win, bbar->w, bbar->h);
1057         bbar_draw(bbar, IMAGE_STATE_CURRENT, MODE_MASK);
1058     }
1059 }
1060 
1061 void
bbar_resize_all(int width)1062 bbar_resize_all(int width)
1063 {
1064     buttonbar_t *bbar;
1065 
1066     D_BBAR(("width == %d\n", width));
1067     for (bbar = buttonbar; bbar; bbar = bbar->next) {
1068         bbar_resize(bbar, width);
1069     }
1070     bbar_calc_positions();
1071 }
1072 
1073 void
bbar_draw(buttonbar_t * bbar,unsigned char image_state,unsigned char force_modes)1074 bbar_draw(buttonbar_t *bbar, unsigned char image_state, unsigned char force_modes)
1075 {
1076     button_t *button;
1077 
1078     ASSERT(bbar != NULL);
1079 
1080     D_BBAR(("bbar_draw(%8p, 0x%02x, 0x%02x) called.\n", bbar, image_state, force_modes));
1081     if (image_state != IMAGE_STATE_CURRENT) {
1082         if ((image_state == IMAGE_STATE_NORMAL) && (bbar->image_state != IMAGE_STATE_NORMAL)) {
1083             images[image_bbar].current = images[image_bbar].norm;
1084             force_modes = MODE_MASK;
1085         } else if ((image_state == IMAGE_STATE_SELECTED) && (bbar->image_state != IMAGE_STATE_SELECTED)) {
1086             images[image_bbar].current = images[image_bbar].selected;
1087             force_modes = MODE_MASK;
1088         } else if ((image_state == IMAGE_STATE_CLICKED) && (bbar->image_state != IMAGE_STATE_CLICKED)) {
1089             images[image_bbar].current = images[image_bbar].clicked;
1090             force_modes = MODE_MASK;
1091         } else if ((image_state == IMAGE_STATE_DISABLED) && (bbar->image_state != IMAGE_STATE_DISABLED)) {
1092             images[image_bbar].current = images[image_bbar].disabled;
1093             force_modes = MODE_MASK;
1094         }
1095     }
1096     if (image_mode_is(image_bbar, MODE_MASK) && !((images[image_bbar].mode & MODE_MASK) & (force_modes))) {
1097         return;
1098     } else if (!bbar_is_visible(bbar)) {
1099         return;
1100     } else {
1101         render_simage(images[image_bbar].current, bbar->win, bbar->w, bbar->h, image_bbar, RENDER_FORCE_PIXMAP);
1102         bbar->bg = images[image_bbar].current->pmap->pixmap;
1103         REQUIRE(bbar->bg != None);
1104     }
1105     XSetForeground(Xdisplay, bbar->gc, images[image_bbar].current->fg);
1106     for (button = bbar->buttons; button; button = button->next) {
1107         if (button->icon) {
1108             paste_simage(button->icon, image_max, bbar->win, bbar->bg, button->icon_x, button->icon_y, button->icon_w,
1109                          button->icon_h);
1110         }
1111         if (button->len) {
1112 #ifdef ESCREEN
1113             /* evil temporary hack */
1114             int f = button->flags & ~NS_SCREAM_BUTTON;
1115 
1116             if (f & NS_SCREAM_CURR) {
1117                 f = ES_COLOR_CURRENT;
1118             } else if (f & NS_SCREAM_ACT) {
1119                 f = ES_COLOR_ACTIVE;
1120             } else {
1121                 f = 0;
1122             }
1123 
1124             D_BBAR(("bbar_draw: text \"%s\", color %d.\n", button->text, f));
1125             if (f) {
1126                 GC gc;
1127 
1128                 gc = LIBAST_X_CREATE_GC(0, NULL);
1129                 XCopyGC(Xdisplay, bbar->gc, GCFont, gc);
1130                 XSetForeground(Xdisplay, gc, PixColors[f]);
1131 
1132                 draw_string(bbar, bbar->bg, gc, button->text_x, button->text_y, button->text, button->len);
1133                 LIBAST_X_FREE_GC(gc);
1134             } else
1135 #endif
1136                 draw_string(bbar, bbar->bg, bbar->gc, button->text_x, button->text_y, button->text, button->len);
1137         }
1138     }
1139     for (button = bbar->rbuttons; button; button = button->next) {
1140         if (button->icon) {
1141             paste_simage(button->icon, image_max, bbar->win, bbar->bg, button->icon_x, button->icon_y, button->icon_w,
1142                          button->icon_h);
1143         }
1144         if (button->len) {
1145             draw_string(bbar, bbar->bg, bbar->gc, button->text_x, button->text_y, button->text, button->len);
1146         }
1147     }
1148     XSetWindowBackgroundPixmap(Xdisplay, bbar->win, bbar->bg);
1149     XClearWindow(Xdisplay, bbar->win);
1150     XSetForeground(Xdisplay, bbar->gc, images[image_bbar].norm->fg);
1151     if (bbar->current) {
1152         bbar_select_button(bbar, bbar->current);
1153     }
1154 }
1155 
1156 void
bbar_draw_all(unsigned char image_state,unsigned char force_modes)1157 bbar_draw_all(unsigned char image_state, unsigned char force_modes)
1158 {
1159     buttonbar_t *bbar;
1160 
1161     for (bbar = buttonbar; bbar; bbar = bbar->next) {
1162         bbar_draw(bbar, image_state, force_modes);
1163     }
1164 }
1165 
1166 void
bbar_dock(buttonbar_t * bbar,unsigned char dock)1167 bbar_dock(buttonbar_t *bbar, unsigned char dock)
1168 {
1169     D_BBAR(("bbar_dock(%8p, %d) called.\n", bbar, dock));
1170     if (dock == BBAR_DOCKED_TOP) {
1171         bbar_set_docked(bbar, BBAR_DOCKED_TOP);
1172         bbar_calc_positions();
1173     } else if (dock == BBAR_DOCKED_BOTTOM) {
1174         bbar_set_docked(bbar, BBAR_DOCKED_BOTTOM);
1175         bbar_calc_positions();
1176     } else {
1177         bbar_set_docked(bbar, 0);
1178         bbar_calc_positions();
1179         XReparentWindow(Xdisplay, bbar->win, Xroot, bbar->x, bbar->y);
1180         XMoveResizeWindow(Xdisplay, bbar->win, bbar->x, bbar->y, bbar->w, bbar->h);
1181     }
1182 }
1183 
1184 void
bbar_calc_positions(void)1185 bbar_calc_positions(void)
1186 {
1187     register buttonbar_t *bbar;
1188     unsigned short top_y, bottom_y;
1189 
1190     top_y = 0;
1191     bottom_y = szHint.height;
1192     for (bbar = buttonbar; bbar; bbar = bbar->next) {
1193         if (!bbar_is_visible(bbar) || !bbar_is_docked(bbar)) {
1194             D_BBAR(("Skipping invisible/undocked buttonbar %8p\n", bbar));
1195             continue;
1196         }
1197 
1198         D_BBAR(("top_y %lu, bottom_y %lu\n", top_y, bottom_y));
1199         bbar->x = 0;
1200         if (bbar_is_bottom_docked(bbar)) {
1201             bottom_y = bottom_y - bbar->h;
1202             bbar->y = bottom_y;
1203         } else {
1204             bbar->y = top_y;
1205             top_y += bbar->h;
1206         }
1207         D_BBAR(("Set coordinates for buttonbar %8p (window 0x%08x) to %lu, %lu\n", bbar, bbar->win, bbar->x, bbar->y));
1208         if (TermWin.parent != None) {
1209             XReparentWindow(Xdisplay, bbar->win, TermWin.parent, bbar->x, bbar->y);
1210             XMoveResizeWindow(Xdisplay, bbar->win, bbar->x, bbar->y, bbar->w, bbar->h);
1211         }
1212     }
1213 }
1214 
1215 unsigned long
bbar_calc_total_height(void)1216 bbar_calc_total_height(void)
1217 {
1218     register buttonbar_t *bbar;
1219 
1220     bbar_total_h = 0;
1221     for (bbar = buttonbar; bbar; bbar = bbar->next) {
1222         if (bbar_is_visible(bbar)) {
1223             bbar_total_h += bbar->h;
1224         }
1225     }
1226     D_BBAR(("Height of all visible buttonbars:  %lu\n", bbar_total_h));
1227     return bbar_total_h;
1228 }
1229 
1230 unsigned long
bbar_calc_docked_height(register unsigned char dock_flag)1231 bbar_calc_docked_height(register unsigned char dock_flag)
1232 {
1233     register buttonbar_t *bbar;
1234     register unsigned long h = 0;
1235 
1236     for (bbar = buttonbar; bbar; bbar = bbar->next) {
1237         if ((bbar->state & dock_flag) && bbar_is_visible(bbar)) {
1238             h += bbar->h;
1239         }
1240     }
1241     D_BBAR(("Height of buttonbars with dock state 0x%02x:  %lu\n", (unsigned) dock_flag, h));
1242     return h;
1243 }
1244 
1245 /* redraw a button bar */
1246 void
bbar_redraw(buttonbar_t * bbar)1247 bbar_redraw(buttonbar_t *bbar)
1248 {
1249     bbar_calc_height(bbar);
1250     bbar_calc_button_sizes(bbar);
1251     bbar_calc_button_positions(bbar);
1252     bbar_draw(bbar, IMAGE_STATE_CURRENT, MODE_MASK);
1253 }
1254