~compiz-team/compiz-core/compiz-core.fix_882826

« back to all changes in this revision

Viewing changes to gnome/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
 
}