Fix move command parsing.
[fvwm.git] / modules / FvwmIconMan / xmanager.c
blobb9fb47b6f41e639ec2bef7d5ff32d591582c15e5
1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 #include "config.h"
19 #include "libs/fvwmlib.h"
20 #include "libs/FShape.h"
21 #include "libs/Module.h"
22 #include "FvwmIconMan.h"
23 #include "x.h"
24 #include "xmanager.h"
25 #include "libs/PictureGraphics.h"
26 #include "libs/PictureUtils.h"
27 #include "libs/Rectangles.h"
28 #include "libs/Grab.h"
29 #include "libs/Graphics.h"
30 #include "libs/Strings.h"
31 #include "libs/wild.h"
33 extern FlocaleWinString *FwinString;
35 /* button dirty bits: */
36 #define ICON_STATE_CHANGED 1
37 #define STATE_CHANGED 2
38 #define PICTURE_CHANGED 4
39 #define WINDOW_CHANGED 8
40 #define STRING_CHANGED 16
41 #define REDRAW_BUTTON 32
42 #define GEOMETRY_CHANGED 64
44 /* manager dirty bits: */
45 /* GEOMETRY_CHANGED 64 same as with button */
46 #define MAPPING_CHANGED 2
47 #define SHAPE_CHANGED 4
48 #define REDRAW_MANAGER 8
49 #define REDRAW_BG 16
51 /* ButtonArray dirty bits: */
52 #define NUM_BUTTONS_CHANGED 1
53 #define NUM_WINDOWS_CHANGED 2
55 #define ALL_CHANGED 0x7f /* high bit is special */
57 typedef struct {
58 int button_x, button_y, button_h, button_w; /* dim's of the whole button */
59 int icon_x, icon_y, icon_h, icon_w; /* what denotes icon state */
60 int text_x, text_y, text_h, text_w; /* text field */
61 int text_base; /* text baseline */
62 } ButtonGeometry;
64 static void print_button_info(Button *b);
65 static void insert_windows_button(WinData *win);
68 * Utility leaf functions
71 static int selected_button_in_man(WinManager *man)
73 assert(man);
74 ConsoleDebug(X11, "selected_button_in_man: %p\n",
75 globals.select_win);
76 if (globals.select_win && globals.select_win->button &&
77 globals.select_win->manager == man) {
78 return globals.select_win->button->index;
80 return -1;
83 #if 0
84 static void ClipRectangle(WinManager *man, int context,
85 int x, int y, int w, int h)
87 XRectangle r;
89 r.x = x;
90 r.y = y;
91 r.width = w;
92 r.height = h;
94 XSetClipRectangles(theDisplay, man->hiContext[context], 0, 0, &r, 1,
95 YXBanded);
97 #endif
99 static Region GetRegion(int x, int y, int w, int h)
101 Region region;
102 XRectangle rectangle;
104 rectangle.x = x;
105 rectangle.y = y;
106 rectangle.width = w;
107 rectangle.height = h;
109 region = XCreateRegion();
110 XUnionRectWithRegion(&rectangle, region, region);
111 return region;
114 static int num_visible_rows(int n, int cols)
116 return (n - 1) / cols + 1;
119 static int first_row_len(int n, int cols)
121 int ret = n % cols;
122 if (ret == 0)
123 ret = cols;
125 return ret;
128 static int index_to_box(WinManager *man, int index)
130 int first_len, n, cols;
132 if (man->geometry.dir & GROW_DOWN) {
133 return index;
135 else {
136 n = man->buttons.num_windows;
137 cols = man->geometry.cols;
138 first_len = first_row_len(n, cols);
139 if (index >= first_len)
140 index += cols - first_len;
141 index += (man->geometry.rows - num_visible_rows(n, cols)) * cols;
142 return index;
146 static int box_to_index(WinManager *man, int box)
148 int first_len, n, cols;
149 int index = box;
151 if (man->geometry.dir & GROW_DOWN)
153 return index;
155 else
157 n = man->buttons.num_windows;
158 cols = man->geometry.cols;
159 first_len = first_row_len(n, cols);
161 index = box - (man->geometry.rows - num_visible_rows(n, cols)) * cols;
162 if (!((index >= 0 && index < first_len) || index >= cols))
164 index = -1;
166 if (index >= first_len)
168 index -= cols - first_len;
173 return index;
176 static int index_to_row(WinManager *man, int index)
178 int row;
180 row = index_to_box(man, index) / man->geometry.cols;
182 return row;
185 static int index_to_col(WinManager *man, int index)
187 int col;
189 col = index_to_box(man, index) % man->geometry.cols;
191 return col;
194 static int rects_equal(XRectangle *x, XRectangle *y)
196 return (x->x == y->x) && (x->y == y->y) && (x->width == y->width) &&
197 (x->height == y->height);
200 static int top_y_coord(WinManager *man)
202 if (man->buttons.num_windows > 0 && (man->geometry.dir & GROW_UP)) {
203 return index_to_row(man, 0) * man->geometry.boxheight;
205 else {
206 return 0;
210 static ManGeometry *figure_geometry(WinManager *man)
212 /* Given the number of wins in icon_list and width x height, compute
213 new geometry. */
214 /* if GROW_FIXED is set, don't change window geometry */
216 static ManGeometry ret;
217 ManGeometry *g = &man->geometry;
218 int n = man->buttons.num_windows;
219 Bool noWindow = False;
221 ret = *g;
223 ConsoleDebug(
224 X11, "figure_geometry: %s: %d, %d %d %d %d\n",
225 man->titlename, n,
226 ret.width, ret.height, ret.cols, ret.rows);
228 if (n == 0)
230 n = 1;
231 noWindow = True;
234 if (man->geometry.dir & GROW_FIXED)
236 ret.cols = num_visible_rows(n, g->rows);
237 ret.boxwidth = ret.width / ret.cols;
238 if (man->max_button_width_columns > 0)
240 man->max_button_width =
241 ret.width / man->max_button_width_columns;
243 if (!noWindow && man->max_button_width > 0 &&
244 ret.boxwidth > man->max_button_width)
246 int i = 1;
247 while(i <= g->rows)
249 if (n*man->max_button_width <= ret.width)
251 ret.cols = n;
252 break;
254 else if ((n/i)*man->max_button_width <=
255 ret.width)
257 ret.cols =
258 ret.width /
259 man->max_button_width;
260 break;
262 i++;
264 ret.boxwidth = man->max_button_width;
266 if (ret.boxwidth < 1)
268 ret.boxwidth = 1;
271 else
273 if (man->geometry.dir & GROW_VERT)
275 if (g->cols)
277 ret.rows = num_visible_rows(n, g->cols);
279 else
281 ConsoleMessage(
282 "Internal error in figure_geometry\n");
283 ret.rows = 1;
285 ret.height = ret.rows * g->boxheight;
286 ret.width = ret.cols * g->boxwidth;
287 if (ret.boxwidth < 1)
289 ret.boxwidth = 1;
292 else
294 /* need to set resize inc */
295 if (g->rows)
297 ret.cols = num_visible_rows(n, g->rows);
299 else
301 ConsoleMessage(
302 "Internal error in figure_geometry\n");
303 ret.cols = 1;
305 ret.height = ret.rows * g->boxheight;
306 ret.width = ret.cols * g->boxwidth;
307 ret.boxwidth = ret.width / ret.cols;
308 if (ret.boxwidth < 1)
310 ret.boxwidth = 1;
315 ConsoleDebug(
316 X11, "figure_geometry: %d %d %d %d %d\n",
317 n, ret.width, ret.height, ret.cols, ret.rows);
319 return &ret;
322 static ManGeometry *query_geometry(WinManager *man)
324 XWindowAttributes frame_attr, win_attr;
325 int off_x, off_y;
326 static ManGeometry g;
328 assert(man->window_mapped);
330 off_x = 0;
331 off_y = 0;
332 man->theFrame = find_frame_window(man->theWindow, &off_x, &off_y);
333 if (XGetWindowAttributes(theDisplay, man->theFrame, &frame_attr))
335 g.x = frame_attr.x + off_x + frame_attr.border_width;
336 g.y = frame_attr.y + off_y + frame_attr.border_width;
338 else
340 g.x = off_x;
341 g.y = off_y;
342 fprintf(stderr, "%s: query_geometry: failed to get frame attributes.\n",
343 MyName);
345 if (XGetWindowAttributes(theDisplay, man->theWindow, &win_attr))
347 g.width = win_attr.width;
348 g.height = win_attr.height;
350 else
352 g.width = 1;
353 g.height = 1;
354 fprintf(stderr, "%s: query_geometry: failed to get window attributes.\n",
355 MyName);
358 return &g;
361 static void fix_manager_size(WinManager *man, int w, int h)
363 XSizeHints size;
364 long mask;
366 if (man->geometry.dir & GROW_FIXED)
367 return;
369 XGetWMNormalHints(theDisplay, man->theWindow, &size, &mask);
370 size.min_width = w;
371 size.max_width = w;
372 size.min_height = h;
373 size.max_height = h;
374 XSetWMNormalHints(theDisplay, man->theWindow, &size);
377 /* Like XMoveResizeWindow(), but can move in arbitary directions */
378 static void resize_window(WinManager *man)
380 ManGeometry *g;
381 int x_changed, y_changed, dir;
383 dir = man->geometry.dir;
384 fix_manager_size(man, man->geometry.width, man->geometry.height);
386 if ((dir & GROW_DOWN) && (dir & GROW_RIGHT)) {
387 XResizeWindow(theDisplay, man->theWindow, man->geometry.width,
388 man->geometry.height);
390 else {
391 MyXGrabServer(theDisplay);
392 g = query_geometry(man);
393 x_changed = y_changed = 0;
394 if (dir & GROW_LEFT) {
395 man->geometry.x = g->x + g->width - man->geometry.width;
396 x_changed = 1;
398 else {
399 man->geometry.x = g->x;
401 if (dir & GROW_UP) {
402 man->geometry.y = g->y + g->height - man->geometry.height;
403 y_changed = 1;
405 else {
406 man->geometry.y = g->y;
409 ConsoleDebug(X11, "queried: y: %d, h: %d, queried: %d\n", g->y,
410 man->geometry.height, g->height);
412 if (x_changed || y_changed) {
413 XMoveResizeWindow(theDisplay, man->theWindow,
414 man->geometry.x,
415 man->geometry.y,
416 man->geometry.width, man->geometry.height);
418 else {
419 XResizeWindow(theDisplay, man->theWindow, man->geometry.width,
420 man->geometry.height);
422 MyXUngrabServer(theDisplay);
426 static char *make_display_string(WinData *win, char *format, int len)
428 #define MAX_DISPLAY_SIZE 1024
429 #define COPY(field) \
430 temp_p = win->field; \
431 if (temp_p) \
432 while (*temp_p && out_p - buf < len - 1) \
433 *out_p++ = *temp_p++; \
434 in_p++;
436 static char buf[MAX_DISPLAY_SIZE];
437 char *string, *in_p, *out_p, *temp_p;
439 in_p = format;
440 out_p = buf;
442 if (len > MAX_DISPLAY_SIZE || len <= 0)
443 len = MAX_DISPLAY_SIZE;
445 while (*in_p && out_p - buf < len - 1) {
446 if (*in_p == '%') {
447 switch (*(++in_p)) {
448 case 'i':
449 COPY(visible_icon_name);
450 break;
452 case 't':
453 COPY(visible_name);
454 break;
456 case 'r':
457 COPY(resname);
458 break;
460 case 'c':
461 COPY(classname);
462 break;
464 default:
465 *out_p++ = *in_p++;
466 break;
469 else {
470 *out_p++ = *in_p++;
474 *out_p++ = '\0';
476 string = buf;
477 return string;
479 #undef COPY
480 #undef MAX_DISPLAY_SIZE
483 Button *button_above(WinManager *man, Button *b)
485 int n = man->buttons.num_windows, cols = man->geometry.cols;
486 int i = -1;
488 if (b) {
489 i = box_to_index(man, index_to_box(man, b->index) - cols);
491 if (i < 0 || i >= n)
492 return b;
493 else
494 return man->buttons.buttons[i];
497 Button *button_below(WinManager *man, Button *b)
499 int n = man->buttons.num_windows;
500 int i = -1;
502 if (b) {
503 i = box_to_index(man, index_to_box(man, b->index) + man->geometry.cols);
505 if (i < 0 || i >= n)
506 return b;
507 else
508 return man->buttons.buttons[i];
511 Button *button_right(WinManager *man, Button *b)
513 int i = -1;
515 if (index_to_col(man, b->index) < man->geometry.cols - 1) {
516 i = box_to_index(man, index_to_box(man, b->index) + 1);
519 if (i < 0 || i >= man->buttons.num_windows)
520 return b;
521 else
522 return man->buttons.buttons[i];
525 Button *button_left(WinManager *man, Button *b)
527 int i = -1;
528 if (index_to_col(man, b->index) > 0) {
529 i = box_to_index(man, index_to_box(man, b->index) - 1);
532 if (i < 0 || i >= man->buttons.num_windows)
533 return b;
534 else
535 return man->buttons.buttons[i];
538 Button *button_next(WinManager *man, Button *b)
540 int i = b->index + 1;
542 if (i >= 0 && i < man->buttons.num_windows)
543 return man->buttons.buttons[i];
544 else
545 return b;
548 Button *button_prev(WinManager *man, Button *b)
550 int i = b->index - 1;
552 if (i >= 0 && i < man->buttons.num_windows)
553 return man->buttons.buttons[i];
554 else
555 return b;
558 Button *xy_to_button(WinManager *man, int x, int y)
560 ManGeometry *g;
561 int row, col, box, index;
563 g = figure_geometry(man);
564 row = y / g->boxheight;
565 col = x / g->boxwidth;
567 if (x >= 0 && x <= g->width &&
568 y >= 0 && y <= g->height && col < g->cols)
570 box = row * g->cols + col;
571 index = box_to_index(man, box);
572 if (index >= 0 && index < man->buttons.num_windows)
574 return man->buttons.buttons[index];
578 return NULL;
582 * Routines which change dirtyable state
585 static void set_button_geometry(WinManager *man, Button *box)
587 ManGeometry *g;
589 g = figure_geometry(man);
590 box->x = index_to_col(man, box->index) * g->boxwidth;
591 box->y = index_to_row(man, box->index) * g->boxheight;
592 box->w = g->boxwidth;
593 box->h = g->boxheight;
594 box->drawn_state.dirty_flags |= GEOMETRY_CHANGED;
597 static void clear_button(Button *b)
599 assert(b);
600 b->drawn_state.win = NULL;
601 b->drawn_state.dirty_flags = REDRAW_BUTTON;
602 b->drawn_state.display_string = NULL;
603 b->drawn_state.ew = 0;
606 static void set_window_button(WinData *win, int index)
608 Button *b;
610 assert(win->manager && index < win->manager->buttons.num_buttons);
612 b = win->manager->buttons.buttons[index];
614 /* Can optimize here */
615 if (FMiniIconsSupported)
617 b->drawn_state.pic = win->pic;
619 b->drawn_state.win = win;
620 copy_string(&b->drawn_state.display_string, win->display_string);
621 b->drawn_state.iconified = win->iconified;
622 b->drawn_state.state = win->state;
623 b->drawn_state.dirty_flags = ALL_CHANGED;
625 win->button = b;
628 static void set_num_buttons(ButtonArray *buttons, int n)
630 int i;
632 ConsoleDebug(X11, "set_num_buttons: %d %d\n", buttons->num_buttons, n);
634 if (n > buttons->num_buttons) {
635 buttons->dirty_flags |= NUM_BUTTONS_CHANGED;
636 buttons->buttons = (Button **)saferealloc((void *)buttons->buttons,
637 n * sizeof(Button *));
639 for (i = buttons->num_buttons; i < n; i++) {
640 buttons->buttons[i] = (Button *)safemalloc(sizeof(Button));
641 memset(buttons->buttons[i], 0, sizeof(Button));
642 buttons->buttons[i]->drawn_state.display_string = NULL;
643 buttons->buttons[i]->index = i;
646 buttons->dirty_flags |= NUM_BUTTONS_CHANGED;
647 buttons->num_buttons = n;
651 static void increase_num_windows(ButtonArray *buttons, int off)
653 int n;
655 if (off != 0) {
656 buttons->num_windows += off;
657 buttons->dirty_flags |= NUM_WINDOWS_CHANGED;
659 if (buttons->num_windows > buttons->num_buttons) {
660 n = buttons->num_windows + 10;
661 set_num_buttons(buttons, n);
666 static void set_man_gravity_origin(WinManager *man)
668 if (man->gravity == NorthWestGravity || man->gravity == NorthEastGravity)
669 man->geometry.gravity_y = 0;
670 else
671 man->geometry.gravity_y = man->geometry.height;
672 if (man->gravity == NorthWestGravity || man->gravity == SouthWestGravity)
673 man->geometry.gravity_x = 0;
674 else
675 man->geometry.gravity_x = man->geometry.width;
678 static void set_man_geometry(WinManager *man, ManGeometry *new)
680 int n;
682 if (man->geometry.width != new->width ||
683 man->geometry.height != new->height ||
684 man->geometry.rows != new->rows ||
685 man->geometry.cols != new->cols ||
686 man->geometry.boxheight != new->boxheight ||
687 man->geometry.boxwidth != new->boxwidth) {
688 man->dirty_flags |= GEOMETRY_CHANGED;
691 man->geometry = *new;
692 set_man_gravity_origin(man);
693 n = man->geometry.rows * man->geometry.cols;
694 if (man->buttons.num_buttons < n)
695 set_num_buttons(&man->buttons, n + 10);
698 void set_manager_width(WinManager *man, int width)
700 if (width != man->geometry.width) {
701 ConsoleDebug(X11, "set_manager_width: %d -> %d, %d -> %d\n",
702 man->geometry.width, width, man->geometry.boxwidth,
703 width / man->geometry.cols);
704 man->geometry.width = width;
705 man->geometry.boxwidth = width / man->geometry.cols;
706 if (man->geometry.boxwidth < 1)
707 man->geometry.boxwidth = 1;
708 man->dirty_flags |= GEOMETRY_CHANGED;
712 void force_manager_redraw(WinManager *man)
714 man->dirty_flags |= REDRAW_MANAGER;
715 draw_manager(man);
718 void set_win_picture(WinData *win, Pixmap picture, Pixmap mask, Pixmap alpha,
719 unsigned int depth, unsigned int width,
720 unsigned int height)
722 if (!FMiniIconsSupported)
724 return;
726 if (win->button)
727 win->button->drawn_state.dirty_flags |= PICTURE_CHANGED;
728 win->old_pic = win->pic;
729 win->pic.picture = picture;
730 win->pic.mask = mask;
731 win->pic.alpha = alpha;
732 win->pic.width = width;
733 win->pic.height = height;
734 win->pic.depth = depth;
737 void set_win_iconified(WinData *win, int iconified)
739 /* This change has become necessary because with colorsets we don't
740 * know the background colour of the button (gradient background).
741 * Thus the button has to be redrawn completely, we can not just draw
742 * the square in the background colour. */
743 char string[256];
744 WinData *man_data = NULL;
745 Bool do_animate = True;
747 if (win->button != NULL && (win->iconified != iconified) )
749 if (win->manager->flags.is_shaded)
751 man_data = id_to_win(win->manager->theWindow);
752 if (!man_data->geometry_set)
754 do_animate = False;
757 else if (win->manager->swallowed)
759 if (win->manager->swallower_win &&
760 (man_data =
761 id_to_win(win->manager->swallower_win)) &&
762 man_data->geometry_set)
764 /* ok */
765 if (!IS_SHADED(man_data))
767 /* animate as usual */
768 man_data = NULL;
771 else
773 do_animate = False;
776 /* we check the win->button width and height because they
777 * will only be == zero on init, and if we didn't check we
778 * would get animations of all iconified windows to the far
779 * left of whereever thae manager would eventually be. */
780 if (do_animate && win->manager->AnimCommand &&
781 (win->manager->AnimCommand[0] != 0)
782 && IS_ICON_SUPPRESSED(win) && (win->button->w != 0)
783 && (win->button->h !=0))
785 int abs_x, abs_y, w, h;
786 Window junkw;
788 XTranslateCoordinates(
789 theDisplay, win->manager->theWindow,
790 theRoot, win->button->x, win->button->y,
791 &abs_x, &abs_y, &junkw);
792 w = win->button->w;
793 h = win->button->h;
794 if (man_data)
796 if (w > man_data->real_g.width)
798 w = 1;
800 if (h > man_data->real_g.height)
802 h = 1;
804 if (abs_x < man_data->real_g.x ||
805 abs_x > man_data->real_g.x +
806 man_data->real_g.width)
808 abs_x = man_data->real_g.x;
810 if (abs_y < man_data->real_g.y ||
811 abs_y > man_data->real_g.y +
812 man_data->real_g.height)
814 abs_y = man_data->real_g.y;
817 if (iconified)
819 sprintf(string, "%s %d %d %d %d %d %d %d %d",
820 win->manager->AnimCommand,
821 (int)win->x, (int)win->y,
822 (int)win->width, (int)win->height,
823 abs_x, abs_y, w, h);
825 else
827 sprintf(string, "%s %d %d %d %d %d %d %d %d",
828 win->manager->AnimCommand,
829 abs_x, abs_y, w, h,
830 (int)win->x, (int)win->y,
831 (int)win->width, (int)win->height);
833 SendText(fvwm_fd, string, 0);
835 win->button->drawn_state.dirty_flags |= ICON_STATE_CHANGED;
837 win->iconified = iconified;
838 if (!iconified)
840 win->state = PLAIN_CONTEXT;
841 if (globals.select_win == win)
843 add_win_state(win, SELECT_CONTEXT);
845 if (globals.focus_win == win)
847 add_win_state(win, FOCUS_CONTEXT);
852 void set_win_state(WinData *win, int state)
854 if (win->button && win->state != state)
855 win->button->drawn_state.dirty_flags |= STATE_CHANGED;
856 win->state = state;
859 /* this is "broken" */
860 void add_win_state(WinData *win, int flag)
862 int old_state = win->state;
864 if (flag == FOCUS_CONTEXT)
866 if (win->state == SELECT_CONTEXT ||
867 win->state == FOCUS_SELECT_CONTEXT)
869 win->state = FOCUS_SELECT_CONTEXT;
871 else
873 win->state = FOCUS_CONTEXT;
876 else if (flag == SELECT_CONTEXT)
878 if (win->state == FOCUS_CONTEXT ||
879 win->state == FOCUS_SELECT_CONTEXT)
881 win->state = FOCUS_SELECT_CONTEXT;
883 else
885 win->state = SELECT_CONTEXT;
888 else
890 /* add_win_state should not be called */
891 win->state = flag;
893 if (win->button && (old_state != win->state))
895 win->button->drawn_state.dirty_flags |= STATE_CHANGED;
897 ConsoleDebug(X11, "add_win_state: %s 0x%x\n", win->titlename, flag);
900 /* this is "broken" */
901 void del_win_state(WinData *win, int flag)
904 if (flag == FOCUS_CONTEXT)
906 if (win->state == FOCUS_SELECT_CONTEXT)
908 win->state = SELECT_CONTEXT;
910 else if (win->state == FOCUS_CONTEXT)
912 if (win->iconified)
914 win->state = ICON_CONTEXT;
916 else
918 win->state = PLAIN_CONTEXT;
921 else
923 /* nothing */
926 else if (flag == SELECT_CONTEXT)
928 if (win->state == FOCUS_SELECT_CONTEXT)
930 win->state = FOCUS_CONTEXT;
932 else if (win->state == SELECT_CONTEXT)
934 if (win->iconified)
936 win->state = ICON_CONTEXT;
938 else
940 win->state = PLAIN_CONTEXT;
943 else
945 /* */
948 else
950 /* del_win_state should not be called */
951 /*win->state = PLAIN_CONTEXT;*/
953 if (win->button)
955 win->button->drawn_state.dirty_flags |= STATE_CHANGED;
957 ConsoleDebug(X11, "del_win_state: %s 0x%x\n", win->titlename, flag);
960 void set_win_displaystring(WinData *win)
962 WinManager *man = win->manager;
963 int maxlen;
964 char *tmp;
966 if (man && win->button && win->button == man->tipped_button)
968 tips_update_label(man);
971 if (!man || ((man->format_depend & CLASS_NAME) && !win->classname)
972 || ((man->format_depend & ICON_NAME) && !win->visible_icon_name)
973 || ((man->format_depend & TITLE_NAME) && !win->visible_name)
974 || ((man->format_depend & RESOURCE_NAME) && !win->resname)) {
975 return;
978 if (man->window_up) {
979 assert(man->geometry.width && man->fontwidth);
980 maxlen = man->geometry.width / man->fontwidth + 2 /* fudge factor */;
982 else {
983 maxlen = 0;
986 tmp = make_display_string(win, man->formatstring, maxlen);
987 if ((tmp == NULL && win->display_string == NULL) ||
988 (tmp != NULL && win->display_string != NULL &&
989 strcmp(tmp, win->display_string) == 0))
991 return;
993 copy_string(&win->display_string, tmp);
994 if (win->button)
995 win->button->drawn_state.dirty_flags |= STRING_CHANGED;
998 /* This function is here and not with the other static utility functions
999 because it basically is the inverse of set_shape() */
1001 static void clear_empty_region(WinManager *man)
1003 XRectangle rects[3];
1004 int num_rects = 0, n = man->buttons.num_windows, cols = man->geometry.cols;
1005 int rows = man->geometry.rows;
1006 int boxwidth = man->geometry.boxwidth;
1007 int boxheight = man->geometry.boxheight;
1009 if (man->shaped)
1010 return;
1012 rects[1].x = rects[1].y = rects[1].width = rects[1].height = 0;
1014 if (n == 0 || rows * cols == 0 /* just be to safe */)
1016 rects[0].x = 0;
1017 rects[0].y = 0;
1018 rects[0].width = man->geometry.width;
1019 rects[0].height = man->geometry.height;
1020 num_rects = 1;
1022 else if (man->geometry.dir & GROW_DOWN)
1024 assert(cols);
1025 if (n % cols == 0)
1027 rects[0].x = 0;
1028 rects[0].y = num_visible_rows(n, cols) * man->geometry.boxheight;
1029 rects[0].width = man->geometry.width;
1030 rects[0].height = man->geometry.height - rects[0].y;
1031 num_rects = 1;
1033 else
1035 rects[0].x = (n % cols) * man->geometry.boxwidth;
1036 rects[0].y = (num_visible_rows(n, cols) - 1) * man->geometry.boxheight;
1037 rects[0].width = man->geometry.width - rects[0].x;
1038 rects[0].height = boxheight;
1039 rects[1].x = 0;
1040 rects[1].y = rects[0].y + rects[0].height;
1041 rects[1].width = man->geometry.width;
1042 rects[1].height = man->geometry.height - rects[0].y;
1043 num_rects = 2;
1046 else
1048 assert(cols);
1049 /* for shaped windows, we won't see this part of the window */
1050 if (n % cols == 0)
1052 rects[0].x = 0;
1053 rects[0].y = 0;
1054 rects[0].width = man->geometry.width;
1055 rects[0].height = top_y_coord(man);
1056 num_rects = 1;
1058 else
1060 rects[0].x = 0;
1061 rects[0].y = 0;
1062 rects[0].width = man->geometry.width;
1063 rects[0].height = top_y_coord(man);
1064 rects[1].x = (n % cols) * man->geometry.boxwidth;
1065 rects[1].y = rects[0].height;
1066 rects[1].width = man->geometry.width - rects[1].x;
1067 rects[1].height = boxheight;
1068 num_rects = 2;
1072 if (n != 0 && rows * cols != 0)
1074 rects[num_rects].x = cols * boxwidth;
1075 rects[num_rects].y = 0;
1076 rects[num_rects].width = man->geometry.width - cols * boxwidth;
1077 rects[num_rects].height = man->geometry.height;
1078 num_rects++;
1081 ConsoleDebug(X11, "Clearing: %d: (%d, %d, %d, %d) + (%d, %d, %d, %d)\n",
1082 num_rects,
1083 rects[0].x, rects[0].y, rects[0].width, rects[0].height,
1084 rects[1].x, rects[1].y, rects[1].width, rects[1].height);
1086 if (CSET_IS_TRANSPARENT_PR_PURE(man->colorsets[DEFAULT]))
1088 for(n=0; n < num_rects; n++)
1090 if (rects[n].width > 0 && rects[n].height > 0)
1092 XClearArea(
1093 theDisplay, man->theWindow, rects[n].x, rects[n].y,
1094 rects[n].width, rects[n].height, False);
1098 else
1100 XFillRectangles(theDisplay, man->theWindow,
1101 man->backContext[DEFAULT], rects, num_rects);
1105 void set_shape(WinManager *man)
1107 if (FShapesSupported)
1109 int n;
1110 XRectangle rects[2];
1111 int cols = man->geometry.cols;
1113 if (man->shaped == 0)
1114 return;
1116 ConsoleDebug(X11, "in set_shape: %s\n", man->titlename);
1118 n = man->buttons.num_windows;
1119 if (n == 0)
1121 man->shape.num_rects = 1;
1122 rects[0].x = -1;
1123 rects[0].y = -1;
1124 rects[0].width = 1;
1125 rects[0].height = 1;
1126 if (man->shape.num_rects != 0) {
1127 man->dirty_flags |= SHAPE_CHANGED;
1129 man->shape.rects[0] = rects[0];
1130 return;
1133 if (cols == 0 || n % cols == 0) {
1134 rects[0].x = 0;
1135 rects[0].y = top_y_coord(man);
1136 rects[0].width = cols * man->geometry.boxwidth;
1137 rects[0].height = num_visible_rows(n, cols) * man->geometry.boxheight;
1138 if (man->shape.num_rects != 1 || !rects_equal(rects, man->shape.rects)) {
1139 man->dirty_flags |= SHAPE_CHANGED;
1141 man->shape.num_rects = 1;
1142 man->shape.rects[0] = rects[0];
1144 else {
1145 if (man->geometry.dir & GROW_DOWN) {
1146 rects[0].x = 0;
1147 rects[0].y = 0;
1148 rects[0].width = cols * man->geometry.boxwidth;
1149 rects[0].height =
1150 (num_visible_rows(n, cols) - 1) * man->geometry.boxheight;
1151 rects[1].x = 0;
1152 rects[1].y = rects[0].height;
1153 rects[1].width = (n % cols) * man->geometry.boxwidth;
1154 rects[1].height = man->geometry.boxheight;
1156 else {
1157 rects[0].x = 0;
1158 rects[0].y = top_y_coord(man);
1159 rects[0].width = (n % cols) * man->geometry.boxwidth;
1160 rects[0].height = man->geometry.boxheight;
1161 rects[1].x = 0;
1162 rects[1].y = rects[0].y + rects[0].height;
1163 rects[1].width = man->geometry.width;
1164 rects[1].height = (num_visible_rows(n, cols) - 1) *
1165 man->geometry.boxheight;
1167 if (man->shape.num_rects != 2 ||
1168 !rects_equal(rects, man->shape.rects) ||
1169 !rects_equal(rects + 1, man->shape.rects + 1)) {
1170 man->dirty_flags |= SHAPE_CHANGED;
1172 man->shape.num_rects = 2;
1173 man->shape.rects[0] = rects[0];
1174 man->shape.rects[1] = rects[1];
1179 void set_manager_window_mapping(WinManager *man, int flag)
1181 if (flag != man->window_mapped) {
1182 man->window_mapped = flag;
1183 man->dirty_flags |= MAPPING_CHANGED;
1188 * Major exported functions
1191 void init_button_array(ButtonArray *array)
1193 memset(array, 0, sizeof(ButtonArray));
1196 /* Pretty much like resize_manager, but used only to figure the
1197 correct size when creating the window */
1199 void size_manager(WinManager *man)
1201 ManGeometry *new;
1202 int oldwidth, oldheight, w, h;
1204 new = figure_geometry(man);
1206 assert(new->width && new->height);
1208 w = new->width;
1209 h = new->height;
1211 oldwidth = man->geometry.width;
1212 oldheight = man->geometry.height;
1214 set_man_geometry(man, new);
1216 if (oldheight != h || oldwidth != w) {
1217 if (man->geometry.dir & GROW_UP)
1218 man->geometry.y -= h - oldheight;
1219 if (man->geometry.dir & GROW_LEFT)
1220 man->geometry.x -= w - oldwidth;
1223 ConsoleDebug(X11, "size_manager %s: %d %d %d %d\n", man->titlename,
1224 man->geometry.x, man->geometry.y, man->geometry.width,
1225 man->geometry.height);
1228 static void resize_manager(WinManager *man, int force)
1230 ManGeometry *new;
1231 int oldwidth, oldheight, oldrows, oldcols, old_boxwidth, old_boxheight;
1232 int dir;
1233 int i;
1235 if (man->flags.is_shaded)
1237 man->flags.needs_resize_after_unshade = 1;
1238 return;
1240 if (man->can_draw == 0)
1241 return;
1243 oldwidth = man->geometry.width;
1244 oldheight = man->geometry.height;
1245 oldrows = man->geometry.rows;
1246 oldcols = man->geometry.cols;
1247 dir = man->geometry.dir;
1248 old_boxwidth = man->geometry.boxheight;
1249 old_boxheight = man->geometry.boxwidth;
1251 if (dir & GROW_FIXED) {
1252 new = figure_geometry(man);
1253 set_man_geometry(man, new);
1254 set_shape(man);
1255 if (force || oldrows != new->rows || oldcols != new->cols ||
1256 oldwidth != new->width || oldheight != new->height) {
1257 man->dirty_flags |= GEOMETRY_CHANGED;
1260 else {
1261 new = figure_geometry(man);
1262 set_man_geometry(man, new);
1263 set_shape(man);
1264 if (force || oldrows != new->rows || oldcols != new->cols ||
1265 oldwidth != new->width || oldheight != new->height) {
1266 resize_window(man);
1270 #if 1 /* not sure that this is needed */
1271 if (oldwidth != new->width || oldheight != new->height)
1273 for (i = 0; i < NUM_CONTEXTS; i++)
1275 if (man->colorsets[i] >=0 &&
1276 (i == DEFAULT || CSET_IS_TRANSPARENT(man->colorsets[i])) &&
1277 Colorset[man->colorsets[i]].pixmap)
1279 recreate_background(man, i);
1284 if (old_boxwidth != new->boxwidth || old_boxheight != new->boxheight)
1286 for (i = 0; i < NUM_CONTEXTS; i++)
1288 if (man->colorsets[i] >= 0 && i != DEFAULT &&
1289 !CSET_IS_TRANSPARENT(man->colorsets[i]) &&
1290 Colorset[man->colorsets[i]].pixmap)
1292 recreate_background(man, i);
1296 #endif
1299 static int center_padding(int h1, int h2)
1301 return (h2 - h1) / 2;
1304 static void get_title_geometry(WinManager *man, ButtonGeometry *g)
1306 int text_pad;
1307 assert(man);
1308 g->button_x = 0;
1309 g->button_y = 0;
1310 g->button_w = man->geometry.boxwidth;
1311 g->button_h = man->geometry.boxheight;
1312 g->text_x = g->button_x + g->button_h / 2;
1313 g->text_w = g->button_w - 4 - (g->text_x - g->button_x);
1314 if (g->text_w <= 0)
1315 g->text_w = 1;
1316 g->text_h = man->fontheight;
1317 text_pad = center_padding(man->fontheight, g->button_h);
1319 g->text_y = g->button_y + text_pad;
1320 g->text_base = g->text_y + man->FButtonFont->ascent;
1323 static void get_button_geometry(WinManager *man, Button *button,
1324 ButtonGeometry *g)
1326 int icon_pad, text_pad;
1327 WinData *win;
1329 assert(man);
1331 win = button->drawn_state.win;
1333 g->button_x = button->x;
1334 g->button_y = button->y;
1336 g->button_w = button->w;
1337 g->button_h = button->h;
1339 /* [BV 16-Apr-97] Mini Icons work on black-and-white too */
1340 if (FMiniIconsSupported && man->draw_icons && win && win->pic.picture) {
1341 /* If no window, then icon_* aren't used, so doesn't matter what
1342 they are */
1343 g->icon_w = min(win->pic.width, g->button_h);
1344 g->icon_h = min(g->button_h - 4, win->pic.height);
1345 icon_pad = center_padding(g->icon_h, g->button_h);
1346 g->icon_x = g->button_x + 4;
1347 g->icon_y = g->button_y + icon_pad;
1349 else {
1350 g->icon_h = man->geometry.boxheight - 8;
1351 g->icon_w = g->icon_h;
1353 icon_pad = center_padding(g->icon_h, g->button_h);
1354 g->icon_x = g->button_x + icon_pad;
1355 g->icon_y = g->button_y + icon_pad;
1358 g->text_x = g->icon_x + g->icon_w + 2;
1359 g->text_w = g->button_w - 4 - (g->text_x - g->button_x);
1360 if (g->text_w <= 0)
1361 g->text_w = 1;
1362 g->text_h = man->fontheight;
1364 text_pad = center_padding(man->fontheight, g->button_h);
1366 g->text_y = g->button_y + text_pad;
1367 g->text_base = g->text_y + man->FButtonFont->ascent;
1370 static void draw_button_background(
1371 WinManager *man, XRectangle bounding, Contexts button_state)
1373 int cset = man->colorsets[button_state];
1375 if (CSET_IS_TRANSPARENT_PR_PURE(cset) ||
1376 man->backContext[button_state] == None)
1378 XClearArea(
1379 theDisplay, man->theWindow,
1380 bounding.x, bounding.y,
1381 bounding.width, bounding.height,
1382 False);
1384 else if (CSET_IS_TRANSPARENT_PR_TINT(cset))
1386 SetRectangleBackground(
1387 theDisplay, man->theWindow,
1388 bounding.x, bounding.y,
1389 bounding.width, bounding.height,
1390 &Colorset[cset], Pdepth, man->backContext[button_state]);
1392 else
1394 XFillRectangle(
1395 theDisplay, man->theWindow,
1396 man->backContext[button_state],
1397 bounding.x, bounding.y,
1398 bounding.width, bounding.height);
1402 static void draw_3d_icon(WinManager *man, int box, ButtonGeometry *g,
1403 int iconified, Contexts contextId)
1405 if ((iconified == 0) || (man->relief_thickness == 0))
1406 return;
1407 else
1408 RelieveRectangle(theDisplay, man->theWindow, g->icon_x, g->icon_y,
1409 g->icon_w - 1, g->icon_h - 1,
1410 man->reliefContext[contextId],
1411 man->shadowContext[contextId], man->relief_thickness);
1415 /* this routine should only be called from draw_button() */
1416 static void iconify_box(WinManager *man, WinData *win, int box,
1417 ButtonGeometry *g, int iconified, Contexts contextId,
1418 int button_already_cleared, XRectangle bounding)
1420 XRectangle inter;
1421 int cset = man->colorsets[contextId];
1422 Bool erase = False;
1424 if (!man->window_up)
1426 return;
1428 frect_get_intersection(
1429 bounding.x, bounding.y, bounding.width, bounding.height,
1430 g->icon_x, g->icon_y, g->icon_w, g->icon_h,
1431 &inter);
1433 if (inter.width <= 0 || inter.height <= 0)
1435 return;
1438 /* [BV 16-Apr-97] Mini Icons work on black-and-white too */
1439 if (FMiniIconsSupported && man->draw_icons && win->pic.picture)
1441 if (iconified == 0 && man->draw_icons != 2)
1443 erase = True;
1445 else
1447 FvwmRenderAttributes fra;
1448 int p_x = 0, p_y = 0;
1450 fra.mask = FRAM_DEST_IS_A_WINDOW;
1451 if (cset >= 0)
1453 fra.mask |= FRAM_HAVE_ICON_CSET;
1454 fra.colorset = &Colorset[cset];
1456 if (inter.x > g->icon_x)
1458 p_x = inter.x - g->icon_x;
1460 if (inter.y > g->icon_y)
1462 p_y = inter.y - g->icon_y;
1464 PGraphicsRenderPicture(
1465 theDisplay, man->theWindow, &win->pic, &fra,
1466 man->theWindow, man->hiContext[contextId],
1467 None, None,
1468 p_x, p_y, inter.width, inter.height,
1469 inter.x, inter.y, inter.width, inter.height,
1470 False);
1473 else
1475 if (!PictureUseBWOnly())
1477 draw_3d_icon(man, box, g, iconified, contextId);
1479 else
1481 if (iconified == 0)
1483 erase = True;
1485 else
1487 XFillArc(
1488 theDisplay, man->theWindow,
1489 man->hiContext[contextId],
1490 g->icon_x, g->icon_y, g->icon_w,
1491 g->icon_h, 0, 360 * 64);
1495 if (erase)
1497 draw_button_background(man, inter, contextId);
1501 int change_windows_manager(WinData *win)
1503 WinManager *oldman;
1504 WinManager *newman;
1506 ConsoleDebug(X11, "change_windows_manager: %s\n", win->titlename);
1508 oldman = win->manager;
1509 newman = figure_win_manager(win, ALL_NAME);
1510 if (oldman && newman != oldman && win->button) {
1511 delete_windows_button(win);
1513 win->manager = newman;
1514 set_win_displaystring(win);
1515 check_win_complete(win);
1516 check_in_window(win);
1517 ConsoleDebug(X11, "change_windows_manager: returning %d\n",
1518 newman != oldman);
1519 return (newman != oldman);
1522 void check_in_window(WinData *win)
1524 int in_viewport;
1525 int is_state_selected;
1527 if (win->complete) {
1528 WinManager *oldman;
1529 WinManager *newman;
1531 ConsoleDebug(X11, "change_windows_manager: %s\n", win->titlename);
1533 oldman = win->manager;
1534 newman = figure_win_manager(win, ALL_NAME);
1535 if (oldman && newman != oldman && win->button) {
1536 oldman->we_are_drawing = 1;
1537 delete_windows_button(win);
1539 win->manager = newman;
1540 set_win_displaystring(win);
1543 if (win->manager && win->complete) {
1544 is_state_selected =
1545 ((!win->manager->showonlyiconic || win->iconified) &&
1546 (!win->manager->shownoiconic || !win->iconified) &&
1547 (win->manager->showtransient || !IS_TRANSIENT(win)));
1548 in_viewport = win_in_viewport(win);
1549 if (win->manager->usewinlist && DO_SKIP_WINDOW_LIST(win))
1550 in_viewport = 0;
1551 if ((win->manager->showonlyfocused && win->state != FOCUS_CONTEXT) &&
1552 (win->manager->showonlyfocused && win->state != FOCUS_SELECT_CONTEXT))
1553 in_viewport = 0;
1554 if (win->button == NULL && in_viewport && is_state_selected) {
1555 insert_windows_button(win);
1556 if (win->manager->window_up == 0 && globals.got_window_list)
1557 create_manager_window(win->manager->index);
1559 if (win->button && (!in_viewport || !is_state_selected)) {
1560 if (win->button->drawn_state.display_string)
1561 Free(win->button->drawn_state.display_string);
1562 delete_windows_button(win);
1567 static void get_gcs(WinManager *man, int state, int iconified,
1568 GC *context1, GC *context2)
1570 GC gc1, gc2;
1572 switch (man->buttonState[state]) {
1573 case BUTTON_FLAT:
1574 gc1 = man->flatContext[state];
1575 gc2 = man->flatContext[state];
1576 break;
1578 case BUTTON_UP:
1579 case BUTTON_EDGEUP:
1580 gc1 = man->reliefContext[state];
1581 gc2 = man->shadowContext[state];
1582 break;
1584 case BUTTON_DOWN:
1585 case BUTTON_EDGEDOWN:
1586 gc1 = man->shadowContext[state];
1587 gc2 = man->reliefContext[state];
1588 break;
1590 default:
1591 ConsoleMessage("Internal error in get_gcs\n");
1592 return;
1595 if (((man->rev == REVERSE_ICON) && iconified)
1596 || ((man->rev == REVERSE_NORMAL) && !iconified)) {
1597 *context1 = gc2;
1598 *context2 = gc1;
1599 } else {
1600 *context1 = gc1;
1601 *context2 = gc2;
1603 return;
1606 static void draw_relief(WinManager *man, int button_state, ButtonGeometry *g,
1607 GC context1, GC context2)
1609 int state;
1610 int relief;
1612 state = man->buttonState[button_state];
1613 relief = man->relief_thickness;
1615 /* Make sure that the relief isn't too large for the button... */
1616 if ((abs(relief) > (man->geometry.boxheight / 2)) ||
1617 (abs(relief) > (man->geometry.boxwidth / 2))) {
1618 relief = min(man->geometry.boxheight/2, man->geometry.boxwidth/2);
1619 if (man->relief_thickness < 0)
1620 relief *= -1;
1623 if (state == BUTTON_FLAT || relief == 0)
1624 return;
1625 if (state == BUTTON_EDGEUP || state == BUTTON_EDGEDOWN) {
1626 RelieveRectangle(theDisplay, man->theWindow, g->button_x, g->button_y,
1627 g->button_w - 1, g->button_h - 1, context1, context2,
1628 relief);
1629 RelieveRectangle(theDisplay, man->theWindow, g->button_x+2, g->button_y+2,
1630 g->button_w - 5, g->button_h - 5, context2, context1,
1631 relief);
1633 else {
1634 RelieveRectangle(theDisplay, man->theWindow, g->button_x, g->button_y,
1635 g->button_w - 1, g->button_h - 1, context1, context2,
1636 relief);
1640 static void draw_button(WinManager *man, int button, int force)
1642 Button *b;
1643 WinData *win;
1644 ButtonGeometry g, old_g;
1645 GC context1, context2;
1646 Contexts button_state;
1647 int cleared_button = 0, dirty;
1648 int draw_background = 0, draw_icon = 0, draw_string = 0;
1649 int clear_old_pic = 0;
1651 assert(man);
1653 if (!man->window_up)
1655 ConsoleMessage("draw_button: manager not up yet\n");
1656 return;
1659 b = man->buttons.buttons[button];
1660 win = b->drawn_state.win;
1661 dirty = b->drawn_state.dirty_flags;
1663 if (win && win->button != b)
1665 ConsoleMessage("Internal error in draw_button.\n");
1666 return;
1669 if (!win)
1671 return;
1674 if (force || (dirty & REDRAW_BUTTON))
1676 ConsoleDebug(X11, "draw_button: %d forced\n", b->index);
1677 draw_background = 1;
1678 draw_icon = 1;
1679 draw_string = 1;
1682 /* figure out what we have to draw */
1683 if (dirty)
1685 ConsoleDebug(X11, "draw_button: %d dirty\n", b->index);
1686 /* humm ... this should be optimised one day ! */
1687 if (dirty & GEOMETRY_CHANGED)
1689 ConsoleDebug(X11, "\tGeometry changed\n");
1690 /* Determine if geometry has changed relative
1691 * to the window gravity */
1692 if (b->w != b->drawn_state.w ||
1693 b->h != b->drawn_state.h ||
1694 b->x - man->geometry.gravity_x !=
1695 b->drawn_state.x -
1696 man->drawn_geometry.gravity_x ||
1697 b->y - man->geometry.gravity_y !=
1698 b->drawn_state.y -
1699 man->drawn_geometry.gravity_y)
1701 draw_background = 1;
1702 draw_icon = 1;
1703 draw_string = 1;
1706 if (dirty & STATE_CHANGED)
1708 ConsoleDebug(X11, "\tState changed\n");
1709 b->drawn_state.state = win->state;
1710 draw_background = 1;
1711 draw_icon = 1;
1712 draw_string = 1;
1714 if (FMiniIconsSupported && (dirty & PICTURE_CHANGED))
1716 FvwmPicture tpic;
1718 ConsoleDebug(X11, "\tPicture changed\n");
1719 tpic = win->pic;
1720 win->pic = win->old_pic;
1721 get_button_geometry(man, b, &old_g);
1722 win->pic = tpic;
1723 b->drawn_state.pic = win->pic;
1724 draw_icon = 1;
1725 draw_string = 1;
1726 draw_background = 1;
1728 if ((dirty & ICON_STATE_CHANGED) &&
1729 b->drawn_state.iconified != win->iconified)
1731 ConsoleDebug(X11, "\tIcon changed\n");
1732 b->drawn_state.iconified = win->iconified;
1733 draw_icon = 1;
1734 draw_background = 1;
1735 draw_string = 1;
1737 if (dirty & STRING_CHANGED)
1739 ConsoleDebug(
1740 X11, "\tString changed: %s\n",
1741 win->display_string);
1742 copy_string(
1743 &b->drawn_state.display_string,
1744 win->display_string);
1745 assert(b->drawn_state.display_string);
1746 draw_icon = 1;
1747 draw_background = 1;
1748 draw_string = 1;
1752 if (draw_background || draw_icon || draw_string)
1754 XRectangle bounding;
1755 Region b_region;
1757 get_button_geometry(man, b, &g);
1758 if (b->drawn_state.ew > 0 && b->drawn_state.eh > 0)
1760 /* we redraw from an expose event */
1761 bounding.x = b->drawn_state.ex;
1762 bounding.y = b->drawn_state.ey;
1763 bounding.width = b->drawn_state.ew;
1764 bounding.height = b->drawn_state.eh;
1766 else
1768 bounding.x = g.button_x;
1769 bounding.y = g.button_y;
1770 bounding.width = g.button_w;
1771 bounding.height = g.button_h;
1773 b_region = GetRegion(
1774 bounding.x, bounding.y, bounding.width, bounding.height);
1775 ConsoleDebug(
1776 X11, "\tgeometry: %d %d %d %d\n", g.button_x, g.button_y,
1777 g.button_w, g.button_h);
1778 button_state = b->drawn_state.state;
1779 if (b->drawn_state.iconified && button_state == PLAIN_CONTEXT)
1781 button_state = ICON_CONTEXT;
1783 if (draw_background)
1785 ConsoleDebug(X11, "\tDrawing background\n");
1786 draw_button_background(man, bounding, button_state);
1787 cleared_button = 1;
1789 if (clear_old_pic)
1791 ConsoleDebug(X11, "\tClearing old picture\n");
1792 if (!cleared_button)
1794 XRectangle r;
1796 frect_get_intersection(
1797 bounding.x, bounding.y,
1798 bounding.width, bounding.height,
1799 g.icon_x, g.icon_y, g.icon_w, g.icon_h,
1800 &r);
1801 if (r.width > 0)
1803 draw_button_background(
1804 man, r, button_state);
1808 if (draw_icon)
1810 ConsoleDebug(X11, "\tDrawing icon\n");
1811 iconify_box(
1812 man, win, button, &g, win->iconified,
1813 button_state, cleared_button, bounding);
1815 /* Draw reliefs after icon since the icon might overlay
1816 part of it. */
1817 if (draw_background)
1819 ConsoleDebug(X11, "\tDrawing reliefs\n");
1820 if (!PictureUseBWOnly())
1822 get_gcs(
1823 man, button_state, win->iconified,
1824 &context1, &context2);
1825 draw_relief(
1826 man, button_state, &g, context1,
1827 context2);
1829 else if (button_state & SELECT_CONTEXT)
1831 XDrawRectangle(
1832 theDisplay, man->theWindow,
1833 man->hiContext[button_state],
1834 g.button_x + 2, g.button_y + 1,
1835 g.button_w - 4, g.button_h - 2);
1838 if (draw_string)
1840 Region tr;
1842 ConsoleDebug(
1843 X11, "\tDrawing text: %s\n",
1844 b->drawn_state.display_string);
1846 tr = GetRegion(
1847 g.text_x, g.text_y, g.text_w, g.text_h);
1848 XIntersectRegion(tr, b_region, tr);
1849 XSetRegion(
1850 theDisplay, man->hiContext[button_state], tr);
1851 if (!cleared_button)
1853 XRectangle r;
1855 frect_get_intersection(
1856 bounding.x, bounding.y,
1857 bounding.width, bounding.height,
1858 g.text_x, g.text_y, g.text_w, g.text_h,
1859 &r);
1860 draw_button_background(man, r, button_state);
1862 FwinString->str = b->drawn_state.display_string;
1863 FwinString->win = man->theWindow;
1864 FwinString->gc = man->hiContext[button_state];
1865 if (man->colorsets[button_state] >= 0)
1867 FwinString->colorset =
1868 &Colorset[man->colorsets[button_state]];
1869 FwinString->flags.has_colorset = True;
1871 else
1873 FwinString->flags.has_colorset = False;
1875 FwinString->flags.has_clip_region = True;
1876 FwinString->clip_region = tr;
1877 FwinString->x = g.text_x;
1878 FwinString->y = g.text_base;
1879 FlocaleDrawString(
1880 theDisplay, man->FButtonFont, FwinString, 0);
1881 XDestroyRegion(tr);
1882 XSetClipMask(
1883 theDisplay, man->hiContext[button_state], None);
1885 XDestroyRegion(b_region);
1888 b->drawn_state.dirty_flags = 0;
1889 b->drawn_state.x = b->x;
1890 b->drawn_state.y = b->y;
1891 b->drawn_state.w = b->w;
1892 b->drawn_state.h = b->h;
1893 b->drawn_state.ew = 0;
1894 b->drawn_state.eh = 0;
1895 XFlush(theDisplay);
1898 void draw_managers(void)
1900 int i;
1901 for (i = 0; i < globals.num_managers; i++)
1902 draw_manager(&globals.managers[i]);
1905 static void draw_empty_manager(WinManager *man)
1907 GC context1, context2;
1908 int state = TITLE_CONTEXT;
1909 ButtonGeometry g;
1910 int len = strlen(man->titlename);
1911 Region region;
1913 ConsoleDebug(X11, "draw_empty_manager\n");
1914 clear_empty_region(man);
1915 get_title_geometry(man, &g);
1917 /* FIXME: should bound when exposed */
1918 if (len > 0)
1920 XRectangle r;
1922 r.x = g.button_x;
1923 r.y = g.button_y;
1924 r.width = g.button_w;
1925 r.height = g.button_h;
1926 draw_button_background(man, r, state);
1928 if (!PictureUseBWOnly())
1930 get_gcs(man, state, 0, &context1, &context2);
1931 draw_relief(man, state, &g, context1, context2);
1933 region = GetRegion(g.text_x, g.text_y, g.text_w, g.text_h);
1934 XSetRegion(theDisplay, man->hiContext[state], region);
1935 FwinString->str = man->titlename;
1936 FwinString->win = man->theWindow;
1937 FwinString->gc = man->hiContext[state];
1938 if (man->colorsets[state] >= 0)
1940 FwinString->colorset = &Colorset[man->colorsets[state]];
1941 FwinString->flags.has_colorset = True;
1943 else
1945 FwinString->flags.has_colorset = False;
1947 FwinString->flags.has_clip_region = True;
1948 FwinString->clip_region = region;
1949 FwinString->x = g.text_x;
1950 FwinString->y = g.text_base;
1951 FlocaleDrawString(theDisplay, man->FButtonFont, FwinString, 0);
1952 XSetClipMask(theDisplay, man->hiContext[state], None);
1955 void draw_manager(WinManager *man)
1957 int i, force_draw = 0, update_geometry = 0, redraw_all = 0;
1958 int shape_changed = 0;
1960 assert(man->buttons.num_buttons >= 0 && man->buttons.num_windows >= 0);
1962 if (!man->window_up)
1963 return;
1964 ConsoleDebug(X11, "Drawing Manager: %s\n", man->titlename);
1965 redraw_all = man->dirty_flags & REDRAW_MANAGER;
1967 if (!man->flags.is_shaded && man->flags.needs_resize_after_unshade) {
1968 ConsoleDebug(X11, "\tresizing manager\n");
1969 resize_manager(man, 1);
1970 update_geometry = 1;
1971 force_draw = 1;
1972 } else if (redraw_all || (man->buttons.dirty_flags & NUM_WINDOWS_CHANGED)) {
1973 ConsoleDebug(X11, "\tresizing manager\n");
1974 resize_manager(man, redraw_all);
1975 update_geometry = 1;
1976 force_draw = 1;
1979 if (redraw_all || (man->dirty_flags & MAPPING_CHANGED)) {
1980 force_draw = 1;
1981 ConsoleDebug(X11, "manager %s: mapping changed\n", man->titlename);
1984 if (FShapesSupported && man->shaped)
1986 if (redraw_all || (man->dirty_flags & SHAPE_CHANGED)) {
1987 FShapeCombineRectangles(
1988 theDisplay, man->theWindow, FShapeBounding, 0, 0, man->shape.rects,
1989 man->shape.num_rects, FShapeSet, Unsorted);
1990 FShapeCombineRectangles(
1991 theDisplay, man->theWindow, FShapeClip, 0, 0, man->shape.rects,
1992 man->shape.num_rects, FShapeSet, Unsorted);
1993 shape_changed = 1;
1994 update_geometry = 1;
1998 if (redraw_all || (man->dirty_flags & GEOMETRY_CHANGED)) {
1999 ConsoleDebug(X11, "\tredrawing all buttons\n");
2000 update_geometry = 1;
2003 if (update_geometry) {
2004 for (i = 0; i < man->buttons.num_windows; i++)
2005 set_button_geometry(man, man->buttons.buttons[i]);
2008 if (force_draw || update_geometry || (man->dirty_flags & REDRAW_BG)) {
2009 ConsoleDebug(X11, "\tredrawing background\n");
2010 clear_empty_region(man);
2012 if (force_draw || update_geometry)
2014 /* FIXME: maybe not useful but safe */
2015 if (CSET_IS_TRANSPARENT_PR_PURE(man->colorsets[DEFAULT]))
2016 force_draw = True;
2019 man->dirty_flags = 0;
2020 man->buttons.dirty_flags = 0;
2021 man->buttons.drawn_num_buttons = man->buttons.num_buttons;
2022 man->buttons.drawn_num_windows = man->buttons.num_windows;
2024 if (man->buttons.num_windows == 0) {
2025 if (force_draw)
2026 draw_empty_manager(man);
2028 else {
2029 /* I was having the problem where when the shape changed the manager
2030 wouldn't get redrawn. It appears we weren't getting the expose.
2031 How can I tell when I am going to reliably get an expose event? */
2033 if (1 || shape_changed) {
2034 /* if shape changed, we'll catch it on the expose */
2035 for (i = 0; i < man->buttons.num_buttons; i++) {
2036 draw_button(man, i, force_draw);
2040 man->drawn_geometry = man->geometry;
2041 XFlush(theDisplay);
2044 Bool draw_transparent_buttons(
2045 WinManager *man, Bool only_moved, Bool clear_only)
2047 Button **bp;
2048 Contexts button_state;
2049 int i,cset;
2050 Bool r = False;
2051 Bool man_bg_transparent = False;
2053 if (CSET_IS_TRANSPARENT(man->colorsets[DEFAULT]))
2055 clear_empty_region(man);
2056 man_bg_transparent = True;
2059 if (!man->buttons.num_windows)
2061 if (CSET_IS_TRANSPARENT(man->colorsets[TITLE_CONTEXT]) ||
2062 CSET_IS_TRANSPARENT_PR_TINT(man->colorsets[DEFAULT]))
2064 draw_empty_manager(man);
2066 return 0;
2069 bp = man->buttons.buttons;
2070 for (i = 0; i < man->buttons.num_windows; i++)
2072 button_state = bp[i]->drawn_state.state;
2073 if (bp[i]->drawn_state.iconified &&
2074 button_state == PLAIN_CONTEXT)
2076 button_state = ICON_CONTEXT;
2078 cset = man->colorsets[button_state];
2080 if ((!CSET_IS_TRANSPARENT(cset) &&
2081 !CSET_IS_TRANSPARENT_PR_TINT(man->colorsets[DEFAULT]))
2083 (only_moved && !man_bg_transparent &&
2084 !CSET_IS_TRANSPARENT_ROOT(cset)))
2086 continue;
2088 if (clear_only)
2090 XClearArea(
2091 theDisplay, man->theWindow,
2092 bp[i]->x, bp[i]->y, bp[i]->w, bp[i]->h,
2093 True);
2094 r = True;
2096 else
2098 bp[i]->drawn_state.dirty_flags |= REDRAW_BUTTON;
2099 draw_button(man, i, 0);
2102 return r;
2105 static int compute_weight(WinData *win)
2107 WinManager *man;
2108 WeightedSort *sort;
2109 int i;
2111 man = win->manager;
2112 for (i = 0; i < man->weighted_sorts_len; i++) {
2113 sort = &man->weighted_sorts[i];
2114 if (sort->resname && !matchWildcards(sort->resname, win->resname)) {
2115 continue;
2117 if (sort->classname && !matchWildcards(sort->classname, win->classname)) {
2118 continue;
2120 if (sort->titlename && !matchWildcards(sort->titlename, win->titlename)) {
2121 continue;
2123 if (sort->iconname && !matchWildcards(sort->iconname, win->iconname)) {
2124 continue;
2126 return sort->weight;
2128 return 0;
2131 static int compare_windows(SortType type, WinData *a, WinData *b)
2133 int wa, wb;
2135 if (type == SortId)
2137 return a->app_id - b->app_id;
2139 else if (type == SortName)
2141 return strcasecmp(
2142 (a->display_string)? a->display_string:"",
2143 (b->display_string)? b->display_string:"");
2145 else if (type == SortNameCase)
2147 return strcmp((a->display_string)? a->display_string:"",
2148 (b->display_string)? b->display_string:"");
2150 else if (type == SortWeighted)
2152 wa = compute_weight(a);
2153 wb = compute_weight(b);
2154 if (wa != wb)
2156 return wa - wb;
2158 return strcmp((a->display_string)? a->display_string:"",
2159 (b->display_string)? b->display_string:"");
2161 else
2163 ConsoleMessage("Internal error in compare_windows\n");
2164 return 0;
2168 /* find_windows_spot: returns index of button to stick the window in.
2169 * checks win->button to see if it's already in manager.
2170 * if it isn't, then gives spot at which it should be,
2171 * if it were.
2174 static int find_windows_spot(WinData *win)
2176 WinManager *man = win->manager;
2177 int num_windows = man->buttons.num_windows;
2179 if (man->sort != SortNone) {
2180 int i, cur, start, finish, cmp_dir, correction;
2181 Button **bp;
2183 bp = man->buttons.buttons;
2184 if (win->button) {
2185 /* start search from our current location */
2186 cur = win->button->index;
2188 if (cur - 1 >= 0 &&
2189 compare_windows(man->sort,
2190 win, bp[cur - 1]->drawn_state.win) < 0) {
2191 start = cur - 1;
2192 finish = -1;
2193 cmp_dir = -1;
2194 correction = 1;
2196 else if (cur < num_windows - 1 &&
2197 compare_windows(man->sort,
2198 win, bp[cur + 1]->drawn_state.win) > 0) {
2199 start = cur + 1;
2200 finish = num_windows;
2201 cmp_dir = 1;
2202 correction = -1;
2204 else {
2205 return cur;
2208 else {
2209 start = 0;
2210 finish = num_windows;
2211 cmp_dir = 1;
2212 correction = 0;
2214 for (i = start; i != finish && bp[i]->drawn_state.win && cmp_dir *
2215 compare_windows(man->sort, win, bp[i]->drawn_state.win) > 0;
2216 i = i + cmp_dir)
2218 i += correction;
2219 ConsoleDebug(X11, "find_windows_spot: %s %d\n", win->display_string, i);
2220 return i;
2222 else {
2223 if (win->button) {
2224 /* already have a perfectly fine spot */
2225 return win->button->index;
2227 else {
2228 return num_windows;
2232 /* shouldn't get here */
2233 return -1;
2236 static void move_window_buttons(WinManager *man, int start, int finish,
2237 int offset)
2239 int n = man->buttons.num_buttons, i;
2240 Button **bp;
2242 ConsoleDebug(X11, "move_window_buttons: %s(%d): (%d, %d) + %d\n",
2243 man->titlename, n, start, finish, offset);
2245 if (finish >= n || finish + offset >= n || start < 0 || start + offset < 0) {
2246 ConsoleMessage("Internal error in move_window_buttons\n");
2247 ConsoleMessage("\tn = %d, start = %d, finish = %d, offset = %d\n",
2248 n, start, finish, offset);
2249 return;
2251 bp = man->buttons.buttons;
2252 if (offset > 0)
2254 for (i = finish; i >= start; i--)
2256 bp[i + offset]->drawn_state = bp[i]->drawn_state;
2257 bp[i + offset]->drawn_state.dirty_flags = ALL_CHANGED;
2258 if (bp[i + offset]->drawn_state.win)
2259 bp[i + offset]->drawn_state.win->button = bp[i + offset];
2261 for (i = 0; i < offset; i++)
2262 clear_button(bp[start + i]);
2264 else if (offset < 0)
2266 for (i = start; i <= finish; i++)
2268 bp[i + offset]->drawn_state = bp[i]->drawn_state;
2269 bp[i + offset]->drawn_state.dirty_flags = ALL_CHANGED;
2270 if (bp[i + offset]->drawn_state.win)
2271 bp[i + offset]->drawn_state.win->button = bp[i + offset];
2273 for (i = 0; i > offset; i--)
2274 clear_button(bp[finish + i]);
2278 static void insert_windows_button(WinData *win)
2280 int spot;
2281 int selected_index = -1;
2282 WinManager *man = win->manager;
2283 ButtonArray *buttons;
2285 ConsoleDebug(X11, "insert_windows_button: %s\n", win->titlename);
2287 assert(man);
2288 selected_index = selected_button_in_man(man);
2290 if (win->button) {
2291 ConsoleDebug(X11, "insert_windows_button: POSSIBLE BUG: "
2292 "already have a button\n");
2293 return;
2296 if (!win || !win->complete || !man) {
2297 ConsoleMessage("Internal error in insert_windows_button\n");
2298 ShutMeDown(1);
2301 buttons = &man->buttons;
2303 spot = find_windows_spot(win);
2305 increase_num_windows(buttons, 1);
2306 move_window_buttons(man, spot, buttons->num_windows - 2, 1);
2308 set_window_button(win, spot);
2309 if (selected_index >= 0) {
2310 ConsoleDebug(X11, "insert_windows_button: selected_index = %d, moving\n",
2311 selected_index);
2312 move_highlight(man, man->buttons.buttons[selected_index]);
2316 void delete_windows_button(WinData *win)
2318 int spot;
2319 int selected_index = -1;
2320 WinManager *man = (win->manager);
2321 ButtonArray *buttons;
2323 ConsoleDebug(X11, "delete_windows_button: %s\n", win->titlename);
2325 assert(man);
2327 buttons = &win->manager->buttons;
2329 assert(win->button);
2330 assert(buttons->buttons);
2332 selected_index = selected_button_in_man(man);
2333 ConsoleDebug(X11, "delete_windows_button: selected_index = %d\n",
2334 selected_index);
2336 spot = win->button->index;
2338 tips_cancel(man);
2339 move_window_buttons(win->manager, spot + 1, buttons->num_windows - 1, -1);
2340 increase_num_windows(buttons, -1);
2341 win->button = NULL;
2342 if (globals.focus_win == win) {
2343 globals.focus_win = NULL;
2345 if (selected_index >= 0) {
2346 ConsoleDebug(X11, "delete_windows_button: selected_index = %d, moving\n",
2347 selected_index);
2348 move_highlight(man, man->buttons.buttons[selected_index]);
2350 win->state = PLAIN_CONTEXT;
2353 void resort_windows_button(WinData *win)
2355 int new_spot, cur_spot;
2356 int selected_index = -1;
2357 WinManager *man = win->manager;
2359 assert(win->button && man);
2361 ConsoleDebug(X11, "In resort_windows_button: %s\n", win->resname);
2363 selected_index = selected_button_in_man(man);
2365 new_spot = find_windows_spot(win);
2366 cur_spot = win->button->index;
2368 print_button_info(win->button);
2370 if (new_spot != cur_spot) {
2371 ConsoleDebug(X11, "resort_windows_button: win moves from %d to %d\n",
2372 cur_spot, new_spot);
2373 if (new_spot < cur_spot) {
2374 move_window_buttons(man, new_spot, cur_spot - 1, +1);
2376 else {
2377 move_window_buttons(man, cur_spot + 1, new_spot, -1);
2379 set_window_button(win, new_spot);
2381 if (selected_index >= 0) {
2382 move_highlight(man, man->buttons.buttons[selected_index]);
2387 void move_highlight(WinManager *man, Button *b)
2389 WinData *old;
2391 assert(man);
2393 ConsoleDebug(X11, "move_highlight\n");
2395 old = globals.select_win;
2397 if (old && old->button) {
2398 del_win_state(old, SELECT_CONTEXT);
2399 old->manager->select_button = NULL;
2400 draw_button(old->manager, old->button->index, 0);
2402 if (b && b->drawn_state.win) {
2403 add_win_state(b->drawn_state.win, SELECT_CONTEXT);
2404 draw_button(man, b->index, 0);
2405 globals.select_win = b->drawn_state.win;
2407 else {
2408 globals.select_win = NULL;
2411 man->select_button = b;
2414 void man_exposed(WinManager *man, XEvent *theEvent)
2416 rectangle r1, r2;
2417 int i;
2418 Button **bp;
2420 ConsoleDebug(X11, "manager: %s, got expose\n", man->titlename);
2422 r1.x = theEvent->xexpose.x;
2423 r1.y = theEvent->xexpose.y;
2424 r1.width = theEvent->xexpose.width;
2425 r1.height = theEvent->xexpose.height;
2427 r2.width = man->geometry.boxwidth;
2428 r2.height = man->geometry.boxheight;
2430 bp = man->buttons.buttons;
2432 /* Background must be redrawn. */
2433 /* olicha: I do not think so */
2434 /*man->dirty_flags |= REDRAW_BG;*/
2436 if (0 && FHaveShapeExtension && man->shaped)
2438 /* There's some weird problem where if we change window shapes,
2439 * we can't draw into buttons in the area NewShape intersect
2440 * (not OldShape) until we get our Expose event. So, for now,
2441 * just redraw everything when we get Expose events. This has
2442 * the disadvantage of drawing buttons twice, but avoids having
2443 * to match which expose event results from which shape change.*/
2444 /* seems fixed ? olicha */
2445 if (man->buttons.num_windows)
2447 for (i = 0; i < man->buttons.num_windows; i++)
2449 bp[i]->drawn_state.dirty_flags |= REDRAW_BUTTON;
2452 else
2454 draw_empty_manager(man);
2457 return;
2460 if (CSET_IS_TRANSPARENT_PR(man->colorsets[DEFAULT]))
2462 clear_empty_region(man);
2464 if (man->buttons.num_windows)
2466 for (i = 0; i < man->buttons.num_windows; i++)
2468 r2.x = index_to_col(man, i) * r2.width;
2469 r2.y = index_to_row(man, i) * r2.height;
2470 if (fvwmrect_do_rectangles_intersect(
2471 &r1, &r2))
2473 bp[i]->drawn_state.ex = max(r1.x,r2.x);
2474 bp[i]->drawn_state.ey = max(r1.y,r2.y);
2475 bp[i]->drawn_state.ew =
2476 min(r1.x+r1.width,r2.x+r2.width) -
2477 max(r1.x,r2.x);
2478 bp[i]->drawn_state.eh =
2479 min(r1.y+r1.height, r2.y+r2.height) -
2480 max(r1.y,r2.y);
2481 bp[i]->drawn_state.dirty_flags |= REDRAW_BUTTON;
2485 else
2487 draw_empty_manager(man);
2492 * tips routine
2495 static char *get_tips(WinManager *man, Button *b)
2497 ButtonGeometry g;
2498 char *s;
2499 static char *free_str = NULL;
2501 if (man->tips == TIPS_NEVER || b == NULL)
2503 return NULL;
2506 if (free_str != NULL)
2508 free(free_str);
2509 free_str = NULL;
2512 if (man->tips_formatstring && b->drawn_state.win)
2514 CopyString(
2515 &s, make_display_string(
2516 b->drawn_state.win, man->tips_formatstring,
2517 0));
2518 free_str = s;
2520 else
2522 s = b->drawn_state.display_string;
2525 if (s == NULL)
2527 return NULL;
2530 if (man->tips == TIPS_ALWAYS)
2532 return s;
2535 /* TIPS_NEEDED */
2536 if (free_str != NULL &&
2537 (b->drawn_state.display_string == NULL ||
2538 strcmp(s, b->drawn_state.display_string)))
2540 return s;
2543 get_button_geometry(man, b, &g);
2545 if (g.text_x + FlocaleTextWidth(man->FButtonFont, s, strlen(s))
2546 > g.button_x + g.button_w - 4)
2548 return s;
2551 return NULL;
2554 void tips_cancel(WinManager *man)
2556 int j;
2558 if (man)
2560 man->tipped_button = NULL;
2562 else
2564 for (j = 0; j < globals.num_managers; j++)
2566 man = &globals.managers[j];
2567 man->tipped_button = NULL;
2570 FTipsCancel(theDisplay);
2573 void tips_on(WinManager *man, Button *b)
2575 char *tips_str;
2577 if ((tips_str = get_tips(man, b)) != NULL)
2579 FTipsOn(
2580 theDisplay, man->theWindow, man->tips_conf, (void *)b,
2581 tips_str, b->x, b->y, b->w, b->h);
2582 man->tipped_button = b;
2584 else
2586 tips_cancel(man);
2590 void tips_update_label(WinManager *man)
2592 char *tips_str;
2594 if ((tips_str = get_tips(man, man->tipped_button)) != NULL)
2596 FTipsUpdateLabel(theDisplay, tips_str);
2598 else
2600 tips_cancel(man);
2606 * Debugging routines
2609 void check_managers_consistency(void)
2611 #ifdef FVWM_DEBUG_MSGS
2612 int i, j;
2613 Button **b;
2615 for (i = 0; i < globals.num_managers; i++) {
2616 for (j = 0, b = globals.managers[i].buttons.buttons;
2617 j < globals.managers[i].buttons.num_buttons; j++, b++) {
2618 if ((*b)->drawn_state.win && (*b)->drawn_state.win->button != *b) {
2619 ConsoleMessage("manager %d, button %d is confused\n", i, j);
2620 abort();
2622 else if ((*b)->drawn_state.win &&
2623 j >= globals.managers[i].buttons.num_windows) {
2624 ConsoleMessage("manager %d: button %d has window and shouldn't\n",
2625 i, j);
2626 abort();
2630 #endif
2633 static void print_button_info(Button *b)
2635 #ifdef FVWM_DEBUG_MSGS
2636 ConsoleMessage("button: %d\n", b->index);
2637 ConsoleMessage("win: 0x%x\n", (unsigned int) b->drawn_state.win);
2638 ConsoleMessage("dirty: 0x%x\n", b->drawn_state.dirty_flags);
2639 if (b->drawn_state.win) {
2640 ConsoleMessage("name: %s\n", b->drawn_state.display_string);
2641 ConsoleMessage("iconified: %d state %d\n", b->drawn_state.iconified,
2642 b->drawn_state.state);
2643 ConsoleMessage("win->button: 0x%x\n",
2644 (unsigned int) b->drawn_state.win->button);
2646 #endif