~vanvugt/compiz-core/fix-963470

« back to all changes in this revision

Viewing changes to gtk/window-decorator/gtk-window-decorator.c

  • Committer: David Reveman
  • Date: 2006-09-22 18:18:44 UTC
  • Revision ID: git-v1:3e7e4b340fb2f7ba4b93534b1b62e8a9ebe02331
Rename gnome directory to gtk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2006 Novell, Inc.
 
3
 *
 
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.
 
8
 *
 
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.
 
13
 *
 
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.
 
18
 */
 
19
 
 
20
#ifdef HAVE_CONFIG_H
 
21
#include <config.h>
 
22
#endif
 
23
 
 
24
#include <X11/Xlib.h>
 
25
#include <X11/Xatom.h>
 
26
#include <X11/cursorfont.h>
 
27
#include <X11/extensions/Xrender.h>
 
28
#include <X11/Xregion.h>
 
29
 
 
30
#ifndef GTK_DISABLE_DEPRECATED
 
31
#define GTK_DISABLE_DEPRECATED
 
32
#endif
 
33
 
 
34
#include <gtk/gtk.h>
 
35
#include <gtk/gtkwindow.h>
 
36
#include <gdk/gdkx.h>
 
37
 
 
38
#include <gconf/gconf-client.h>
 
39
 
 
40
#define WNCK_I_KNOW_THIS_IS_UNSTABLE
 
41
#include <libwnck/libwnck.h>
 
42
#include <libwnck/window-action-menu.h>
 
43
 
 
44
#include <cairo.h>
 
45
#include <cairo-xlib.h>
 
46
 
 
47
#if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 1, 0)
 
48
#define CAIRO_EXTEND_PAD CAIRO_EXTEND_NONE
 
49
#endif
 
50
 
 
51
#include <pango/pango-context.h>
 
52
#include <pango/pangocairo.h>
 
53
 
 
54
#include <string.h>
 
55
#include <stdlib.h>
 
56
#include <math.h>
 
57
#include <limits.h>
 
58
#include <unistd.h>
 
59
#include <sys/types.h>
 
60
#include <signal.h>
 
61
 
 
62
#ifdef USE_METACITY
 
63
#include <metacity-private/theme.h>
 
64
#endif
 
65
 
 
66
#define METACITY_GCONF_DIR "/apps/metacity/general"
 
67
 
 
68
#define COMPIZ_USE_SYSTEM_FONT_KEY                  \
 
69
    METACITY_GCONF_DIR "/titlebar_uses_system_font"
 
70
 
 
71
#define COMPIZ_TITLEBAR_FONT_KEY        \
 
72
    METACITY_GCONF_DIR "/titlebar_font"
 
73
 
 
74
#define COMPIZ_DOUBLE_CLICK_TITLEBAR_KEY               \
 
75
    METACITY_GCONF_DIR "/action_double_click_titlebar"
 
76
 
 
77
#define COMPIZ_GCONF_DIR1 "/apps/compiz/plugins/decoration/allscreens/options"
 
78
 
 
79
#define COMPIZ_SHADOW_RADIUS_KEY \
 
80
    COMPIZ_GCONF_DIR1 "/shadow_radius"
 
81
 
 
82
#define COMPIZ_SHADOW_OPACITY_KEY \
 
83
    COMPIZ_GCONF_DIR1 "/shadow_opacity"
 
84
 
 
85
#define COMPIZ_SHADOW_OFFSET_X_KEY \
 
86
    COMPIZ_GCONF_DIR1 "/shadow_offset_x"
 
87
 
 
88
#define COMPIZ_SHADOW_OFFSET_Y_KEY \
 
89
    COMPIZ_GCONF_DIR1 "/shadow_offset_y"
 
90
 
 
91
#define META_AUDIBLE_BELL_KEY          \
 
92
    METACITY_GCONF_DIR "/audible_bell"
 
93
 
 
94
#define META_VISUAL_BELL_KEY          \
 
95
    METACITY_GCONF_DIR "/visual_bell"
 
96
 
 
97
#define META_VISUAL_BELL_TYPE_KEY          \
 
98
    METACITY_GCONF_DIR "/visual_bell_type"
 
99
 
 
100
#define META_THEME_KEY          \
 
101
    METACITY_GCONF_DIR "/theme"
 
102
 
 
103
#define COMPIZ_GCONF_DIR2 "/apps/compiz/general/allscreens/options"
 
104
 
 
105
#define COMPIZ_AUDIBLE_BELL_KEY       \
 
106
    COMPIZ_GCONF_DIR2 "/audible_bell"
 
107
 
 
108
#define COMPIZ_GCONF_DIR3 "/apps/compiz/plugins/fade/screen0/options"
 
109
 
 
110
#define COMPIZ_VISUAL_BELL_KEY       \
 
111
    COMPIZ_GCONF_DIR3 "/visual_bell"
 
112
 
 
113
#define COMPIZ_FULLSCREEN_VISUAL_BELL_KEY       \
 
114
    COMPIZ_GCONF_DIR3 "/fullscreen_visual_bell"
 
115
 
 
116
#define GCONF_DIR "/apps/gwd"
 
117
 
 
118
#define USE_META_THEME_KEY          \
 
119
    GCONF_DIR "/use_metacity_theme"
 
120
 
 
121
#define STROKE_ALPHA 0.6
 
122
 
 
123
#define ICON_SPACE 20
 
124
 
 
125
#define DOUBLE_CLICK_DISTANCE 8.0
 
126
 
 
127
typedef struct _extents {
 
128
    gint left;
 
129
    gint right;
 
130
    gint top;
 
131
    gint bottom;
 
132
} extents;
 
133
 
 
134
#define GRAVITY_WEST  (1 << 0)
 
135
#define GRAVITY_EAST  (1 << 1)
 
136
#define GRAVITY_NORTH (1 << 2)
 
137
#define GRAVITY_SOUTH (1 << 3)
 
138
 
 
139
#define ALIGN_LEFT   (0)
 
140
#define ALIGN_RIGHT  (1 << 0)
 
141
#define ALIGN_TOP    (0)
 
142
#define ALIGN_BOTTOM (1 << 1)
 
143
 
 
144
#define CLAMP_HORZ (1 << 0)
 
145
#define CLAMP_VERT (1 << 1)
 
146
 
 
147
#define XX_MASK (1 << 12)
 
148
#define XY_MASK (1 << 13)
 
149
#define YX_MASK (1 << 14)
 
150
#define YY_MASK (1 << 15)
 
151
 
 
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
 
163
 
 
164
#define SHADOW_RADIUS   8.0
 
165
#define SHADOW_OPACITY  0.5
 
166
#define SHADOW_OFFSET_X 1
 
167
#define SHADOW_OFFSET_Y 1
 
168
 
 
169
#define N_QUADS_MAX 24
 
170
 
 
171
typedef struct _point {
 
172
    gint x;
 
173
    gint y;
 
174
    gint gravity;
 
175
} point;
 
176
 
 
177
typedef struct _quad {
 
178
    point          p1;
 
179
    point          p2;
 
180
    gint           max_width;
 
181
    gint           max_height;
 
182
    gint           align;
 
183
    gint           clamp;
 
184
    cairo_matrix_t m;
 
185
} quad;
 
186
 
 
187
#define MWM_HINTS_DECORATIONS (1L << 1)
 
188
 
 
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)
 
196
 
 
197
#define PROP_MOTIF_WM_HINT_ELEMENTS 3
 
198
 
 
199
typedef struct {
 
200
    unsigned long flags;
 
201
    unsigned long functions;
 
202
    unsigned long decorations;
 
203
} MwmHints;
 
204
 
 
205
enum {
 
206
    DOUBLE_CLICK_SHADE,
 
207
    DOUBLE_CLICK_MAXIMIZE
 
208
};
 
209
 
 
210
int double_click_action = DOUBLE_CLICK_SHADE;
 
211
 
 
212
static gboolean minimal = FALSE;
 
213
 
 
214
static double decoration_alpha = 0.5;
 
215
 
 
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 };
 
219
 
 
220
#define SWITCHER_SPACE     40
 
221
#define SWITCHER_TOP_EXTRA 4
 
222
 
 
223
static gint left_space   = 6;
 
224
static gint right_space  = 6;
 
225
static gint top_space    = 4;
 
226
static gint bottom_space = 6;
 
227
 
 
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;
 
232
 
 
233
static gint titlebar_height = 17;
 
234
 
 
235
static gint normal_top_corner_space      = 0;
 
236
static gint switcher_top_corner_space    = 0;
 
237
static gint switcher_bottom_corner_space = 0;
 
238
 
 
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;
 
243
 
 
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;
 
248
 
 
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;
 
253
 
 
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;
 
258
 
 
259
static cairo_pattern_t *shadow_pattern = NULL;
 
260
 
 
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;
 
267
 
 
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;
 
273
 
 
274
static Atom panel_action_atom;
 
275
static Atom panel_action_main_menu_atom;
 
276
static Atom panel_action_run_dialog_atom;
 
277
 
 
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;
 
284
 
 
285
static Atom utf8_string_atom;
 
286
 
 
287
static Atom dm_name_atom;
 
288
static Atom dm_sn_atom;
 
289
 
 
290
static Time dm_sn_timestamp;
 
291
 
 
292
#define C(name) { 0, XC_ ## name }
 
293
 
 
294
static struct _cursor {
 
295
    Cursor       cursor;
 
296
    unsigned int shape;
 
297
} cursor[3][3] = {
 
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) }
 
301
};
 
302
 
 
303
static struct _pos {
 
304
    int x, y, w, h;
 
305
    int xw, yh, ww, hh, yth, hth;
 
306
} pos[3][3] = {
 
307
    {
 
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 }
 
311
    }, {
 
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 }
 
315
    }, {
 
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 }
 
319
    }
 
320
}, bpos[3] = {
 
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 }
 
324
};
 
325
 
 
326
typedef struct _decor_color {
 
327
    double r;
 
328
    double g;
 
329
    double b;
 
330
} decor_color_t;
 
331
 
 
332
#define IN_EVENT_WINDOW      (1 << 0)
 
333
#define PRESSED_EVENT_WINDOW (1 << 1)
 
334
 
 
335
typedef struct _decor {
 
336
    Window            event_windows[3][3];
 
337
    Window            button_windows[3];
 
338
    guint             button_states[3];
 
339
    GdkPixmap         *pixmap;
 
340
    GdkPixmap         *buffer_pixmap;
 
341
    GdkGC             *gc;
 
342
    gint              button_width;
 
343
    gint              width;
 
344
    gint              height;
 
345
    gboolean          decorated;
 
346
    gboolean          active;
 
347
    PangoLayout       *layout;
 
348
    gchar             *name;
 
349
    cairo_pattern_t   *icon;
 
350
    GdkPixmap         *icon_pixmap;
 
351
    GdkPixbuf         *icon_pixbuf;
 
352
    WnckWindowState   state;
 
353
    WnckWindowActions actions;
 
354
    XID               prop_xid;
 
355
    GtkWidget         *force_quit_dialog;
 
356
    void              (*draw) (struct _decor *d);
 
357
} decor_t;
 
358
 
 
359
void     (*theme_draw_window_decoration) (decor_t *d);
 
360
gboolean (*theme_calc_decoration_size)   (decor_t *d,
 
361
                                          int     client_width,
 
362
                                          int     client_height,
 
363
                                          int     text_width,
 
364
                                          int     *width,
 
365
                                          int     *height);
 
366
gint     (*theme_calc_titlebar_height)   (gint    text_height);
 
367
 
 
368
typedef void (*event_callback) (WnckWindow *win, XEvent *event);
 
369
 
 
370
static char *program_name;
 
371
 
 
372
static GtkWidget     *style_window;
 
373
 
 
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;
 
380
 
 
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;
 
385
 
 
386
static GSList *draw_list = NULL;
 
387
static guint  draw_idle_id = 0;
 
388
 
 
389
static PangoFontDescription *titlebar_font = NULL;
 
390
static gboolean             use_system_font = FALSE;
 
391
static gint                 text_height;
 
392
 
 
393
static GdkPixmap *switcher_pixmap = NULL;
 
394
static GdkPixmap *switcher_buffer_pixmap = NULL;
 
395
static gint      switcher_width;
 
396
static gint      switcher_height;
 
397
 
 
398
/*
 
399
  decoration property
 
400
  -------------------
 
401
 
 
402
  data[0] = pixmap
 
403
 
 
404
  data[1] = input left
 
405
  data[2] = input right
 
406
  data[3] = input top
 
407
  data[4] = input bottom
 
408
 
 
409
  data[5] = min width
 
410
  data[6] = min height
 
411
 
 
412
  flags
 
413
 
 
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.
 
417
 
 
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
 
427
 */
 
428
static void
 
429
decoration_to_property (long    *data,
 
430
                        Pixmap  pixmap,
 
431
                        extents *input,
 
432
                        int     min_width,
 
433
                        int     min_height,
 
434
                        quad    *quad,
 
435
                        int     nQuad)
 
436
{
 
437
    memcpy (data++, &pixmap, sizeof (Pixmap));
 
438
 
 
439
    *data++ = input->left;
 
440
    *data++ = input->right;
 
441
    *data++ = input->top;
 
442
    *data++ = input->bottom;
 
443
 
 
444
    *data++ = min_width;
 
445
    *data++ = min_height;
 
446
 
 
447
    while (nQuad--)
 
448
    {
 
449
        *data++ =
 
450
            (quad->p1.gravity << 0)    |
 
451
            (quad->p2.gravity << 4)    |
 
452
            (quad->align      << 8)    |
 
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);
 
458
 
 
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;
 
467
 
 
468
        quad++;
 
469
    }
 
470
}
 
471
 
 
472
static gint
 
473
set_horz_quad_line (quad   *q,
 
474
                    int    left,
 
475
                    int    left_corner,
 
476
                    int    right,
 
477
                    int    right_corner,
 
478
                    int    top,
 
479
                    int    bottom,
 
480
                    int    gravity,
 
481
                    int    width,
 
482
                    double x0,
 
483
                    double y0)
 
484
{
 
485
    gint dx, nQuad = 0;
 
486
 
 
487
    dx = (left_corner - right_corner) >> 1;
 
488
 
 
489
    q->p1.x       = -left;
 
490
    q->p1.y       = top;
 
491
    q->p1.gravity = gravity | GRAVITY_WEST;
 
492
    q->p2.x       = dx;
 
493
    q->p2.y       = bottom;
 
494
    q->p2.gravity = gravity;
 
495
    q->max_width  = left + left_corner;
 
496
    q->max_height = SHRT_MAX;
 
497
    q->align      = ALIGN_LEFT;
 
498
    q->clamp      = 0;
 
499
    q->m.xx       = 1.0;
 
500
    q->m.xy       = 0.0;
 
501
    q->m.yx       = 0.0;
 
502
    q->m.yy       = 1.0;
 
503
    q->m.x0       = x0;
 
504
    q->m.y0       = y0;
 
505
 
 
506
    q++; nQuad++;
 
507
 
 
508
    q->p1.x       = left_corner;
 
509
    q->p1.y       = top;
 
510
    q->p1.gravity = gravity | GRAVITY_WEST;
 
511
    q->p2.x       = -right_corner;
 
512
    q->p2.y       = bottom;
 
513
    q->p2.gravity = gravity | GRAVITY_EAST;
 
514
    q->max_width  = SHRT_MAX;
 
515
    q->max_height = SHRT_MAX;
 
516
    q->align      = 0;
 
517
    q->clamp      = 0;
 
518
    q->m.xx       = 0.0;
 
519
    q->m.xy       = 0.0;
 
520
    q->m.yx       = 0.0;
 
521
    q->m.yy       = 1.0;
 
522
    q->m.x0       = x0 + left + left_corner;
 
523
    q->m.y0       = y0;
 
524
 
 
525
    q++; nQuad++;
 
526
 
 
527
    q->p1.x       = dx;
 
528
    q->p1.y       = top;
 
529
    q->p1.gravity = gravity;
 
530
    q->p2.x       = right;
 
531
    q->p2.y       = bottom;
 
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;
 
536
    q->clamp      = 0;
 
537
    q->m.xx       = 1.0;
 
538
    q->m.xy       = 0.0;
 
539
    q->m.yx       = 0.0;
 
540
    q->m.yy       = 1.0;
 
541
    q->m.x0       = x0 + width;
 
542
    q->m.y0       = y0;
 
543
 
 
544
    nQuad++;
 
545
 
 
546
    return nQuad;
 
547
}
 
548
 
 
549
static gint
 
550
set_vert_quad_row (quad   *q,
 
551
                   int    top,
 
552
                   int    top_corner,
 
553
                   int    bottom,
 
554
                   int    bottom_corner,
 
555
                   int    left,
 
556
                   int    right,
 
557
                   int    gravity,
 
558
                   int    height,
 
559
                   double x0,
 
560
                   double y0)
 
561
{
 
562
    gint dy, nQuad = 0;
 
563
 
 
564
    dy = (top_corner - bottom_corner) >> 1;
 
565
 
 
566
    q->p1.x       = left;
 
567
    q->p1.y       = -top;
 
568
    q->p1.gravity = gravity | GRAVITY_NORTH;
 
569
    q->p2.x       = right;
 
570
    q->p2.y       = dy;
 
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;
 
576
    q->m.xx       = 1.0;
 
577
    q->m.xy       = 0.0;
 
578
    q->m.yx       = 0.0;
 
579
    q->m.yy       = 1.0;
 
580
    q->m.x0       = x0;
 
581
    q->m.y0       = y0;
 
582
 
 
583
    q++; nQuad++;
 
584
 
 
585
    q->p1.x       = left;
 
586
    q->p1.y       = top_corner;
 
587
    q->p1.gravity = gravity | GRAVITY_NORTH;
 
588
    q->p2.x       = right;
 
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;
 
593
    q->align      = 0;
 
594
    q->clamp      = CLAMP_VERT;
 
595
    q->m.xx       = 1.0;
 
596
    q->m.xy       = 0.0;
 
597
    q->m.yx       = 0.0;
 
598
    q->m.yy       = 0.0;
 
599
    q->m.x0       = x0;
 
600
    q->m.y0       = y0 + top + top_corner;
 
601
 
 
602
    q++; nQuad++;
 
603
 
 
604
    q->p1.x       = left;
 
605
    q->p1.y       = dy;
 
606
    q->p1.gravity = gravity;
 
607
    q->p2.x       = right;
 
608
    q->p2.y       = bottom;
 
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;
 
614
    q->m.xx       = 1.0;
 
615
    q->m.xy       = 0.0;
 
616
    q->m.yx       = 0.0;
 
617
    q->m.yy       = 1.0;
 
618
    q->m.x0       = x0;
 
619
    q->m.y0       = y0 + height;
 
620
 
 
621
    nQuad++;
 
622
 
 
623
    return nQuad;
 
624
}
 
625
 
 
626
static int
 
627
set_common_window_quads (quad *q,
 
628
                         int  width,
 
629
                         int  height)
 
630
{
 
631
    gint n, nQuad = 0;
 
632
 
 
633
    /* left quads */
 
634
    n = set_vert_quad_row (q,
 
635
                           0,
 
636
                           normal_top_corner_space,
 
637
                           0,
 
638
                           bottom_corner_space,
 
639
                           -left_space,
 
640
                           0,
 
641
                           GRAVITY_WEST,
 
642
                           height - top_space - titlebar_height - bottom_space,
 
643
                           0.0,
 
644
                           top_space + titlebar_height + 1.0);
 
645
 
 
646
    q += n; nQuad += n;
 
647
 
 
648
    /* right quads */
 
649
    n = set_vert_quad_row (q,
 
650
                           0,
 
651
                           normal_top_corner_space,
 
652
                           0,
 
653
                           bottom_corner_space,
 
654
                           0,
 
655
                           right_space,
 
656
                           GRAVITY_EAST,
 
657
                           height - top_space - titlebar_height - bottom_space,
 
658
                           width - right_space,
 
659
                           top_space + titlebar_height + 1.0);
 
660
 
 
661
    q += n; nQuad += n;
 
662
 
 
663
    /* bottom quads */
 
664
    n = set_horz_quad_line (q,
 
665
                            left_space,
 
666
                            left_corner_space,
 
667
                            right_space,
 
668
                            right_corner_space,
 
669
                            0,
 
670
                            bottom_space,
 
671
                            GRAVITY_SOUTH,
 
672
                            width,
 
673
                            0.0,
 
674
                            top_space + titlebar_height +
 
675
                            normal_top_corner_space +
 
676
                            bottom_corner_space + 2.0);
 
677
 
 
678
    nQuad += n;
 
679
 
 
680
    return nQuad;
 
681
}
 
682
 
 
683
static int
 
684
set_window_quads (quad *q,
 
685
                  int  width,
 
686
                  int  height,
 
687
                  int  button_width)
 
688
{
 
689
    gint    n, nQuad = 0;
 
690
    int     top_left, top_right, y;
 
691
    double  y0;
 
692
 
 
693
    top_right = button_width;
 
694
    top_left  = width - left_space - right_space - top_right - 1;
 
695
 
 
696
    /* special case which can happen with large shadows */
 
697
    if (right_corner_space > top_right || left_corner_space > top_left)
 
698
    {
 
699
        y  = -titlebar_height;
 
700
        y0 = top_space;
 
701
 
 
702
        /* top quads */
 
703
        n = set_horz_quad_line (q,
 
704
                                left_space,
 
705
                                left_corner_space,
 
706
                                right_space,
 
707
                                right_corner_space,
 
708
                                -top_space - titlebar_height,
 
709
                                y,
 
710
                                GRAVITY_NORTH,
 
711
                                width,
 
712
                                0.0,
 
713
                                0.0);
 
714
 
 
715
        q += n; nQuad += n;
 
716
    }
 
717
    else
 
718
    {
 
719
        y  = -top_space - titlebar_height;
 
720
        y0 = 0.0;
 
721
    }
 
722
 
 
723
    /* 3 top/titlebar quads */
 
724
    q->p1.x       = -left_space;
 
725
    q->p1.y       = y;
 
726
    q->p1.gravity = GRAVITY_NORTH | GRAVITY_WEST;
 
727
    q->p2.x       = -top_right;
 
728
    q->p2.y       = 0;
 
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;
 
733
    q->clamp      = 0;
 
734
    q->m.xx       = 1.0;
 
735
    q->m.xy       = 0.0;
 
736
    q->m.yx       = 0.0;
 
737
    q->m.yy       = 1.0;
 
738
    q->m.x0       = 0.0;
 
739
    q->m.y0       = y0;
 
740
 
 
741
    q++; nQuad++;
 
742
 
 
743
    q->p1.x       = top_left;
 
744
    q->p1.y       = y;
 
745
    q->p1.gravity = GRAVITY_NORTH | GRAVITY_WEST;
 
746
    q->p2.x       = -top_right;
 
747
    q->p2.y       = 0;
 
748
    q->p2.gravity = GRAVITY_NORTH | GRAVITY_EAST;
 
749
    q->max_width  = SHRT_MAX;
 
750
    q->max_height = SHRT_MAX;
 
751
    q->align      = 0;
 
752
    q->clamp      = 0;
 
753
    q->m.xx       = 0.0;
 
754
    q->m.xy       = 0.0;
 
755
    q->m.yx       = 0.0;
 
756
    q->m.yy       = 1.0;
 
757
    q->m.x0       = left_space + top_left;
 
758
    q->m.y0       = y0;
 
759
 
 
760
    q++; nQuad++;
 
761
 
 
762
    q->p1.x       = 0;
 
763
    q->p1.y       = y;
 
764
    q->p1.gravity = GRAVITY_NORTH | GRAVITY_WEST;
 
765
    q->p2.x       = right_space;
 
766
    q->p2.y       = 0;
 
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;
 
771
    q->clamp      = 0;
 
772
    q->m.xx       = 1.0;
 
773
    q->m.xy       = 0.0;
 
774
    q->m.yx       = 0.0;
 
775
    q->m.yy       = 1.0;
 
776
    q->m.x0       = width;
 
777
    q->m.y0       = y0;
 
778
 
 
779
    q++; nQuad++;
 
780
 
 
781
    n = set_common_window_quads (q, width, height);
 
782
 
 
783
    nQuad += n;
 
784
 
 
785
    return nQuad;
 
786
}
 
787
 
 
788
static int
 
789
set_no_title_window_quads (quad *q,
 
790
                           int  width,
 
791
                           int  height)
 
792
{
 
793
    gint n, nQuad = 0;
 
794
 
 
795
    /* top quads */
 
796
    n = set_horz_quad_line (q,
 
797
                            left_space,
 
798
                            left_corner_space,
 
799
                            right_space,
 
800
                            right_corner_space,
 
801
                            -top_space - titlebar_height,
 
802
                            0,
 
803
                            GRAVITY_NORTH,
 
804
                            width,
 
805
                            0.0,
 
806
                            0.0);
 
807
 
 
808
    q += n; nQuad += n;
 
809
 
 
810
    n = set_common_window_quads (q, width, height);
 
811
 
 
812
    nQuad += n;
 
813
 
 
814
    return nQuad;
 
815
}
 
816
 
 
817
static void
 
818
decor_update_window_property (decor_t *d)
 
819
{
 
820
    long    data[256];
 
821
    Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
 
822
    extents extents = _win_extents;
 
823
    gint    nQuad;
 
824
    quad    quads[N_QUADS_MAX];
 
825
 
 
826
    nQuad = set_window_quads (quads, d->width, d->height, d->button_width);
 
827
 
 
828
    extents.top += titlebar_height;
 
829
 
 
830
    decoration_to_property (data, GDK_PIXMAP_XID (d->pixmap),
 
831
                            &extents,
 
832
                            ICON_SPACE + d->button_width,
 
833
                            0,
 
834
                            quads, nQuad);
 
835
 
 
836
    gdk_error_trap_push ();
 
837
    XChangeProperty (xdisplay, d->prop_xid,
 
838
                     win_decor_atom,
 
839
                     XA_INTEGER,
 
840
                     32, PropModeReplace, (guchar *) data, 7 + 9 * nQuad);
 
841
                     XSync (xdisplay, FALSE);
 
842
    gdk_error_trap_pop ();
 
843
}
 
844
 
 
845
static int
 
846
set_switcher_quads (quad *q,
 
847
                    int  width,
 
848
                    int  height)
 
849
{
 
850
    gint n, nQuad = 0;
 
851
 
 
852
    /* 1 top quads */
 
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;
 
857
    q->p2.y       = 0;
 
858
    q->p2.gravity = GRAVITY_NORTH | GRAVITY_EAST;
 
859
    q->max_width  = SHRT_MAX;
 
860
    q->max_height = SHRT_MAX;
 
861
    q->align      = 0;
 
862
    q->clamp      = 0;
 
863
    q->m.xx       = 1.0;
 
864
    q->m.xy       = 0.0;
 
865
    q->m.yx       = 0.0;
 
866
    q->m.yy       = 1.0;
 
867
    q->m.x0       = 0.0;
 
868
    q->m.y0       = 0.0;
 
869
 
 
870
    q++; nQuad++;
 
871
 
 
872
    /* left quads */
 
873
    n = set_vert_quad_row (q,
 
874
                           0,
 
875
                           switcher_top_corner_space,
 
876
                           0,
 
877
                           bottom_corner_space,
 
878
                           -left_space,
 
879
                           0,
 
880
                           GRAVITY_WEST,
 
881
                           height - top_space - titlebar_height - bottom_space,
 
882
                           0.0,
 
883
                           top_space + SWITCHER_TOP_EXTRA);
 
884
 
 
885
    q += n; nQuad += n;
 
886
 
 
887
    /* right quads */
 
888
    n = set_vert_quad_row (q,
 
889
                           0,
 
890
                           switcher_top_corner_space,
 
891
                           0,
 
892
                           switcher_bottom_corner_space,
 
893
                           0,
 
894
                           right_space,
 
895
                           GRAVITY_EAST,
 
896
                           height - top_space - titlebar_height - bottom_space,
 
897
                           width - right_space,
 
898
                           top_space + SWITCHER_TOP_EXTRA);
 
899
 
 
900
    q += n; nQuad += n;
 
901
 
 
902
    /* 1 bottom quad */
 
903
    q->p1.x       = -left_space;
 
904
    q->p1.y       = 0;
 
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;
 
911
    q->align      = 0;
 
912
    q->clamp      = 0;
 
913
    q->m.xx       = 1.0;
 
914
    q->m.xy       = 0.0;
 
915
    q->m.yx       = 0.0;
 
916
    q->m.yy       = 1.0;
 
917
    q->m.x0       = 0.0;
 
918
    q->m.y0       = height - bottom_space - SWITCHER_SPACE;
 
919
 
 
920
    nQuad++;
 
921
 
 
922
    return nQuad;
 
923
}
 
924
 
 
925
static void
 
926
decor_update_switcher_property (decor_t *d)
 
927
{
 
928
    long    data[256];
 
929
    Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
 
930
    gint    nQuad;
 
931
    quad    quads[N_QUADS_MAX];
 
932
    extents extents = _switcher_extents;
 
933
 
 
934
    nQuad = set_switcher_quads (quads, d->width, d->height);
 
935
 
 
936
    decoration_to_property (data, GDK_PIXMAP_XID (d->pixmap),
 
937
                            &extents, 0, 0, quads, nQuad);
 
938
 
 
939
    gdk_error_trap_push ();
 
940
    XChangeProperty (xdisplay, d->prop_xid,
 
941
                     win_decor_atom,
 
942
                     XA_INTEGER,
 
943
                     32, PropModeReplace, (guchar *) data, 7 + 9 * nQuad);
 
944
    XSync (xdisplay, FALSE);
 
945
    gdk_error_trap_pop ();
 
946
}
 
947
 
 
948
static int
 
949
set_shadow_quads (quad *q,
 
950
                  gint width,
 
951
                  gint height)
 
952
{
 
953
    gint n, nQuad = 0;
 
954
 
 
955
    /* top quads */
 
956
    n = set_horz_quad_line (q,
 
957
                            shadow_left_space,
 
958
                            shadow_left_corner_space,
 
959
                            shadow_right_space,
 
960
                            shadow_right_corner_space,
 
961
                            -shadow_top_space,
 
962
                            0,
 
963
                            GRAVITY_NORTH,
 
964
                            width,
 
965
                            0.0,
 
966
                            0.0);
 
967
 
 
968
    q += n; nQuad += n;
 
969
 
 
970
    /* left quads */
 
971
    n = set_vert_quad_row (q,
 
972
                           0,
 
973
                           shadow_top_corner_space,
 
974
                           0,
 
975
                           shadow_bottom_corner_space,
 
976
                           -shadow_left_space,
 
977
                           0,
 
978
                           GRAVITY_WEST,
 
979
                           height - shadow_top_space - shadow_bottom_space,
 
980
                           0.0,
 
981
                           shadow_top_space);
 
982
 
 
983
    q += n; nQuad += n;
 
984
 
 
985
    /* right quads */
 
986
    n = set_vert_quad_row (q,
 
987
                           0,
 
988
                           shadow_top_corner_space,
 
989
                           0,
 
990
                           shadow_bottom_corner_space,
 
991
                           0,
 
992
                           shadow_right_space,
 
993
                           GRAVITY_EAST,
 
994
                           height - shadow_top_space - shadow_bottom_space,
 
995
                           width - shadow_right_space,
 
996
                           shadow_top_space);
 
997
 
 
998
    q += n; nQuad += n;
 
999
 
 
1000
    /* bottom quads */
 
1001
    n = set_horz_quad_line (q,
 
1002
                            shadow_left_space,
 
1003
                            shadow_left_corner_space,
 
1004
                            shadow_right_space,
 
1005
                            shadow_right_corner_space,
 
1006
                            0,
 
1007
                            shadow_bottom_space,
 
1008
                            GRAVITY_SOUTH,
 
1009
                            width,
 
1010
                            0.0,
 
1011
                            shadow_top_space + shadow_top_corner_space +
 
1012
                            shadow_bottom_corner_space + 1.0);
 
1013
 
 
1014
    nQuad += n;
 
1015
 
 
1016
    return nQuad;
 
1017
}
 
1018
 
 
1019
static void
 
1020
gdk_cairo_set_source_color_alpha (cairo_t  *cr,
 
1021
                                  GdkColor *color,
 
1022
                                  double   alpha)
 
1023
{
 
1024
    cairo_set_source_rgba (cr,
 
1025
                           color->red   / 65535.0,
 
1026
                           color->green / 65535.0,
 
1027
                           color->blue  / 65535.0,
 
1028
                           alpha);
 
1029
}
 
1030
 
 
1031
#define CORNER_TOPLEFT     (1 << 0)
 
1032
#define CORNER_TOPRIGHT    (1 << 1)
 
1033
#define CORNER_BOTTOMRIGHT (1 << 2)
 
1034
#define CORNER_BOTTOMLEFT  (1 << 3)
 
1035
 
 
1036
static void
 
1037
rounded_rectangle (cairo_t *cr,
 
1038
                   double  x,
 
1039
                   double  y,
 
1040
                   double  w,
 
1041
                   double  h,
 
1042
                   double  radius,
 
1043
                   int     corner)
 
1044
{
 
1045
    if (corner & CORNER_TOPLEFT)
 
1046
        cairo_move_to (cr, x + radius, y);
 
1047
    else
 
1048
        cairo_move_to (cr, x, y);
 
1049
 
 
1050
    if (corner & CORNER_TOPRIGHT)
 
1051
        cairo_arc (cr, x + w - radius, y + radius, radius,
 
1052
                   M_PI * 1.5, M_PI * 2.0);
 
1053
    else
 
1054
        cairo_line_to (cr, x + w, y);
 
1055
 
 
1056
    if (corner & CORNER_BOTTOMRIGHT)
 
1057
        cairo_arc (cr, x + w - radius, y + h - radius, radius,
 
1058
                   0.0, M_PI * 0.5);
 
1059
    else
 
1060
        cairo_line_to (cr, x + w, y + h);
 
1061
 
 
1062
    if (corner & CORNER_BOTTOMLEFT)
 
1063
        cairo_arc (cr, x + radius, y + h - radius, radius,
 
1064
                   M_PI * 0.5, M_PI);
 
1065
    else
 
1066
        cairo_line_to (cr, x, y + h);
 
1067
 
 
1068
    if (corner & CORNER_TOPLEFT)
 
1069
        cairo_arc (cr, x + radius, y + radius, radius, M_PI, M_PI * 1.5);
 
1070
    else
 
1071
        cairo_line_to (cr, x, y);
 
1072
}
 
1073
 
 
1074
#define SHADE_LEFT   (1 << 0)
 
1075
#define SHADE_RIGHT  (1 << 1)
 
1076
#define SHADE_TOP    (1 << 2)
 
1077
#define SHADE_BOTTOM (1 << 3)
 
1078
 
 
1079
static void
 
1080
fill_rounded_rectangle (cairo_t       *cr,
 
1081
                        double        x,
 
1082
                        double        y,
 
1083
                        double        w,
 
1084
                        double        h,
 
1085
                        double        radius,
 
1086
                        int           corner,
 
1087
                        decor_color_t *c0,
 
1088
                        double        alpha0,
 
1089
                        decor_color_t *c1,
 
1090
                        double        alpha1,
 
1091
                        int           gravity)
 
1092
{
 
1093
    cairo_pattern_t *pattern;
 
1094
 
 
1095
    rounded_rectangle (cr, x, y, w, h, radius, corner);
 
1096
 
 
1097
    if (gravity & SHADE_RIGHT)
 
1098
    {
 
1099
        x = x + w;
 
1100
        w = -w;
 
1101
    }
 
1102
    else if (!(gravity & SHADE_LEFT))
 
1103
    {
 
1104
        x = w = 0;
 
1105
    }
 
1106
 
 
1107
    if (gravity & SHADE_BOTTOM)
 
1108
    {
 
1109
        y = y + h;
 
1110
        h = -h;
 
1111
    }
 
1112
    else if (!(gravity & SHADE_TOP))
 
1113
    {
 
1114
        y = h = 0;
 
1115
    }
 
1116
 
 
1117
    if (w && h)
 
1118
    {
 
1119
        cairo_matrix_t matrix;
 
1120
 
 
1121
        pattern = cairo_pattern_create_radial (0.0, 0.0, 0.0, 0.0, 0.0, w);
 
1122
 
 
1123
        cairo_matrix_init_scale (&matrix, 1.0, w / h);
 
1124
        cairo_matrix_translate (&matrix, -(x + w), -(y + h));
 
1125
 
 
1126
        cairo_pattern_set_matrix (pattern, &matrix);
 
1127
    }
 
1128
    else
 
1129
    {
 
1130
        pattern = cairo_pattern_create_linear (x + w, y + h, x, y);
 
1131
    }
 
1132
 
 
1133
    cairo_pattern_add_color_stop_rgba (pattern, 0.0, c0->r, c0->g, c0->b,
 
1134
                                       alpha0);
 
1135
 
 
1136
    cairo_pattern_add_color_stop_rgba (pattern, 1.0, c1->r, c1->g, c1->b,
 
1137
                                       alpha1);
 
1138
 
 
1139
    cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
 
1140
 
 
1141
    cairo_set_source (cr, pattern);
 
1142
    cairo_fill (cr);
 
1143
    cairo_pattern_destroy (pattern);
 
1144
}
 
1145
 
 
1146
static void
 
1147
draw_shadow_background (decor_t *d,
 
1148
                        cairo_t *cr)
 
1149
{
 
1150
    cairo_matrix_t matrix;
 
1151
    double         w, h, x2, y2;
 
1152
    gint           width, height;
 
1153
    gint           left, right, top, bottom;
 
1154
 
 
1155
    if (!large_shadow_pixmap)
 
1156
    {
 
1157
        cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
 
1158
        cairo_paint (cr);
 
1159
 
 
1160
        return;
 
1161
    }
 
1162
 
 
1163
    gdk_drawable_get_size (large_shadow_pixmap, &width, &height);
 
1164
 
 
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;
 
1169
 
 
1170
    if (d->width - left - right < 0)
 
1171
    {
 
1172
        left = d->width / 2;
 
1173
        right = d->width - left;
 
1174
    }
 
1175
 
 
1176
    if (d->height - top - bottom < 0)
 
1177
    {
 
1178
        top = d->height / 2;
 
1179
        bottom = d->height - top;
 
1180
    }
 
1181
 
 
1182
    w = d->width - left - right;
 
1183
    h = d->height - top - bottom;
 
1184
 
 
1185
    x2 = d->width - right;
 
1186
    y2 = d->height - bottom;
 
1187
 
 
1188
    /* top left */
 
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);
 
1193
    cairo_fill (cr);
 
1194
 
 
1195
    /* top */
 
1196
    if (w > 0)
 
1197
    {
 
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);
 
1204
        cairo_fill (cr);
 
1205
    }
 
1206
 
 
1207
    /* top right */
 
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);
 
1212
    cairo_fill (cr);
 
1213
 
 
1214
    /* left */
 
1215
    if (h > 0)
 
1216
    {
 
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);
 
1223
        cairo_fill (cr);
 
1224
    }
 
1225
 
 
1226
    /* right */
 
1227
    if (h > 0)
 
1228
    {
 
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);
 
1235
        cairo_fill (cr);
 
1236
    }
 
1237
 
 
1238
    /* bottom left */
 
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);
 
1243
    cairo_fill (cr);
 
1244
 
 
1245
    /* bottom */
 
1246
    if (w > 0)
 
1247
    {
 
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);
 
1255
        cairo_fill (cr);
 
1256
    }
 
1257
 
 
1258
    /* bottom right */
 
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);
 
1264
    cairo_fill (cr);
 
1265
}
 
1266
 
 
1267
static void
 
1268
draw_close_button (decor_t *d,
 
1269
                   cairo_t *cr,
 
1270
                   double  s)
 
1271
{
 
1272
    cairo_rel_move_to (cr, 0.0, s);
 
1273
 
 
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);
 
1278
 
 
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);
 
1283
 
 
1284
    cairo_rel_line_to (cr, -s, s);
 
1285
    cairo_rel_line_to (cr, -s, -s);
 
1286
    cairo_rel_line_to (cr, s, -s);
 
1287
 
 
1288
    cairo_close_path (cr);
 
1289
}
 
1290
 
 
1291
static void
 
1292
draw_max_button (decor_t *d,
 
1293
                 cairo_t *cr,
 
1294
                 double  s)
 
1295
{
 
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);
 
1299
 
 
1300
    cairo_close_path (cr);
 
1301
 
 
1302
    cairo_rel_move_to (cr, 2.0, s);
 
1303
 
 
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);
 
1307
 
 
1308
    cairo_close_path (cr);
 
1309
}
 
1310
 
 
1311
static void
 
1312
draw_unmax_button (decor_t *d,
 
1313
                   cairo_t *cr,
 
1314
                   double  s)
 
1315
{
 
1316
    cairo_rel_move_to (cr, 1.0, 1.0);
 
1317
 
 
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);
 
1321
 
 
1322
    cairo_close_path (cr);
 
1323
 
 
1324
    cairo_rel_move_to (cr, 2.0, s);
 
1325
 
 
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);
 
1329
 
 
1330
    cairo_close_path (cr);
 
1331
}
 
1332
 
 
1333
static void
 
1334
draw_min_button (decor_t *d,
 
1335
                 cairo_t *cr,
 
1336
                 double  s)
 
1337
{
 
1338
    cairo_rel_move_to (cr, 0.0, 8.0);
 
1339
 
 
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);
 
1343
 
 
1344
    cairo_close_path (cr);
 
1345
}
 
1346
 
 
1347
typedef void (*draw_proc) (cairo_t *cr);
 
1348
 
 
1349
static void
 
1350
button_state_offsets (gdouble x,
 
1351
                      gdouble y,
 
1352
                      guint   state,
 
1353
                      gdouble *return_x,
 
1354
                      gdouble *return_y)
 
1355
{
 
1356
    static double off[] = { 0.0, 0.0, 0.0, 0.5 };
 
1357
 
 
1358
    *return_x  = x + off[state];
 
1359
    *return_y  = y + off[state];
 
1360
}
 
1361
 
 
1362
static void
 
1363
button_state_paint (cairo_t       *cr,
 
1364
                    GtkStyle      *style,
 
1365
                    decor_color_t *color,
 
1366
                    guint         state)
 
1367
{
 
1368
 
 
1369
#define IN_STATE (PRESSED_EVENT_WINDOW | IN_EVENT_WINDOW)
 
1370
 
 
1371
    if ((state & IN_STATE) == IN_STATE)
 
1372
    {
 
1373
        if (state & IN_EVENT_WINDOW)
 
1374
            cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
 
1375
        else
 
1376
            cairo_set_source_rgba (cr, color->r, color->g, color->b, 0.95);
 
1377
 
 
1378
        cairo_fill_preserve (cr);
 
1379
 
 
1380
        gdk_cairo_set_source_color_alpha (cr,
 
1381
                                          &style->fg[GTK_STATE_NORMAL],
 
1382
                                          STROKE_ALPHA);
 
1383
 
 
1384
        cairo_set_line_width (cr, 1.0);
 
1385
        cairo_stroke (cr);
 
1386
        cairo_set_line_width (cr, 2.0);
 
1387
    }
 
1388
    else
 
1389
    {
 
1390
        gdk_cairo_set_source_color_alpha (cr,
 
1391
                                          &style->fg[GTK_STATE_NORMAL],
 
1392
                                          STROKE_ALPHA);
 
1393
        cairo_stroke_preserve (cr);
 
1394
 
 
1395
        if (state & IN_EVENT_WINDOW)
 
1396
            cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
 
1397
        else
 
1398
            cairo_set_source_rgba (cr, color->r, color->g, color->b, 0.95);
 
1399
 
 
1400
        cairo_fill (cr);
 
1401
    }
 
1402
}
 
1403
 
 
1404
static void
 
1405
draw_window_decoration (decor_t *d)
 
1406
{
 
1407
    cairo_t       *cr;
 
1408
    GtkStyle      *style;
 
1409
    decor_color_t color;
 
1410
    double        alpha;
 
1411
    double        x1, y1, x2, y2, x, y, h;
 
1412
    int           corners = SHADE_LEFT | SHADE_RIGHT | SHADE_TOP | SHADE_BOTTOM;
 
1413
    int           top;
 
1414
    int           button_x;
 
1415
 
 
1416
    if (!d->pixmap)
 
1417
        return;
 
1418
 
 
1419
    style = gtk_widget_get_style (style_window);
 
1420
 
 
1421
    if (d->state & (WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY |
 
1422
                    WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY))
 
1423
        corners = 0;
 
1424
 
 
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;
 
1428
 
 
1429
    if (d->buffer_pixmap)
 
1430
        cr = gdk_cairo_create (GDK_DRAWABLE (d->buffer_pixmap));
 
1431
    else
 
1432
        cr = gdk_cairo_create (GDK_DRAWABLE (d->pixmap));
 
1433
 
 
1434
    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 
1435
 
 
1436
    top = _win_extents.top + titlebar_height;
 
1437
 
 
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;
 
1442
 
 
1443
    h = d->height - top_space - titlebar_height - bottom_space;
 
1444
 
 
1445
    cairo_set_line_width (cr, 1.0);
 
1446
 
 
1447
    draw_shadow_background (d, cr);
 
1448
 
 
1449
    if (d->active)
 
1450
    {
 
1451
        decor_color_t *title_color = _title_color;
 
1452
 
 
1453
        alpha = decoration_alpha + 0.3;
 
1454
 
 
1455
        fill_rounded_rectangle (cr,
 
1456
                                x1 + 0.5,
 
1457
                                y1 + 0.5,
 
1458
                                _win_extents.left - 0.5,
 
1459
                                top - 0.5,
 
1460
                                5.0, CORNER_TOPLEFT & corners,
 
1461
                                &title_color[0], 1.0, &title_color[1], alpha,
 
1462
                                SHADE_TOP | SHADE_LEFT);
 
1463
 
 
1464
        fill_rounded_rectangle (cr,
 
1465
                                x1 + _win_extents.left,
 
1466
                                y1 + 0.5,
 
1467
                                x2 - x1 - _win_extents.left -
 
1468
                                _win_extents.right,
 
1469
                                top - 0.5,
 
1470
                                5.0, 0,
 
1471
                                &title_color[0], 1.0, &title_color[1], alpha,
 
1472
                                SHADE_TOP);
 
1473
 
 
1474
        fill_rounded_rectangle (cr,
 
1475
                                x2 - _win_extents.right,
 
1476
                                y1 + 0.5,
 
1477
                                _win_extents.right - 0.5,
 
1478
                                top - 0.5,
 
1479
                                5.0, CORNER_TOPRIGHT & corners,
 
1480
                                &title_color[0], 1.0, &title_color[1], alpha,
 
1481
                                SHADE_TOP | SHADE_RIGHT);
 
1482
    }
 
1483
    else
 
1484
    {
 
1485
        alpha = decoration_alpha;
 
1486
 
 
1487
        fill_rounded_rectangle (cr,
 
1488
                                x1 + 0.5,
 
1489
                                y1 + 0.5,
 
1490
                                _win_extents.left - 0.5,
 
1491
                                top - 0.5,
 
1492
                                5.0, CORNER_TOPLEFT & corners,
 
1493
                                &color, 1.0, &color, alpha,
 
1494
                                SHADE_TOP | SHADE_LEFT);
 
1495
 
 
1496
        fill_rounded_rectangle (cr,
 
1497
                                x1 + _win_extents.left,
 
1498
                                y1 + 0.5,
 
1499
                                x2 - x1 - _win_extents.left -
 
1500
                                _win_extents.right,
 
1501
                                top - 0.5,
 
1502
                                5.0, 0,
 
1503
                                &color, 1.0, &color, alpha,
 
1504
                                SHADE_TOP);
 
1505
 
 
1506
        fill_rounded_rectangle (cr,
 
1507
                                x2 - _win_extents.right,
 
1508
                                y1 + 0.5,
 
1509
                                _win_extents.right - 0.5,
 
1510
                                top - 0.5,
 
1511
                                5.0, CORNER_TOPRIGHT & corners,
 
1512
                                &color, 1.0, &color, alpha,
 
1513
                                SHADE_TOP | SHADE_RIGHT);
 
1514
    }
 
1515
 
 
1516
    fill_rounded_rectangle (cr,
 
1517
                            x1 + 0.5,
 
1518
                            y1 + top,
 
1519
                            _win_extents.left - 0.5,
 
1520
                            h,
 
1521
                            5.0, 0,
 
1522
                            &color, 1.0, &color, alpha,
 
1523
                            SHADE_LEFT);
 
1524
 
 
1525
    fill_rounded_rectangle (cr,
 
1526
                            x2 - _win_extents.right,
 
1527
                            y1 + top,
 
1528
                            _win_extents.right - 0.5,
 
1529
                            h,
 
1530
                            5.0, 0,
 
1531
                            &color, 1.0, &color, alpha,
 
1532
                            SHADE_RIGHT);
 
1533
 
 
1534
 
 
1535
    fill_rounded_rectangle (cr,
 
1536
                            x1 + 0.5,
 
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);
 
1543
 
 
1544
    fill_rounded_rectangle (cr,
 
1545
                            x1 + _win_extents.left,
 
1546
                            y2 - _win_extents.bottom,
 
1547
                            x2 - x1 - _win_extents.left -
 
1548
                            _win_extents.right,
 
1549
                            _win_extents.bottom - 0.5,
 
1550
                            5.0, 0,
 
1551
                            &color, 1.0, &color, alpha,
 
1552
                            SHADE_BOTTOM);
 
1553
 
 
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);
 
1562
 
 
1563
    cairo_rectangle (cr,
 
1564
                     left_space,
 
1565
                     titlebar_height + top_space,
 
1566
                     d->width - left_space - right_space,
 
1567
                     h);
 
1568
    gdk_cairo_set_source_color (cr, &style->bg[GTK_STATE_NORMAL]);
 
1569
    cairo_fill (cr);
 
1570
 
 
1571
    cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
 
1572
 
 
1573
    if (d->active)
 
1574
    {
 
1575
        gdk_cairo_set_source_color_alpha (cr,
 
1576
                                          &style->fg[GTK_STATE_NORMAL],
 
1577
                                          0.7);
 
1578
 
 
1579
        cairo_move_to (cr, x1 + 0.5, y1 + top - 0.5);
 
1580
        cairo_rel_line_to (cr, x2 - x1 - 1.0, 0.0);
 
1581
 
 
1582
        cairo_stroke (cr);
 
1583
    }
 
1584
 
 
1585
    rounded_rectangle (cr,
 
1586
                       x1 + 0.5, y1 + 0.5,
 
1587
                       x2 - x1 - 1.0, y2 - y1 - 1.0,
 
1588
                       5.0,
 
1589
                       (CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
 
1590
                        CORNER_BOTTOMRIGHT) & corners);
 
1591
 
 
1592
    cairo_clip (cr);
 
1593
 
 
1594
    cairo_translate (cr, 1.0, 1.0);
 
1595
 
 
1596
    rounded_rectangle (cr,
 
1597
                       x1 + 0.5, y1 + 0.5,
 
1598
                       x2 - x1 - 1.0, y2 - y1 - 1.0,
 
1599
                       5.0,
 
1600
                       (CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
 
1601
                        CORNER_BOTTOMRIGHT) & corners);
 
1602
 
 
1603
    cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.4);
 
1604
    cairo_stroke (cr);
 
1605
 
 
1606
    cairo_translate (cr, -2.0, -2.0);
 
1607
 
 
1608
    rounded_rectangle (cr,
 
1609
                       x1 + 0.5, y1 + 0.5,
 
1610
                       x2 - x1 - 1.0, y2 - y1 - 1.0,
 
1611
                       5.0,
 
1612
                       (CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
 
1613
                        CORNER_BOTTOMRIGHT) & corners);
 
1614
 
 
1615
    cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.1);
 
1616
    cairo_stroke (cr);
 
1617
 
 
1618
    cairo_translate (cr, 1.0, 1.0);
 
1619
 
 
1620
    cairo_reset_clip (cr);
 
1621
 
 
1622
    rounded_rectangle (cr,
 
1623
                       x1 + 0.5, y1 + 0.5,
 
1624
                       x2 - x1 - 1.0, y2 - y1 - 1.0,
 
1625
                       5.0,
 
1626
                       (CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
 
1627
                        CORNER_BOTTOMRIGHT) & corners);
 
1628
 
 
1629
    gdk_cairo_set_source_color_alpha (cr,
 
1630
                                      &style->fg[GTK_STATE_NORMAL],
 
1631
                                      alpha);
 
1632
 
 
1633
    cairo_stroke (cr);
 
1634
 
 
1635
    cairo_set_line_width (cr, 2.0);
 
1636
 
 
1637
    button_x = d->width - right_space - 13;
 
1638
 
 
1639
    if (d->actions & WNCK_WINDOW_ACTION_CLOSE)
 
1640
    {
 
1641
        button_state_offsets (button_x,
 
1642
                              y1 - 3.0 + titlebar_height / 2,
 
1643
                              d->button_states[0], &x, &y);
 
1644
 
 
1645
        button_x -= 17;
 
1646
 
 
1647
        if (d->active)
 
1648
        {
 
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]);
 
1652
        }
 
1653
        else
 
1654
        {
 
1655
            gdk_cairo_set_source_color_alpha (cr,
 
1656
                                              &style->fg[GTK_STATE_NORMAL],
 
1657
                                              alpha * 0.75);
 
1658
            cairo_move_to (cr, x, y);
 
1659
            draw_close_button (d, cr, 3.0);
 
1660
            cairo_fill (cr);
 
1661
        }
 
1662
    }
 
1663
 
 
1664
    if (d->actions & WNCK_WINDOW_ACTION_MAXIMIZE)
 
1665
    {
 
1666
        button_state_offsets (button_x,
 
1667
                              y1 - 3.0 + titlebar_height / 2,
 
1668
                              d->button_states[1], &x, &y);
 
1669
 
 
1670
        button_x -= 17;
 
1671
 
 
1672
        cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
 
1673
 
 
1674
        if (d->active)
 
1675
        {
 
1676
            gdk_cairo_set_source_color_alpha (cr,
 
1677
                                              &style->fg[GTK_STATE_NORMAL],
 
1678
                                              STROKE_ALPHA);
 
1679
            cairo_move_to (cr, x, y);
 
1680
 
 
1681
            if (d->state & (WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY |
 
1682
                            WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY))
 
1683
                draw_unmax_button (d, cr, 4.0);
 
1684
            else
 
1685
                draw_max_button (d, cr, 4.0);
 
1686
 
 
1687
            button_state_paint (cr, style, &color, d->button_states[1]);
 
1688
        }
 
1689
        else
 
1690
        {
 
1691
            gdk_cairo_set_source_color_alpha (cr,
 
1692
                                              &style->fg[GTK_STATE_NORMAL],
 
1693
                                              alpha * 0.75);
 
1694
            cairo_move_to (cr, x, y);
 
1695
 
 
1696
            if (d->state & (WNCK_WINDOW_STATE_MAXIMIZED_HORIZONTALLY |
 
1697
                            WNCK_WINDOW_STATE_MAXIMIZED_VERTICALLY))
 
1698
                draw_unmax_button (d, cr, 4.0);
 
1699
            else
 
1700
                draw_max_button (d, cr, 4.0);
 
1701
 
 
1702
            cairo_fill (cr);
 
1703
        }
 
1704
    }
 
1705
 
 
1706
    if (d->actions & WNCK_WINDOW_ACTION_MINIMIZE)
 
1707
    {
 
1708
        button_state_offsets (button_x,
 
1709
                              y1 - 3.0 + titlebar_height / 2,
 
1710
                              d->button_states[2], &x, &y);
 
1711
 
 
1712
        button_x -= 17;
 
1713
 
 
1714
        if (d->active)
 
1715
        {
 
1716
            gdk_cairo_set_source_color_alpha (cr,
 
1717
                                              &style->fg[GTK_STATE_NORMAL],
 
1718
                                              STROKE_ALPHA);
 
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]);
 
1722
        }
 
1723
        else
 
1724
        {
 
1725
            gdk_cairo_set_source_color_alpha (cr,
 
1726
                                              &style->fg[GTK_STATE_NORMAL],
 
1727
                                              alpha * 0.75);
 
1728
            cairo_move_to (cr, x, y);
 
1729
            draw_min_button (d, cr, 4.0);
 
1730
            cairo_fill (cr);
 
1731
        }
 
1732
    }
 
1733
 
 
1734
    if (d->layout)
 
1735
    {
 
1736
        if (d->active)
 
1737
        {
 
1738
            cairo_move_to (cr,
 
1739
                           left_space + 21.0,
 
1740
                           y1 + 2.0 + (titlebar_height - text_height) / 2.0);
 
1741
 
 
1742
            gdk_cairo_set_source_color_alpha (cr,
 
1743
                                              &style->fg[GTK_STATE_NORMAL],
 
1744
                                              STROKE_ALPHA);
 
1745
 
 
1746
            pango_cairo_layout_path (cr, d->layout);
 
1747
            cairo_stroke (cr);
 
1748
 
 
1749
            cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
 
1750
        }
 
1751
        else
 
1752
        {
 
1753
            gdk_cairo_set_source_color_alpha (cr,
 
1754
                                              &style->fg[GTK_STATE_NORMAL],
 
1755
                                              alpha);
 
1756
        }
 
1757
 
 
1758
        cairo_move_to (cr,
 
1759
                       left_space + 21.0,
 
1760
                       y1 + 2.0 + (titlebar_height - text_height) / 2.0);
 
1761
 
 
1762
        pango_cairo_show_layout (cr, d->layout);
 
1763
    }
 
1764
 
 
1765
    if (d->icon)
 
1766
    {
 
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);
 
1770
        cairo_clip (cr);
 
1771
 
 
1772
        if (d->active)
 
1773
            cairo_paint (cr);
 
1774
        else
 
1775
            cairo_paint_with_alpha (cr, alpha);
 
1776
    }
 
1777
 
 
1778
    cairo_destroy (cr);
 
1779
 
 
1780
    if (d->buffer_pixmap)
 
1781
        gdk_draw_drawable  (d->pixmap,
 
1782
                            d->gc,
 
1783
                            d->buffer_pixmap,
 
1784
                            0,
 
1785
                            0,
 
1786
                            0,
 
1787
                            0,
 
1788
                            d->width,
 
1789
                            d->height);
 
1790
 
 
1791
    if (d->prop_xid)
 
1792
    {
 
1793
        decor_update_window_property (d);
 
1794
        d->prop_xid = 0;
 
1795
    }
 
1796
}
 
1797
 
 
1798
#ifdef USE_METACITY
 
1799
static Region
 
1800
meta_get_window_region (const MetaFrameGeometry *fgeom,
 
1801
                        int                     width,
 
1802
                        int                     height)
 
1803
{
 
1804
    Region     corners_xregion, window_xregion;
 
1805
    XRectangle xrect;
 
1806
 
 
1807
    corners_xregion = XCreateRegion ();
 
1808
 
 
1809
    if (fgeom->top_left_corner_rounded)
 
1810
    {
 
1811
        xrect.x = 0;
 
1812
        xrect.y = 0;
 
1813
        xrect.width = 5;
 
1814
        xrect.height = 1;
 
1815
 
 
1816
        XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
1817
 
 
1818
        xrect.y = 1;
 
1819
        xrect.width = 3;
 
1820
 
 
1821
        XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
1822
 
 
1823
        xrect.y = 2;
 
1824
        xrect.width = 2;
 
1825
 
 
1826
        XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
1827
 
 
1828
        xrect.y = 3;
 
1829
        xrect.width = 1;
 
1830
        xrect.height = 2;
 
1831
 
 
1832
        XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
1833
    }
 
1834
 
 
1835
    if (fgeom->top_right_corner_rounded)
 
1836
    {
 
1837
        xrect.x = width - 5;
 
1838
        xrect.y = 0;
 
1839
        xrect.width = 5;
 
1840
        xrect.height = 1;
 
1841
 
 
1842
        XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
1843
 
 
1844
        xrect.y = 1;
 
1845
        xrect.x = width - 3;
 
1846
        xrect.width = 3;
 
1847
 
 
1848
        XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
1849
 
 
1850
        xrect.y = 2;
 
1851
        xrect.x = width - 2;
 
1852
        xrect.width = 2;
 
1853
 
 
1854
        XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
1855
 
 
1856
        xrect.y = 3;
 
1857
        xrect.x = width - 1;
 
1858
        xrect.width = 1;
 
1859
        xrect.height = 2;
 
1860
 
 
1861
        XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
1862
    }
 
1863
 
 
1864
    if (fgeom->bottom_left_corner_rounded)
 
1865
    {
 
1866
        xrect.x = 0;
 
1867
        xrect.y = height - 1;
 
1868
        xrect.width = 5;
 
1869
        xrect.height = 1;
 
1870
 
 
1871
        XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
1872
 
 
1873
        xrect.y = height - 2;
 
1874
        xrect.width = 3;
 
1875
 
 
1876
        XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
1877
 
 
1878
        xrect.y = height - 3;
 
1879
        xrect.width = 2;
 
1880
 
 
1881
        XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
1882
 
 
1883
        xrect.y = height - 5;
 
1884
        xrect.width = 1;
 
1885
        xrect.height = 2;
 
1886
 
 
1887
        XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
1888
    }
 
1889
 
 
1890
    if (fgeom->bottom_right_corner_rounded)
 
1891
    {
 
1892
        xrect.x = width - 5;
 
1893
        xrect.y = height - 1;
 
1894
        xrect.width = 5;
 
1895
        xrect.height = 1;
 
1896
 
 
1897
        XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
1898
 
 
1899
        xrect.y = height - 2;
 
1900
        xrect.x = width - 3;
 
1901
        xrect.width = 3;
 
1902
 
 
1903
        XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
1904
 
 
1905
        xrect.y = height - 3;
 
1906
        xrect.x = width - 2;
 
1907
        xrect.width = 2;
 
1908
 
 
1909
        XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
1910
 
 
1911
        xrect.y = height - 5;
 
1912
        xrect.x = width - 1;
 
1913
        xrect.width = 1;
 
1914
        xrect.height = 2;
 
1915
 
 
1916
        XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
 
1917
    }
 
1918
 
 
1919
    window_xregion = XCreateRegion ();
 
1920
 
 
1921
    xrect.x = 0;
 
1922
    xrect.y = 0;
 
1923
    xrect.width = width;
 
1924
    xrect.height = height;
 
1925
 
 
1926
    XUnionRectWithRegion (&xrect, window_xregion, window_xregion);
 
1927
 
 
1928
    XSubtractRegion (window_xregion, corners_xregion, window_xregion);
 
1929
 
 
1930
    XDestroyRegion (corners_xregion);
 
1931
 
 
1932
    return window_xregion;
 
1933
}
 
1934
 
 
1935
static MetaButtonState
 
1936
meta_button_state (int state)
 
1937
{
 
1938
    if (state & IN_EVENT_WINDOW)
 
1939
    {
 
1940
        if (state & PRESSED_EVENT_WINDOW)
 
1941
            return META_BUTTON_STATE_PRESSED;
 
1942
 
 
1943
        return META_BUTTON_STATE_PRELIGHT;
 
1944
    }
 
1945
 
 
1946
    return META_BUTTON_STATE_NORMAL;
 
1947
}
 
1948
static MetaButtonState
 
1949
meta_button_state_for_button_type (decor_t        *d,
 
1950
                                   MetaButtonType type)
 
1951
{
 
1952
    switch (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:
 
1966
    default:
 
1967
        break;
 
1968
    }
 
1969
 
 
1970
    return META_BUTTON_STATE_NORMAL;
 
1971
}
 
1972
 
 
1973
static void
 
1974
meta_draw_window_decoration (decor_t *d)
 
1975
{
 
1976
    MetaButtonState   button_states[META_BUTTON_TYPE_LAST];
 
1977
    MetaButtonLayout  button_layout;
 
1978
    MetaFrameGeometry fgeom;
 
1979
    MetaTheme         *theme;
 
1980
    GtkStyle          *style;
 
1981
    MetaFrameFlags    flags = 0;
 
1982
    cairo_t           *cr;
 
1983
    gint              i, left_width, right_width, top_height, bottom_height;
 
1984
    GdkRectangle      clip, rect;
 
1985
    GdkDrawable       *drawable;
 
1986
    Region            region;
 
1987
 
 
1988
    if (!d->pixmap)
 
1989
        return;
 
1990
 
 
1991
    style = gtk_widget_get_style (style_window);
 
1992
 
 
1993
    if (d->buffer_pixmap)
 
1994
        cr = gdk_cairo_create (GDK_DRAWABLE (d->buffer_pixmap));
 
1995
    else
 
1996
        cr = gdk_cairo_create (GDK_DRAWABLE (d->pixmap));
 
1997
 
 
1998
    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 
1999
 
 
2000
    draw_shadow_background (d, cr);
 
2001
 
 
2002
    theme = meta_theme_get_current ();
 
2003
 
 
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;
 
2008
 
 
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;
 
2013
 
 
2014
    if (d->actions & WNCK_WINDOW_ACTION_CLOSE)
 
2015
        flags |= META_FRAME_ALLOWS_DELETE;
 
2016
 
 
2017
    if (d->actions & WNCK_WINDOW_ACTION_MINIMIZE)
 
2018
        flags |= META_FRAME_ALLOWS_MINIMIZE;
 
2019
 
 
2020
    if (d->actions & WNCK_WINDOW_ACTION_MAXIMIZE)
 
2021
        flags |= META_FRAME_ALLOWS_MAXIMIZE;
 
2022
 
 
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;
 
2027
 
 
2028
    if (d->active)
 
2029
        flags |= META_FRAME_HAS_FOCUS;
 
2030
 
 
2031
    for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
 
2032
        button_states[i] = meta_button_state_for_button_type (d, i);
 
2033
 
 
2034
    meta_theme_get_frame_borders (theme,
 
2035
                                  META_FRAME_TYPE_NORMAL,
 
2036
                                  text_height,
 
2037
                                  flags,
 
2038
                                  &top_height,
 
2039
                                  &bottom_height,
 
2040
                                  &left_width,
 
2041
                                  &right_width);
 
2042
 
 
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;
 
2047
 
 
2048
    drawable = d->buffer_pixmap ? d->buffer_pixmap : d->pixmap;
 
2049
 
 
2050
    meta_theme_calc_geometry (theme,
 
2051
                              META_FRAME_TYPE_NORMAL,
 
2052
                              text_height,
 
2053
                              flags,
 
2054
                              clip.width - left_width - right_width,
 
2055
                              clip.height - top_height - bottom_height,
 
2056
                              &button_layout,
 
2057
                              &fgeom);
 
2058
 
 
2059
    region = meta_get_window_region (&fgeom, clip.width, clip.height);
 
2060
 
 
2061
    gdk_cairo_set_source_color (cr, &style->bg[GTK_STATE_NORMAL]);
 
2062
 
 
2063
    for (i = 0; i < region->numRects; i++)
 
2064
    {
 
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;
 
2069
 
 
2070
        cairo_rectangle (cr, rect.x, rect.y, rect.width, rect.height);
 
2071
        cairo_fill (cr);
 
2072
 
 
2073
        meta_theme_draw_frame (theme,
 
2074
                               style_window,
 
2075
                               drawable,
 
2076
                               &rect,
 
2077
                               clip.x,
 
2078
                               clip.y,
 
2079
                               META_FRAME_TYPE_NORMAL,
 
2080
                               flags,
 
2081
                               clip.width - left_width - right_width,
 
2082
                               clip.height - top_height - bottom_height,
 
2083
                               d->layout,
 
2084
                               text_height,
 
2085
                               &button_layout,
 
2086
                               button_states,
 
2087
                               d->icon_pixbuf,
 
2088
                               NULL);
 
2089
    }
 
2090
 
 
2091
    cairo_destroy (cr);
 
2092
 
 
2093
    XDestroyRegion (region);
 
2094
 
 
2095
    if (d->buffer_pixmap)
 
2096
        gdk_draw_drawable  (d->pixmap,
 
2097
                            d->gc,
 
2098
                            d->buffer_pixmap,
 
2099
                            0,
 
2100
                            0,
 
2101
                            0,
 
2102
                            0,
 
2103
                            d->width,
 
2104
                            d->height);
 
2105
 
 
2106
    if (d->prop_xid)
 
2107
    {
 
2108
        decor_update_window_property (d);
 
2109
        d->prop_xid = 0;
 
2110
    }
 
2111
}
 
2112
#endif
 
2113
 
 
2114
#define SWITCHER_ALPHA 0xa0a0
 
2115
 
 
2116
static void
 
2117
draw_switcher_background (decor_t *d)
 
2118
{
 
2119
    Display       *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
 
2120
    cairo_t       *cr;
 
2121
    GtkStyle      *style;
 
2122
    decor_color_t color;
 
2123
    double        alpha = SWITCHER_ALPHA / 65535.0;
 
2124
    double        x1, y1, x2, y2, h;
 
2125
    int           top;
 
2126
    unsigned long pixel;
 
2127
    ushort        a = SWITCHER_ALPHA;
 
2128
 
 
2129
    if (!d->buffer_pixmap)
 
2130
        return;
 
2131
 
 
2132
    style = gtk_widget_get_style (style_window);
 
2133
 
 
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;
 
2137
 
 
2138
    cr = gdk_cairo_create (GDK_DRAWABLE (d->buffer_pixmap));
 
2139
 
 
2140
    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 
2141
 
 
2142
    top = _win_extents.bottom;
 
2143
 
 
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;
 
2148
 
 
2149
    h = y2 - y1 - _win_extents.bottom - _win_extents.bottom;
 
2150
 
 
2151
    cairo_set_line_width (cr, 1.0);
 
2152
 
 
2153
    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 
2154
 
 
2155
    draw_shadow_background (d, cr);
 
2156
 
 
2157
    fill_rounded_rectangle (cr,
 
2158
                            x1 + 0.5,
 
2159
                            y1 + 0.5,
 
2160
                            _win_extents.left - 0.5,
 
2161
                            top - 0.5,
 
2162
                            5.0, CORNER_TOPLEFT,
 
2163
                            &color, alpha, &color, alpha * 0.75,
 
2164
                            SHADE_TOP | SHADE_LEFT);
 
2165
 
 
2166
    fill_rounded_rectangle (cr,
 
2167
                            x1 + _win_extents.left,
 
2168
                            y1 + 0.5,
 
2169
                            x2 - x1 - _win_extents.left -
 
2170
                            _win_extents.right,
 
2171
                            top - 0.5,
 
2172
                            5.0, 0,
 
2173
                            &color, alpha, &color, alpha * 0.75,
 
2174
                            SHADE_TOP);
 
2175
 
 
2176
    fill_rounded_rectangle (cr,
 
2177
                            x2 - _win_extents.right,
 
2178
                            y1 + 0.5,
 
2179
                            _win_extents.right - 0.5,
 
2180
                            top - 0.5,
 
2181
                            5.0, CORNER_TOPRIGHT,
 
2182
                            &color, alpha, &color, alpha * 0.75,
 
2183
                            SHADE_TOP | SHADE_RIGHT);
 
2184
 
 
2185
    fill_rounded_rectangle (cr,
 
2186
                            x1 + 0.5,
 
2187
                            y1 + top,
 
2188
                            _win_extents.left - 0.5,
 
2189
                            h,
 
2190
                            5.0, 0,
 
2191
                            &color, alpha, &color, alpha * 0.75,
 
2192
                            SHADE_LEFT);
 
2193
 
 
2194
    fill_rounded_rectangle (cr,
 
2195
                            x2 - _win_extents.right,
 
2196
                            y1 + top,
 
2197
                            _win_extents.right - 0.5,
 
2198
                            h,
 
2199
                            5.0, 0,
 
2200
                            &color, alpha, &color, alpha * 0.75,
 
2201
                            SHADE_RIGHT);
 
2202
 
 
2203
    fill_rounded_rectangle (cr,
 
2204
                            x1 + 0.5,
 
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);
 
2211
 
 
2212
    fill_rounded_rectangle (cr,
 
2213
                            x1 + _win_extents.left,
 
2214
                            y2 - _win_extents.bottom,
 
2215
                            x2 - x1 - _win_extents.left -
 
2216
                            _win_extents.right,
 
2217
                            _win_extents.bottom - 0.5,
 
2218
                            5.0, 0,
 
2219
                            &color, alpha, &color, alpha * 0.75,
 
2220
                            SHADE_BOTTOM);
 
2221
 
 
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);
 
2230
 
 
2231
    cairo_rectangle (cr, x1 + _win_extents.left,
 
2232
                     y1 + top,
 
2233
                     x2 - x1 - _win_extents.left - _win_extents.right,
 
2234
                     h);
 
2235
    gdk_cairo_set_source_color_alpha (cr,
 
2236
                                      &style->bg[GTK_STATE_NORMAL],
 
2237
                                      alpha);
 
2238
    cairo_fill (cr);
 
2239
 
 
2240
    cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
 
2241
 
 
2242
    rounded_rectangle (cr,
 
2243
                       x1 + 0.5, y1 + 0.5,
 
2244
                       x2 - x1 - 1.0, y2 - y1 - 1.0,
 
2245
                       5.0,
 
2246
                       CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
 
2247
                       CORNER_BOTTOMRIGHT);
 
2248
 
 
2249
    cairo_clip (cr);
 
2250
 
 
2251
    cairo_translate (cr, 1.0, 1.0);
 
2252
 
 
2253
    rounded_rectangle (cr,
 
2254
                       x1 + 0.5, y1 + 0.5,
 
2255
                       x2 - x1 - 1.0, y2 - y1 - 1.0,
 
2256
                       5.0,
 
2257
                       CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
 
2258
                       CORNER_BOTTOMRIGHT);
 
2259
 
 
2260
    cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.4);
 
2261
    cairo_stroke (cr);
 
2262
 
 
2263
    cairo_translate (cr, -2.0, -2.0);
 
2264
 
 
2265
    rounded_rectangle (cr,
 
2266
                       x1 + 0.5, y1 + 0.5,
 
2267
                       x2 - x1 - 1.0, y2 - y1 - 1.0,
 
2268
                       5.0,
 
2269
                       CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
 
2270
                       CORNER_BOTTOMRIGHT);
 
2271
 
 
2272
    cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.1);
 
2273
    cairo_stroke (cr);
 
2274
 
 
2275
    cairo_translate (cr, 1.0, 1.0);
 
2276
 
 
2277
    cairo_reset_clip (cr);
 
2278
 
 
2279
    rounded_rectangle (cr,
 
2280
                       x1 + 0.5, y1 + 0.5,
 
2281
                       x2 - x1 - 1.0, y2 - y1 - 1.0,
 
2282
                       5.0,
 
2283
                       CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
 
2284
                       CORNER_BOTTOMRIGHT);
 
2285
 
 
2286
    gdk_cairo_set_source_color_alpha (cr,
 
2287
                                      &style->fg[GTK_STATE_NORMAL],
 
2288
                                      alpha);
 
2289
 
 
2290
    cairo_stroke (cr);
 
2291
 
 
2292
    cairo_destroy (cr);
 
2293
 
 
2294
    gdk_draw_drawable (d->pixmap,
 
2295
                       d->gc,
 
2296
                       d->buffer_pixmap,
 
2297
                       0,
 
2298
                       0,
 
2299
                       0,
 
2300
                       0,
 
2301
                       d->width,
 
2302
                       d->height);
 
2303
 
 
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)));
 
2308
 
 
2309
    decor_update_switcher_property (d);
 
2310
 
 
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 ();
 
2316
 
 
2317
    d->prop_xid = 0;
 
2318
}
 
2319
 
 
2320
static void
 
2321
draw_switcher_foreground (decor_t *d)
 
2322
{
 
2323
    cairo_t       *cr;
 
2324
    GtkStyle      *style;
 
2325
    decor_color_t color;
 
2326
    double        alpha = SWITCHER_ALPHA / 65535.0;
 
2327
    double        x1, y1, x2;
 
2328
    int           top;
 
2329
 
 
2330
    if (!d->pixmap || !d->buffer_pixmap)
 
2331
        return;
 
2332
 
 
2333
    style = gtk_widget_get_style (style_window);
 
2334
 
 
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;
 
2338
 
 
2339
    top = _win_extents.bottom;
 
2340
 
 
2341
    x1 = left_space - _win_extents.left;
 
2342
    y1 = top_space - _win_extents.top;
 
2343
    x2 = d->width - right_space + _win_extents.right;
 
2344
 
 
2345
    cr = gdk_cairo_create (GDK_DRAWABLE (d->buffer_pixmap));
 
2346
 
 
2347
    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 
2348
 
 
2349
    cairo_rectangle (cr, x1 + _win_extents.left,
 
2350
                     y1 + top + switcher_top_corner_space,
 
2351
                     x2 - x1 - _win_extents.left - _win_extents.right,
 
2352
                     SWITCHER_SPACE);
 
2353
 
 
2354
    gdk_cairo_set_source_color_alpha (cr,
 
2355
                                      &style->bg[GTK_STATE_NORMAL],
 
2356
                                      alpha);
 
2357
    cairo_fill (cr);
 
2358
 
 
2359
    if (d->layout)
 
2360
    {
 
2361
        int w;
 
2362
 
 
2363
        cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
 
2364
 
 
2365
        gdk_cairo_set_source_color_alpha (cr,
 
2366
                                          &style->fg[GTK_STATE_NORMAL],
 
2367
                                          1.0);
 
2368
 
 
2369
        pango_layout_get_pixel_size (d->layout, &w, NULL);
 
2370
 
 
2371
        cairo_move_to (cr, d->width / 2 - w / 2,
 
2372
                       y1 + top + switcher_top_corner_space +
 
2373
                       SWITCHER_SPACE / 2 - text_height / 2);
 
2374
 
 
2375
        pango_cairo_show_layout (cr, d->layout);
 
2376
    }
 
2377
 
 
2378
    cairo_destroy (cr);
 
2379
 
 
2380
    gdk_draw_drawable  (d->pixmap,
 
2381
                        d->gc,
 
2382
                        d->buffer_pixmap,
 
2383
                        0,
 
2384
                        0,
 
2385
                        0,
 
2386
                        0,
 
2387
                        d->width,
 
2388
                        d->height);
 
2389
}
 
2390
 
 
2391
static void
 
2392
draw_switcher_decoration (decor_t *d)
 
2393
{
 
2394
    if (d->prop_xid)
 
2395
        draw_switcher_background (d);
 
2396
 
 
2397
    draw_switcher_foreground (d);
 
2398
}
 
2399
 
 
2400
static gboolean
 
2401
draw_decor_list (void *data)
 
2402
{
 
2403
    GSList  *list;
 
2404
    decor_t *d;
 
2405
 
 
2406
    draw_idle_id = 0;
 
2407
 
 
2408
    for (list = draw_list; list; list = list->next)
 
2409
    {
 
2410
        d = (decor_t *) list->data;
 
2411
        (*d->draw) (d);
 
2412
    }
 
2413
 
 
2414
    g_slist_free (draw_list);
 
2415
    draw_list = NULL;
 
2416
 
 
2417
    return FALSE;
 
2418
}
 
2419
 
 
2420
static void
 
2421
queue_decor_draw (decor_t *d)
 
2422
{
 
2423
    if (g_slist_find (draw_list, d))
 
2424
        return;
 
2425
 
 
2426
    draw_list = g_slist_append (draw_list, d);
 
2427
 
 
2428
    if (!draw_idle_id)
 
2429
        draw_idle_id = g_idle_add (draw_decor_list, NULL);
 
2430
}
 
2431
 
 
2432
static GdkPixmap *
 
2433
create_pixmap (int w,
 
2434
               int h)
 
2435
{
 
2436
    GdkPixmap   *pixmap;
 
2437
    GdkVisual   *visual;
 
2438
    GdkColormap *colormap;
 
2439
 
 
2440
    visual = gdk_visual_get_best_with_depth (32);
 
2441
    if (!visual)
 
2442
        return NULL;
 
2443
 
 
2444
    pixmap = gdk_pixmap_new (NULL, w, h, 32);
 
2445
    if (!pixmap)
 
2446
        return NULL;
 
2447
 
 
2448
    colormap = gdk_colormap_new (visual, FALSE);
 
2449
    if (!colormap)
 
2450
    {
 
2451
        gdk_pixmap_unref (pixmap);
 
2452
        return NULL;
 
2453
    }
 
2454
 
 
2455
    gdk_drawable_set_colormap (GDK_DRAWABLE (pixmap), colormap);
 
2456
    gdk_colormap_unref (colormap);
 
2457
 
 
2458
    return pixmap;
 
2459
}
 
2460
 
 
2461
static GdkPixmap *
 
2462
pixmap_new_from_pixbuf (GdkPixbuf *pixbuf)
 
2463
{
 
2464
    GdkPixmap *pixmap;
 
2465
    guint     width, height;
 
2466
    cairo_t   *cr;
 
2467
 
 
2468
    width  = gdk_pixbuf_get_width (pixbuf);
 
2469
    height = gdk_pixbuf_get_height (pixbuf);
 
2470
 
 
2471
    pixmap = create_pixmap (width, height);
 
2472
    if (!pixmap)
 
2473
        return NULL;
 
2474
 
 
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);
 
2478
    cairo_paint (cr);
 
2479
    cairo_destroy (cr);
 
2480
 
 
2481
    return pixmap;
 
2482
}
 
2483
 
 
2484
static void
 
2485
update_default_decorations (GdkScreen *screen)
 
2486
{
 
2487
    long       data[256];
 
2488
    Window     xroot;
 
2489
    GdkDisplay *gdkdisplay = gdk_display_get_default ();
 
2490
    Display    *xdisplay = gdk_x11_display_get_xdisplay (gdkdisplay);
 
2491
    Atom       bareAtom, normalAtom, activeAtom;
 
2492
    decor_t    d;
 
2493
    gint       nQuad;
 
2494
    quad       quads[N_QUADS_MAX];
 
2495
    extents    extents = _win_extents;
 
2496
 
 
2497
    xroot = RootWindowOfScreen (gdk_x11_screen_get_xscreen (screen));
 
2498
 
 
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);
 
2502
 
 
2503
    if (shadow_pixmap)
 
2504
    {
 
2505
        int width, height;
 
2506
 
 
2507
        gdk_drawable_get_size (shadow_pixmap, &width, &height);
 
2508
 
 
2509
        nQuad = set_shadow_quads (quads, width, height);
 
2510
 
 
2511
        decoration_to_property (data, GDK_PIXMAP_XID (shadow_pixmap),
 
2512
                                &_shadow_extents, 0, 0, quads, nQuad);
 
2513
 
 
2514
        XChangeProperty (xdisplay, xroot,
 
2515
                         bareAtom,
 
2516
                         XA_INTEGER,
 
2517
                         32, PropModeReplace, (guchar *) data,
 
2518
                         7 + 9 * nQuad);
 
2519
 
 
2520
        if (minimal)
 
2521
        {
 
2522
            XChangeProperty (xdisplay, xroot,
 
2523
                             normalAtom,
 
2524
                             XA_INTEGER,
 
2525
                             32, PropModeReplace, (guchar *) data,
 
2526
                             7 + 9 * nQuad);
 
2527
            XChangeProperty (xdisplay, xroot,
 
2528
                             activeAtom,
 
2529
                             XA_INTEGER,
 
2530
                             32, PropModeReplace, (guchar *) data,
 
2531
                             7 + 9 * nQuad);
 
2532
        }
 
2533
    }
 
2534
    else
 
2535
    {
 
2536
        XDeleteProperty (xdisplay, xroot, bareAtom);
 
2537
 
 
2538
        if (minimal)
 
2539
        {
 
2540
            XDeleteProperty (xdisplay, xroot, normalAtom);
 
2541
            XDeleteProperty (xdisplay, xroot, activeAtom);
 
2542
        }
 
2543
    }
 
2544
 
 
2545
    if (minimal)
 
2546
        return;
 
2547
 
 
2548
    d.width  = left_space + left_corner_space + 1 + right_corner_space +
 
2549
        right_space;
 
2550
    d.height = top_space + titlebar_height + normal_top_corner_space + 2 +
 
2551
        bottom_corner_space + bottom_space;
 
2552
 
 
2553
    extents.top += titlebar_height;
 
2554
 
 
2555
    d.buffer_pixmap = NULL;
 
2556
    d.layout        = NULL;
 
2557
    d.icon          = NULL;
 
2558
    d.icon_pixmap   = NULL;
 
2559
    d.icon_pixbuf   = NULL;
 
2560
    d.state         = 0;
 
2561
    d.actions       = 0;
 
2562
    d.prop_xid      = 0;
 
2563
    d.button_width  = 0;
 
2564
    d.draw          = theme_draw_window_decoration;
 
2565
 
 
2566
    if (decor_normal_pixmap)
 
2567
        gdk_pixmap_unref (decor_normal_pixmap);
 
2568
 
 
2569
    nQuad = set_no_title_window_quads (quads, d.width, d.height);
 
2570
 
 
2571
    decor_normal_pixmap = create_pixmap (d.width, d.height);
 
2572
    if (decor_normal_pixmap)
 
2573
    {
 
2574
        d.pixmap = decor_normal_pixmap;
 
2575
        d.active = FALSE;
 
2576
 
 
2577
        (*d.draw) (&d);
 
2578
 
 
2579
        decoration_to_property (data, GDK_PIXMAP_XID (d.pixmap),
 
2580
                                &extents, 0, 0, quads, nQuad);
 
2581
 
 
2582
        XChangeProperty (xdisplay, xroot,
 
2583
                         normalAtom,
 
2584
                         XA_INTEGER,
 
2585
                         32, PropModeReplace, (guchar *) data, 7 + 9 * nQuad);
 
2586
    }
 
2587
 
 
2588
    if (decor_active_pixmap)
 
2589
        gdk_pixmap_unref (decor_active_pixmap);
 
2590
 
 
2591
    decor_active_pixmap = create_pixmap (d.width, d.height);
 
2592
    if (decor_active_pixmap)
 
2593
    {
 
2594
        d.pixmap = decor_active_pixmap;
 
2595
        d.active = TRUE;
 
2596
 
 
2597
        (*d.draw) (&d);
 
2598
 
 
2599
        decoration_to_property (data, GDK_PIXMAP_XID (d.pixmap),
 
2600
                                &extents, 0, 0, quads, nQuad);
 
2601
 
 
2602
        XChangeProperty (xdisplay, xroot,
 
2603
                         activeAtom,
 
2604
                         XA_INTEGER,
 
2605
                         32, PropModeReplace, (guchar *) data, 7 + 9 * nQuad);
 
2606
    }
 
2607
}
 
2608
 
 
2609
static void
 
2610
set_dm_check_hint (GdkScreen *screen)
 
2611
{
 
2612
    XSetWindowAttributes attrs;
 
2613
    unsigned long        data[1];
 
2614
    Window               xroot;
 
2615
    GdkDisplay           *gdkdisplay = gdk_display_get_default ();
 
2616
    Display              *xdisplay = gdk_x11_display_get_xdisplay (gdkdisplay);
 
2617
    Atom                 atom;
 
2618
 
 
2619
    attrs.override_redirect = TRUE;
 
2620
    attrs.event_mask        = PropertyChangeMask;
 
2621
 
 
2622
    xroot = RootWindowOfScreen (gdk_x11_screen_get_xscreen (screen));
 
2623
 
 
2624
    data[0] = XCreateWindow (xdisplay,
 
2625
                             xroot,
 
2626
                             -100, -100, 1, 1,
 
2627
                             0,
 
2628
                             CopyFromParent,
 
2629
                             CopyFromParent,
 
2630
                             (Visual *) CopyFromParent,
 
2631
                             CWOverrideRedirect | CWEventMask,
 
2632
                             &attrs);
 
2633
 
 
2634
    atom = XInternAtom (xdisplay, "_NET_SUPPORTING_DM_CHECK", FALSE);
 
2635
 
 
2636
    XChangeProperty (xdisplay, xroot,
 
2637
                     atom,
 
2638
                     XA_WINDOW,
 
2639
                     32, PropModeReplace, (guchar *) data, 1);
 
2640
}
 
2641
 
 
2642
static gboolean
 
2643
get_window_prop (Window xwindow,
 
2644
                 Atom   atom,
 
2645
                 Window *val)
 
2646
{
 
2647
    Atom   type;
 
2648
    int    format;
 
2649
    gulong nitems;
 
2650
    gulong bytes_after;
 
2651
    Window *w;
 
2652
    int    err, result;
 
2653
 
 
2654
    *val = 0;
 
2655
 
 
2656
    gdk_error_trap_push ();
 
2657
 
 
2658
    type = None;
 
2659
    result = XGetWindowProperty (gdk_display,
 
2660
                                 xwindow,
 
2661
                                 atom,
 
2662
                                 0, G_MAXLONG,
 
2663
                                 False, XA_WINDOW, &type, &format, &nitems,
 
2664
                                 &bytes_after, (void*) &w);
 
2665
    err = gdk_error_trap_pop ();
 
2666
    if (err != Success || result != Success)
 
2667
        return FALSE;
 
2668
 
 
2669
    if (type != XA_WINDOW)
 
2670
    {
 
2671
        XFree (w);
 
2672
        return FALSE;
 
2673
    }
 
2674
 
 
2675
    *val = *w;
 
2676
    XFree (w);
 
2677
 
 
2678
    return TRUE;
 
2679
}
 
2680
 
 
2681
static unsigned int
 
2682
get_mwm_prop (Window xwindow)
 
2683
{
 
2684
    Display       *xdisplay;
 
2685
    Atom          actual;
 
2686
    int           err, result, format;
 
2687
    unsigned long n, left;
 
2688
    MwmHints      *mwm_hints;
 
2689
    unsigned int  decor = MWM_DECOR_ALL;
 
2690
 
 
2691
    xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
 
2692
 
 
2693
    gdk_error_trap_push ();
 
2694
 
 
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);
 
2699
 
 
2700
    err = gdk_error_trap_pop ();
 
2701
    if (err != Success || result != Success)
 
2702
        return decor;
 
2703
 
 
2704
    if (n && mwm_hints)
 
2705
    {
 
2706
        if (n >= PROP_MOTIF_WM_HINT_ELEMENTS)
 
2707
        {
 
2708
            if (mwm_hints->flags & MWM_HINTS_DECORATIONS)
 
2709
                decor = mwm_hints->decorations;
 
2710
        }
 
2711
 
 
2712
        XFree (mwm_hints);
 
2713
    }
 
2714
 
 
2715
    return decor;
 
2716
}
 
2717
 
 
2718
static void
 
2719
update_event_windows (WnckWindow *win)
 
2720
{
 
2721
    Display *xdisplay;
 
2722
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
2723
    gint    x0, y0, width, height, x, y, w, h;
 
2724
    gint    i, j, k, l;
 
2725
    gint    button_x = 10;
 
2726
 
 
2727
    xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
 
2728
 
 
2729
    wnck_window_get_geometry (win, &x0, &y0, &width, &height);
 
2730
 
 
2731
    if (d->state & WNCK_WINDOW_STATE_SHADED)
 
2732
    {
 
2733
        height = 0;
 
2734
        k = l = 1;
 
2735
    }
 
2736
    else
 
2737
    {
 
2738
        k = 0;
 
2739
        l = 2;
 
2740
    }
 
2741
 
 
2742
    gdk_error_trap_push ();
 
2743
 
 
2744
    for (i = 0; i < 3; i++)
 
2745
    {
 
2746
        static guint event_window_actions[3][3] = {
 
2747
            {
 
2748
                WNCK_WINDOW_ACTION_RESIZE,
 
2749
                WNCK_WINDOW_ACTION_RESIZE,
 
2750
                WNCK_WINDOW_ACTION_RESIZE
 
2751
            }, {
 
2752
                WNCK_WINDOW_ACTION_RESIZE,
 
2753
                WNCK_WINDOW_ACTION_MOVE,
 
2754
                WNCK_WINDOW_ACTION_RESIZE
 
2755
            }, {
 
2756
                WNCK_WINDOW_ACTION_RESIZE,
 
2757
                WNCK_WINDOW_ACTION_RESIZE,
 
2758
                WNCK_WINDOW_ACTION_RESIZE
 
2759
            }
 
2760
        };
 
2761
 
 
2762
        for (j = 0; j < 3; j++)
 
2763
        {
 
2764
            if (d->actions & event_window_actions[i][j] && i >= k && i <= l)
 
2765
            {
 
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);
 
2770
 
 
2771
                XMapWindow (xdisplay, d->event_windows[i][j]);
 
2772
                XMoveResizeWindow (xdisplay, d->event_windows[i][j],
 
2773
                                   x, y, w, h);
 
2774
            }
 
2775
            else
 
2776
            {
 
2777
                XUnmapWindow (xdisplay, d->event_windows[i][j]);
 
2778
            }
 
2779
        }
 
2780
    }
 
2781
 
 
2782
    for (i = 0; i < 3; i++)
 
2783
    {
 
2784
        static guint button_actions[3] = {
 
2785
            WNCK_WINDOW_ACTION_CLOSE,
 
2786
            WNCK_WINDOW_ACTION_MAXIMIZE,
 
2787
            WNCK_WINDOW_ACTION_MINIMIZE
 
2788
        };
 
2789
 
 
2790
        if (d->actions & button_actions[i])
 
2791
        {
 
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);
 
2796
 
 
2797
            x -= button_x;
 
2798
            button_x += 16;
 
2799
 
 
2800
            XMapWindow (xdisplay, d->button_windows[i]);
 
2801
            XMoveResizeWindow (xdisplay, d->button_windows[i], x, y, w, h);
 
2802
        }
 
2803
        else
 
2804
            XUnmapWindow (xdisplay, d->button_windows[i]);
 
2805
    }
 
2806
 
 
2807
    XSync (xdisplay, FALSE);
 
2808
    gdk_error_trap_pop ();
 
2809
}
 
2810
 
 
2811
#if HAVE_WNCK_WINDOW_HAS_NAME
 
2812
static const char *
 
2813
wnck_window_get_real_name (WnckWindow *win)
 
2814
{
 
2815
    return wnck_window_has_name (win) ? wnck_window_get_name (win) : NULL;
 
2816
}
 
2817
#define wnck_window_get_name wnck_window_get_real_name
 
2818
#endif
 
2819
 
 
2820
static gint
 
2821
max_window_name_width (WnckWindow *win)
 
2822
{
 
2823
    decor_t     *d = g_object_get_data (G_OBJECT (win), "decor");
 
2824
    const gchar *name;
 
2825
    gint        w;
 
2826
 
 
2827
    name = wnck_window_get_name (win);
 
2828
    if (!name)
 
2829
        return 0;
 
2830
 
 
2831
    if (!d->layout)
 
2832
    {
 
2833
        d->layout = pango_layout_new (pango_context);
 
2834
        if (!d->layout)
 
2835
            return 0;
 
2836
 
 
2837
        pango_layout_set_wrap (d->layout, PANGO_WRAP_CHAR);
 
2838
    }
 
2839
 
 
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);
 
2843
 
 
2844
    if (d->name)
 
2845
        pango_layout_set_text (d->layout, d->name, strlen (d->name));
 
2846
 
 
2847
    return w + 6;
 
2848
}
 
2849
 
 
2850
static void
 
2851
update_window_decoration_name (WnckWindow *win)
 
2852
{
 
2853
    decor_t         *d = g_object_get_data (G_OBJECT (win), "decor");
 
2854
    const gchar     *name;
 
2855
    glong           name_length;
 
2856
    PangoLayoutLine *line;
 
2857
 
 
2858
    if (d->name)
 
2859
    {
 
2860
        g_free (d->name);
 
2861
        d->name = NULL;
 
2862
    }
 
2863
 
 
2864
    name = wnck_window_get_name (win);
 
2865
    if (name && (name_length = strlen (name)))
 
2866
    {
 
2867
        gint w, n_line;
 
2868
 
 
2869
        w  = d->width - left_space - right_space - ICON_SPACE - 4;
 
2870
        w -= d->button_width;
 
2871
        if (w < 1)
 
2872
            w = 1;
 
2873
 
 
2874
        pango_layout_set_width (d->layout, w * PANGO_SCALE);
 
2875
        pango_layout_set_text (d->layout, name, name_length);
 
2876
 
 
2877
        n_line = pango_layout_get_line_count (d->layout);
 
2878
 
 
2879
        line = pango_layout_get_line (d->layout, 0);
 
2880
 
 
2881
        name_length = line->length;
 
2882
        if (pango_layout_get_line_count (d->layout) > 1)
 
2883
        {
 
2884
            if (name_length < 4)
 
2885
            {
 
2886
                g_object_unref (G_OBJECT (d->layout));
 
2887
                d->layout = NULL;
 
2888
                return;
 
2889
            }
 
2890
 
 
2891
            d->name = g_strndup (name, name_length);
 
2892
            strcpy (d->name + name_length - 3, "...");
 
2893
        }
 
2894
        else
 
2895
            d->name = g_strndup (name, name_length);
 
2896
 
 
2897
        pango_layout_set_text (d->layout, d->name, name_length);
 
2898
    }
 
2899
    else if (d->layout)
 
2900
    {
 
2901
        g_object_unref (G_OBJECT (d->layout));
 
2902
        d->layout = NULL;
 
2903
    }
 
2904
}
 
2905
 
 
2906
static void
 
2907
update_window_decoration_icon (WnckWindow *win)
 
2908
{
 
2909
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
2910
 
 
2911
    if (d->icon)
 
2912
    {
 
2913
        cairo_pattern_destroy (d->icon);
 
2914
        d->icon = NULL;
 
2915
    }
 
2916
 
 
2917
    if (d->icon_pixmap)
 
2918
    {
 
2919
        gdk_pixmap_unref (d->icon_pixmap);
 
2920
        d->icon_pixmap = NULL;
 
2921
    }
 
2922
 
 
2923
    if (d->icon_pixbuf)
 
2924
        gdk_pixbuf_unref (d->icon_pixbuf);
 
2925
 
 
2926
    d->icon_pixbuf = wnck_window_get_mini_icon (win);
 
2927
    if (d->icon_pixbuf)
 
2928
    {
 
2929
        cairo_t *cr;
 
2930
 
 
2931
        gdk_pixbuf_ref (d->icon_pixbuf);
 
2932
 
 
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));
 
2936
        cairo_destroy (cr);
 
2937
    }
 
2938
}
 
2939
 
 
2940
static void
 
2941
update_window_decoration_state (WnckWindow *win)
 
2942
{
 
2943
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
2944
 
 
2945
    d->state = wnck_window_get_state (win);
 
2946
}
 
2947
 
 
2948
static void
 
2949
update_window_decoration_actions (WnckWindow *win)
 
2950
{
 
2951
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
2952
 
 
2953
    d->actions = wnck_window_get_actions (win);
 
2954
}
 
2955
 
 
2956
static gboolean
 
2957
update_window_button_size (WnckWindow *win)
 
2958
{
 
2959
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
2960
    gint    button_width;
 
2961
 
 
2962
    button_width = 0;
 
2963
 
 
2964
    if (d->actions & WNCK_WINDOW_ACTION_CLOSE)
 
2965
        button_width += 17;
 
2966
 
 
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))
 
2971
        button_width += 17;
 
2972
 
 
2973
    if (d->actions & (WNCK_WINDOW_ACTION_MINIMIZE |
 
2974
                      WNCK_WINDOW_ACTION_MINIMIZE))
 
2975
        button_width += 17;
 
2976
 
 
2977
    if (button_width)
 
2978
        button_width++;
 
2979
 
 
2980
    if (button_width != d->button_width)
 
2981
    {
 
2982
        d->button_width = button_width;
 
2983
 
 
2984
        return TRUE;
 
2985
    }
 
2986
 
 
2987
    return FALSE;
 
2988
}
 
2989
 
 
2990
static gboolean
 
2991
calc_decoration_size (decor_t *d,
 
2992
                      gint    w,
 
2993
                      gint    h,
 
2994
                      gint    name_width,
 
2995
                      gint    *width,
 
2996
                      gint    *height)
 
2997
{
 
2998
    if (w < ICON_SPACE + d->button_width)
 
2999
        return FALSE;
 
3000
 
 
3001
    *width = name_width + d->button_width + ICON_SPACE;
 
3002
    if (w < *width)
 
3003
        *width = MAX (ICON_SPACE + d->button_width, w);
 
3004
 
 
3005
    *width  = MAX (*width, left_corner_space + right_corner_space);
 
3006
    *width += left_space + 1 + right_space;
 
3007
 
 
3008
    *height  = titlebar_height + normal_top_corner_space + bottom_corner_space;
 
3009
    *height += top_space + 2 + bottom_space;
 
3010
 
 
3011
    return (*width != d->width || *height != d->height);
 
3012
}
 
3013
 
 
3014
#ifdef USE_METACITY
 
3015
static gboolean
 
3016
meta_calc_decoration_size (decor_t *d,
 
3017
                           gint    w,
 
3018
                           gint    h,
 
3019
                           gint    name_width,
 
3020
                           gint    *width,
 
3021
                           gint    *height)
 
3022
{
 
3023
    *width  = MAX (w, left_corner_space + right_corner_space);
 
3024
    *width += left_space + 1 + right_space;
 
3025
 
 
3026
    *height  = titlebar_height + normal_top_corner_space + bottom_corner_space;
 
3027
    *height += top_space + 2 + bottom_space;
 
3028
 
 
3029
    return (*width != d->width || *height != d->height);
 
3030
}
 
3031
#endif
 
3032
 
 
3033
static gboolean
 
3034
update_window_decoration_size (WnckWindow *win)
 
3035
{
 
3036
    decor_t   *d = g_object_get_data (G_OBJECT (win), "decor");
 
3037
    GdkPixmap *pixmap, *buffer_pixmap = NULL;
 
3038
    gint      width, height;
 
3039
    gint      w, h, name_width;
 
3040
 
 
3041
    wnck_window_get_geometry (win, NULL, NULL, &w, &h);
 
3042
 
 
3043
    name_width = max_window_name_width (win);
 
3044
 
 
3045
    if (!(*theme_calc_decoration_size) (d, w, h, name_width, &width, &height))
 
3046
    {
 
3047
        update_window_decoration_name (win);
 
3048
        return FALSE;
 
3049
    }
 
3050
 
 
3051
    pixmap = create_pixmap (width, height);
 
3052
    if (!pixmap)
 
3053
        return FALSE;
 
3054
 
 
3055
    buffer_pixmap = create_pixmap (width, height);
 
3056
    if (!buffer_pixmap)
 
3057
    {
 
3058
        gdk_pixmap_unref (pixmap);
 
3059
        return FALSE;
 
3060
    }
 
3061
 
 
3062
    if (d->pixmap)
 
3063
        gdk_pixmap_unref (d->pixmap);
 
3064
 
 
3065
    if (d->buffer_pixmap)
 
3066
        gdk_pixmap_unref (d->buffer_pixmap);
 
3067
 
 
3068
    if (d->gc)
 
3069
        gdk_gc_unref (d->gc);
 
3070
 
 
3071
    d->pixmap        = pixmap;
 
3072
    d->buffer_pixmap = buffer_pixmap;
 
3073
    d->gc            = gdk_gc_new (pixmap);
 
3074
 
 
3075
    d->width  = width;
 
3076
    d->height = height;
 
3077
 
 
3078
    d->prop_xid = wnck_window_get_xid (win);
 
3079
 
 
3080
    update_window_decoration_name (win);
 
3081
 
 
3082
    queue_decor_draw (d);
 
3083
 
 
3084
    return TRUE;
 
3085
}
 
3086
 
 
3087
static void
 
3088
add_frame_window (WnckWindow *win,
 
3089
                  Window     frame)
 
3090
{
 
3091
    Display              *xdisplay;
 
3092
    XSetWindowAttributes attr;
 
3093
    gulong               xid = wnck_window_get_xid (win);
 
3094
    decor_t              *d = g_object_get_data (G_OBJECT (win), "decor");
 
3095
    gint                 i, j;
 
3096
 
 
3097
    xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
 
3098
 
 
3099
    attr.event_mask = ButtonPressMask | EnterWindowMask | LeaveWindowMask;
 
3100
    attr.override_redirect = TRUE;
 
3101
 
 
3102
    gdk_error_trap_push ();
 
3103
 
 
3104
    for (i = 0; i < 3; i++)
 
3105
    {
 
3106
        for (j = 0; j < 3; j++)
 
3107
        {
 
3108
            d->event_windows[i][j] =
 
3109
                XCreateWindow (xdisplay,
 
3110
                               frame,
 
3111
                               0, 0, 1, 1, 0,
 
3112
                               CopyFromParent, CopyFromParent, CopyFromParent,
 
3113
                               CWOverrideRedirect | CWEventMask, &attr);
 
3114
 
 
3115
            if (cursor[i][j].cursor)
 
3116
                XDefineCursor (xdisplay, d->event_windows[i][j],
 
3117
                               cursor[i][j].cursor);
 
3118
        }
 
3119
    }
 
3120
 
 
3121
    attr.event_mask |= ButtonReleaseMask;
 
3122
 
 
3123
    for (i = 0; i < 3; i++)
 
3124
    {
 
3125
        d->button_windows[i] =
 
3126
            XCreateWindow (xdisplay,
 
3127
                           frame,
 
3128
                           0, 0, 1, 1, 0,
 
3129
                           CopyFromParent, CopyFromParent, CopyFromParent,
 
3130
                           CWOverrideRedirect | CWEventMask, &attr);
 
3131
 
 
3132
        d->button_states[i] = 0;
 
3133
    }
 
3134
 
 
3135
    XSync (xdisplay, FALSE);
 
3136
    if (!gdk_error_trap_pop ())
 
3137
    {
 
3138
        if (get_mwm_prop (xid) & (MWM_DECOR_ALL | MWM_DECOR_TITLE))
 
3139
            d->decorated = TRUE;
 
3140
 
 
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));
 
3146
 
 
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));
 
3151
 
 
3152
 
 
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);
 
3158
 
 
3159
        update_event_windows (win);
 
3160
    }
 
3161
    else
 
3162
    {
 
3163
        memset (d->event_windows, 0, sizeof (d->event_windows));
 
3164
    }
 
3165
}
 
3166
 
 
3167
static gboolean
 
3168
update_switcher_window (WnckWindow *win,
 
3169
                        Window     selected)
 
3170
{
 
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;
 
3175
 
 
3176
    wnck_window_get_geometry (win, NULL, NULL, &width, NULL);
 
3177
 
 
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;
 
3181
 
 
3182
    d->decorated = FALSE;
 
3183
    d->draw      = draw_switcher_decoration;
 
3184
 
 
3185
    if (!d->pixmap && switcher_pixmap)
 
3186
    {
 
3187
        gdk_pixmap_ref (switcher_pixmap);
 
3188
        d->pixmap = switcher_pixmap;
 
3189
    }
 
3190
 
 
3191
    if (!d->buffer_pixmap && switcher_buffer_pixmap)
 
3192
    {
 
3193
        gdk_pixmap_ref (switcher_buffer_pixmap);
 
3194
        d->buffer_pixmap = switcher_buffer_pixmap;
 
3195
    }
 
3196
 
 
3197
    if (!d->width)
 
3198
        d->width = switcher_width;
 
3199
 
 
3200
    if (!d->height)
 
3201
        d->height = switcher_height;
 
3202
 
 
3203
    selected_win = wnck_window_get (selected);
 
3204
    if (selected_win)
 
3205
    {
 
3206
        glong           name_length;
 
3207
        PangoLayoutLine *line;
 
3208
        const gchar     *name;
 
3209
 
 
3210
        if (d->name)
 
3211
        {
 
3212
            g_free (d->name);
 
3213
            d->name = NULL;
 
3214
        }
 
3215
 
 
3216
        name = wnck_window_get_name (selected_win);
 
3217
        if (name && (name_length = strlen (name)))
 
3218
        {
 
3219
            gint n_line;
 
3220
 
 
3221
            if (!d->layout)
 
3222
            {
 
3223
                d->layout = pango_layout_new (pango_context);
 
3224
                if (d->layout)
 
3225
                    pango_layout_set_wrap (d->layout, PANGO_WRAP_CHAR);
 
3226
            }
 
3227
 
 
3228
            if (d->layout)
 
3229
            {
 
3230
                int tw;
 
3231
 
 
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);
 
3235
 
 
3236
                n_line = pango_layout_get_line_count (d->layout);
 
3237
 
 
3238
                line = pango_layout_get_line (d->layout, 0);
 
3239
 
 
3240
                name_length = line->length;
 
3241
                if (pango_layout_get_line_count (d->layout) > 1)
 
3242
                {
 
3243
                    if (name_length < 4)
 
3244
                    {
 
3245
                        g_object_unref (G_OBJECT (d->layout));
 
3246
                        d->layout = NULL;
 
3247
                    }
 
3248
                    else
 
3249
                    {
 
3250
                        d->name = g_strndup (name, name_length);
 
3251
                        strcpy (d->name + name_length - 3, "...");
 
3252
                    }
 
3253
                }
 
3254
                else
 
3255
                    d->name = g_strndup (name, name_length);
 
3256
 
 
3257
                if (d->layout)
 
3258
                    pango_layout_set_text (d->layout, d->name, name_length);
 
3259
            }
 
3260
        }
 
3261
        else if (d->layout)
 
3262
        {
 
3263
            g_object_unref (G_OBJECT (d->layout));
 
3264
            d->layout = NULL;
 
3265
        }
 
3266
    }
 
3267
 
 
3268
    if (width == d->width && height == d->height)
 
3269
    {
 
3270
        if (!d->gc)
 
3271
            d->gc = gdk_gc_new (d->pixmap);
 
3272
 
 
3273
        queue_decor_draw (d);
 
3274
        return FALSE;
 
3275
    }
 
3276
 
 
3277
    pixmap = create_pixmap (width, height);
 
3278
    if (!pixmap)
 
3279
        return FALSE;
 
3280
 
 
3281
    buffer_pixmap = create_pixmap (width, height);
 
3282
    if (!buffer_pixmap)
 
3283
    {
 
3284
        gdk_pixmap_unref (pixmap);
 
3285
        return FALSE;
 
3286
    }
 
3287
 
 
3288
    if (switcher_pixmap)
 
3289
        gdk_pixmap_unref (switcher_pixmap);
 
3290
 
 
3291
    if (switcher_buffer_pixmap)
 
3292
        gdk_pixmap_unref (switcher_buffer_pixmap);
 
3293
 
 
3294
    if (d->pixmap)
 
3295
        gdk_pixmap_unref (d->pixmap);
 
3296
 
 
3297
    if (d->buffer_pixmap)
 
3298
        gdk_pixmap_unref (d->buffer_pixmap);
 
3299
 
 
3300
    if (d->gc)
 
3301
        gdk_gc_unref (d->gc);
 
3302
 
 
3303
    switcher_pixmap        = pixmap;
 
3304
    switcher_buffer_pixmap = buffer_pixmap;
 
3305
 
 
3306
    switcher_width  = width;
 
3307
    switcher_height = height;
 
3308
 
 
3309
    gdk_pixmap_ref (pixmap);
 
3310
    gdk_pixmap_ref (buffer_pixmap);
 
3311
 
 
3312
    d->pixmap        = pixmap;
 
3313
    d->buffer_pixmap = buffer_pixmap;
 
3314
    d->gc            = gdk_gc_new (pixmap);
 
3315
 
 
3316
    d->width  = width;
 
3317
    d->height = height;
 
3318
 
 
3319
    d->prop_xid = wnck_window_get_xid (win);
 
3320
 
 
3321
    queue_decor_draw (d);
 
3322
 
 
3323
    return TRUE;
 
3324
}
 
3325
 
 
3326
static void
 
3327
remove_frame_window (WnckWindow *win)
 
3328
{
 
3329
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
3330
 
 
3331
    if (d->pixmap)
 
3332
    {
 
3333
        gdk_pixmap_unref (d->pixmap);
 
3334
        d->pixmap = NULL;
 
3335
    }
 
3336
 
 
3337
    if (d->buffer_pixmap)
 
3338
    {
 
3339
        gdk_pixmap_unref (d->buffer_pixmap);
 
3340
        d->buffer_pixmap = NULL;
 
3341
    }
 
3342
 
 
3343
    if (d->gc)
 
3344
    {
 
3345
        gdk_gc_unref (d->gc);
 
3346
        d->gc = NULL;
 
3347
    }
 
3348
 
 
3349
    if (d->name)
 
3350
    {
 
3351
        g_free (d->name);
 
3352
        d->name = NULL;
 
3353
    }
 
3354
 
 
3355
    if (d->layout)
 
3356
    {
 
3357
        g_object_unref (G_OBJECT (d->layout));
 
3358
        d->layout = NULL;
 
3359
    }
 
3360
 
 
3361
    if (d->icon)
 
3362
    {
 
3363
        cairo_pattern_destroy (d->icon);
 
3364
        d->icon = NULL;
 
3365
    }
 
3366
 
 
3367
    if (d->icon_pixmap)
 
3368
    {
 
3369
        gdk_pixmap_unref (d->icon_pixmap);
 
3370
        d->icon_pixmap = NULL;
 
3371
    }
 
3372
 
 
3373
    if (d->icon_pixbuf)
 
3374
    {
 
3375
        gdk_pixbuf_unref (d->icon_pixbuf);
 
3376
        d->icon_pixbuf = NULL;
 
3377
    }
 
3378
 
 
3379
    if (d->force_quit_dialog)
 
3380
    {
 
3381
        GtkWidget *dialog = d->force_quit_dialog;
 
3382
 
 
3383
        d->force_quit_dialog = NULL;
 
3384
        gtk_widget_destroy (dialog);
 
3385
    }
 
3386
 
 
3387
    d->width  = 0;
 
3388
    d->height = 0;
 
3389
 
 
3390
    d->decorated = FALSE;
 
3391
 
 
3392
    d->state   = 0;
 
3393
    d->actions = 0;
 
3394
 
 
3395
    draw_list = g_slist_remove (draw_list, d);
 
3396
}
 
3397
 
 
3398
static void
 
3399
window_name_changed (WnckWindow *win)
 
3400
{
 
3401
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
3402
 
 
3403
    if (d->decorated)
 
3404
    {
 
3405
        if (!update_window_decoration_size (win))
 
3406
            queue_decor_draw (d);
 
3407
    }
 
3408
}
 
3409
 
 
3410
static void
 
3411
window_geometry_changed (WnckWindow *win)
 
3412
{
 
3413
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
3414
 
 
3415
    if (d->decorated)
 
3416
    {
 
3417
        update_window_decoration_size (win);
 
3418
        update_event_windows (win);
 
3419
    }
 
3420
}
 
3421
 
 
3422
static void
 
3423
window_icon_changed (WnckWindow *win)
 
3424
{
 
3425
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
3426
 
 
3427
    if (d->decorated)
 
3428
    {
 
3429
        update_window_decoration_icon (win);
 
3430
        queue_decor_draw (d);
 
3431
    }
 
3432
}
 
3433
 
 
3434
static void
 
3435
window_state_changed (WnckWindow *win)
 
3436
{
 
3437
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
3438
 
 
3439
    if (d->decorated)
 
3440
    {
 
3441
        update_window_decoration_state (win);
 
3442
        queue_decor_draw (d);
 
3443
        update_event_windows (win);
 
3444
    }
 
3445
}
 
3446
 
 
3447
static void
 
3448
window_actions_changed (WnckWindow *win)
 
3449
{
 
3450
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
3451
 
 
3452
    if (d->decorated)
 
3453
    {
 
3454
        update_window_decoration_actions (win);
 
3455
        if (update_window_button_size (win))
 
3456
        {
 
3457
            update_window_decoration_size (win);
 
3458
            update_event_windows (win);
 
3459
        }
 
3460
        else
 
3461
        {
 
3462
            queue_decor_draw (d);
 
3463
        }
 
3464
    }
 
3465
}
 
3466
 
 
3467
static void
 
3468
connect_window (WnckWindow *win)
 
3469
{
 
3470
    g_signal_connect_object (win, "name_changed",
 
3471
                             G_CALLBACK (window_name_changed),
 
3472
                             0, 0);
 
3473
    g_signal_connect_object (win, "geometry_changed",
 
3474
                             G_CALLBACK (window_geometry_changed),
 
3475
                             0, 0);
 
3476
    g_signal_connect_object (win, "icon_changed",
 
3477
                             G_CALLBACK (window_icon_changed),
 
3478
                             0, 0);
 
3479
    g_signal_connect_object (win, "state_changed",
 
3480
                             G_CALLBACK (window_state_changed),
 
3481
                             0, 0);
 
3482
    g_signal_connect_object (win, "actions_changed",
 
3483
                             G_CALLBACK (window_actions_changed),
 
3484
                             0, 0);
 
3485
}
 
3486
 
 
3487
static void
 
3488
active_window_changed (WnckScreen *screen)
 
3489
{
 
3490
    WnckWindow *win;
 
3491
    decor_t    *d;
 
3492
 
 
3493
    win = wnck_screen_get_previously_active_window (screen);
 
3494
    if (win)
 
3495
    {
 
3496
        d = g_object_get_data (G_OBJECT (win), "decor");
 
3497
        if (d->pixmap)
 
3498
        {
 
3499
            d->active = wnck_window_is_active (win);
 
3500
            queue_decor_draw (d);
 
3501
        }
 
3502
    }
 
3503
 
 
3504
    win = wnck_screen_get_active_window (screen);
 
3505
    if (win)
 
3506
    {
 
3507
        d = g_object_get_data (G_OBJECT (win), "decor");
 
3508
        if (d->pixmap)
 
3509
        {
 
3510
            d->active = wnck_window_is_active (win);
 
3511
            queue_decor_draw (d);
 
3512
        }
 
3513
    }
 
3514
}
 
3515
 
 
3516
static void
 
3517
window_opened (WnckScreen *screen,
 
3518
               WnckWindow *win)
 
3519
{
 
3520
    decor_t *d;
 
3521
    Window  window;
 
3522
    gulong  xid;
 
3523
 
 
3524
    d = g_malloc (sizeof (decor_t));
 
3525
    if (!d)
 
3526
        return;
 
3527
 
 
3528
    d->pixmap        = NULL;
 
3529
    d->buffer_pixmap = NULL;
 
3530
    d->gc            = NULL;
 
3531
 
 
3532
    d->icon        = NULL;
 
3533
    d->icon_pixmap = NULL;
 
3534
    d->icon_pixbuf = NULL;
 
3535
 
 
3536
    d->button_width = 0;
 
3537
 
 
3538
    d->width  = 0;
 
3539
    d->height = 0;
 
3540
 
 
3541
    d->active = wnck_window_is_active (win);
 
3542
 
 
3543
    d->layout = NULL;
 
3544
    d->name   = NULL;
 
3545
 
 
3546
    d->state   = 0;
 
3547
    d->actions = 0;
 
3548
 
 
3549
    d->prop_xid = 0;
 
3550
 
 
3551
    d->decorated = FALSE;
 
3552
 
 
3553
    d->force_quit_dialog = NULL;
 
3554
 
 
3555
    d->draw = theme_draw_window_decoration;
 
3556
 
 
3557
    g_object_set_data (G_OBJECT (win), "decor", d);
 
3558
 
 
3559
    connect_window (win);
 
3560
 
 
3561
    xid = wnck_window_get_xid (win);
 
3562
 
 
3563
    if (get_window_prop (xid, frame_window_atom, &window))
 
3564
    {
 
3565
        add_frame_window (win, window);
 
3566
    }
 
3567
    else if (get_window_prop (xid, select_window_atom, &window))
 
3568
    {
 
3569
        d->prop_xid = wnck_window_get_xid (win);
 
3570
        update_switcher_window (win, window);
 
3571
    }
 
3572
}
 
3573
 
 
3574
static void
 
3575
window_closed (WnckScreen *screen,
 
3576
               WnckWindow *win)
 
3577
{
 
3578
    Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
 
3579
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
3580
 
 
3581
    remove_frame_window (win);
 
3582
 
 
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 ();
 
3587
 
 
3588
    g_free (d);
 
3589
}
 
3590
 
 
3591
static void
 
3592
connect_screen (WnckScreen *screen)
 
3593
{
 
3594
    GList *windows;
 
3595
 
 
3596
    g_signal_connect_object (G_OBJECT (screen), "active_window_changed",
 
3597
                             G_CALLBACK (active_window_changed),
 
3598
                             0, 0);
 
3599
    g_signal_connect_object (G_OBJECT (screen), "window_opened",
 
3600
                             G_CALLBACK (window_opened),
 
3601
                             0, 0);
 
3602
    g_signal_connect_object (G_OBJECT (screen), "window_closed",
 
3603
                             G_CALLBACK (window_closed),
 
3604
                             0, 0);
 
3605
 
 
3606
    windows = wnck_screen_get_windows (screen);
 
3607
    while (windows != NULL)
 
3608
    {
 
3609
        window_opened (screen, windows->data);
 
3610
        windows = windows->next;
 
3611
    }
 
3612
}
 
3613
 
 
3614
static void
 
3615
move_resize_window (WnckWindow *win,
 
3616
                    int        direction,
 
3617
                    XEvent     *xevent)
 
3618
{
 
3619
    Display    *xdisplay;
 
3620
    GdkDisplay *gdkdisplay;
 
3621
    GdkScreen  *screen;
 
3622
    Window     xroot;
 
3623
    XEvent     ev;
 
3624
 
 
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));
 
3629
 
 
3630
    if (action_menu_mapped)
 
3631
    {
 
3632
        gtk_object_destroy (GTK_OBJECT (action_menu));
 
3633
        action_menu_mapped = FALSE;
 
3634
        action_menu = NULL;
 
3635
        return;
 
3636
    }
 
3637
 
 
3638
    ev.xclient.type    = ClientMessage;
 
3639
    ev.xclient.display = xdisplay;
 
3640
 
 
3641
    ev.xclient.serial     = 0;
 
3642
    ev.xclient.send_event = TRUE;
 
3643
 
 
3644
    ev.xclient.window       = wnck_window_get_xid (win);
 
3645
    ev.xclient.message_type = wm_move_resize_atom;
 
3646
    ev.xclient.format       = 32;
 
3647
 
 
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;
 
3653
 
 
3654
    XUngrabPointer (xdisplay, xevent->xbutton.time);
 
3655
    XUngrabKeyboard (xdisplay, xevent->xbutton.time);
 
3656
 
 
3657
    XSendEvent (xdisplay, xroot, FALSE,
 
3658
                SubstructureRedirectMask | SubstructureNotifyMask,
 
3659
                &ev);
 
3660
 
 
3661
    XSync (xdisplay, FALSE);
 
3662
}
 
3663
 
 
3664
static void
 
3665
restack_window (WnckWindow *win,
 
3666
                int        stack_mode)
 
3667
{
 
3668
    Display    *xdisplay;
 
3669
    GdkDisplay *gdkdisplay;
 
3670
    GdkScreen  *screen;
 
3671
    Window     xroot;
 
3672
    XEvent     ev;
 
3673
 
 
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));
 
3678
 
 
3679
    if (action_menu_mapped)
 
3680
    {
 
3681
        gtk_object_destroy (GTK_OBJECT (action_menu));
 
3682
        action_menu_mapped = FALSE;
 
3683
        action_menu = NULL;
 
3684
        return;
 
3685
    }
 
3686
 
 
3687
    ev.xclient.type    = ClientMessage;
 
3688
    ev.xclient.display = xdisplay;
 
3689
 
 
3690
    ev.xclient.serial     = 0;
 
3691
    ev.xclient.send_event = TRUE;
 
3692
 
 
3693
    ev.xclient.window       = wnck_window_get_xid (win);
 
3694
    ev.xclient.message_type = restack_window_atom;
 
3695
    ev.xclient.format       = 32;
 
3696
 
 
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;
 
3702
 
 
3703
    XSendEvent (xdisplay, xroot, FALSE,
 
3704
                SubstructureRedirectMask | SubstructureNotifyMask,
 
3705
                &ev);
 
3706
 
 
3707
    XSync (xdisplay, FALSE);
 
3708
}
 
3709
 
 
3710
/* stolen from gtktooltip.c */
 
3711
 
 
3712
#define DEFAULT_DELAY 500           /* Default delay in ms */
 
3713
#define STICKY_DELAY 0              /* Delay before popping up next tip
 
3714
                                     * if we're sticky
 
3715
                                     */
 
3716
#define STICKY_REVERT_DELAY 1000    /* Delay before sticky tooltips revert
 
3717
                                     * to normal
 
3718
                                     */
 
3719
 
 
3720
static void
 
3721
show_tooltip (const char *text)
 
3722
{
 
3723
    GdkDisplay     *gdkdisplay;
 
3724
    GtkRequisition requisition;
 
3725
    gint           x, y, w, h;
 
3726
    GdkScreen      *screen;
 
3727
    gint           monitor_num;
 
3728
    GdkRectangle   monitor;
 
3729
 
 
3730
    gdkdisplay = gdk_display_get_default ();
 
3731
 
 
3732
    gtk_label_set_text (GTK_LABEL (tip_label), text);
 
3733
 
 
3734
    gtk_widget_size_request (tip_window, &requisition);
 
3735
 
 
3736
    w = requisition.width;
 
3737
    h = requisition.height;
 
3738
 
 
3739
    gdk_display_get_pointer (gdkdisplay, &screen, &x, &y, NULL);
 
3740
 
 
3741
    x -= (w / 2 + 4);
 
3742
 
 
3743
    monitor_num = gdk_screen_get_monitor_at_point (screen, x, y);
 
3744
    gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
 
3745
 
 
3746
    if ((x + w) > monitor.x + monitor.width)
 
3747
        x -= (x + w) - (monitor.x + monitor.width);
 
3748
    else if (x < monitor.x)
 
3749
        x = monitor.x;
 
3750
 
 
3751
    if ((y + h + 16) > monitor.y + monitor.height)
 
3752
        y = y - h - 16;
 
3753
    else
 
3754
        y = y + 16;
 
3755
 
 
3756
    gtk_window_move (GTK_WINDOW (tip_window), x, y);
 
3757
    gtk_widget_show (tip_window);
 
3758
}
 
3759
 
 
3760
static void
 
3761
hide_tooltip (void)
 
3762
{
 
3763
    if (GTK_WIDGET_VISIBLE (tip_window))
 
3764
        g_get_current_time (&tooltip_last_popdown);
 
3765
 
 
3766
    gtk_widget_hide (tip_window);
 
3767
 
 
3768
    if (tooltip_timer_tag)
 
3769
    {
 
3770
        g_source_remove (tooltip_timer_tag);
 
3771
        tooltip_timer_tag = 0;
 
3772
    }
 
3773
}
 
3774
 
 
3775
static gboolean
 
3776
tooltip_recently_shown (void)
 
3777
{
 
3778
    GTimeVal now;
 
3779
    glong    msec;
 
3780
 
 
3781
    g_get_current_time (&now);
 
3782
 
 
3783
    msec = (now.tv_sec - tooltip_last_popdown.tv_sec) * 1000 +
 
3784
        (now.tv_usec - tooltip_last_popdown.tv_usec) / 1000;
 
3785
 
 
3786
    return (msec < STICKY_REVERT_DELAY);
 
3787
}
 
3788
 
 
3789
static gint
 
3790
tooltip_timeout (gpointer data)
 
3791
{
 
3792
    tooltip_timer_tag = 0;
 
3793
 
 
3794
    show_tooltip ((const char *) data);
 
3795
 
 
3796
    return FALSE;
 
3797
}
 
3798
 
 
3799
static void
 
3800
tooltip_start_delay (const char *text)
 
3801
{
 
3802
    guint delay = DEFAULT_DELAY;
 
3803
 
 
3804
    if (tooltip_timer_tag)
 
3805
        return;
 
3806
 
 
3807
    if (tooltip_recently_shown ())
 
3808
        delay = STICKY_DELAY;
 
3809
 
 
3810
    tooltip_timer_tag = g_timeout_add (delay,
 
3811
                                       tooltip_timeout,
 
3812
                                       (gpointer) text);
 
3813
}
 
3814
 
 
3815
static gint
 
3816
tooltip_paint_window (GtkWidget *tooltip)
 
3817
{
 
3818
    GtkRequisition req;
 
3819
 
 
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);
 
3825
 
 
3826
    return FALSE;
 
3827
}
 
3828
 
 
3829
static gboolean
 
3830
create_tooltip_window (void)
 
3831
{
 
3832
    tip_window = gtk_window_new (GTK_WINDOW_POPUP);
 
3833
 
 
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);
 
3838
 
 
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);
 
3843
#endif
 
3844
 
 
3845
    g_signal_connect_swapped (tip_window,
 
3846
                              "expose_event",
 
3847
                              G_CALLBACK (tooltip_paint_window),
 
3848
                              0);
 
3849
 
 
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);
 
3854
 
 
3855
    gtk_container_add (GTK_CONTAINER (tip_window), tip_label);
 
3856
 
 
3857
    gtk_widget_ensure_style (tip_window);
 
3858
 
 
3859
    return TRUE;
 
3860
}
 
3861
 
 
3862
static void
 
3863
handle_tooltip_event (WnckWindow *win,
 
3864
                      XEvent     *xevent,
 
3865
                      guint      state,
 
3866
                      const char *tip)
 
3867
{
 
3868
    switch (xevent->type) {
 
3869
    case ButtonPress:
 
3870
        hide_tooltip ();
 
3871
        break;
 
3872
    case ButtonRelease:
 
3873
        break;
 
3874
    case EnterNotify:
 
3875
        if (!(state & PRESSED_EVENT_WINDOW))
 
3876
        {
 
3877
            if (wnck_window_is_active (win))
 
3878
                tooltip_start_delay (tip);
 
3879
        }
 
3880
        break;
 
3881
    case LeaveNotify:
 
3882
        hide_tooltip ();
 
3883
        break;
 
3884
    }
 
3885
}
 
3886
 
 
3887
static void
 
3888
close_button_event (WnckWindow *win,
 
3889
                    XEvent     *xevent)
 
3890
{
 
3891
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
3892
    guint   state = d->button_states[0];
 
3893
 
 
3894
    handle_tooltip_event (win, xevent, state, "Close Window");
 
3895
 
 
3896
    switch (xevent->type) {
 
3897
    case ButtonPress:
 
3898
        if (xevent->xbutton.button == 1)
 
3899
            d->button_states[0] |= PRESSED_EVENT_WINDOW;
 
3900
        break;
 
3901
    case ButtonRelease:
 
3902
        if (xevent->xbutton.button == 1)
 
3903
        {
 
3904
            if (d->button_states[0] == (PRESSED_EVENT_WINDOW | IN_EVENT_WINDOW))
 
3905
                wnck_window_close (win, xevent->xbutton.time);
 
3906
 
 
3907
            d->button_states[0] &= ~PRESSED_EVENT_WINDOW;
 
3908
        }
 
3909
        break;
 
3910
    case EnterNotify:
 
3911
        d->button_states[0] |= IN_EVENT_WINDOW;
 
3912
        break;
 
3913
    case LeaveNotify:
 
3914
        d->button_states[0] &= ~IN_EVENT_WINDOW;
 
3915
        break;
 
3916
    }
 
3917
 
 
3918
    if (state != d->button_states[0])
 
3919
        queue_decor_draw (d);
 
3920
}
 
3921
 
 
3922
static void
 
3923
max_button_event (WnckWindow *win,
 
3924
                  XEvent     *xevent)
 
3925
{
 
3926
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
3927
    guint   state = d->button_states[1];
 
3928
 
 
3929
    if (wnck_window_is_maximized (win))
 
3930
        handle_tooltip_event (win, xevent, state, "Unmaximize Window");
 
3931
    else
 
3932
        handle_tooltip_event (win, xevent, state, "Maximize Window");
 
3933
 
 
3934
    switch (xevent->type) {
 
3935
    case ButtonPress:
 
3936
        if (xevent->xbutton.button == 1)
 
3937
            d->button_states[1] |= PRESSED_EVENT_WINDOW;
 
3938
        break;
 
3939
    case ButtonRelease:
 
3940
        if (xevent->xbutton.button == 1)
 
3941
        {
 
3942
            if (d->button_states[1] == (PRESSED_EVENT_WINDOW | IN_EVENT_WINDOW))
 
3943
            {
 
3944
                if (wnck_window_is_maximized (win))
 
3945
                    wnck_window_unmaximize (win);
 
3946
                else
 
3947
                    wnck_window_maximize (win);
 
3948
            }
 
3949
 
 
3950
            d->button_states[1] &= ~PRESSED_EVENT_WINDOW;
 
3951
        }
 
3952
        break;
 
3953
    case EnterNotify:
 
3954
        d->button_states[1] |= IN_EVENT_WINDOW;
 
3955
        break;
 
3956
    case LeaveNotify:
 
3957
        d->button_states[1] &= ~IN_EVENT_WINDOW;
 
3958
        break;
 
3959
    }
 
3960
 
 
3961
    if (state != d->button_states[1])
 
3962
        queue_decor_draw (d);
 
3963
}
 
3964
 
 
3965
static void
 
3966
min_button_event (WnckWindow *win,
 
3967
                  XEvent     *xevent)
 
3968
{
 
3969
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
3970
    guint   state = d->button_states[2];
 
3971
 
 
3972
    handle_tooltip_event (win, xevent, state, "Minimize Window");
 
3973
 
 
3974
    switch (xevent->type) {
 
3975
    case ButtonPress:
 
3976
        if (xevent->xbutton.button == 1)
 
3977
            d->button_states[2] |= PRESSED_EVENT_WINDOW;
 
3978
        break;
 
3979
    case ButtonRelease:
 
3980
        if (xevent->xbutton.button == 1)
 
3981
        {
 
3982
            if (d->button_states[2] == (PRESSED_EVENT_WINDOW | IN_EVENT_WINDOW))
 
3983
                wnck_window_minimize (win);
 
3984
 
 
3985
            d->button_states[2] &= ~PRESSED_EVENT_WINDOW;
 
3986
        }
 
3987
        break;
 
3988
    case EnterNotify:
 
3989
        d->button_states[2] |= IN_EVENT_WINDOW;
 
3990
        if (wnck_window_is_active (win))
 
3991
            tooltip_start_delay ("Minimize Window");
 
3992
        break;
 
3993
    case LeaveNotify:
 
3994
        d->button_states[2] &= ~IN_EVENT_WINDOW;
 
3995
        break;
 
3996
    }
 
3997
 
 
3998
    if (state != d->button_states[2])
 
3999
        queue_decor_draw (d);
 
4000
}
 
4001
 
 
4002
static void
 
4003
top_left_event (WnckWindow *win,
 
4004
                XEvent     *xevent)
 
4005
{
 
4006
    if (xevent->xbutton.button == 1)
 
4007
        move_resize_window (win, WM_MOVERESIZE_SIZE_TOPLEFT, xevent);
 
4008
}
 
4009
 
 
4010
static void
 
4011
top_event (WnckWindow *win,
 
4012
           XEvent     *xevent)
 
4013
{
 
4014
    if (xevent->xbutton.button == 1)
 
4015
        move_resize_window (win, WM_MOVERESIZE_SIZE_TOP, xevent);
 
4016
}
 
4017
 
 
4018
static void
 
4019
top_right_event (WnckWindow *win,
 
4020
                 XEvent     *xevent)
 
4021
{
 
4022
    if (xevent->xbutton.button == 1)
 
4023
        move_resize_window (win, WM_MOVERESIZE_SIZE_TOPRIGHT, xevent);
 
4024
}
 
4025
 
 
4026
static void
 
4027
left_event (WnckWindow *win,
 
4028
            XEvent     *xevent)
 
4029
{
 
4030
    if (xevent->xbutton.button == 1)
 
4031
        move_resize_window (win, WM_MOVERESIZE_SIZE_LEFT, xevent);
 
4032
}
 
4033
 
 
4034
static void
 
4035
action_menu_unmap (GObject *object)
 
4036
{
 
4037
    action_menu_mapped = FALSE;
 
4038
}
 
4039
 
 
4040
static void
 
4041
position_action_menu (GtkMenu  *menu,
 
4042
                      gint     *x,
 
4043
                      gint     *y,
 
4044
                      gboolean *push_in,
 
4045
                      gpointer user_data)
 
4046
{
 
4047
    WnckWindow *win = (WnckWindow *) user_data;
 
4048
 
 
4049
    wnck_window_get_geometry (win, x, y, NULL, NULL);
 
4050
 
 
4051
    *push_in = TRUE;
 
4052
}
 
4053
 
 
4054
static void
 
4055
action_menu_map (WnckWindow *win,
 
4056
                 long       button,
 
4057
                 Time       time)
 
4058
{
 
4059
    GdkDisplay *gdkdisplay;
 
4060
    GdkScreen  *screen;
 
4061
 
 
4062
    gdkdisplay = gdk_display_get_default ();
 
4063
    screen     = gdk_display_get_default_screen (gdkdisplay);
 
4064
 
 
4065
    if (action_menu)
 
4066
    {
 
4067
        if (action_menu_mapped)
 
4068
        {
 
4069
            gtk_widget_destroy (action_menu);
 
4070
            action_menu_mapped = FALSE;
 
4071
            action_menu = NULL;
 
4072
            return;
 
4073
        }
 
4074
        else
 
4075
            gtk_widget_destroy (action_menu);
 
4076
    }
 
4077
 
 
4078
    switch (wnck_window_get_window_type (win)) {
 
4079
    case WNCK_WINDOW_DESKTOP:
 
4080
    case WNCK_WINDOW_DOCK:
 
4081
        /* don't allow window action */
 
4082
        return;
 
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 */
 
4091
        break;
 
4092
    }
 
4093
 
 
4094
    action_menu = wnck_create_window_action_menu (win);
 
4095
 
 
4096
    gtk_menu_set_screen (GTK_MENU (action_menu), screen);
 
4097
 
 
4098
    g_signal_connect_object (G_OBJECT (action_menu), "unmap",
 
4099
                             G_CALLBACK (action_menu_unmap),
 
4100
                             0, 0);
 
4101
 
 
4102
    gtk_widget_show (action_menu);
 
4103
 
 
4104
    if (button)
 
4105
        gtk_menu_popup (GTK_MENU (action_menu),
 
4106
                        NULL, NULL,
 
4107
                        NULL, NULL,
 
4108
                        button,
 
4109
                        time);
 
4110
    else
 
4111
        gtk_menu_popup (GTK_MENU (action_menu),
 
4112
                        NULL, NULL,
 
4113
                        position_action_menu, (gpointer) win,
 
4114
                        button,
 
4115
                        time);
 
4116
 
 
4117
    action_menu_mapped = TRUE;
 
4118
}
 
4119
 
 
4120
static double
 
4121
square (double x)
 
4122
{
 
4123
    return x * x;
 
4124
}
 
4125
 
 
4126
static double
 
4127
dist (double x1, double y1,
 
4128
      double x2, double y2)
 
4129
{
 
4130
    return sqrt (square (x1 - x2) + square (y1 - y2));
 
4131
}
 
4132
 
 
4133
static void
 
4134
title_event (WnckWindow *win,
 
4135
             XEvent     *xevent)
 
4136
{
 
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;
 
4142
 
 
4143
    if (xevent->type != ButtonPress)
 
4144
        return;
 
4145
 
 
4146
    if (xevent->xbutton.button == 1)
 
4147
    {
 
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)
 
4153
        {
 
4154
            switch (double_click_action) {
 
4155
            case DOUBLE_CLICK_SHADE:
 
4156
                if (wnck_window_is_shaded (win))
 
4157
                    wnck_window_unshade (win);
 
4158
                else
 
4159
                    wnck_window_shade (win);
 
4160
                break;
 
4161
            case DOUBLE_CLICK_MAXIMIZE:
 
4162
                if (wnck_window_is_maximized (win))
 
4163
                    wnck_window_unmaximize (win);
 
4164
                else
 
4165
                    wnck_window_maximize (win);
 
4166
            default:
 
4167
                break;
 
4168
            }
 
4169
 
 
4170
            last_button_num     = 0;
 
4171
            last_button_xwindow = None;
 
4172
            last_button_time    = 0;
 
4173
            last_button_x       = 0;
 
4174
            last_button_y       = 0;
 
4175
        }
 
4176
        else
 
4177
        {
 
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;
 
4183
 
 
4184
            restack_window (win, Above);
 
4185
 
 
4186
            move_resize_window (win, WM_MOVERESIZE_MOVE, xevent);
 
4187
        }
 
4188
    }
 
4189
    else if (xevent->xbutton.button == 2)
 
4190
    {
 
4191
        restack_window (win, Below);
 
4192
    }
 
4193
    else if (xevent->xbutton.button == 3)
 
4194
    {
 
4195
        action_menu_map (win,
 
4196
                         xevent->xbutton.button,
 
4197
                         xevent->xbutton.time);
 
4198
    }
 
4199
}
 
4200
 
 
4201
static void
 
4202
right_event (WnckWindow *win,
 
4203
             XEvent     *xevent)
 
4204
{
 
4205
    if (xevent->xbutton.button == 1)
 
4206
        move_resize_window (win, WM_MOVERESIZE_SIZE_RIGHT, xevent);
 
4207
}
 
4208
 
 
4209
static void
 
4210
bottom_left_event (WnckWindow *win,
 
4211
                   XEvent     *xevent)
 
4212
{
 
4213
    if (xevent->xbutton.button == 1)
 
4214
        move_resize_window (win, WM_MOVERESIZE_SIZE_BOTTOMLEFT, xevent);
 
4215
}
 
4216
 
 
4217
static void
 
4218
bottom_event (WnckWindow *win,
 
4219
              XEvent     *xevent)
 
4220
{
 
4221
    if (xevent->xbutton.button == 1)
 
4222
        move_resize_window (win, WM_MOVERESIZE_SIZE_BOTTOM, xevent);
 
4223
}
 
4224
 
 
4225
static void
 
4226
bottom_right_event (WnckWindow *win,
 
4227
                    XEvent     *xevent)
 
4228
{
 
4229
    if (xevent->xbutton.button == 1)
 
4230
        move_resize_window (win, WM_MOVERESIZE_SIZE_BOTTOMRIGHT, xevent);
 
4231
}
 
4232
 
 
4233
static void
 
4234
panel_action (Display *xdisplay,
 
4235
              Window  root,
 
4236
              Atom    panel_action,
 
4237
              Time    event_time)
 
4238
{
 
4239
    XEvent ev;
 
4240
 
 
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;
 
4250
 
 
4251
    XSendEvent (xdisplay, root, FALSE, StructureNotifyMask, &ev);
 
4252
}
 
4253
 
 
4254
static void
 
4255
force_quit_dialog_realize (GtkWidget *dialog,
 
4256
                           void      *data)
 
4257
{
 
4258
    WnckWindow *win = data;
 
4259
 
 
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 ();
 
4266
}
 
4267
 
 
4268
static char *
 
4269
get_client_machine (Window xwindow)
 
4270
{
 
4271
    Atom   atom, type;
 
4272
    gulong nitems, bytes_after;
 
4273
    gchar  *str = NULL;
 
4274
    int    format, result;
 
4275
    char   *retval;
 
4276
 
 
4277
    atom = XInternAtom (gdk_display, "WM_CLIENT_MACHINE", FALSE);
 
4278
 
 
4279
    gdk_error_trap_push ();
 
4280
 
 
4281
    result = XGetWindowProperty (gdk_display,
 
4282
                                 xwindow, atom,
 
4283
                                 0, G_MAXLONG,
 
4284
                                 FALSE, XA_STRING, &type, &format, &nitems,
 
4285
                                 &bytes_after, (guchar **) &str);
 
4286
 
 
4287
    gdk_error_trap_pop ();
 
4288
 
 
4289
    if (result != Success)
 
4290
        return NULL;
 
4291
 
 
4292
    if (type != XA_STRING)
 
4293
    {
 
4294
        XFree (str);
 
4295
        return NULL;
 
4296
    }
 
4297
 
 
4298
    retval = g_strdup (str);
 
4299
 
 
4300
    XFree (str);
 
4301
 
 
4302
    return retval;
 
4303
}
 
4304
 
 
4305
static void
 
4306
kill_window (WnckWindow *win)
 
4307
{
 
4308
    WnckApplication *app;
 
4309
 
 
4310
    app = wnck_window_get_application (win);
 
4311
    if (app)
 
4312
    {
 
4313
        gchar buf[257], *client_machine;
 
4314
        int   pid;
 
4315
 
 
4316
        pid = wnck_application_get_pid (app);
 
4317
        client_machine = get_client_machine (wnck_application_get_xid (app));
 
4318
 
 
4319
        if (client_machine && pid > 0)
 
4320
        {
 
4321
            if (gethostname (buf, sizeof (buf) - 1) == 0)
 
4322
            {
 
4323
                if (strcmp (buf, client_machine) == 0)
 
4324
                    kill (pid, 9);
 
4325
            }
 
4326
        }
 
4327
 
 
4328
        if (client_machine)
 
4329
            g_free (client_machine);
 
4330
    }
 
4331
 
 
4332
    gdk_error_trap_push ();
 
4333
    XKillClient (gdk_display, wnck_window_get_xid (win));
 
4334
    XSync (gdk_display, FALSE);
 
4335
    gdk_error_trap_pop ();
 
4336
}
 
4337
 
 
4338
static void
 
4339
force_quit_dialog_response (GtkWidget *dialog,
 
4340
                            gint      response,
 
4341
                            void      *data)
 
4342
{
 
4343
    WnckWindow *win = data;
 
4344
    decor_t    *d = g_object_get_data (G_OBJECT (win), "decor");
 
4345
 
 
4346
    if (response == GTK_RESPONSE_ACCEPT)
 
4347
        kill_window (win);
 
4348
 
 
4349
    if (d->force_quit_dialog)
 
4350
    {
 
4351
        d->force_quit_dialog = NULL;
 
4352
        gtk_widget_destroy (dialog);
 
4353
    }
 
4354
}
 
4355
 
 
4356
static void
 
4357
show_force_quit_dialog (WnckWindow *win,
 
4358
                        Time        timestamp)
 
4359
{
 
4360
    decor_t   *d = g_object_get_data (G_OBJECT (win), "decor");
 
4361
    GtkWidget *dialog;
 
4362
    gchar     *str, *tmp;
 
4363
 
 
4364
    if (d->force_quit_dialog)
 
4365
        return;
 
4366
 
 
4367
    tmp = g_markup_escape_text (wnck_window_get_name (win), -1);
 
4368
    str = g_strdup_printf ("The window \"%s\" is not responding.", tmp);
 
4369
 
 
4370
    g_free (tmp);
 
4371
 
 
4372
    dialog = gtk_message_dialog_new (NULL, 0,
 
4373
                                     GTK_MESSAGE_WARNING,
 
4374
                                     GTK_BUTTONS_NONE,
 
4375
                                     "<b>%s</b>\n\n%s",
 
4376
                                     str,
 
4377
                                     "Forcing this application to "
 
4378
                                     "quit will cause you to lose any "
 
4379
                                     "unsaved changes.");
 
4380
    g_free (str);
 
4381
 
 
4382
    gtk_window_set_icon_name (GTK_WINDOW (dialog), "force-quit");
 
4383
 
 
4384
    gtk_label_set_use_markup (GTK_LABEL (GTK_MESSAGE_DIALOG (dialog)->label),
 
4385
                              TRUE);
 
4386
    gtk_label_set_line_wrap (GTK_LABEL (GTK_MESSAGE_DIALOG (dialog)->label),
 
4387
                             TRUE);
 
4388
 
 
4389
    gtk_dialog_add_buttons (GTK_DIALOG (dialog),
 
4390
                            GTK_STOCK_CANCEL,
 
4391
                            GTK_RESPONSE_REJECT,
 
4392
                            "_Force Quit",
 
4393
                            GTK_RESPONSE_ACCEPT,
 
4394
                            NULL);
 
4395
 
 
4396
    gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_REJECT);
 
4397
 
 
4398
    g_signal_connect (G_OBJECT (dialog), "realize",
 
4399
                      G_CALLBACK (force_quit_dialog_realize),
 
4400
                      win);
 
4401
 
 
4402
    g_signal_connect (G_OBJECT (dialog), "response",
 
4403
                      G_CALLBACK (force_quit_dialog_response),
 
4404
                      win);
 
4405
 
 
4406
    gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
 
4407
 
 
4408
    gtk_widget_realize (dialog);
 
4409
 
 
4410
    gdk_x11_window_set_user_time (dialog->window, timestamp);
 
4411
 
 
4412
    gtk_widget_show (dialog);
 
4413
 
 
4414
    d->force_quit_dialog = dialog;
 
4415
}
 
4416
 
 
4417
static void
 
4418
hide_force_quit_dialog (WnckWindow *win)
 
4419
{
 
4420
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
4421
 
 
4422
    if (d->force_quit_dialog)
 
4423
    {
 
4424
        gtk_widget_destroy (d->force_quit_dialog);
 
4425
        d->force_quit_dialog = NULL;
 
4426
    }
 
4427
}
 
4428
 
 
4429
/* from fvwm2, Copyright Matthias Clasen, Dominik Vogt */
 
4430
static gboolean
 
4431
convert_property (Display *xdisplay,
 
4432
                  Window  w,
 
4433
                  Atom    target,
 
4434
                  Atom    property)
 
4435
{
 
4436
 
 
4437
#define N_TARGETS 4
 
4438
 
 
4439
    Atom conversion_targets[N_TARGETS];
 
4440
    long icccm_version[] = { 2, 0 };
 
4441
 
 
4442
    conversion_targets[0] = targets_atom;
 
4443
    conversion_targets[1] = multiple_atom;
 
4444
    conversion_targets[2] = timestamp_atom;
 
4445
    conversion_targets[3] = version_atom;
 
4446
 
 
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);
 
4459
    else
 
4460
        return FALSE;
 
4461
 
 
4462
    /* Be sure the PropertyNotify has arrived so we
 
4463
     * can send SelectionNotify
 
4464
     */
 
4465
    XSync (xdisplay, FALSE);
 
4466
 
 
4467
    return TRUE;
 
4468
}
 
4469
 
 
4470
static void
 
4471
handle_selection_request (Display *xdisplay,
 
4472
                          XEvent  *event)
 
4473
{
 
4474
    XSelectionEvent reply;
 
4475
 
 
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;
 
4483
 
 
4484
    if (event->xselectionrequest.target == multiple_atom)
 
4485
    {
 
4486
        if (event->xselectionrequest.property != None)
 
4487
        {
 
4488
            Atom          type, *adata;
 
4489
            int           i, format;
 
4490
            unsigned long num, rest;
 
4491
            unsigned char *data;
 
4492
 
 
4493
            if (XGetWindowProperty (xdisplay,
 
4494
                                    event->xselectionrequest.requestor,
 
4495
                                    event->xselectionrequest.property,
 
4496
                                    0, 256, FALSE,
 
4497
                                    atom_pair_atom,
 
4498
                                    &type, &format, &num, &rest,
 
4499
                                    &data) != Success)
 
4500
                return;
 
4501
 
 
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
 
4505
             */
 
4506
            adata = (Atom *) data;
 
4507
            i = 0;
 
4508
            while (i < (int) num)
 
4509
            {
 
4510
                if (!convert_property (xdisplay,
 
4511
                                       event->xselectionrequest.requestor,
 
4512
                                       adata[i], adata[i + 1]))
 
4513
                    adata[i + 1] = None;
 
4514
 
 
4515
                i += 2;
 
4516
            }
 
4517
 
 
4518
            XChangeProperty (xdisplay,
 
4519
                             event->xselectionrequest.requestor,
 
4520
                             event->xselectionrequest.property,
 
4521
                             atom_pair_atom,
 
4522
                             32, PropModeReplace, data, num);
 
4523
        }
 
4524
    }
 
4525
    else
 
4526
    {
 
4527
        if (event->xselectionrequest.property == None)
 
4528
            event->xselectionrequest.property = event->xselectionrequest.target;
 
4529
 
 
4530
        if (convert_property (xdisplay,
 
4531
                              event->xselectionrequest.requestor,
 
4532
                              event->xselectionrequest.target,
 
4533
                              event->xselectionrequest.property))
 
4534
            reply.property = event->xselectionrequest.property;
 
4535
    }
 
4536
 
 
4537
    XSendEvent (xdisplay,
 
4538
                event->xselectionrequest.requestor,
 
4539
                FALSE, 0L, (XEvent *) &reply);
 
4540
}
 
4541
 
 
4542
static void
 
4543
handle_selection_clear (Display *xdisplay,
 
4544
                        XEvent  *xevent)
 
4545
{
 
4546
    if (xevent->xselectionclear.selection == dm_sn_atom)
 
4547
        exit (0);
 
4548
}
 
4549
 
 
4550
static gboolean
 
4551
acquire_dm_session (Display  *xdisplay,
 
4552
                    int      screen,
 
4553
                    gboolean replace_current_dm)
 
4554
{
 
4555
    XEvent               event;
 
4556
    XSetWindowAttributes attr;
 
4557
    Window               current_dm_sn_owner, new_dm_sn_owner;
 
4558
    char                 buf[128];
 
4559
 
 
4560
    sprintf (buf, "DM_S%d", screen);
 
4561
    dm_sn_atom = XInternAtom (xdisplay, buf, 0);
 
4562
 
 
4563
    current_dm_sn_owner = XGetSelectionOwner (xdisplay, dm_sn_atom);
 
4564
 
 
4565
    if (current_dm_sn_owner != None)
 
4566
    {
 
4567
        if (!replace_current_dm)
 
4568
        {
 
4569
            fprintf (stderr,
 
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));
 
4575
 
 
4576
            return FALSE;
 
4577
        }
 
4578
 
 
4579
        XSelectInput (xdisplay, current_dm_sn_owner, StructureNotifyMask);
 
4580
    }
 
4581
 
 
4582
    attr.override_redirect = TRUE;
 
4583
    attr.event_mask        = PropertyChangeMask;
 
4584
 
 
4585
    new_dm_sn_owner =
 
4586
        XCreateWindow (xdisplay, XRootWindow (xdisplay, screen),
 
4587
                       -100, -100, 1, 1, 0,
 
4588
                       CopyFromParent, CopyFromParent,
 
4589
                       CopyFromParent,
 
4590
                       CWOverrideRedirect | CWEventMask,
 
4591
                       &attr);
 
4592
 
 
4593
    XChangeProperty (xdisplay,
 
4594
                     new_dm_sn_owner,
 
4595
                     dm_name_atom,
 
4596
                     utf8_string_atom, 8,
 
4597
                     PropModeReplace,
 
4598
                     (unsigned char *) "gwd",
 
4599
                     strlen ("gwd"));
 
4600
 
 
4601
    XWindowEvent (xdisplay,
 
4602
                  new_dm_sn_owner,
 
4603
                  PropertyChangeMask,
 
4604
                  &event);
 
4605
 
 
4606
    dm_sn_timestamp = event.xproperty.time;
 
4607
 
 
4608
    XSetSelectionOwner (xdisplay, dm_sn_atom, new_dm_sn_owner,
 
4609
                        dm_sn_timestamp);
 
4610
 
 
4611
    if (XGetSelectionOwner (xdisplay, dm_sn_atom) != new_dm_sn_owner)
 
4612
    {
 
4613
        fprintf (stderr,
 
4614
                 "%s: Could not acquire decoration manager "
 
4615
                 "selection on screen %d display \"%s\"\n",
 
4616
                 program_name, screen, DisplayString (xdisplay));
 
4617
 
 
4618
        XDestroyWindow (xdisplay, new_dm_sn_owner);
 
4619
 
 
4620
        return FALSE;
 
4621
    }
 
4622
 
 
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;
 
4633
 
 
4634
    XSendEvent (xdisplay, XRootWindow (xdisplay, screen), FALSE,
 
4635
                StructureNotifyMask, &event);
 
4636
 
 
4637
    /* Wait for old decoration manager to go away */
 
4638
    if (current_dm_sn_owner != None)
 
4639
    {
 
4640
        do {
 
4641
            XWindowEvent (xdisplay, current_dm_sn_owner,
 
4642
                          StructureNotifyMask, &event);
 
4643
        } while (event.type != DestroyNotify);
 
4644
    }
 
4645
 
 
4646
    return TRUE;
 
4647
}
 
4648
 
 
4649
static GdkFilterReturn
 
4650
event_filter_func (GdkXEvent *gdkxevent,
 
4651
                   GdkEvent  *event,
 
4652
                   gpointer  data)
 
4653
{
 
4654
    Display    *xdisplay;
 
4655
    GdkDisplay *gdkdisplay;
 
4656
    XEvent     *xevent = gdkxevent;
 
4657
    gulong     xid = 0;
 
4658
 
 
4659
    gdkdisplay = gdk_display_get_default ();
 
4660
    xdisplay   = GDK_DISPLAY_XDISPLAY (gdkdisplay);
 
4661
 
 
4662
    switch (xevent->type) {
 
4663
    case ButtonPress:
 
4664
    case ButtonRelease:
 
4665
        xid = (gulong)
 
4666
            g_hash_table_lookup (frame_table,
 
4667
                                 GINT_TO_POINTER (xevent->xbutton.window));
 
4668
        break;
 
4669
    case EnterNotify:
 
4670
    case LeaveNotify:
 
4671
        xid = (gulong)
 
4672
            g_hash_table_lookup (frame_table,
 
4673
                                 GINT_TO_POINTER (xevent->xcrossing.window));
 
4674
        break;
 
4675
    case MotionNotify:
 
4676
        xid = (gulong)
 
4677
            g_hash_table_lookup (frame_table,
 
4678
                                 GINT_TO_POINTER (xevent->xmotion.window));
 
4679
        break;
 
4680
    case PropertyNotify:
 
4681
        if (xevent->xproperty.atom == frame_window_atom)
 
4682
        {
 
4683
            WnckWindow *win;
 
4684
 
 
4685
            xid = xevent->xproperty.window;
 
4686
 
 
4687
            win = wnck_window_get (xid);
 
4688
            if (win)
 
4689
            {
 
4690
                Window frame;
 
4691
 
 
4692
                if (get_window_prop (xid, frame_window_atom, &frame))
 
4693
                    add_frame_window (win, frame);
 
4694
                else
 
4695
                    remove_frame_window (win);
 
4696
            }
 
4697
        }
 
4698
        else if (xevent->xproperty.atom == mwm_hints_atom)
 
4699
        {
 
4700
            WnckWindow *win;
 
4701
 
 
4702
            xid = xevent->xproperty.window;
 
4703
 
 
4704
            win = wnck_window_get (xid);
 
4705
            if (win)
 
4706
            {
 
4707
                decor_t  *d = g_object_get_data (G_OBJECT (win), "decor");
 
4708
                gboolean decorated = FALSE;
 
4709
 
 
4710
                if (get_mwm_prop (xid) & (MWM_DECOR_ALL | MWM_DECOR_TITLE))
 
4711
                    decorated = TRUE;
 
4712
 
 
4713
                if (decorated != d->decorated)
 
4714
                {
 
4715
                    d->decorated = decorated;
 
4716
                    if (decorated)
 
4717
                    {
 
4718
                        d->width = d->height = 0;
 
4719
 
 
4720
                        update_window_decoration_size (win);
 
4721
                        update_event_windows (win);
 
4722
                    }
 
4723
                    else
 
4724
                    {
 
4725
                        gdk_error_trap_push ();
 
4726
                        XDeleteProperty (xdisplay, xid, win_decor_atom);
 
4727
                        XSync (xdisplay, FALSE);
 
4728
                        gdk_error_trap_pop ();
 
4729
                    }
 
4730
                }
 
4731
            }
 
4732
        }
 
4733
        else if (xevent->xproperty.atom == select_window_atom)
 
4734
        {
 
4735
            WnckWindow *win;
 
4736
 
 
4737
            xid = xevent->xproperty.window;
 
4738
 
 
4739
            win = wnck_window_get (xid);
 
4740
            if (win)
 
4741
            {
 
4742
                Window select;
 
4743
 
 
4744
                if (get_window_prop (xid, select_window_atom, &select))
 
4745
                    update_switcher_window (win, select);
 
4746
            }
 
4747
        }
 
4748
        break;
 
4749
    case DestroyNotify:
 
4750
        g_hash_table_remove (frame_table,
 
4751
                             GINT_TO_POINTER (xevent->xproperty.window));
 
4752
        break;
 
4753
    case ClientMessage:
 
4754
        if (xevent->xclient.message_type == toolkit_action_atom)
 
4755
        {
 
4756
            long action;
 
4757
 
 
4758
            action = xevent->xclient.data.l[0];
 
4759
            if (action == toolkit_action_main_menu_atom)
 
4760
            {
 
4761
                panel_action (xdisplay, xevent->xclient.window,
 
4762
                              panel_action_main_menu_atom,
 
4763
                              xevent->xclient.data.l[1]);
 
4764
            }
 
4765
            else if (action == toolkit_action_run_dialog_atom)
 
4766
            {
 
4767
                panel_action (xdisplay, xevent->xclient.window,
 
4768
                              panel_action_run_dialog_atom,
 
4769
                              xevent->xclient.data.l[1]);
 
4770
            }
 
4771
            else if (action == toolkit_action_window_menu_atom)
 
4772
            {
 
4773
                WnckWindow *win;
 
4774
 
 
4775
                win = wnck_window_get (xevent->xclient.window);
 
4776
                if (win)
 
4777
                {
 
4778
                    action_menu_map (win,
 
4779
                                     xevent->xclient.data.l[2],
 
4780
                                     xevent->xclient.data.l[1]);
 
4781
                }
 
4782
            }
 
4783
            else if (action == toolkit_action_force_quit_dialog_atom)
 
4784
            {
 
4785
                WnckWindow *win;
 
4786
 
 
4787
                win = wnck_window_get (xevent->xclient.window);
 
4788
                if (win)
 
4789
                {
 
4790
                    if (xevent->xclient.data.l[2])
 
4791
                        show_force_quit_dialog (win,
 
4792
                                                xevent->xclient.data.l[1]);
 
4793
                    else
 
4794
                        hide_force_quit_dialog (win);
 
4795
                }
 
4796
            }
 
4797
        }
 
4798
    default:
 
4799
        break;
 
4800
    }
 
4801
 
 
4802
    if (xid)
 
4803
    {
 
4804
        WnckWindow *win;
 
4805
 
 
4806
        win = wnck_window_get (xid);
 
4807
        if (win)
 
4808
        {
 
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 }
 
4813
            };
 
4814
            static event_callback button_callback[3] = {
 
4815
                close_button_event,
 
4816
                max_button_event,
 
4817
                min_button_event
 
4818
            };
 
4819
            decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
4820
 
 
4821
            if (d->decorated)
 
4822
            {
 
4823
                gint i, j;
 
4824
 
 
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);
 
4829
 
 
4830
                for (i = 0; i < 3; i++)
 
4831
                    if (d->button_windows[i] == xevent->xany.window)
 
4832
                        (*button_callback[i]) (win, xevent);
 
4833
            }
 
4834
        }
 
4835
    }
 
4836
 
 
4837
    return GDK_FILTER_CONTINUE;
 
4838
}
 
4839
 
 
4840
static GdkFilterReturn
 
4841
selection_event_filter_func (GdkXEvent *gdkxevent,
 
4842
                             GdkEvent  *event,
 
4843
                             gpointer  data)
 
4844
{
 
4845
    Display    *xdisplay;
 
4846
    GdkDisplay *gdkdisplay;
 
4847
    XEvent     *xevent = gdkxevent;
 
4848
 
 
4849
    gdkdisplay = gdk_display_get_default ();
 
4850
    xdisplay   = GDK_DISPLAY_XDISPLAY (gdkdisplay);
 
4851
 
 
4852
    switch (xevent->type) {
 
4853
    case SelectionRequest:
 
4854
        handle_selection_request (xdisplay, xevent);
 
4855
        break;
 
4856
    case SelectionClear:
 
4857
        handle_selection_clear (xdisplay, xevent);
 
4858
    default:
 
4859
        break;
 
4860
    }
 
4861
 
 
4862
    return GDK_FILTER_CONTINUE;
 
4863
}
 
4864
 
 
4865
 
 
4866
/* from clearlooks theme */
 
4867
static void
 
4868
rgb_to_hls (gdouble *r,
 
4869
            gdouble *g,
 
4870
            gdouble *b)
 
4871
{
 
4872
    gdouble min;
 
4873
    gdouble max;
 
4874
    gdouble red;
 
4875
    gdouble green;
 
4876
    gdouble blue;
 
4877
    gdouble h, l, s;
 
4878
    gdouble delta;
 
4879
 
 
4880
    red = *r;
 
4881
    green = *g;
 
4882
    blue = *b;
 
4883
 
 
4884
    if (red > green)
 
4885
    {
 
4886
        if (red > blue)
 
4887
            max = red;
 
4888
        else
 
4889
            max = blue;
 
4890
 
 
4891
        if (green < blue)
 
4892
            min = green;
 
4893
        else
 
4894
            min = blue;
 
4895
    }
 
4896
    else
 
4897
    {
 
4898
        if (green > blue)
 
4899
            max = green;
 
4900
        else
 
4901
            max = blue;
 
4902
 
 
4903
        if (red < blue)
 
4904
            min = red;
 
4905
        else
 
4906
            min = blue;
 
4907
    }
 
4908
 
 
4909
    l = (max + min) / 2;
 
4910
    s = 0;
 
4911
    h = 0;
 
4912
 
 
4913
    if (max != min)
 
4914
    {
 
4915
        if (l <= 0.5)
 
4916
            s = (max - min) / (max + min);
 
4917
        else
 
4918
            s = (max - min) / (2 - max - min);
 
4919
 
 
4920
        delta = max -min;
 
4921
        if (red == max)
 
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;
 
4927
 
 
4928
        h *= 60;
 
4929
        if (h < 0.0)
 
4930
            h += 360;
 
4931
    }
 
4932
 
 
4933
    *r = h;
 
4934
    *g = l;
 
4935
    *b = s;
 
4936
}
 
4937
 
 
4938
static void
 
4939
hls_to_rgb (gdouble *h,
 
4940
            gdouble *l,
 
4941
            gdouble *s)
 
4942
{
 
4943
    gdouble hue;
 
4944
    gdouble lightness;
 
4945
    gdouble saturation;
 
4946
    gdouble m1, m2;
 
4947
    gdouble r, g, b;
 
4948
 
 
4949
    lightness = *l;
 
4950
    saturation = *s;
 
4951
 
 
4952
    if (lightness <= 0.5)
 
4953
        m2 = lightness * (1 + saturation);
 
4954
    else
 
4955
        m2 = lightness + saturation - lightness * saturation;
 
4956
 
 
4957
    m1 = 2 * lightness - m2;
 
4958
 
 
4959
    if (saturation == 0)
 
4960
    {
 
4961
        *h = lightness;
 
4962
        *l = lightness;
 
4963
        *s = lightness;
 
4964
    }
 
4965
    else
 
4966
    {
 
4967
        hue = *h + 120;
 
4968
        while (hue > 360)
 
4969
            hue -= 360;
 
4970
        while (hue < 0)
 
4971
            hue += 360;
 
4972
 
 
4973
        if (hue < 60)
 
4974
            r = m1 + (m2 - m1) * hue / 60;
 
4975
        else if (hue < 180)
 
4976
            r = m2;
 
4977
        else if (hue < 240)
 
4978
            r = m1 + (m2 - m1) * (240 - hue) / 60;
 
4979
        else
 
4980
            r = m1;
 
4981
 
 
4982
        hue = *h;
 
4983
        while (hue > 360)
 
4984
            hue -= 360;
 
4985
        while (hue < 0)
 
4986
            hue += 360;
 
4987
 
 
4988
        if (hue < 60)
 
4989
            g = m1 + (m2 - m1) * hue / 60;
 
4990
        else if (hue < 180)
 
4991
            g = m2;
 
4992
        else if (hue < 240)
 
4993
            g = m1 + (m2 - m1) * (240 - hue) / 60;
 
4994
        else
 
4995
            g = m1;
 
4996
 
 
4997
        hue = *h - 120;
 
4998
        while (hue > 360)
 
4999
            hue -= 360;
 
5000
        while (hue < 0)
 
5001
            hue += 360;
 
5002
 
 
5003
        if (hue < 60)
 
5004
            b = m1 + (m2 - m1) * hue / 60;
 
5005
        else if (hue < 180)
 
5006
            b = m2;
 
5007
        else if (hue < 240)
 
5008
            b = m1 + (m2 - m1) * (240 - hue) / 60;
 
5009
        else
 
5010
            b = m1;
 
5011
 
 
5012
        *h = r;
 
5013
        *l = g;
 
5014
        *s = b;
 
5015
    }
 
5016
}
 
5017
 
 
5018
static void
 
5019
shade (const decor_color_t *a,
 
5020
       decor_color_t       *b,
 
5021
       float               k)
 
5022
{
 
5023
    double red;
 
5024
    double green;
 
5025
    double blue;
 
5026
 
 
5027
    red   = a->r;
 
5028
    green = a->g;
 
5029
    blue  = a->b;
 
5030
 
 
5031
    rgb_to_hls (&red, &green, &blue);
 
5032
 
 
5033
    green *= k;
 
5034
    if (green > 1.0)
 
5035
        green = 1.0;
 
5036
    else if (green < 0.0)
 
5037
        green = 0.0;
 
5038
 
 
5039
    blue *= k;
 
5040
    if (blue > 1.0)
 
5041
        blue = 1.0;
 
5042
    else if (blue < 0.0)
 
5043
        blue = 0.0;
 
5044
 
 
5045
    hls_to_rgb (&red, &green, &blue);
 
5046
 
 
5047
    b->r = red;
 
5048
    b->g = green;
 
5049
    b->b = blue;
 
5050
}
 
5051
 
 
5052
static void
 
5053
update_style (GtkWidget *widget)
 
5054
{
 
5055
    GtkStyle      *style;
 
5056
    decor_color_t spot_color;
 
5057
 
 
5058
    style = gtk_widget_get_style (widget);
 
5059
    gtk_style_attach (style, widget->window);
 
5060
 
 
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;
 
5064
 
 
5065
    shade (&spot_color, &_title_color[0], 1.05);
 
5066
    shade (&_title_color[0], &_title_color[1], 0.85);
 
5067
}
 
5068
 
 
5069
#if G_MAXINT != G_MAXLONG
 
5070
/* XRenderSetPictureFilter used to be broken on LP64. This
 
5071
 * works with either the broken or fixed version.
 
5072
 */
 
5073
static void
 
5074
XRenderSetPictureFilter_wrapper (Display *dpy,
 
5075
                                 Picture picture,
 
5076
                                 char    *filter,
 
5077
                                 XFixed  *params,
 
5078
                                 int     nparams)
 
5079
{
 
5080
    gdk_error_trap_push ();
 
5081
    XRenderSetPictureFilter (dpy, picture, filter, params, nparams);
 
5082
    XSync (dpy, False);
 
5083
    if (gdk_error_trap_pop ())
 
5084
    {
 
5085
        long *long_params = g_new (long, nparams);
 
5086
        int  i;
 
5087
 
 
5088
        for (i = 0; i < nparams; i++)
 
5089
            long_params[i] = params[i];
 
5090
 
 
5091
        XRenderSetPictureFilter (dpy, picture, filter,
 
5092
                                 (XFixed *) long_params, nparams);
 
5093
        g_free (long_params);
 
5094
    }
 
5095
}
 
5096
 
 
5097
#define XRenderSetPictureFilter XRenderSetPictureFilter_wrapper
 
5098
#endif
 
5099
 
 
5100
static void
 
5101
set_picture_transform (Display *xdisplay,
 
5102
                       Picture p,
 
5103
                       int     dx,
 
5104
                       int     dy)
 
5105
{
 
5106
    XTransform transform = {
 
5107
        {
 
5108
            { 1 << 16, 0,       -dx << 16 },
 
5109
            { 0,       1 << 16, -dy << 16 },
 
5110
            { 0,       0,         1 << 16 },
 
5111
        }
 
5112
    };
 
5113
 
 
5114
    XRenderSetPictureTransform (xdisplay, p, &transform);
 
5115
}
 
5116
 
 
5117
static XFixed *
 
5118
create_gaussian_kernel (double radius,
 
5119
                        double sigma,
 
5120
                        double alpha,
 
5121
                        double opacity,
 
5122
                        int    *r_size)
 
5123
{
 
5124
    XFixed *params;
 
5125
    double *amp, scale, x_scale, fx, sum;
 
5126
    int    size, half_size, x, i, n;
 
5127
 
 
5128
    scale = 1.0f / (2.0f * M_PI * sigma * sigma);
 
5129
    half_size = alpha + 0.5f;
 
5130
 
 
5131
    if (half_size == 0)
 
5132
        half_size = 1;
 
5133
 
 
5134
    size = half_size * 2 + 1;
 
5135
    x_scale = 2.0f * radius / size;
 
5136
 
 
5137
    if (size < 3)
 
5138
        return NULL;
 
5139
 
 
5140
    n = size;
 
5141
 
 
5142
    amp = g_malloc (sizeof (double) * n);
 
5143
    if (!amp)
 
5144
        return NULL;
 
5145
 
 
5146
    n += 2;
 
5147
 
 
5148
    params = g_malloc (sizeof (XFixed) * n);
 
5149
    if (!params)
 
5150
        return NULL;
 
5151
 
 
5152
    i   = 0;
 
5153
    sum = 0.0f;
 
5154
 
 
5155
    for (x = 0; x < size; x++)
 
5156
    {
 
5157
        fx = x_scale * (x - half_size);
 
5158
 
 
5159
        amp[i] = scale * exp ((-1.0f * (fx * fx)) / (2.0f * sigma * sigma));
 
5160
 
 
5161
        sum += amp[i];
 
5162
 
 
5163
        i++;
 
5164
    }
 
5165
 
 
5166
    /* normalize */
 
5167
    if (sum != 0.0)
 
5168
        sum = 1.0 / sum;
 
5169
 
 
5170
    params[0] = params[1] = 0;
 
5171
 
 
5172
    for (i = 2; i < n; i++)
 
5173
        params[i] = XDoubleToFixed (amp[i - 2] * sum * opacity * 1.2);
 
5174
 
 
5175
    g_free (amp);
 
5176
 
 
5177
    *r_size = size;
 
5178
 
 
5179
    return params;
 
5180
}
 
5181
 
 
5182
/* to save some memory, value is specific to current decorations */
 
5183
#define CORNER_REDUCTION 3
 
5184
 
 
5185
#define SIGMA(r) ((r) / 2.0)
 
5186
#define ALPHA(r) (r)
 
5187
 
 
5188
static int
 
5189
update_shadow (void)
 
5190
{
 
5191
    Display             *xdisplay = gdk_display;
 
5192
    XRenderPictFormat   *format;
 
5193
    GdkPixmap           *pixmap;
 
5194
    Picture             src, dst, tmp;
 
5195
    XFixed              *params;
 
5196
    XFilters            *filters;
 
5197
    char                *filter = NULL;
 
5198
    int                 size, n_params = 0;
 
5199
    cairo_t             *cr;
 
5200
    decor_t             d;
 
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 };
 
5205
 
 
5206
    /* compute a gaussian convolution kernel */
 
5207
    params = create_gaussian_kernel (shadow_radius,
 
5208
                                     SIGMA (shadow_radius),
 
5209
                                     ALPHA (shadow_radius),
 
5210
                                     shadow_opacity,
 
5211
                                     &size);
 
5212
    if (!params)
 
5213
        shadow_offset_x = shadow_offset_y = size = 0;
 
5214
 
 
5215
    if (shadow_radius <= 0.0 && shadow_offset_x == 0 && shadow_offset_y == 0)
 
5216
        size = 0;
 
5217
 
 
5218
    n_params = size + 2;
 
5219
    size     = size / 2;
 
5220
 
 
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;
 
5225
 
 
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);
 
5230
 
 
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);
 
5235
 
 
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);
 
5240
 
 
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);
 
5246
 
 
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);
 
5251
 
 
5252
    d.buffer_pixmap = NULL;
 
5253
    d.layout        = NULL;
 
5254
    d.icon          = NULL;
 
5255
    d.icon_pixmap   = NULL;
 
5256
    d.icon_pixbuf   = NULL;
 
5257
    d.state         = 0;
 
5258
    d.actions       = 0;
 
5259
    d.prop_xid      = 0;
 
5260
    d.button_width  = 0;
 
5261
    d.draw          = theme_draw_window_decoration;
 
5262
    d.active        = TRUE;
 
5263
 
 
5264
    d.width  = left_space + left_corner_space + 1 + right_corner_space +
 
5265
        right_space;
 
5266
    d.height = top_space + titlebar_height + normal_top_corner_space + 2 +
 
5267
        bottom_corner_space + bottom_space;
 
5268
 
 
5269
    /* all pixmaps are ARGB32 */
 
5270
    format = XRenderFindStandardFormat (xdisplay, PictStandardARGB32);
 
5271
 
 
5272
    /* shadow color */
 
5273
    src = XRenderCreateSolidFill (xdisplay, &color);
 
5274
 
 
5275
    if (large_shadow_pixmap)
 
5276
    {
 
5277
        gdk_pixmap_unref (large_shadow_pixmap);
 
5278
        large_shadow_pixmap = NULL;
 
5279
    }
 
5280
 
 
5281
    if (shadow_pattern)
 
5282
    {
 
5283
        cairo_pattern_destroy (shadow_pattern);
 
5284
        shadow_pattern = NULL;
 
5285
    }
 
5286
 
 
5287
    if (shadow_pixmap)
 
5288
    {
 
5289
        gdk_pixmap_unref (shadow_pixmap);
 
5290
        shadow_pixmap = NULL;
 
5291
    }
 
5292
 
 
5293
    /* no shadow */
 
5294
    if (size <= 0)
 
5295
    {
 
5296
        if (params)
 
5297
            g_free (params);
 
5298
 
 
5299
        return 1;
 
5300
    }
 
5301
 
 
5302
    pixmap = create_pixmap (d.width, d.height);
 
5303
    if (!pixmap)
 
5304
    {
 
5305
        g_free (params);
 
5306
        return 0;
 
5307
    }
 
5308
 
 
5309
    /* query server for convolution filter */
 
5310
    filters = XRenderQueryFilters (xdisplay, GDK_PIXMAP_XID (pixmap));
 
5311
    if (filters)
 
5312
    {
 
5313
        int i;
 
5314
 
 
5315
        for (i = 0; i < filters->nfilter; i++)
 
5316
        {
 
5317
            if (strcmp (filters->filter[i], FilterConvolution) == 0)
 
5318
            {
 
5319
                filter = FilterConvolution;
 
5320
                break;
 
5321
            }
 
5322
        }
 
5323
 
 
5324
        XFree (filters);
 
5325
    }
 
5326
 
 
5327
    if (!filter)
 
5328
    {
 
5329
        fprintf (stderr, "can't generate shadows, X server doesn't support "
 
5330
                 "convolution filters\n");
 
5331
 
 
5332
        g_free (params);
 
5333
        gdk_pixmap_unref (pixmap);
 
5334
        return 1;
 
5335
    }
 
5336
 
 
5337
 
 
5338
    /* WINDOWS WITH DECORATION */
 
5339
 
 
5340
    d.pixmap = create_pixmap (d.width, d.height);
 
5341
    if (!d.pixmap)
 
5342
    {
 
5343
        g_free (params);
 
5344
        gdk_pixmap_unref (pixmap);
 
5345
        return 0;
 
5346
    }
 
5347
 
 
5348
    /* create shadow from opaque decoration */
 
5349
    save_decoration_alpha = decoration_alpha;
 
5350
    decoration_alpha = 1.0;
 
5351
 
 
5352
    /* draw decorations */
 
5353
    (*d.draw) (&d);
 
5354
 
 
5355
    decoration_alpha = save_decoration_alpha;
 
5356
 
 
5357
    dst = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (d.pixmap),
 
5358
                                format, 0, NULL);
 
5359
    tmp = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (pixmap),
 
5360
                                format, 0, NULL);
 
5361
 
 
5362
    /* first pass */
 
5363
    params[0] = (n_params - 2) << 16;
 
5364
    params[1] = 1 << 16;
 
5365
 
 
5366
    set_picture_transform (xdisplay, dst, shadow_offset_x, 0);
 
5367
    XRenderSetPictureFilter (xdisplay, dst, filter, params, n_params);
 
5368
    XRenderComposite (xdisplay,
 
5369
                      PictOpSrc,
 
5370
                      src,
 
5371
                      dst,
 
5372
                      tmp,
 
5373
                      0, 0,
 
5374
                      0, 0,
 
5375
                      0, 0,
 
5376
                      d.width, d.height);
 
5377
 
 
5378
    /* second pass */
 
5379
    params[0] = 1 << 16;
 
5380
    params[1] = (n_params - 2) << 16;
 
5381
 
 
5382
    set_picture_transform (xdisplay, tmp, 0, shadow_offset_y);
 
5383
    XRenderSetPictureFilter (xdisplay, tmp, filter, params, n_params);
 
5384
    XRenderComposite (xdisplay,
 
5385
                      PictOpSrc,
 
5386
                      src,
 
5387
                      tmp,
 
5388
                      dst,
 
5389
                      0, 0,
 
5390
                      0, 0,
 
5391
                      0, 0,
 
5392
                      d.width, d.height);
 
5393
 
 
5394
    XRenderFreePicture (xdisplay, tmp);
 
5395
    XRenderFreePicture (xdisplay, dst);
 
5396
 
 
5397
    gdk_pixmap_unref (pixmap);
 
5398
 
 
5399
    large_shadow_pixmap = d.pixmap;
 
5400
 
 
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);
 
5404
    cairo_destroy (cr);
 
5405
 
 
5406
 
 
5407
    /* WINDOWS WITHOUT DECORATIONS */
 
5408
 
 
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;
 
5413
 
 
5414
    pixmap = create_pixmap (d.width, d.height);
 
5415
    if (!pixmap)
 
5416
    {
 
5417
        g_free (params);
 
5418
        return 0;
 
5419
    }
 
5420
 
 
5421
    d.pixmap = create_pixmap (d.width, d.height);
 
5422
    if (!d.pixmap)
 
5423
    {
 
5424
        gdk_pixmap_unref (pixmap);
 
5425
        g_free (params);
 
5426
        return 0;
 
5427
    }
 
5428
 
 
5429
    dst = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (d.pixmap),
 
5430
                                format, 0, NULL);
 
5431
 
 
5432
    /* draw rectangle */
 
5433
    XRenderFillRectangle (xdisplay, PictOpSrc, dst, &clear,
 
5434
                          0,
 
5435
                          0,
 
5436
                          d.width,
 
5437
                          d.height);
 
5438
    XRenderFillRectangle (xdisplay, PictOpSrc, dst, &white,
 
5439
                          shadow_left_space,
 
5440
                          shadow_top_space,
 
5441
                          d.width - shadow_left_space - shadow_right_space,
 
5442
                          d.height - shadow_top_space - shadow_bottom_space);
 
5443
 
 
5444
    tmp = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (pixmap),
 
5445
                                format, 0, NULL);
 
5446
 
 
5447
    /* first pass */
 
5448
    params[0] = (n_params - 2) << 16;
 
5449
    params[1] = 1 << 16;
 
5450
 
 
5451
    set_picture_transform (xdisplay, dst, shadow_offset_x, 0);
 
5452
    XRenderSetPictureFilter (xdisplay, dst, filter, params, n_params);
 
5453
    XRenderComposite (xdisplay,
 
5454
                      PictOpSrc,
 
5455
                      src,
 
5456
                      dst,
 
5457
                      tmp,
 
5458
                      0, 0,
 
5459
                      0, 0,
 
5460
                      0, 0,
 
5461
                      d.width, d.height);
 
5462
 
 
5463
    /* second pass */
 
5464
    params[0] = 1 << 16;
 
5465
    params[1] = (n_params - 2) << 16;
 
5466
 
 
5467
    set_picture_transform (xdisplay, tmp, 0, shadow_offset_y);
 
5468
    XRenderSetPictureFilter (xdisplay, tmp, filter, params, n_params);
 
5469
    XRenderComposite (xdisplay,
 
5470
                      PictOpSrc,
 
5471
                      src,
 
5472
                      tmp,
 
5473
                      dst,
 
5474
                      0, 0,
 
5475
                      0, 0,
 
5476
                      0, 0,
 
5477
                      d.width, d.height);
 
5478
 
 
5479
    XRenderFreePicture (xdisplay, tmp);
 
5480
    XRenderFreePicture (xdisplay, dst);
 
5481
    XRenderFreePicture (xdisplay, src);
 
5482
 
 
5483
    gdk_pixmap_unref (pixmap);
 
5484
 
 
5485
    g_free (params);
 
5486
 
 
5487
    shadow_pixmap = d.pixmap;
 
5488
 
 
5489
    return 1;
 
5490
}
 
5491
 
 
5492
static void
 
5493
style_changed (GtkWidget *widget)
 
5494
{
 
5495
    GdkDisplay *gdkdisplay;
 
5496
    GdkScreen  *gdkscreen;
 
5497
    WnckScreen *screen;
 
5498
    GList      *windows;
 
5499
 
 
5500
    gdkdisplay = gdk_display_get_default ();
 
5501
    gdkscreen  = gdk_display_get_default_screen (gdkdisplay);
 
5502
    screen     = wnck_screen_get_default ();
 
5503
 
 
5504
    update_style (widget);
 
5505
 
 
5506
    update_default_decorations (gdkscreen);
 
5507
 
 
5508
    if (minimal)
 
5509
        return;
 
5510
 
 
5511
    windows = wnck_screen_get_windows (screen);
 
5512
    while (windows != NULL)
 
5513
    {
 
5514
        decor_t *d = g_object_get_data (G_OBJECT (windows->data), "decor");
 
5515
 
 
5516
        if (d->decorated)
 
5517
        {
 
5518
            /* force size update */
 
5519
            d->width = d->height = 0;
 
5520
 
 
5521
            update_window_decoration_size (WNCK_WINDOW (windows->data));
 
5522
            update_event_windows (WNCK_WINDOW (windows->data));
 
5523
        }
 
5524
        windows = windows->next;
 
5525
    }
 
5526
}
 
5527
 
 
5528
static const PangoFontDescription *
 
5529
get_titlebar_font (void)
 
5530
{
 
5531
    if (use_system_font)
 
5532
    {
 
5533
        return NULL;
 
5534
    }
 
5535
    else
 
5536
        return titlebar_font;
 
5537
}
 
5538
 
 
5539
static void
 
5540
titlebar_font_changed (GConfClient *client)
 
5541
{
 
5542
    gchar *str;
 
5543
 
 
5544
    str = gconf_client_get_string (client,
 
5545
                                   COMPIZ_TITLEBAR_FONT_KEY,
 
5546
                                   NULL);
 
5547
    if (!str)
 
5548
        str = g_strdup ("Sans Bold 12");
 
5549
 
 
5550
    if (titlebar_font)
 
5551
        pango_font_description_free (titlebar_font);
 
5552
 
 
5553
    titlebar_font = pango_font_description_from_string (str);
 
5554
 
 
5555
    g_free (str);
 
5556
}
 
5557
 
 
5558
static void
 
5559
double_click_titlebar_changed (GConfClient *client)
 
5560
{
 
5561
    gchar *action;
 
5562
 
 
5563
    double_click_action = DOUBLE_CLICK_MAXIMIZE;
 
5564
 
 
5565
    action = gconf_client_get_string (client,
 
5566
                                      COMPIZ_DOUBLE_CLICK_TITLEBAR_KEY,
 
5567
                                      NULL);
 
5568
    if (action)
 
5569
    {
 
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;
 
5574
    }
 
5575
}
 
5576
 
 
5577
static gint
 
5578
calc_titlebar_height (gint text_height)
 
5579
{
 
5580
    return (text_height < 17) ? 17 : text_height;
 
5581
}
 
5582
 
 
5583
#ifdef USE_METACITY
 
5584
static gint
 
5585
meta_calc_titlebar_height (gint text_height)
 
5586
{
 
5587
    MetaTheme *theme;
 
5588
    gint      top_height, bottom_height, left_width, right_width;
 
5589
 
 
5590
    theme = meta_theme_get_current ();
 
5591
 
 
5592
    meta_theme_get_frame_borders (theme,
 
5593
                                  META_FRAME_TYPE_NORMAL,
 
5594
                                  text_height, 0,
 
5595
                                  &top_height,
 
5596
                                  &bottom_height,
 
5597
                                  &left_width,
 
5598
                                  &right_width);
 
5599
 
 
5600
    return top_height - _win_extents.top;
 
5601
}
 
5602
#endif
 
5603
 
 
5604
static void
 
5605
update_titlebar_font (void)
 
5606
{
 
5607
    const PangoFontDescription *font_desc;
 
5608
    PangoFontMetrics           *metrics;
 
5609
    PangoLanguage              *lang;
 
5610
 
 
5611
    font_desc = get_titlebar_font ();
 
5612
    if (!font_desc)
 
5613
    {
 
5614
        GtkStyle *default_style;
 
5615
 
 
5616
        default_style = gtk_widget_get_default_style ();
 
5617
        font_desc = default_style->font_desc;
 
5618
    }
 
5619
 
 
5620
    pango_context_set_font_description (pango_context, font_desc);
 
5621
 
 
5622
    lang    = pango_context_get_language (pango_context);
 
5623
    metrics = pango_context_get_metrics (pango_context, font_desc, lang);
 
5624
 
 
5625
    text_height = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
 
5626
                                pango_font_metrics_get_descent (metrics));
 
5627
 
 
5628
    titlebar_height = (*theme_calc_titlebar_height) (text_height);
 
5629
 
 
5630
    pango_font_metrics_unref (metrics);
 
5631
}
 
5632
 
 
5633
static gboolean
 
5634
shadow_settings_changed (GConfClient *client)
 
5635
{
 
5636
    double   radius, opacity;
 
5637
    int      offset;
 
5638
    gboolean changed = FALSE;
 
5639
 
 
5640
    radius = gconf_client_get_float (client,
 
5641
                                     COMPIZ_SHADOW_RADIUS_KEY,
 
5642
                                     NULL);
 
5643
    radius = MAX (0.0, MIN (radius, 48.0));
 
5644
    if (shadow_radius != radius)
 
5645
    {
 
5646
        shadow_radius = radius;
 
5647
        changed = TRUE;
 
5648
    }
 
5649
 
 
5650
    opacity = gconf_client_get_float (client,
 
5651
                                      COMPIZ_SHADOW_OPACITY_KEY,
 
5652
                                      NULL);
 
5653
    opacity = MAX (0.0, MIN (opacity, 6.0));
 
5654
    if (shadow_opacity != opacity)
 
5655
    {
 
5656
        shadow_opacity = opacity;
 
5657
        changed = TRUE;
 
5658
    }
 
5659
 
 
5660
    offset = gconf_client_get_int (client,
 
5661
                                   COMPIZ_SHADOW_OFFSET_X_KEY,
 
5662
                                   NULL);
 
5663
    offset = MAX (-16, MIN (offset, 16));
 
5664
    if (shadow_offset_x != offset)
 
5665
    {
 
5666
        shadow_offset_x = offset;
 
5667
        changed = TRUE;
 
5668
    }
 
5669
 
 
5670
    offset = gconf_client_get_int (client,
 
5671
                                   COMPIZ_SHADOW_OFFSET_Y_KEY,
 
5672
                                   NULL);
 
5673
    offset = MAX (-16, MIN (offset, 16));
 
5674
    if (shadow_offset_y != offset)
 
5675
    {
 
5676
        shadow_offset_y = offset;
 
5677
        changed = TRUE;
 
5678
    }
 
5679
 
 
5680
    return changed;
 
5681
}
 
5682
 
 
5683
static void
 
5684
bell_settings_changed (GConfClient *client)
 
5685
{
 
5686
    gboolean audible, visual, fullscreen;
 
5687
    gchar    *type;
 
5688
 
 
5689
    audible = gconf_client_get_bool (client,
 
5690
                                     META_AUDIBLE_BELL_KEY,
 
5691
                                     NULL);
 
5692
 
 
5693
    visual = gconf_client_get_bool (client,
 
5694
                                    META_VISUAL_BELL_KEY,
 
5695
                                    NULL);
 
5696
 
 
5697
    type = gconf_client_get_string (client,
 
5698
                                    META_VISUAL_BELL_TYPE_KEY,
 
5699
                                    NULL);
 
5700
 
 
5701
    if (type && strcmp (type, "fullscreen") == 0)
 
5702
        fullscreen = TRUE;
 
5703
    else
 
5704
        fullscreen = FALSE;
 
5705
 
 
5706
    g_free (type);
 
5707
 
 
5708
    gconf_client_set_bool (client,
 
5709
                           COMPIZ_AUDIBLE_BELL_KEY,
 
5710
                           audible,
 
5711
                           NULL);
 
5712
 
 
5713
    gconf_client_set_bool (client,
 
5714
                           COMPIZ_VISUAL_BELL_KEY,
 
5715
                           visual,
 
5716
                           NULL);
 
5717
 
 
5718
    gconf_client_set_bool (client,
 
5719
                           COMPIZ_FULLSCREEN_VISUAL_BELL_KEY,
 
5720
                           fullscreen,
 
5721
                           NULL);
 
5722
}
 
5723
 
 
5724
static gboolean
 
5725
theme_changed (GConfClient *client)
 
5726
{
 
5727
 
 
5728
#ifdef USE_METACITY
 
5729
    gboolean use_meta_theme;
 
5730
 
 
5731
    use_meta_theme = gconf_client_get_bool (client,
 
5732
                                            USE_META_THEME_KEY,
 
5733
                                            NULL);
 
5734
 
 
5735
    if (use_meta_theme)
 
5736
    {
 
5737
        gchar *theme;
 
5738
 
 
5739
        theme = gconf_client_get_string (client,
 
5740
                                         META_THEME_KEY,
 
5741
                                         NULL);
 
5742
 
 
5743
        if (theme)
 
5744
        {
 
5745
            meta_theme_set_current (theme, TRUE);
 
5746
 
 
5747
            g_free (theme);
 
5748
        }
 
5749
        else
 
5750
        {
 
5751
            use_meta_theme = FALSE;
 
5752
        }
 
5753
    }
 
5754
 
 
5755
    if (use_meta_theme)
 
5756
    {
 
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;
 
5760
    }
 
5761
    else
 
5762
    {
 
5763
        theme_draw_window_decoration = draw_window_decoration;
 
5764
        theme_calc_decoration_size   = calc_decoration_size;
 
5765
        theme_calc_titlebar_height   = calc_titlebar_height;
 
5766
    }
 
5767
 
 
5768
    return TRUE;
 
5769
#else
 
5770
    theme_draw_window_decoration = draw_window_decoration;
 
5771
    theme_calc_decoration_size   = calc_decoration_size;
 
5772
    theme_calc_titlebar_height   = calc_titlebar_height;
 
5773
 
 
5774
    return FALSE;
 
5775
#endif
 
5776
 
 
5777
}
 
5778
 
 
5779
static void
 
5780
value_changed (GConfClient *client,
 
5781
               const gchar *key,
 
5782
               GConfValue  *value,
 
5783
               void        *data)
 
5784
{
 
5785
    gboolean changed = FALSE;
 
5786
 
 
5787
    if (strcmp (key, COMPIZ_USE_SYSTEM_FONT_KEY) == 0)
 
5788
    {
 
5789
        if (gconf_client_get_bool (client,
 
5790
                                   COMPIZ_USE_SYSTEM_FONT_KEY,
 
5791
                                   NULL) != use_system_font)
 
5792
        {
 
5793
            use_system_font = !use_system_font;
 
5794
            changed = TRUE;
 
5795
        }
 
5796
    }
 
5797
    else if (strcmp (key, COMPIZ_TITLEBAR_FONT_KEY) == 0)
 
5798
    {
 
5799
        titlebar_font_changed (client);
 
5800
        changed = !use_system_font;
 
5801
    }
 
5802
    else if (strcmp (key, COMPIZ_DOUBLE_CLICK_TITLEBAR_KEY) == 0)
 
5803
    {
 
5804
        double_click_titlebar_changed (client);
 
5805
    }
 
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)
 
5810
    {
 
5811
        if (shadow_settings_changed (client))
 
5812
            changed = TRUE;
 
5813
    }
 
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)
 
5817
    {
 
5818
        bell_settings_changed (client);
 
5819
    }
 
5820
    else if (strcmp (key, USE_META_THEME_KEY) == 0 ||
 
5821
             strcmp (key, META_THEME_KEY) == 0)
 
5822
    {
 
5823
        if (theme_changed (client))
 
5824
            changed = TRUE;
 
5825
    }
 
5826
 
 
5827
    if (changed)
 
5828
    {
 
5829
        GdkDisplay *gdkdisplay;
 
5830
        GdkScreen  *gdkscreen;
 
5831
        WnckScreen *screen = data;
 
5832
        GList      *windows;
 
5833
 
 
5834
        gdkdisplay = gdk_display_get_default ();
 
5835
        gdkscreen  = gdk_display_get_default_screen (gdkdisplay);
 
5836
 
 
5837
        update_titlebar_font ();
 
5838
        update_shadow ();
 
5839
 
 
5840
        update_default_decorations (gdkscreen);
 
5841
 
 
5842
        if (minimal)
 
5843
            return;
 
5844
 
 
5845
        windows = wnck_screen_get_windows (screen);
 
5846
        while (windows != NULL)
 
5847
        {
 
5848
            decor_t *d = g_object_get_data (G_OBJECT (windows->data), "decor");
 
5849
 
 
5850
            if (d->decorated)
 
5851
            {
 
5852
                d->width = d->height = 0;
 
5853
 
 
5854
#ifdef USE_METACITY
 
5855
                if (d->draw == draw_window_decoration ||
 
5856
                    d->draw == meta_draw_window_decoration)
 
5857
                    d->draw = theme_draw_window_decoration;
 
5858
#endif
 
5859
 
 
5860
                update_window_decoration_size (WNCK_WINDOW (windows->data));
 
5861
                update_event_windows (WNCK_WINDOW (windows->data));
 
5862
            }
 
5863
            windows = windows->next;
 
5864
        }
 
5865
    }
 
5866
}
 
5867
 
 
5868
static gboolean
 
5869
init_settings (WnckScreen *screen)
 
5870
{
 
5871
    GtkSettings *settings;
 
5872
    GConfClient *gconf;
 
5873
    GdkScreen   *gdkscreen;
 
5874
    GdkColormap *colormap;
 
5875
 
 
5876
    gconf = gconf_client_get_default ();
 
5877
 
 
5878
    gconf_client_add_dir (gconf,
 
5879
                          GCONF_DIR,
 
5880
                          GCONF_CLIENT_PRELOAD_ONELEVEL,
 
5881
                          NULL);
 
5882
 
 
5883
    gconf_client_add_dir (gconf,
 
5884
                          METACITY_GCONF_DIR,
 
5885
                          GCONF_CLIENT_PRELOAD_ONELEVEL,
 
5886
                          NULL);
 
5887
 
 
5888
    gconf_client_add_dir (gconf,
 
5889
                          COMPIZ_GCONF_DIR1,
 
5890
                          GCONF_CLIENT_PRELOAD_ONELEVEL,
 
5891
                          NULL);
 
5892
 
 
5893
    gconf_client_add_dir (gconf,
 
5894
                          COMPIZ_GCONF_DIR2,
 
5895
                          GCONF_CLIENT_PRELOAD_ONELEVEL,
 
5896
                          NULL);
 
5897
 
 
5898
    gconf_client_add_dir (gconf,
 
5899
                          COMPIZ_GCONF_DIR3,
 
5900
                          GCONF_CLIENT_PRELOAD_ONELEVEL,
 
5901
                          NULL);
 
5902
 
 
5903
    g_signal_connect (G_OBJECT (gconf),
 
5904
                      "value_changed",
 
5905
                      G_CALLBACK (value_changed),
 
5906
                      screen);
 
5907
 
 
5908
    style_window = gtk_window_new (GTK_WINDOW_POPUP);
 
5909
 
 
5910
    gdkscreen = gdk_display_get_default_screen (gdk_display_get_default ());
 
5911
    colormap = gdk_screen_get_rgba_colormap (gdkscreen);
 
5912
    if (colormap)
 
5913
        gtk_widget_set_colormap (style_window, colormap);
 
5914
 
 
5915
    gtk_widget_realize (style_window);
 
5916
 
 
5917
    g_signal_connect_object (style_window, "style-set",
 
5918
                             G_CALLBACK (style_changed),
 
5919
                             0, 0);
 
5920
 
 
5921
    settings = gtk_widget_get_settings (style_window);
 
5922
 
 
5923
    g_object_get (G_OBJECT (settings), "gtk-double-click-time",
 
5924
                  &double_click_timeout, NULL);
 
5925
 
 
5926
    pango_context = gtk_widget_create_pango_context (style_window);
 
5927
 
 
5928
    use_system_font = gconf_client_get_bool (gconf,
 
5929
                                             COMPIZ_USE_SYSTEM_FONT_KEY,
 
5930
                                             NULL);
 
5931
 
 
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);
 
5939
    update_shadow ();
 
5940
 
 
5941
    return TRUE;
 
5942
}
 
5943
 
 
5944
int
 
5945
main (int argc, char *argv[])
 
5946
{
 
5947
    GdkDisplay *gdkdisplay;
 
5948
    Display    *xdisplay;
 
5949
    GdkScreen  *gdkscreen;
 
5950
    WnckScreen *screen;
 
5951
    gint       i, j;
 
5952
    gboolean   replace = FALSE;
 
5953
 
 
5954
    program_name = argv[0];
 
5955
 
 
5956
    gtk_init (&argc, &argv);
 
5957
 
 
5958
    for (i = 0; i < argc; i++)
 
5959
    {
 
5960
        if (strcmp (argv[i], "--minimal") == 0)
 
5961
        {
 
5962
            minimal = TRUE;
 
5963
        }
 
5964
        else  if (strcmp (argv[i], "--replace") == 0)
 
5965
        {
 
5966
            replace = TRUE;
 
5967
        }
 
5968
        else  if (strcmp (argv[i], "--help") == 0)
 
5969
        {
 
5970
            fprintf (stderr, "%s [--minimal] [--replace] [--help]\n",
 
5971
                     program_name);
 
5972
            return 0;
 
5973
        }
 
5974
    }
 
5975
 
 
5976
    gdkdisplay = gdk_display_get_default ();
 
5977
    xdisplay   = gdk_x11_display_get_xdisplay (gdkdisplay);
 
5978
    gdkscreen  = gdk_display_get_default_screen (gdkdisplay);
 
5979
 
 
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",
 
5985
                                       FALSE);
 
5986
    mwm_hints_atom      = XInternAtom (xdisplay, "_MOTIF_WM_HINTS", FALSE);
 
5987
 
 
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",
 
5998
                     FALSE);
 
5999
 
 
6000
    panel_action_atom            =
 
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);
 
6006
 
 
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);
 
6013
 
 
6014
    utf8_string_atom = XInternAtom (xdisplay, "UTF8_STRING", FALSE);
 
6015
 
 
6016
    dm_name_atom = XInternAtom (xdisplay, "_NET_DM_NAME", FALSE);
 
6017
 
 
6018
    if (!acquire_dm_session (xdisplay, 0, replace))
 
6019
        return 1;
 
6020
 
 
6021
    for (i = 0; i < 3; i++)
 
6022
    {
 
6023
        for (j = 0; j < 3; j++)
 
6024
        {
 
6025
            if (cursor[i][j].shape != XC_left_ptr)
 
6026
                cursor[i][j].cursor =
 
6027
                    XCreateFontCursor (xdisplay, cursor[i][j].shape);
 
6028
        }
 
6029
    }
 
6030
 
 
6031
    frame_table = g_hash_table_new (NULL, NULL);
 
6032
 
 
6033
    if (!create_tooltip_window ())
 
6034
    {
 
6035
        fprintf (stderr, "%s, Couldn't create tooltip window\n", argv[0]);
 
6036
        return 1;
 
6037
    }
 
6038
 
 
6039
    screen = wnck_screen_get_default ();
 
6040
 
 
6041
    gdk_window_add_filter (NULL,
 
6042
                           selection_event_filter_func,
 
6043
                           NULL);
 
6044
 
 
6045
    if (!minimal)
 
6046
    {
 
6047
        gdk_window_add_filter (NULL,
 
6048
                               event_filter_func,
 
6049
                               NULL);
 
6050
 
 
6051
        connect_screen (screen);
 
6052
    }
 
6053
 
 
6054
    if (!init_settings (screen))
 
6055
    {
 
6056
        fprintf (stderr, "%s: Failed to get necessary gtk settings\n", argv[0]);
 
6057
        return 1;
 
6058
    }
 
6059
 
 
6060
    set_dm_check_hint (gdk_display_get_default_screen (gdkdisplay));
 
6061
 
 
6062
    update_default_decorations (gdkscreen);
 
6063
 
 
6064
    gtk_main ();
 
6065
 
 
6066
    return 0;
 
6067
}