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