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.
6 *
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.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, see: <http://www.gnu.org/licenses/>
14 */
15
16 #include "config.h"
17
18 #include "libs/fvwmlib.h"
19 #include "libs/FShape.h"
20 #include "libs/Module.h"
21 #include "libs/FEvent.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"
32
33 extern FlocaleWinString *FwinString;
34
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
43
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
50
51 /* ButtonArray dirty bits: */
52 #define NUM_BUTTONS_CHANGED 1
53 #define NUM_WINDOWS_CHANGED 2
54
55 #define ALL_CHANGED 0x7f /* high bit is special */
56
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;
63
64 static void print_button_info(Button *b);
65 static void insert_windows_button(WinData *win);
66
67 /*
68 * Utility leaf functions
69 */
70
selected_button_in_man(WinManager * man)71 static int selected_button_in_man(WinManager *man)
72 {
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;
79 }
80 return -1;
81 }
82
83 #if 0
84 static void ClipRectangle(WinManager *man, int context,
85 int x, int y, int w, int h)
86 {
87 XRectangle r;
88
89 r.x = x;
90 r.y = y;
91 r.width = w;
92 r.height = h;
93
94 XSetClipRectangles(theDisplay, man->hiContext[context], 0, 0, &r, 1,
95 YXBanded);
96 }
97 #endif
98
GetRegion(int x,int y,int w,int h)99 static Region GetRegion(int x, int y, int w, int h)
100 {
101 Region region;
102 XRectangle rectangle;
103
104 rectangle.x = x;
105 rectangle.y = y;
106 rectangle.width = w;
107 rectangle.height = h;
108
109 region = XCreateRegion();
110 XUnionRectWithRegion(&rectangle, region, region);
111 return region;
112 }
113
num_visible_rows(int n,int cols)114 static int num_visible_rows(int n, int cols)
115 {
116 return (n - 1) / cols + 1;
117 }
118
first_row_len(int n,int cols)119 static int first_row_len(int n, int cols)
120 {
121 int ret = n % cols;
122 if (ret == 0)
123 ret = cols;
124
125 return ret;
126 }
127
index_to_box(WinManager * man,int index)128 static int index_to_box(WinManager *man, int index)
129 {
130 int first_len, n, cols;
131
132 if (man->geometry.dir & GROW_DOWN) {
133 return index;
134 }
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;
143 }
144 }
145
box_to_index(WinManager * man,int box)146 static int box_to_index(WinManager *man, int box)
147 {
148 int first_len, n, cols;
149 int index = box;
150
151 if (man->geometry.dir & GROW_DOWN)
152 {
153 return index;
154 }
155 else
156 {
157 n = man->buttons.num_windows;
158 cols = man->geometry.cols;
159 first_len = first_row_len(n, cols);
160
161 index = box - (man->geometry.rows - num_visible_rows(n, cols)) * cols;
162 if (!((index >= 0 && index < first_len) || index >= cols))
163 {
164 index = -1;
165 }
166 if (index >= first_len)
167 {
168 index -= cols - first_len;
169 }
170
171 }
172
173 return index;
174 }
175
index_to_row(WinManager * man,int index)176 static int index_to_row(WinManager *man, int index)
177 {
178 int row;
179
180 row = index_to_box(man, index) / man->geometry.cols;
181
182 return row;
183 }
184
index_to_col(WinManager * man,int index)185 static int index_to_col(WinManager *man, int index)
186 {
187 int col;
188
189 col = index_to_box(man, index) % man->geometry.cols;
190
191 return col;
192 }
193
rects_equal(XRectangle * x,XRectangle * y)194 static int rects_equal(XRectangle *x, XRectangle *y)
195 {
196 return (x->x == y->x) && (x->y == y->y) && (x->width == y->width) &&
197 (x->height == y->height);
198 }
199
top_y_coord(WinManager * man)200 static int top_y_coord(WinManager *man)
201 {
202 if (man->buttons.num_windows > 0 && (man->geometry.dir & GROW_UP)) {
203 return index_to_row(man, 0) * man->geometry.boxheight;
204 }
205 else {
206 return 0;
207 }
208 }
209
figure_geometry(WinManager * man)210 static ManGeometry *figure_geometry(WinManager *man)
211 {
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 */
215
216 static ManGeometry ret;
217 ManGeometry *g = &man->geometry;
218 int n = man->buttons.num_windows;
219 Bool noWindow = False;
220
221 ret = *g;
222
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);
227
228 if (n == 0)
229 {
230 n = 1;
231 noWindow = True;
232 }
233
234 if (man->geometry.dir & GROW_FIXED)
235 {
236 ret.cols = num_visible_rows(n, g->rows);
237 ret.boxwidth = ret.width / ret.cols;
238 if (man->max_button_width_columns > 0)
239 {
240 man->max_button_width =
241 ret.width / man->max_button_width_columns;
242 }
243 if (!noWindow && man->max_button_width > 0 &&
244 ret.boxwidth > man->max_button_width)
245 {
246 int i = 1;
247 while(i <= g->rows)
248 {
249 if (n*man->max_button_width <= ret.width)
250 {
251 ret.cols = n;
252 break;
253 }
254 else if ((n/i)*man->max_button_width <=
255 ret.width)
256 {
257 ret.cols =
258 ret.width /
259 man->max_button_width;
260 break;
261 }
262 i++;
263 }
264 ret.boxwidth = man->max_button_width;
265 }
266 if (ret.boxwidth < 1)
267 {
268 ret.boxwidth = 1;
269 }
270 }
271 else
272 {
273 if (man->geometry.dir & GROW_VERT)
274 {
275 if (g->cols)
276 {
277 ret.rows = num_visible_rows(n, g->cols);
278 }
279 else
280 {
281 ConsoleMessage(
282 "Internal error in figure_geometry\n");
283 ret.rows = 1;
284 }
285 ret.height = ret.rows * g->boxheight;
286 ret.width = ret.cols * g->boxwidth;
287 if (ret.boxwidth < 1)
288 {
289 ret.boxwidth = 1;
290 }
291 }
292 else
293 {
294 /* need to set resize inc */
295 if (g->rows)
296 {
297 ret.cols = num_visible_rows(n, g->rows);
298 }
299 else
300 {
301 ConsoleMessage(
302 "Internal error in figure_geometry\n");
303 ret.cols = 1;
304 }
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)
309 {
310 ret.boxwidth = 1;
311 }
312 }
313 }
314
315 ConsoleDebug(
316 X11, "figure_geometry: %d %d %d %d %d\n",
317 n, ret.width, ret.height, ret.cols, ret.rows);
318
319 return &ret;
320 }
321
query_geometry(WinManager * man)322 static ManGeometry *query_geometry(WinManager *man)
323 {
324 XWindowAttributes frame_attr, win_attr;
325 int off_x, off_y;
326 static ManGeometry g;
327
328 assert(man->window_mapped);
329
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))
334 {
335 g.x = frame_attr.x + off_x + frame_attr.border_width;
336 g.y = frame_attr.y + off_y + frame_attr.border_width;
337 }
338 else
339 {
340 g.x = off_x;
341 g.y = off_y;
342 fvwm_debug(__func__,
343 "%s: query_geometry: failed to get frame attributes.\n",
344 MyName);
345 }
346 if (XGetWindowAttributes(theDisplay, man->theWindow, &win_attr))
347 {
348 g.width = win_attr.width;
349 g.height = win_attr.height;
350 }
351 else
352 {
353 g.width = 1;
354 g.height = 1;
355 fvwm_debug(__func__,
356 "%s: query_geometry: failed to get window attributes.\n",
357 MyName);
358 }
359
360 return &g;
361 }
362
fix_manager_size(WinManager * man,int w,int h)363 static void fix_manager_size(WinManager *man, int w, int h)
364 {
365 XSizeHints size;
366 long mask;
367
368 if (man->geometry.dir & GROW_FIXED)
369 return;
370
371 FGetWMNormalHints(theDisplay, man->theWindow, &size, &mask);
372 size.min_width = w;
373 size.max_width = w;
374 size.min_height = h;
375 size.max_height = h;
376 XSetWMNormalHints(theDisplay, man->theWindow, &size);
377 }
378
release_manager_size(WinManager * man)379 static void release_manager_size(WinManager *man)
380 {
381 XSizeHints size;
382 long mask;
383
384 if (man->geometry.dir & GROW_FIXED)
385 return;
386
387 FGetWMNormalHints(theDisplay, man->theWindow, &size, &mask);
388 size.min_width = 1;
389 size.max_width = 65535;
390 size.min_height = 1;
391 size.max_height = 65535;
392 XSetWMNormalHints(theDisplay, man->theWindow, &size);
393 }
394
395 /* Like XMoveResizeWindow(), but can move in arbitary directions */
resize_window(WinManager * man)396 static void resize_window(WinManager *man)
397 {
398 ManGeometry *g;
399 int x_changed, y_changed, dir;
400
401 dir = man->geometry.dir;
402 /* Remove any size limits so that the window can be resized without
403 * warnings. */
404 release_manager_size(man);
405
406 if ((dir & GROW_DOWN) && (dir & GROW_RIGHT)) {
407 XResizeWindow(theDisplay, man->theWindow, man->geometry.width,
408 man->geometry.height);
409 }
410 else {
411 MyXGrabServer(theDisplay);
412 g = query_geometry(man);
413 x_changed = y_changed = 0;
414 if (dir & GROW_LEFT) {
415 man->geometry.x = g->x + g->width - man->geometry.width;
416 x_changed = 1;
417 }
418 else {
419 man->geometry.x = g->x;
420 }
421 if (dir & GROW_UP) {
422 man->geometry.y = g->y + g->height - man->geometry.height;
423 y_changed = 1;
424 }
425 else {
426 man->geometry.y = g->y;
427 }
428
429 ConsoleDebug(X11, "queried: y: %d, h: %d, queried: %d\n", g->y,
430 man->geometry.height, g->height);
431
432 if (x_changed || y_changed) {
433 XMoveResizeWindow(theDisplay, man->theWindow,
434 man->geometry.x,
435 man->geometry.y,
436 man->geometry.width, man->geometry.height);
437 }
438 else {
439 XResizeWindow(theDisplay, man->theWindow, man->geometry.width,
440 man->geometry.height);
441 }
442 MyXUngrabServer(theDisplay);
443 }
444 fix_manager_size(man, man->geometry.width, man->geometry.height);
445 }
446
make_display_string(WinData * win,char * format,int len)447 static char *make_display_string(WinData *win, char *format, int len)
448 {
449 #define MAX_DISPLAY_SIZE 1024
450 #define COPY(field) \
451 temp_p = win->field; \
452 if (temp_p) \
453 while (*temp_p && out_p - buf < len - 1) \
454 *out_p++ = *temp_p++; \
455 in_p++;
456
457 static char buf[MAX_DISPLAY_SIZE];
458 char *string, *in_p, *out_p, *temp_p;
459
460 in_p = format;
461 out_p = buf;
462
463 if (len > MAX_DISPLAY_SIZE || len <= 0)
464 len = MAX_DISPLAY_SIZE;
465
466 while (*in_p && out_p - buf < len - 1) {
467 if (*in_p == '%') {
468 switch (*(++in_p)) {
469 case 'i':
470 COPY(visible_icon_name);
471 break;
472
473 case 't':
474 COPY(visible_name);
475 break;
476
477 case 'r':
478 COPY(resname);
479 break;
480
481 case 'c':
482 COPY(classname);
483 break;
484
485 default:
486 *out_p++ = *in_p++;
487 break;
488 }
489 }
490 else {
491 *out_p++ = *in_p++;
492 }
493 }
494
495 *out_p++ = '\0';
496
497 string = buf;
498 return string;
499
500 #undef COPY
501 #undef MAX_DISPLAY_SIZE
502 }
503
button_above(WinManager * man,Button * b)504 Button *button_above(WinManager *man, Button *b)
505 {
506 int n = man->buttons.num_windows, cols = man->geometry.cols;
507 int i = -1;
508
509 if (b) {
510 i = box_to_index(man, index_to_box(man, b->index) - cols);
511 }
512 if (i < 0 || i >= n)
513 return b;
514 else
515 return man->buttons.buttons[i];
516 }
517
button_below(WinManager * man,Button * b)518 Button *button_below(WinManager *man, Button *b)
519 {
520 int n = man->buttons.num_windows;
521 int i = -1;
522
523 if (b) {
524 i = box_to_index(man, index_to_box(man, b->index) + man->geometry.cols);
525 }
526 if (i < 0 || i >= n)
527 return b;
528 else
529 return man->buttons.buttons[i];
530 }
531
button_right(WinManager * man,Button * b)532 Button *button_right(WinManager *man, Button *b)
533 {
534 int i = -1;
535
536 if (index_to_col(man, b->index) < man->geometry.cols - 1) {
537 i = box_to_index(man, index_to_box(man, b->index) + 1);
538 }
539
540 if (i < 0 || i >= man->buttons.num_windows)
541 return b;
542 else
543 return man->buttons.buttons[i];
544 }
545
button_left(WinManager * man,Button * b)546 Button *button_left(WinManager *man, Button *b)
547 {
548 int i = -1;
549 if (index_to_col(man, b->index) > 0) {
550 i = box_to_index(man, index_to_box(man, b->index) - 1);
551 }
552
553 if (i < 0 || i >= man->buttons.num_windows)
554 return b;
555 else
556 return man->buttons.buttons[i];
557 }
558
button_next(WinManager * man,Button * b)559 Button *button_next(WinManager *man, Button *b)
560 {
561 int i = b->index + 1;
562
563 if (i >= 0 && i < man->buttons.num_windows)
564 return man->buttons.buttons[i];
565 else
566 return b;
567 }
568
button_prev(WinManager * man,Button * b)569 Button *button_prev(WinManager *man, Button *b)
570 {
571 int i = b->index - 1;
572
573 if (i >= 0 && i < man->buttons.num_windows)
574 return man->buttons.buttons[i];
575 else
576 return b;
577 }
578
xy_to_button(WinManager * man,int x,int y)579 Button *xy_to_button(WinManager *man, int x, int y)
580 {
581 ManGeometry *g;
582 int row, col, box, index;
583
584 g = figure_geometry(man);
585 row = y / g->boxheight;
586 col = x / g->boxwidth;
587
588 if (x >= 0 && x <= g->width &&
589 y >= 0 && y <= g->height && col < g->cols)
590 {
591 box = row * g->cols + col;
592 index = box_to_index(man, box);
593 if (index >= 0 && index < man->buttons.num_windows)
594 {
595 return man->buttons.buttons[index];
596 }
597 }
598
599 return NULL;
600 }
601
602 /*
603 * Routines which change dirtyable state
604 */
605
set_button_geometry(WinManager * man,Button * box)606 static void set_button_geometry(WinManager *man, Button *box)
607 {
608 ManGeometry *g;
609
610 g = figure_geometry(man);
611 box->x = index_to_col(man, box->index) * g->boxwidth;
612 box->y = index_to_row(man, box->index) * g->boxheight;
613 box->w = g->boxwidth;
614 box->h = g->boxheight;
615 box->drawn_state.dirty_flags |= GEOMETRY_CHANGED;
616 }
617
clear_button(Button * b)618 static void clear_button(Button *b)
619 {
620 assert(b);
621 b->drawn_state.win = NULL;
622 b->drawn_state.dirty_flags = REDRAW_BUTTON;
623 b->drawn_state.display_string = NULL;
624 b->drawn_state.ew = 0;
625 }
626
set_window_button(WinData * win,int index)627 static void set_window_button(WinData *win, int index)
628 {
629 Button *b;
630
631 assert(win->manager && index < win->manager->buttons.num_buttons);
632
633 b = win->manager->buttons.buttons[index];
634
635 /* Can optimize here */
636 if (FMiniIconsSupported)
637 {
638 b->drawn_state.pic = win->pic;
639 }
640 b->drawn_state.win = win;
641 copy_string(&b->drawn_state.display_string, win->display_string);
642 b->drawn_state.iconified = win->iconified;
643 b->drawn_state.state = win->state;
644 b->drawn_state.dirty_flags = ALL_CHANGED;
645
646 win->button = b;
647 }
648
set_num_buttons(ButtonArray * buttons,int n)649 static void set_num_buttons(ButtonArray *buttons, int n)
650 {
651 int i;
652
653 ConsoleDebug(X11, "set_num_buttons: %d %d\n", buttons->num_buttons, n);
654
655 if (n > buttons->num_buttons) {
656 buttons->dirty_flags |= NUM_BUTTONS_CHANGED;
657 buttons->buttons = fxrealloc((void *)buttons->buttons, n, sizeof(Button *));
658
659 for (i = buttons->num_buttons; i < n; i++) {
660 buttons->buttons[i] = fxcalloc(1, sizeof(Button));
661 buttons->buttons[i]->drawn_state.display_string = NULL;
662 buttons->buttons[i]->index = i;
663 }
664
665 buttons->dirty_flags |= NUM_BUTTONS_CHANGED;
666 buttons->num_buttons = n;
667 }
668 }
669
increase_num_windows(ButtonArray * buttons,int off)670 static void increase_num_windows(ButtonArray *buttons, int off)
671 {
672 int n;
673
674 if (off != 0) {
675 buttons->num_windows += off;
676 buttons->dirty_flags |= NUM_WINDOWS_CHANGED;
677
678 if (buttons->num_windows > buttons->num_buttons) {
679 n = buttons->num_windows + 10;
680 set_num_buttons(buttons, n);
681 }
682 }
683 }
684
set_man_gravity_origin(WinManager * man)685 static void set_man_gravity_origin(WinManager *man)
686 {
687 if (man->gravity == NorthWestGravity || man->gravity == NorthEastGravity)
688 man->geometry.gravity_y = 0;
689 else
690 man->geometry.gravity_y = man->geometry.height;
691 if (man->gravity == NorthWestGravity || man->gravity == SouthWestGravity)
692 man->geometry.gravity_x = 0;
693 else
694 man->geometry.gravity_x = man->geometry.width;
695 }
696
set_man_geometry(WinManager * man,ManGeometry * new)697 static void set_man_geometry(WinManager *man, ManGeometry *new)
698 {
699 int n;
700
701 if (man->geometry.width != new->width ||
702 man->geometry.height != new->height ||
703 man->geometry.rows != new->rows ||
704 man->geometry.cols != new->cols ||
705 man->geometry.boxheight != new->boxheight ||
706 man->geometry.boxwidth != new->boxwidth) {
707 man->dirty_flags |= GEOMETRY_CHANGED;
708 }
709
710 man->geometry = *new;
711 set_man_gravity_origin(man);
712 n = man->geometry.rows * man->geometry.cols;
713 if (man->buttons.num_buttons < n)
714 set_num_buttons(&man->buttons, n + 10);
715 }
716
set_manager_width(WinManager * man,int width)717 void set_manager_width(WinManager *man, int width)
718 {
719 if (width != man->geometry.width) {
720 ConsoleDebug(X11, "set_manager_width: %d -> %d, %d -> %d\n",
721 man->geometry.width, width, man->geometry.boxwidth,
722 width / man->geometry.cols);
723 man->geometry.width = width;
724 man->geometry.boxwidth = width / man->geometry.cols;
725 if (man->geometry.boxwidth < 1)
726 man->geometry.boxwidth = 1;
727 man->dirty_flags |= GEOMETRY_CHANGED;
728 }
729 }
730
force_manager_redraw(WinManager * man)731 void force_manager_redraw(WinManager *man)
732 {
733 man->dirty_flags |= REDRAW_MANAGER;
734 draw_manager(man);
735 }
736
set_win_picture(WinData * win,Pixmap picture,Pixmap mask,Pixmap alpha,unsigned int depth,unsigned int width,unsigned int height)737 void set_win_picture(WinData *win, Pixmap picture, Pixmap mask, Pixmap alpha,
738 unsigned int depth, unsigned int width,
739 unsigned int height)
740 {
741 if (!FMiniIconsSupported)
742 {
743 return;
744 }
745 if (win->button)
746 win->button->drawn_state.dirty_flags |= PICTURE_CHANGED;
747 win->old_pic = win->pic;
748 win->pic.picture = picture;
749 win->pic.mask = mask;
750 win->pic.alpha = alpha;
751 win->pic.width = width;
752 win->pic.height = height;
753 win->pic.depth = depth;
754 }
755
set_win_iconified(WinData * win,int iconified)756 void set_win_iconified(WinData *win, int iconified)
757 {
758 /* This change has become necessary because with colorsets we don't
759 * know the background colour of the button (gradient background).
760 * Thus the button has to be redrawn completely, we can not just draw
761 * the square in the background colour. */
762 char string[256];
763 WinData *man_data = NULL;
764 Bool do_animate = True;
765
766 if (win->button != NULL && (win->iconified != iconified) )
767 {
768 if (win->manager->flags.is_shaded)
769 {
770 man_data = id_to_win(win->manager->theWindow);
771 if (!man_data->geometry_set)
772 {
773 do_animate = False;
774 }
775 }
776 else if (win->manager->swallowed)
777 {
778 if (win->manager->swallower_win &&
779 (man_data =
780 id_to_win(win->manager->swallower_win)) &&
781 man_data->geometry_set)
782 {
783 /* ok */
784 if (!IS_SHADED(man_data))
785 {
786 /* animate as usual */
787 man_data = NULL;
788 }
789 }
790 else
791 {
792 do_animate = False;
793 }
794 }
795 /* we check the win->button width and height because they
796 * will only be == zero on init, and if we didn't check we
797 * would get animations of all iconified windows to the far
798 * left of whereever thae manager would eventually be. */
799 if (do_animate && win->manager->AnimCommand &&
800 (win->manager->AnimCommand[0] != 0)
801 && IS_ICON_SUPPRESSED(win) && (win->button->w != 0)
802 && (win->button->h !=0))
803 {
804 int abs_x, abs_y, w, h;
805 Window junkw;
806
807 XTranslateCoordinates(
808 theDisplay, win->manager->theWindow,
809 theRoot, win->button->x, win->button->y,
810 &abs_x, &abs_y, &junkw);
811 w = win->button->w;
812 h = win->button->h;
813 if (man_data)
814 {
815 if (w > man_data->real_g.width)
816 {
817 w = 1;
818 }
819 if (h > man_data->real_g.height)
820 {
821 h = 1;
822 }
823 if (abs_x < man_data->real_g.x ||
824 abs_x > man_data->real_g.x +
825 man_data->real_g.width)
826 {
827 abs_x = man_data->real_g.x;
828 }
829 if (abs_y < man_data->real_g.y ||
830 abs_y > man_data->real_g.y +
831 man_data->real_g.height)
832 {
833 abs_y = man_data->real_g.y;
834 }
835 }
836 if (iconified)
837 {
838 sprintf(string, "%s %d %d %d %d %d %d %d %d",
839 win->manager->AnimCommand,
840 (int)win->x, (int)win->y,
841 (int)win->width, (int)win->height,
842 abs_x, abs_y, w, h);
843 }
844 else
845 {
846 sprintf(string, "%s %d %d %d %d %d %d %d %d",
847 win->manager->AnimCommand,
848 abs_x, abs_y, w, h,
849 (int)win->x, (int)win->y,
850 (int)win->width, (int)win->height);
851 }
852 SendText(fvwm_fd, string, 0);
853 }
854 win->button->drawn_state.dirty_flags |= ICON_STATE_CHANGED;
855 }
856 win->iconified = iconified;
857 if (iconified)
858 {
859 win->state = ICON_CONTEXT;
860 if (globals.select_win == win)
861 {
862 add_win_state(win, SELECT_CONTEXT);
863 }
864 }
865 else
866 {
867 win->state = PLAIN_CONTEXT;
868 if (globals.select_win == win)
869 {
870 add_win_state(win, SELECT_CONTEXT);
871 }
872 if (globals.focus_win == win)
873 {
874 add_win_state(win, FOCUS_CONTEXT);
875 }
876 }
877 }
878
set_win_state(WinData * win,int state)879 void set_win_state(WinData *win, int state)
880 {
881 if (win->button && win->state != state)
882 win->button->drawn_state.dirty_flags |= STATE_CHANGED;
883 win->state = state;
884 }
885
886 /* this is "broken" */
add_win_state(WinData * win,int flag)887 void add_win_state(WinData *win, int flag)
888 {
889 int old_state = win->state;
890
891 if (flag == FOCUS_CONTEXT)
892 {
893 if (win->state == SELECT_CONTEXT ||
894 win->state == FOCUS_SELECT_CONTEXT)
895 {
896 win->state = FOCUS_SELECT_CONTEXT;
897 }
898 else
899 {
900 win->state = FOCUS_CONTEXT;
901 }
902 }
903 else if (flag == SELECT_CONTEXT)
904 {
905 if (win->state == FOCUS_CONTEXT ||
906 win->state == FOCUS_SELECT_CONTEXT)
907 {
908 win->state = FOCUS_SELECT_CONTEXT;
909 }
910 else if (win->state == ICON_CONTEXT ||
911 win->state == ICON_SELECT_CONTEXT)
912 {
913 win->state = ICON_SELECT_CONTEXT;
914 }
915 else
916 {
917 win->state = SELECT_CONTEXT;
918 }
919 }
920 else
921 {
922 /* add_win_state should not be called */
923 win->state = flag;
924 }
925 if (win->button && (old_state != win->state))
926 {
927 win->button->drawn_state.dirty_flags |= STATE_CHANGED;
928 }
929 }
930
931 /* this is "broken" */
del_win_state(WinData * win,int flag)932 void del_win_state(WinData *win, int flag)
933 {
934 if (flag == FOCUS_CONTEXT)
935 {
936 if (win->state == FOCUS_SELECT_CONTEXT)
937 {
938 if (win->iconified)
939 {
940 win->state = ICON_SELECT_CONTEXT;
941 }
942 else
943 {
944 win->state = SELECT_CONTEXT;
945 }
946 }
947 else if (win->state == FOCUS_CONTEXT)
948 {
949 if (win->iconified)
950 {
951 win->state = ICON_CONTEXT;
952 }
953 else
954 {
955 win->state = PLAIN_CONTEXT;
956 }
957 }
958 else
959 {
960 /* nothing */
961 }
962 }
963 else if (flag == SELECT_CONTEXT)
964 {
965 if (win->state == FOCUS_SELECT_CONTEXT)
966 {
967 win->state = FOCUS_CONTEXT;
968 }
969 else if (win->state == ICON_SELECT_CONTEXT)
970 {
971 win->state = ICON_CONTEXT;
972 }
973 else if (win->state == SELECT_CONTEXT)
974 {
975 win->state = PLAIN_CONTEXT;
976 }
977 else
978 {
979 /* */
980 }
981 }
982 else
983 {
984 /* del_win_state should not be called */
985 /*win->state = PLAIN_CONTEXT;*/
986 }
987 if (win->button)
988 {
989 win->button->drawn_state.dirty_flags |= STATE_CHANGED;
990 }
991 }
992
set_win_displaystring(WinData * win)993 void set_win_displaystring(WinData *win)
994 {
995 WinManager *man = win->manager;
996 int maxlen;
997 char *tmp;
998
999 if (man && win->button && win->button == man->tipped_button)
1000 {
1001 tips_update_label(man);
1002 }
1003
1004 if (!man || ((man->format_depend & CLASS_NAME) && !win->classname)
1005 || ((man->format_depend & ICON_NAME) && !win->visible_icon_name)
1006 || ((man->format_depend & TITLE_NAME) && !win->visible_name)
1007 || ((man->format_depend & RESOURCE_NAME) && !win->resname)) {
1008 return;
1009 }
1010
1011 if (man->window_up) {
1012 assert(man->geometry.width && man->fontwidth);
1013 maxlen = man->geometry.width / man->fontwidth + 2 /* fudge factor */;
1014 }
1015 else {
1016 maxlen = 0;
1017 }
1018
1019 tmp = make_display_string(win, man->formatstring, maxlen);
1020 if ((tmp == NULL && win->display_string == NULL) ||
1021 (tmp != NULL && win->display_string != NULL &&
1022 strcmp(tmp, win->display_string) == 0))
1023 {
1024 return;
1025 }
1026 copy_string(&win->display_string, tmp);
1027 if (win->button)
1028 win->button->drawn_state.dirty_flags |= STRING_CHANGED;
1029 }
1030
1031 /* This function is here and not with the other static utility functions
1032 because it basically is the inverse of set_shape() */
1033
clear_empty_region(WinManager * man)1034 static void clear_empty_region(WinManager *man)
1035 {
1036 XRectangle rects[3];
1037 int num_rects = 0, n = man->buttons.num_windows, cols = man->geometry.cols;
1038 int rows = man->geometry.rows;
1039 int boxwidth = man->geometry.boxwidth;
1040 int boxheight = man->geometry.boxheight;
1041
1042 if (man->shaped)
1043 return;
1044
1045 rects[1].x = rects[1].y = rects[1].width = rects[1].height = 0;
1046
1047 if (n == 0 || rows * cols == 0 /* just be to safe */)
1048 {
1049 rects[0].x = 0;
1050 rects[0].y = 0;
1051 rects[0].width = man->geometry.width;
1052 rects[0].height = man->geometry.height;
1053 num_rects = 1;
1054 }
1055 else if (man->geometry.dir & GROW_DOWN)
1056 {
1057 assert(cols);
1058 if (n % cols == 0)
1059 {
1060 rects[0].x = 0;
1061 rects[0].y = num_visible_rows(n, cols) * man->geometry.boxheight;
1062 rects[0].width = man->geometry.width;
1063 rects[0].height = man->geometry.height - rects[0].y;
1064 num_rects = 1;
1065 }
1066 else
1067 {
1068 rects[0].x = (n % cols) * man->geometry.boxwidth;
1069 rects[0].y = (num_visible_rows(n, cols) - 1) * man->geometry.boxheight;
1070 rects[0].width = man->geometry.width - rects[0].x;
1071 rects[0].height = boxheight;
1072 rects[1].x = 0;
1073 rects[1].y = rects[0].y + rects[0].height;
1074 rects[1].width = man->geometry.width;
1075 rects[1].height = man->geometry.height - rects[0].y;
1076 num_rects = 2;
1077 }
1078 }
1079 else
1080 {
1081 assert(cols);
1082 /* for shaped windows, we won't see this part of the window */
1083 if (n % cols == 0)
1084 {
1085 rects[0].x = 0;
1086 rects[0].y = 0;
1087 rects[0].width = man->geometry.width;
1088 rects[0].height = top_y_coord(man);
1089 num_rects = 1;
1090 }
1091 else
1092 {
1093 rects[0].x = 0;
1094 rects[0].y = 0;
1095 rects[0].width = man->geometry.width;
1096 rects[0].height = top_y_coord(man);
1097 rects[1].x = (n % cols) * man->geometry.boxwidth;
1098 rects[1].y = rects[0].height;
1099 rects[1].width = man->geometry.width - rects[1].x;
1100 rects[1].height = boxheight;
1101 num_rects = 2;
1102 }
1103 }
1104
1105 if (n != 0 && rows * cols != 0)
1106 {
1107 rects[num_rects].x = cols * boxwidth;
1108 rects[num_rects].y = 0;
1109 rects[num_rects].width = man->geometry.width - cols * boxwidth;
1110 rects[num_rects].height = man->geometry.height;
1111 num_rects++;
1112 }
1113
1114 ConsoleDebug(X11, "Clearing: %d: (%d, %d, %d, %d) + (%d, %d, %d, %d)\n",
1115 num_rects,
1116 rects[0].x, rects[0].y, rects[0].width, rects[0].height,
1117 rects[1].x, rects[1].y, rects[1].width, rects[1].height);
1118
1119 int cset = man->colorsets[DEFAULT];
1120
1121 if (CSET_IS_TRANSPARENT_PR_PURE(cset))
1122 {
1123 for(n=0; n < num_rects; n++)
1124 {
1125 if (rects[n].width > 0 && rects[n].height > 0)
1126 {
1127 XClearArea(
1128 theDisplay, man->theWindow, rects[n].x, rects[n].y,
1129 rects[n].width, rects[n].height, False);
1130 }
1131 }
1132 }
1133 else if (cset >= 0)
1134 {
1135 for(n=0; n < num_rects; n++)
1136 {
1137 if (rects[n].width > 0 && rects[n].height > 0)
1138 {
1139 SetRectangleBackground(theDisplay, man->theWindow,
1140 rects[n].x, rects[n].y, rects[n].width,
1141 rects[n].height, &Colorset[cset], Pdepth,
1142 man->backContext[DEFAULT]);
1143 }
1144 }
1145 }
1146 else
1147 {
1148 XFillRectangles(theDisplay, man->theWindow,
1149 man->backContext[DEFAULT], rects, num_rects);
1150 }
1151 }
1152
set_shape(WinManager * man)1153 void set_shape(WinManager *man)
1154 {
1155 if (FShapesSupported)
1156 {
1157 int n;
1158 XRectangle rects[2];
1159 int cols = man->geometry.cols;
1160
1161 if (man->shaped == 0)
1162 return;
1163
1164 ConsoleDebug(X11, "in set_shape: %s\n", man->titlename);
1165
1166 n = man->buttons.num_windows;
1167 if (n == 0)
1168 {
1169 man->shape.num_rects = 1;
1170 rects[0].x = -1;
1171 rects[0].y = -1;
1172 rects[0].width = 1;
1173 rects[0].height = 1;
1174 if (man->shape.num_rects != 0) {
1175 man->dirty_flags |= SHAPE_CHANGED;
1176 }
1177 man->shape.rects[0] = rects[0];
1178 return;
1179 }
1180
1181 if (cols == 0 || n % cols == 0) {
1182 rects[0].x = 0;
1183 rects[0].y = top_y_coord(man);
1184 rects[0].width = cols * man->geometry.boxwidth;
1185 rects[0].height = num_visible_rows(n, cols) * man->geometry.boxheight;
1186 if (man->shape.num_rects != 1 || !rects_equal(rects, man->shape.rects)) {
1187 man->dirty_flags |= SHAPE_CHANGED;
1188 }
1189 man->shape.num_rects = 1;
1190 man->shape.rects[0] = rects[0];
1191 }
1192 else {
1193 if (man->geometry.dir & GROW_DOWN) {
1194 rects[0].x = 0;
1195 rects[0].y = 0;
1196 rects[0].width = cols * man->geometry.boxwidth;
1197 rects[0].height =
1198 (num_visible_rows(n, cols) - 1) * man->geometry.boxheight;
1199 rects[1].x = 0;
1200 rects[1].y = rects[0].height;
1201 rects[1].width = (n % cols) * man->geometry.boxwidth;
1202 rects[1].height = man->geometry.boxheight;
1203 }
1204 else {
1205 rects[0].x = 0;
1206 rects[0].y = top_y_coord(man);
1207 rects[0].width = (n % cols) * man->geometry.boxwidth;
1208 rects[0].height = man->geometry.boxheight;
1209 rects[1].x = 0;
1210 rects[1].y = rects[0].y + rects[0].height;
1211 rects[1].width = man->geometry.width;
1212 rects[1].height = (num_visible_rows(n, cols) - 1) *
1213 man->geometry.boxheight;
1214 }
1215 if (man->shape.num_rects != 2 ||
1216 !rects_equal(rects, man->shape.rects) ||
1217 !rects_equal(rects + 1, man->shape.rects + 1)) {
1218 man->dirty_flags |= SHAPE_CHANGED;
1219 }
1220 man->shape.num_rects = 2;
1221 man->shape.rects[0] = rects[0];
1222 man->shape.rects[1] = rects[1];
1223 }
1224 }
1225 }
1226
set_manager_window_mapping(WinManager * man,int flag)1227 void set_manager_window_mapping(WinManager *man, int flag)
1228 {
1229 if (flag != man->window_mapped) {
1230 man->window_mapped = flag;
1231 man->dirty_flags |= MAPPING_CHANGED;
1232 }
1233 }
1234
1235 /*
1236 * Major exported functions
1237 */
1238
init_button_array(ButtonArray * array)1239 void init_button_array(ButtonArray *array)
1240 {
1241 memset(array, 0, sizeof(ButtonArray));
1242 }
1243
1244 /* Pretty much like resize_manager, but used only to figure the
1245 correct size when creating the window */
1246
size_manager(WinManager * man)1247 void size_manager(WinManager *man)
1248 {
1249 ManGeometry *new;
1250 int oldwidth, oldheight, w, h;
1251
1252 new = figure_geometry(man);
1253
1254 assert(new->width && new->height);
1255
1256 w = new->width;
1257 h = new->height;
1258
1259 oldwidth = man->geometry.width;
1260 oldheight = man->geometry.height;
1261
1262 set_man_geometry(man, new);
1263
1264 if (oldheight != h || oldwidth != w) {
1265 if (man->geometry.dir & GROW_UP)
1266 man->geometry.y -= h - oldheight;
1267 if (man->geometry.dir & GROW_LEFT)
1268 man->geometry.x -= w - oldwidth;
1269 }
1270
1271 ConsoleDebug(X11, "size_manager %s: %d %d %d %d\n", man->titlename,
1272 man->geometry.x, man->geometry.y, man->geometry.width,
1273 man->geometry.height);
1274 }
1275
resize_manager(WinManager * man,int force)1276 static void resize_manager(WinManager *man, int force)
1277 {
1278 ManGeometry *new;
1279 int oldwidth, oldheight, oldrows, oldcols, old_boxwidth, old_boxheight;
1280 int dir;
1281 int i;
1282
1283 if (man->flags.is_shaded)
1284 {
1285 man->flags.needs_resize_after_unshade = 1;
1286 return;
1287 }
1288 if (man->can_draw == 0)
1289 return;
1290
1291 oldwidth = man->geometry.width;
1292 oldheight = man->geometry.height;
1293 oldrows = man->geometry.rows;
1294 oldcols = man->geometry.cols;
1295 dir = man->geometry.dir;
1296 old_boxwidth = man->geometry.boxheight;
1297 old_boxheight = man->geometry.boxwidth;
1298
1299 if (dir & GROW_FIXED) {
1300 new = figure_geometry(man);
1301 set_man_geometry(man, new);
1302 set_shape(man);
1303 if (force || oldrows != new->rows || oldcols != new->cols ||
1304 oldwidth != new->width || oldheight != new->height) {
1305 man->dirty_flags |= GEOMETRY_CHANGED;
1306 }
1307 }
1308 else {
1309 new = figure_geometry(man);
1310 set_man_geometry(man, new);
1311 set_shape(man);
1312 if (force || oldrows != new->rows || oldcols != new->cols ||
1313 oldwidth != new->width || oldheight != new->height) {
1314 resize_window(man);
1315 }
1316 }
1317
1318 #if 1 /* not sure that this is needed */
1319 if (oldwidth != new->width || oldheight != new->height)
1320 {
1321 for (i = 0; i < NUM_CONTEXTS; i++)
1322 {
1323 if (man->colorsets[i] >=0 &&
1324 (i == DEFAULT || CSET_IS_TRANSPARENT(man->colorsets[i])) &&
1325 Colorset[man->colorsets[i]].pixmap)
1326 {
1327 recreate_background(man, i);
1328 }
1329 }
1330 }
1331
1332 if (old_boxwidth != new->boxwidth || old_boxheight != new->boxheight)
1333 {
1334 for (i = 0; i < NUM_CONTEXTS; i++)
1335 {
1336 if (man->colorsets[i] >= 0 && i != DEFAULT &&
1337 !CSET_IS_TRANSPARENT(man->colorsets[i]) &&
1338 Colorset[man->colorsets[i]].pixmap)
1339 {
1340 recreate_background(man, i);
1341 }
1342 }
1343 }
1344 #endif
1345 }
1346
center_padding(int h1,int h2)1347 static int center_padding(int h1, int h2)
1348 {
1349 return (h2 - h1) / 2;
1350 }
1351
get_title_geometry(WinManager * man,ButtonGeometry * g)1352 static void get_title_geometry(WinManager *man, ButtonGeometry *g)
1353 {
1354 int text_pad;
1355 assert(man);
1356 g->button_x = 0;
1357 g->button_y = 0;
1358 g->button_w = man->geometry.boxwidth;
1359 g->button_h = man->geometry.boxheight;
1360 g->text_x = g->button_x + g->button_h / 2;
1361 g->text_w = g->button_w - 4 - (g->text_x - g->button_x);
1362 if (g->text_w <= 0)
1363 g->text_w = 1;
1364 g->text_h = man->fontheight;
1365 text_pad = center_padding(man->fontheight, g->button_h);
1366
1367 g->text_y = g->button_y + text_pad;
1368 g->text_base = g->text_y + man->FButtonFont->ascent;
1369 }
1370
get_button_geometry(WinManager * man,Button * button,ButtonGeometry * g)1371 static void get_button_geometry(WinManager *man, Button *button,
1372 ButtonGeometry *g)
1373 {
1374 int icon_pad, text_pad;
1375 WinData *win;
1376
1377 assert(man);
1378
1379 win = button->drawn_state.win;
1380
1381 g->button_x = button->x;
1382 g->button_y = button->y;
1383
1384 g->button_w = button->w;
1385 g->button_h = button->h;
1386
1387 /* [BV 16-Apr-97] Mini Icons work on black-and-white too */
1388 if (FMiniIconsSupported && man->draw_icons && win && win->pic.picture) {
1389 /* If no window, then icon_* aren't used, so doesn't matter what
1390 they are */
1391 g->icon_w = min(win->pic.width, g->button_h);
1392 g->icon_h = min(g->button_h - 4, win->pic.height);
1393 icon_pad = center_padding(g->icon_h, g->button_h);
1394 g->icon_x = g->button_x + 4;
1395 g->icon_y = g->button_y + icon_pad;
1396 }
1397 else {
1398 g->icon_h = man->geometry.boxheight - 8;
1399 g->icon_w = g->icon_h;
1400
1401 icon_pad = center_padding(g->icon_h, g->button_h);
1402 g->icon_x = g->button_x + icon_pad;
1403 g->icon_y = g->button_y + icon_pad;
1404 }
1405
1406 g->text_x = g->icon_x + g->icon_w + 2;
1407 g->text_w = g->button_w - 4 - (g->text_x - g->button_x);
1408 if (g->text_w <= 0)
1409 g->text_w = 1;
1410 g->text_h = man->fontheight;
1411
1412 text_pad = center_padding(man->fontheight, g->button_h);
1413
1414 g->text_y = g->button_y + text_pad;
1415 g->text_base = g->text_y + man->FButtonFont->ascent;
1416 }
1417
draw_button_background(WinManager * man,XRectangle bounding,Contexts button_state)1418 static void draw_button_background(
1419 WinManager *man, XRectangle bounding, Contexts button_state)
1420 {
1421 int cset = man->colorsets[button_state];
1422
1423 if (cset >= 0)
1424 {
1425 SetRectangleBackground(
1426 theDisplay, man->theWindow,
1427 bounding.x, bounding.y,
1428 bounding.width, bounding.height,
1429 &Colorset[cset], Pdepth,
1430 man->backContext[button_state]);
1431 }
1432 else if (man->backContext[button_state] == None)
1433 {
1434 XClearArea(
1435 theDisplay, man->theWindow,
1436 bounding.x, bounding.y,
1437 bounding.width, bounding.height,
1438 False);
1439 }
1440 else
1441 {
1442 XFillRectangle(
1443 theDisplay, man->theWindow,
1444 man->backContext[button_state],
1445 bounding.x, bounding.y,
1446 bounding.width, bounding.height);
1447 }
1448 }
1449
draw_3d_icon(WinManager * man,int box,ButtonGeometry * g,int iconified,Contexts contextId)1450 static void draw_3d_icon(WinManager *man, int box, ButtonGeometry *g,
1451 int iconified, Contexts contextId)
1452 {
1453 if ((iconified == 0) || (man->relief_thickness == 0))
1454 return;
1455 else
1456 RelieveRectangle(theDisplay, man->theWindow, g->icon_x, g->icon_y,
1457 g->icon_w - 1, g->icon_h - 1,
1458 man->reliefContext[contextId],
1459 man->shadowContext[contextId], man->relief_thickness);
1460 }
1461
1462
1463 /* this routine should only be called from draw_button() */
iconify_box(WinManager * man,WinData * win,int box,ButtonGeometry * g,int iconified,Contexts contextId,int button_already_cleared,XRectangle bounding)1464 static void iconify_box(WinManager *man, WinData *win, int box,
1465 ButtonGeometry *g, int iconified, Contexts contextId,
1466 int button_already_cleared, XRectangle bounding)
1467 {
1468 XRectangle inter;
1469 int cset = man->colorsets[contextId];
1470 Bool erase = False;
1471
1472 if (!man->window_up)
1473 {
1474 return;
1475 }
1476 frect_get_intersection(
1477 bounding.x, bounding.y, bounding.width, bounding.height,
1478 g->icon_x, g->icon_y, g->icon_w, g->icon_h,
1479 &inter);
1480
1481 if (inter.width <= 0 || inter.height <= 0)
1482 {
1483 return;
1484 }
1485
1486 /* [BV 16-Apr-97] Mini Icons work on black-and-white too */
1487 if (FMiniIconsSupported && man->draw_icons && win->pic.picture)
1488 {
1489 if (iconified == 0 && man->draw_icons != 2)
1490 {
1491 erase = True;
1492 }
1493 else
1494 {
1495 FvwmRenderAttributes fra;
1496 int p_x = 0, p_y = 0;
1497
1498 fra.mask = FRAM_DEST_IS_A_WINDOW;
1499 if (cset >= 0)
1500 {
1501 fra.mask |= FRAM_HAVE_ICON_CSET;
1502 fra.colorset = &Colorset[cset];
1503 }
1504 if (inter.x > g->icon_x)
1505 {
1506 p_x = inter.x - g->icon_x;
1507 }
1508 if (inter.y > g->icon_y)
1509 {
1510 p_y = inter.y - g->icon_y;
1511 }
1512 PGraphicsRenderPicture(
1513 theDisplay, man->theWindow, &win->pic, &fra,
1514 man->theWindow, man->hiContext[contextId],
1515 None, None,
1516 p_x, p_y, inter.width, inter.height,
1517 inter.x, inter.y, inter.width, inter.height,
1518 False);
1519 }
1520 }
1521 else
1522 {
1523 if (!PictureUseBWOnly())
1524 {
1525 draw_3d_icon(man, box, g, iconified, contextId);
1526 }
1527 else
1528 {
1529 if (iconified == 0)
1530 {
1531 erase = True;
1532 }
1533 else
1534 {
1535 XFillArc(
1536 theDisplay, man->theWindow,
1537 man->hiContext[contextId],
1538 g->icon_x, g->icon_y, g->icon_w,
1539 g->icon_h, 0, 360 * 64);
1540 }
1541 }
1542 }
1543 if (erase)
1544 {
1545 draw_button_background(man, inter, contextId);
1546 }
1547 }
1548
change_windows_manager(WinData * win)1549 int change_windows_manager(WinData *win)
1550 {
1551 WinManager *oldman;
1552 WinManager *newman;
1553
1554 ConsoleDebug(X11, "change_windows_manager: %s\n", win->titlename);
1555
1556 oldman = win->manager;
1557 newman = figure_win_manager(win, ALL_NAME);
1558 if (oldman && newman != oldman && win->button) {
1559 delete_windows_button(win);
1560 }
1561 win->manager = newman;
1562 set_win_displaystring(win);
1563 check_win_complete(win);
1564 check_in_window(win);
1565 ConsoleDebug(X11, "change_windows_manager: returning %d\n",
1566 newman != oldman);
1567 return (newman != oldman);
1568 }
1569
check_in_window(WinData * win)1570 void check_in_window(WinData *win)
1571 {
1572 int in_viewport;
1573 int is_state_selected;
1574
1575 if (win->complete) {
1576 WinManager *oldman;
1577 WinManager *newman;
1578
1579 ConsoleDebug(X11, "change_windows_manager: %s\n", win->titlename);
1580
1581 oldman = win->manager;
1582 newman = figure_win_manager(win, ALL_NAME);
1583 if (oldman && newman != oldman && win->button) {
1584 oldman->we_are_drawing = 1;
1585 delete_windows_button(win);
1586 }
1587 win->manager = newman;
1588 set_win_displaystring(win);
1589 }
1590
1591 if (win->manager && win->complete) {
1592 is_state_selected =
1593 ((!win->manager->showonlyiconic || win->iconified) &&
1594 (!win->manager->shownoiconic || !win->iconified) &&
1595 (win->manager->showtransient || !IS_TRANSIENT(win)));
1596 in_viewport = win_in_viewport(win);
1597 if (win->manager->usewinlist && DO_SKIP_WINDOW_LIST(win))
1598 in_viewport = 0;
1599 if ((win->manager->showonlyfocused && win->state != FOCUS_CONTEXT) &&
1600 (win->manager->showonlyfocused && win->state != FOCUS_SELECT_CONTEXT))
1601 in_viewport = 0;
1602 if (win->button == NULL && in_viewport && is_state_selected) {
1603 insert_windows_button(win);
1604 if (win->manager->window_up == 0 && globals.got_window_list)
1605 create_manager_window(win->manager->index);
1606 }
1607 if (win->button && (!in_viewport || !is_state_selected)) {
1608 if (win->button->drawn_state.display_string)
1609 Free(win->button->drawn_state.display_string);
1610 delete_windows_button(win);
1611 }
1612 }
1613 }
1614
get_gcs(WinManager * man,int state,int iconified,GC * context1,GC * context2)1615 static void get_gcs(WinManager *man, int state, int iconified,
1616 GC *context1, GC *context2)
1617 {
1618 GC gc1, gc2;
1619
1620 switch (man->buttonState[state]) {
1621 case BUTTON_FLAT:
1622 gc1 = man->flatContext[state];
1623 gc2 = man->flatContext[state];
1624 break;
1625
1626 case BUTTON_UP:
1627 case BUTTON_EDGEUP:
1628 gc1 = man->reliefContext[state];
1629 gc2 = man->shadowContext[state];
1630 break;
1631
1632 case BUTTON_DOWN:
1633 case BUTTON_EDGEDOWN:
1634 gc1 = man->shadowContext[state];
1635 gc2 = man->reliefContext[state];
1636 break;
1637
1638 default:
1639 ConsoleMessage("Internal error in get_gcs\n");
1640 return;
1641 }
1642
1643 if (((man->rev == REVERSE_ICON) && iconified)
1644 || ((man->rev == REVERSE_NORMAL) && !iconified)) {
1645 *context1 = gc2;
1646 *context2 = gc1;
1647 } else {
1648 *context1 = gc1;
1649 *context2 = gc2;
1650 }
1651 return;
1652 }
1653
draw_relief(WinManager * man,int button_state,ButtonGeometry * g,GC context1,GC context2)1654 static void draw_relief(WinManager *man, int button_state, ButtonGeometry *g,
1655 GC context1, GC context2)
1656 {
1657 int state;
1658 int relief;
1659
1660 state = man->buttonState[button_state];
1661 relief = man->relief_thickness;
1662
1663 /* Make sure that the relief isn't too large for the button... */
1664 if ((abs(relief) > (man->geometry.boxheight / 2)) ||
1665 (abs(relief) > (man->geometry.boxwidth / 2))) {
1666 relief = min(man->geometry.boxheight/2, man->geometry.boxwidth/2);
1667 if (man->relief_thickness < 0)
1668 relief *= -1;
1669 }
1670
1671 if (state == BUTTON_FLAT || relief == 0)
1672 return;
1673 if (state == BUTTON_EDGEUP || state == BUTTON_EDGEDOWN) {
1674 RelieveRectangle(theDisplay, man->theWindow, g->button_x, g->button_y,
1675 g->button_w - 1, g->button_h - 1, context1, context2,
1676 relief);
1677 RelieveRectangle(theDisplay, man->theWindow, g->button_x+2, g->button_y+2,
1678 g->button_w - 5, g->button_h - 5, context2, context1,
1679 relief);
1680 }
1681 else {
1682 RelieveRectangle(theDisplay, man->theWindow, g->button_x, g->button_y,
1683 g->button_w - 1, g->button_h - 1, context1, context2,
1684 relief);
1685 }
1686 }
1687
draw_button(WinManager * man,int button,int force)1688 static void draw_button(WinManager *man, int button, int force)
1689 {
1690 Button *b;
1691 WinData *win;
1692 ButtonGeometry g, old_g;
1693 GC context1 = 0, context2 = 0;
1694 Contexts button_state;
1695 int cleared_button = 0, dirty;
1696 int draw_background = 0, draw_icon = 0, draw_string = 0;
1697 int clear_old_pic = 0;
1698
1699 assert(man);
1700
1701 if (!man->window_up)
1702 {
1703 ConsoleMessage("draw_button: manager not up yet\n");
1704 return;
1705 }
1706
1707 b = man->buttons.buttons[button];
1708 win = b->drawn_state.win;
1709 dirty = b->drawn_state.dirty_flags;
1710
1711 if (win && win->button != b)
1712 {
1713 ConsoleMessage("Internal error in draw_button.\n");
1714 return;
1715 }
1716
1717 if (!win)
1718 {
1719 return;
1720 }
1721
1722 if (force || (dirty & REDRAW_BUTTON))
1723 {
1724 ConsoleDebug(X11, "draw_button: %d forced\n", b->index);
1725 draw_background = 1;
1726 draw_icon = 1;
1727 draw_string = 1;
1728 }
1729
1730 /* figure out what we have to draw */
1731 if (dirty)
1732 {
1733 ConsoleDebug(X11, "draw_button: %d dirty\n", b->index);
1734 /* humm ... this should be optimised one day ! */
1735 if (dirty & GEOMETRY_CHANGED)
1736 {
1737 ConsoleDebug(X11, "\tGeometry changed\n");
1738 /* Determine if geometry has changed relative
1739 * to the window gravity */
1740 if (b->w != b->drawn_state.w ||
1741 b->h != b->drawn_state.h ||
1742 b->x - man->geometry.gravity_x !=
1743 b->drawn_state.x -
1744 man->drawn_geometry.gravity_x ||
1745 b->y - man->geometry.gravity_y !=
1746 b->drawn_state.y -
1747 man->drawn_geometry.gravity_y)
1748 {
1749 draw_background = 1;
1750 draw_icon = 1;
1751 draw_string = 1;
1752 }
1753 }
1754 if (dirty & STATE_CHANGED)
1755 {
1756 ConsoleDebug(X11, "\tState changed\n");
1757 b->drawn_state.state = win->state;
1758 draw_background = 1;
1759 draw_icon = 1;
1760 draw_string = 1;
1761 }
1762 if (FMiniIconsSupported && (dirty & PICTURE_CHANGED))
1763 {
1764 FvwmPicture tpic;
1765
1766 ConsoleDebug(X11, "\tPicture changed\n");
1767 tpic = win->pic;
1768 win->pic = win->old_pic;
1769 get_button_geometry(man, b, &old_g);
1770 win->pic = tpic;
1771 b->drawn_state.pic = win->pic;
1772 draw_icon = 1;
1773 draw_string = 1;
1774 draw_background = 1;
1775 }
1776 if ((dirty & ICON_STATE_CHANGED) &&
1777 b->drawn_state.iconified != win->iconified)
1778 {
1779 ConsoleDebug(X11, "\tIcon changed\n");
1780 b->drawn_state.iconified = win->iconified;
1781 draw_icon = 1;
1782 draw_background = 1;
1783 draw_string = 1;
1784 }
1785 if (dirty & STRING_CHANGED)
1786 {
1787 ConsoleDebug(
1788 X11, "\tString changed: %s\n",
1789 win->display_string);
1790 copy_string(
1791 &b->drawn_state.display_string,
1792 win->display_string);
1793 assert(b->drawn_state.display_string);
1794 draw_icon = 1;
1795 draw_background = 1;
1796 draw_string = 1;
1797 }
1798 }
1799
1800 if (draw_background || draw_icon || draw_string)
1801 {
1802 XRectangle bounding;
1803 Region b_region;
1804
1805 get_button_geometry(man, b, &g);
1806 if (b->drawn_state.ew > 0 && b->drawn_state.eh > 0)
1807 {
1808 /* we redraw from an expose event */
1809 bounding.x = b->drawn_state.ex;
1810 bounding.y = b->drawn_state.ey;
1811 bounding.width = b->drawn_state.ew;
1812 bounding.height = b->drawn_state.eh;
1813 }
1814 else
1815 {
1816 bounding.x = g.button_x;
1817 bounding.y = g.button_y;
1818 bounding.width = g.button_w;
1819 bounding.height = g.button_h;
1820 }
1821 b_region = GetRegion(
1822 bounding.x, bounding.y, bounding.width, bounding.height);
1823 ConsoleDebug(
1824 X11, "\tgeometry: %d %d %d %d\n", g.button_x, g.button_y,
1825 g.button_w, g.button_h);
1826 button_state = b->drawn_state.state;
1827 if (b->drawn_state.iconified && button_state == PLAIN_CONTEXT)
1828 {
1829 button_state = ICON_CONTEXT;
1830 }
1831 if (draw_background)
1832 {
1833 ConsoleDebug(X11, "\tDrawing background\n");
1834 draw_button_background(man, bounding, button_state);
1835 cleared_button = 1;
1836 }
1837 if (clear_old_pic)
1838 {
1839 ConsoleDebug(X11, "\tClearing old picture\n");
1840 if (!cleared_button)
1841 {
1842 XRectangle r;
1843
1844 frect_get_intersection(
1845 bounding.x, bounding.y,
1846 bounding.width, bounding.height,
1847 g.icon_x, g.icon_y, g.icon_w, g.icon_h,
1848 &r);
1849 if (r.width > 0)
1850 {
1851 draw_button_background(
1852 man, r, button_state);
1853 }
1854 }
1855 }
1856 if (draw_icon)
1857 {
1858 ConsoleDebug(X11, "\tDrawing icon\n");
1859 iconify_box(
1860 man, win, button, &g, win->iconified,
1861 button_state, cleared_button, bounding);
1862 }
1863 /* Draw reliefs after icon since the icon might overlay
1864 part of it. */
1865 if (draw_background)
1866 {
1867 ConsoleDebug(X11, "\tDrawing reliefs\n");
1868 if (!PictureUseBWOnly())
1869 {
1870 get_gcs(
1871 man, button_state, win->iconified,
1872 &context1, &context2);
1873 draw_relief(
1874 man, button_state, &g, context1,
1875 context2);
1876 }
1877 else if (button_state == SELECT_CONTEXT ||
1878 button_state == FOCUS_SELECT_CONTEXT ||
1879 button_state == ICON_SELECT_CONTEXT)
1880 {
1881 XDrawRectangle(
1882 theDisplay, man->theWindow,
1883 man->hiContext[button_state],
1884 g.button_x + 2, g.button_y + 1,
1885 g.button_w - 4, g.button_h - 2);
1886 }
1887 }
1888 if (draw_string)
1889 {
1890 Region tr;
1891
1892 ConsoleDebug(
1893 X11, "\tDrawing text: %s\n",
1894 b->drawn_state.display_string);
1895
1896 tr = GetRegion(
1897 g.text_x, g.text_y, g.text_w, g.text_h);
1898 XIntersectRegion(tr, b_region, tr);
1899 XSetRegion(
1900 theDisplay, man->hiContext[button_state], tr);
1901 if (!cleared_button)
1902 {
1903 XRectangle r;
1904
1905 frect_get_intersection(
1906 bounding.x, bounding.y,
1907 bounding.width, bounding.height,
1908 g.text_x, g.text_y, g.text_w, g.text_h,
1909 &r);
1910 draw_button_background(man, r, button_state);
1911 }
1912 FwinString->str = b->drawn_state.display_string;
1913 FwinString->win = man->theWindow;
1914 FwinString->gc = man->hiContext[button_state];
1915 if (man->colorsets[button_state] >= 0)
1916 {
1917 FwinString->colorset =
1918 &Colorset[man->colorsets[button_state]];
1919 FwinString->flags.has_colorset = True;
1920 }
1921 else
1922 {
1923 FwinString->flags.has_colorset = False;
1924 }
1925 FwinString->flags.has_clip_region = True;
1926 FwinString->clip_region = tr;
1927 FwinString->x = g.text_x;
1928 FwinString->y = g.text_base;
1929 FlocaleDrawString(
1930 theDisplay, man->FButtonFont, FwinString, 0);
1931 XDestroyRegion(tr);
1932 XSetClipMask(
1933 theDisplay, man->hiContext[button_state], None);
1934 }
1935 XDestroyRegion(b_region);
1936 }
1937
1938 b->drawn_state.dirty_flags = 0;
1939 b->drawn_state.x = b->x;
1940 b->drawn_state.y = b->y;
1941 b->drawn_state.w = b->w;
1942 b->drawn_state.h = b->h;
1943 b->drawn_state.ew = 0;
1944 b->drawn_state.eh = 0;
1945 XFlush(theDisplay);
1946 }
1947
draw_managers(void)1948 void draw_managers(void)
1949 {
1950 int i;
1951 for (i = 0; i < globals.num_managers; i++)
1952 draw_manager(&globals.managers[i]);
1953 }
1954
draw_empty_manager(WinManager * man)1955 static void draw_empty_manager(WinManager *man)
1956 {
1957 GC context1 = 0, context2 = 0;
1958 int state = TITLE_CONTEXT;
1959 ButtonGeometry g;
1960 int len = strlen(man->titlename);
1961 Region region;
1962
1963 ConsoleDebug(X11, "draw_empty_manager\n");
1964 clear_empty_region(man);
1965 get_title_geometry(man, &g);
1966
1967 /* FIXME: should bound when exposed */
1968 if (len > 0)
1969 {
1970 XRectangle r;
1971
1972 r.x = g.button_x;
1973 r.y = g.button_y;
1974 r.width = g.button_w;
1975 r.height = g.button_h;
1976 draw_button_background(man, r, state);
1977 }
1978 if (!PictureUseBWOnly())
1979 {
1980 get_gcs(man, state, 0, &context1, &context2);
1981 draw_relief(man, state, &g, context1, context2);
1982 }
1983 region = GetRegion(g.text_x, g.text_y, g.text_w, g.text_h);
1984 XSetRegion(theDisplay, man->hiContext[state], region);
1985 FwinString->str = man->titlename;
1986 FwinString->win = man->theWindow;
1987 FwinString->gc = man->hiContext[state];
1988 if (man->colorsets[state] >= 0)
1989 {
1990 FwinString->colorset = &Colorset[man->colorsets[state]];
1991 FwinString->flags.has_colorset = True;
1992 }
1993 else
1994 {
1995 FwinString->flags.has_colorset = False;
1996 }
1997 FwinString->flags.has_clip_region = True;
1998 FwinString->clip_region = region;
1999 FwinString->x = g.text_x;
2000 FwinString->y = g.text_base;
2001 FlocaleDrawString(theDisplay, man->FButtonFont, FwinString, 0);
2002 XSetClipMask(theDisplay, man->hiContext[state], None);
2003 }
2004
draw_manager(WinManager * man)2005 void draw_manager(WinManager *man)
2006 {
2007 int i, force_draw = 0, update_geometry = 0, redraw_all = 0;
2008 int shape_changed = 0;
2009
2010 assert(man->buttons.num_buttons >= 0 && man->buttons.num_windows >= 0);
2011
2012 if (!man->window_up)
2013 return;
2014 ConsoleDebug(X11, "Drawing Manager: %s\n", man->titlename);
2015 redraw_all = (man->dirty_flags & REDRAW_MANAGER);
2016
2017 if (!man->flags.is_shaded && man->flags.needs_resize_after_unshade) {
2018 ConsoleDebug(X11, "\tresizing manager\n");
2019 resize_manager(man, 1);
2020 update_geometry = 1;
2021 force_draw = 1;
2022 } else if (redraw_all || (man->buttons.dirty_flags & NUM_WINDOWS_CHANGED)) {
2023 ConsoleDebug(X11, "\tresizing manager\n");
2024 resize_manager(man, redraw_all);
2025 update_geometry = 1;
2026 force_draw = 1;
2027 }
2028
2029 if (redraw_all || (man->dirty_flags & MAPPING_CHANGED)) {
2030 force_draw = 1;
2031 ConsoleDebug(X11, "manager %s: mapping changed\n", man->titlename);
2032 }
2033
2034 if (FShapesSupported && man->shaped)
2035 {
2036 if (redraw_all || (man->dirty_flags & SHAPE_CHANGED)) {
2037 FShapeCombineRectangles(
2038 theDisplay, man->theWindow, FShapeBounding, 0, 0, man->shape.rects,
2039 man->shape.num_rects, FShapeSet, Unsorted);
2040 FShapeCombineRectangles(
2041 theDisplay, man->theWindow, FShapeClip, 0, 0, man->shape.rects,
2042 man->shape.num_rects, FShapeSet, Unsorted);
2043 shape_changed = 1;
2044 update_geometry = 1;
2045 }
2046 }
2047
2048 if (redraw_all || (man->dirty_flags & GEOMETRY_CHANGED)) {
2049 ConsoleDebug(X11, "\tredrawing all buttons\n");
2050 update_geometry = 1;
2051 }
2052
2053 if (update_geometry) {
2054 for (i = 0; i < man->buttons.num_windows; i++)
2055 set_button_geometry(man, man->buttons.buttons[i]);
2056 }
2057
2058 if (force_draw || update_geometry || (man->dirty_flags & REDRAW_BG)) {
2059 ConsoleDebug(X11, "\tredrawing background\n");
2060 clear_empty_region(man);
2061 }
2062 if (force_draw || update_geometry)
2063 {
2064 /* FIXME: maybe not useful but safe */
2065 if (CSET_IS_TRANSPARENT_PR_PURE(man->colorsets[DEFAULT]))
2066 force_draw = True;
2067 }
2068
2069 man->dirty_flags = 0;
2070 man->buttons.dirty_flags = 0;
2071 man->buttons.drawn_num_buttons = man->buttons.num_buttons;
2072 man->buttons.drawn_num_windows = man->buttons.num_windows;
2073
2074 if (man->buttons.num_windows == 0) {
2075 if (force_draw)
2076 draw_empty_manager(man);
2077 }
2078 else {
2079 /* I was having the problem where when the shape changed the manager
2080 wouldn't get redrawn. It appears we weren't getting the expose.
2081 How can I tell when I am going to reliably get an expose event? */
2082
2083 if (1 || shape_changed) {
2084 /* if shape changed, we'll catch it on the expose */
2085 for (i = 0; i < man->buttons.num_buttons; i++) {
2086 draw_button(man, i, force_draw);
2087 }
2088 }
2089 }
2090 man->drawn_geometry = man->geometry;
2091 XFlush(theDisplay);
2092 }
2093
draw_transparent_buttons(WinManager * man,Bool only_moved,Bool clear_only)2094 Bool draw_transparent_buttons(
2095 WinManager *man, Bool only_moved, Bool clear_only)
2096 {
2097 Button **bp;
2098 Contexts button_state;
2099 int i,cset;
2100 Bool r = False;
2101 Bool man_bg_transparent = False;
2102
2103 if (CSET_IS_TRANSPARENT(man->colorsets[DEFAULT]))
2104 {
2105 clear_empty_region(man);
2106 man_bg_transparent = True;
2107 }
2108
2109 if (!man->buttons.num_windows)
2110 {
2111 if (CSET_IS_TRANSPARENT(man->colorsets[TITLE_CONTEXT]) ||
2112 CSET_IS_TRANSPARENT_PR_TINT(man->colorsets[DEFAULT]))
2113 {
2114 draw_empty_manager(man);
2115 }
2116 return 0;
2117 }
2118
2119 bp = man->buttons.buttons;
2120 for (i = 0; i < man->buttons.num_windows; i++)
2121 {
2122 button_state = bp[i]->drawn_state.state;
2123 if (bp[i]->drawn_state.iconified &&
2124 button_state == PLAIN_CONTEXT)
2125 {
2126 button_state = ICON_CONTEXT;
2127 }
2128 cset = man->colorsets[button_state];
2129
2130 if ((!CSET_IS_TRANSPARENT(cset) &&
2131 !CSET_IS_TRANSPARENT_PR_TINT(man->colorsets[DEFAULT]))
2132 ||
2133 (only_moved && !man_bg_transparent &&
2134 !CSET_IS_TRANSPARENT_ROOT(cset)))
2135 {
2136 continue;
2137 }
2138 if (clear_only)
2139 {
2140 XClearArea(
2141 theDisplay, man->theWindow,
2142 bp[i]->x, bp[i]->y, bp[i]->w, bp[i]->h,
2143 True);
2144 r = True;
2145 }
2146 else
2147 {
2148 bp[i]->drawn_state.dirty_flags |= REDRAW_BUTTON;
2149 draw_button(man, i, 0);
2150 }
2151 }
2152 return r;
2153 }
2154
compute_weight(WinData * win)2155 static int compute_weight(WinData *win)
2156 {
2157 WinManager *man;
2158 WeightedSort *sort;
2159 int i;
2160
2161 man = win->manager;
2162 for (i = 0; i < man->weighted_sorts_len; i++) {
2163 sort = &man->weighted_sorts[i];
2164 if (sort->resname && !matchWildcards(sort->resname, win->resname)) {
2165 continue;
2166 }
2167 if (sort->classname && !matchWildcards(sort->classname, win->classname)) {
2168 continue;
2169 }
2170 if (sort->titlename && !matchWildcards(sort->titlename, win->titlename)) {
2171 continue;
2172 }
2173 if (sort->iconname && !matchWildcards(sort->iconname, win->iconname)) {
2174 continue;
2175 }
2176 return sort->weight;
2177 }
2178 return 0;
2179 }
2180
compare_windows(SortType type,WinData * a,WinData * b)2181 static int compare_windows(SortType type, WinData *a, WinData *b)
2182 {
2183 int wa, wb;
2184
2185 if (type == SortId)
2186 {
2187 return a->app_id - b->app_id;
2188 }
2189 else if (type == SortName)
2190 {
2191 return strcasecmp(
2192 (a->display_string)? a->display_string:"",
2193 (b->display_string)? b->display_string:"");
2194 }
2195 else if (type == SortNameCase)
2196 {
2197 return strcmp((a->display_string)? a->display_string:"",
2198 (b->display_string)? b->display_string:"");
2199 }
2200 else if (type == SortWeighted)
2201 {
2202 wa = compute_weight(a);
2203 wb = compute_weight(b);
2204 if (wa != wb)
2205 {
2206 return wa - wb;
2207 }
2208 return strcmp((a->display_string)? a->display_string:"",
2209 (b->display_string)? b->display_string:"");
2210 }
2211 else
2212 {
2213 ConsoleMessage("Internal error in compare_windows\n");
2214 return 0;
2215 }
2216 }
2217
2218 /* find_windows_spot: returns index of button to stick the window in.
2219 * checks win->button to see if it's already in manager.
2220 * if it isn't, then gives spot at which it should be,
2221 * if it were.
2222 */
2223
find_windows_spot(WinData * win)2224 static int find_windows_spot(WinData *win)
2225 {
2226 WinManager *man = win->manager;
2227 int num_windows = man->buttons.num_windows;
2228
2229 if (man->sort != SortNone) {
2230 int i, cur, start, finish, cmp_dir, correction;
2231 Button **bp;
2232
2233 bp = man->buttons.buttons;
2234 if (win->button) {
2235 /* start search from our current location */
2236 cur = win->button->index;
2237
2238 if (cur - 1 >= 0 &&
2239 compare_windows(man->sort,
2240 win, bp[cur - 1]->drawn_state.win) < 0) {
2241 start = cur - 1;
2242 finish = -1;
2243 cmp_dir = -1;
2244 correction = 1;
2245 }
2246 else if (cur < num_windows - 1 &&
2247 compare_windows(man->sort,
2248 win, bp[cur + 1]->drawn_state.win) > 0) {
2249 start = cur + 1;
2250 finish = num_windows;
2251 cmp_dir = 1;
2252 correction = -1;
2253 }
2254 else {
2255 return cur;
2256 }
2257 }
2258 else {
2259 start = 0;
2260 finish = num_windows;
2261 cmp_dir = 1;
2262 correction = 0;
2263 }
2264 for (i = start; i != finish && bp[i]->drawn_state.win && cmp_dir *
2265 compare_windows(man->sort, win, bp[i]->drawn_state.win) > 0;
2266 i = i + cmp_dir)
2267 ;
2268 i += correction;
2269 ConsoleDebug(X11, "find_windows_spot: %s %d\n", win->display_string, i);
2270 return i;
2271 }
2272 else {
2273 if (win->button) {
2274 /* already have a perfectly fine spot */
2275 return win->button->index;
2276 }
2277 else {
2278 return num_windows;
2279 }
2280 }
2281
2282 /* shouldn't get here */
2283 return -1;
2284 }
2285
move_window_buttons(WinManager * man,int start,int finish,int offset)2286 static void move_window_buttons(WinManager *man, int start, int finish,
2287 int offset)
2288 {
2289 int n = man->buttons.num_buttons, i;
2290 Button **bp;
2291
2292 ConsoleDebug(X11, "move_window_buttons: %s(%d): (%d, %d) + %d\n",
2293 man->titlename, n, start, finish, offset);
2294
2295 if (finish >= n || finish + offset >= n || start < 0 || start + offset < 0) {
2296 ConsoleMessage("Internal error in move_window_buttons\n");
2297 ConsoleMessage("\tn = %d, start = %d, finish = %d, offset = %d\n",
2298 n, start, finish, offset);
2299 return;
2300 }
2301 bp = man->buttons.buttons;
2302 if (offset > 0)
2303 {
2304 for (i = finish; i >= start; i--)
2305 {
2306 bp[i + offset]->drawn_state = bp[i]->drawn_state;
2307 bp[i + offset]->drawn_state.dirty_flags = ALL_CHANGED;
2308 if (bp[i + offset]->drawn_state.win)
2309 bp[i + offset]->drawn_state.win->button = bp[i + offset];
2310 }
2311 for (i = 0; i < offset; i++)
2312 clear_button(bp[start + i]);
2313 }
2314 else if (offset < 0)
2315 {
2316 for (i = start; i <= finish; i++)
2317 {
2318 bp[i + offset]->drawn_state = bp[i]->drawn_state;
2319 bp[i + offset]->drawn_state.dirty_flags = ALL_CHANGED;
2320 if (bp[i + offset]->drawn_state.win)
2321 bp[i + offset]->drawn_state.win->button = bp[i + offset];
2322 }
2323 for (i = 0; i > offset; i--)
2324 clear_button(bp[finish + i]);
2325 }
2326 }
2327
insert_windows_button(WinData * win)2328 static void insert_windows_button(WinData *win)
2329 {
2330 int spot;
2331 int selected_index = -1;
2332 WinManager *man = win->manager;
2333 ButtonArray *buttons;
2334
2335 ConsoleDebug(X11, "insert_windows_button: %s\n", win->titlename);
2336
2337 assert(man);
2338 selected_index = selected_button_in_man(man);
2339
2340 if (win->button) {
2341 ConsoleDebug(X11, "insert_windows_button: POSSIBLE BUG: "
2342 "already have a button\n");
2343 return;
2344 }
2345
2346 if (!win || !win->complete || !man) {
2347 ConsoleMessage("Internal error in insert_windows_button\n");
2348 ShutMeDown(1);
2349 }
2350
2351 buttons = &man->buttons;
2352
2353 spot = find_windows_spot(win);
2354
2355 increase_num_windows(buttons, 1);
2356 move_window_buttons(man, spot, buttons->num_windows - 2, 1);
2357
2358 set_window_button(win, spot);
2359 if (selected_index >= 0) {
2360 ConsoleDebug(X11, "insert_windows_button: selected_index = %d, moving\n",
2361 selected_index);
2362 move_highlight(man, man->buttons.buttons[selected_index]);
2363 }
2364 }
2365
delete_windows_button(WinData * win)2366 void delete_windows_button(WinData *win)
2367 {
2368 int spot;
2369 int selected_index = -1;
2370 WinManager *man = (win->manager);
2371 ButtonArray *buttons;
2372
2373 ConsoleDebug(X11, "delete_windows_button: %s\n", win->titlename);
2374
2375 assert(man);
2376
2377 buttons = &win->manager->buttons;
2378
2379 assert(win->button);
2380 assert(buttons->buttons);
2381
2382 selected_index = selected_button_in_man(man);
2383 ConsoleDebug(X11, "delete_windows_button: selected_index = %d\n",
2384 selected_index);
2385
2386 spot = win->button->index;
2387
2388 tips_cancel(man);
2389 move_window_buttons(win->manager, spot + 1, buttons->num_windows - 1, -1);
2390 increase_num_windows(buttons, -1);
2391 win->button = NULL;
2392 if (globals.focus_win == win) {
2393 globals.focus_win = NULL;
2394 }
2395 if (selected_index >= 0) {
2396 ConsoleDebug(X11, "delete_windows_button: selected_index = %d, moving\n",
2397 selected_index);
2398 move_highlight(man, man->buttons.buttons[selected_index]);
2399 }
2400 if (win->iconified)
2401 {
2402 win->state = ICON_CONTEXT;
2403 }
2404 else
2405 {
2406 win->state = PLAIN_CONTEXT;
2407 }
2408 }
2409
resort_windows_button(WinData * win)2410 void resort_windows_button(WinData *win)
2411 {
2412 int new_spot, cur_spot;
2413 int selected_index = -1;
2414 WinManager *man = win->manager;
2415
2416 assert(win->button && man);
2417
2418 ConsoleDebug(X11, "In resort_windows_button: %s\n", win->resname);
2419
2420 selected_index = selected_button_in_man(man);
2421
2422 new_spot = find_windows_spot(win);
2423 cur_spot = win->button->index;
2424
2425 print_button_info(win->button);
2426
2427 if (new_spot != cur_spot) {
2428 ConsoleDebug(X11, "resort_windows_button: win moves from %d to %d\n",
2429 cur_spot, new_spot);
2430 if (new_spot < cur_spot) {
2431 move_window_buttons(man, new_spot, cur_spot - 1, +1);
2432 }
2433 else {
2434 move_window_buttons(man, cur_spot + 1, new_spot, -1);
2435 }
2436 set_window_button(win, new_spot);
2437
2438 if (selected_index >= 0) {
2439 move_highlight(man, man->buttons.buttons[selected_index]);
2440 }
2441 }
2442 }
2443
move_highlight(WinManager * man,Button * b)2444 void move_highlight(WinManager *man, Button *b)
2445 {
2446 WinData *old;
2447
2448 assert(man);
2449
2450 ConsoleDebug(X11, "move_highlight\n");
2451
2452 old = globals.select_win;
2453
2454 if (old && old->button) {
2455 del_win_state(old, SELECT_CONTEXT);
2456 old->manager->select_button = NULL;
2457 draw_button(old->manager, old->button->index, 0);
2458 }
2459 if (b && b->drawn_state.win) {
2460 add_win_state(b->drawn_state.win, SELECT_CONTEXT);
2461 draw_button(man, b->index, 0);
2462 globals.select_win = b->drawn_state.win;
2463 }
2464 else {
2465 globals.select_win = NULL;
2466 }
2467
2468 man->select_button = b;
2469 }
2470
man_exposed(WinManager * man,XEvent * theEvent)2471 void man_exposed(WinManager *man, XEvent *theEvent)
2472 {
2473 rectangle r1, r2;
2474 int i;
2475 Button **bp;
2476
2477 ConsoleDebug(X11, "manager: %s, got expose\n", man->titlename);
2478
2479 r1.x = theEvent->xexpose.x;
2480 r1.y = theEvent->xexpose.y;
2481 r1.width = theEvent->xexpose.width;
2482 r1.height = theEvent->xexpose.height;
2483
2484 r2.width = man->geometry.boxwidth;
2485 r2.height = man->geometry.boxheight;
2486
2487 bp = man->buttons.buttons;
2488
2489 /* Background must be redrawn. */
2490 /* olicha: I do not think so */
2491 /*man->dirty_flags |= REDRAW_BG;*/
2492
2493 if (0 && FHaveShapeExtension && man->shaped)
2494 {
2495 /* There's some weird problem where if we change window shapes,
2496 * we can't draw into buttons in the area NewShape intersect
2497 * (not OldShape) until we get our Expose event. So, for now,
2498 * just redraw everything when we get Expose events. This has
2499 * the disadvantage of drawing buttons twice, but avoids having
2500 * to match which expose event results from which shape change.*/
2501 /* seems fixed ? olicha */
2502 if (man->buttons.num_windows)
2503 {
2504 for (i = 0; i < man->buttons.num_windows; i++)
2505 {
2506 bp[i]->drawn_state.dirty_flags |= REDRAW_BUTTON;
2507 }
2508 }
2509 else
2510 {
2511 draw_empty_manager(man);
2512 }
2513
2514 return;
2515 }
2516
2517 if (CSET_IS_TRANSPARENT_PR(man->colorsets[DEFAULT]))
2518 {
2519 clear_empty_region(man);
2520 }
2521 if (man->buttons.num_windows)
2522 {
2523 for (i = 0; i < man->buttons.num_windows; i++)
2524 {
2525 r2.x = index_to_col(man, i) * r2.width;
2526 r2.y = index_to_row(man, i) * r2.height;
2527 if (fvwmrect_do_rectangles_intersect(
2528 &r1, &r2))
2529 {
2530 bp[i]->drawn_state.ex = max(r1.x,r2.x);
2531 bp[i]->drawn_state.ey = max(r1.y,r2.y);
2532 bp[i]->drawn_state.ew =
2533 min(r1.x+r1.width,r2.x+r2.width) -
2534 max(r1.x,r2.x);
2535 bp[i]->drawn_state.eh =
2536 min(r1.y+r1.height, r2.y+r2.height) -
2537 max(r1.y,r2.y);
2538 bp[i]->drawn_state.dirty_flags |= REDRAW_BUTTON;
2539 }
2540 }
2541 }
2542 else
2543 {
2544 draw_empty_manager(man);
2545 }
2546 }
2547
2548 /*
2549 * tips routine
2550 */
2551
get_tips(WinManager * man,Button * b)2552 static char *get_tips(WinManager *man, Button *b)
2553 {
2554 ButtonGeometry g;
2555 char *s;
2556 static char *free_str = NULL;
2557
2558 if (man->tips == TIPS_NEVER || b == NULL)
2559 {
2560 return NULL;
2561 }
2562
2563 if (free_str != NULL)
2564 {
2565 free(free_str);
2566 free_str = NULL;
2567 }
2568
2569 if (man->tips_formatstring && b->drawn_state.win)
2570 {
2571 CopyString(
2572 &s, make_display_string(
2573 b->drawn_state.win, man->tips_formatstring,
2574 0));
2575 free_str = s;
2576 }
2577 else
2578 {
2579 s = b->drawn_state.display_string;
2580 }
2581
2582 if (s == NULL)
2583 {
2584 return NULL;
2585 }
2586
2587 if (man->tips == TIPS_ALWAYS)
2588 {
2589 return s;
2590 }
2591
2592 /* TIPS_NEEDED */
2593 if (free_str != NULL &&
2594 (b->drawn_state.display_string == NULL ||
2595 strcmp(s, b->drawn_state.display_string)))
2596 {
2597 return s;
2598 }
2599
2600 get_button_geometry(man, b, &g);
2601
2602 if (g.text_x + FlocaleTextWidth(man->FButtonFont, s, strlen(s))
2603 > g.button_x + g.button_w - 4)
2604 {
2605 return s;
2606 }
2607
2608 return NULL;
2609 }
2610
tips_cancel(WinManager * man)2611 void tips_cancel(WinManager *man)
2612 {
2613 int j;
2614
2615 if (man)
2616 {
2617 man->tipped_button = NULL;
2618 }
2619 else
2620 {
2621 for (j = 0; j < globals.num_managers; j++)
2622 {
2623 man = &globals.managers[j];
2624 man->tipped_button = NULL;
2625 }
2626 }
2627 FTipsCancel(theDisplay);
2628 }
2629
tips_on(WinManager * man,Button * b)2630 void tips_on(WinManager *man, Button *b)
2631 {
2632 char *tips_str;
2633
2634 if ((tips_str = get_tips(man, b)) != NULL)
2635 {
2636 FTipsOn(
2637 theDisplay, man->theWindow, man->tips_conf, (void *)b,
2638 tips_str, b->x, b->y, b->w, b->h);
2639 man->tipped_button = b;
2640 }
2641 else
2642 {
2643 tips_cancel(man);
2644 }
2645 }
2646
tips_update_label(WinManager * man)2647 void tips_update_label(WinManager *man)
2648 {
2649 char *tips_str;
2650
2651 if ((tips_str = get_tips(man, man->tipped_button)) != NULL)
2652 {
2653 FTipsUpdateLabel(theDisplay, tips_str);
2654 }
2655 else
2656 {
2657 tips_cancel(man);
2658 }
2659 }
2660
2661
2662 /*
2663 * Debugging routines
2664 */
2665
check_managers_consistency(void)2666 void check_managers_consistency(void)
2667 {
2668 #ifdef FVWM_DEBUG_MSGS
2669 int i, j;
2670 Button **b;
2671
2672 for (i = 0; i < globals.num_managers; i++) {
2673 for (j = 0, b = globals.managers[i].buttons.buttons;
2674 j < globals.managers[i].buttons.num_buttons; j++, b++) {
2675 if ((*b)->drawn_state.win && (*b)->drawn_state.win->button != *b) {
2676 ConsoleMessage("manager %d, button %d is confused\n", i, j);
2677 abort();
2678 }
2679 else if ((*b)->drawn_state.win &&
2680 j >= globals.managers[i].buttons.num_windows) {
2681 ConsoleMessage("manager %d: button %d has window and shouldn't\n",
2682 i, j);
2683 abort();
2684 }
2685 }
2686 }
2687 #endif
2688 }
2689
print_button_info(Button * b)2690 static void print_button_info(Button *b)
2691 {
2692 #ifdef FVWM_DEBUG_MSGS
2693 ConsoleMessage("button: %d\n", b->index);
2694 ConsoleMessage("win: 0x%x\n", (unsigned int) b->drawn_state.win);
2695 ConsoleMessage("dirty: 0x%x\n", b->drawn_state.dirty_flags);
2696 if (b->drawn_state.win) {
2697 ConsoleMessage("name: %s\n", b->drawn_state.display_string);
2698 ConsoleMessage("iconified: %d state %d\n", b->drawn_state.iconified,
2699 b->drawn_state.state);
2700 ConsoleMessage("win->button: 0x%x\n",
2701 (unsigned int) b->drawn_state.win->button);
2702 }
2703 #endif
2704 }
2705