~dbarth/compiz/reworked-fix-744104

« back to all changes in this revision

Viewing changes to unity/unity_window_decorator/src/switcher.c

  • Committer: David Barth
  • Date: 2011-04-05 20:20:54 UTC
  • Revision ID: david.barth@canonical.com-20110405202054-fnh0y5t2s228mf4k
re-integrate the unity-window-decorator, for real this time

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "gtk-window-decorator.h"
 
2
 
 
3
static void
 
4
draw_switcher_background (decor_t *d)
 
5
{
 
6
    Display       *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
 
7
    cairo_t       *cr;
 
8
    GtkStyle      *style;
 
9
    decor_color_t color;
 
10
    double        alpha = SWITCHER_ALPHA / 65535.0;
 
11
    double        x1, y1, x2, y2, h;
 
12
    int           top;
 
13
    unsigned long pixel;
 
14
    ushort        a = SWITCHER_ALPHA;
 
15
 
 
16
    if (!d->buffer_pixmap)
 
17
        return;
 
18
 
 
19
    style = gtk_widget_get_style (style_window_rgba);
 
20
 
 
21
    color.r = style->bg[GTK_STATE_NORMAL].red   / 65535.0;
 
22
    color.g = style->bg[GTK_STATE_NORMAL].green / 65535.0;
 
23
    color.b = style->bg[GTK_STATE_NORMAL].blue  / 65535.0;
 
24
 
 
25
    cr = gdk_cairo_create (GDK_DRAWABLE (d->buffer_pixmap));
 
26
 
 
27
    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 
28
 
 
29
    top = _switcher_extents.top;
 
30
 
 
31
    x1 = switcher_context.left_space - _switcher_extents.left;
 
32
    y1 = switcher_context.top_space - _switcher_extents.top;
 
33
    x2 = d->width - switcher_context.right_space + _switcher_extents.right;
 
34
    y2 = d->height - switcher_context.bottom_space + _switcher_extents.bottom;
 
35
 
 
36
    h = y2 - y1 - _switcher_extents.top - _switcher_extents.top;
 
37
 
 
38
    cairo_set_line_width (cr, 1.0);
 
39
 
 
40
    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 
41
 
 
42
    draw_shadow_background (d, cr, switcher_shadow, &switcher_context);
 
43
 
 
44
    fill_rounded_rectangle (cr,
 
45
                            x1 + 0.5,
 
46
                            y1 + 0.5,
 
47
                            _switcher_extents.left - 0.5,
 
48
                            top - 0.5,
 
49
                            5.0, CORNER_TOPLEFT,
 
50
                            &color, alpha, &color, alpha * 0.75,
 
51
                            SHADE_TOP | SHADE_LEFT);
 
52
 
 
53
    fill_rounded_rectangle (cr,
 
54
                            x1 + _switcher_extents.left,
 
55
                            y1 + 0.5,
 
56
                            x2 - x1 - _switcher_extents.left -
 
57
                            _switcher_extents.right,
 
58
                            top - 0.5,
 
59
                            5.0, 0,
 
60
                            &color, alpha, &color, alpha * 0.75,
 
61
                            SHADE_TOP);
 
62
 
 
63
    fill_rounded_rectangle (cr,
 
64
                            x2 - _switcher_extents.right,
 
65
                            y1 + 0.5,
 
66
                            _switcher_extents.right - 0.5,
 
67
                            top - 0.5,
 
68
                            5.0, CORNER_TOPRIGHT,
 
69
                            &color, alpha, &color, alpha * 0.75,
 
70
                            SHADE_TOP | SHADE_RIGHT);
 
71
 
 
72
    fill_rounded_rectangle (cr,
 
73
                            x1 + 0.5,
 
74
                            y1 + top,
 
75
                            _switcher_extents.left - 0.5,
 
76
                            h,
 
77
                            5.0, 0,
 
78
                            &color, alpha, &color, alpha * 0.75,
 
79
                            SHADE_LEFT);
 
80
 
 
81
    fill_rounded_rectangle (cr,
 
82
                            x2 - _switcher_extents.right,
 
83
                            y1 + top,
 
84
                            _switcher_extents.right - 0.5,
 
85
                            h,
 
86
                            5.0, 0,
 
87
                            &color, alpha, &color, alpha * 0.75,
 
88
                            SHADE_RIGHT);
 
89
 
 
90
    fill_rounded_rectangle (cr,
 
91
                            x1 + 0.5,
 
92
                            y2 - _switcher_extents.top,
 
93
                            _switcher_extents.left - 0.5,
 
94
                            _switcher_extents.top - 0.5,
 
95
                            5.0, CORNER_BOTTOMLEFT,
 
96
                            &color, alpha, &color, alpha * 0.75,
 
97
                            SHADE_BOTTOM | SHADE_LEFT);
 
98
 
 
99
    fill_rounded_rectangle (cr,
 
100
                            x1 + _switcher_extents.left,
 
101
                            y2 - _switcher_extents.top,
 
102
                            x2 - x1 - _switcher_extents.left -
 
103
                            _switcher_extents.right,
 
104
                            _switcher_extents.top - 0.5,
 
105
                            5.0, 0,
 
106
                            &color, alpha, &color, alpha * 0.75,
 
107
                            SHADE_BOTTOM);
 
108
 
 
109
    fill_rounded_rectangle (cr,
 
110
                            x2 - _switcher_extents.right,
 
111
                            y2 - _switcher_extents.top,
 
112
                            _switcher_extents.right - 0.5,
 
113
                            _switcher_extents.top - 0.5,
 
114
                            5.0, CORNER_BOTTOMRIGHT,
 
115
                            &color, alpha, &color, alpha * 0.75,
 
116
                            SHADE_BOTTOM | SHADE_RIGHT);
 
117
 
 
118
    cairo_rectangle (cr, x1 + _switcher_extents.left,
 
119
                     y1 + top,
 
120
                     x2 - x1 - _switcher_extents.left - _switcher_extents.right,
 
121
                     h);
 
122
    gdk_cairo_set_source_color_alpha (cr,
 
123
                                      &style->bg[GTK_STATE_NORMAL],
 
124
                                      alpha);
 
125
    cairo_fill (cr);
 
126
 
 
127
    cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
 
128
 
 
129
    rounded_rectangle (cr,
 
130
                       x1 + 0.5, y1 + 0.5,
 
131
                       x2 - x1 - 1.0, y2 - y1 - 1.0,
 
132
                       5.0,
 
133
                       CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
 
134
                       CORNER_BOTTOMRIGHT);
 
135
 
 
136
    cairo_clip (cr);
 
137
 
 
138
    cairo_translate (cr, 1.0, 1.0);
 
139
 
 
140
    rounded_rectangle (cr,
 
141
                       x1 + 0.5, y1 + 0.5,
 
142
                       x2 - x1 - 1.0, y2 - y1 - 1.0,
 
143
                       5.0,
 
144
                       CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
 
145
                       CORNER_BOTTOMRIGHT);
 
146
 
 
147
    cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.4);
 
148
    cairo_stroke (cr);
 
149
 
 
150
    cairo_translate (cr, -2.0, -2.0);
 
151
 
 
152
    rounded_rectangle (cr,
 
153
                       x1 + 0.5, y1 + 0.5,
 
154
                       x2 - x1 - 1.0, y2 - y1 - 1.0,
 
155
                       5.0,
 
156
                       CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
 
157
                       CORNER_BOTTOMRIGHT);
 
158
 
 
159
    cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.1);
 
160
    cairo_stroke (cr);
 
161
 
 
162
    cairo_translate (cr, 1.0, 1.0);
 
163
 
 
164
    cairo_reset_clip (cr);
 
165
 
 
166
    rounded_rectangle (cr,
 
167
                       x1 + 0.5, y1 + 0.5,
 
168
                       x2 - x1 - 1.0, y2 - y1 - 1.0,
 
169
                       5.0,
 
170
                       CORNER_TOPLEFT | CORNER_TOPRIGHT | CORNER_BOTTOMLEFT |
 
171
                       CORNER_BOTTOMRIGHT);
 
172
 
 
173
    gdk_cairo_set_source_color_alpha (cr,
 
174
                                      &style->fg[GTK_STATE_NORMAL],
 
175
                                      alpha);
 
176
 
 
177
    cairo_stroke (cr);
 
178
 
 
179
    cairo_destroy (cr);
 
180
 
 
181
    copy_to_front_buffer (d);
 
182
 
 
183
    pixel = ((((a * style->bg[GTK_STATE_NORMAL].blue ) >> 24) & 0x0000ff) |
 
184
             (((a * style->bg[GTK_STATE_NORMAL].green) >> 16) & 0x00ff00) |
 
185
             (((a * style->bg[GTK_STATE_NORMAL].red  ) >>  8) & 0xff0000) |
 
186
             (((a & 0xff00) << 16)));
 
187
 
 
188
    decor_update_switcher_property (d);
 
189
 
 
190
    gdk_error_trap_push ();
 
191
    XSetWindowBackground (xdisplay, d->prop_xid, pixel);
 
192
    XClearWindow (xdisplay, d->prop_xid);
 
193
 
 
194
    gdk_display_sync (gdk_display_get_default ());
 
195
    gdk_error_trap_pop ();
 
196
 
 
197
    d->prop_xid = 0;
 
198
}
 
199
 
 
200
static void
 
201
draw_switcher_foreground (decor_t *d)
 
202
{
 
203
    cairo_t       *cr;
 
204
    GtkStyle      *style;
 
205
    double        alpha = SWITCHER_ALPHA / 65535.0;
 
206
 
 
207
    if (!d->pixmap || !d->buffer_pixmap)
 
208
        return;
 
209
 
 
210
    style = gtk_widget_get_style (style_window_rgba);
 
211
 
 
212
    cr = gdk_cairo_create (GDK_DRAWABLE (d->buffer_pixmap));
 
213
 
 
214
    cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
 
215
 
 
216
    cairo_rectangle (cr, switcher_context.left_space,
 
217
                     d->height - switcher_context.bottom_space,
 
218
                     d->width - switcher_context.left_space -
 
219
                     switcher_context.right_space,
 
220
                     SWITCHER_SPACE);
 
221
 
 
222
    gdk_cairo_set_source_color_alpha (cr,
 
223
                                      &style->bg[GTK_STATE_NORMAL],
 
224
                                      alpha);
 
225
    cairo_fill (cr);
 
226
 
 
227
    if (d->layout)
 
228
    {
 
229
        int w;
 
230
 
 
231
        cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
 
232
 
 
233
        gdk_cairo_set_source_color_alpha (cr,
 
234
                                          &style->fg[GTK_STATE_NORMAL],
 
235
                                          1.0);
 
236
 
 
237
        pango_layout_get_pixel_size (d->layout, &w, NULL);
 
238
 
 
239
        cairo_move_to (cr, d->width / 2 - w / 2,
 
240
                       d->height - switcher_context.bottom_space +
 
241
                       SWITCHER_SPACE / 2 - text_height / 2);
 
242
 
 
243
        pango_cairo_show_layout (cr, d->layout);
 
244
    }
 
245
 
 
246
    cairo_destroy (cr);
 
247
 
 
248
    copy_to_front_buffer (d);
 
249
}
 
250
 
 
251
void
 
252
draw_switcher_decoration (decor_t *d)
 
253
{
 
254
    if (d->prop_xid)
 
255
        draw_switcher_background (d);
 
256
 
 
257
    draw_switcher_foreground (d);
 
258
}
 
259
 
 
260
void
 
261
switcher_window_closed ()
 
262
{
 
263
    g_free (switcher_window);
 
264
    switcher_window = NULL;
 
265
}
 
266
 
 
267
/* Switcher is override-redirect now, we need to track
 
268
 * it separately */
 
269
decor_t *
 
270
switcher_window_opened (Window popup, Window window)
 
271
{
 
272
    decor_t      *d;
 
273
 
 
274
    d = switcher_window = calloc (1, sizeof (decor_t));
 
275
    if (!d)
 
276
        return NULL;
 
277
 
 
278
    return d;
 
279
}
 
280
 
 
281
gboolean
 
282
update_switcher_window (Window     popup,
 
283
                        Window     selected)
 
284
{
 
285
    decor_t           *d = switcher_window;
 
286
    GdkPixmap         *pixmap, *buffer_pixmap = NULL;
 
287
    unsigned int      height, width = 0, border, depth;
 
288
    int               x, y;
 
289
    Window            root_return;
 
290
    WnckWindow        *selected_win;
 
291
    Display           *xdisplay;
 
292
    XRenderPictFormat *format;
 
293
 
 
294
    if (!d)
 
295
        d = switcher_window_opened (popup, selected);
 
296
 
 
297
    xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
 
298
 
 
299
    /* Thats a round-trip */
 
300
    XGetGeometry (gdk_x11_get_default_xdisplay (), popup, &root_return,
 
301
                  &x, &y, &width, &height, &border, &depth);
 
302
 
 
303
    decor_get_default_layout (&switcher_context, width, 1, &d->border_layout);
 
304
 
 
305
    width  = d->border_layout.width;
 
306
    height = d->border_layout.height;
 
307
 
 
308
    d->decorated = FALSE;
 
309
    d->draw      = draw_switcher_decoration;
 
310
 
 
311
    if (!d->pixmap && switcher_pixmap)
 
312
    {
 
313
        g_object_ref (G_OBJECT (switcher_pixmap));
 
314
 
 
315
        d->pixmap = switcher_pixmap;
 
316
    }
 
317
 
 
318
    if (!d->buffer_pixmap && switcher_buffer_pixmap)
 
319
    {
 
320
        g_object_ref (G_OBJECT (switcher_buffer_pixmap));
 
321
        d->buffer_pixmap = switcher_buffer_pixmap;
 
322
    }
 
323
 
 
324
    if (!d->width)
 
325
        d->width = switcher_width;
 
326
 
 
327
    if (!d->height)
 
328
        d->height = switcher_height;
 
329
 
 
330
    selected_win = wnck_window_get (selected);
 
331
    if (selected_win)
 
332
    {
 
333
        glong           name_length;
 
334
        PangoLayoutLine *line;
 
335
        const gchar     *name;
 
336
 
 
337
        if (d->name)
 
338
        {
 
339
            g_free (d->name);
 
340
            d->name = NULL;
 
341
        }
 
342
 
 
343
        name = wnck_window_get_name (selected_win);
 
344
        if (name && (name_length = strlen (name)))
 
345
        {
 
346
            if (!d->layout)
 
347
            {
 
348
                d->layout = pango_layout_new (pango_context);
 
349
                if (d->layout)
 
350
                    pango_layout_set_wrap (d->layout, PANGO_WRAP_CHAR);
 
351
            }
 
352
 
 
353
            if (d->layout)
 
354
            {
 
355
                int tw;
 
356
 
 
357
                tw = width - switcher_context.left_space -
 
358
                    switcher_context.right_space - 64;
 
359
                pango_layout_set_auto_dir (d->layout, FALSE);
 
360
                pango_layout_set_width (d->layout, tw * PANGO_SCALE);
 
361
                pango_layout_set_text (d->layout, name, name_length);
 
362
 
 
363
                line = pango_layout_get_line (d->layout, 0);
 
364
 
 
365
                name_length = line->length;
 
366
                if (pango_layout_get_line_count (d->layout) > 1)
 
367
                {
 
368
                    if (name_length < 4)
 
369
                    {
 
370
                        g_object_unref (G_OBJECT (d->layout));
 
371
                        d->layout = NULL;
 
372
                    }
 
373
                    else
 
374
                    {
 
375
                        d->name = g_strndup (name, name_length);
 
376
                        strcpy (d->name + name_length - 3, "...");
 
377
                    }
 
378
                }
 
379
                else
 
380
                    d->name = g_strndup (name, name_length);
 
381
 
 
382
                if (d->layout)
 
383
                    pango_layout_set_text (d->layout, d->name, name_length);
 
384
            }
 
385
        }
 
386
        else if (d->layout)
 
387
        {
 
388
            g_object_unref (G_OBJECT (d->layout));
 
389
            d->layout = NULL;
 
390
        }
 
391
    }
 
392
 
 
393
    if (selected != switcher_selected_window)
 
394
    {
 
395
        gtk_label_set_text (GTK_LABEL (switcher_label), "");
 
396
        if (selected_win && d->name)
 
397
            gtk_label_set_text (GTK_LABEL (switcher_label), d->name);
 
398
        switcher_selected_window = selected;
 
399
    }
 
400
 
 
401
    pixmap = create_pixmap (width, height, 32);
 
402
    if (!pixmap)
 
403
        return FALSE;
 
404
 
 
405
    buffer_pixmap = create_pixmap (width, height, 32);
 
406
    if (!buffer_pixmap)
 
407
    {
 
408
        g_object_unref (G_OBJECT (pixmap));
 
409
        return FALSE;
 
410
    }
 
411
 
 
412
    if (switcher_pixmap)
 
413
        g_object_unref (G_OBJECT (switcher_pixmap));
 
414
 
 
415
    if (switcher_buffer_pixmap)
 
416
        g_object_unref (G_OBJECT (switcher_buffer_pixmap));
 
417
 
 
418
    if (d->pixmap)
 
419
        g_object_unref (G_OBJECT (d->pixmap));
 
420
 
 
421
    if (d->buffer_pixmap)
 
422
        g_object_unref (G_OBJECT (d->buffer_pixmap));
 
423
 
 
424
    if (d->cr)
 
425
        cairo_destroy (d->cr);
 
426
 
 
427
    if (d->picture)
 
428
        XRenderFreePicture (xdisplay, d->picture);
 
429
 
 
430
    switcher_pixmap        = pixmap;
 
431
    switcher_buffer_pixmap = buffer_pixmap;
 
432
 
 
433
    switcher_width  = width;
 
434
    switcher_height = height;
 
435
 
 
436
    g_object_ref (G_OBJECT (pixmap));
 
437
    g_object_ref (G_OBJECT (buffer_pixmap));
 
438
 
 
439
    d->pixmap        = pixmap;
 
440
    d->buffer_pixmap = buffer_pixmap;
 
441
    d->cr            = gdk_cairo_create (pixmap);
 
442
 
 
443
    format = get_format_for_drawable (d, GDK_DRAWABLE (d->buffer_pixmap));
 
444
    d->picture = XRenderCreatePicture (xdisplay, GDK_PIXMAP_XID (buffer_pixmap),
 
445
                                       format, 0, NULL);
 
446
 
 
447
    d->width  = width;
 
448
    d->height = height;
 
449
 
 
450
    d->prop_xid = popup;
 
451
 
 
452
    queue_decor_draw (d);
 
453
 
 
454
    return TRUE;
 
455
}