2
* Copyright © 2006 Novell, Inc.
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Lesser General Public
6
* License as published by the Free Software Foundation; either
7
* version 2 of the License, or (at your option) any later version.
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Lesser General Public License for more details.
14
* You should have received a copy of the GNU Lesser General Public
15
* License along with this library; if not, write to the
16
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
* Boston, MA 02111-1307, USA.
25
#include <X11/Xatom.h>
26
#include <X11/cursorfont.h>
27
#include <X11/extensions/Xrender.h>
28
#include <X11/Xregion.h>
30
#ifndef GTK_DISABLE_DEPRECATED
31
#define GTK_DISABLE_DEPRECATED
35
#include <gtk/gtkwindow.h>
38
#include <gconf/gconf-client.h>
40
#define WNCK_I_KNOW_THIS_IS_UNSTABLE
41
#include <libwnck/libwnck.h>
42
#include <libwnck/window-action-menu.h>
45
#include <cairo-xlib.h>
47
#if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 1, 0)
48
#define CAIRO_EXTEND_PAD CAIRO_EXTEND_NONE
51
#include <pango/pango-context.h>
52
#include <pango/pangocairo.h>
59
#include <sys/types.h>
63
#include <metacity-private/theme.h>
66
#define METACITY_GCONF_DIR "/apps/metacity/general"
68
#define COMPIZ_USE_SYSTEM_FONT_KEY \
69
METACITY_GCONF_DIR "/titlebar_uses_system_font"
71
#define COMPIZ_TITLEBAR_FONT_KEY \
72
METACITY_GCONF_DIR "/titlebar_font"
74
#define COMPIZ_DOUBLE_CLICK_TITLEBAR_KEY \
75
METACITY_GCONF_DIR "/action_double_click_titlebar"
77
#define COMPIZ_GCONF_DIR1 "/apps/compiz/plugins/decoration/allscreens/options"
79
#define COMPIZ_SHADOW_RADIUS_KEY \
80
COMPIZ_GCONF_DIR1 "/shadow_radius"
82
#define COMPIZ_SHADOW_OPACITY_KEY \
83
COMPIZ_GCONF_DIR1 "/shadow_opacity"
85
#define COMPIZ_SHADOW_OFFSET_X_KEY \
86
COMPIZ_GCONF_DIR1 "/shadow_offset_x"
88
#define COMPIZ_SHADOW_OFFSET_Y_KEY \
89
COMPIZ_GCONF_DIR1 "/shadow_offset_y"
91
#define META_AUDIBLE_BELL_KEY \
92
METACITY_GCONF_DIR "/audible_bell"
94
#define META_VISUAL_BELL_KEY \
95
METACITY_GCONF_DIR "/visual_bell"
97
#define META_VISUAL_BELL_TYPE_KEY \
98
METACITY_GCONF_DIR "/visual_bell_type"
100
#define META_THEME_KEY \
101
METACITY_GCONF_DIR "/theme"
103
#define COMPIZ_GCONF_DIR2 "/apps/compiz/general/allscreens/options"
105
#define COMPIZ_AUDIBLE_BELL_KEY \
106
COMPIZ_GCONF_DIR2 "/audible_bell"
108
#define COMPIZ_GCONF_DIR3 "/apps/compiz/plugins/fade/screen0/options"
110
#define COMPIZ_VISUAL_BELL_KEY \
111
COMPIZ_GCONF_DIR3 "/visual_bell"
113
#define COMPIZ_FULLSCREEN_VISUAL_BELL_KEY \
114
COMPIZ_GCONF_DIR3 "/fullscreen_visual_bell"
116
#define GCONF_DIR "/apps/gwd"
118
#define USE_META_THEME_KEY \
119
GCONF_DIR "/use_metacity_theme"
121
#define STROKE_ALPHA 0.6
123
#define ICON_SPACE 20
125
#define DOUBLE_CLICK_DISTANCE 8.0
127
typedef struct _extents {
134
#define GRAVITY_WEST (1 << 0)
135
#define GRAVITY_EAST (1 << 1)
136
#define GRAVITY_NORTH (1 << 2)
137
#define GRAVITY_SOUTH (1 << 3)
139
#define ALIGN_LEFT (0)
140
#define ALIGN_RIGHT (1 << 0)
141
#define ALIGN_TOP (0)
142
#define ALIGN_BOTTOM (1 << 1)
144
#define CLAMP_HORZ (1 << 0)
145
#define CLAMP_VERT (1 << 1)
147
#define XX_MASK (1 << 12)
148
#define XY_MASK (1 << 13)
149
#define YX_MASK (1 << 14)
150
#define YY_MASK (1 << 15)
152
#define WM_MOVERESIZE_SIZE_TOPLEFT 0
153
#define WM_MOVERESIZE_SIZE_TOP 1
154
#define WM_MOVERESIZE_SIZE_TOPRIGHT 2
155
#define WM_MOVERESIZE_SIZE_RIGHT 3
156
#define WM_MOVERESIZE_SIZE_BOTTOMRIGHT 4
157
#define WM_MOVERESIZE_SIZE_BOTTOM 5
158
#define WM_MOVERESIZE_SIZE_BOTTOMLEFT 6
159
#define WM_MOVERESIZE_SIZE_LEFT 7
160
#define WM_MOVERESIZE_MOVE 8
161
#define WM_MOVERESIZE_SIZE_KEYBOARD 9
162
#define WM_MOVERESIZE_MOVE_KEYBOARD 10
164
#define SHADOW_RADIUS 8.0
165
#define SHADOW_OPACITY 0.5
166
#define SHADOW_OFFSET_X 1
167
#define SHADOW_OFFSET_Y 1
169
#define N_QUADS_MAX 24
171
typedef struct _point {
177
typedef struct _quad {
187
#define MWM_HINTS_DECORATIONS (1L << 1)
189
#define MWM_DECOR_ALL (1L << 0)
190
#define MWM_DECOR_BORDER (1L << 1)
191
#define MWM_DECOR_HANDLE (1L << 2)
192
#define MWM_DECOR_TITLE (1L << 3)
193
#define MWM_DECOR_MENU (1L << 4)
194
#define MWM_DECOR_MINIMIZE (1L << 5)
195
#define MWM_DECOR_MAXIMIZE (1L << 6)
197
#define PROP_MOTIF_WM_HINT_ELEMENTS 3
201
unsigned long functions;
202
unsigned long decorations;
207
DOUBLE_CLICK_MAXIMIZE
210
int double_click_action = DOUBLE_CLICK_SHADE;
212
static gboolean minimal = FALSE;
214
static double decoration_alpha = 0.5;
216
static extents _shadow_extents = { 0, 0, 0, 0 };
217
static extents _win_extents = { 6, 6, 4, 6 };
218
static extents _switcher_extents = { 0, 0, 0, 0 };
220
#define SWITCHER_SPACE 40
221
#define SWITCHER_TOP_EXTRA 4
223
static gint left_space = 6;
224
static gint right_space = 6;
225
static gint top_space = 4;
226
static gint bottom_space = 6;
228
static gint left_corner_space = 0;
229
static gint right_corner_space = 0;
230
static gint top_corner_space = 0;
231
static gint bottom_corner_space = 0;
233
static gint titlebar_height = 17;
235
static gint normal_top_corner_space = 0;
236
static gint switcher_top_corner_space = 0;
237
static gint switcher_bottom_corner_space = 0;
239
static gint shadow_left_space = 0;
240
static gint shadow_right_space = 0;
241
static gint shadow_top_space = 0;
242
static gint shadow_bottom_space = 0;
244
static gint shadow_left_corner_space = 0;
245
static gint shadow_right_corner_space = 0;
246
static gint shadow_top_corner_space = 0;
247
static gint shadow_bottom_corner_space = 0;
249
static gdouble shadow_radius = SHADOW_RADIUS;
250
static gdouble shadow_opacity = SHADOW_OPACITY;
251
static gint shadow_offset_x = SHADOW_OFFSET_X;
252
static gint shadow_offset_y = SHADOW_OFFSET_Y;
254
static GdkPixmap *shadow_pixmap = NULL;
255
static GdkPixmap *large_shadow_pixmap = NULL;
256
static GdkPixmap *decor_normal_pixmap = NULL;
257
static GdkPixmap *decor_active_pixmap = NULL;
259
static cairo_pattern_t *shadow_pattern = NULL;
261
static Atom frame_window_atom;
262
static Atom win_decor_atom;
263
static Atom wm_move_resize_atom;
264
static Atom restack_window_atom;
265
static Atom select_window_atom;
266
static Atom mwm_hints_atom;
268
static Atom toolkit_action_atom;
269
static Atom toolkit_action_main_menu_atom;
270
static Atom toolkit_action_run_dialog_atom;
271
static Atom toolkit_action_window_menu_atom;
272
static Atom toolkit_action_force_quit_dialog_atom;
274
static Atom panel_action_atom;
275
static Atom panel_action_main_menu_atom;
276
static Atom panel_action_run_dialog_atom;
278
static Atom manager_atom;
279
static Atom targets_atom;
280
static Atom multiple_atom;
281
static Atom timestamp_atom;
282
static Atom version_atom;
283
static Atom atom_pair_atom;
285
static Atom utf8_string_atom;
287
static Atom dm_name_atom;
288
static Atom dm_sn_atom;
290
static Time dm_sn_timestamp;
292
#define C(name) { 0, XC_ ## name }
294
static struct _cursor {
298
{ C (top_left_corner), C (top_side), C (top_right_corner) },
299
{ C (left_side), C (left_ptr), C (right_side) },
300
{ C (bottom_left_corner), C (bottom_side), C (bottom_right_corner) }
305
int xw, yh, ww, hh, yth, hth;
308
{ 0, 0, 10, 21, 0, 0, 0, 0, 0, 1 },
309
{ 10, 0, -8, 6, 0, 0, 1, 0, 0, 1 },
310
{ 2, 0, 10, 21, 1, 0, 0, 0, 0, 1 }
312
{ 0, 10, 6, 11, 0, 0, 0, 1, 1, 0 },
313
{ 6, 6, 0, 15, 0, 0, 1, 0, 0, 1 },
314
{ 6, 10, 6, 11, 1, 0, 0, 1, 1, 0 }
316
{ 0, 17, 10, 10, 0, 1, 0, 0, 1, 0 },
317
{ 10, 21, -8, 6, 0, 1, 1, 0, 1, 0 },
318
{ 2, 17, 10, 10, 1, 1, 0, 0, 1, 0 }
321
{ 0, 6, 16, 16, 1, 0, 0, 0, 0, 0 },
322
{ 0, 6, 16, 16, 1, 0, 0, 0, 0, 0 },
323
{ 0, 6, 16, 16, 1, 0, 0, 0, 0, 0 }
326
typedef struct _decor_color {
332
#define IN_EVENT_WINDOW (1 << 0)
333
#define PRESSED_EVENT_WINDOW (1 << 1)
335
typedef struct _decor {
336
Window event_windows[3][3];
337
Window button_windows[3];
338
guint button_states[3];
340
GdkPixmap *buffer_pixmap;
349
cairo_pattern_t *icon;
350
GdkPixmap *icon_pixmap;
351
GdkPixbuf *icon_pixbuf;
352
WnckWindowState state;
353
WnckWindowActions actions;
355
GtkWidget *force_quit_dialog;
356
void (*draw) (struct _decor *d);
359
void (*theme_draw_window_decoration) (decor_t *d);
360
gboolean (*theme_calc_decoration_size) (decor_t *d,
366
gint (*theme_calc_titlebar_height) (gint text_height);
368
typedef void (*event_callback) (WnckWindow *win, XEvent *event);
370
static char *program_name;
372
static GtkWidget *style_window;
374
static GHashTable *frame_table;
375
static GtkWidget *action_menu = NULL;
376
static gboolean action_menu_mapped = FALSE;
377
static decor_color_t _title_color[2];
378
static PangoContext *pango_context;
379
static gint double_click_timeout = 250;
381
static GtkWidget *tip_window;
382
static GtkWidget *tip_label;
383
static GTimeVal tooltip_last_popdown = { -1, -1 };
384
static gint tooltip_timer_tag = 0;
386
static GSList *draw_list = NULL;
387
static guint draw_idle_id = 0;
389
static PangoFontDescription *titlebar_font = NULL;
390
static gboolean use_system_font = FALSE;
391
static gint text_height;
393
static GdkPixmap *switcher_pixmap = NULL;
394
static GdkPixmap *switcher_buffer_pixmap = NULL;
395
static gint switcher_width;
396
static gint switcher_height;
405
data[2] = input right
407
data[4] = input bottom
414
1st to 4nd bit p1 gravity, 5rd to 8th bit p2 gravity,
415
9rd and 10th bit alignment, 11rd and 12th bit clamp,
416
13th bit XX, 14th bit XY, 15th bit YX, 16th bit YY.
418
data[6 + n * 9 + 1] = flags
419
data[6 + n * 9 + 2] = p1 x
420
data[6 + n * 9 + 3] = p1 y
421
data[6 + n * 9 + 4] = p2 x
422
data[6 + n * 9 + 5] = p2 y
423
data[6 + n * 9 + 6] = widthMax
424
data[6 + n * 9 + 7] = heightMax
425
data[6 + n * 9 + 8] = x0
426
data[6 + n * 9 + 9] = y0
429
decoration_to_property (long *data,
437
memcpy (data++, &pixmap, sizeof (Pixmap));
439
*data++ = input->left;
440
*data++ = input->right;
441
*data++ = input->top;
442
*data++ = input->bottom;
445
*data++ = min_height;
450
(quad->p1.gravity << 0) |
451
(quad->p2.gravity << 4) |
453
(quad->clamp << 10) |
454
(quad->m.xx ? XX_MASK : 0) |
455
(quad->m.xy ? XY_MASK : 0) |
456
(quad->m.yx ? YX_MASK : 0) |
457
(quad->m.yy ? YY_MASK : 0);
459
*data++ = quad->p1.x;
460
*data++ = quad->p1.y;
461
*data++ = quad->p2.x;
462
*data++ = quad->p2.y;
463
*data++ = quad->max_width;
464
*data++ = quad->max_height;
465
*data++ = quad->m.x0;
466
*data++ = quad->m.y0;
473
set_horz_quad_line (quad *q,
487
dx = (left_corner - right_corner) >> 1;
491
q->p1.gravity = gravity | GRAVITY_WEST;
494
q->p2.gravity = gravity;
495
q->max_width = left + left_corner;
496
q->max_height = SHRT_MAX;
497
q->align = ALIGN_LEFT;
508
q->p1.x = left_corner;
510
q->p1.gravity = gravity | GRAVITY_WEST;
511
q->p2.x = -right_corner;
513
q->p2.gravity = gravity | GRAVITY_EAST;
514
q->max_width = SHRT_MAX;
515
q->max_height = SHRT_MAX;
522
q->m.x0 = x0 + left + left_corner;
529
q->p1.gravity = gravity;
532
q->p2.gravity = gravity | GRAVITY_EAST;
533
q->max_width = right_corner + right;
534
q->max_height = SHRT_MAX;
535
q->align = ALIGN_RIGHT;
541
q->m.x0 = x0 + width;
550
set_vert_quad_row (quad *q,
564
dy = (top_corner - bottom_corner) >> 1;
568
q->p1.gravity = gravity | GRAVITY_NORTH;
571
q->p2.gravity = gravity;
572
q->max_width = SHRT_MAX;
573
q->max_height = top + top_corner;
574
q->align = ALIGN_TOP;
575
q->clamp = CLAMP_VERT;
586
q->p1.y = top_corner;
587
q->p1.gravity = gravity | GRAVITY_NORTH;
589
q->p2.y = -bottom_corner;
590
q->p2.gravity = gravity | GRAVITY_SOUTH;
591
q->max_width = SHRT_MAX;
592
q->max_height = SHRT_MAX;
594
q->clamp = CLAMP_VERT;
600
q->m.y0 = y0 + top + top_corner;
606
q->p1.gravity = gravity;
609
q->p2.gravity = gravity | GRAVITY_SOUTH;
610
q->max_width = SHRT_MAX;
611
q->max_height = bottom_corner + bottom;
612
q->align = ALIGN_BOTTOM;
613
q->clamp = CLAMP_VERT;
619
q->m.y0 = y0 + height;
627
set_common_window_quads (quad *q,
634
n = set_vert_quad_row (q,
636
normal_top_corner_space,
642
height - top_space - titlebar_height - bottom_space,
644
top_space + titlebar_height + 1.0);
649
n = set_vert_quad_row (q,
651
normal_top_corner_space,
657
height - top_space - titlebar_height - bottom_space,
659
top_space + titlebar_height + 1.0);
664
n = set_horz_quad_line (q,
674
top_space + titlebar_height +
675
normal_top_corner_space +
676
bottom_corner_space + 2.0);
684
set_window_quads (quad *q,
690
int top_left, top_right, y;
693
top_right = button_width;
694
top_left = width - left_space - right_space - top_right - 1;
696
/* special case which can happen with large shadows */
697
if (right_corner_space > top_right || left_corner_space > top_left)
699
y = -titlebar_height;
703
n = set_horz_quad_line (q,
708
-top_space - titlebar_height,
719
y = -top_space - titlebar_height;
723
/* 3 top/titlebar quads */
724
q->p1.x = -left_space;
726
q->p1.gravity = GRAVITY_NORTH | GRAVITY_WEST;
727
q->p2.x = -top_right;
729
q->p2.gravity = GRAVITY_NORTH | GRAVITY_EAST;
730
q->max_width = left_space + top_left;
731
q->max_height = SHRT_MAX;
732
q->align = ALIGN_LEFT;
745
q->p1.gravity = GRAVITY_NORTH | GRAVITY_WEST;
746
q->p2.x = -top_right;
748
q->p2.gravity = GRAVITY_NORTH | GRAVITY_EAST;
749
q->max_width = SHRT_MAX;
750
q->max_height = SHRT_MAX;
757
q->m.x0 = left_space + top_left;
764
q->p1.gravity = GRAVITY_NORTH | GRAVITY_WEST;
765
q->p2.x = right_space;
767
q->p2.gravity = GRAVITY_NORTH | GRAVITY_EAST;
768
q->max_width = right_space + top_right;
769
q->max_height = SHRT_MAX;
770
q->align = ALIGN_RIGHT;
781
n = set_common_window_quads (q, width, height);
789
set_no_title_window_quads (quad *q,
796
n = set_horz_quad_line (q,
801
-top_space - titlebar_height,
810
n = set_common_window_quads (q, width, height);
818
decor_update_window_property (decor_t *d)
821
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
822
extents extents = _win_extents;
824
quad quads[N_QUADS_MAX];
826
nQuad = set_window_quads (quads, d->width, d->height, d->button_width);
828
extents.top += titlebar_height;
830
decoration_to_property (data, GDK_PIXMAP_XID (d->pixmap),
832
ICON_SPACE + d->button_width,
836
gdk_error_trap_push ();
837
XChangeProperty (xdisplay, d->prop_xid,
840
32, PropModeReplace, (guchar *) data, 7 + 9 * nQuad);
841
XSync (xdisplay, FALSE);
842
gdk_error_trap_pop ();
846
set_switcher_quads (quad *q,
853
q->p1.x = -left_space;
854
q->p1.y = -top_space - SWITCHER_TOP_EXTRA;
855
q->p1.gravity = GRAVITY_NORTH | GRAVITY_WEST;
856
q->p2.x = right_space;
858
q->p2.gravity = GRAVITY_NORTH | GRAVITY_EAST;
859
q->max_width = SHRT_MAX;
860
q->max_height = SHRT_MAX;
873
n = set_vert_quad_row (q,
875
switcher_top_corner_space,
881
height - top_space - titlebar_height - bottom_space,
883
top_space + SWITCHER_TOP_EXTRA);
888
n = set_vert_quad_row (q,
890
switcher_top_corner_space,
892
switcher_bottom_corner_space,
896
height - top_space - titlebar_height - bottom_space,
898
top_space + SWITCHER_TOP_EXTRA);
903
q->p1.x = -left_space;
905
q->p1.gravity = GRAVITY_SOUTH | GRAVITY_WEST;
906
q->p2.x = right_space;
907
q->p2.y = bottom_space + SWITCHER_SPACE;
908
q->p2.gravity = GRAVITY_SOUTH | GRAVITY_EAST;
909
q->max_width = SHRT_MAX;
910
q->max_height = SHRT_MAX;
918
q->m.y0 = height - bottom_space - SWITCHER_SPACE;
926
decor_update_switcher_property (decor_t *d)
929
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
931
quad quads[N_QUADS_MAX];
932
extents extents = _switcher_extents;
934
nQuad = set_switcher_quads (quads, d->width, d->height);
936
decoration_to_property (data, GDK_PIXMAP_XID (d->pixmap),
937
&extents, 0, 0, quads, nQuad);
939
gdk_error_trap_push ();
940
XChangeProperty (xdisplay, d->prop_xid,
943
32, PropModeReplace, (guchar *) data, 7 + 9 * nQuad);
944
XSync (xdisplay, FALSE);
945
gdk_error_trap_pop ();
949
set_shadow_quads (quad *q,
956
n = set_horz_quad_line (q,
958
shadow_left_corner_space,
960
shadow_right_corner_space,
971
n = set_vert_quad_row (q,
973
shadow_top_corner_space,
975
shadow_bottom_corner_space,
979
height - shadow_top_space - shadow_bottom_space,
986
n = set_vert_quad_row (q,
988
shadow_top_corner_space,
990
shadow_bottom_corner_space,
994
height - shadow_top_space - shadow_bottom_space,
995
width - shadow_right_space,
1001
n = set_horz_quad_line (q,
1003
shadow_left_corner_space,
1005
shadow_right_corner_space,
1007
shadow_bottom_space,
1011
shadow_top_space + shadow_top_corner_space +
1012
shadow_bottom_corner_space + 1.0);
1020
gdk_cairo_set_source_color_alpha (cairo_t *cr,
1024
cairo_set_source_rgba (cr,
1025
color->red / 65535.0,
1026
color->green / 65535.0,
1027
color->blue / 65535.0,
1031
#define CORNER_TOPLEFT (1 << 0)
1032
#define CORNER_TOPRIGHT (1 << 1)
1033
#define CORNER_BOTTOMRIGHT (1 << 2)
1034
#define CORNER_BOTTOMLEFT (1 << 3)
1037
rounded_rectangle (cairo_t *cr,
1045
if (corner & CORNER_TOPLEFT)
1046
cairo_move_to (cr, x + radius, y);
1048
cairo_move_to (cr, x, y);
1050
if (corner & CORNER_TOPRIGHT)
1051
cairo_arc (cr, x + w - radius, y + radius, radius,
1052
M_PI * 1.5, M_PI * 2.0);
1054
cairo_line_to (cr, x + w, y);
1056
if (corner & CORNER_BOTTOMRIGHT)
1057
cairo_arc (cr, x + w - radius, y + h - radius, radius,
1060
cairo_line_to (cr, x + w, y + h);
1062
if (corner & CORNER_BOTTOMLEFT)
1063
cairo_arc (cr, x + radius, y + h - radius, radius,
1066
cairo_line_to (cr, x, y + h);
1068
if (corner & CORNER_TOPLEFT)
1069
cairo_arc (cr, x + radius, y + radius, radius, M_PI, M_PI * 1.5);
1071
cairo_line_to (cr, x, y);
1074
#define SHADE_LEFT (1 << 0)
1075
#define SHADE_RIGHT (1 << 1)
1076
#define SHADE_TOP (1 << 2)
1077
#define SHADE_BOTTOM (1 << 3)
1080
fill_rounded_rectangle (cairo_t *cr,
1093
cairo_pattern_t *pattern;
1095
rounded_rectangle (cr, x, y, w, h, radius, corner);
1097
if (gravity & SHADE_RIGHT)
1102
else if (!(gravity & SHADE_LEFT))
1107
if (gravity & SHADE_BOTTOM)
1112
else if (!(gravity & SHADE_TOP))
1119
cairo_matrix_t matrix;
1121
pattern = cairo_pattern_create_radial (0.0, 0.0, 0.0, 0.0, 0.0, w);
1123
cairo_matrix_init_scale (&matrix, 1.0, w / h);
1124
cairo_matrix_translate (&matrix, -(x + w), -(y + h));
1126
cairo_pattern_set_matrix (pattern, &matrix);
1130
pattern = cairo_pattern_create_linear (x + w, y + h, x, y);
1133
cairo_pattern_add_color_stop_rgba (pattern, 0.0, c0->r, c0->g, c0->b,
1136
cairo_pattern_add_color_stop_rgba (pattern, 1.0, c1->r, c1->g, c1->b,
1139
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
1141
cairo_set_source (cr, pattern);
1143
cairo_pattern_destroy (pattern);
1147
draw_shadow_background (decor_t *d,
1150
cairo_matrix_t matrix;
1151
double w, h, x2, y2;
1153
gint left, right, top, bottom;
1155
if (!large_shadow_pixmap)
1157
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
1163
gdk_drawable_get_size (large_shadow_pixmap, &width, &height);
1165
left = left_space + left_corner_space;
1166
right = right_space + right_corner_space;
1167
top = top_space + top_corner_space;
1168
bottom = bottom_space + bottom_corner_space;
1170
if (d->width - left - right < 0)
1172
left = d->width / 2;
1173
right = d->width - left;
1176
if (d->height - top - bottom < 0)
1178
top = d->height / 2;
1179
bottom = d->height - top;
1182
w = d->width - left - right;
1183
h = d->height - top - bottom;
1185
x2 = d->width - right;
1186
y2 = d->height - bottom;
1189
cairo_matrix_init_identity (&matrix);
1190
cairo_pattern_set_matrix (shadow_pattern, &matrix);
1191
cairo_set_source (cr, shadow_pattern);
1192
cairo_rectangle (cr, 0.0, 0.0, left, top);
1198
cairo_matrix_init_translate (&matrix, left, 0.0);
1199
cairo_matrix_scale (&matrix, 1.0 / w, 1.0);
1200
cairo_matrix_translate (&matrix, -left, 0.0);
1201
cairo_pattern_set_matrix (shadow_pattern, &matrix);
1202
cairo_set_source (cr, shadow_pattern);
1203
cairo_rectangle (cr, left, 0.0, w, top);
1208
cairo_matrix_init_translate (&matrix, width - right - x2, 0.0);
1209
cairo_pattern_set_matrix (shadow_pattern, &matrix);
1210
cairo_set_source (cr, shadow_pattern);
1211
cairo_rectangle (cr, x2, 0.0, right, top);
1217
cairo_matrix_init_translate (&matrix, 0.0, top);
1218
cairo_matrix_scale (&matrix, 1.0, 1.0 / h);
1219
cairo_matrix_translate (&matrix, 0.0, -top);
1220
cairo_pattern_set_matrix (shadow_pattern, &matrix);
1221
cairo_set_source (cr, shadow_pattern);
1222
cairo_rectangle (cr, 0.0, top, left, h);
1229
cairo_matrix_init_translate (&matrix, width - right - x2, top);
1230
cairo_matrix_scale (&matrix, 1.0, 1.0 / h);
1231
cairo_matrix_translate (&matrix, 0.0, -top);
1232
cairo_pattern_set_matrix (shadow_pattern, &matrix);
1233
cairo_set_source (cr, shadow_pattern);
1234
cairo_rectangle (cr, x2, top, right, h);
1239
cairo_matrix_init_translate (&matrix, 0.0, height - bottom - y2);
1240
cairo_pattern_set_matrix (shadow_pattern, &matrix);
1241
cairo_set_source (cr, shadow_pattern);
1242
cairo_rectangle (cr, 0.0, y2, left, bottom);
1248
cairo_matrix_init_translate (&matrix, left,
1249
height - bottom - y2);
1250
cairo_matrix_scale (&matrix, 1.0 / w, 1.0);
1251
cairo_matrix_translate (&matrix, -left, 0.0);
1252
cairo_pattern_set_matrix (shadow_pattern, &matrix);
1253
cairo_set_source (cr, shadow_pattern);
1254
cairo_rectangle (cr, left, y2, w, bottom);
1259
cairo_matrix_init_translate (&matrix, width - right - x2,
1260
height - bottom - y2);
1261
cairo_pattern_set_matrix (shadow_pattern, &matrix);
1262
cairo_set_source (cr, shadow_pattern);
1263
cairo_rectangle (cr, x2, y2, right, bottom);
1268
draw_close_button (decor_t *d,
1272
cairo_rel_move_to (cr, 0.0, s);
1274
cairo_rel_line_to (cr, s, -s);
1275
cairo_rel_line_to (cr, s, s);
1276
cairo_rel_line_to (cr, s, -s);
1277
cairo_rel_line_to (cr, s, s);
1279
cairo_rel_line_to (cr, -s, s);
1280
cairo_rel_line_to (cr, s, s);
1281
cairo_rel_line_to (cr, -s, s);
1282
cairo_rel_line_to (cr, -s, -s);
1284
cairo_rel_line_to (cr, -s, s);
1285
cairo_rel_line_to (cr, -s, -s);
1286
cairo_rel_line_to (cr, s, -s);
1288
cairo_close_path (cr);
1292
draw_max_button (decor_t *d,
1296
cairo_rel_line_to (cr, 12.0, 0.0);
1297
cairo_rel_line_to (cr, 0.0, 12.0);
1298
cairo_rel_line_to (cr, -12.0, 0.0);
1300
cairo_close_path (cr);
1302
cairo_rel_move_to (cr, 2.0, s);
1304
cairo_rel_line_to (cr, 12.0 - 4.0, 0.0);
1305
cairo_rel_line_to (cr, 0.0, 12.0 - s - 2.0);
1306
cairo_rel_line_to (cr, -(12.0 - 4.0), 0.0);
1308
cairo_close_path (cr);
1312
draw_unmax_button (decor_t *d,
1316
cairo_rel_move_to (cr, 1.0, 1.0);
1318
cairo_rel_line_to (cr, 10.0, 0.0);
1319
cairo_rel_line_to (cr, 0.0, 10.0);
1320
cairo_rel_line_to (cr, -10.0, 0.0);
1322
cairo_close_path (cr);
1324
cairo_rel_move_to (cr, 2.0, s);
1326
cairo_rel_line_to (cr, 10.0 - 4.0, 0.0);
1327
cairo_rel_line_to (cr, 0.0, 10.0 - s - 2.0);
1328
cairo_rel_line_to (cr, -(10.0 - 4.0), 0.0);
1330
cairo_close_path (cr);
1334
draw_min_button (decor_t *d,
1338
cairo_rel_move_to (cr, 0.0, 8.0);
1340
cairo_rel_line_to (cr, 12.0, 0.0);
1341
cairo_rel_line_to (cr, 0.0, s);
1342
cairo_rel_line_to (cr, -12.0, 0.0);
1344
cairo_close_path (cr);
1347
typedef void (*draw_proc) (cairo_t *cr);
1350
button_state_offsets (gdouble x,
1356
static double off[] = { 0.0, 0.0, 0.0, 0.5 };
1358
*return_x = x + off[state];
1359
*return_y = y + off[state];
1363
button_state_paint (cairo_t *cr,
1365
decor_color_t *color,
1369
#define IN_STATE (PRESSED_EVENT_WINDOW | IN_EVENT_WINDOW)
1371
if ((state & IN_STATE) == IN_STATE)
1373
if (state & IN_EVENT_WINDOW)
1374
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
1376
cairo_set_source_rgba (cr, color->r, color->g, color->b, 0.95);
1378
cairo_fill_preserve (cr);
1380
gdk_cairo_set_source_color_alpha (cr,
1381
&style->fg[GTK_STATE_NORMAL],
1384
cairo_set_line_width (cr, 1.0);
1386
cairo_set_line_width (cr, 2.0);
1390
gdk_cairo_set_source_color_alpha (cr,
1391
&style->fg[GTK_STATE_NORMAL],
1393
cairo_stroke_preserve (cr);
1395
if (state & IN_EVENT_WINDOW)
1396
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
1398
cairo_set_source_rgba (cr, color->r, color->g, color->b, 0.95);
1405
draw_window_decoration (decor_t *d)
1409
decor_color_t color;
1411
double x1, y1, x2, y2, x, y, h;
1412
int corners = SHADE_LEFT | SHADE_RIGHT | SHADE_TOP | SHADE_BOTTOM;
1419
style = gtk_widget_get_style (style_window);
1421
if (d->state & (WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY |
1422
WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY))
1425
color.r = style->bg[GTK_STATE_NORMAL].red / 65535.0;
1426
color.g = style->bg[GTK_STATE_NORMAL].green / 65535.0;
1427
color.b = style->bg[GTK_STATE_NORMAL].blue / 65535.0;
1429
if (d->buffer_pixmap)
1430
cr = gdk_cairo_create (GDK_DRAWABLE (d->buffer_pixmap));
1432
cr = gdk_cairo_create (GDK_DRAWABLE (d->pixmap));
1434
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
1436
top = _win_extents.top + titlebar_height;
1438
x1 = left_space - _win_extents.left;
1439
y1 = top_space - _win_extents.top;
1440
x2 = d->width - right_space + _win_extents.right;
1441
y2 = d->height - bottom_space + _win_extents.bottom;
1443
h = d->height - top_space - titlebar_height - bottom_space;
1445
cairo_set_line_width (cr, 1.0);
1447
draw_shadow_background (d, cr);
1451
decor_color_t *title_color = _title_color;
1453
alpha = decoration_alpha + 0.3;
1455
fill_rounded_rectangle (cr,
1458
_win_extents.left - 0.5,
1460
5.0, CORNER_TOPLEFT & corners,
1461
&title_color[0], 1.0, &title_color[1], alpha,
1462
SHADE_TOP | SHADE_LEFT);
1464
fill_rounded_rectangle (cr,
1465
x1 + _win_extents.left,
1467
x2 - x1 - _win_extents.left -
1471
&title_color[0], 1.0, &title_color[1], alpha,
1474
fill_rounded_rectangle (cr,
1475
x2 - _win_extents.right,
1477
_win_extents.right - 0.5,
1479
5.0, CORNER_TOPRIGHT & corners,
1480
&title_color[0], 1.0, &title_color[1], alpha,
1481
SHADE_TOP | SHADE_RIGHT);
1485
alpha = decoration_alpha;
1487
fill_rounded_rectangle (cr,
1490
_win_extents.left - 0.5,
1492
5.0, CORNER_TOPLEFT & corners,
1493
&color, 1.0, &color, alpha,
1494
SHADE_TOP | SHADE_LEFT);
1496
fill_rounded_rectangle (cr,
1497
x1 + _win_extents.left,
1499
x2 - x1 - _win_extents.left -
1503
&color, 1.0, &color, alpha,
1506
fill_rounded_rectangle (cr,
1507
x2 - _win_extents.right,
1509
_win_extents.right - 0.5,
1511
5.0, CORNER_TOPRIGHT & corners,
1512
&color, 1.0, &color, alpha,
1513
SHADE_TOP | SHADE_RIGHT);
1516
fill_rounded_rectangle (cr,
1519
_win_extents.left - 0.5,
1522
&color, 1.0, &color, alpha,
1525
fill_rounded_rectangle (cr,
1526
x2 - _win_extents.right,
1528
_win_extents.right - 0.5,
1531
&color, 1.0, &color, alpha,
1535
fill_rounded_rectangle (cr,
1537
y2 - _win_extents.bottom,
1538
_win_extents.left - 0.5,
1539
_win_extents.bottom - 0.5,
1540
5.0, CORNER_BOTTOMLEFT & corners,
1541
&color, 1.0, &color, alpha,
1542
SHADE_BOTTOM | SHADE_LEFT);
1544
fill_rounded_rectangle (cr,
1545
x1 + _win_extents.left,
1546
y2 - _win_extents.bottom,
1547
x2 - x1 - _win_extents.left -
1549
_win_extents.bottom - 0.5,
1551
&color, 1.0, &color, alpha,
1554
fill_rounded_rectangle (cr,
1555
x2 - _win_extents.right,
1556
y2 - _win_extents.bottom,
1557
_win_extents.right - 0.5,
1558
_win_extents.bottom - 0.5,
1559
5.0, CORNER_BOTTOMRIGHT & corners,
1560
&color, 1.0, &color, alpha,
1561
SHADE_BOTTOM | SHADE_RIGHT);
1563
cairo_rectangle (cr,
1565
titlebar_height + top_space,
1566
d->width - left_space - right_space,
1568
gdk_cairo_set_source_color (cr, &style->bg[GTK_STATE_NORMAL]);
1571
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
1575
gdk_cairo_set_source_color_alpha (cr,
1576
&style->fg[GTK_STATE_NORMAL],
1579
cairo_move_to (cr, x1 + 0.5, y1 + top - 0.5);
1580
cairo_rel_line_to (cr, x2 - x1 - 1.0, 0.0);
1585
rounded_rectangle (cr,
1587
x2 - x1 - 1.0, y2 - y1 - 1.0,
1589
(CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
1590
CORNER_BOTTOMRIGHT) & corners);
1594
cairo_translate (cr, 1.0, 1.0);
1596
rounded_rectangle (cr,
1598
x2 - x1 - 1.0, y2 - y1 - 1.0,
1600
(CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
1601
CORNER_BOTTOMRIGHT) & corners);
1603
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.4);
1606
cairo_translate (cr, -2.0, -2.0);
1608
rounded_rectangle (cr,
1610
x2 - x1 - 1.0, y2 - y1 - 1.0,
1612
(CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
1613
CORNER_BOTTOMRIGHT) & corners);
1615
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.1);
1618
cairo_translate (cr, 1.0, 1.0);
1620
cairo_reset_clip (cr);
1622
rounded_rectangle (cr,
1624
x2 - x1 - 1.0, y2 - y1 - 1.0,
1626
(CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
1627
CORNER_BOTTOMRIGHT) & corners);
1629
gdk_cairo_set_source_color_alpha (cr,
1630
&style->fg[GTK_STATE_NORMAL],
1635
cairo_set_line_width (cr, 2.0);
1637
button_x = d->width - right_space - 13;
1639
if (d->actions & WNCK_WINDOW_ACTION_CLOSE)
1641
button_state_offsets (button_x,
1642
y1 - 3.0 + titlebar_height / 2,
1643
d->button_states[0], &x, &y);
1649
cairo_move_to (cr, x, y);
1650
draw_close_button (d, cr, 3.0);
1651
button_state_paint (cr, style, &color, d->button_states[0]);
1655
gdk_cairo_set_source_color_alpha (cr,
1656
&style->fg[GTK_STATE_NORMAL],
1658
cairo_move_to (cr, x, y);
1659
draw_close_button (d, cr, 3.0);
1664
if (d->actions & WNCK_WINDOW_ACTION_MAXIMIZE)
1666
button_state_offsets (button_x,
1667
y1 - 3.0 + titlebar_height / 2,
1668
d->button_states[1], &x, &y);
1672
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
1676
gdk_cairo_set_source_color_alpha (cr,
1677
&style->fg[GTK_STATE_NORMAL],
1679
cairo_move_to (cr, x, y);
1681
if (d->state & (WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY |
1682
WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY))
1683
draw_unmax_button (d, cr, 4.0);
1685
draw_max_button (d, cr, 4.0);
1687
button_state_paint (cr, style, &color, d->button_states[1]);
1691
gdk_cairo_set_source_color_alpha (cr,
1692
&style->fg[GTK_STATE_NORMAL],
1694
cairo_move_to (cr, x, y);
1696
if (d->state & (WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY |
1697
WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY))
1698
draw_unmax_button (d, cr, 4.0);
1700
draw_max_button (d, cr, 4.0);
1706
if (d->actions & WNCK_WINDOW_ACTION_MINIMIZE)
1708
button_state_offsets (button_x,
1709
y1 - 3.0 + titlebar_height / 2,
1710
d->button_states[2], &x, &y);
1716
gdk_cairo_set_source_color_alpha (cr,
1717
&style->fg[GTK_STATE_NORMAL],
1719
cairo_move_to (cr, x, y);
1720
draw_min_button (d, cr, 4.0);
1721
button_state_paint (cr, style, &color, d->button_states[2]);
1725
gdk_cairo_set_source_color_alpha (cr,
1726
&style->fg[GTK_STATE_NORMAL],
1728
cairo_move_to (cr, x, y);
1729
draw_min_button (d, cr, 4.0);
1740
y1 + 2.0 + (titlebar_height - text_height) / 2.0);
1742
gdk_cairo_set_source_color_alpha (cr,
1743
&style->fg[GTK_STATE_NORMAL],
1746
pango_cairo_layout_path (cr, d->layout);
1749
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
1753
gdk_cairo_set_source_color_alpha (cr,
1754
&style->fg[GTK_STATE_NORMAL],
1760
y1 + 2.0 + (titlebar_height - text_height) / 2.0);
1762
pango_cairo_show_layout (cr, d->layout);
1767
cairo_translate (cr, left_space + 1, y1 - 5.0 + titlebar_height / 2);
1768
cairo_set_source (cr, d->icon);
1769
cairo_rectangle (cr, 0.0, 0.0, 16.0, 16.0);
1775
cairo_paint_with_alpha (cr, alpha);
1780
if (d->buffer_pixmap)
1781
gdk_draw_drawable (d->pixmap,
1793
decor_update_window_property (d);
1800
meta_get_window_region (const MetaFrameGeometry *fgeom,
1804
Region corners_xregion, window_xregion;
1807
corners_xregion = XCreateRegion ();
1809
if (fgeom->top_left_corner_rounded)
1816
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
1821
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
1826
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
1832
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
1835
if (fgeom->top_right_corner_rounded)
1837
xrect.x = width - 5;
1842
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
1845
xrect.x = width - 3;
1848
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
1851
xrect.x = width - 2;
1854
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
1857
xrect.x = width - 1;
1861
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
1864
if (fgeom->bottom_left_corner_rounded)
1867
xrect.y = height - 1;
1871
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
1873
xrect.y = height - 2;
1876
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
1878
xrect.y = height - 3;
1881
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
1883
xrect.y = height - 5;
1887
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
1890
if (fgeom->bottom_right_corner_rounded)
1892
xrect.x = width - 5;
1893
xrect.y = height - 1;
1897
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
1899
xrect.y = height - 2;
1900
xrect.x = width - 3;
1903
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
1905
xrect.y = height - 3;
1906
xrect.x = width - 2;
1909
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
1911
xrect.y = height - 5;
1912
xrect.x = width - 1;
1916
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
1919
window_xregion = XCreateRegion ();
1923
xrect.width = width;
1924
xrect.height = height;
1926
XUnionRectWithRegion (&xrect, window_xregion, window_xregion);
1928
XSubtractRegion (window_xregion, corners_xregion, window_xregion);
1930
XDestroyRegion (corners_xregion);
1932
return window_xregion;
1935
static MetaButtonState
1936
meta_button_state (int state)
1938
if (state & IN_EVENT_WINDOW)
1940
if (state & PRESSED_EVENT_WINDOW)
1941
return META_BUTTON_STATE_PRESSED;
1943
return META_BUTTON_STATE_PRELIGHT;
1946
return META_BUTTON_STATE_NORMAL;
1948
static MetaButtonState
1949
meta_button_state_for_button_type (decor_t *d,
1950
MetaButtonType type)
1953
case META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND:
1954
case META_BUTTON_TYPE_MINIMIZE:
1955
return meta_button_state (d->button_states[2]);
1956
case META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND:
1957
case META_BUTTON_TYPE_MAXIMIZE:
1958
return meta_button_state (d->button_states[1]);
1959
case META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND:
1960
case META_BUTTON_TYPE_CLOSE:
1961
return meta_button_state (d->button_states[0]);
1962
case META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND:
1963
case META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND:
1964
case META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND:
1965
case META_BUTTON_TYPE_MENU:
1970
return META_BUTTON_STATE_NORMAL;
1974
meta_draw_window_decoration (decor_t *d)
1976
MetaButtonState button_states[META_BUTTON_TYPE_LAST];
1977
MetaButtonLayout button_layout;
1978
MetaFrameGeometry fgeom;
1981
MetaFrameFlags flags = 0;
1983
gint i, left_width, right_width, top_height, bottom_height;
1984
GdkRectangle clip, rect;
1985
GdkDrawable *drawable;
1991
style = gtk_widget_get_style (style_window);
1993
if (d->buffer_pixmap)
1994
cr = gdk_cairo_create (GDK_DRAWABLE (d->buffer_pixmap));
1996
cr = gdk_cairo_create (GDK_DRAWABLE (d->pixmap));
1998
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
2000
draw_shadow_background (d, cr);
2002
theme = meta_theme_get_current ();
2004
button_layout.left_buttons[0] = META_BUTTON_FUNCTION_MENU;
2005
button_layout.left_buttons[1] = META_BUTTON_FUNCTION_LAST;
2006
button_layout.left_buttons[2] = META_BUTTON_FUNCTION_LAST;
2007
button_layout.left_buttons[3] = META_BUTTON_FUNCTION_LAST;
2009
button_layout.right_buttons[0] = META_BUTTON_FUNCTION_MINIMIZE;
2010
button_layout.right_buttons[1] = META_BUTTON_FUNCTION_MAXIMIZE;
2011
button_layout.right_buttons[2] = META_BUTTON_FUNCTION_CLOSE;
2012
button_layout.right_buttons[3] = META_BUTTON_FUNCTION_LAST;
2014
if (d->actions & WNCK_WINDOW_ACTION_CLOSE)
2015
flags |= META_FRAME_ALLOWS_DELETE;
2017
if (d->actions & WNCK_WINDOW_ACTION_MINIMIZE)
2018
flags |= META_FRAME_ALLOWS_MINIMIZE;
2020
if (d->actions & WNCK_WINDOW_ACTION_MAXIMIZE)
2021
flags |= META_FRAME_ALLOWS_MAXIMIZE;
2023
flags |= META_FRAME_ALLOWS_MENU;
2024
flags |= META_FRAME_ALLOWS_VERTICAL_RESIZE;
2025
flags |= META_FRAME_ALLOWS_HORIZONTAL_RESIZE;
2026
flags |= META_FRAME_ALLOWS_MOVE;
2029
flags |= META_FRAME_HAS_FOCUS;
2031
for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
2032
button_states[i] = meta_button_state_for_button_type (d, i);
2034
meta_theme_get_frame_borders (theme,
2035
META_FRAME_TYPE_NORMAL,
2043
clip.x = left_space - left_width;
2044
clip.y = top_space + titlebar_height - top_height;
2045
clip.width = d->width - right_space + right_width - clip.x;
2046
clip.height = d->height - bottom_space + bottom_height - clip.y;
2048
drawable = d->buffer_pixmap ? d->buffer_pixmap : d->pixmap;
2050
meta_theme_calc_geometry (theme,
2051
META_FRAME_TYPE_NORMAL,
2054
clip.width - left_width - right_width,
2055
clip.height - top_height - bottom_height,
2059
region = meta_get_window_region (&fgeom, clip.width, clip.height);
2061
gdk_cairo_set_source_color (cr, &style->bg[GTK_STATE_NORMAL]);
2063
for (i = 0; i < region->numRects; i++)
2065
rect.x = clip.x + region->rects[i].x1;
2066
rect.y = clip.y + region->rects[i].y1;
2067
rect.width = region->rects[i].x2 - region->rects[i].x1;
2068
rect.height = region->rects[i].y2 - region->rects[i].y1;
2070
cairo_rectangle (cr, rect.x, rect.y, rect.width, rect.height);
2073
meta_theme_draw_frame (theme,
2079
META_FRAME_TYPE_NORMAL,
2081
clip.width - left_width - right_width,
2082
clip.height - top_height - bottom_height,
2093
XDestroyRegion (region);
2095
if (d->buffer_pixmap)
2096
gdk_draw_drawable (d->pixmap,
2108
decor_update_window_property (d);
2114
#define SWITCHER_ALPHA 0xa0a0
2117
draw_switcher_background (decor_t *d)
2119
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
2122
decor_color_t color;
2123
double alpha = SWITCHER_ALPHA / 65535.0;
2124
double x1, y1, x2, y2, h;
2126
unsigned long pixel;
2127
ushort a = SWITCHER_ALPHA;
2129
if (!d->buffer_pixmap)
2132
style = gtk_widget_get_style (style_window);
2134
color.r = style->bg[GTK_STATE_NORMAL].red / 65535.0;
2135
color.g = style->bg[GTK_STATE_NORMAL].green / 65535.0;
2136
color.b = style->bg[GTK_STATE_NORMAL].blue / 65535.0;
2138
cr = gdk_cairo_create (GDK_DRAWABLE (d->buffer_pixmap));
2140
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
2142
top = _win_extents.bottom;
2144
x1 = left_space - _win_extents.left;
2145
y1 = top_space - _win_extents.top;
2146
x2 = d->width - right_space + _win_extents.right;
2147
y2 = d->height - bottom_space + _win_extents.bottom;
2149
h = y2 - y1 - _win_extents.bottom - _win_extents.bottom;
2151
cairo_set_line_width (cr, 1.0);
2153
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
2155
draw_shadow_background (d, cr);
2157
fill_rounded_rectangle (cr,
2160
_win_extents.left - 0.5,
2162
5.0, CORNER_TOPLEFT,
2163
&color, alpha, &color, alpha * 0.75,
2164
SHADE_TOP | SHADE_LEFT);
2166
fill_rounded_rectangle (cr,
2167
x1 + _win_extents.left,
2169
x2 - x1 - _win_extents.left -
2173
&color, alpha, &color, alpha * 0.75,
2176
fill_rounded_rectangle (cr,
2177
x2 - _win_extents.right,
2179
_win_extents.right - 0.5,
2181
5.0, CORNER_TOPRIGHT,
2182
&color, alpha, &color, alpha * 0.75,
2183
SHADE_TOP | SHADE_RIGHT);
2185
fill_rounded_rectangle (cr,
2188
_win_extents.left - 0.5,
2191
&color, alpha, &color, alpha * 0.75,
2194
fill_rounded_rectangle (cr,
2195
x2 - _win_extents.right,
2197
_win_extents.right - 0.5,
2200
&color, alpha, &color, alpha * 0.75,
2203
fill_rounded_rectangle (cr,
2205
y2 - _win_extents.bottom,
2206
_win_extents.left - 0.5,
2207
_win_extents.bottom - 0.5,
2208
5.0, CORNER_BOTTOMLEFT,
2209
&color, alpha, &color, alpha * 0.75,
2210
SHADE_BOTTOM | SHADE_LEFT);
2212
fill_rounded_rectangle (cr,
2213
x1 + _win_extents.left,
2214
y2 - _win_extents.bottom,
2215
x2 - x1 - _win_extents.left -
2217
_win_extents.bottom - 0.5,
2219
&color, alpha, &color, alpha * 0.75,
2222
fill_rounded_rectangle (cr,
2223
x2 - _win_extents.right,
2224
y2 - _win_extents.bottom,
2225
_win_extents.right - 0.5,
2226
_win_extents.bottom - 0.5,
2227
5.0, CORNER_BOTTOMRIGHT,
2228
&color, alpha, &color, alpha * 0.75,
2229
SHADE_BOTTOM | SHADE_RIGHT);
2231
cairo_rectangle (cr, x1 + _win_extents.left,
2233
x2 - x1 - _win_extents.left - _win_extents.right,
2235
gdk_cairo_set_source_color_alpha (cr,
2236
&style->bg[GTK_STATE_NORMAL],
2240
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
2242
rounded_rectangle (cr,
2244
x2 - x1 - 1.0, y2 - y1 - 1.0,
2246
CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
2247
CORNER_BOTTOMRIGHT);
2251
cairo_translate (cr, 1.0, 1.0);
2253
rounded_rectangle (cr,
2255
x2 - x1 - 1.0, y2 - y1 - 1.0,
2257
CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
2258
CORNER_BOTTOMRIGHT);
2260
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.4);
2263
cairo_translate (cr, -2.0, -2.0);
2265
rounded_rectangle (cr,
2267
x2 - x1 - 1.0, y2 - y1 - 1.0,
2269
CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
2270
CORNER_BOTTOMRIGHT);
2272
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.1);
2275
cairo_translate (cr, 1.0, 1.0);
2277
cairo_reset_clip (cr);
2279
rounded_rectangle (cr,
2281
x2 - x1 - 1.0, y2 - y1 - 1.0,
2283
CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
2284
CORNER_BOTTOMRIGHT);
2286
gdk_cairo_set_source_color_alpha (cr,
2287
&style->fg[GTK_STATE_NORMAL],
2294
gdk_draw_drawable (d->pixmap,
2304
pixel = ((((a * style->bg[GTK_STATE_NORMAL].red ) >> 24) & 0x0000ff) |
2305
(((a * style->bg[GTK_STATE_NORMAL].green) >> 16) & 0x00ff00) |
2306
(((a * style->bg[GTK_STATE_NORMAL].blue ) >> 8) & 0xff0000) |
2307
(((a & 0xff00) << 16)));
2309
decor_update_switcher_property (d);
2311
gdk_error_trap_push ();
2312
XSetWindowBackground (xdisplay, d->prop_xid, pixel);
2313
XClearWindow (xdisplay, d->prop_xid);
2314
XSync (xdisplay, FALSE);
2315
gdk_error_trap_pop ();
2321
draw_switcher_foreground (decor_t *d)
2325
decor_color_t color;
2326
double alpha = SWITCHER_ALPHA / 65535.0;
2330
if (!d->pixmap || !d->buffer_pixmap)
2333
style = gtk_widget_get_style (style_window);
2335
color.r = style->bg[GTK_STATE_NORMAL].red / 65535.0;
2336
color.g = style->bg[GTK_STATE_NORMAL].green / 65535.0;
2337
color.b = style->bg[GTK_STATE_NORMAL].blue / 65535.0;
2339
top = _win_extents.bottom;
2341
x1 = left_space - _win_extents.left;
2342
y1 = top_space - _win_extents.top;
2343
x2 = d->width - right_space + _win_extents.right;
2345
cr = gdk_cairo_create (GDK_DRAWABLE (d->buffer_pixmap));
2347
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
2349
cairo_rectangle (cr, x1 + _win_extents.left,
2350
y1 + top + switcher_top_corner_space,
2351
x2 - x1 - _win_extents.left - _win_extents.right,
2354
gdk_cairo_set_source_color_alpha (cr,
2355
&style->bg[GTK_STATE_NORMAL],
2363
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
2365
gdk_cairo_set_source_color_alpha (cr,
2366
&style->fg[GTK_STATE_NORMAL],
2369
pango_layout_get_pixel_size (d->layout, &w, NULL);
2371
cairo_move_to (cr, d->width / 2 - w / 2,
2372
y1 + top + switcher_top_corner_space +
2373
SWITCHER_SPACE / 2 - text_height / 2);
2375
pango_cairo_show_layout (cr, d->layout);
2380
gdk_draw_drawable (d->pixmap,
2392
draw_switcher_decoration (decor_t *d)
2395
draw_switcher_background (d);
2397
draw_switcher_foreground (d);
2401
draw_decor_list (void *data)
2408
for (list = draw_list; list; list = list->next)
2410
d = (decor_t *) list->data;
2414
g_slist_free (draw_list);
2421
queue_decor_draw (decor_t *d)
2423
if (g_slist_find (draw_list, d))
2426
draw_list = g_slist_append (draw_list, d);
2429
draw_idle_id = g_idle_add (draw_decor_list, NULL);
2433
create_pixmap (int w,
2438
GdkColormap *colormap;
2440
visual = gdk_visual_get_best_with_depth (32);
2444
pixmap = gdk_pixmap_new (NULL, w, h, 32);
2448
colormap = gdk_colormap_new (visual, FALSE);
2451
gdk_pixmap_unref (pixmap);
2455
gdk_drawable_set_colormap (GDK_DRAWABLE (pixmap), colormap);
2456
gdk_colormap_unref (colormap);
2462
pixmap_new_from_pixbuf (GdkPixbuf *pixbuf)
2465
guint width, height;
2468
width = gdk_pixbuf_get_width (pixbuf);
2469
height = gdk_pixbuf_get_height (pixbuf);
2471
pixmap = create_pixmap (width, height);
2475
cr = (cairo_t *) gdk_cairo_create (GDK_DRAWABLE (pixmap));
2476
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
2477
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
2485
update_default_decorations (GdkScreen *screen)
2489
GdkDisplay *gdkdisplay = gdk_display_get_default ();
2490
Display *xdisplay = gdk_x11_display_get_xdisplay (gdkdisplay);
2491
Atom bareAtom, normalAtom, activeAtom;
2494
quad quads[N_QUADS_MAX];
2495
extents extents = _win_extents;
2497
xroot = RootWindowOfScreen (gdk_x11_screen_get_xscreen (screen));
2499
bareAtom = XInternAtom (xdisplay, "_NET_WINDOW_DECOR_BARE", FALSE);
2500
normalAtom = XInternAtom (xdisplay, "_NET_WINDOW_DECOR_NORMAL", FALSE);
2501
activeAtom = XInternAtom (xdisplay, "_NET_WINDOW_DECOR_ACTIVE", FALSE);
2507
gdk_drawable_get_size (shadow_pixmap, &width, &height);
2509
nQuad = set_shadow_quads (quads, width, height);
2511
decoration_to_property (data, GDK_PIXMAP_XID (shadow_pixmap),
2512
&_shadow_extents, 0, 0, quads, nQuad);
2514
XChangeProperty (xdisplay, xroot,
2517
32, PropModeReplace, (guchar *) data,
2522
XChangeProperty (xdisplay, xroot,
2525
32, PropModeReplace, (guchar *) data,
2527
XChangeProperty (xdisplay, xroot,
2530
32, PropModeReplace, (guchar *) data,
2536
XDeleteProperty (xdisplay, xroot, bareAtom);
2540
XDeleteProperty (xdisplay, xroot, normalAtom);
2541
XDeleteProperty (xdisplay, xroot, activeAtom);
2548
d.width = left_space + left_corner_space + 1 + right_corner_space +
2550
d.height = top_space + titlebar_height + normal_top_corner_space + 2 +
2551
bottom_corner_space + bottom_space;
2553
extents.top += titlebar_height;
2555
d.buffer_pixmap = NULL;
2558
d.icon_pixmap = NULL;
2559
d.icon_pixbuf = NULL;
2564
d.draw = theme_draw_window_decoration;
2566
if (decor_normal_pixmap)
2567
gdk_pixmap_unref (decor_normal_pixmap);
2569
nQuad = set_no_title_window_quads (quads, d.width, d.height);
2571
decor_normal_pixmap = create_pixmap (d.width, d.height);
2572
if (decor_normal_pixmap)
2574
d.pixmap = decor_normal_pixmap;
2579
decoration_to_property (data, GDK_PIXMAP_XID (d.pixmap),
2580
&extents, 0, 0, quads, nQuad);
2582
XChangeProperty (xdisplay, xroot,
2585
32, PropModeReplace, (guchar *) data, 7 + 9 * nQuad);
2588
if (decor_active_pixmap)
2589
gdk_pixmap_unref (decor_active_pixmap);
2591
decor_active_pixmap = create_pixmap (d.width, d.height);
2592
if (decor_active_pixmap)
2594
d.pixmap = decor_active_pixmap;
2599
decoration_to_property (data, GDK_PIXMAP_XID (d.pixmap),
2600
&extents, 0, 0, quads, nQuad);
2602
XChangeProperty (xdisplay, xroot,
2605
32, PropModeReplace, (guchar *) data, 7 + 9 * nQuad);
2610
set_dm_check_hint (GdkScreen *screen)
2612
XSetWindowAttributes attrs;
2613
unsigned long data[1];
2615
GdkDisplay *gdkdisplay = gdk_display_get_default ();
2616
Display *xdisplay = gdk_x11_display_get_xdisplay (gdkdisplay);
2619
attrs.override_redirect = TRUE;
2620
attrs.event_mask = PropertyChangeMask;
2622
xroot = RootWindowOfScreen (gdk_x11_screen_get_xscreen (screen));
2624
data[0] = XCreateWindow (xdisplay,
2630
(Visual *) CopyFromParent,
2631
CWOverrideRedirect | CWEventMask,
2634
atom = XInternAtom (xdisplay, "_NET_SUPPORTING_DM_CHECK", FALSE);
2636
XChangeProperty (xdisplay, xroot,
2639
32, PropModeReplace, (guchar *) data, 1);
2643
get_window_prop (Window xwindow,
2656
gdk_error_trap_push ();
2659
result = XGetWindowProperty (gdk_display,
2663
False, XA_WINDOW, &type, &format, &nitems,
2664
&bytes_after, (void*) &w);
2665
err = gdk_error_trap_pop ();
2666
if (err != Success || result != Success)
2669
if (type != XA_WINDOW)
2682
get_mwm_prop (Window xwindow)
2686
int err, result, format;
2687
unsigned long n, left;
2688
MwmHints *mwm_hints;
2689
unsigned int decor = MWM_DECOR_ALL;
2691
xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
2693
gdk_error_trap_push ();
2695
result = XGetWindowProperty (xdisplay, xwindow, mwm_hints_atom,
2696
0L, 20L, FALSE, mwm_hints_atom,
2697
&actual, &format, &n, &left,
2698
(unsigned char **) &mwm_hints);
2700
err = gdk_error_trap_pop ();
2701
if (err != Success || result != Success)
2706
if (n >= PROP_MOTIF_WM_HINT_ELEMENTS)
2708
if (mwm_hints->flags & MWM_HINTS_DECORATIONS)
2709
decor = mwm_hints->decorations;
2719
update_event_windows (WnckWindow *win)
2722
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
2723
gint x0, y0, width, height, x, y, w, h;
2727
xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
2729
wnck_window_get_geometry (win, &x0, &y0, &width, &height);
2731
if (d->state & WNCK_WINDOW_STATE_SHADED)
2742
gdk_error_trap_push ();
2744
for (i = 0; i < 3; i++)
2746
static guint event_window_actions[3][3] = {
2748
WNCK_WINDOW_ACTION_RESIZE,
2749
WNCK_WINDOW_ACTION_RESIZE,
2750
WNCK_WINDOW_ACTION_RESIZE
2752
WNCK_WINDOW_ACTION_RESIZE,
2753
WNCK_WINDOW_ACTION_MOVE,
2754
WNCK_WINDOW_ACTION_RESIZE
2756
WNCK_WINDOW_ACTION_RESIZE,
2757
WNCK_WINDOW_ACTION_RESIZE,
2758
WNCK_WINDOW_ACTION_RESIZE
2762
for (j = 0; j < 3; j++)
2764
if (d->actions & event_window_actions[i][j] && i >= k && i <= l)
2766
x = pos[i][j].x + pos[i][j].xw * width;
2767
y = pos[i][j].y + pos[i][j].yh * height + pos[i][j].yth * (titlebar_height - 17);
2768
w = pos[i][j].w + pos[i][j].ww * width;
2769
h = pos[i][j].h + pos[i][j].hh * height + pos[i][j].hth * (titlebar_height - 17);
2771
XMapWindow (xdisplay, d->event_windows[i][j]);
2772
XMoveResizeWindow (xdisplay, d->event_windows[i][j],
2777
XUnmapWindow (xdisplay, d->event_windows[i][j]);
2782
for (i = 0; i < 3; i++)
2784
static guint button_actions[3] = {
2785
WNCK_WINDOW_ACTION_CLOSE,
2786
WNCK_WINDOW_ACTION_MAXIMIZE,
2787
WNCK_WINDOW_ACTION_MINIMIZE
2790
if (d->actions & button_actions[i])
2792
x = bpos[i].x + bpos[i].xw * width;
2793
y = bpos[i].y + bpos[i].yh * height + bpos[i].yth * (titlebar_height - 17);
2794
w = bpos[i].w + bpos[i].ww * width;
2795
h = bpos[i].h + bpos[i].hh * height + bpos[i].hth + (titlebar_height - 17);
2800
XMapWindow (xdisplay, d->button_windows[i]);
2801
XMoveResizeWindow (xdisplay, d->button_windows[i], x, y, w, h);
2804
XUnmapWindow (xdisplay, d->button_windows[i]);
2807
XSync (xdisplay, FALSE);
2808
gdk_error_trap_pop ();
2811
#if HAVE_WNCK_WINDOW_HAS_NAME
2813
wnck_window_get_real_name (WnckWindow *win)
2815
return wnck_window_has_name (win) ? wnck_window_get_name (win) : NULL;
2817
#define wnck_window_get_name wnck_window_get_real_name
2821
max_window_name_width (WnckWindow *win)
2823
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
2827
name = wnck_window_get_name (win);
2833
d->layout = pango_layout_new (pango_context);
2837
pango_layout_set_wrap (d->layout, PANGO_WRAP_CHAR);
2840
pango_layout_set_width (d->layout, -1);
2841
pango_layout_set_text (d->layout, name, strlen (name));
2842
pango_layout_get_pixel_size (d->layout, &w, NULL);
2845
pango_layout_set_text (d->layout, d->name, strlen (d->name));
2851
update_window_decoration_name (WnckWindow *win)
2853
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
2856
PangoLayoutLine *line;
2864
name = wnck_window_get_name (win);
2865
if (name && (name_length = strlen (name)))
2869
w = d->width - left_space - right_space - ICON_SPACE - 4;
2870
w -= d->button_width;
2874
pango_layout_set_width (d->layout, w * PANGO_SCALE);
2875
pango_layout_set_text (d->layout, name, name_length);
2877
n_line = pango_layout_get_line_count (d->layout);
2879
line = pango_layout_get_line (d->layout, 0);
2881
name_length = line->length;
2882
if (pango_layout_get_line_count (d->layout) > 1)
2884
if (name_length < 4)
2886
g_object_unref (G_OBJECT (d->layout));
2891
d->name = g_strndup (name, name_length);
2892
strcpy (d->name + name_length - 3, "...");
2895
d->name = g_strndup (name, name_length);
2897
pango_layout_set_text (d->layout, d->name, name_length);
2901
g_object_unref (G_OBJECT (d->layout));
2907
update_window_decoration_icon (WnckWindow *win)
2909
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
2913
cairo_pattern_destroy (d->icon);
2919
gdk_pixmap_unref (d->icon_pixmap);
2920
d->icon_pixmap = NULL;
2924
gdk_pixbuf_unref (d->icon_pixbuf);
2926
d->icon_pixbuf = wnck_window_get_mini_icon (win);
2931
gdk_pixbuf_ref (d->icon_pixbuf);
2933
d->icon_pixmap = pixmap_new_from_pixbuf (d->icon_pixbuf);
2934
cr = gdk_cairo_create (GDK_DRAWABLE (d->icon_pixmap));
2935
d->icon = cairo_pattern_create_for_surface (cairo_get_target (cr));
2941
update_window_decoration_state (WnckWindow *win)
2943
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
2945
d->state = wnck_window_get_state (win);
2949
update_window_decoration_actions (WnckWindow *win)
2951
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
2953
d->actions = wnck_window_get_actions (win);
2957
update_window_button_size (WnckWindow *win)
2959
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
2964
if (d->actions & WNCK_WINDOW_ACTION_CLOSE)
2967
if (d->actions & (WNCK_WINDOW_ACTION_MAXIMIZE_HORIZONTALLY |
2968
WNCK_WINDOW_ACTION_MAXIMIZE_VERTICALLY |
2969
WNCK_WINDOW_ACTION_UNMAXIMIZE_HORIZONTALLY |
2970
WNCK_WINDOW_ACTION_UNMAXIMIZE_VERTICALLY))
2973
if (d->actions & (WNCK_WINDOW_ACTION_MINIMIZE |
2974
WNCK_WINDOW_ACTION_MINIMIZE))
2980
if (button_width != d->button_width)
2982
d->button_width = button_width;
2991
calc_decoration_size (decor_t *d,
2998
if (w < ICON_SPACE + d->button_width)
3001
*width = name_width + d->button_width + ICON_SPACE;
3003
*width = MAX (ICON_SPACE + d->button_width, w);
3005
*width = MAX (*width, left_corner_space + right_corner_space);
3006
*width += left_space + 1 + right_space;
3008
*height = titlebar_height + normal_top_corner_space + bottom_corner_space;
3009
*height += top_space + 2 + bottom_space;
3011
return (*width != d->width || *height != d->height);
3016
meta_calc_decoration_size (decor_t *d,
3023
*width = MAX (w, left_corner_space + right_corner_space);
3024
*width += left_space + 1 + right_space;
3026
*height = titlebar_height + normal_top_corner_space + bottom_corner_space;
3027
*height += top_space + 2 + bottom_space;
3029
return (*width != d->width || *height != d->height);
3034
update_window_decoration_size (WnckWindow *win)
3036
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
3037
GdkPixmap *pixmap, *buffer_pixmap = NULL;
3039
gint w, h, name_width;
3041
wnck_window_get_geometry (win, NULL, NULL, &w, &h);
3043
name_width = max_window_name_width (win);
3045
if (!(*theme_calc_decoration_size) (d, w, h, name_width, &width, &height))
3047
update_window_decoration_name (win);
3051
pixmap = create_pixmap (width, height);
3055
buffer_pixmap = create_pixmap (width, height);
3058
gdk_pixmap_unref (pixmap);
3063
gdk_pixmap_unref (d->pixmap);
3065
if (d->buffer_pixmap)
3066
gdk_pixmap_unref (d->buffer_pixmap);
3069
gdk_gc_unref (d->gc);
3072
d->buffer_pixmap = buffer_pixmap;
3073
d->gc = gdk_gc_new (pixmap);
3078
d->prop_xid = wnck_window_get_xid (win);
3080
update_window_decoration_name (win);
3082
queue_decor_draw (d);
3088
add_frame_window (WnckWindow *win,
3092
XSetWindowAttributes attr;
3093
gulong xid = wnck_window_get_xid (win);
3094
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
3097
xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
3099
attr.event_mask = ButtonPressMask | EnterWindowMask | LeaveWindowMask;
3100
attr.override_redirect = TRUE;
3102
gdk_error_trap_push ();
3104
for (i = 0; i < 3; i++)
3106
for (j = 0; j < 3; j++)
3108
d->event_windows[i][j] =
3109
XCreateWindow (xdisplay,
3112
CopyFromParent, CopyFromParent, CopyFromParent,
3113
CWOverrideRedirect | CWEventMask, &attr);
3115
if (cursor[i][j].cursor)
3116
XDefineCursor (xdisplay, d->event_windows[i][j],
3117
cursor[i][j].cursor);
3121
attr.event_mask |= ButtonReleaseMask;
3123
for (i = 0; i < 3; i++)
3125
d->button_windows[i] =
3126
XCreateWindow (xdisplay,
3129
CopyFromParent, CopyFromParent, CopyFromParent,
3130
CWOverrideRedirect | CWEventMask, &attr);
3132
d->button_states[i] = 0;
3135
XSync (xdisplay, FALSE);
3136
if (!gdk_error_trap_pop ())
3138
if (get_mwm_prop (xid) & (MWM_DECOR_ALL | MWM_DECOR_TITLE))
3139
d->decorated = TRUE;
3141
for (i = 0; i < 3; i++)
3142
for (j = 0; j < 3; j++)
3143
g_hash_table_insert (frame_table,
3144
GINT_TO_POINTER (d->event_windows[i][j]),
3145
GINT_TO_POINTER (xid));
3147
for (i = 0; i < 3; i++)
3148
g_hash_table_insert (frame_table,
3149
GINT_TO_POINTER (d->button_windows[i]),
3150
GINT_TO_POINTER (xid));
3153
update_window_decoration_state (win);
3154
update_window_decoration_actions (win);
3155
update_window_decoration_icon (win);
3156
update_window_button_size (win);
3157
update_window_decoration_size (win);
3159
update_event_windows (win);
3163
memset (d->event_windows, 0, sizeof (d->event_windows));
3168
update_switcher_window (WnckWindow *win,
3171
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
3172
GdkPixmap *pixmap, *buffer_pixmap = NULL;
3173
gint height, width = 0;
3174
WnckWindow *selected_win;
3176
wnck_window_get_geometry (win, NULL, NULL, &width, NULL);
3178
width += left_space + right_space;
3179
height = top_space + SWITCHER_TOP_EXTRA + switcher_top_corner_space +
3180
SWITCHER_SPACE + switcher_bottom_corner_space + bottom_space;
3182
d->decorated = FALSE;
3183
d->draw = draw_switcher_decoration;
3185
if (!d->pixmap && switcher_pixmap)
3187
gdk_pixmap_ref (switcher_pixmap);
3188
d->pixmap = switcher_pixmap;
3191
if (!d->buffer_pixmap && switcher_buffer_pixmap)
3193
gdk_pixmap_ref (switcher_buffer_pixmap);
3194
d->buffer_pixmap = switcher_buffer_pixmap;
3198
d->width = switcher_width;
3201
d->height = switcher_height;
3203
selected_win = wnck_window_get (selected);
3207
PangoLayoutLine *line;
3216
name = wnck_window_get_name (selected_win);
3217
if (name && (name_length = strlen (name)))
3223
d->layout = pango_layout_new (pango_context);
3225
pango_layout_set_wrap (d->layout, PANGO_WRAP_CHAR);
3232
tw = width - left_space - right_space - 64;
3233
pango_layout_set_width (d->layout, tw * PANGO_SCALE);
3234
pango_layout_set_text (d->layout, name, name_length);
3236
n_line = pango_layout_get_line_count (d->layout);
3238
line = pango_layout_get_line (d->layout, 0);
3240
name_length = line->length;
3241
if (pango_layout_get_line_count (d->layout) > 1)
3243
if (name_length < 4)
3245
g_object_unref (G_OBJECT (d->layout));
3250
d->name = g_strndup (name, name_length);
3251
strcpy (d->name + name_length - 3, "...");
3255
d->name = g_strndup (name, name_length);
3258
pango_layout_set_text (d->layout, d->name, name_length);
3263
g_object_unref (G_OBJECT (d->layout));
3268
if (width == d->width && height == d->height)
3271
d->gc = gdk_gc_new (d->pixmap);
3273
queue_decor_draw (d);
3277
pixmap = create_pixmap (width, height);
3281
buffer_pixmap = create_pixmap (width, height);
3284
gdk_pixmap_unref (pixmap);
3288
if (switcher_pixmap)
3289
gdk_pixmap_unref (switcher_pixmap);
3291
if (switcher_buffer_pixmap)
3292
gdk_pixmap_unref (switcher_buffer_pixmap);
3295
gdk_pixmap_unref (d->pixmap);
3297
if (d->buffer_pixmap)
3298
gdk_pixmap_unref (d->buffer_pixmap);
3301
gdk_gc_unref (d->gc);
3303
switcher_pixmap = pixmap;
3304
switcher_buffer_pixmap = buffer_pixmap;
3306
switcher_width = width;
3307
switcher_height = height;
3309
gdk_pixmap_ref (pixmap);
3310
gdk_pixmap_ref (buffer_pixmap);
3313
d->buffer_pixmap = buffer_pixmap;
3314
d->gc = gdk_gc_new (pixmap);
3319
d->prop_xid = wnck_window_get_xid (win);
3321
queue_decor_draw (d);
3327
remove_frame_window (WnckWindow *win)
3329
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
3333
gdk_pixmap_unref (d->pixmap);
3337
if (d->buffer_pixmap)
3339
gdk_pixmap_unref (d->buffer_pixmap);
3340
d->buffer_pixmap = NULL;
3345
gdk_gc_unref (d->gc);
3357
g_object_unref (G_OBJECT (d->layout));
3363
cairo_pattern_destroy (d->icon);
3369
gdk_pixmap_unref (d->icon_pixmap);
3370
d->icon_pixmap = NULL;
3375
gdk_pixbuf_unref (d->icon_pixbuf);
3376
d->icon_pixbuf = NULL;
3379
if (d->force_quit_dialog)
3381
GtkWidget *dialog = d->force_quit_dialog;
3383
d->force_quit_dialog = NULL;
3384
gtk_widget_destroy (dialog);
3390
d->decorated = FALSE;
3395
draw_list = g_slist_remove (draw_list, d);
3399
window_name_changed (WnckWindow *win)
3401
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
3405
if (!update_window_decoration_size (win))
3406
queue_decor_draw (d);
3411
window_geometry_changed (WnckWindow *win)
3413
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
3417
update_window_decoration_size (win);
3418
update_event_windows (win);
3423
window_icon_changed (WnckWindow *win)
3425
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
3429
update_window_decoration_icon (win);
3430
queue_decor_draw (d);
3435
window_state_changed (WnckWindow *win)
3437
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
3441
update_window_decoration_state (win);
3442
queue_decor_draw (d);
3443
update_event_windows (win);
3448
window_actions_changed (WnckWindow *win)
3450
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
3454
update_window_decoration_actions (win);
3455
if (update_window_button_size (win))
3457
update_window_decoration_size (win);
3458
update_event_windows (win);
3462
queue_decor_draw (d);
3468
connect_window (WnckWindow *win)
3470
g_signal_connect_object (win, "name_changed",
3471
G_CALLBACK (window_name_changed),
3473
g_signal_connect_object (win, "geometry_changed",
3474
G_CALLBACK (window_geometry_changed),
3476
g_signal_connect_object (win, "icon_changed",
3477
G_CALLBACK (window_icon_changed),
3479
g_signal_connect_object (win, "state_changed",
3480
G_CALLBACK (window_state_changed),
3482
g_signal_connect_object (win, "actions_changed",
3483
G_CALLBACK (window_actions_changed),
3488
active_window_changed (WnckScreen *screen)
3493
win = wnck_screen_get_previously_active_window (screen);
3496
d = g_object_get_data (G_OBJECT (win), "decor");
3499
d->active = wnck_window_is_active (win);
3500
queue_decor_draw (d);
3504
win = wnck_screen_get_active_window (screen);
3507
d = g_object_get_data (G_OBJECT (win), "decor");
3510
d->active = wnck_window_is_active (win);
3511
queue_decor_draw (d);
3517
window_opened (WnckScreen *screen,
3524
d = g_malloc (sizeof (decor_t));
3529
d->buffer_pixmap = NULL;
3533
d->icon_pixmap = NULL;
3534
d->icon_pixbuf = NULL;
3536
d->button_width = 0;
3541
d->active = wnck_window_is_active (win);
3551
d->decorated = FALSE;
3553
d->force_quit_dialog = NULL;
3555
d->draw = theme_draw_window_decoration;
3557
g_object_set_data (G_OBJECT (win), "decor", d);
3559
connect_window (win);
3561
xid = wnck_window_get_xid (win);
3563
if (get_window_prop (xid, frame_window_atom, &window))
3565
add_frame_window (win, window);
3567
else if (get_window_prop (xid, select_window_atom, &window))
3569
d->prop_xid = wnck_window_get_xid (win);
3570
update_switcher_window (win, window);
3575
window_closed (WnckScreen *screen,
3578
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
3579
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
3581
remove_frame_window (win);
3583
gdk_error_trap_push ();
3584
XDeleteProperty (xdisplay, wnck_window_get_xid (win), win_decor_atom);
3585
XSync (xdisplay, FALSE);
3586
gdk_error_trap_pop ();
3592
connect_screen (WnckScreen *screen)
3596
g_signal_connect_object (G_OBJECT (screen), "active_window_changed",
3597
G_CALLBACK (active_window_changed),
3599
g_signal_connect_object (G_OBJECT (screen), "window_opened",
3600
G_CALLBACK (window_opened),
3602
g_signal_connect_object (G_OBJECT (screen), "window_closed",
3603
G_CALLBACK (window_closed),
3606
windows = wnck_screen_get_windows (screen);
3607
while (windows != NULL)
3609
window_opened (screen, windows->data);
3610
windows = windows->next;
3615
move_resize_window (WnckWindow *win,
3620
GdkDisplay *gdkdisplay;
3625
gdkdisplay = gdk_display_get_default ();
3626
xdisplay = GDK_DISPLAY_XDISPLAY (gdkdisplay);
3627
screen = gdk_display_get_default_screen (gdkdisplay);
3628
xroot = RootWindowOfScreen (gdk_x11_screen_get_xscreen (screen));
3630
if (action_menu_mapped)
3632
gtk_object_destroy (GTK_OBJECT (action_menu));
3633
action_menu_mapped = FALSE;
3638
ev.xclient.type = ClientMessage;
3639
ev.xclient.display = xdisplay;
3641
ev.xclient.serial = 0;
3642
ev.xclient.send_event = TRUE;
3644
ev.xclient.window = wnck_window_get_xid (win);
3645
ev.xclient.message_type = wm_move_resize_atom;
3646
ev.xclient.format = 32;
3648
ev.xclient.data.l[0] = xevent->xbutton.x_root;
3649
ev.xclient.data.l[1] = xevent->xbutton.y_root;
3650
ev.xclient.data.l[2] = direction;
3651
ev.xclient.data.l[3] = xevent->xbutton.button;
3652
ev.xclient.data.l[4] = 1;
3654
XUngrabPointer (xdisplay, xevent->xbutton.time);
3655
XUngrabKeyboard (xdisplay, xevent->xbutton.time);
3657
XSendEvent (xdisplay, xroot, FALSE,
3658
SubstructureRedirectMask | SubstructureNotifyMask,
3661
XSync (xdisplay, FALSE);
3665
restack_window (WnckWindow *win,
3669
GdkDisplay *gdkdisplay;
3674
gdkdisplay = gdk_display_get_default ();
3675
xdisplay = GDK_DISPLAY_XDISPLAY (gdkdisplay);
3676
screen = gdk_display_get_default_screen (gdkdisplay);
3677
xroot = RootWindowOfScreen (gdk_x11_screen_get_xscreen (screen));
3679
if (action_menu_mapped)
3681
gtk_object_destroy (GTK_OBJECT (action_menu));
3682
action_menu_mapped = FALSE;
3687
ev.xclient.type = ClientMessage;
3688
ev.xclient.display = xdisplay;
3690
ev.xclient.serial = 0;
3691
ev.xclient.send_event = TRUE;
3693
ev.xclient.window = wnck_window_get_xid (win);
3694
ev.xclient.message_type = restack_window_atom;
3695
ev.xclient.format = 32;
3697
ev.xclient.data.l[0] = 2;
3698
ev.xclient.data.l[1] = None;
3699
ev.xclient.data.l[2] = stack_mode;
3700
ev.xclient.data.l[3] = 0;
3701
ev.xclient.data.l[4] = 0;
3703
XSendEvent (xdisplay, xroot, FALSE,
3704
SubstructureRedirectMask | SubstructureNotifyMask,
3707
XSync (xdisplay, FALSE);
3710
/* stolen from gtktooltip.c */
3712
#define DEFAULT_DELAY 500 /* Default delay in ms */
3713
#define STICKY_DELAY 0 /* Delay before popping up next tip
3716
#define STICKY_REVERT_DELAY 1000 /* Delay before sticky tooltips revert
3721
show_tooltip (const char *text)
3723
GdkDisplay *gdkdisplay;
3724
GtkRequisition requisition;
3728
GdkRectangle monitor;
3730
gdkdisplay = gdk_display_get_default ();
3732
gtk_label_set_text (GTK_LABEL (tip_label), text);
3734
gtk_widget_size_request (tip_window, &requisition);
3736
w = requisition.width;
3737
h = requisition.height;
3739
gdk_display_get_pointer (gdkdisplay, &screen, &x, &y, NULL);
3743
monitor_num = gdk_screen_get_monitor_at_point (screen, x, y);
3744
gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
3746
if ((x + w) > monitor.x + monitor.width)
3747
x -= (x + w) - (monitor.x + monitor.width);
3748
else if (x < monitor.x)
3751
if ((y + h + 16) > monitor.y + monitor.height)
3756
gtk_window_move (GTK_WINDOW (tip_window), x, y);
3757
gtk_widget_show (tip_window);
3763
if (GTK_WIDGET_VISIBLE (tip_window))
3764
g_get_current_time (&tooltip_last_popdown);
3766
gtk_widget_hide (tip_window);
3768
if (tooltip_timer_tag)
3770
g_source_remove (tooltip_timer_tag);
3771
tooltip_timer_tag = 0;
3776
tooltip_recently_shown (void)
3781
g_get_current_time (&now);
3783
msec = (now.tv_sec - tooltip_last_popdown.tv_sec) * 1000 +
3784
(now.tv_usec - tooltip_last_popdown.tv_usec) / 1000;
3786
return (msec < STICKY_REVERT_DELAY);
3790
tooltip_timeout (gpointer data)
3792
tooltip_timer_tag = 0;
3794
show_tooltip ((const char *) data);
3800
tooltip_start_delay (const char *text)
3802
guint delay = DEFAULT_DELAY;
3804
if (tooltip_timer_tag)
3807
if (tooltip_recently_shown ())
3808
delay = STICKY_DELAY;
3810
tooltip_timer_tag = g_timeout_add (delay,
3816
tooltip_paint_window (GtkWidget *tooltip)
3820
gtk_widget_size_request (tip_window, &req);
3821
gtk_paint_flat_box (tip_window->style, tip_window->window,
3822
GTK_STATE_NORMAL, GTK_SHADOW_OUT,
3823
NULL, GTK_WIDGET (tip_window), "tooltip",
3824
0, 0, req.width, req.height);
3830
create_tooltip_window (void)
3832
tip_window = gtk_window_new (GTK_WINDOW_POPUP);
3834
gtk_widget_set_app_paintable (tip_window, TRUE);
3835
gtk_window_set_resizable (GTK_WINDOW (tip_window), FALSE);
3836
gtk_widget_set_name (tip_window, "gtk-tooltips");
3837
gtk_container_set_border_width (GTK_CONTAINER (tip_window), 4);
3839
#if GTK_CHECK_VERSION (2, 10, 0)
3840
if (!gtk_check_version (2, 10, 0))
3841
gtk_window_set_type_hint (GTK_WINDOW (tip_window),
3842
GDK_WINDOW_TYPE_HINT_TOOLTIP);
3845
g_signal_connect_swapped (tip_window,
3847
G_CALLBACK (tooltip_paint_window),
3850
tip_label = gtk_label_new (NULL);
3851
gtk_label_set_line_wrap (GTK_LABEL (tip_label), TRUE);
3852
gtk_misc_set_alignment (GTK_MISC (tip_label), 0.5, 0.5);
3853
gtk_widget_show (tip_label);
3855
gtk_container_add (GTK_CONTAINER (tip_window), tip_label);
3857
gtk_widget_ensure_style (tip_window);
3863
handle_tooltip_event (WnckWindow *win,
3868
switch (xevent->type) {
3875
if (!(state & PRESSED_EVENT_WINDOW))
3877
if (wnck_window_is_active (win))
3878
tooltip_start_delay (tip);
3888
close_button_event (WnckWindow *win,
3891
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
3892
guint state = d->button_states[0];
3894
handle_tooltip_event (win, xevent, state, "Close Window");
3896
switch (xevent->type) {
3898
if (xevent->xbutton.button == 1)
3899
d->button_states[0] |= PRESSED_EVENT_WINDOW;
3902
if (xevent->xbutton.button == 1)
3904
if (d->button_states[0] == (PRESSED_EVENT_WINDOW | IN_EVENT_WINDOW))
3905
wnck_window_close (win, xevent->xbutton.time);
3907
d->button_states[0] &= ~PRESSED_EVENT_WINDOW;
3911
d->button_states[0] |= IN_EVENT_WINDOW;
3914
d->button_states[0] &= ~IN_EVENT_WINDOW;
3918
if (state != d->button_states[0])
3919
queue_decor_draw (d);
3923
max_button_event (WnckWindow *win,
3926
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
3927
guint state = d->button_states[1];
3929
if (wnck_window_is_maximized (win))
3930
handle_tooltip_event (win, xevent, state, "Unmaximize Window");
3932
handle_tooltip_event (win, xevent, state, "Maximize Window");
3934
switch (xevent->type) {
3936
if (xevent->xbutton.button == 1)
3937
d->button_states[1] |= PRESSED_EVENT_WINDOW;
3940
if (xevent->xbutton.button == 1)
3942
if (d->button_states[1] == (PRESSED_EVENT_WINDOW | IN_EVENT_WINDOW))
3944
if (wnck_window_is_maximized (win))
3945
wnck_window_unmaximize (win);
3947
wnck_window_maximize (win);
3950
d->button_states[1] &= ~PRESSED_EVENT_WINDOW;
3954
d->button_states[1] |= IN_EVENT_WINDOW;
3957
d->button_states[1] &= ~IN_EVENT_WINDOW;
3961
if (state != d->button_states[1])
3962
queue_decor_draw (d);
3966
min_button_event (WnckWindow *win,
3969
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
3970
guint state = d->button_states[2];
3972
handle_tooltip_event (win, xevent, state, "Minimize Window");
3974
switch (xevent->type) {
3976
if (xevent->xbutton.button == 1)
3977
d->button_states[2] |= PRESSED_EVENT_WINDOW;
3980
if (xevent->xbutton.button == 1)
3982
if (d->button_states[2] == (PRESSED_EVENT_WINDOW | IN_EVENT_WINDOW))
3983
wnck_window_minimize (win);
3985
d->button_states[2] &= ~PRESSED_EVENT_WINDOW;
3989
d->button_states[2] |= IN_EVENT_WINDOW;
3990
if (wnck_window_is_active (win))
3991
tooltip_start_delay ("Minimize Window");
3994
d->button_states[2] &= ~IN_EVENT_WINDOW;
3998
if (state != d->button_states[2])
3999
queue_decor_draw (d);
4003
top_left_event (WnckWindow *win,
4006
if (xevent->xbutton.button == 1)
4007
move_resize_window (win, WM_MOVERESIZE_SIZE_TOPLEFT, xevent);
4011
top_event (WnckWindow *win,
4014
if (xevent->xbutton.button == 1)
4015
move_resize_window (win, WM_MOVERESIZE_SIZE_TOP, xevent);
4019
top_right_event (WnckWindow *win,
4022
if (xevent->xbutton.button == 1)
4023
move_resize_window (win, WM_MOVERESIZE_SIZE_TOPRIGHT, xevent);
4027
left_event (WnckWindow *win,
4030
if (xevent->xbutton.button == 1)
4031
move_resize_window (win, WM_MOVERESIZE_SIZE_LEFT, xevent);
4035
action_menu_unmap (GObject *object)
4037
action_menu_mapped = FALSE;
4041
position_action_menu (GtkMenu *menu,
4047
WnckWindow *win = (WnckWindow *) user_data;
4049
wnck_window_get_geometry (win, x, y, NULL, NULL);
4055
action_menu_map (WnckWindow *win,
4059
GdkDisplay *gdkdisplay;
4062
gdkdisplay = gdk_display_get_default ();
4063
screen = gdk_display_get_default_screen (gdkdisplay);
4067
if (action_menu_mapped)
4069
gtk_widget_destroy (action_menu);
4070
action_menu_mapped = FALSE;
4075
gtk_widget_destroy (action_menu);
4078
switch (wnck_window_get_window_type (win)) {
4079
case WNCK_WINDOW_DESKTOP:
4080
case WNCK_WINDOW_DOCK:
4081
/* don't allow window action */
4083
case WNCK_WINDOW_NORMAL:
4084
case WNCK_WINDOW_DIALOG:
4085
case WNCK_WINDOW_MODAL_DIALOG:
4086
case WNCK_WINDOW_TOOLBAR:
4087
case WNCK_WINDOW_MENU:
4088
case WNCK_WINDOW_UTILITY:
4089
case WNCK_WINDOW_SPLASHSCREEN:
4090
/* allow window action menu */
4094
action_menu = wnck_create_window_action_menu (win);
4096
gtk_menu_set_screen (GTK_MENU (action_menu), screen);
4098
g_signal_connect_object (G_OBJECT (action_menu), "unmap",
4099
G_CALLBACK (action_menu_unmap),
4102
gtk_widget_show (action_menu);
4105
gtk_menu_popup (GTK_MENU (action_menu),
4111
gtk_menu_popup (GTK_MENU (action_menu),
4113
position_action_menu, (gpointer) win,
4117
action_menu_mapped = TRUE;
4127
dist (double x1, double y1,
4128
double x2, double y2)
4130
return sqrt (square (x1 - x2) + square (y1 - y2));
4134
title_event (WnckWindow *win,
4137
static int last_button_num = 0;
4138
static Window last_button_xwindow = None;
4139
static Time last_button_time = 0;
4140
static int last_button_x = 0;
4141
static int last_button_y = 0;
4143
if (xevent->type != ButtonPress)
4146
if (xevent->xbutton.button == 1)
4148
if (xevent->xbutton.button == last_button_num &&
4149
xevent->xbutton.window == last_button_xwindow &&
4150
xevent->xbutton.time < last_button_time + double_click_timeout &&
4151
dist (xevent->xbutton.x, xevent->xbutton.y,
4152
last_button_x, last_button_y) < DOUBLE_CLICK_DISTANCE)
4154
switch (double_click_action) {
4155
case DOUBLE_CLICK_SHADE:
4156
if (wnck_window_is_shaded (win))
4157
wnck_window_unshade (win);
4159
wnck_window_shade (win);
4161
case DOUBLE_CLICK_MAXIMIZE:
4162
if (wnck_window_is_maximized (win))
4163
wnck_window_unmaximize (win);
4165
wnck_window_maximize (win);
4170
last_button_num = 0;
4171
last_button_xwindow = None;
4172
last_button_time = 0;
4178
last_button_num = xevent->xbutton.button;
4179
last_button_xwindow = xevent->xbutton.window;
4180
last_button_time = xevent->xbutton.time;
4181
last_button_x = xevent->xbutton.x;
4182
last_button_y = xevent->xbutton.y;
4184
restack_window (win, Above);
4186
move_resize_window (win, WM_MOVERESIZE_MOVE, xevent);
4189
else if (xevent->xbutton.button == 2)
4191
restack_window (win, Below);
4193
else if (xevent->xbutton.button == 3)
4195
action_menu_map (win,
4196
xevent->xbutton.button,
4197
xevent->xbutton.time);
4202
right_event (WnckWindow *win,
4205
if (xevent->xbutton.button == 1)
4206
move_resize_window (win, WM_MOVERESIZE_SIZE_RIGHT, xevent);
4210
bottom_left_event (WnckWindow *win,
4213
if (xevent->xbutton.button == 1)
4214
move_resize_window (win, WM_MOVERESIZE_SIZE_BOTTOMLEFT, xevent);
4218
bottom_event (WnckWindow *win,
4221
if (xevent->xbutton.button == 1)
4222
move_resize_window (win, WM_MOVERESIZE_SIZE_BOTTOM, xevent);
4226
bottom_right_event (WnckWindow *win,
4229
if (xevent->xbutton.button == 1)
4230
move_resize_window (win, WM_MOVERESIZE_SIZE_BOTTOMRIGHT, xevent);
4234
panel_action (Display *xdisplay,
4241
ev.type = ClientMessage;
4242
ev.xclient.window = root;
4243
ev.xclient.message_type = panel_action_atom;
4244
ev.xclient.format = 32;
4245
ev.xclient.data.l[0] = panel_action;
4246
ev.xclient.data.l[1] = event_time;
4247
ev.xclient.data.l[2] = 0;
4248
ev.xclient.data.l[3] = 0;
4249
ev.xclient.data.l[4] = 0;
4251
XSendEvent (xdisplay, root, FALSE, StructureNotifyMask, &ev);
4255
force_quit_dialog_realize (GtkWidget *dialog,
4258
WnckWindow *win = data;
4260
gdk_error_trap_push ();
4261
XSetTransientForHint (gdk_display,
4262
GDK_WINDOW_XID (dialog->window),
4263
wnck_window_get_xid (win));
4264
XSync (gdk_display, FALSE);
4265
gdk_error_trap_pop ();
4269
get_client_machine (Window xwindow)
4272
gulong nitems, bytes_after;
4277
atom = XInternAtom (gdk_display, "WM_CLIENT_MACHINE", FALSE);
4279
gdk_error_trap_push ();
4281
result = XGetWindowProperty (gdk_display,
4284
FALSE, XA_STRING, &type, &format, &nitems,
4285
&bytes_after, (guchar **) &str);
4287
gdk_error_trap_pop ();
4289
if (result != Success)
4292
if (type != XA_STRING)
4298
retval = g_strdup (str);
4306
kill_window (WnckWindow *win)
4308
WnckApplication *app;
4310
app = wnck_window_get_application (win);
4313
gchar buf[257], *client_machine;
4316
pid = wnck_application_get_pid (app);
4317
client_machine = get_client_machine (wnck_application_get_xid (app));
4319
if (client_machine && pid > 0)
4321
if (gethostname (buf, sizeof (buf) - 1) == 0)
4323
if (strcmp (buf, client_machine) == 0)
4329
g_free (client_machine);
4332
gdk_error_trap_push ();
4333
XKillClient (gdk_display, wnck_window_get_xid (win));
4334
XSync (gdk_display, FALSE);
4335
gdk_error_trap_pop ();
4339
force_quit_dialog_response (GtkWidget *dialog,
4343
WnckWindow *win = data;
4344
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
4346
if (response == GTK_RESPONSE_ACCEPT)
4349
if (d->force_quit_dialog)
4351
d->force_quit_dialog = NULL;
4352
gtk_widget_destroy (dialog);
4357
show_force_quit_dialog (WnckWindow *win,
4360
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
4364
if (d->force_quit_dialog)
4367
tmp = g_markup_escape_text (wnck_window_get_name (win), -1);
4368
str = g_strdup_printf ("The window \"%s\" is not responding.", tmp);
4372
dialog = gtk_message_dialog_new (NULL, 0,
4373
GTK_MESSAGE_WARNING,
4377
"Forcing this application to "
4378
"quit will cause you to lose any "
4379
"unsaved changes.");
4382
gtk_window_set_icon_name (GTK_WINDOW (dialog), "force-quit");
4384
gtk_label_set_use_markup (GTK_LABEL (GTK_MESSAGE_DIALOG (dialog)->label),
4386
gtk_label_set_line_wrap (GTK_LABEL (GTK_MESSAGE_DIALOG (dialog)->label),
4389
gtk_dialog_add_buttons (GTK_DIALOG (dialog),
4391
GTK_RESPONSE_REJECT,
4393
GTK_RESPONSE_ACCEPT,
4396
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT);
4398
g_signal_connect (G_OBJECT (dialog), "realize",
4399
G_CALLBACK (force_quit_dialog_realize),
4402
g_signal_connect (G_OBJECT (dialog), "response",
4403
G_CALLBACK (force_quit_dialog_response),
4406
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
4408
gtk_widget_realize (dialog);
4410
gdk_x11_window_set_user_time (dialog->window, timestamp);
4412
gtk_widget_show (dialog);
4414
d->force_quit_dialog = dialog;
4418
hide_force_quit_dialog (WnckWindow *win)
4420
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
4422
if (d->force_quit_dialog)
4424
gtk_widget_destroy (d->force_quit_dialog);
4425
d->force_quit_dialog = NULL;
4429
/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
4431
convert_property (Display *xdisplay,
4439
Atom conversion_targets[N_TARGETS];
4440
long icccm_version[] = { 2, 0 };
4442
conversion_targets[0] = targets_atom;
4443
conversion_targets[1] = multiple_atom;
4444
conversion_targets[2] = timestamp_atom;
4445
conversion_targets[3] = version_atom;
4447
if (target == targets_atom)
4448
XChangeProperty (xdisplay, w, property,
4449
XA_ATOM, 32, PropModeReplace,
4450
(unsigned char *) conversion_targets, N_TARGETS);
4451
else if (target == timestamp_atom)
4452
XChangeProperty (xdisplay, w, property,
4453
XA_INTEGER, 32, PropModeReplace,
4454
(unsigned char *) &dm_sn_timestamp, 1);
4455
else if (target == version_atom)
4456
XChangeProperty (xdisplay, w, property,
4457
XA_INTEGER, 32, PropModeReplace,
4458
(unsigned char *) icccm_version, 2);
4462
/* Be sure the PropertyNotify has arrived so we
4463
* can send SelectionNotify
4465
XSync (xdisplay, FALSE);
4471
handle_selection_request (Display *xdisplay,
4474
XSelectionEvent reply;
4476
reply.type = SelectionNotify;
4477
reply.display = xdisplay;
4478
reply.requestor = event->xselectionrequest.requestor;
4479
reply.selection = event->xselectionrequest.selection;
4480
reply.target = event->xselectionrequest.target;
4481
reply.property = None;
4482
reply.time = event->xselectionrequest.time;
4484
if (event->xselectionrequest.target == multiple_atom)
4486
if (event->xselectionrequest.property != None)
4490
unsigned long num, rest;
4491
unsigned char *data;
4493
if (XGetWindowProperty (xdisplay,
4494
event->xselectionrequest.requestor,
4495
event->xselectionrequest.property,
4498
&type, &format, &num, &rest,
4502
/* FIXME: to be 100% correct, should deal with rest > 0,
4503
* but since we have 4 possible targets, we will hardly ever
4504
* meet multiple requests with a length > 8
4506
adata = (Atom *) data;
4508
while (i < (int) num)
4510
if (!convert_property (xdisplay,
4511
event->xselectionrequest.requestor,
4512
adata[i], adata[i + 1]))
4513
adata[i + 1] = None;
4518
XChangeProperty (xdisplay,
4519
event->xselectionrequest.requestor,
4520
event->xselectionrequest.property,
4522
32, PropModeReplace, data, num);
4527
if (event->xselectionrequest.property == None)
4528
event->xselectionrequest.property = event->xselectionrequest.target;
4530
if (convert_property (xdisplay,
4531
event->xselectionrequest.requestor,
4532
event->xselectionrequest.target,
4533
event->xselectionrequest.property))
4534
reply.property = event->xselectionrequest.property;
4537
XSendEvent (xdisplay,
4538
event->xselectionrequest.requestor,
4539
FALSE, 0L, (XEvent *) &reply);
4543
handle_selection_clear (Display *xdisplay,
4546
if (xevent->xselectionclear.selection == dm_sn_atom)
4551
acquire_dm_session (Display *xdisplay,
4553
gboolean replace_current_dm)
4556
XSetWindowAttributes attr;
4557
Window current_dm_sn_owner, new_dm_sn_owner;
4560
sprintf (buf, "DM_S%d", screen);
4561
dm_sn_atom = XInternAtom (xdisplay, buf, 0);
4563
current_dm_sn_owner = XGetSelectionOwner (xdisplay, dm_sn_atom);
4565
if (current_dm_sn_owner != None)
4567
if (!replace_current_dm)
4570
"%s: Screen %d on display \"%s\" already "
4571
"has a decoration manager; try using the "
4572
"--replace option to replace the current "
4573
"decoration manager.\n",
4574
program_name, screen, DisplayString (xdisplay));
4579
XSelectInput (xdisplay, current_dm_sn_owner, StructureNotifyMask);
4582
attr.override_redirect = TRUE;
4583
attr.event_mask = PropertyChangeMask;
4586
XCreateWindow (xdisplay, XRootWindow (xdisplay, screen),
4587
-100, -100, 1, 1, 0,
4588
CopyFromParent, CopyFromParent,
4590
CWOverrideRedirect | CWEventMask,
4593
XChangeProperty (xdisplay,
4596
utf8_string_atom, 8,
4598
(unsigned char *) "gwd",
4601
XWindowEvent (xdisplay,
4606
dm_sn_timestamp = event.xproperty.time;
4608
XSetSelectionOwner (xdisplay, dm_sn_atom, new_dm_sn_owner,
4611
if (XGetSelectionOwner (xdisplay, dm_sn_atom) != new_dm_sn_owner)
4614
"%s: Could not acquire decoration manager "
4615
"selection on screen %d display \"%s\"\n",
4616
program_name, screen, DisplayString (xdisplay));
4618
XDestroyWindow (xdisplay, new_dm_sn_owner);
4623
/* Send client message indicating that we are now the DM */
4624
event.xclient.type = ClientMessage;
4625
event.xclient.window = XRootWindow (xdisplay, screen);
4626
event.xclient.message_type = manager_atom;
4627
event.xclient.format = 32;
4628
event.xclient.data.l[0] = dm_sn_timestamp;
4629
event.xclient.data.l[1] = dm_sn_atom;
4630
event.xclient.data.l[2] = 0;
4631
event.xclient.data.l[3] = 0;
4632
event.xclient.data.l[4] = 0;
4634
XSendEvent (xdisplay, XRootWindow (xdisplay, screen), FALSE,
4635
StructureNotifyMask, &event);
4637
/* Wait for old decoration manager to go away */
4638
if (current_dm_sn_owner != None)
4641
XWindowEvent (xdisplay, current_dm_sn_owner,
4642
StructureNotifyMask, &event);
4643
} while (event.type != DestroyNotify);
4649
static GdkFilterReturn
4650
event_filter_func (GdkXEvent *gdkxevent,
4655
GdkDisplay *gdkdisplay;
4656
XEvent *xevent = gdkxevent;
4659
gdkdisplay = gdk_display_get_default ();
4660
xdisplay = GDK_DISPLAY_XDISPLAY (gdkdisplay);
4662
switch (xevent->type) {
4666
g_hash_table_lookup (frame_table,
4667
GINT_TO_POINTER (xevent->xbutton.window));
4672
g_hash_table_lookup (frame_table,
4673
GINT_TO_POINTER (xevent->xcrossing.window));
4677
g_hash_table_lookup (frame_table,
4678
GINT_TO_POINTER (xevent->xmotion.window));
4680
case PropertyNotify:
4681
if (xevent->xproperty.atom == frame_window_atom)
4685
xid = xevent->xproperty.window;
4687
win = wnck_window_get (xid);
4692
if (get_window_prop (xid, frame_window_atom, &frame))
4693
add_frame_window (win, frame);
4695
remove_frame_window (win);
4698
else if (xevent->xproperty.atom == mwm_hints_atom)
4702
xid = xevent->xproperty.window;
4704
win = wnck_window_get (xid);
4707
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
4708
gboolean decorated = FALSE;
4710
if (get_mwm_prop (xid) & (MWM_DECOR_ALL | MWM_DECOR_TITLE))
4713
if (decorated != d->decorated)
4715
d->decorated = decorated;
4718
d->width = d->height = 0;
4720
update_window_decoration_size (win);
4721
update_event_windows (win);
4725
gdk_error_trap_push ();
4726
XDeleteProperty (xdisplay, xid, win_decor_atom);
4727
XSync (xdisplay, FALSE);
4728
gdk_error_trap_pop ();
4733
else if (xevent->xproperty.atom == select_window_atom)
4737
xid = xevent->xproperty.window;
4739
win = wnck_window_get (xid);
4744
if (get_window_prop (xid, select_window_atom, &select))
4745
update_switcher_window (win, select);
4750
g_hash_table_remove (frame_table,
4751
GINT_TO_POINTER (xevent->xproperty.window));
4754
if (xevent->xclient.message_type == toolkit_action_atom)
4758
action = xevent->xclient.data.l[0];
4759
if (action == toolkit_action_main_menu_atom)
4761
panel_action (xdisplay, xevent->xclient.window,
4762
panel_action_main_menu_atom,
4763
xevent->xclient.data.l[1]);
4765
else if (action == toolkit_action_run_dialog_atom)
4767
panel_action (xdisplay, xevent->xclient.window,
4768
panel_action_run_dialog_atom,
4769
xevent->xclient.data.l[1]);
4771
else if (action == toolkit_action_window_menu_atom)
4775
win = wnck_window_get (xevent->xclient.window);
4778
action_menu_map (win,
4779
xevent->xclient.data.l[2],
4780
xevent->xclient.data.l[1]);
4783
else if (action == toolkit_action_force_quit_dialog_atom)
4787
win = wnck_window_get (xevent->xclient.window);
4790
if (xevent->xclient.data.l[2])
4791
show_force_quit_dialog (win,
4792
xevent->xclient.data.l[1]);
4794
hide_force_quit_dialog (win);
4806
win = wnck_window_get (xid);
4809
static event_callback callback[3][3] = {
4810
{ top_left_event, top_event, top_right_event },
4811
{ left_event, title_event, right_event },
4812
{ bottom_left_event, bottom_event, bottom_right_event }
4814
static event_callback button_callback[3] = {
4819
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
4825
for (i = 0; i < 3; i++)
4826
for (j = 0; j < 3; j++)
4827
if (d->event_windows[i][j] == xevent->xany.window)
4828
(*callback[i][j]) (win, xevent);
4830
for (i = 0; i < 3; i++)
4831
if (d->button_windows[i] == xevent->xany.window)
4832
(*button_callback[i]) (win, xevent);
4837
return GDK_FILTER_CONTINUE;
4840
static GdkFilterReturn
4841
selection_event_filter_func (GdkXEvent *gdkxevent,
4846
GdkDisplay *gdkdisplay;
4847
XEvent *xevent = gdkxevent;
4849
gdkdisplay = gdk_display_get_default ();
4850
xdisplay = GDK_DISPLAY_XDISPLAY (gdkdisplay);
4852
switch (xevent->type) {
4853
case SelectionRequest:
4854
handle_selection_request (xdisplay, xevent);
4856
case SelectionClear:
4857
handle_selection_clear (xdisplay, xevent);
4862
return GDK_FILTER_CONTINUE;
4866
/* from clearlooks theme */
4868
rgb_to_hls (gdouble *r,
4909
l = (max + min) / 2;
4916
s = (max - min) / (max + min);
4918
s = (max - min) / (2 - max - min);
4922
h = (green - blue) / delta;
4923
else if (green == max)
4924
h = 2 + (blue - red) / delta;
4925
else if (blue == max)
4926
h = 4 + (red - green) / delta;
4939
hls_to_rgb (gdouble *h,
4952
if (lightness <= 0.5)
4953
m2 = lightness * (1 + saturation);
4955
m2 = lightness + saturation - lightness * saturation;
4957
m1 = 2 * lightness - m2;
4959
if (saturation == 0)
4974
r = m1 + (m2 - m1) * hue / 60;
4978
r = m1 + (m2 - m1) * (240 - hue) / 60;
4989
g = m1 + (m2 - m1) * hue / 60;
4993
g = m1 + (m2 - m1) * (240 - hue) / 60;
5004
b = m1 + (m2 - m1) * hue / 60;
5008
b = m1 + (m2 - m1) * (240 - hue) / 60;
5019
shade (const decor_color_t *a,
5031
rgb_to_hls (&red, &green, &blue);
5036
else if (green < 0.0)
5042
else if (blue < 0.0)
5045
hls_to_rgb (&red, &green, &blue);
5053
update_style (GtkWidget *widget)
5056
decor_color_t spot_color;
5058
style = gtk_widget_get_style (widget);
5059
gtk_style_attach (style, widget->window);
5061
spot_color.r = style->bg[GTK_STATE_SELECTED].red / 65535.0;
5062
spot_color.g = style->bg[GTK_STATE_SELECTED].green / 65535.0;
5063
spot_color.b = style->bg[GTK_STATE_SELECTED].blue / 65535.0;
5065
shade (&spot_color, &_title_color[0], 1.05);
5066
shade (&_title_color[0], &_title_color[1], 0.85);
5069
#if G_MAXINT != G_MAXLONG
5070
/* XRenderSetPictureFilter used to be broken on LP64. This
5071
* works with either the broken or fixed version.
5074
XRenderSetPictureFilter_wrapper (Display *dpy,
5080
gdk_error_trap_push ();
5081
XRenderSetPictureFilter (dpy, picture, filter, params, nparams);
5083
if (gdk_error_trap_pop ())
5085
long *long_params = g_new (long, nparams);
5088
for (i = 0; i < nparams; i++)
5089
long_params[i] = params[i];
5091
XRenderSetPictureFilter (dpy, picture, filter,
5092
(XFixed *) long_params, nparams);
5093
g_free (long_params);
5097
#define XRenderSetPictureFilter XRenderSetPictureFilter_wrapper
5101
set_picture_transform (Display *xdisplay,
5106
XTransform transform = {
5108
{ 1 << 16, 0, -dx << 16 },
5109
{ 0, 1 << 16, -dy << 16 },
5114
XRenderSetPictureTransform (xdisplay, p, &transform);
5118
create_gaussian_kernel (double radius,
5125
double *amp, scale, x_scale, fx, sum;
5126
int size, half_size, x, i, n;
5128
scale = 1.0f / (2.0f * M_PI * sigma * sigma);
5129
half_size = alpha + 0.5f;
5134
size = half_size * 2 + 1;
5135
x_scale = 2.0f * radius / size;
5142
amp = g_malloc (sizeof (double) * n);
5148
params = g_malloc (sizeof (XFixed) * n);
5155
for (x = 0; x < size; x++)
5157
fx = x_scale * (x - half_size);
5159
amp[i] = scale * exp ((-1.0f * (fx * fx)) / (2.0f * sigma * sigma));
5170
params[0] = params[1] = 0;
5172
for (i = 2; i < n; i++)
5173
params[i] = XDoubleToFixed (amp[i - 2] * sum * opacity * 1.2);
5182
/* to save some memory, value is specific to current decorations */
5183
#define CORNER_REDUCTION 3
5185
#define SIGMA(r) ((r) / 2.0)
5186
#define ALPHA(r) (r)
5189
update_shadow (void)
5191
Display *xdisplay = gdk_display;
5192
XRenderPictFormat *format;
5194
Picture src, dst, tmp;
5197
char *filter = NULL;
5198
int size, n_params = 0;
5201
double save_decoration_alpha;
5202
static XRenderColor color = { 0x0000, 0x0000, 0x0000, 0xffff };
5203
static XRenderColor clear = { 0x0000, 0x0000, 0x0000, 0x0000 };
5204
static XRenderColor white = { 0xffff, 0xffff, 0xffff, 0xffff };
5206
/* compute a gaussian convolution kernel */
5207
params = create_gaussian_kernel (shadow_radius,
5208
SIGMA (shadow_radius),
5209
ALPHA (shadow_radius),
5213
shadow_offset_x = shadow_offset_y = size = 0;
5215
if (shadow_radius <= 0.0 && shadow_offset_x == 0 && shadow_offset_y == 0)
5218
n_params = size + 2;
5221
left_space = _win_extents.left + size - shadow_offset_x;
5222
right_space = _win_extents.right + size + shadow_offset_x;
5223
top_space = _win_extents.top + size - shadow_offset_y;
5224
bottom_space = _win_extents.bottom + size + shadow_offset_y;
5226
left_space = MAX (_win_extents.left, left_space);
5227
right_space = MAX (_win_extents.right, right_space);
5228
top_space = MAX (_win_extents.top, top_space);
5229
bottom_space = MAX (_win_extents.bottom, bottom_space);
5231
shadow_left_space = MAX (0, size - shadow_offset_x);
5232
shadow_right_space = MAX (0, size + shadow_offset_x);
5233
shadow_top_space = MAX (0, size - shadow_offset_y);
5234
shadow_bottom_space = MAX (0, size + shadow_offset_y);
5236
shadow_left_corner_space = MAX (0, size + shadow_offset_x);
5237
shadow_right_corner_space = MAX (0, size - shadow_offset_x);
5238
shadow_top_corner_space = MAX (0, size + shadow_offset_y);
5239
shadow_bottom_corner_space = MAX (0, size - shadow_offset_y);
5241
left_corner_space = MAX (0, shadow_left_corner_space - CORNER_REDUCTION);
5242
right_corner_space = MAX (0, shadow_right_corner_space - CORNER_REDUCTION);
5243
top_corner_space = MAX (0, shadow_top_corner_space - CORNER_REDUCTION);
5244
bottom_corner_space =
5245
MAX (0, shadow_bottom_corner_space - CORNER_REDUCTION);
5247
normal_top_corner_space = MAX (0, top_corner_space - titlebar_height);
5248
switcher_top_corner_space = MAX (0, top_corner_space - SWITCHER_TOP_EXTRA);
5249
switcher_bottom_corner_space =
5250
MAX (0, bottom_corner_space - SWITCHER_SPACE);
5252
d.buffer_pixmap = NULL;
5255
d.icon_pixmap = NULL;
5256
d.icon_pixbuf = NULL;
5261
d.draw = theme_draw_window_decoration;
5264
d.width = left_space + left_corner_space + 1 + right_corner_space +
5266
d.height = top_space + titlebar_height + normal_top_corner_space + 2 +
5267
bottom_corner_space + bottom_space;
5269
/* all pixmaps are ARGB32 */
5270
format = XRenderFindStandardFormat (xdisplay, PictStandardARGB32);
5273
src = XRenderCreateSolidFill (xdisplay, &color);
5275
if (large_shadow_pixmap)
5277
gdk_pixmap_unref (large_shadow_pixmap);
5278
large_shadow_pixmap = NULL;
5283
cairo_pattern_destroy (shadow_pattern);
5284
shadow_pattern = NULL;
5289
gdk_pixmap_unref (shadow_pixmap);
5290
shadow_pixmap = NULL;
5302
pixmap = create_pixmap (d.width, d.height);
5309
/* query server for convolution filter */
5310
filters = XRenderQueryFilters (xdisplay, GDK_PIXMAP_XID (pixmap));
5315
for (i = 0; i < filters->nfilter; i++)
5317
if (strcmp (filters->filter[i], FilterConvolution) == 0)
5319
filter = FilterConvolution;
5329
fprintf (stderr, "can't generate shadows, X server doesn't support "
5330
"convolution filters\n");
5333
gdk_pixmap_unref (pixmap);
5338
/* WINDOWS WITH DECORATION */
5340
d.pixmap = create_pixmap (d.width, d.height);
5344
gdk_pixmap_unref (pixmap);
5348
/* create shadow from opaque decoration */
5349
save_decoration_alpha = decoration_alpha;
5350
decoration_alpha = 1.0;
5352
/* draw decorations */
5355
decoration_alpha = save_decoration_alpha;
5357
dst = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (d.pixmap),
5359
tmp = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (pixmap),
5363
params[0] = (n_params - 2) << 16;
5364
params[1] = 1 << 16;
5366
set_picture_transform (xdisplay, dst, shadow_offset_x, 0);
5367
XRenderSetPictureFilter (xdisplay, dst, filter, params, n_params);
5368
XRenderComposite (xdisplay,
5379
params[0] = 1 << 16;
5380
params[1] = (n_params - 2) << 16;
5382
set_picture_transform (xdisplay, tmp, 0, shadow_offset_y);
5383
XRenderSetPictureFilter (xdisplay, tmp, filter, params, n_params);
5384
XRenderComposite (xdisplay,
5394
XRenderFreePicture (xdisplay, tmp);
5395
XRenderFreePicture (xdisplay, dst);
5397
gdk_pixmap_unref (pixmap);
5399
large_shadow_pixmap = d.pixmap;
5401
cr = gdk_cairo_create (GDK_DRAWABLE (large_shadow_pixmap));
5402
shadow_pattern = cairo_pattern_create_for_surface (cairo_get_target (cr));
5403
cairo_pattern_set_filter (shadow_pattern, CAIRO_FILTER_NEAREST);
5407
/* WINDOWS WITHOUT DECORATIONS */
5409
d.width = shadow_left_space + shadow_left_corner_space + 1 +
5410
shadow_right_space + shadow_right_corner_space;
5411
d.height = shadow_top_space + shadow_top_corner_space + 1 +
5412
shadow_bottom_space + shadow_bottom_corner_space;
5414
pixmap = create_pixmap (d.width, d.height);
5421
d.pixmap = create_pixmap (d.width, d.height);
5424
gdk_pixmap_unref (pixmap);
5429
dst = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (d.pixmap),
5432
/* draw rectangle */
5433
XRenderFillRectangle (xdisplay, PictOpSrc, dst, &clear,
5438
XRenderFillRectangle (xdisplay, PictOpSrc, dst, &white,
5441
d.width - shadow_left_space - shadow_right_space,
5442
d.height - shadow_top_space - shadow_bottom_space);
5444
tmp = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (pixmap),
5448
params[0] = (n_params - 2) << 16;
5449
params[1] = 1 << 16;
5451
set_picture_transform (xdisplay, dst, shadow_offset_x, 0);
5452
XRenderSetPictureFilter (xdisplay, dst, filter, params, n_params);
5453
XRenderComposite (xdisplay,
5464
params[0] = 1 << 16;
5465
params[1] = (n_params - 2) << 16;
5467
set_picture_transform (xdisplay, tmp, 0, shadow_offset_y);
5468
XRenderSetPictureFilter (xdisplay, tmp, filter, params, n_params);
5469
XRenderComposite (xdisplay,
5479
XRenderFreePicture (xdisplay, tmp);
5480
XRenderFreePicture (xdisplay, dst);
5481
XRenderFreePicture (xdisplay, src);
5483
gdk_pixmap_unref (pixmap);
5487
shadow_pixmap = d.pixmap;
5493
style_changed (GtkWidget *widget)
5495
GdkDisplay *gdkdisplay;
5496
GdkScreen *gdkscreen;
5500
gdkdisplay = gdk_display_get_default ();
5501
gdkscreen = gdk_display_get_default_screen (gdkdisplay);
5502
screen = wnck_screen_get_default ();
5504
update_style (widget);
5506
update_default_decorations (gdkscreen);
5511
windows = wnck_screen_get_windows (screen);
5512
while (windows != NULL)
5514
decor_t *d = g_object_get_data (G_OBJECT (windows->data), "decor");
5518
/* force size update */
5519
d->width = d->height = 0;
5521
update_window_decoration_size (WNCK_WINDOW (windows->data));
5522
update_event_windows (WNCK_WINDOW (windows->data));
5524
windows = windows->next;
5528
static const PangoFontDescription *
5529
get_titlebar_font (void)
5531
if (use_system_font)
5536
return titlebar_font;
5540
titlebar_font_changed (GConfClient *client)
5544
str = gconf_client_get_string (client,
5545
COMPIZ_TITLEBAR_FONT_KEY,
5548
str = g_strdup ("Sans Bold 12");
5551
pango_font_description_free (titlebar_font);
5553
titlebar_font = pango_font_description_from_string (str);
5559
double_click_titlebar_changed (GConfClient *client)
5563
double_click_action = DOUBLE_CLICK_MAXIMIZE;
5565
action = gconf_client_get_string (client,
5566
COMPIZ_DOUBLE_CLICK_TITLEBAR_KEY,
5570
if (strcmp (action, "toggle_shade") == 0)
5571
double_click_action = DOUBLE_CLICK_SHADE;
5572
else if (strcmp (action, "toggle_maximize") == 0)
5573
double_click_action = DOUBLE_CLICK_MAXIMIZE;
5578
calc_titlebar_height (gint text_height)
5580
return (text_height < 17) ? 17 : text_height;
5585
meta_calc_titlebar_height (gint text_height)
5588
gint top_height, bottom_height, left_width, right_width;
5590
theme = meta_theme_get_current ();
5592
meta_theme_get_frame_borders (theme,
5593
META_FRAME_TYPE_NORMAL,
5600
return top_height - _win_extents.top;
5605
update_titlebar_font (void)
5607
const PangoFontDescription *font_desc;
5608
PangoFontMetrics *metrics;
5609
PangoLanguage *lang;
5611
font_desc = get_titlebar_font ();
5614
GtkStyle *default_style;
5616
default_style = gtk_widget_get_default_style ();
5617
font_desc = default_style->font_desc;
5620
pango_context_set_font_description (pango_context, font_desc);
5622
lang = pango_context_get_language (pango_context);
5623
metrics = pango_context_get_metrics (pango_context, font_desc, lang);
5625
text_height = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
5626
pango_font_metrics_get_descent (metrics));
5628
titlebar_height = (*theme_calc_titlebar_height) (text_height);
5630
pango_font_metrics_unref (metrics);
5634
shadow_settings_changed (GConfClient *client)
5636
double radius, opacity;
5638
gboolean changed = FALSE;
5640
radius = gconf_client_get_float (client,
5641
COMPIZ_SHADOW_RADIUS_KEY,
5643
radius = MAX (0.0, MIN (radius, 48.0));
5644
if (shadow_radius != radius)
5646
shadow_radius = radius;
5650
opacity = gconf_client_get_float (client,
5651
COMPIZ_SHADOW_OPACITY_KEY,
5653
opacity = MAX (0.0, MIN (opacity, 6.0));
5654
if (shadow_opacity != opacity)
5656
shadow_opacity = opacity;
5660
offset = gconf_client_get_int (client,
5661
COMPIZ_SHADOW_OFFSET_X_KEY,
5663
offset = MAX (-16, MIN (offset, 16));
5664
if (shadow_offset_x != offset)
5666
shadow_offset_x = offset;
5670
offset = gconf_client_get_int (client,
5671
COMPIZ_SHADOW_OFFSET_Y_KEY,
5673
offset = MAX (-16, MIN (offset, 16));
5674
if (shadow_offset_y != offset)
5676
shadow_offset_y = offset;
5684
bell_settings_changed (GConfClient *client)
5686
gboolean audible, visual, fullscreen;
5689
audible = gconf_client_get_bool (client,
5690
META_AUDIBLE_BELL_KEY,
5693
visual = gconf_client_get_bool (client,
5694
META_VISUAL_BELL_KEY,
5697
type = gconf_client_get_string (client,
5698
META_VISUAL_BELL_TYPE_KEY,
5701
if (type && strcmp (type, "fullscreen") == 0)
5708
gconf_client_set_bool (client,
5709
COMPIZ_AUDIBLE_BELL_KEY,
5713
gconf_client_set_bool (client,
5714
COMPIZ_VISUAL_BELL_KEY,
5718
gconf_client_set_bool (client,
5719
COMPIZ_FULLSCREEN_VISUAL_BELL_KEY,
5725
theme_changed (GConfClient *client)
5729
gboolean use_meta_theme;
5731
use_meta_theme = gconf_client_get_bool (client,
5739
theme = gconf_client_get_string (client,
5745
meta_theme_set_current (theme, TRUE);
5751
use_meta_theme = FALSE;
5757
theme_draw_window_decoration = meta_draw_window_decoration;
5758
theme_calc_decoration_size = meta_calc_decoration_size;
5759
theme_calc_titlebar_height = meta_calc_titlebar_height;
5763
theme_draw_window_decoration = draw_window_decoration;
5764
theme_calc_decoration_size = calc_decoration_size;
5765
theme_calc_titlebar_height = calc_titlebar_height;
5770
theme_draw_window_decoration = draw_window_decoration;
5771
theme_calc_decoration_size = calc_decoration_size;
5772
theme_calc_titlebar_height = calc_titlebar_height;
5780
value_changed (GConfClient *client,
5785
gboolean changed = FALSE;
5787
if (strcmp (key, COMPIZ_USE_SYSTEM_FONT_KEY) == 0)
5789
if (gconf_client_get_bool (client,
5790
COMPIZ_USE_SYSTEM_FONT_KEY,
5791
NULL) != use_system_font)
5793
use_system_font = !use_system_font;
5797
else if (strcmp (key, COMPIZ_TITLEBAR_FONT_KEY) == 0)
5799
titlebar_font_changed (client);
5800
changed = !use_system_font;
5802
else if (strcmp (key, COMPIZ_DOUBLE_CLICK_TITLEBAR_KEY) == 0)
5804
double_click_titlebar_changed (client);
5806
else if (strcmp (key, COMPIZ_SHADOW_RADIUS_KEY) == 0 ||
5807
strcmp (key, COMPIZ_SHADOW_OPACITY_KEY) == 0 ||
5808
strcmp (key, COMPIZ_SHADOW_OFFSET_X_KEY) == 0 ||
5809
strcmp (key, COMPIZ_SHADOW_OFFSET_Y_KEY) == 0)
5811
if (shadow_settings_changed (client))
5814
else if (strcmp (key, META_AUDIBLE_BELL_KEY) == 0 ||
5815
strcmp (key, META_VISUAL_BELL_KEY) == 0 ||
5816
strcmp (key, META_VISUAL_BELL_TYPE_KEY) == 0)
5818
bell_settings_changed (client);
5820
else if (strcmp (key, USE_META_THEME_KEY) == 0 ||
5821
strcmp (key, META_THEME_KEY) == 0)
5823
if (theme_changed (client))
5829
GdkDisplay *gdkdisplay;
5830
GdkScreen *gdkscreen;
5831
WnckScreen *screen = data;
5834
gdkdisplay = gdk_display_get_default ();
5835
gdkscreen = gdk_display_get_default_screen (gdkdisplay);
5837
update_titlebar_font ();
5840
update_default_decorations (gdkscreen);
5845
windows = wnck_screen_get_windows (screen);
5846
while (windows != NULL)
5848
decor_t *d = g_object_get_data (G_OBJECT (windows->data), "decor");
5852
d->width = d->height = 0;
5855
if (d->draw == draw_window_decoration ||
5856
d->draw == meta_draw_window_decoration)
5857
d->draw = theme_draw_window_decoration;
5860
update_window_decoration_size (WNCK_WINDOW (windows->data));
5861
update_event_windows (WNCK_WINDOW (windows->data));
5863
windows = windows->next;
5869
init_settings (WnckScreen *screen)
5871
GtkSettings *settings;
5873
GdkScreen *gdkscreen;
5874
GdkColormap *colormap;
5876
gconf = gconf_client_get_default ();
5878
gconf_client_add_dir (gconf,
5880
GCONF_CLIENT_PRELOAD_ONELEVEL,
5883
gconf_client_add_dir (gconf,
5885
GCONF_CLIENT_PRELOAD_ONELEVEL,
5888
gconf_client_add_dir (gconf,
5890
GCONF_CLIENT_PRELOAD_ONELEVEL,
5893
gconf_client_add_dir (gconf,
5895
GCONF_CLIENT_PRELOAD_ONELEVEL,
5898
gconf_client_add_dir (gconf,
5900
GCONF_CLIENT_PRELOAD_ONELEVEL,
5903
g_signal_connect (G_OBJECT (gconf),
5905
G_CALLBACK (value_changed),
5908
style_window = gtk_window_new (GTK_WINDOW_POPUP);
5910
gdkscreen = gdk_display_get_default_screen (gdk_display_get_default ());
5911
colormap = gdk_screen_get_rgba_colormap (gdkscreen);
5913
gtk_widget_set_colormap (style_window, colormap);
5915
gtk_widget_realize (style_window);
5917
g_signal_connect_object (style_window, "style-set",
5918
G_CALLBACK (style_changed),
5921
settings = gtk_widget_get_settings (style_window);
5923
g_object_get (G_OBJECT (settings), "gtk-double-click-time",
5924
&double_click_timeout, NULL);
5926
pango_context = gtk_widget_create_pango_context (style_window);
5928
use_system_font = gconf_client_get_bool (gconf,
5929
COMPIZ_USE_SYSTEM_FONT_KEY,
5932
theme_changed (gconf);
5933
update_style (style_window);
5934
titlebar_font_changed (gconf);
5935
update_titlebar_font ();
5936
double_click_titlebar_changed (gconf);
5937
shadow_settings_changed (gconf);
5938
bell_settings_changed (gconf);
5945
main (int argc, char *argv[])
5947
GdkDisplay *gdkdisplay;
5949
GdkScreen *gdkscreen;
5952
gboolean replace = FALSE;
5954
program_name = argv[0];
5956
gtk_init (&argc, &argv);
5958
for (i = 0; i < argc; i++)
5960
if (strcmp (argv[i], "--minimal") == 0)
5964
else if (strcmp (argv[i], "--replace") == 0)
5968
else if (strcmp (argv[i], "--help") == 0)
5970
fprintf (stderr, "%s [--minimal] [--replace] [--help]\n",
5976
gdkdisplay = gdk_display_get_default ();
5977
xdisplay = gdk_x11_display_get_xdisplay (gdkdisplay);
5978
gdkscreen = gdk_display_get_default_screen (gdkdisplay);
5980
frame_window_atom = XInternAtom (xdisplay, "_NET_FRAME_WINDOW", FALSE);
5981
win_decor_atom = XInternAtom (xdisplay, "_NET_WINDOW_DECOR", FALSE);
5982
wm_move_resize_atom = XInternAtom (xdisplay, "_NET_WM_MOVERESIZE", FALSE);
5983
restack_window_atom = XInternAtom (xdisplay, "_NET_RESTACK_WINDOW", FALSE);
5984
select_window_atom = XInternAtom (xdisplay, "_SWITCH_SELECT_WINDOW",
5986
mwm_hints_atom = XInternAtom (xdisplay, "_MOTIF_WM_HINTS", FALSE);
5988
toolkit_action_atom =
5989
XInternAtom (xdisplay, "_COMPIZ_TOOLKIT_ACTION", FALSE);
5990
toolkit_action_main_menu_atom =
5991
XInternAtom (xdisplay, "_COMPIZ_TOOLKIT_ACTION_MAIN_MENU", FALSE);
5992
toolkit_action_run_dialog_atom =
5993
XInternAtom (xdisplay, "_COMPIZ_TOOLKIT_ACTION_RUN_DIALOG", FALSE);
5994
toolkit_action_window_menu_atom =
5995
XInternAtom (xdisplay, "_COMPIZ_TOOLKIT_ACTION_WINDOW_MENU", FALSE);
5996
toolkit_action_force_quit_dialog_atom =
5997
XInternAtom (xdisplay, "_COMPIZ_TOOLKIT_ACTION_FORCE_QUIT_DIALOG",
6001
XInternAtom (xdisplay, "_GNOME_PANEL_ACTION", FALSE);
6002
panel_action_main_menu_atom =
6003
XInternAtom (xdisplay, "_GNOME_PANEL_ACTION_MAIN_MENU", FALSE);
6004
panel_action_run_dialog_atom =
6005
XInternAtom (xdisplay, "_GNOME_PANEL_ACTION_RUN_DIALOG", FALSE);
6007
manager_atom = XInternAtom (xdisplay, "MANAGER", FALSE);
6008
targets_atom = XInternAtom (xdisplay, "TARGETS", FALSE);
6009
multiple_atom = XInternAtom (xdisplay, "MULTIPLE", FALSE);
6010
timestamp_atom = XInternAtom (xdisplay, "TIMESTAMP", FALSE);
6011
version_atom = XInternAtom (xdisplay, "VERSION", FALSE);
6012
atom_pair_atom = XInternAtom (xdisplay, "ATOM_PAIR", FALSE);
6014
utf8_string_atom = XInternAtom (xdisplay, "UTF8_STRING", FALSE);
6016
dm_name_atom = XInternAtom (xdisplay, "_NET_DM_NAME", FALSE);
6018
if (!acquire_dm_session (xdisplay, 0, replace))
6021
for (i = 0; i < 3; i++)
6023
for (j = 0; j < 3; j++)
6025
if (cursor[i][j].shape != XC_left_ptr)
6026
cursor[i][j].cursor =
6027
XCreateFontCursor (xdisplay, cursor[i][j].shape);
6031
frame_table = g_hash_table_new (NULL, NULL);
6033
if (!create_tooltip_window ())
6035
fprintf (stderr, "%s, Couldn't create tooltip window\n", argv[0]);
6039
screen = wnck_screen_get_default ();
6041
gdk_window_add_filter (NULL,
6042
selection_event_filter_func,
6047
gdk_window_add_filter (NULL,
6051
connect_screen (screen);
6054
if (!init_settings (screen))
6056
fprintf (stderr, "%s: Failed to get necessary gtk settings\n", argv[0]);
6060
set_dm_check_hint (gdk_display_get_default_screen (gdkdisplay));
6062
update_default_decorations (gdkscreen);