1 /*      $Id$
2 
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.
7 
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.
12 
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., Inc., 51 Franklin Street, Fifth Floor, Boston,
16         MA 02110-1301, USA.
17 
18 
19         oroborus - (c) 2001 Ken Lynch
20         xfwm4    - (c) 2002-2015 Olivier Fourdan
21 
22  */
23 
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27 
28 #include <glib.h>
29 #include <gdk/gdk.h>
30 #include <gdk/gdkx.h>
31 #include <pango/pango.h>
32 #include <libxfce4util/libxfce4util.h>
33 
34 #include "screen.h"
35 #include "client.h"
36 #include "settings.h"
37 #include "mywindow.h"
38 #include "focus.h"
39 #include "frame.h"
40 #include "compositor.h"
41 
42 typedef struct
43 {
44     xfwmPixmap pm_title;
45     xfwmPixmap pm_sides[SIDE_COUNT];
46 } FramePixmap;
47 
48 static int
frameDecorationBorderTop(ScreenInfo * screen_info)49 frameDecorationBorderTop (ScreenInfo *screen_info)
50 {
51     TRACE ("entering");
52 
53     g_return_val_if_fail (screen_info != NULL, 0);
54     return screen_info->params->frame_border_top;
55 }
56 
57 static int
frameBorderTop(Client * c)58 frameBorderTop (Client * c)
59 {
60     g_return_val_if_fail (c != NULL, 0);
61     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
62 
63     if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
64         && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN)
65         && FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
66         && (c->screen_info->params->borderless_maximize))
67     {
68         return frameDecorationBorderTop (c->screen_info);
69     }
70     return 0;
71 }
72 
73 static int
frameTopLeftWidth(Client * c,int state)74 frameTopLeftWidth (Client * c, int state)
75 {
76     g_return_val_if_fail (c != NULL, 0);
77     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
78 
79     if (FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
80         && c->screen_info->params->borderless_maximize)
81     {
82         return 0;
83     }
84     return c->screen_info->corners[CORNER_TOP_LEFT][state].width;
85 
86 }
87 
88 static int
frameTopRightWidth(Client * c,int state)89 frameTopRightWidth (Client * c, int state)
90 {
91     g_return_val_if_fail (c != NULL, 0);
92     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
93 
94     if (FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
95         && c->screen_info->params->borderless_maximize)
96     {
97         return 0;
98     }
99     return c->screen_info->corners[CORNER_TOP_RIGHT][state].width;
100 }
101 
102 static int
frameButtonOffset(Client * c)103 frameButtonOffset (Client *c)
104 {
105     g_return_val_if_fail (c != NULL, 0);
106     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
107 
108     if (FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
109         && c->screen_info->params->borderless_maximize)
110     {
111         return MAX (0, c->screen_info->params->maximized_offset);
112     }
113     return c->screen_info->params->button_offset;
114 }
115 
116 static void
frameFillTitlePixmap(Client * c,int state,int part,int x,int w,int h,xfwmPixmap * title_pm,xfwmPixmap * top_pm)117 frameFillTitlePixmap (Client * c, int state, int part, int x, int w, int h, xfwmPixmap * title_pm, xfwmPixmap * top_pm)
118 {
119     ScreenInfo *screen_info;
120 
121     g_return_if_fail (c);
122     g_return_if_fail (title_pm);
123     g_return_if_fail (top_pm);
124     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
125 
126     screen_info = c->screen_info;
127 
128     if (!xfwmPixmapNone(&screen_info->top[part][state]))
129     {
130         xfwmPixmapFill (&screen_info->top[part][state], top_pm, x, 0, w, h);
131     }
132     else
133     {
134         xfwmPixmapFill (&screen_info->title[part][state], top_pm, x, 0, w, h);
135     }
136     xfwmPixmapFill (&screen_info->title[part][state], title_pm, x, 0, w, frameDecorationTop(screen_info));
137 }
138 
139 static void
frameCreateTitlePixmap(Client * c,int state,int left,int right,xfwmPixmap * title_pm,xfwmPixmap * top_pm)140 frameCreateTitlePixmap (Client * c, int state, int left, int right, xfwmPixmap * title_pm, xfwmPixmap * top_pm)
141 {
142     ScreenInfo *screen_info;
143     cairo_surface_t *surface;
144     cairo_t *cr;
145     PangoLayout *layout;
146     PangoRectangle logical_rect;
147     int width, x, hoffset, w1, w2, w3, w4, w5, temp;
148     int voffset, title_x, title_y;
149     int title_height, top_height;
150 
151     g_return_if_fail (c);
152     g_return_if_fail (title_pm);
153     g_return_if_fail (top_pm);
154     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
155 
156     screen_info = c->screen_info;
157 
158     if (left > right)
159     {
160         temp = left;
161         left = right;
162         right = temp;
163     }
164 
165     width = frameWidth (c) - frameTopLeftWidth (c, state) - frameTopRightWidth (c, state);
166     if (width < 1)
167     {
168         return;
169     }
170 
171     if (left < frameTopLeftWidth (c, state))
172     {
173         left = frameTopLeftWidth (c, state);
174     }
175     if (right > frameWidth (c) - frameTopRightWidth (c, state))
176     {
177         right = frameWidth (c) - frameTopRightWidth (c, state);
178     }
179     if (right < frameTopLeftWidth (c, state))
180     {
181         right = frameTopLeftWidth (c, state);
182     }
183 
184     left = left - frameTopLeftWidth (c, state);
185     right = right - frameTopLeftWidth (c, state);
186 
187     x = 0;
188     hoffset = 0;
189 
190     if (state == ACTIVE)
191     {
192         voffset = screen_info->params->title_vertical_offset_active;
193     }
194     else
195     {
196         voffset = screen_info->params->title_vertical_offset_inactive;
197     }
198 
199     layout = gtk_widget_create_pango_layout (myScreenGetGtkWidget (screen_info), c->name);
200     pango_layout_set_font_description (layout, myScreenGetFontDescription (screen_info));
201     pango_layout_set_auto_dir (layout, FALSE);
202     if (screen_info->pango_attr_list != NULL)
203     {
204         pango_layout_set_attributes (layout, screen_info->pango_attr_list);
205     }
206     pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
207 
208     title_height = logical_rect.height;
209     title_y = voffset + (frameDecorationTop(screen_info) - title_height) / 2;
210     if (title_y + title_height > frameDecorationTop(screen_info))
211     {
212         title_y = MAX (0, frameDecorationTop(screen_info) - title_height);
213     }
214 
215     if (!xfwmPixmapNone(&screen_info->top[3][ACTIVE]))
216     {
217         top_height = screen_info->top[3][ACTIVE].height;
218     }
219     else if (frameDecorationBorderTop(c->screen_info) > 0)
220     {
221         top_height = frameDecorationBorderTop(c->screen_info);
222     }
223     else
224     {
225         top_height = frameDecorationTop(screen_info) / 10 + 1;
226         if (top_height > title_y - 1)
227         {
228              top_height = MAX (title_y - 1, 0);
229         }
230     }
231 
232     w1 = 0;
233     w2 = screen_info->title[TITLE_2][state].width;
234     w4 = screen_info->title[TITLE_4][state].width;
235 
236     if (screen_info->params->full_width_title)
237     {
238         w1 = left;
239         w5 = width - right;
240         w3 = width - w1 - w2 - w4 - w5;
241         if (w3 < 0)
242         {
243             w3 = 0;
244         }
245         switch (screen_info->params->title_alignment)
246         {
247             case ALIGN_LEFT:
248                 hoffset = screen_info->params->title_horizontal_offset;
249                 break;
250             case ALIGN_RIGHT:
251                 hoffset = w3 - logical_rect.width - screen_info->params->title_horizontal_offset;
252                 break;
253             case ALIGN_CENTER:
254                 hoffset = (w3 / 2) - (logical_rect.width / 2);
255                 break;
256         }
257         if (hoffset < screen_info->params->title_horizontal_offset)
258         {
259             hoffset = screen_info->params->title_horizontal_offset;
260         }
261     }
262     else
263     {
264         w3 = logical_rect.width + screen_info->params->title_shadow[state];
265         w5 = width;
266         if (w3 > width - w2 - w4)
267         {
268             w3 = width - w2 - w4;
269         }
270         if (w3 < 0)
271         {
272             w3 = 0;
273         }
274         switch (screen_info->params->title_alignment)
275         {
276             case ALIGN_LEFT:
277                 w1 = left + screen_info->params->title_horizontal_offset;
278                 break;
279             case ALIGN_RIGHT:
280                 w1 = right - w2 - w3 - w4 - screen_info->params->title_horizontal_offset;
281                 break;
282             case ALIGN_CENTER:
283                 w1 = left + ((right - left) / 2) - (w3 / 2) - w2;
284                 break;
285         }
286         if (w1 < left)
287         {
288             w1 = left;
289         }
290     }
291 
292     xfwmPixmapCreate (screen_info, top_pm, width, top_height);
293     xfwmPixmapCreate (screen_info, title_pm, width, frameDecorationTop(screen_info));
294 
295     surface = xfwmPixmapCreateSurface (title_pm, FALSE);
296     cr = cairo_create (surface);
297 
298     if (w1 > 0)
299     {
300         frameFillTitlePixmap (c, state, TITLE_1, x, w1, top_height, title_pm, top_pm);
301         x = x + w1;
302     }
303 
304     frameFillTitlePixmap (c, state, TITLE_2, x, w2, top_height, title_pm, top_pm);
305     x = x + w2;
306 
307     if (w3 > 0)
308     {
309         frameFillTitlePixmap (c, state, TITLE_3, x, w3, top_height, title_pm, top_pm);
310         title_x = hoffset + x;
311         cairo_translate (cr, title_x, title_y);
312         if (screen_info->params->title_shadow[state])
313         {
314             gdk_cairo_set_source_rgba (cr, &screen_info->title_shadow_colors[state]);
315             if (screen_info->params->title_shadow[state] == TITLE_SHADOW_UNDER)
316             {
317                 cairo_translate (cr, 1, 1);
318                 pango_cairo_show_layout (cr, layout);
319                 cairo_translate (cr, -1, -1);
320             }
321             else
322             {
323                 cairo_translate (cr, -1, 0);
324                 pango_cairo_show_layout (cr, layout);
325                 cairo_translate (cr, 1, -1);
326                 pango_cairo_show_layout (cr, layout);
327                 cairo_translate (cr, 1, 1);
328                 pango_cairo_show_layout (cr, layout);
329                 cairo_translate (cr, -1, 1);
330                 pango_cairo_show_layout (cr, layout);
331                 cairo_translate (cr, 0, -1);
332             }
333         }
334         gdk_cairo_set_source_rgba (cr, &screen_info->title_colors[state]);
335         pango_cairo_show_layout (cr, layout);
336         x = x + w3;
337     }
338 
339     if (x > right - w4)
340     {
341         x = right - w4;
342     }
343     frameFillTitlePixmap (c, state, TITLE_4, x, w4, top_height, title_pm, top_pm);
344     x = x + w4;
345 
346     if (w5 > 0)
347     {
348         frameFillTitlePixmap (c, state, TITLE_5, x, w5, top_height, title_pm, top_pm);
349     }
350     cairo_destroy (cr);
351     cairo_surface_destroy (surface);
352     g_object_unref (G_OBJECT (layout));
353 }
354 
355 static int
getButtonFromLetter(char chr,Client * c)356 getButtonFromLetter (char chr, Client * c)
357 {
358     int b;
359 
360     g_return_val_if_fail (c != NULL, -1);
361     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
362 
363     b = -1;
364     switch (chr)
365     {
366         case 'H':
367             if (CLIENT_CAN_HIDE_WINDOW (c))
368             {
369                 b = HIDE_BUTTON;
370             }
371             break;
372         case 'C':
373             if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_CLOSE))
374             {
375                 b = CLOSE_BUTTON;
376             }
377             break;
378         case 'M':
379             if (CLIENT_CAN_MAXIMIZE_WINDOW (c))
380             {
381                 b = MAXIMIZE_BUTTON;
382             }
383             break;
384         case 'S':
385             b = SHADE_BUTTON;
386             break;
387         case 'T':
388             if (FLAG_TEST_ALL (c->xfwm_flags, XFWM_FLAG_HAS_STICK | XFWM_FLAG_HAS_MENU))
389             {
390                 b = STICK_BUTTON;
391             }
392             break;
393         case 'O':
394             if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_MENU))
395             {
396                 b = MENU_BUTTON;
397             }
398             break;
399         case '|':
400             b = TITLE_SEPARATOR;
401             break;
402         default:
403             b = -1;
404     }
405     return b;
406 }
407 
408 static char
getLetterFromButton(int i,Client * c)409 getLetterFromButton (int i, Client * c)
410 {
411     char chr;
412 
413     g_return_val_if_fail (c != NULL, 0);
414     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
415 
416     chr = 0;
417     switch (i)
418     {
419         case HIDE_BUTTON:
420             if (CLIENT_CAN_HIDE_WINDOW (c))
421             {
422                 chr = 'H';
423             }
424             break;
425         case CLOSE_BUTTON:
426             if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_CLOSE))
427             {
428                 chr = 'C';
429             }
430             break;
431         case MAXIMIZE_BUTTON:
432             if (CLIENT_CAN_MAXIMIZE_WINDOW (c))
433             {
434                 chr = 'M';
435             }
436             break;
437         case SHADE_BUTTON:
438             chr = 'S';
439             break;
440         case STICK_BUTTON:
441             if (FLAG_TEST_ALL (c->xfwm_flags, XFWM_FLAG_HAS_STICK | XFWM_FLAG_HAS_MENU))
442             {
443                 chr = 'T';
444             }
445             break;
446         case MENU_BUTTON:
447             if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_MENU))
448             {
449                 chr = 'O';
450             }
451             break;
452         default:
453             chr = 0;
454     }
455     return chr;
456 }
457 
458 static void
frameSetShape(Client * c,int state,FramePixmap * frame_pix,int button_x[BUTTON_COUNT])459 frameSetShape (Client * c, int state, FramePixmap * frame_pix, int button_x[BUTTON_COUNT])
460 {
461     ScreenInfo *screen_info;
462     DisplayInfo *display_info;
463     XRectangle rect;
464     xfwmPixmap *my_pixmap;
465     int i;
466 
467     g_return_if_fail (c != NULL);
468     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
469 
470     screen_info = c->screen_info;
471     display_info = screen_info->display_info;
472 
473     if (!display_info->have_shape)
474     {
475         return;
476     }
477 
478     myDisplayErrorTrapPush (display_info);
479 
480     if (screen_info->shape_win == None)
481     {
482         screen_info->shape_win = XCreateSimpleWindow (display_info->dpy, screen_info->xroot, 0, 0, frameWidth (c), frameHeight (c), 0, 0, 0);
483     }
484     else
485     {
486         XResizeWindow (display_info->dpy, screen_info->shape_win, frameWidth (c), frameHeight (c));
487     }
488 
489     if (FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
490     {
491         rect.x = 0;
492         rect.y = 0;
493         rect.width  = frameWidth (c);
494         rect.height = frameHeight (c);
495         XShapeCombineRectangles (display_info->dpy, screen_info->shape_win, ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, Unsorted);
496     }
497     else if (!FLAG_TEST (c->flags, CLIENT_FLAG_HAS_SHAPE))
498     {
499         rect.x = frameLeft (c);
500         rect.y = frameTop (c);
501         rect.width  = c->width;
502         rect.height = c->height;
503         XShapeCombineRectangles (display_info->dpy, screen_info->shape_win, ShapeBounding, 0, 0, &rect, 1, ShapeSet, Unsorted);
504     }
505     else
506     {
507         XShapeCombineShape (display_info->dpy, screen_info->shape_win, ShapeBounding, frameLeft (c),
508                             frameTop (c), c->window, ShapeBounding, ShapeSet);
509     }
510     if (frame_pix)
511     {
512         XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->title), ShapeBounding,
513                            0, 0, frame_pix->pm_title.mask, ShapeSet);
514         if (!FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
515         {
516             if (xfwmWindowVisible (&c->sides[SIDE_LEFT]))
517             {
518                 XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->sides[SIDE_LEFT]),
519                                    ShapeBounding, 0, 0, frame_pix->pm_sides[SIDE_LEFT].mask, ShapeSet);
520             }
521 
522             if (xfwmWindowVisible (&c->sides[SIDE_RIGHT]))
523             {
524                 XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->sides[SIDE_RIGHT]),
525                                    ShapeBounding, 0, 0, frame_pix->pm_sides[SIDE_RIGHT].mask, ShapeSet);
526             }
527         }
528 
529         if (xfwmWindowVisible (&c->sides[SIDE_BOTTOM]))
530         {
531             XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->sides[SIDE_BOTTOM]),
532                                ShapeBounding, 0, 0, frame_pix->pm_sides[SIDE_BOTTOM].mask, ShapeSet);
533         }
534 
535         if (xfwmWindowVisible (&c->sides[SIDE_TOP]))
536         {
537             XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->sides[SIDE_TOP]),
538                                ShapeBounding, 0, 0, frame_pix->pm_sides[SIDE_TOP].mask, ShapeSet);
539         }
540 
541         if (xfwmWindowVisible (&c->corners[CORNER_BOTTOM_LEFT]))
542         {
543             XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->corners[CORNER_BOTTOM_LEFT]),
544                                ShapeBounding, 0, 0, screen_info->corners[CORNER_BOTTOM_LEFT][state].mask, ShapeSet);
545         }
546 
547         if (xfwmWindowVisible (&c->corners[CORNER_BOTTOM_RIGHT]))
548         {
549             XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->corners[CORNER_BOTTOM_RIGHT]),
550                                ShapeBounding, 0, 0, screen_info->corners[CORNER_BOTTOM_RIGHT][state].mask, ShapeSet);
551         }
552 
553         if (xfwmWindowVisible (&c->corners[CORNER_TOP_LEFT]))
554         {
555             XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->corners[CORNER_TOP_LEFT]),
556                                ShapeBounding, 0, 0, screen_info->corners[CORNER_TOP_LEFT][state].mask, ShapeSet);
557         }
558 
559         if (xfwmWindowVisible (&c->corners[CORNER_TOP_RIGHT]))
560         {
561             XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->corners[CORNER_TOP_RIGHT]),
562                                ShapeBounding, 0, 0, screen_info->corners[CORNER_TOP_RIGHT][state].mask, ShapeSet);
563         }
564 
565         for (i = 0; i < BUTTON_COUNT; i++)
566         {
567             if (xfwmWindowVisible (&c->buttons[i]))
568             {
569                 my_pixmap = clientGetButtonPixmap (c, i, clientGetButtonState (c, i, state));
570                 XShapeCombineMask (display_info->dpy, MYWINDOW_XWINDOW (c->buttons[i]),
571                                    ShapeBounding, 0, 0, my_pixmap->mask, ShapeSet);
572             }
573         }
574 
575         if (xfwmWindowVisible (&c->corners[CORNER_TOP_LEFT]) &&
576             (screen_info->corners[CORNER_TOP_LEFT][state].height > frameHeight (c) - frameBottom (c) + 1))
577         {
578             rect.x      = 0;
579             rect.y      = frameHeight (c) - frameBottom (c) + 1;
580             rect.width  = frameTopLeftWidth (c, state);
581             rect.height = screen_info->corners[CORNER_TOP_LEFT][state].height
582                            - (frameHeight (c) - frameBottom (c) + 1);
583             XShapeCombineRectangles (display_info->dpy, MYWINDOW_XWINDOW (c->corners[CORNER_TOP_LEFT]),
584                                      ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, 0);
585         }
586 
587         if (xfwmWindowVisible (&c->corners[CORNER_TOP_RIGHT]) &&
588             (screen_info->corners[CORNER_TOP_RIGHT][state].height > frameHeight (c) - frameBottom (c) + 1))
589         {
590             rect.x      = 0;
591             rect.y      = frameHeight (c) - frameBottom (c) + 1;
592             rect.width  = frameTopRightWidth (c, state);
593             rect.height = screen_info->corners[CORNER_TOP_RIGHT][state].height
594                            - (frameHeight (c) - frameBottom (c) + 1);
595             XShapeCombineRectangles (display_info->dpy, MYWINDOW_XWINDOW (c->corners[CORNER_TOP_RIGHT]),
596                                      ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, 0);
597         }
598 
599         if (xfwmWindowVisible (&c->corners[CORNER_BOTTOM_LEFT]) &&
600             (screen_info->corners[CORNER_BOTTOM_LEFT][state].height > frameHeight (c) - frameTop (c) + 1))
601         {
602             rect.x      = 0;
603             rect.y      = 0;
604             rect.width  = screen_info->corners[CORNER_BOTTOM_LEFT][state].width;
605             rect.height = screen_info->corners[CORNER_BOTTOM_LEFT][state].height
606                            - (frameHeight (c) - frameTop (c) + 1);
607             XShapeCombineRectangles (display_info->dpy, MYWINDOW_XWINDOW (c->corners[CORNER_BOTTOM_LEFT]),
608                                      ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, 0);
609         }
610 
611         if (xfwmWindowVisible (&c->corners[CORNER_BOTTOM_RIGHT]) &&
612             (screen_info->corners[CORNER_BOTTOM_RIGHT][state].height > frameHeight (c) - frameTop (c) + 1))
613         {
614             rect.x      = 0;
615             rect.y      = 0;
616             rect.width  = screen_info->corners[CORNER_BOTTOM_RIGHT][state].width;
617             rect.height = screen_info->corners[CORNER_BOTTOM_RIGHT][state].height
618                            - (frameHeight (c) - frameTop (c) + 1);
619             XShapeCombineRectangles (display_info->dpy, MYWINDOW_XWINDOW (c->corners[CORNER_BOTTOM_RIGHT]),
620                                      ShapeBounding, 0, 0, &rect, 1, ShapeSubtract, 0);
621         }
622 
623         if (!FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
624         {
625             if (xfwmWindowVisible (&c->sides[SIDE_LEFT]))
626             {
627                 XShapeCombineShape (display_info->dpy, screen_info->shape_win, ShapeBounding, 0, frameTop (c),
628                                     MYWINDOW_XWINDOW (c->sides[SIDE_LEFT]), ShapeBounding, ShapeUnion);
629             }
630 
631             if (xfwmWindowVisible (&c->sides[SIDE_RIGHT]))
632             {
633                 XShapeCombineShape (display_info->dpy, screen_info->shape_win, ShapeBounding, frameWidth (c) - frameRight (c), frameTop (c),
634                                     MYWINDOW_XWINDOW (c->sides[SIDE_RIGHT]), ShapeBounding, ShapeUnion);
635             }
636         }
637 
638         if (xfwmWindowVisible (&c->title))
639         {
640             XShapeCombineShape (display_info->dpy, screen_info->shape_win, ShapeBounding,
641                                 frameTopLeftWidth (c, state), 0,
642                                 MYWINDOW_XWINDOW (c->title), ShapeBounding, ShapeUnion);
643         }
644 
645         if (xfwmWindowVisible (&c->corners[CORNER_TOP_LEFT]))
646         {
647 
648             XShapeCombineShape (display_info->dpy, screen_info->shape_win, ShapeBounding, 0, 0,
649                                 MYWINDOW_XWINDOW (c->corners[CORNER_TOP_LEFT]), ShapeBounding, ShapeUnion);
650         }
651 
652         if (xfwmWindowVisible (&c->sides[SIDE_BOTTOM]))
653         {
654             XShapeCombineShape (display_info->dpy, screen_info->shape_win, ShapeBounding,
655                                 screen_info->corners[CORNER_BOTTOM_LEFT][state].width,
656                                 frameHeight (c) - frameBottom (c),
657                                 MYWINDOW_XWINDOW (c->sides[SIDE_BOTTOM]), ShapeBounding, ShapeUnion);
658         }
659 
660         if (xfwmWindowVisible (&c->sides[SIDE_TOP]))
661         {
662             XShapeCombineShape (display_info->dpy, screen_info->shape_win, ShapeBounding,
663                                 screen_info->corners[CORNER_BOTTOM_LEFT][state].width,
664                                 frameTop (c) - frameBottom (c),
665                                 MYWINDOW_XWINDOW (c->sides[SIDE_TOP]), ShapeBounding, ShapeUnion);
666         }
667 
668         if (xfwmWindowVisible (&c->corners[CORNER_BOTTOM_LEFT]))
669         {
670             XShapeCombineShape (display_info->dpy, screen_info->shape_win, ShapeBounding, 0,
671                                 frameHeight (c) - screen_info->corners[CORNER_BOTTOM_LEFT][state].height,
672                                 MYWINDOW_XWINDOW (c->corners[CORNER_BOTTOM_LEFT]), ShapeBounding, ShapeUnion);
673         }
674 
675         if (xfwmWindowVisible (&c->corners[CORNER_BOTTOM_RIGHT]))
676         {
677             XShapeCombineShape (display_info->dpy, screen_info->shape_win, ShapeBounding,
678                                 frameWidth (c) - screen_info->corners[CORNER_BOTTOM_RIGHT][state].width,
679                                 frameHeight (c) - screen_info->corners[CORNER_BOTTOM_RIGHT][state].height,
680                                 MYWINDOW_XWINDOW (c->corners[CORNER_BOTTOM_RIGHT]), ShapeBounding, ShapeUnion);
681         }
682 
683         if (xfwmWindowVisible (&c->corners[CORNER_TOP_RIGHT]))
684         {
685             XShapeCombineShape (display_info->dpy, screen_info->shape_win, ShapeBounding,
686                                 frameWidth (c) - frameTopRightWidth (c, state),
687                                 0, MYWINDOW_XWINDOW (c->corners[CORNER_TOP_RIGHT]), ShapeBounding, ShapeUnion);
688         }
689 
690         for (i = 0; i < BUTTON_COUNT; i++)
691         {
692             if (xfwmWindowVisible (&c->buttons[i]))
693             {
694                 XShapeCombineShape (display_info->dpy, screen_info->shape_win, ShapeBounding, button_x[i],
695                                     (frameTop (c) - screen_info->buttons[i][state].height + 1) / 2,
696                                     MYWINDOW_XWINDOW (c->buttons[i]), ShapeBounding, ShapeUnion);
697             }
698         }
699     }
700     rect.x = 0;
701     rect.y = 0;
702     rect.width  = frameWidth (c);
703     rect.height = frameHeight (c);
704     XShapeCombineRectangles (display_info->dpy, screen_info->shape_win, ShapeBounding, 0, 0, &rect, 1, ShapeIntersect, Unsorted);
705     XShapeCombineShape (display_info->dpy, c->frame, ShapeBounding, 0, 0, screen_info->shape_win, ShapeBounding, ShapeSet);
706 
707     myDisplayErrorTrapPopIgnored (display_info);
708 }
709 
710 static void
frameDrawWin(Client * c)711 frameDrawWin (Client * c)
712 {
713     ScreenInfo *screen_info;
714     DisplayInfo *display_info;
715     FramePixmap frame_pix;
716     xfwmPixmap *my_pixmap;
717     gint state, x, button, left, right;
718     gint top_width, bottom_width, left_height, right_height;
719     gint button_x[BUTTON_COUNT];
720     guint i, j;
721     gboolean requires_clearing;
722     gboolean width_changed;
723     gboolean height_changed;
724 
725     g_return_if_fail (c != NULL);
726     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
727 
728     frameClearQueueDraw (c);
729 
730     screen_info = c->screen_info;
731     display_info = screen_info->display_info;
732 
733     requires_clearing = FALSE;
734     width_changed = FALSE;
735     height_changed = FALSE;
736     state = ACTIVE;
737 
738     myDisplayErrorTrapPush (display_info);
739 
740     if (c != clientGetFocus ())
741     {
742         TRACE ("\"%s\" is not the active window", c->name);
743         if (FLAG_TEST (c->wm_flags, WM_FLAG_URGENT))
744         {
745             if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_SEEN_ACTIVE))
746             {
747                 state = ACTIVE;
748             }
749             else
750             {
751                 state = INACTIVE;
752             }
753         }
754         else
755         {
756             state = INACTIVE;
757         }
758     }
759 
760     if ((state == INACTIVE)
761         && FLAG_TEST(c->xfwm_flags, XFWM_FLAG_DRAW_ACTIVE | XFWM_FLAG_FIRST_MAP))
762     {
763         requires_clearing = TRUE;
764         FLAG_UNSET (c->xfwm_flags,  XFWM_FLAG_DRAW_ACTIVE);
765     }
766     else if ((state == ACTIVE)
767              && (!FLAG_TEST (c->xfwm_flags, XFWM_FLAG_DRAW_ACTIVE)
768                  || FLAG_TEST (c->xfwm_flags, XFWM_FLAG_FIRST_MAP)))
769     {
770         requires_clearing = TRUE;
771         FLAG_SET (c->xfwm_flags,  XFWM_FLAG_DRAW_ACTIVE);
772     }
773     /* Flag clearance */
774     FLAG_UNSET (c->xfwm_flags,  XFWM_FLAG_FIRST_MAP);
775 
776     /* Cache mgmt */
777     if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_NEEDS_REDRAW))
778     {
779         FLAG_UNSET (c->xfwm_flags, XFWM_FLAG_NEEDS_REDRAW);
780         width_changed = TRUE;
781         height_changed = TRUE;
782         requires_clearing = TRUE;
783     }
784     else
785     {
786         if (c->frame_cache_width != c->width)
787         {
788             width_changed = TRUE;
789             c->frame_cache_width = c->width;
790         }
791         if (c->frame_cache_height != c->height)
792         {
793             height_changed = TRUE;
794             c->frame_cache_height = c->height;
795         }
796     }
797 
798     if (CLIENT_HAS_FRAME (c))
799     {
800         /* First, hide the buttons that we don't have... */
801         for (i = 0; i < BUTTON_COUNT; i++)
802         {
803             char b = getLetterFromButton (i, c);
804             if ((!b) || !strchr (screen_info->params->button_layout, b))
805             {
806                 xfwmWindowHide (&c->buttons[i]);
807             }
808         }
809 
810         /* Then, show the ones that we do have on left... */
811         x = frameLeft (c) + frameButtonOffset (c);
812         if (x < 0)
813         {
814             x = 0;
815         }
816         right = frameWidth (c) - frameRight (c) - frameButtonOffset (c);
817         for (i = 0; i < strlen (screen_info->params->button_layout); i++)
818         {
819             button = getButtonFromLetter (screen_info->params->button_layout[i], c);
820             if (button == TITLE_SEPARATOR)
821             {
822                 break;
823             }
824             else if (button >= 0)
825             {
826                 if (x + screen_info->buttons[button][state].width + screen_info->params->button_spacing < right)
827                 {
828                     my_pixmap = clientGetButtonPixmap (c, button, clientGetButtonState (c, button, state));
829                     if (!xfwmPixmapNone(my_pixmap))
830                     {
831                         xfwmWindowSetBG (&c->buttons[button], my_pixmap);
832                     }
833                     xfwmWindowShow (&c->buttons[button], x,
834                         ((frameDecorationTop(screen_info) - screen_info->buttons[button][state].height + 1) / 2) - frameBorderTop (c),
835                         screen_info->buttons[button][state].width,
836                         screen_info->buttons[button][state].height, TRUE);
837                     button_x[button] = x;
838                     x = x + screen_info->buttons[button][state].width +
839                         screen_info->params->button_spacing;
840                 }
841                 else
842                 {
843                     xfwmWindowHide (&c->buttons[button]);
844                 }
845             }
846         }
847         left = x + screen_info->params->button_spacing;
848 
849         /* and those that we do have on right... */
850         x = frameWidth (c) - frameRight (c) + screen_info->params->button_spacing -
851             frameButtonOffset (c);
852         for (j = strlen (screen_info->params->button_layout) - 1; j >= i; j--)
853         {
854             button = getButtonFromLetter (screen_info->params->button_layout[j], c);
855             if (button == TITLE_SEPARATOR)
856             {
857                 break;
858             }
859             else if (button >= 0)
860             {
861                 if (x - screen_info->buttons[button][state].width - screen_info->params->button_spacing > left)
862                 {
863                     my_pixmap = clientGetButtonPixmap (c, button, clientGetButtonState (c, button, state));
864                     if (!xfwmPixmapNone(my_pixmap))
865                     {
866                         xfwmWindowSetBG (&c->buttons[button], my_pixmap);
867                     }
868                     x = x - screen_info->buttons[button][state].width -
869                         screen_info->params->button_spacing;
870                     xfwmWindowShow (&c->buttons[button], x,
871                         ((frameDecorationTop(screen_info) - screen_info->buttons[button][state].height + 1) / 2) - frameBorderTop (c),
872                         screen_info->buttons[button][state].width,
873                         screen_info->buttons[button][state].height, TRUE);
874                     button_x[button] = x;
875                 }
876                 else
877                 {
878                     xfwmWindowHide (&c->buttons[button]);
879                 }
880             }
881         }
882         left = left - 2 * screen_info->params->button_spacing;
883         right = x;
884 
885         top_width = frameWidth (c) - frameTopLeftWidth (c, state) - frameTopRightWidth (c, state);
886         bottom_width = frameWidth (c) -
887             screen_info->corners[CORNER_BOTTOM_LEFT][state].width -
888             screen_info->corners[CORNER_BOTTOM_RIGHT][state].width;
889         left_height = frameHeight (c) - frameTop (c) -
890             screen_info->corners[CORNER_BOTTOM_LEFT][state].height;
891         right_height = frameHeight (c) - frameTop (c) -
892             screen_info->corners[CORNER_BOTTOM_RIGHT][state].height;
893 
894         xfwmPixmapInit (screen_info, &frame_pix.pm_title);
895         xfwmPixmapInit (screen_info, &frame_pix.pm_sides[SIDE_TOP]);
896         xfwmPixmapInit (screen_info, &frame_pix.pm_sides[SIDE_BOTTOM]);
897         xfwmPixmapInit (screen_info, &frame_pix.pm_sides[SIDE_LEFT]);
898         xfwmPixmapInit (screen_info, &frame_pix.pm_sides[SIDE_RIGHT]);
899 
900         /* The title is always visible */
901         frameCreateTitlePixmap (c, state, left, right, &frame_pix.pm_title, &frame_pix.pm_sides[SIDE_TOP]);
902         xfwmWindowSetBG (&c->title, &frame_pix.pm_title);
903         xfwmWindowShow (&c->title,
904             frameTopLeftWidth (c, state), 0 - frameBorderTop (c), top_width,
905             frameDecorationTop(screen_info), (requires_clearing | width_changed));
906 
907         /* Corners are never resized, we need to update them separately */
908         if (requires_clearing)
909         {
910             xfwmWindowSetBG (&c->corners[CORNER_TOP_LEFT],
911                 &screen_info->corners[CORNER_TOP_LEFT][state]);
912             xfwmWindowSetBG (&c->corners[CORNER_TOP_RIGHT],
913                 &screen_info->corners[CORNER_TOP_RIGHT][state]);
914             xfwmWindowSetBG (&c->corners[CORNER_BOTTOM_LEFT],
915                 &screen_info->corners[CORNER_BOTTOM_LEFT][state]);
916             xfwmWindowSetBG (&c->corners[CORNER_BOTTOM_RIGHT],
917                 &screen_info->corners[CORNER_BOTTOM_RIGHT][state]);
918         }
919 
920         if (FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
921             && (c->screen_info->params->borderless_maximize))
922         {
923             xfwmWindowHide (&c->sides[SIDE_LEFT]);
924             xfwmWindowHide (&c->sides[SIDE_RIGHT]);
925             xfwmWindowHide (&c->sides[SIDE_BOTTOM]);
926             xfwmWindowHide (&c->sides[SIDE_TOP]);
927             xfwmWindowHide (&c->corners[CORNER_TOP_LEFT]);
928             xfwmWindowHide (&c->corners[CORNER_TOP_RIGHT]);
929             xfwmWindowHide (&c->corners[CORNER_BOTTOM_LEFT]);
930             xfwmWindowHide (&c->corners[CORNER_BOTTOM_RIGHT]);
931         }
932         else
933         {
934             if (FLAG_TEST (c->flags, CLIENT_FLAG_SHADED))
935             {
936                 xfwmWindowHide (&c->sides[SIDE_LEFT]);
937                 xfwmWindowHide (&c->sides[SIDE_RIGHT]);
938             }
939             else
940             {
941                 xfwmPixmapCreate (screen_info, &frame_pix.pm_sides[SIDE_LEFT],
942                     frameLeft (c), left_height);
943                 xfwmPixmapFill (&screen_info->sides[SIDE_LEFT][state],
944                     &frame_pix.pm_sides[SIDE_LEFT],
945                     0, 0, frameLeft (c), left_height);
946                 xfwmWindowSetBG (&c->sides[SIDE_LEFT],
947                     &frame_pix.pm_sides[SIDE_LEFT]);
948                 xfwmWindowShow (&c->sides[SIDE_LEFT], 0, frameTop (c),
949                     frameLeft (c), left_height, (requires_clearing | height_changed));
950 
951                 xfwmPixmapCreate (screen_info, &frame_pix.pm_sides[SIDE_RIGHT],
952                     frameRight (c), right_height);
953                 xfwmPixmapFill (&screen_info->sides[SIDE_RIGHT][state],
954                     &frame_pix.pm_sides[SIDE_RIGHT],
955                     0, 0, frameRight (c), right_height);
956                 xfwmWindowSetBG (&c->sides[SIDE_RIGHT],
957                     &frame_pix.pm_sides[SIDE_RIGHT]);
958                 xfwmWindowShow (&c->sides[SIDE_RIGHT],
959                     frameWidth (c) - frameRight (c), frameTop (c), frameRight (c),
960                     right_height, (requires_clearing | height_changed));
961             }
962 
963             xfwmPixmapCreate (screen_info, &frame_pix.pm_sides[SIDE_BOTTOM],
964                 bottom_width, frameBottom (c));
965             xfwmPixmapFill (&screen_info->sides[SIDE_BOTTOM][state],
966                 &frame_pix.pm_sides[SIDE_BOTTOM],
967                 0, 0, bottom_width, frameBottom (c));
968             xfwmWindowSetBG (&c->sides[SIDE_BOTTOM],
969                 &frame_pix.pm_sides[SIDE_BOTTOM]);
970             xfwmWindowShow (&c->sides[SIDE_BOTTOM],
971                 screen_info->corners[CORNER_BOTTOM_LEFT][state].width,
972                 frameHeight (c) - frameBottom (c), bottom_width, frameBottom (c),
973                 (requires_clearing | width_changed));
974 
975             if (!xfwmPixmapNone(&frame_pix.pm_sides[SIDE_TOP]))
976             {
977                 xfwmWindowSetBG (&c->sides[SIDE_TOP], &frame_pix.pm_sides[SIDE_TOP]);
978                 xfwmWindowShow (&c->sides[SIDE_TOP],
979                     screen_info->corners[CORNER_TOP_LEFT][state].width,
980                     0, top_width, frame_pix.pm_sides[SIDE_TOP].height,
981                     (requires_clearing | width_changed));
982             }
983             else
984             {
985                 xfwmWindowHide (&c->sides[SIDE_TOP]);
986             }
987 
988             xfwmWindowShow (&c->corners[CORNER_TOP_LEFT], 0, 0,
989                 frameTopLeftWidth (c, state),
990                 screen_info->corners[CORNER_TOP_LEFT][state].height,
991                 requires_clearing);
992 
993             xfwmWindowShow (&c->corners[CORNER_TOP_RIGHT],
994                 frameWidth (c) - frameTopRightWidth (c, state),
995                 0, frameTopRightWidth (c, state),
996                 screen_info->corners[CORNER_TOP_RIGHT][state].height,
997                 requires_clearing);
998 
999             xfwmWindowShow (&c->corners[CORNER_BOTTOM_LEFT], 0,
1000                 frameHeight (c) -
1001                 screen_info->corners[CORNER_BOTTOM_LEFT][state].height,
1002                 screen_info->corners[CORNER_BOTTOM_LEFT][state].width,
1003                 screen_info->corners[CORNER_BOTTOM_LEFT][state].height,
1004                 requires_clearing);
1005 
1006             xfwmWindowShow (&c->corners[CORNER_BOTTOM_RIGHT],
1007                 frameWidth (c) -
1008                 screen_info->corners[CORNER_BOTTOM_RIGHT][state].width,
1009                 frameHeight (c) -
1010                 screen_info->corners[CORNER_BOTTOM_RIGHT][state].height,
1011                 screen_info->corners[CORNER_BOTTOM_RIGHT][state].width,
1012                 screen_info->corners[CORNER_BOTTOM_RIGHT][state].height,
1013                 requires_clearing);
1014         }
1015         frameSetShape (c, state, &frame_pix, button_x);
1016 
1017         xfwmPixmapFree (&frame_pix.pm_title);
1018         xfwmPixmapFree (&frame_pix.pm_sides[SIDE_TOP]);
1019         xfwmPixmapFree (&frame_pix.pm_sides[SIDE_BOTTOM]);
1020         xfwmPixmapFree (&frame_pix.pm_sides[SIDE_LEFT]);
1021         xfwmPixmapFree (&frame_pix.pm_sides[SIDE_RIGHT]);
1022     }
1023     else
1024     {
1025         if (xfwmWindowVisible (&c->title))
1026         {
1027             xfwmWindowHide (&c->title);
1028         }
1029         for (i = 0; i < 4; i++)
1030         {
1031             if (MYWINDOW_XWINDOW (c->sides[i]) && xfwmWindowVisible (&c->sides[i]))
1032             {
1033                 xfwmWindowHide (&c->sides[i]);
1034             }
1035         }
1036         for (i = 0; i < 4; i++)
1037         {
1038             if (MYWINDOW_XWINDOW (c->corners[i]) && xfwmWindowVisible (&c->corners[i]))
1039             {
1040                 xfwmWindowHide (&c->corners[i]);
1041             }
1042         }
1043         for (i = 0; i < BUTTON_COUNT; i++)
1044         {
1045             if (MYWINDOW_XWINDOW (c->buttons[i]) && xfwmWindowVisible (&c->buttons[i]))
1046             {
1047                 xfwmWindowHide (&c->buttons[i]);
1048             }
1049         }
1050         frameSetShape (c, 0, NULL, 0);
1051     }
1052 
1053     myDisplayErrorTrapPopIgnored (display_info);
1054 }
1055 
1056 static gboolean
update_frame_idle_cb(gpointer data)1057 update_frame_idle_cb (gpointer data)
1058 {
1059     Client *c;
1060 
1061     c = (Client *) data;
1062     g_return_val_if_fail (c, FALSE);
1063     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1064 
1065     frameDrawWin (c);
1066     c->frame_timeout_id = 0;
1067 
1068     return (FALSE);
1069 }
1070 
1071 int
frameDecorationLeft(ScreenInfo * screen_info)1072 frameDecorationLeft (ScreenInfo *screen_info)
1073 {
1074     TRACE ("entering");
1075 
1076     g_return_val_if_fail (screen_info != NULL, 0);
1077     return screen_info->sides[SIDE_LEFT][ACTIVE].width;
1078 }
1079 
1080 int
frameDecorationRight(ScreenInfo * screen_info)1081 frameDecorationRight (ScreenInfo *screen_info)
1082 {
1083     TRACE ("entering");
1084 
1085     g_return_val_if_fail (screen_info != NULL, 0);
1086     return screen_info->sides[SIDE_RIGHT][ACTIVE].width;
1087 }
1088 
1089 int
frameDecorationTop(ScreenInfo * screen_info)1090 frameDecorationTop (ScreenInfo *screen_info)
1091 {
1092     TRACE ("entering");
1093 
1094     g_return_val_if_fail (screen_info != NULL, 0);
1095     return screen_info->title[TITLE_3][ACTIVE].height;
1096 }
1097 
1098 int
frameDecorationBottom(ScreenInfo * screen_info)1099 frameDecorationBottom (ScreenInfo *screen_info)
1100 {
1101     TRACE ("entering");
1102 
1103     g_return_val_if_fail (screen_info != NULL, 0);
1104     return screen_info->sides[SIDE_BOTTOM][ACTIVE].height;
1105 }
1106 
1107 int
frameLeft(Client * c)1108 frameLeft (Client * c)
1109 {
1110     g_return_val_if_fail (c != NULL, 0);
1111     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1112 
1113     if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
1114         && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN)
1115         && (!FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
1116             || !(c->screen_info->params->borderless_maximize)))
1117     {
1118         return c->screen_info->sides[SIDE_LEFT][ACTIVE].width;
1119     }
1120     return 0;
1121 }
1122 
1123 int
frameRight(Client * c)1124 frameRight (Client * c)
1125 {
1126     g_return_val_if_fail (c != NULL, 0);
1127     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1128 
1129     if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
1130         && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN)
1131         && (!FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
1132             || !(c->screen_info->params->borderless_maximize)))
1133     {
1134         return c->screen_info->sides[SIDE_RIGHT][ACTIVE].width;
1135     }
1136     return 0;
1137 }
1138 
1139 int
frameTop(Client * c)1140 frameTop (Client * c)
1141 {
1142     g_return_val_if_fail (c != NULL, 0);
1143     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1144 
1145     if (CLIENT_HAS_FRAME (c))
1146     {
1147         return frameDecorationTop(c->screen_info) - frameBorderTop (c);
1148     }
1149     return 0;
1150 }
1151 
1152 int
frameBottom(Client * c)1153 frameBottom (Client * c)
1154 {
1155     g_return_val_if_fail (c != NULL, 0);
1156     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1157 
1158     if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
1159         && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN)
1160         && (!FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
1161             || !(c->screen_info->params->borderless_maximize)))
1162     {
1163         return c->screen_info->sides[SIDE_BOTTOM][ACTIVE].height;
1164     }
1165     return 0;
1166 }
1167 
1168 int
frameX(Client * c)1169 frameX (Client * c)
1170 {
1171     g_return_val_if_fail (c != NULL, 0);
1172     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1173 
1174     if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
1175         && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN)
1176         && (!FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
1177             || !(c->screen_info->params->borderless_maximize)))
1178     {
1179         return c->x - frameLeft (c);
1180     }
1181     return c->x;
1182 }
1183 
1184 int
frameY(Client * c)1185 frameY (Client * c)
1186 {
1187     g_return_val_if_fail (c != NULL, 0);
1188     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1189 
1190     if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
1191          && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
1192     {
1193         return c->y - frameTop (c);
1194     }
1195     return c->y;
1196 }
1197 
1198 int
frameWidth(Client * c)1199 frameWidth (Client * c)
1200 {
1201     g_return_val_if_fail (c != NULL, 0);
1202     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1203 
1204     if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
1205         && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN)
1206         && (!FLAG_TEST_ALL (c->flags, CLIENT_FLAG_MAXIMIZED)
1207             || !(c->screen_info->params->borderless_maximize)))
1208     {
1209         return c->width + frameLeft (c) + frameRight (c);
1210     }
1211     return c->width;
1212 }
1213 
1214 int
frameHeight(Client * c)1215 frameHeight (Client * c)
1216 {
1217     g_return_val_if_fail (c != NULL, 0);
1218     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1219 
1220     if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
1221         && FLAG_TEST (c->flags, CLIENT_FLAG_SHADED)
1222         && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
1223     {
1224         return frameTop (c) + frameBottom (c);
1225     }
1226     else if (FLAG_TEST (c->xfwm_flags, XFWM_FLAG_HAS_BORDER)
1227              && !FLAG_TEST (c->flags, CLIENT_FLAG_FULLSCREEN))
1228     {
1229         return c->height + frameTop (c) + frameBottom (c);
1230     }
1231     return c->height;
1232 }
1233 
1234 int
frameExtentLeft(Client * c)1235 frameExtentLeft (Client * c)
1236 {
1237     g_return_val_if_fail (c != NULL, 0);
1238     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1239 
1240     if (FLAG_TEST (c->flags, CLIENT_FLAG_HAS_FRAME_EXTENTS))
1241     {
1242         return -c->frame_extents[SIDE_LEFT];
1243     }
1244     return frameLeft(c);
1245 }
1246 
1247 int
frameExtentRight(Client * c)1248 frameExtentRight (Client * c)
1249 {
1250     g_return_val_if_fail (c != NULL, 0);
1251     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1252 
1253     if (FLAG_TEST (c->flags, CLIENT_FLAG_HAS_FRAME_EXTENTS))
1254     {
1255         return -c->frame_extents[SIDE_RIGHT];
1256     }
1257     return frameRight(c);
1258 }
1259 
1260 int
frameExtentTop(Client * c)1261 frameExtentTop (Client * c)
1262 {
1263     g_return_val_if_fail (c != NULL, 0);
1264     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1265 
1266     if (FLAG_TEST (c->flags, CLIENT_FLAG_HAS_FRAME_EXTENTS))
1267     {
1268         return -c->frame_extents[SIDE_TOP];
1269     }
1270     return frameTop(c);
1271 }
1272 
1273 int
frameExtentBottom(Client * c)1274 frameExtentBottom (Client * c)
1275 {
1276     g_return_val_if_fail (c != NULL, 0);
1277     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1278 
1279     if (FLAG_TEST (c->flags, CLIENT_FLAG_HAS_FRAME_EXTENTS))
1280     {
1281         return -c->frame_extents[SIDE_BOTTOM];
1282     }
1283     return frameBottom(c);
1284 }
1285 
1286 int
frameExtentX(Client * c)1287 frameExtentX (Client * c)
1288 {
1289     g_return_val_if_fail (c != NULL, 0);
1290     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1291 
1292     if (FLAG_TEST (c->flags, CLIENT_FLAG_HAS_FRAME_EXTENTS))
1293     {
1294         return c->x + c->frame_extents[SIDE_LEFT];
1295     }
1296     return frameX(c);
1297 }
1298 
1299 int
frameExtentY(Client * c)1300 frameExtentY (Client * c)
1301 {
1302     g_return_val_if_fail (c != NULL, 0);
1303     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1304 
1305     if (FLAG_TEST (c->flags, CLIENT_FLAG_HAS_FRAME_EXTENTS))
1306     {
1307         return c->y + c->frame_extents[SIDE_TOP];
1308     }
1309     return frameY(c);
1310 }
1311 
1312 int
frameExtentWidth(Client * c)1313 frameExtentWidth (Client * c)
1314 {
1315     g_return_val_if_fail (c != NULL, 0);
1316     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1317 
1318     if (FLAG_TEST (c->flags, CLIENT_FLAG_HAS_FRAME_EXTENTS))
1319     {
1320         return MAX (0, c->width - c->frame_extents[SIDE_LEFT]
1321                                 - c->frame_extents[SIDE_RIGHT]);
1322     }
1323     return frameWidth(c);
1324 }
1325 
1326 int
frameExtentHeight(Client * c)1327 frameExtentHeight (Client * c)
1328 {
1329     g_return_val_if_fail (c != NULL, 0);
1330     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1331 
1332     if (FLAG_TEST (c->flags, CLIENT_FLAG_HAS_FRAME_EXTENTS))
1333     {
1334         return MAX (0, c->height - c->frame_extents[SIDE_TOP]
1335                                  - c->frame_extents[SIDE_BOTTOM]);
1336     }
1337     return frameHeight(c);
1338 }
1339 
1340 void
frameClearQueueDraw(Client * c)1341 frameClearQueueDraw (Client * c)
1342 {
1343     g_return_if_fail (c);
1344     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1345 
1346     if (c->frame_timeout_id)
1347     {
1348         g_source_remove (c->frame_timeout_id);
1349         c->frame_timeout_id = 0;
1350     }
1351 }
1352 
1353 void
frameDraw(Client * c,gboolean clear_all)1354 frameDraw (Client * c, gboolean clear_all)
1355 {
1356     g_return_if_fail (c);
1357     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1358 
1359     if (clear_all)
1360     {
1361         FLAG_SET (c->xfwm_flags, XFWM_FLAG_NEEDS_REDRAW);
1362     }
1363     frameDrawWin (c);
1364 }
1365 
1366 void
frameQueueDraw(Client * c,gboolean clear_all)1367 frameQueueDraw (Client * c, gboolean clear_all)
1368 {
1369     g_return_if_fail (c);
1370     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1371 
1372     /* Reschedule update */
1373     if (c->frame_timeout_id)
1374     {
1375         frameClearQueueDraw (c);
1376     }
1377     if (clear_all)
1378     {
1379         FLAG_SET (c->xfwm_flags, XFWM_FLAG_NEEDS_REDRAW);
1380     }
1381     /* Otherwise leave previous schedule */
1382     if (c->frame_timeout_id == 0)
1383     {
1384         c->frame_timeout_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
1385                                               update_frame_idle_cb, c, NULL);
1386     }
1387 }
1388 
1389 void
frameSetShapeInput(Client * c)1390 frameSetShapeInput (Client * c)
1391 {
1392     ScreenInfo *screen_info;
1393     DisplayInfo *display_info;
1394 
1395     g_return_if_fail (c != NULL);
1396     TRACE ("client \"%s\" (0x%lx)", c->name, c->window);
1397 
1398     screen_info = c->screen_info;
1399     display_info = screen_info->display_info;
1400 
1401     if (!myDisplayHaveShapeInput(display_info))
1402     {
1403         return;
1404     }
1405 
1406     myDisplayErrorTrapPush (display_info);
1407 
1408     if (screen_info->shape_win == None)
1409     {
1410         screen_info->shape_win = XCreateSimpleWindow (display_info->dpy, screen_info->xroot, 0, 0, frameWidth (c), frameHeight (c), 0, 0, 0);
1411     }
1412     else
1413     {
1414         XResizeWindow (display_info->dpy, screen_info->shape_win, frameWidth (c), frameHeight (c));
1415     }
1416 
1417     /* Set Input shape when using XShape extension 1.1 and later */
1418     XShapeCombineShape(display_info->dpy, screen_info->shape_win, ShapeInput, 0, 0, c->frame, ShapeBounding, ShapeSet);
1419     XShapeCombineShape(display_info->dpy, screen_info->shape_win, ShapeInput, frameLeft (c), frameTop (c), c->window, ShapeBounding, ShapeSubtract);
1420     XShapeCombineShape(display_info->dpy, screen_info->shape_win, ShapeInput, frameLeft (c), frameTop (c), c->window, ShapeInput, ShapeUnion);
1421     XShapeCombineShape(display_info->dpy, c->frame, ShapeInput, 0, 0, screen_info->shape_win, ShapeInput, ShapeSet);
1422 
1423     myDisplayErrorTrapPopIgnored (display_info);
1424 }
1425