1
#include "gtk-window-decorator.h"
3
static const PangoFontDescription *
4
get_titlebar_font (void)
15
update_titlebar_font (void)
17
const PangoFontDescription *font_desc;
18
PangoFontMetrics *metrics;
21
font_desc = get_titlebar_font ();
24
GtkStyle *default_style;
26
default_style = gtk_widget_get_default_style ();
27
font_desc = default_style->font_desc;
30
pango_context_set_font_description (pango_context, font_desc);
32
lang = pango_context_get_language (pango_context);
33
metrics = pango_context_get_metrics (pango_context, font_desc, lang);
35
text_height = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
36
pango_font_metrics_get_descent (metrics));
38
pango_font_metrics_unref (metrics);
42
update_event_windows (WnckWindow *win)
45
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
46
gint x0, y0, width, height, x, y, w, h;
48
gint actions = d->actions;
50
xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
52
wnck_window_get_client_window_geometry (win, &x0, &y0, &width, &height);
54
if (d->state & WNCK_WINDOW_STATE_SHADED)
65
gdk_error_trap_push ();
67
for (i = 0; i < 3; i++)
69
static guint event_window_actions[3][3] = {
71
WNCK_WINDOW_ACTION_RESIZE,
72
WNCK_WINDOW_ACTION_RESIZE,
73
WNCK_WINDOW_ACTION_RESIZE
75
WNCK_WINDOW_ACTION_RESIZE,
76
WNCK_WINDOW_ACTION_MOVE,
77
WNCK_WINDOW_ACTION_RESIZE
79
WNCK_WINDOW_ACTION_RESIZE,
80
WNCK_WINDOW_ACTION_RESIZE,
81
WNCK_WINDOW_ACTION_RESIZE
85
for (j = 0; j < 3; j++)
90
if (actions & event_window_actions[i][j] && i >= k && i <= l)
91
(*theme_get_event_window_position) (d, i, j, width, height,
96
BoxPtr box = &d->event_windows[i][j].pos;
102
else if (!d->frame_window && w != 0 && h != 0)
104
XMapWindow (xdisplay, d->event_windows[i][j].window);
105
XMoveResizeWindow (xdisplay, d->event_windows[i][j].window,
108
else if (!d->frame_window)
110
XUnmapWindow (xdisplay, d->event_windows[i][j].window);
115
/* no button event windows if width is less than minimum width */
116
if (width < ICON_SPACE + d->button_width)
119
for (i = 0; i < BUTTON_NUM; i++)
121
static guint button_actions[BUTTON_NUM] = {
122
WNCK_WINDOW_ACTION_CLOSE,
123
WNCK_WINDOW_ACTION_MAXIMIZE,
124
WNCK_WINDOW_ACTION_MINIMIZE,
126
WNCK_WINDOW_ACTION_SHADE,
128
#ifdef HAVE_LIBWNCK_2_18_1
129
WNCK_WINDOW_ACTION_ABOVE,
130
WNCK_WINDOW_ACTION_STICK,
131
WNCK_WINDOW_ACTION_UNSHADE,
132
WNCK_WINDOW_ACTION_ABOVE,
133
WNCK_WINDOW_ACTION_UNSTICK
144
if (d->frame_window &&
145
button_actions[i] && !(actions & button_actions[i]))
147
memset (&d->button_windows[i].pos, 0, sizeof (Box));
149
else if (!d->frame_window &&
150
button_actions[i] && !(actions & button_actions[i]))
152
XUnmapWindow (xdisplay, d->button_windows[i].window);
156
if (d->frame_window &&
157
(*theme_get_button_position) (d, i, width, height, &x, &y, &w, &h))
159
BoxPtr box = &d->button_windows[i].pos;
165
else if (!d->frame_window &&
166
(*theme_get_button_position) (d, i, width, height,
169
Window win = d->button_windows[i].window;
170
XMapWindow (xdisplay, win);
171
XMoveResizeWindow (xdisplay, win, x, y, w, h);
173
else if (!d->frame_window)
175
XUnmapWindow (xdisplay, d->button_windows[i].window);
179
gdk_display_sync (gdk_display_get_default ());
180
gdk_error_trap_pop ();
183
#ifdef HAVE_WNCK_WINDOW_HAS_NAME
185
wnck_window_get_real_name (WnckWindow *win)
187
return wnck_window_has_name (win) ? wnck_window_get_name (win) : NULL;
189
#define wnck_window_get_name wnck_window_get_real_name
193
max_window_name_width (WnckWindow *win)
195
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
201
d->layout = pango_layout_new (pango_context);
205
pango_layout_set_wrap (d->layout, PANGO_WRAP_CHAR);
208
name = wnck_window_get_name (win);
212
pango_layout_set_auto_dir (d->layout, FALSE);
213
pango_layout_set_width (d->layout, -1);
214
pango_layout_set_text (d->layout, name, strlen (name));
215
pango_layout_get_pixel_size (d->layout, &w, NULL);
218
pango_layout_set_text (d->layout, d->name, strlen (d->name));
224
update_window_decoration_name (WnckWindow *win)
226
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
229
PangoLayoutLine *line;
237
name = wnck_window_get_name (win);
238
if (name && (name_length = strlen (name)))
242
if (theme_draw_window_decoration != draw_window_decoration)
250
wnck_window_get_client_window_geometry (win, NULL, NULL,
253
w = width - ICON_SPACE - 2 - d->button_width;
258
pango_layout_set_auto_dir (d->layout, FALSE);
259
pango_layout_set_width (d->layout, w * PANGO_SCALE);
260
pango_layout_set_text (d->layout, name, name_length);
262
line = pango_layout_get_line (d->layout, 0);
264
name_length = line->length;
265
if (pango_layout_get_line_count (d->layout) > 1)
269
pango_layout_set_text (d->layout, NULL, 0);
273
d->name = g_strndup (name, name_length);
274
strcpy (d->name + name_length - 3, "...");
277
d->name = g_strndup (name, name_length);
279
pango_layout_set_text (d->layout, d->name, name_length);
284
update_window_decoration_icon (WnckWindow *win)
286
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
290
cairo_pattern_destroy (d->icon);
296
g_object_unref (G_OBJECT (d->icon_pixmap));
297
d->icon_pixmap = NULL;
301
g_object_unref (G_OBJECT (d->icon_pixbuf));
303
d->icon_pixbuf = wnck_window_get_mini_icon (win);
308
g_object_ref (G_OBJECT (d->icon_pixbuf));
311
d->icon_pixmap = pixmap_new_from_pixbuf (d->icon_pixbuf,
314
d->icon_pixmap = pixmap_new_from_pixbuf (d->icon_pixbuf,
316
cr = gdk_cairo_create (GDK_DRAWABLE (d->icon_pixmap));
317
d->icon = cairo_pattern_create_for_surface (cairo_get_target (cr));
323
update_window_decoration_size (WnckWindow *win)
325
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
326
GdkPixmap *pixmap, *buffer_pixmap = NULL;
329
gint x, y, w, h, name_width;
331
XRenderPictFormat *format;
337
xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
339
wnck_window_get_client_window_geometry (win, &x, &y, &w, &h);
341
name_width = max_window_name_width (win);
343
if (!(*theme_calc_decoration_size) (d, w, h, name_width, &width, &height))
345
update_window_decoration_name (win);
349
gdk_error_trap_push ();
352
depth = gdk_drawable_get_depth (GDK_DRAWABLE (d->frame_window));
356
pixmap = create_pixmap (width, height, depth);
360
if (!pixmap || gdk_error_trap_pop ())
362
memset (pixmap, 0, sizeof (pixmap));
366
gdk_error_trap_push ();
368
buffer_pixmap = create_pixmap (width, height, depth);
372
if (!buffer_pixmap || gdk_error_trap_pop ())
374
memset (buffer_pixmap, 0, sizeof (buffer_pixmap));
375
g_object_unref (G_OBJECT (pixmap));
379
format = get_format_for_drawable (d, GDK_DRAWABLE (buffer_pixmap));
380
picture = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (buffer_pixmap),
384
g_object_unref (G_OBJECT (d->pixmap));
386
if (d->buffer_pixmap)
387
g_object_unref (G_OBJECT (d->buffer_pixmap));
390
XRenderFreePicture (xdisplay, d->picture);
393
cairo_destroy (d->cr);
396
d->buffer_pixmap = buffer_pixmap;
397
d->cr = gdk_cairo_create (pixmap);
399
d->picture = picture;
404
d->prop_xid = wnck_window_get_xid (win);
406
update_window_decoration_name (win);
408
queue_decor_draw (d);
414
draw_border_shape (Display *xdisplay,
422
static XRenderColor white = { 0xffff, 0xffff, 0xffff, 0xffff };
423
GdkColormap *colormap;
425
double save_decoration_alpha;
427
memset (&d, 0, sizeof (d));
429
d.pixmap = gdk_pixmap_foreign_new_for_display (gdk_display_get_default (),
434
d.draw = theme_draw_window_decoration;
438
/* we use closure argument if maximized */
441
WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY |
442
WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY;
444
decor_get_default_layout (c, 1, 1, &d.border_layout);
446
colormap = get_colormap_for_drawable (GDK_DRAWABLE (d.pixmap));
447
gdk_drawable_set_colormap (d.pixmap, colormap);
449
/* create shadow from opaque decoration */
450
save_decoration_alpha = decoration_alpha;
451
decoration_alpha = 1.0;
455
decoration_alpha = save_decoration_alpha;
457
XRenderFillRectangle (xdisplay, PictOpSrc, picture, &white,
460
width - c->left_space - c->right_space,
461
height - c->top_space - c->bottom_space);
463
g_object_unref (G_OBJECT (d.pixmap));
469
decor_shadow_options_t opt_active_shadow;
470
decor_shadow_options_t opt_inactive_shadow;
471
decor_shadow_options_t opt_no_shadow;
472
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
473
GdkDisplay *display = gdk_display_get_default ();
474
GdkScreen *screen = gdk_display_get_default_screen (display);
476
opt_active_shadow.shadow_radius = shadow_radius;
477
opt_active_shadow.shadow_opacity = shadow_opacity;
479
memcpy (opt_active_shadow.shadow_color, shadow_color, sizeof (shadow_color));
481
opt_active_shadow.shadow_offset_x = shadow_offset_x;
482
opt_active_shadow.shadow_offset_y = shadow_offset_y;
484
opt_inactive_shadow.shadow_radius = shadow_radius;
485
opt_inactive_shadow.shadow_opacity = shadow_opacity;
487
memcpy (opt_inactive_shadow.shadow_color, shadow_color, sizeof (shadow_color));
489
opt_inactive_shadow.shadow_offset_x = shadow_offset_x;
490
opt_inactive_shadow.shadow_offset_y = shadow_offset_y;
492
opt_no_shadow.shadow_radius = 0;
493
opt_no_shadow.shadow_opacity = 0;
495
opt_no_shadow.shadow_offset_x = 0;
496
opt_no_shadow.shadow_offset_y = 0;
498
if (no_border_shadow)
500
decor_shadow_destroy (xdisplay, no_border_shadow);
501
no_border_shadow = NULL;
504
no_border_shadow = decor_shadow_create (xdisplay,
505
gdk_x11_screen_get_xscreen (screen),
512
&opt_inactive_shadow,
517
if (border_active_shadow)
519
decor_shadow_destroy (xdisplay, border_active_shadow);
520
border_active_shadow = NULL;
523
border_active_shadow = (*theme_update_shadow) (SHADOW_TYPE_ACTIVE_NORMAL);
525
if (!border_active_shadow)
526
border_active_shadow = cairo_update_shadow (SHADOW_TYPE_ACTIVE_NORMAL);
528
if (border_inactive_shadow)
530
decor_shadow_destroy (xdisplay, border_inactive_shadow);
531
border_inactive_shadow = NULL;
534
border_inactive_shadow = (*theme_update_shadow) (SHADOW_TYPE_INACTIVE_NORMAL);
536
if (!border_inactive_shadow)
537
border_inactive_shadow = cairo_update_shadow (SHADOW_TYPE_INACTIVE_NORMAL);
539
if (border_no_shadow)
541
decor_shadow_destroy (xdisplay, border_no_shadow);
542
border_no_shadow = NULL;
545
border_no_shadow = decor_shadow_create (xdisplay,
546
gdk_x11_screen_get_xscreen (screen),
550
_win_extents.top + titlebar_height,
553
TRANSLUCENT_CORNER_SIZE,
555
TRANSLUCENT_CORNER_SIZE,
556
_win_extents.top + titlebar_height -
557
TRANSLUCENT_CORNER_SIZE,
558
_win_extents.bottom -
559
TRANSLUCENT_CORNER_SIZE,
561
&window_context_no_shadow,
565
decor_context_t *context = &window_context_no_shadow;
568
if (max_border_active_shadow)
570
decor_shadow_destroy (xdisplay, max_border_active_shadow);
571
max_border_active_shadow = NULL;
574
max_border_active_shadow = (*theme_update_shadow) (SHADOW_TYPE_ACTIVE_MAX);
576
if (!max_border_active_shadow)
577
max_border_active_shadow = cairo_update_shadow (SHADOW_TYPE_ACTIVE_MAX);
579
if (max_border_inactive_shadow)
581
decor_shadow_destroy (xdisplay, max_border_inactive_shadow);
582
max_border_inactive_shadow = NULL;
585
max_border_inactive_shadow = (*theme_update_shadow) (SHADOW_TYPE_INACTIVE_MAX);
587
if (!max_border_inactive_shadow)
588
max_border_inactive_shadow = cairo_update_shadow (SHADOW_TYPE_INACTIVE_MAX);
590
if (max_border_no_shadow)
592
decor_shadow_destroy (xdisplay, max_border_active_shadow);
593
max_border_active_shadow = NULL;
596
max_border_no_shadow =
597
decor_shadow_create (xdisplay,
598
gdk_x11_screen_get_xscreen (screen),
600
_max_win_extents.left,
601
_max_win_extents.right,
602
_max_win_extents.top + max_titlebar_height,
603
_max_win_extents.bottom,
604
_max_win_extents.left - TRANSLUCENT_CORNER_SIZE,
605
_max_win_extents.right - TRANSLUCENT_CORNER_SIZE,
606
_max_win_extents.top + max_titlebar_height -
607
TRANSLUCENT_CORNER_SIZE,
608
_max_win_extents.bottom - TRANSLUCENT_CORNER_SIZE,
610
&max_window_context_no_shadow,
616
decor_shadow_destroy (xdisplay, switcher_shadow);
617
switcher_shadow = NULL;
620
switcher_shadow = decor_shadow_create (xdisplay,
621
gdk_x11_screen_get_xscreen (screen),
623
_switcher_extents.left,
624
_switcher_extents.right,
625
_switcher_extents.top,
626
_switcher_extents.bottom,
627
_switcher_extents.left -
628
TRANSLUCENT_CORNER_SIZE,
629
_switcher_extents.right -
630
TRANSLUCENT_CORNER_SIZE,
631
_switcher_extents.top -
632
TRANSLUCENT_CORNER_SIZE,
633
_switcher_extents.bottom -
634
TRANSLUCENT_CORNER_SIZE,
635
&opt_inactive_shadow,
644
update_window_decoration (WnckWindow *win)
646
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
650
/* force size update */
652
d->width = d->height = 0;
654
update_window_decoration_size (win);
655
update_event_windows (win);
660
update_window_decoration_state (WnckWindow *win)
662
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
664
d->state = wnck_window_get_state (win);
668
update_window_decoration_actions (WnckWindow *win)
670
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
672
d->actions = wnck_window_get_actions (win);
676
draw_decor_list (void *data)
683
for (list = draw_list; list; list = list->next)
685
d = (decor_t *) list->data;
689
g_slist_free (draw_list);
696
queue_decor_draw (decor_t *d)
698
if (g_slist_find (draw_list, d))
701
draw_list = g_slist_append (draw_list, d);
704
draw_idle_id = g_idle_add (draw_decor_list, NULL);
708
update_default_decorations (GdkScreen *screen)
712
GdkDisplay *gdkdisplay = gdk_display_get_default ();
713
Display *xdisplay = gdk_x11_display_get_xdisplay (gdkdisplay);
714
Atom bareAtom, normalAtom, activeAtom;
717
decor_quad_t quads[N_QUADS_MAX];
718
decor_extents_t extents = _win_extents;
720
xroot = RootWindowOfScreen (gdk_x11_screen_get_xscreen (screen));
722
bareAtom = XInternAtom (xdisplay, DECOR_BARE_ATOM_NAME, FALSE);
723
normalAtom = XInternAtom (xdisplay, DECOR_NORMAL_ATOM_NAME, FALSE);
724
activeAtom = XInternAtom (xdisplay, DECOR_ACTIVE_ATOM_NAME, FALSE);
726
if (no_border_shadow)
728
decor_layout_t layout;
730
decor_get_default_layout (&shadow_context, 1, 1, &layout);
732
nQuad = decor_set_lSrStSbS_window_quads (quads, &shadow_context,
735
decor_quads_to_property (data, no_border_shadow->pixmap,
736
&_shadow_extents, &_shadow_extents,
737
&_shadow_extents, &_shadow_extents,
740
XChangeProperty (xdisplay, xroot,
743
32, PropModeReplace, (guchar *) data,
744
BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
748
XChangeProperty (xdisplay, xroot,
751
32, PropModeReplace, (guchar *) data,
752
BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
753
XChangeProperty (xdisplay, xroot,
756
32, PropModeReplace, (guchar *) data,
757
BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
762
XDeleteProperty (xdisplay, xroot, bareAtom);
766
XDeleteProperty (xdisplay, xroot, normalAtom);
767
XDeleteProperty (xdisplay, xroot, activeAtom);
774
memset (&d, 0, sizeof (d));
778
d.context = &window_active_context;
779
d.shadow = border_active_shadow;
783
d.context = &window_inactive_context;
784
d.shadow = border_inactive_shadow;
787
d.layout = pango_layout_new (pango_context);
789
decor_get_default_layout (d.context, 1, 1, &d.border_layout);
791
d.width = d.border_layout.width;
792
d.height = d.border_layout.height;
794
extents.top += titlebar_height;
796
d.draw = theme_draw_window_decoration;
798
if (decor_normal_pixmap)
799
g_object_unref (G_OBJECT (decor_normal_pixmap));
801
nQuad = decor_set_lSrStSbS_window_quads (quads, d.context,
804
decor_normal_pixmap = create_pixmap (d.width, d.height, 32);
806
if (decor_normal_pixmap)
808
d.pixmap = decor_normal_pixmap;
810
d.picture = XRenderCreatePicture (xdisplay,
811
GDK_PIXMAP_XID (d.pixmap),
812
xformat_rgba, 0, NULL);
816
XRenderFreePicture (xdisplay, d.picture);
818
fprintf (stderr, "extents are %i %i %i %i %i\n", extents.left, extents.right, extents.top, extents.bottom);
820
decor_quads_to_property (data, GDK_PIXMAP_XID (d.pixmap),
821
&extents, &extents, &extents, &extents, 0, 0, quads, nQuad);
823
XChangeProperty (xdisplay, xroot,
826
32, PropModeReplace, (guchar *) data,
827
BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
830
if (decor_active_pixmap)
831
g_object_unref (G_OBJECT (decor_active_pixmap));
833
decor_active_pixmap = create_pixmap (d.width, d.height, 32);
835
if (decor_active_pixmap)
837
d.pixmap = decor_active_pixmap;
839
d.picture = XRenderCreatePicture (xdisplay,
840
GDK_PIXMAP_XID (d.pixmap),
841
xformat_rgba, 0, NULL);
845
XRenderFreePicture (xdisplay, d.picture);
847
decor_quads_to_property (data, GDK_PIXMAP_XID (d.pixmap),
848
&extents, &extents, &extents, &extents, 0, 0, quads, nQuad);
850
XChangeProperty (xdisplay, xroot,
853
32, PropModeReplace, (guchar *) data,
854
BASE_PROP_SIZE + QUAD_PROP_SIZE * nQuad);
858
g_object_unref (G_OBJECT (d.layout));
862
copy_to_front_buffer (decor_t *d)
864
if (!d->buffer_pixmap)
867
cairo_set_operator (d->cr, CAIRO_OPERATOR_SOURCE);
868
gdk_cairo_set_source_pixmap (d->cr, d->buffer_pixmap, 0, 0);