Better error message when defaults file is missing.
[xfwm4.git] / src / frame.c
blob1990d51116adc87faf5c4776d523ecb6cd5c0a26
1 /* $Id$
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 oroborus - (c) 2001 Ken Lynch
18 xfwm4 - (c) 2002-2007 Olivier Fourdan
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
26 #include <glib.h>
27 #include <gdk/gdk.h>
28 #include <gdk/gdkx.h>
29 #include <pango/pango.h>
30 #include <libxfce4util/libxfce4util.h>
32 #include "screen.h"
33 #include "client.h"
34 #include "settings.h"
35 #include "mywindow.h"
36 #include "focus.h"
37 #include "frame.h"
38 #include "compositor.h"
40 #ifndef ShapeInput
41 #define ShapeInput 2
42 #endif
44 typedef struct
46 xfwmPixmap pm_title;
47 xfwmPixmap pm_sides[SIDE_COUNT];
48 } FramePixmap;
51 int
52 frameDecorationLeft (ScreenInfo *screen_info)
54 TRACE ("entering frameDecorationLeft");
56 g_return_val_if_fail (screen_info != NULL, 0);
57 return screen_info->sides[SIDE_LEFT][ACTIVE].width;
60 int
61 frameDecorationRight (ScreenInfo *screen_info)
63 TRACE ("entering frameDecorationRight");
65 g_return_val_if_fail (screen_info != NULL, 0);
66 return screen_info->sides[SIDE_RIGHT][ACTIVE].width;
69 int
70 frameDecorationTop (ScreenInfo *screen_info)
72 TRACE ("entering frameDecorationTop");
74 g_return_val_if_fail (screen_info != NULL, 0);
75 return screen_info->title[TITLE_3][ACTIVE].height;
78 int
79 frameDecorationBottom (ScreenInfo *screen_info)
81 TRACE ("entering frameDecorationBottom");
83 g_return_val_if_fail (screen_info != NULL, 0);
84 return screen_info->sides[SIDE_BOTTOM][ACTIVE].height;
87 int
88 frameLeft (Client * c)
90 TRACE ("entering frameLeft");
92 g_return_val_if_fail (c != NULL, 0);
93 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
94 && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN)
95 && (!FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
96 || !(c->screen_info->params->borderless_maximize)))
98 return c->screen_info->sides[SIDE_LEFT][ACTIVE].width;
100 return 0;
104 frameRight (Client * c)
106 TRACE ("entering frameRight");
108 g_return_val_if_fail (c != NULL, 0);
109 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
110 && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN)
111 && (!FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
112 || !(c->screen_info->params->borderless_maximize)))
114 return c->screen_info->sides[SIDE_RIGHT][ACTIVE].width;
116 return 0;
120 frameTop (Client * c)
122 TRACE ("entering frameTop");
124 g_return_val_if_fail (c != NULL, 0);
125 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
126 && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
128 return c->screen_info->title[TITLE_3][ACTIVE].height;
130 return 0;
134 frameBottom (Client * c)
136 TRACE ("entering frameBottom");
138 g_return_val_if_fail (c != NULL, 0);
139 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
140 && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN)
141 && (!FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
142 || !(c->screen_info->params->borderless_maximize)))
144 return c->screen_info->sides[SIDE_BOTTOM][ACTIVE].height;
146 return 0;
150 frameX (Client * c)
152 TRACE ("entering frameX");
154 g_return_val_if_fail (c != NULL, 0);
155 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
156 && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN)
157 && (!FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
158 || !(c->screen_info->params->borderless_maximize)))
160 return c->x - frameLeft (c);
162 return c->x;
166 frameY (Client * c)
168 TRACE ("entering frameY");
170 g_return_val_if_fail (c != NULL, 0);
171 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
172 && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
174 return c->y - frameTop (c);
176 return c->y;
180 frameWidth (Client * c)
182 TRACE ("entering frameWidth");
184 g_return_val_if_fail (c != NULL, 0);
185 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
186 && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN)
187 && (!FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
188 || !(c->screen_info->params->borderless_maximize)))
190 return c->width + frameLeft (c) + frameRight (c);
192 return c->width;
196 frameHeight (Client * c)
198 TRACE ("entering frameHeight");
200 g_return_val_if_fail (c != NULL, 0);
201 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
202 && FLAG_TEST (c->flags, CLIENT_FLAG_SHADED)
203 && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
205 return frameTop (c) + frameBottom (c);
207 else if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
208 && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
210 return c->height + frameTop (c) + frameBottom (c);
212 return c->height;
215 static int
216 frameTopLeftWidth (Client * c, int state)
218 TRACE ("entering frameTopLeftWidth");
220 g_return_val_if_fail (c != NULL, 0);
221 if (FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
222 && c->screen_info->params->borderless_maximize)
224 return 0;
226 return c->screen_info->corners[CORNER_TOP_LEFT][state].width;
230 static int
231 frameTopRightWidth (Client * c, int state)
233 TRACE ("entering frameTopRightWidth");
235 g_return_val_if_fail (c != NULL, 0);
236 if (FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
237 && c->screen_info->params->borderless_maximize)
239 return 0;
241 return c->screen_info->corners[CORNER_TOP_RIGHT][state].width;
244 static int
245 frameButtonOffset (Client *c)
247 TRACE ("entering frameButtonOffset");
249 g_return_val_if_fail (c != NULL, 0);
250 if (FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
251 && c->screen_info->params->borderless_maximize)
253 return MAX (0, c->screen_info->params->maximized_offset);
255 return c->screen_info->params->button_offset;
258 static void
259 frameFillTitlePixmap (Client * c, int state, int part, int x, int w, int h, xfwmPixmap * title_pm, xfwmPixmap * top_pm)
261 ScreenInfo *screen_info;
263 TRACE ("entering frameFillTitlePixmap");
265 g_return_if_fail (c);
266 g_return_if_fail (title_pm);
267 g_return_if_fail (top_pm);
269 screen_info = c->screen_info;
271 if (!xfwmPixmapNone(&screen_info->top[part][state]))
273 xfwmPixmapFill (&screen_info->top[part][state], top_pm, x, 0, w, h);
275 else
277 xfwmPixmapFill (&screen_info->title[part][state], top_pm, x, 0, w, h);
279 xfwmPixmapFill (&screen_info->title[part][state], title_pm, x, 0, w, frameTop (c));
282 static void
283 frameCreateTitlePixmap (Client * c, int state, int left, int right, xfwmPixmap * title_pm, xfwmPixmap * top_pm)
285 ScreenInfo *screen_info;
286 DisplayInfo *display_info;
287 GdkPixmap *gpixmap;
288 GdkGCValues values;
289 GdkGC *gc;
290 PangoLayout *layout;
291 PangoRectangle logical_rect;
292 int width, x, hoffset, w1, w2, w3, w4, w5, temp;
293 int voffset, title_x, title_y;
294 int top_height;
296 TRACE ("entering frameCreateTitlePixmap");
298 g_return_if_fail (c);
299 g_return_if_fail (title_pm);
300 g_return_if_fail (top_pm);
302 screen_info = c->screen_info;
303 display_info = screen_info->display_info;
305 if (left > right)
307 temp = left;
308 left = right;
309 right = temp;
312 width = frameWidth (c) - frameTopLeftWidth (c, state) - frameTopRightWidth (c, state);
313 if (width < 1)
315 return;
318 layout = gtk_widget_create_pango_layout (myScreenGetGtkWidget (screen_info), c->name);
319 pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
321 if (left < frameTopLeftWidth (c, state))
323 left = frameTopLeftWidth (c, state);
325 if (right > frameWidth (c) - frameTopRightWidth (c, state))
327 right = frameWidth (c) - frameTopRightWidth (c, state);
329 if (right < frameTopLeftWidth (c, state))
331 right = frameTopLeftWidth (c, state);
334 left = left - frameTopLeftWidth (c, state);
335 right = right - frameTopLeftWidth (c, state);
337 x = 0;
338 hoffset = 0;
340 if (state == ACTIVE)
342 voffset = screen_info->params->title_vertical_offset_active;
344 else
346 voffset = screen_info->params->title_vertical_offset_inactive;
349 title_y = voffset + (frameTop (c) - logical_rect.height) / 2;
350 if (title_y + logical_rect.height > frameTop (c))
352 title_y = MAX (0, frameTop (c) - logical_rect.height);
355 if (!xfwmPixmapNone(&screen_info->top[3][ACTIVE]))
357 top_height = screen_info->top[3][ACTIVE].height;
359 else
361 top_height = frameTop (c) / 10 + 1;
362 if (top_height > title_y - 1)
364 top_height = MAX (title_y - 1, 0);
368 w1 = 0;
369 w2 = screen_info->title[TITLE_2][state].width;
370 w4 = screen_info->title[TITLE_4][state].width;
372 if (screen_info->params->full_width_title)
374 w1 = left;
375 w5 = width - right;
376 w3 = width - w1 - w2 - w4 - w5;
377 if (w3 < 0)
379 w3 = 0;
381 switch (screen_info->params->title_alignment)
383 case ALIGN_LEFT:
384 hoffset = screen_info->params->title_horizontal_offset;
385 break;
386 case ALIGN_RIGHT:
387 hoffset = w3 - logical_rect.width - screen_info->params->title_horizontal_offset;
388 break;
389 case ALIGN_CENTER:
390 hoffset = (w3 / 2) - (logical_rect.width / 2);
391 break;
393 if (hoffset < screen_info->params->title_horizontal_offset)
395 hoffset = screen_info->params->title_horizontal_offset;
398 else
400 w3 = logical_rect.width;
401 w5 = width;
402 if (w3 > width - w2 - w4)
404 w3 = width - w2 - w4;
406 if (w3 < 0)
408 w3 = 0;
410 switch (screen_info->params->title_alignment)
412 case ALIGN_LEFT:
413 w1 = left + screen_info->params->title_horizontal_offset;
414 break;
415 case ALIGN_RIGHT:
416 w1 = right - w2 - w3 - w4 - screen_info->params->title_horizontal_offset;
417 break;
418 case ALIGN_CENTER:
419 w1 = left + ((right - left) / 2) - (w3 / 2) - w2;
420 break;
422 if (w1 < left)
424 w1 = left;
428 xfwmPixmapCreate (screen_info, top_pm, width, top_height);
429 xfwmPixmapCreate (screen_info, title_pm, width, frameTop (c));
430 gpixmap = gdk_pixmap_foreign_new (title_pm->pixmap);
431 gdk_drawable_set_colormap (gpixmap, gdk_screen_get_rgb_colormap (screen_info->gscr));
432 gc = gdk_gc_new (gpixmap);
434 if (w1 > 0)
436 frameFillTitlePixmap (c, state, TITLE_1, x, w1, top_height, title_pm, top_pm);
437 x = x + w1;
440 frameFillTitlePixmap (c, state, TITLE_2, x, w2, top_height, title_pm, top_pm);
441 x = x + w2;
443 if (w3 > 0)
445 frameFillTitlePixmap (c, state, TITLE_3, x, w3, top_height, title_pm, top_pm);
446 title_x = hoffset + x;
447 if (screen_info->params->title_shadow[state])
449 gdk_gc_get_values (screen_info->title_shadow_colors[state].gc, &values);
450 gdk_gc_set_values (gc, &values, GDK_GC_FOREGROUND);
451 if (screen_info->params->title_shadow[state] == TITLE_SHADOW_UNDER)
453 gdk_draw_layout (gpixmap, gc, title_x + 1, title_y + 1, layout);
455 else
457 gdk_draw_layout (gpixmap, gc, title_x - 1, title_y, layout);
458 gdk_draw_layout (gpixmap, gc, title_x, title_y - 1, layout);
459 gdk_draw_layout (gpixmap, gc, title_x + 1, title_y, layout);
460 gdk_draw_layout (gpixmap, gc, title_x, title_y + 1, layout);
463 gdk_gc_get_values (screen_info->title_colors[state].gc, &values);
464 gdk_gc_set_values (gc, &values, GDK_GC_FOREGROUND);
465 gdk_draw_layout (gpixmap, gc, title_x, title_y, layout);
466 x = x + w3;
469 if (x > right - w4)
471 x = right - w4;
473 frameFillTitlePixmap (c, state, TITLE_4, x, w4, top_height, title_pm, top_pm);
474 x = x + w4;
476 if (w5 > 0)
478 frameFillTitlePixmap (c, state, TITLE_5, x, w5, top_height, title_pm, top_pm);
480 g_object_unref (G_OBJECT (gc));
481 g_object_unref (G_OBJECT (gpixmap));
482 g_object_unref (G_OBJECT (layout));
485 static int
486 getButtonFromLetter (char chr, Client * c)
488 int b;
490 TRACE ("entering getButtonFromLetter");
492 b = -1;
493 switch (chr)
495 case 'H':
496 if (CLIENT_CAN_HIDE_WINDOW (c))
498 b = HIDE_BUTTON;
500 break;
501 case 'C':
502 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_CLOSE))
504 b = CLOSE_BUTTON;
506 break;
507 case 'M':
508 if (CLIENT_CAN_MAXIMIZE_WINDOW (c))
510 b = MAXIMIZE_BUTTON;
512 break;
513 case 'S':
514 b = SHADE_BUTTON;
515 break;
516 case 'T':
517 if (FLAG_TEST_ALL (c->xfwm_flags, XFWM_FLAG_HAS_STICK | XFWM_FLAG_HAS_MENU))
519 b = STICK_BUTTON;
521 break;
522 case 'O':
523 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_MENU))
525 b = MENU_BUTTON;
527 break;
528 case '|':
529 b = TITLE_SEPARATOR;
530 break;
531 default:
532 b = -1;
534 return b;
537 static char
538 getLetterFromButton (int i, Client * c)
540 char chr;
542 TRACE ("entering getLetterFromButton");
544 chr = 0;
545 switch (i)
547 case HIDE_BUTTON:
548 if (CLIENT_CAN_HIDE_WINDOW (c))
550 chr = 'H';
552 break;
553 case CLOSE_BUTTON:
554 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_CLOSE))
556 chr = 'C';
558 break;
559 case MAXIMIZE_BUTTON:
560 if (CLIENT_CAN_MAXIMIZE_WINDOW (c))
562 chr = 'M';
564 break;
565 case SHADE_BUTTON:
566 chr = 'S';
567 break;
568 case STICK_BUTTON:
569 if (FLAG_TEST_ALL (c->xfwm_flags, XFWM_FLAG_HAS_STICK | XFWM_FLAG_HAS_MENU))
571 chr = 'T';
573 break;
574 case MENU_BUTTON:
575 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_MENU))
577 chr = 'O';
579 break;
580 default:
581 chr = 0;
583 return chr;
586 static void
587 frameSetShape (Client * c, int state, FramePixmap * frame_pix, int button_x[BUTTON_COUNT])
589 ScreenInfo *screen_info;
590 DisplayInfo *display_info;
591 Window shape_win;
592 XRectangle rect;
593 xfwmPixmap *my_pixmap;
594 int i;
596 TRACE ("entering frameSetShape");
597 TRACE ("setting shape for client (0x%lx)", c->window);
599 screen_info = c->screen_info;
600 display_info = screen_info->display_info;
602 if (!display_info->have_shape)
604 return;
607 shape_win = XCreateSimpleWindow (display_info->dpy, c->frame, 0, 0, frameWidth (c), frameHeight (c), 0, 0, 0);
609 if (FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
611 rect.x = 0;
612 rect.y = 0;
613 rect.width = frameWidth (c);
614 rect.height = frameHeight (c);
615 XShapeCombineRectangles (display_info->dpy, shape_win, ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, Unsorted);
617 else if (!FLAG_TEST (c->flags, CLIENT_FLAG_HAS_SHAPE))
619 rect.x = frameLeft (c);
620 rect.y = frameTop (c);
621 rect.width = c->width;
622 rect.height = c->height;
623 XShapeCombineRectangles (display_info->dpy, shape_win, ShapeBounding, 0, 0, &rect, 1, ShapeSet, Unsorted);
625 else
627 XShapeCombineShape (display_info->dpy, shape_win, ShapeBounding, frameLeft (c),
628 frameTop (c), c->window, ShapeBounding, ShapeSet);
630 if (frame_pix)
632 XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->title), ShapeBounding,
633 0, 0, frame_pix->pm_title.mask, ShapeSet);
634 if (!FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
636 if (xfwmWindowVisible (&c->sides[SIDE_LEFT]))
638 XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->sides[SIDE_LEFT]),
639 ShapeBounding, 0, 0, frame_pix->pm_sides[SIDE_LEFT].mask, ShapeSet);
642 if (xfwmWindowVisible (&c->sides[SIDE_RIGHT]))
644 XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->sides[SIDE_RIGHT]),
645 ShapeBounding, 0, 0, frame_pix->pm_sides[SIDE_RIGHT].mask, ShapeSet);
649 if (xfwmWindowVisible (&c->sides[SIDE_BOTTOM]))
651 XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->sides[SIDE_BOTTOM]),
652 ShapeBounding, 0, 0, frame_pix->pm_sides[SIDE_BOTTOM].mask, ShapeSet);
655 if (xfwmWindowVisible (&c->sides[SIDE_TOP]))
657 XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->sides[SIDE_TOP]),
658 ShapeBounding, 0, 0, frame_pix->pm_sides[SIDE_TOP].mask, ShapeSet);
661 if (xfwmWindowVisible (&c->corners[CORNER_BOTTOM_LEFT]))
663 XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->corners[CORNER_BOTTOM_LEFT]),
664 ShapeBounding, 0, 0, screen_info->corners[CORNER_BOTTOM_LEFT][state].mask, ShapeSet);
667 if (xfwmWindowVisible (&c->corners[CORNER_BOTTOM_RIGHT]))
669 XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->corners[CORNER_BOTTOM_RIGHT]),
670 ShapeBounding, 0, 0, screen_info->corners[CORNER_BOTTOM_RIGHT][state].mask, ShapeSet);
673 if (xfwmWindowVisible (&c->corners[CORNER_TOP_LEFT]))
675 XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->corners[CORNER_TOP_LEFT]),
676 ShapeBounding, 0, 0, screen_info->corners[CORNER_TOP_LEFT][state].mask, ShapeSet);
679 if (xfwmWindowVisible (&c->corners[CORNER_TOP_RIGHT]))
681 XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->corners[CORNER_TOP_RIGHT]),
682 ShapeBounding, 0, 0, screen_info->corners[CORNER_TOP_RIGHT][state].mask, ShapeSet);
685 for (i = 0; i < BUTTON_COUNT; i++)
687 if (xfwmWindowVisible (&c->buttons[i]))
689 my_pixmap = clientGetButtonPixmap (c, i, clientGetButtonState (c, i, state));
690 XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->buttons[i]),
691 ShapeBounding, 0, 0, my_pixmap->mask, ShapeSet);
695 if (xfwmWindowVisible (&c->corners[CORNER_TOP_LEFT]) &&
696 (screen_info->corners[CORNER_TOP_LEFT][state].height > frameHeight (c) - frameBottom (c) + 1))
698 rect.x = 0;
699 rect.y = frameHeight (c) - frameBottom (c) + 1;
700 rect.width = frameTopLeftWidth (c, state);
701 rect.height = screen_info->corners[CORNER_TOP_LEFT][state].height
702 - (frameHeight (c) - frameBottom (c) + 1);
703 XShapeCombineRectangles (display_info->dpy, MYWINDOW_XWINDOW (c->corners[CORNER_TOP_LEFT]),
704 ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, 0);
707 if (xfwmWindowVisible (&c->corners[CORNER_TOP_RIGHT]) &&
708 (screen_info->corners[CORNER_TOP_RIGHT][state].height > frameHeight (c) - frameBottom (c) + 1))
710 rect.x = 0;
711 rect.y = frameHeight (c) - frameBottom (c) + 1;
712 rect.width = frameTopRightWidth (c, state);
713 rect.height = screen_info->corners[CORNER_TOP_RIGHT][state].height
714 - (frameHeight (c) - frameBottom (c) + 1);
715 XShapeCombineRectangles (display_info->dpy, MYWINDOW_XWINDOW (c->corners[CORNER_TOP_RIGHT]),
716 ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, 0);
719 if (xfwmWindowVisible (&c->corners[CORNER_BOTTOM_LEFT]) &&
720 (screen_info->corners[CORNER_BOTTOM_LEFT][state].height > frameHeight (c) - frameTop (c) + 1))
722 rect.x = 0;
723 rect.y = 0;
724 rect.width = screen_info->corners[CORNER_BOTTOM_LEFT][state].width;
725 rect.height = screen_info->corners[CORNER_BOTTOM_LEFT][state].height
726 - (frameHeight (c) - frameTop (c) + 1);
727 XShapeCombineRectangles (display_info->dpy, MYWINDOW_XWINDOW (c->corners[CORNER_BOTTOM_LEFT]),
728 ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, 0);
731 if (xfwmWindowVisible (&c->corners[CORNER_BOTTOM_RIGHT]) &&
732 (screen_info->corners[CORNER_BOTTOM_RIGHT][state].height > frameHeight (c) - frameTop (c) + 1))
734 rect.x = 0;
735 rect.y = 0;
736 rect.width = screen_info->corners[CORNER_BOTTOM_RIGHT][state].width;
737 rect.height = screen_info->corners[CORNER_BOTTOM_RIGHT][state].height
738 - (frameHeight (c) - frameTop (c) + 1);
739 XShapeCombineRectangles (display_info->dpy, MYWINDOW_XWINDOW (c->corners[CORNER_BOTTOM_RIGHT]),
740 ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, 0);
743 if (!FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
745 if (xfwmWindowVisible (&c->sides[SIDE_LEFT]))
747 XShapeCombineShape (display_info->dpy, shape_win, ShapeBounding, 0, frameTop (c),
748 MYWINDOW_XWINDOW (c->sides[SIDE_LEFT]), ShapeBounding, ShapeUnion);
751 if (xfwmWindowVisible (&c->sides[SIDE_RIGHT]))
753 XShapeCombineShape (display_info->dpy, shape_win, ShapeBounding, frameWidth (c) - frameRight (c), frameTop (c),
754 MYWINDOW_XWINDOW (c->sides[SIDE_RIGHT]), ShapeBounding, ShapeUnion);
758 if (xfwmWindowVisible (&c->title))
760 XShapeCombineShape (display_info->dpy, shape_win, ShapeBounding,
761 frameTopLeftWidth (c, state), 0,
762 MYWINDOW_XWINDOW (c->title), ShapeBounding, ShapeUnion);
765 if (xfwmWindowVisible (&c->corners[CORNER_TOP_LEFT]))
768 XShapeCombineShape (display_info->dpy, shape_win, ShapeBounding, 0, 0,
769 MYWINDOW_XWINDOW (c->corners[CORNER_TOP_LEFT]), ShapeBounding, ShapeUnion);
772 if (xfwmWindowVisible (&c->sides[SIDE_BOTTOM]))
774 XShapeCombineShape (display_info->dpy, shape_win, ShapeBounding,
775 screen_info->corners[CORNER_BOTTOM_LEFT][state].width,
776 frameHeight (c) - frameBottom (c),
777 MYWINDOW_XWINDOW (c->sides[SIDE_BOTTOM]), ShapeBounding, ShapeUnion);
780 if (xfwmWindowVisible (&c->sides[SIDE_TOP]))
782 XShapeCombineShape (display_info->dpy, shape_win, ShapeBounding,
783 screen_info->corners[CORNER_BOTTOM_LEFT][state].width,
784 frameTop (c) - frameBottom (c),
785 MYWINDOW_XWINDOW (c->sides[SIDE_TOP]), ShapeBounding, ShapeUnion);
788 if (xfwmWindowVisible (&c->corners[CORNER_BOTTOM_LEFT]))
790 XShapeCombineShape (display_info->dpy, shape_win, ShapeBounding, 0,
791 frameHeight (c) - screen_info->corners[CORNER_BOTTOM_LEFT][state].height,
792 MYWINDOW_XWINDOW (c->corners[CORNER_BOTTOM_LEFT]), ShapeBounding, ShapeUnion);
795 if (xfwmWindowVisible (&c->corners[CORNER_BOTTOM_RIGHT]))
797 XShapeCombineShape (display_info->dpy, shape_win, ShapeBounding,
798 frameWidth (c) - screen_info->corners[CORNER_BOTTOM_RIGHT][state].width,
799 frameHeight (c) - screen_info->corners[CORNER_BOTTOM_RIGHT][state].height,
800 MYWINDOW_XWINDOW (c->corners[CORNER_BOTTOM_RIGHT]), ShapeBounding, ShapeUnion);
803 if (xfwmWindowVisible (&c->corners[CORNER_TOP_RIGHT]))
805 XShapeCombineShape (display_info->dpy, shape_win, ShapeBounding,
806 frameWidth (c) - frameTopRightWidth (c, state),
807 0, MYWINDOW_XWINDOW (c->corners[CORNER_TOP_RIGHT]), ShapeBounding, ShapeUnion);
810 for (i = 0; i < BUTTON_COUNT; i++)
812 if (xfwmWindowVisible (&c->buttons[i]))
814 XShapeCombineShape (display_info->dpy, shape_win, ShapeBounding, button_x[i],
815 (frameTop (c) - screen_info->buttons[i][state].height + 1) / 2,
816 MYWINDOW_XWINDOW (c->buttons[i]), ShapeBounding, ShapeUnion);
820 rect.x = 0;
821 rect.y = 0;
822 rect.width = frameWidth (c);
823 rect.height = frameHeight (c);
824 XShapeCombineRectangles (display_info->dpy, shape_win, ShapeBounding, 0, 0, &rect, 1, ShapeIntersect, Unsorted);
825 XShapeCombineShape (display_info->dpy, c->frame, ShapeBounding, 0, 0, shape_win, ShapeBounding, ShapeSet);
827 /* Set Input shape when using XShape extension 1.1 and later */
828 if (display_info->shape_version >= 1001)
830 XShapeCombineShape (display_info->dpy, shape_win, ShapeInput, frameLeft (c), frameTop (c), c->window, ShapeBounding, ShapeSubtract);
831 XShapeCombineShape (display_info->dpy, shape_win, ShapeInput, frameLeft (c), frameTop (c), c->window, ShapeInput, ShapeUnion);
832 XShapeCombineShape (display_info->dpy, c->frame, ShapeInput, 0, 0, shape_win, ShapeInput, ShapeSet);
834 XDestroyWindow (display_info->dpy, shape_win);
837 void
838 frameDraw (Client * c, gboolean clear_all)
840 ScreenInfo *screen_info;
841 FramePixmap frame_pix;
842 xfwmPixmap *my_pixmap;
843 int state, i, j, x, button, left, right;
844 int top_width, bottom_width, left_height, right_height;
845 int button_x[BUTTON_COUNT];
846 gboolean requires_clearing;
847 gboolean width_changed;
848 gboolean height_changed;
850 TRACE ("entering frameDraw");
851 TRACE ("drawing frame for \"%s\" (0x%lx)", c->name, c->window);
853 g_return_if_fail (c != NULL);
855 screen_info = c->screen_info;
856 requires_clearing = FALSE;
857 width_changed = FALSE;
858 height_changed = FALSE;
859 state = ACTIVE;
861 if (c != clientGetFocus ())
863 TRACE ("\"%s\" is not the active window", c->name);
864 if (FLAG_TEST (c->wm_flags, WM_FLAG_URGENT))
866 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_SEEN_ACTIVE))
868 state = ACTIVE;
870 else
872 state = INACTIVE;
875 else
877 state = INACTIVE;
881 if ((state == INACTIVE)
882 && FLAG_TEST(c->xfwm_flags, XFWM_FLAG_DRAW_ACTIVE | XFWM_FLAG_FIRST_MAP))
884 requires_clearing = TRUE;
885 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_DRAW_ACTIVE);
887 else if ((state == ACTIVE)
888 && (!FLAG_TEST (c->xfwm_flags, XFWM_FLAG_DRAW_ACTIVE)
889 || FLAG_TEST (c->xfwm_flags, XFWM_FLAG_FIRST_MAP)))
891 requires_clearing = TRUE;
892 FLAG_SET (c->xfwm_flags, XFWM_FLAG_DRAW_ACTIVE);
894 /* Flag clearance */
895 FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_FIRST_MAP);
897 /* Cache mgmt */
898 if (clear_all)
900 width_changed = TRUE;
901 height_changed = TRUE;
902 requires_clearing = TRUE;
903 frameClearQueueDraw (c);
904 if (c->frame_timeout_id)
906 g_source_remove (c->frame_timeout_id);
907 c->frame_timeout_id = 0;
911 else
913 if (c->previous_width != c->width)
915 width_changed = TRUE;
916 c->previous_width = c->width;
918 if (c->previous_height != c->height)
920 height_changed = TRUE;
921 c->previous_height = c->height;
925 if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
926 && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
928 /* First, hide the buttons that we don't have... */
929 for (i = 0; i < BUTTON_COUNT; i++)
931 char b = getLetterFromButton (i, c);
932 if ((!b) || !strchr (screen_info->params->button_layout, b))
934 xfwmWindowHide (&c->buttons[i]);
938 /* Then, show the ones that we do have on left... */
939 x = frameLeft (c) + frameButtonOffset (c);
940 if (x < 0)
942 x = 0;
944 right = frameWidth (c) - frameRight (c) - frameButtonOffset (c);
945 for (i = 0; i < strlen (screen_info->params->button_layout); i++)
947 button = getButtonFromLetter (screen_info->params->button_layout[i], c);
948 if (button == TITLE_SEPARATOR)
950 break;
952 else if (button >= 0)
954 if (x + screen_info->buttons[button][state].width + screen_info->params->button_spacing < right)
956 my_pixmap = clientGetButtonPixmap (c, button, clientGetButtonState (c, button, state));
957 if (!xfwmPixmapNone(my_pixmap))
959 xfwmWindowSetBG (&c->buttons[button], my_pixmap);
961 xfwmWindowShow (&c->buttons[button], x,
962 (frameTop (c) - screen_info->buttons[button][state].height + 1) / 2,
963 screen_info->buttons[button][state].width,
964 screen_info->buttons[button][state].height, TRUE);
965 button_x[button] = x;
966 x = x + screen_info->buttons[button][state].width +
967 screen_info->params->button_spacing;
969 else
971 xfwmWindowHide (&c->buttons[button]);
975 left = x + screen_info->params->button_spacing;
977 /* and those that we do have on right... */
978 x = frameWidth (c) - frameRight (c) + screen_info->params->button_spacing -
979 frameButtonOffset (c);
980 for (j = strlen (screen_info->params->button_layout) - 1; j >= i; j--)
982 button = getButtonFromLetter (screen_info->params->button_layout[j], c);
983 if (button == TITLE_SEPARATOR)
985 break;
987 else if (button >= 0)
989 if (x - screen_info->buttons[button][state].width - screen_info->params->button_spacing > left)
991 my_pixmap = clientGetButtonPixmap (c, button, clientGetButtonState (c, button, state));
992 if (!xfwmPixmapNone(my_pixmap))
994 xfwmWindowSetBG (&c->buttons[button], my_pixmap);
996 x = x - screen_info->buttons[button][state].width -
997 screen_info->params->button_spacing;
998 xfwmWindowShow (&c->buttons[button], x,
999 (frameTop (c) - screen_info->buttons[button][state].height + 1) / 2,
1000 screen_info->buttons[button][state].width,
1001 screen_info->buttons[button][state].height, TRUE);
1002 button_x[button] = x;
1004 else
1006 xfwmWindowHide (&c->buttons[button]);
1010 left = left - 2 * screen_info->params->button_spacing;
1011 right = x;
1013 top_width = frameWidth (c) - frameTopLeftWidth (c, state) - frameTopRightWidth (c, state);
1014 bottom_width = frameWidth (c) -
1015 screen_info->corners[CORNER_BOTTOM_LEFT][state].width -
1016 screen_info->corners[CORNER_BOTTOM_RIGHT][state].width;
1017 left_height = frameHeight (c) - frameTop (c) -
1018 screen_info->corners[CORNER_BOTTOM_LEFT][state].height;
1019 right_height = frameHeight (c) - frameTop (c) -
1020 screen_info->corners[CORNER_BOTTOM_RIGHT][state].height;
1022 xfwmPixmapInit (screen_info, &frame_pix.pm_title);
1023 xfwmPixmapInit (screen_info, &frame_pix.pm_sides[SIDE_TOP]);
1024 xfwmPixmapInit (screen_info, &frame_pix.pm_sides[SIDE_BOTTOM]);
1025 xfwmPixmapInit (screen_info, &frame_pix.pm_sides[SIDE_LEFT]);
1026 xfwmPixmapInit (screen_info, &frame_pix.pm_sides[SIDE_RIGHT]);
1028 /* The title is always visible */
1029 frameCreateTitlePixmap (c, state, left, right, &frame_pix.pm_title, &frame_pix.pm_sides[SIDE_TOP]);
1030 xfwmWindowSetBG (&c->title, &frame_pix.pm_title);
1031 xfwmWindowShow (&c->title,
1032 frameTopLeftWidth (c, state), 0, top_width,
1033 frameTop (c), (requires_clearing | width_changed));
1035 /* Corners are never resized, we need to update them separately */
1036 if (requires_clearing)
1038 xfwmWindowSetBG (&c->corners[CORNER_TOP_LEFT],
1039 &screen_info->corners[CORNER_TOP_LEFT][state]);
1040 xfwmWindowSetBG (&c->corners[CORNER_TOP_RIGHT],
1041 &screen_info->corners[CORNER_TOP_RIGHT][state]);
1042 xfwmWindowSetBG (&c->corners[CORNER_BOTTOM_LEFT],
1043 &screen_info->corners[CORNER_BOTTOM_LEFT][state]);
1044 xfwmWindowSetBG (&c->corners[CORNER_BOTTOM_RIGHT],
1045 &screen_info->corners[CORNER_BOTTOM_RIGHT][state]);
1048 if (FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
1049 && (c->screen_info->params->borderless_maximize))
1051 xfwmWindowHide (&c->sides[SIDE_LEFT]);
1052 xfwmWindowHide (&c->sides[SIDE_RIGHT]);
1053 xfwmWindowHide (&c->sides[SIDE_BOTTOM]);
1054 xfwmWindowHide (&c->sides[SIDE_TOP]);
1055 xfwmWindowHide (&c->corners[CORNER_TOP_LEFT]);
1056 xfwmWindowHide (&c->corners[CORNER_TOP_RIGHT]);
1057 xfwmWindowHide (&c->corners[CORNER_BOTTOM_LEFT]);
1058 xfwmWindowHide (&c->corners[CORNER_BOTTOM_RIGHT]);
1060 else
1062 if (FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
1064 xfwmWindowHide (&c->sides[SIDE_LEFT]);
1065 xfwmWindowHide (&c->sides[SIDE_RIGHT]);
1067 else
1069 xfwmPixmapCreate (screen_info, &frame_pix.pm_sides[SIDE_LEFT],
1070 frameLeft (c), left_height);
1071 xfwmPixmapFill (&screen_info->sides[SIDE_LEFT][state],
1072 &frame_pix.pm_sides[SIDE_LEFT],
1073 0, 0, frameLeft (c), left_height);
1074 xfwmWindowSetBG (&c->sides[SIDE_LEFT],
1075 &frame_pix.pm_sides[SIDE_LEFT]);
1076 xfwmWindowShow (&c->sides[SIDE_LEFT], 0, frameTop (c),
1077 frameLeft (c), left_height, (requires_clearing | height_changed));
1079 xfwmPixmapCreate (screen_info, &frame_pix.pm_sides[SIDE_RIGHT],
1080 frameRight (c), right_height);
1081 xfwmPixmapFill (&screen_info->sides[SIDE_RIGHT][state],
1082 &frame_pix.pm_sides[SIDE_RIGHT],
1083 0, 0, frameRight (c), right_height);
1084 xfwmWindowSetBG (&c->sides[SIDE_RIGHT],
1085 &frame_pix.pm_sides[SIDE_RIGHT]);
1086 xfwmWindowShow (&c->sides[SIDE_RIGHT],
1087 frameWidth (c) - frameRight (c), frameTop (c), frameRight (c),
1088 right_height, (requires_clearing | height_changed));
1091 xfwmPixmapCreate (screen_info, &frame_pix.pm_sides[SIDE_BOTTOM],
1092 bottom_width, frameBottom (c));
1093 xfwmPixmapFill (&screen_info->sides[SIDE_BOTTOM][state],
1094 &frame_pix.pm_sides[SIDE_BOTTOM],
1095 0, 0, bottom_width, frameBottom (c));
1096 xfwmWindowSetBG (&c->sides[SIDE_BOTTOM],
1097 &frame_pix.pm_sides[SIDE_BOTTOM]);
1098 xfwmWindowShow (&c->sides[SIDE_BOTTOM],
1099 screen_info->corners[CORNER_BOTTOM_LEFT][state].width,
1100 frameHeight (c) - frameBottom (c), bottom_width, frameBottom (c),
1101 (requires_clearing | width_changed));
1103 if (!xfwmPixmapNone(&frame_pix.pm_sides[SIDE_TOP]))
1105 xfwmWindowSetBG (&c->sides[SIDE_TOP], &frame_pix.pm_sides[SIDE_TOP]);
1106 xfwmWindowShow (&c->sides[SIDE_TOP],
1107 screen_info->corners[CORNER_TOP_LEFT][state].width,
1108 0, top_width, frame_pix.pm_sides[SIDE_TOP].height,
1109 (requires_clearing | width_changed));
1111 else
1113 xfwmWindowHide (&c->sides[SIDE_TOP]);
1116 xfwmWindowShow (&c->corners[CORNER_TOP_LEFT], 0, 0,
1117 frameTopLeftWidth (c, state),
1118 screen_info->corners[CORNER_TOP_LEFT][state].height,
1119 requires_clearing);
1121 xfwmWindowShow (&c->corners[CORNER_TOP_RIGHT],
1122 frameWidth (c) - frameTopRightWidth (c, state),
1123 0, frameTopRightWidth (c, state),
1124 screen_info->corners[CORNER_TOP_RIGHT][state].height,
1125 requires_clearing);
1127 xfwmWindowShow (&c->corners[CORNER_BOTTOM_LEFT], 0,
1128 frameHeight (c) -
1129 screen_info->corners[CORNER_BOTTOM_LEFT][state].height,
1130 screen_info->corners[CORNER_BOTTOM_LEFT][state].width,
1131 screen_info->corners[CORNER_BOTTOM_LEFT][state].height,
1132 requires_clearing);
1134 xfwmWindowShow (&c->corners[CORNER_BOTTOM_RIGHT],
1135 frameWidth (c) -
1136 screen_info->corners[CORNER_BOTTOM_RIGHT][state].width,
1137 frameHeight (c) -
1138 screen_info->corners[CORNER_BOTTOM_RIGHT][state].height,
1139 screen_info->corners[CORNER_BOTTOM_RIGHT][state].width,
1140 screen_info->corners[CORNER_BOTTOM_RIGHT][state].height,
1141 requires_clearing);
1143 frameSetShape (c, state, &frame_pix, button_x);
1145 xfwmPixmapFree (&frame_pix.pm_title);
1146 xfwmPixmapFree (&frame_pix.pm_sides[SIDE_TOP]);
1147 xfwmPixmapFree (&frame_pix.pm_sides[SIDE_BOTTOM]);
1148 xfwmPixmapFree (&frame_pix.pm_sides[SIDE_LEFT]);
1149 xfwmPixmapFree (&frame_pix.pm_sides[SIDE_RIGHT]);
1151 else
1153 if (xfwmWindowVisible (&c->title))
1155 xfwmWindowHide (&c->title);
1157 for (i = 0; i < 4; i++)
1159 if (MYWINDOW_XWINDOW (c->sides[i]) && xfwmWindowVisible (&c->sides[i]))
1161 xfwmWindowHide (&c->sides[i]);
1164 for (i = 0; i < 4; i++)
1166 if (MYWINDOW_XWINDOW (c->corners[i]) && xfwmWindowVisible (&c->corners[i]))
1168 xfwmWindowHide (&c->corners[i]);
1171 for (i = 0; i < BUTTON_COUNT; i++)
1173 if (MYWINDOW_XWINDOW (c->buttons[i]) && xfwmWindowVisible (&c->buttons[i]))
1175 xfwmWindowHide (&c->buttons[i]);
1178 frameSetShape (c, 0, NULL, 0);
1182 static gboolean
1183 update_frame_idle_cb (gpointer data)
1185 Client *c;
1187 TRACE ("entering update_frame_idle_cb");
1189 c = (Client *) data;
1190 g_return_val_if_fail (c, FALSE);
1192 frameDraw (c, TRUE);
1193 c->frame_timeout_id = 0;
1195 return FALSE;
1198 void
1199 frameClearQueueDraw (Client * c)
1201 g_return_if_fail (c);
1203 TRACE ("entering frameClearQueueDraw for \"%s\" (0x%lx)", c->name, c->window);
1205 if (c->frame_timeout_id)
1207 g_source_remove (c->frame_timeout_id);
1208 c->frame_timeout_id = 0;
1212 void
1213 frameQueueDraw (Client * c)
1215 g_return_if_fail (c);
1217 TRACE ("entering frameQueueDraw for \"%s\" (0x%lx)", c->name, c->window);
1219 if (c->frame_timeout_id == 0)
1221 c->frame_timeout_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
1222 update_frame_idle_cb, c, NULL);