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
19 #include "libs/fvwmlib.h"
20 #include "libs/FShape.h"
21 #include "libs/Module.h"
22 #include "FvwmIconMan.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
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 */
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 */
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
)
74 ConsoleDebug(X11
, "selected_button_in_man: %p\n",
76 if (globals
.select_win
&& globals
.select_win
->button
&&
77 globals
.select_win
->manager
== man
) {
78 return globals
.select_win
->button
->index
;
84 static void ClipRectangle(WinManager
*man
, int context
,
85 int x
, int y
, int w
, int h
)
94 XSetClipRectangles(theDisplay
, man
->hiContext
[context
], 0, 0, &r
, 1,
99 static Region
GetRegion(int x
, int y
, int w
, int h
)
102 XRectangle rectangle
;
107 rectangle
.height
= h
;
109 region
= XCreateRegion();
110 XUnionRectWithRegion(&rectangle
, region
, 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
)
128 static int index_to_box(WinManager
*man
, int index
)
130 int first_len
, n
, cols
;
132 if (man
->geometry
.dir
& GROW_DOWN
) {
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
;
146 static int box_to_index(WinManager
*man
, int box
)
148 int first_len
, n
, cols
;
151 if (man
->geometry
.dir
& GROW_DOWN
)
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
))
166 if (index
>= first_len
)
168 index
-= cols
- first_len
;
176 static int index_to_row(WinManager
*man
, int index
)
180 row
= index_to_box(man
, index
) / man
->geometry
.cols
;
185 static int index_to_col(WinManager
*man
, int index
)
189 col
= index_to_box(man
, index
) % man
->geometry
.cols
;
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
;
210 static ManGeometry
*figure_geometry(WinManager
*man
)
212 /* Given the number of wins in icon_list and width x height, compute
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
;
224 X11
, "figure_geometry: %s: %d, %d %d %d %d\n",
226 ret
.width
, ret
.height
, ret
.cols
, ret
.rows
);
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
)
249 if (n
*man
->max_button_width
<= ret
.width
)
254 else if ((n
/i
)*man
->max_button_width
<=
259 man
->max_button_width
;
264 ret
.boxwidth
= man
->max_button_width
;
266 if (ret
.boxwidth
< 1)
273 if (man
->geometry
.dir
& GROW_VERT
)
277 ret
.rows
= num_visible_rows(n
, g
->cols
);
282 "Internal error in figure_geometry\n");
285 ret
.height
= ret
.rows
* g
->boxheight
;
286 ret
.width
= ret
.cols
* g
->boxwidth
;
287 if (ret
.boxwidth
< 1)
294 /* need to set resize inc */
297 ret
.cols
= num_visible_rows(n
, g
->rows
);
302 "Internal error in figure_geometry\n");
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)
316 X11
, "figure_geometry: %d %d %d %d %d\n",
317 n
, ret
.width
, ret
.height
, ret
.cols
, ret
.rows
);
322 static ManGeometry
*query_geometry(WinManager
*man
)
324 XWindowAttributes frame_attr
, win_attr
;
326 static ManGeometry g
;
328 assert(man
->window_mapped
);
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
;
342 fprintf(stderr
, "%s: query_geometry: failed to get frame attributes.\n",
345 if (XGetWindowAttributes(theDisplay
, man
->theWindow
, &win_attr
))
347 g
.width
= win_attr
.width
;
348 g
.height
= win_attr
.height
;
354 fprintf(stderr
, "%s: query_geometry: failed to get window attributes.\n",
361 static void fix_manager_size(WinManager
*man
, int w
, int h
)
366 if (man
->geometry
.dir
& GROW_FIXED
)
369 XGetWMNormalHints(theDisplay
, man
->theWindow
, &size
, &mask
);
374 XSetWMNormalHints(theDisplay
, man
->theWindow
, &size
);
377 /* Like XMoveResizeWindow(), but can move in arbitary directions */
378 static void resize_window(WinManager
*man
)
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
);
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
;
399 man
->geometry
.x
= g
->x
;
402 man
->geometry
.y
= g
->y
+ g
->height
- man
->geometry
.height
;
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
,
416 man
->geometry
.width
, man
->geometry
.height
);
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; \
432 while (*temp_p && out_p - buf < len - 1) \
433 *out_p++ = *temp_p++; \
436 static char buf
[MAX_DISPLAY_SIZE
];
437 char *string
, *in_p
, *out_p
, *temp_p
;
442 if (len
> MAX_DISPLAY_SIZE
|| len
<= 0)
443 len
= MAX_DISPLAY_SIZE
;
445 while (*in_p
&& out_p
- buf
< len
- 1) {
449 COPY(visible_icon_name
);
480 #undef MAX_DISPLAY_SIZE
483 Button
*button_above(WinManager
*man
, Button
*b
)
485 int n
= man
->buttons
.num_windows
, cols
= man
->geometry
.cols
;
489 i
= box_to_index(man
, index_to_box(man
, b
->index
) - cols
);
494 return man
->buttons
.buttons
[i
];
497 Button
*button_below(WinManager
*man
, Button
*b
)
499 int n
= man
->buttons
.num_windows
;
503 i
= box_to_index(man
, index_to_box(man
, b
->index
) + man
->geometry
.cols
);
508 return man
->buttons
.buttons
[i
];
511 Button
*button_right(WinManager
*man
, Button
*b
)
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
)
522 return man
->buttons
.buttons
[i
];
525 Button
*button_left(WinManager
*man
, Button
*b
)
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
)
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
];
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
];
558 Button
*xy_to_button(WinManager
*man
, int x
, int y
)
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
];
582 * Routines which change dirtyable state
585 static void set_button_geometry(WinManager
*man
, Button
*box
)
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
)
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
)
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
;
628 static void set_num_buttons(ButtonArray
*buttons
, int n
)
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
)
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;
671 man
->geometry
.gravity_y
= man
->geometry
.height
;
672 if (man
->gravity
== NorthWestGravity
|| man
->gravity
== SouthWestGravity
)
673 man
->geometry
.gravity_x
= 0;
675 man
->geometry
.gravity_x
= man
->geometry
.width
;
678 static void set_man_geometry(WinManager
*man
, ManGeometry
*new)
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
;
718 void set_win_picture(WinData
*win
, Pixmap picture
, Pixmap mask
, Pixmap alpha
,
719 unsigned int depth
, unsigned int width
,
722 if (!FMiniIconsSupported
)
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. */
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
)
757 else if (win
->manager
->swallowed
)
759 if (win
->manager
->swallower_win
&&
761 id_to_win(win
->manager
->swallower_win
)) &&
762 man_data
->geometry_set
)
765 if (!IS_SHADED(man_data
))
767 /* animate as usual */
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
;
788 XTranslateCoordinates(
789 theDisplay
, win
->manager
->theWindow
,
790 theRoot
, win
->button
->x
, win
->button
->y
,
791 &abs_x
, &abs_y
, &junkw
);
796 if (w
> man_data
->real_g
.width
)
800 if (h
> man_data
->real_g
.height
)
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
;
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
,
827 sprintf(string
, "%s %d %d %d %d %d %d %d %d",
828 win
->manager
->AnimCommand
,
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
;
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
;
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
;
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
;
885 win
->state
= SELECT_CONTEXT
;
890 /* add_win_state should not be called */
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
)
914 win
->state
= ICON_CONTEXT
;
918 win
->state
= PLAIN_CONTEXT
;
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
)
936 win
->state
= ICON_CONTEXT
;
940 win
->state
= PLAIN_CONTEXT
;
950 /* del_win_state should not be called */
951 /*win->state = PLAIN_CONTEXT;*/
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
;
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
)) {
978 if (man
->window_up
) {
979 assert(man
->geometry
.width
&& man
->fontwidth
);
980 maxlen
= man
->geometry
.width
/ man
->fontwidth
+ 2 /* fudge factor */;
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))
993 copy_string(&win
->display_string
, tmp
);
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
;
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 */)
1018 rects
[0].width
= man
->geometry
.width
;
1019 rects
[0].height
= man
->geometry
.height
;
1022 else if (man
->geometry
.dir
& GROW_DOWN
)
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
;
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
;
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
;
1049 /* for shaped windows, we won't see this part of the window */
1054 rects
[0].width
= man
->geometry
.width
;
1055 rects
[0].height
= top_y_coord(man
);
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
;
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
;
1081 ConsoleDebug(X11
, "Clearing: %d: (%d, %d, %d, %d) + (%d, %d, %d, %d)\n",
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)
1093 theDisplay
, man
->theWindow
, rects
[n
].x
, rects
[n
].y
,
1094 rects
[n
].width
, rects
[n
].height
, False
);
1100 XFillRectangles(theDisplay
, man
->theWindow
,
1101 man
->backContext
[DEFAULT
], rects
, num_rects
);
1105 void set_shape(WinManager
*man
)
1107 if (FShapesSupported
)
1110 XRectangle rects
[2];
1111 int cols
= man
->geometry
.cols
;
1113 if (man
->shaped
== 0)
1116 ConsoleDebug(X11
, "in set_shape: %s\n", man
->titlename
);
1118 n
= man
->buttons
.num_windows
;
1121 man
->shape
.num_rects
= 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];
1133 if (cols
== 0 || n
% cols
== 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];
1145 if (man
->geometry
.dir
& GROW_DOWN
) {
1148 rects
[0].width
= cols
* man
->geometry
.boxwidth
;
1150 (num_visible_rows(n
, cols
) - 1) * man
->geometry
.boxheight
;
1152 rects
[1].y
= rects
[0].height
;
1153 rects
[1].width
= (n
% cols
) * man
->geometry
.boxwidth
;
1154 rects
[1].height
= man
->geometry
.boxheight
;
1158 rects
[0].y
= top_y_coord(man
);
1159 rects
[0].width
= (n
% cols
) * man
->geometry
.boxwidth
;
1160 rects
[0].height
= man
->geometry
.boxheight
;
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
)
1202 int oldwidth
, oldheight
, w
, h
;
1204 new = figure_geometry(man
);
1206 assert(new->width
&& 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
)
1231 int oldwidth
, oldheight
, oldrows
, oldcols
, old_boxwidth
, old_boxheight
;
1235 if (man
->flags
.is_shaded
)
1237 man
->flags
.needs_resize_after_unshade
= 1;
1240 if (man
->can_draw
== 0)
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);
1255 if (force
|| oldrows
!= new->rows
|| oldcols
!= new->cols
||
1256 oldwidth
!= new->width
|| oldheight
!= new->height
) {
1257 man
->dirty_flags
|= GEOMETRY_CHANGED
;
1261 new = figure_geometry(man
);
1262 set_man_geometry(man
, new);
1264 if (force
|| oldrows
!= new->rows
|| oldcols
!= new->cols
||
1265 oldwidth
!= new->width
|| oldheight
!= new->height
) {
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
);
1299 static int center_padding(int h1
, int h2
)
1301 return (h2
- h1
) / 2;
1304 static void get_title_geometry(WinManager
*man
, ButtonGeometry
*g
)
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
);
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
,
1326 int icon_pad
, text_pad
;
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
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
;
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
);
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
)
1379 theDisplay
, man
->theWindow
,
1380 bounding
.x
, bounding
.y
,
1381 bounding
.width
, bounding
.height
,
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
]);
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))
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
)
1421 int cset
= man
->colorsets
[contextId
];
1424 if (!man
->window_up
)
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
,
1433 if (inter
.width
<= 0 || inter
.height
<= 0)
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)
1447 FvwmRenderAttributes fra
;
1448 int p_x
= 0, p_y
= 0;
1450 fra
.mask
= FRAM_DEST_IS_A_WINDOW
;
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
],
1468 p_x
, p_y
, inter
.width
, inter
.height
,
1469 inter
.x
, inter
.y
, inter
.width
, inter
.height
,
1475 if (!PictureUseBWOnly())
1477 draw_3d_icon(man
, box
, g
, iconified
, contextId
);
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);
1497 draw_button_background(man
, inter
, contextId
);
1501 int change_windows_manager(WinData
*win
)
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",
1519 return (newman
!= oldman
);
1522 void check_in_window(WinData
*win
)
1525 int is_state_selected
;
1527 if (win
->complete
) {
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
) {
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
))
1551 if ((win
->manager
->showonlyfocused
&& win
->state
!= FOCUS_CONTEXT
) &&
1552 (win
->manager
->showonlyfocused
&& win
->state
!= FOCUS_SELECT_CONTEXT
))
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
)
1572 switch (man
->buttonState
[state
]) {
1574 gc1
= man
->flatContext
[state
];
1575 gc2
= man
->flatContext
[state
];
1580 gc1
= man
->reliefContext
[state
];
1581 gc2
= man
->shadowContext
[state
];
1585 case BUTTON_EDGEDOWN
:
1586 gc1
= man
->shadowContext
[state
];
1587 gc2
= man
->reliefContext
[state
];
1591 ConsoleMessage("Internal error in get_gcs\n");
1595 if (((man
->rev
== REVERSE_ICON
) && iconified
)
1596 || ((man
->rev
== REVERSE_NORMAL
) && !iconified
)) {
1606 static void draw_relief(WinManager
*man
, int button_state
, ButtonGeometry
*g
,
1607 GC context1
, GC context2
)
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)
1623 if (state
== BUTTON_FLAT
|| relief
== 0)
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
,
1629 RelieveRectangle(theDisplay
, man
->theWindow
, g
->button_x
+2, g
->button_y
+2,
1630 g
->button_w
- 5, g
->button_h
- 5, context2
, context1
,
1634 RelieveRectangle(theDisplay
, man
->theWindow
, g
->button_x
, g
->button_y
,
1635 g
->button_w
- 1, g
->button_h
- 1, context1
, context2
,
1640 static void draw_button(WinManager
*man
, int button
, int force
)
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;
1653 if (!man
->window_up
)
1655 ConsoleMessage("draw_button: manager not up yet\n");
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");
1674 if (force
|| (dirty
& REDRAW_BUTTON
))
1676 ConsoleDebug(X11
, "draw_button: %d forced\n", b
->index
);
1677 draw_background
= 1;
1682 /* figure out what we have to draw */
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
!=
1696 man
->drawn_geometry
.gravity_x
||
1697 b
->y
- man
->geometry
.gravity_y
!=
1699 man
->drawn_geometry
.gravity_y
)
1701 draw_background
= 1;
1706 if (dirty
& STATE_CHANGED
)
1708 ConsoleDebug(X11
, "\tState changed\n");
1709 b
->drawn_state
.state
= win
->state
;
1710 draw_background
= 1;
1714 if (FMiniIconsSupported
&& (dirty
& PICTURE_CHANGED
))
1718 ConsoleDebug(X11
, "\tPicture changed\n");
1720 win
->pic
= win
->old_pic
;
1721 get_button_geometry(man
, b
, &old_g
);
1723 b
->drawn_state
.pic
= win
->pic
;
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
;
1734 draw_background
= 1;
1737 if (dirty
& STRING_CHANGED
)
1740 X11
, "\tString changed: %s\n",
1741 win
->display_string
);
1743 &b
->drawn_state
.display_string
,
1744 win
->display_string
);
1745 assert(b
->drawn_state
.display_string
);
1747 draw_background
= 1;
1752 if (draw_background
|| draw_icon
|| draw_string
)
1754 XRectangle bounding
;
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
;
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
);
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
);
1791 ConsoleDebug(X11
, "\tClearing old picture\n");
1792 if (!cleared_button
)
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
,
1803 draw_button_background(
1804 man
, r
, button_state
);
1810 ConsoleDebug(X11
, "\tDrawing icon\n");
1812 man
, win
, button
, &g
, win
->iconified
,
1813 button_state
, cleared_button
, bounding
);
1815 /* Draw reliefs after icon since the icon might overlay
1817 if (draw_background
)
1819 ConsoleDebug(X11
, "\tDrawing reliefs\n");
1820 if (!PictureUseBWOnly())
1823 man
, button_state
, win
->iconified
,
1824 &context1
, &context2
);
1826 man
, button_state
, &g
, context1
,
1829 else if (button_state
& SELECT_CONTEXT
)
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);
1843 X11
, "\tDrawing text: %s\n",
1844 b
->drawn_state
.display_string
);
1847 g
.text_x
, g
.text_y
, g
.text_w
, g
.text_h
);
1848 XIntersectRegion(tr
, b_region
, tr
);
1850 theDisplay
, man
->hiContext
[button_state
], tr
);
1851 if (!cleared_button
)
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
,
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
;
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
;
1880 theDisplay
, man
->FButtonFont
, FwinString
, 0);
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;
1898 void draw_managers(void)
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
;
1910 int len
= strlen(man
->titlename
);
1913 ConsoleDebug(X11
, "draw_empty_manager\n");
1914 clear_empty_region(man
);
1915 get_title_geometry(man
, &g
);
1917 /* FIXME: should bound when exposed */
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
;
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
)
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;
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;
1979 if (redraw_all
|| (man
->dirty_flags
& MAPPING_CHANGED
)) {
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
);
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
]))
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) {
2026 draw_empty_manager(man
);
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
;
2044 Bool
draw_transparent_buttons(
2045 WinManager
*man
, Bool only_moved
, Bool clear_only
)
2048 Contexts button_state
;
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
);
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
)))
2091 theDisplay
, man
->theWindow
,
2092 bp
[i
]->x
, bp
[i
]->y
, bp
[i
]->w
, bp
[i
]->h
,
2098 bp
[i
]->drawn_state
.dirty_flags
|= REDRAW_BUTTON
;
2099 draw_button(man
, i
, 0);
2105 static int compute_weight(WinData
*win
)
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
)) {
2117 if (sort
->classname
&& !matchWildcards(sort
->classname
, win
->classname
)) {
2120 if (sort
->titlename
&& !matchWildcards(sort
->titlename
, win
->titlename
)) {
2123 if (sort
->iconname
&& !matchWildcards(sort
->iconname
, win
->iconname
)) {
2126 return sort
->weight
;
2131 static int compare_windows(SortType type
, WinData
*a
, WinData
*b
)
2137 return a
->app_id
- b
->app_id
;
2139 else if (type
== SortName
)
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
);
2158 return strcmp((a
->display_string
)? a
->display_string
:"",
2159 (b
->display_string
)? b
->display_string
:"");
2163 ConsoleMessage("Internal error in compare_windows\n");
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,
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
;
2183 bp
= man
->buttons
.buttons
;
2185 /* start search from our current location */
2186 cur
= win
->button
->index
;
2189 compare_windows(man
->sort
,
2190 win
, bp
[cur
- 1]->drawn_state
.win
) < 0) {
2196 else if (cur
< num_windows
- 1 &&
2197 compare_windows(man
->sort
,
2198 win
, bp
[cur
+ 1]->drawn_state
.win
) > 0) {
2200 finish
= num_windows
;
2210 finish
= num_windows
;
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;
2219 ConsoleDebug(X11
, "find_windows_spot: %s %d\n", win
->display_string
, i
);
2224 /* already have a perfectly fine spot */
2225 return win
->button
->index
;
2232 /* shouldn't get here */
2236 static void move_window_buttons(WinManager
*man
, int start
, int finish
,
2239 int n
= man
->buttons
.num_buttons
, i
;
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
);
2251 bp
= man
->buttons
.buttons
;
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
)
2281 int selected_index
= -1;
2282 WinManager
*man
= win
->manager
;
2283 ButtonArray
*buttons
;
2285 ConsoleDebug(X11
, "insert_windows_button: %s\n", win
->titlename
);
2288 selected_index
= selected_button_in_man(man
);
2291 ConsoleDebug(X11
, "insert_windows_button: POSSIBLE BUG: "
2292 "already have a button\n");
2296 if (!win
|| !win
->complete
|| !man
) {
2297 ConsoleMessage("Internal error in insert_windows_button\n");
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",
2312 move_highlight(man
, man
->buttons
.buttons
[selected_index
]);
2316 void delete_windows_button(WinData
*win
)
2319 int selected_index
= -1;
2320 WinManager
*man
= (win
->manager
);
2321 ButtonArray
*buttons
;
2323 ConsoleDebug(X11
, "delete_windows_button: %s\n", win
->titlename
);
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",
2336 spot
= win
->button
->index
;
2339 move_window_buttons(win
->manager
, spot
+ 1, buttons
->num_windows
- 1, -1);
2340 increase_num_windows(buttons
, -1);
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",
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);
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
)
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
;
2408 globals
.select_win
= NULL
;
2411 man
->select_button
= b
;
2414 void man_exposed(WinManager
*man
, XEvent
*theEvent
)
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
;
2454 draw_empty_manager(man
);
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(
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
) -
2478 bp
[i
]->drawn_state
.eh
=
2479 min(r1
.y
+r1
.height
, r2
.y
+r2
.height
) -
2481 bp
[i
]->drawn_state
.dirty_flags
|= REDRAW_BUTTON
;
2487 draw_empty_manager(man
);
2495 static char *get_tips(WinManager
*man
, Button
*b
)
2499 static char *free_str
= NULL
;
2501 if (man
->tips
== TIPS_NEVER
|| b
== NULL
)
2506 if (free_str
!= NULL
)
2512 if (man
->tips_formatstring
&& b
->drawn_state
.win
)
2515 &s
, make_display_string(
2516 b
->drawn_state
.win
, man
->tips_formatstring
,
2522 s
= b
->drawn_state
.display_string
;
2530 if (man
->tips
== TIPS_ALWAYS
)
2536 if (free_str
!= NULL
&&
2537 (b
->drawn_state
.display_string
== NULL
||
2538 strcmp(s
, b
->drawn_state
.display_string
)))
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)
2554 void tips_cancel(WinManager
*man
)
2560 man
->tipped_button
= NULL
;
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
)
2577 if ((tips_str
= get_tips(man
, b
)) != NULL
)
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
;
2590 void tips_update_label(WinManager
*man
)
2594 if ((tips_str
= get_tips(man
, man
->tipped_button
)) != NULL
)
2596 FTipsUpdateLabel(theDisplay
, tips_str
);
2606 * Debugging routines
2609 void check_managers_consistency(void)
2611 #ifdef FVWM_DEBUG_MSGS
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
);
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",
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
);