~dbarth/compiz/reworked-fix-744104

« back to all changes in this revision

Viewing changes to unity/unity_window_decorator/src/events.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
void
 
4
move_resize_window (WnckWindow *win,
 
5
                    int        direction,
 
6
                    decor_event *gtkwd_event)
 
7
{
 
8
    Display    *xdisplay;
 
9
    GdkDisplay *gdkdisplay;
 
10
    GdkScreen  *screen;
 
11
    Window     xroot;
 
12
    XEvent     ev;
 
13
 
 
14
    gdkdisplay = gdk_display_get_default ();
 
15
    xdisplay   = GDK_DISPLAY_XDISPLAY (gdkdisplay);
 
16
    screen     = gdk_display_get_default_screen (gdkdisplay);
 
17
    xroot      = RootWindowOfScreen (gdk_x11_screen_get_xscreen (screen));
 
18
 
 
19
    if (action_menu_mapped)
 
20
    {
 
21
        gtk_object_destroy (GTK_OBJECT (action_menu));
 
22
        action_menu_mapped = FALSE;
 
23
        action_menu = NULL;
 
24
        return;
 
25
    }
 
26
 
 
27
    ev.xclient.type    = ClientMessage;
 
28
    ev.xclient.display = xdisplay;
 
29
 
 
30
    ev.xclient.serial     = 0;
 
31
    ev.xclient.send_event = TRUE;
 
32
 
 
33
    ev.xclient.window       = wnck_window_get_xid (win);
 
34
    ev.xclient.message_type = wm_move_resize_atom;
 
35
    ev.xclient.format       = 32;
 
36
 
 
37
    ev.xclient.data.l[0] = gtkwd_event->x_root;
 
38
    ev.xclient.data.l[1] = gtkwd_event->y_root;
 
39
    ev.xclient.data.l[2] = direction;
 
40
    ev.xclient.data.l[3] = gtkwd_event->button;
 
41
    ev.xclient.data.l[4] = 1;
 
42
 
 
43
    XUngrabPointer (xdisplay, gtkwd_event->time);
 
44
    XUngrabKeyboard (xdisplay, gtkwd_event->time);
 
45
 
 
46
    XSendEvent (xdisplay, xroot, FALSE,
 
47
                SubstructureRedirectMask | SubstructureNotifyMask,
 
48
                &ev);
 
49
 
 
50
    XSync (xdisplay, FALSE);
 
51
}
 
52
 
 
53
void
 
54
common_button_event (WnckWindow *win,
 
55
                     decor_event *gtkwd_event,
 
56
                     decor_event_type gtkwd_type,
 
57
                     int        button,
 
58
                     int        max)
 
59
{
 
60
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
61
    guint   state = d->button_states[button];
 
62
 
 
63
    if (d->frame_window && gtkwd_type == GEnterNotify)
 
64
    {
 
65
        GdkCursor* cursor;
 
66
        cursor = gdk_cursor_new (GDK_LEFT_PTR);
 
67
        gdk_window_set_cursor (d->frame_window, cursor);
 
68
        gdk_cursor_unref (cursor);
 
69
    }
 
70
 
 
71
    switch (gtkwd_type) {
 
72
    case GButtonPress:
 
73
        if (gtkwd_event->button <= max)
 
74
            d->button_states[button] |= PRESSED_EVENT_WINDOW;
 
75
        break;
 
76
    case GButtonRelease:
 
77
        if (gtkwd_event->button <= max)
 
78
            d->button_states[button] &= ~PRESSED_EVENT_WINDOW;
 
79
        break;
 
80
    case GEnterNotify:
 
81
        d->button_states[button] |= IN_EVENT_WINDOW;
 
82
        break;
 
83
    case GLeaveNotify:
 
84
        d->button_states[button] &= ~IN_EVENT_WINDOW;
 
85
        break;
 
86
    default:
 
87
        break;
 
88
    }
 
89
 
 
90
    if (state != d->button_states[button])
 
91
        queue_decor_draw (d);
 
92
}
 
93
 
 
94
#define BUTTON_EVENT_ACTION_STATE (PRESSED_EVENT_WINDOW | IN_EVENT_WINDOW)
 
95
 
 
96
void
 
97
close_button_event (WnckWindow *win,
 
98
                    decor_event *gtkwd_event,
 
99
                    decor_event_type gtkwd_type)
 
100
{
 
101
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
102
    guint   state = d->button_states[BUTTON_CLOSE];
 
103
 
 
104
    common_button_event (win, gtkwd_event, gtkwd_type,
 
105
                         BUTTON_CLOSE, 1);
 
106
 
 
107
    switch (gtkwd_type) {
 
108
    case GButtonRelease:
 
109
        if (gtkwd_event->button == 1)
 
110
            if (state == BUTTON_EVENT_ACTION_STATE)
 
111
                wnck_window_close (win, gtkwd_event->time);
 
112
        break;
 
113
    default:
 
114
        break;
 
115
    }
 
116
}
 
117
 
 
118
void
 
119
max_button_event (WnckWindow *win,
 
120
                  decor_event *gtkwd_event,
 
121
                  decor_event_type gtkwd_type)
 
122
{
 
123
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
124
    guint   state = d->button_states[BUTTON_MAX];
 
125
 
 
126
    if (wnck_window_is_maximized (win))
 
127
        common_button_event (win, gtkwd_event, gtkwd_type, BUTTON_MAX,
 
128
                             3);
 
129
    else
 
130
        common_button_event (win, gtkwd_event, gtkwd_type, BUTTON_MAX,
 
131
                             3);
 
132
 
 
133
    switch (gtkwd_type) {
 
134
    case GButtonRelease:
 
135
        if (gtkwd_event->button <= 3)
 
136
        {
 
137
            if (state == BUTTON_EVENT_ACTION_STATE)
 
138
            {
 
139
                if (gtkwd_event->button == 2)
 
140
                {
 
141
                    if (wnck_window_is_maximized_vertically (win))
 
142
                        wnck_window_unmaximize_vertically (win);
 
143
                    else
 
144
                        wnck_window_maximize_vertically (win);
 
145
                }
 
146
                else if (gtkwd_event->button == 3)
 
147
                {
 
148
                    if (wnck_window_is_maximized_horizontally (win))
 
149
                        wnck_window_unmaximize_horizontally (win);
 
150
                    else
 
151
                        wnck_window_maximize_horizontally (win);
 
152
                }
 
153
                else
 
154
                {
 
155
                    if (wnck_window_is_maximized (win))
 
156
                        wnck_window_unmaximize (win);
 
157
                    else
 
158
                        wnck_window_maximize (win);
 
159
                }
 
160
            }
 
161
        }
 
162
        break;
 
163
    default:
 
164
        break;
 
165
    }
 
166
}
 
167
 
 
168
void
 
169
min_button_event (WnckWindow *win,
 
170
                  decor_event *gtkwd_event,
 
171
                  decor_event_type gtkwd_type)
 
172
{
 
173
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
174
    guint   state = d->button_states[BUTTON_MIN];
 
175
 
 
176
    common_button_event (win, gtkwd_event, gtkwd_type,
 
177
                         BUTTON_MIN, 1);
 
178
 
 
179
    switch (gtkwd_type) {
 
180
    case GButtonRelease:
 
181
        if (gtkwd_event->button == 1)
 
182
            if (state == BUTTON_EVENT_ACTION_STATE)
 
183
                wnck_window_minimize (win);
 
184
        break;
 
185
    default:
 
186
        break;
 
187
    }
 
188
}
 
189
 
 
190
void
 
191
menu_button_event (WnckWindow *win,
 
192
                   decor_event *gtkwd_event,
 
193
                   decor_event_type gtkwd_type)
 
194
{
 
195
 
 
196
    common_button_event (win, gtkwd_event, gtkwd_type,
 
197
                         BUTTON_MENU, 1);
 
198
 
 
199
    switch (gtkwd_type) {
 
200
    case GButtonPress:
 
201
        if (gtkwd_event->button == 1)
 
202
            action_menu_map (win,
 
203
                             gtkwd_event->button,
 
204
                             gtkwd_event->time);
 
205
        break;
 
206
    default:
 
207
        break;
 
208
    }
 
209
}
 
210
 
 
211
void
 
212
shade_button_event (WnckWindow *win,
 
213
                    decor_event *gtkwd_event,
 
214
                    decor_event_type gtkwd_type)
 
215
{
 
216
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
217
    guint   state = d->button_states[BUTTON_SHADE];
 
218
 
 
219
    common_button_event (win, gtkwd_event, gtkwd_type,
 
220
                         BUTTON_SHADE, 1);
 
221
 
 
222
    switch (gtkwd_type) {
 
223
    case GButtonRelease:
 
224
        if (gtkwd_event->button == 1)
 
225
        {
 
226
            if (state == BUTTON_EVENT_ACTION_STATE)
 
227
                wnck_window_shade (win);
 
228
        }
 
229
        break;
 
230
    default:
 
231
        break;
 
232
    }
 
233
}
 
234
 
 
235
void
 
236
above_button_event (WnckWindow *win,
 
237
                    decor_event *gtkwd_event,
 
238
                    decor_event_type gtkwd_type)
 
239
{
 
240
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
241
    guint   state = d->button_states[BUTTON_ABOVE];
 
242
 
 
243
    common_button_event (win, gtkwd_event, gtkwd_type,
 
244
                         BUTTON_ABOVE, 1);
 
245
 
 
246
    switch (gtkwd_type) {
 
247
    case GButtonRelease:
 
248
        if (gtkwd_event->button == 1)
 
249
            if (state == BUTTON_EVENT_ACTION_STATE)
 
250
#ifdef HAVE_LIBWNCK_2_18_1
 
251
                wnck_window_make_above (win);
 
252
#endif
 
253
        break;
 
254
    default:
 
255
        break;
 
256
    }
 
257
}
 
258
 
 
259
void
 
260
stick_button_event (WnckWindow *win,
 
261
                    decor_event *gtkwd_event,
 
262
                    decor_event_type gtkwd_type)
 
263
{
 
264
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
265
    guint   state = d->button_states[BUTTON_STICK];
 
266
 
 
267
    common_button_event (win, gtkwd_event, gtkwd_type,
 
268
                         BUTTON_STICK, 1);
 
269
 
 
270
    switch (gtkwd_type) {
 
271
    case GButtonRelease:
 
272
        if (gtkwd_event->button == 1)
 
273
            if (state == BUTTON_EVENT_ACTION_STATE)
 
274
                wnck_window_stick (win);
 
275
        break;
 
276
    default:
 
277
        break;
 
278
    }
 
279
}
 
280
 
 
281
void
 
282
unshade_button_event (WnckWindow *win,
 
283
                      decor_event *gtkwd_event,
 
284
                      decor_event_type gtkwd_type)
 
285
{
 
286
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
287
    guint   state = d->button_states[BUTTON_UNSHADE];
 
288
 
 
289
    common_button_event (win, gtkwd_event, gtkwd_type,
 
290
                         BUTTON_UNSHADE, 1);
 
291
 
 
292
    switch (gtkwd_type) {
 
293
    case GButtonRelease:
 
294
        if (gtkwd_event->button == 1)
 
295
            if (state == BUTTON_EVENT_ACTION_STATE)
 
296
                wnck_window_unshade (win);
 
297
        break;
 
298
    default:
 
299
        break;
 
300
    }
 
301
}
 
302
 
 
303
void
 
304
unabove_button_event (WnckWindow *win,
 
305
                      decor_event *gtkwd_event,
 
306
                      decor_event_type gtkwd_type)
 
307
{
 
308
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
309
    guint   state = d->button_states[BUTTON_UNABOVE];
 
310
 
 
311
    common_button_event (win, gtkwd_event, gtkwd_type,
 
312
                         BUTTON_UNABOVE, 1);
 
313
 
 
314
    switch (gtkwd_type) {
 
315
    case GButtonRelease:
 
316
        if (gtkwd_event->button == 1)
 
317
            if (state == BUTTON_EVENT_ACTION_STATE)
 
318
#ifdef HAVE_LIBWNCK_2_18_1
 
319
                wnck_window_unmake_above (win);
 
320
#endif
 
321
        break;
 
322
    default:
 
323
        break;
 
324
    }
 
325
}
 
326
 
 
327
void
 
328
unstick_button_event (WnckWindow *win,
 
329
                      decor_event *gtkwd_event,
 
330
                      decor_event_type gtkwd_type)
 
331
{
 
332
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
333
    guint   state = d->button_states[BUTTON_UNSTICK];
 
334
 
 
335
    common_button_event (win, gtkwd_event, gtkwd_type,
 
336
                         BUTTON_UNSTICK, 1);
 
337
 
 
338
    switch (gtkwd_type) {
 
339
    case GButtonRelease:
 
340
        if (gtkwd_event->button == 1)
 
341
            if (state == BUTTON_EVENT_ACTION_STATE)
 
342
                wnck_window_unstick (win);
 
343
        break;
 
344
    default:
 
345
        break;
 
346
    }
 
347
}
 
348
 
 
349
void
 
350
handle_title_button_event (WnckWindow   *win,
 
351
                           int          action,
 
352
                           decor_event *gtkwd_event)
 
353
{
 
354
    switch (action) {
 
355
    case CLICK_ACTION_SHADE:
 
356
        if (wnck_window_is_shaded (win))
 
357
            wnck_window_unshade (win);
 
358
        else
 
359
            wnck_window_shade (win);
 
360
        break;
 
361
    case CLICK_ACTION_MAXIMIZE:
 
362
        if (wnck_window_is_maximized (win))
 
363
            wnck_window_unmaximize (win);
 
364
        else
 
365
            wnck_window_maximize (win);
 
366
        break;
 
367
    case CLICK_ACTION_MINIMIZE:
 
368
        if (!wnck_window_is_minimized (win))
 
369
            wnck_window_minimize (win);
 
370
        break;
 
371
    case CLICK_ACTION_RAISE:
 
372
        restack_window (win, Above);
 
373
        break;
 
374
    case CLICK_ACTION_LOWER:
 
375
        restack_window (win, Below);
 
376
        break;
 
377
    case CLICK_ACTION_MENU:
 
378
        action_menu_map (win, gtkwd_event->button, gtkwd_event->time);
 
379
        break;
 
380
    }
 
381
}
 
382
 
 
383
void
 
384
handle_mouse_wheel_title_event (WnckWindow   *win,
 
385
                                unsigned int button)
 
386
{
 
387
    switch (wheel_action) {
 
388
    case WHEEL_ACTION_SHADE:
 
389
        if (button == 4)
 
390
        {
 
391
            if (!wnck_window_is_shaded (win))
 
392
                wnck_window_shade (win);
 
393
        }
 
394
        else if (button == 5)
 
395
        {
 
396
            if (wnck_window_is_shaded (win))
 
397
                wnck_window_unshade (win);
 
398
        }
 
399
        break;
 
400
    default:
 
401
        break;
 
402
    }
 
403
}
 
404
 
 
405
void
 
406
title_event (WnckWindow       *win,
 
407
             decor_event      *gtkwd_event,
 
408
             decor_event_type gtkwd_type)
 
409
{
 
410
    static int    last_button_num = 0;
 
411
    static Window last_button_xwindow = None;
 
412
    static Time   last_button_time = 0;
 
413
    static int    last_button_x = 0;
 
414
    static int    last_button_y = 0;
 
415
 
 
416
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
417
 
 
418
    if (d->frame_window && gtkwd_type == GEnterNotify)
 
419
    {
 
420
        GdkCursor* cursor = gdk_cursor_new (GDK_LEFT_PTR);
 
421
        gdk_window_set_cursor (d->frame_window, cursor);
 
422
        gdk_cursor_unref (cursor);
 
423
    }
 
424
 
 
425
    if (gtkwd_type != GButtonPress)
 
426
        return;
 
427
 
 
428
    if (gtkwd_event->button == 1)
 
429
    {
 
430
        if (gtkwd_event->button == last_button_num                      &&
 
431
            gtkwd_event->window == last_button_xwindow                  &&
 
432
            gtkwd_event->time < last_button_time + double_click_timeout &&
 
433
            dist (gtkwd_event->x, gtkwd_event->y,
 
434
                  last_button_x, last_button_y) < DOUBLE_CLICK_DISTANCE)
 
435
        {
 
436
            handle_title_button_event (win, double_click_action,
 
437
                                       gtkwd_event);
 
438
 
 
439
            last_button_num     = 0;
 
440
            last_button_xwindow = None;
 
441
            last_button_time    = 0;
 
442
            last_button_x       = 0;
 
443
            last_button_y       = 0;
 
444
        }
 
445
        else
 
446
        {
 
447
            last_button_num     = gtkwd_event->button;
 
448
            last_button_xwindow = gtkwd_event->window;
 
449
            last_button_time    = gtkwd_event->time;
 
450
            last_button_x       = gtkwd_event->x;
 
451
            last_button_y       = gtkwd_event->y;
 
452
 
 
453
            restack_window (win, Above);
 
454
 
 
455
            move_resize_window (win, WM_MOVERESIZE_MOVE, gtkwd_event);
 
456
        }
 
457
    }
 
458
    else if (gtkwd_event->button == 2)
 
459
    {
 
460
        handle_title_button_event (win, middle_click_action,
 
461
                                   gtkwd_event);
 
462
    }
 
463
    else if (gtkwd_event->button == 3)
 
464
    {
 
465
        handle_title_button_event (win, right_click_action,
 
466
                                   gtkwd_event);
 
467
    }
 
468
    else if (gtkwd_event->button == 4 ||
 
469
             gtkwd_event->button == 5)
 
470
    {
 
471
        handle_mouse_wheel_title_event (win, gtkwd_event->button);
 
472
    }
 
473
}
 
474
 
 
475
void
 
476
frame_common_event (WnckWindow       *win,
 
477
                    int              direction,
 
478
                    decor_event      *gtkwd_event,
 
479
                    decor_event_type gtkwd_type)
 
480
{
 
481
 
 
482
    decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
483
 
 
484
    if (d->frame_window && gtkwd_type == GEnterNotify)
 
485
    {
 
486
        GdkCursor *cursor = NULL;
 
487
 
 
488
        switch (direction)
 
489
        {
 
490
            case WM_MOVERESIZE_SIZE_TOPLEFT:
 
491
                cursor = gdk_cursor_new (GDK_TOP_LEFT_CORNER);
 
492
                break;
 
493
            case WM_MOVERESIZE_SIZE_LEFT:
 
494
                cursor = gdk_cursor_new (GDK_LEFT_SIDE);
 
495
                break;
 
496
            case WM_MOVERESIZE_SIZE_BOTTOMLEFT:
 
497
                cursor = gdk_cursor_new (GDK_BOTTOM_LEFT_CORNER);
 
498
                break;
 
499
            case WM_MOVERESIZE_SIZE_BOTTOM:
 
500
                cursor = gdk_cursor_new (GDK_BOTTOM_SIDE);
 
501
                break;
 
502
            case WM_MOVERESIZE_SIZE_BOTTOMRIGHT:
 
503
                cursor = gdk_cursor_new (GDK_BOTTOM_RIGHT_CORNER);
 
504
                break;
 
505
            case WM_MOVERESIZE_SIZE_RIGHT:
 
506
                cursor = gdk_cursor_new (GDK_RIGHT_SIDE);
 
507
                break;
 
508
            case WM_MOVERESIZE_SIZE_TOPRIGHT:
 
509
                cursor = gdk_cursor_new (GDK_TOP_RIGHT_CORNER);
 
510
                break;
 
511
            case WM_MOVERESIZE_SIZE_TOP:
 
512
                cursor = gdk_cursor_new (GDK_TOP_SIDE);
 
513
                break;
 
514
            default:
 
515
                break;
 
516
        }
 
517
 
 
518
        if (cursor)
 
519
        {
 
520
            gdk_window_set_cursor (d->frame_window, cursor);
 
521
            gdk_cursor_unref (cursor);
 
522
        }
 
523
    }
 
524
 
 
525
    if (gtkwd_type != GButtonPress)
 
526
        return;
 
527
 
 
528
    switch (gtkwd_event->button) {
 
529
    case 1:
 
530
        move_resize_window (win, direction, gtkwd_event);
 
531
        restack_window (win, Above);
 
532
        break;
 
533
    case 2:
 
534
        handle_title_button_event (win, middle_click_action,
 
535
                                   gtkwd_event);
 
536
        break;
 
537
    case 3:
 
538
        handle_title_button_event (win, right_click_action,
 
539
                                   gtkwd_event);
 
540
        break;
 
541
    }
 
542
}
 
543
 
 
544
void
 
545
top_left_event (WnckWindow       *win,
 
546
                decor_event      *gtkwd_event,
 
547
                decor_event_type gtkwd_type)
 
548
{
 
549
    frame_common_event (win, WM_MOVERESIZE_SIZE_TOPLEFT,
 
550
                        gtkwd_event, gtkwd_type);
 
551
}
 
552
 
 
553
void
 
554
top_event (WnckWindow       *win,
 
555
           decor_event      *gtkwd_event,
 
556
           decor_event_type gtkwd_type)
 
557
{
 
558
    frame_common_event (win, WM_MOVERESIZE_SIZE_TOP,
 
559
                        gtkwd_event, gtkwd_type);
 
560
}
 
561
 
 
562
void
 
563
top_right_event (WnckWindow       *win,
 
564
                 decor_event      *gtkwd_event,
 
565
                 decor_event_type gtkwd_type)
 
566
{
 
567
    frame_common_event (win, WM_MOVERESIZE_SIZE_TOPRIGHT,
 
568
                        gtkwd_event, gtkwd_type);
 
569
}
 
570
 
 
571
void
 
572
left_event (WnckWindow       *win,
 
573
            decor_event      *gtkwd_event,
 
574
            decor_event_type gtkwd_type)
 
575
{
 
576
    frame_common_event (win, WM_MOVERESIZE_SIZE_LEFT,
 
577
                        gtkwd_event, gtkwd_type);
 
578
}
 
579
 
 
580
void
 
581
right_event (WnckWindow       *win,
 
582
             decor_event      *gtkwd_event,
 
583
             decor_event_type gtkwd_type)
 
584
{
 
585
    frame_common_event (win, WM_MOVERESIZE_SIZE_RIGHT,
 
586
                        gtkwd_event, gtkwd_type);
 
587
}
 
588
 
 
589
void
 
590
bottom_left_event (WnckWindow *win,
 
591
                   decor_event *gtkwd_event,
 
592
                   decor_event_type gtkwd_type)
 
593
{
 
594
    frame_common_event (win, WM_MOVERESIZE_SIZE_BOTTOMLEFT,
 
595
                        gtkwd_event, gtkwd_type);
 
596
}
 
597
 
 
598
void
 
599
bottom_event (WnckWindow *win,
 
600
              decor_event *gtkwd_event,
 
601
              decor_event_type gtkwd_type)
 
602
{
 
603
    frame_common_event (win, WM_MOVERESIZE_SIZE_BOTTOM,
 
604
                        gtkwd_event, gtkwd_type);
 
605
}
 
606
 
 
607
void
 
608
bottom_right_event (WnckWindow *win,
 
609
                    decor_event *gtkwd_event,
 
610
                    decor_event_type gtkwd_type)
 
611
{
 
612
    frame_common_event (win, WM_MOVERESIZE_SIZE_BOTTOMRIGHT,
 
613
                        gtkwd_event, gtkwd_type);
 
614
}
 
615
 
 
616
void
 
617
frame_window_realized (GtkWidget *widget,
 
618
                       gpointer  data)
 
619
{
 
620
    decor_t *d = (decor_t *) data;
 
621
 
 
622
    if (d)
 
623
    {
 
624
        GdkWindow *gdk_frame_window = gtk_widget_get_window (d->decor_window);
 
625
        gdk_window_reparent (gdk_frame_window, d->frame_window, 0, 0);
 
626
        gdk_window_lower (gdk_frame_window);
 
627
 
 
628
    }
 
629
}
 
630
 
 
631
event_callback
 
632
find_event_callback_for_point (decor_t *d,
 
633
                               int     x,
 
634
                               int     y,
 
635
                               Bool    *enter,
 
636
                               Bool    *leave,
 
637
                               BoxPtr  *entered_box)
 
638
{
 
639
    int    i, j;
 
640
    BoxPtr box;
 
641
 
 
642
    for (i = 0; i < BUTTON_NUM; i++)
 
643
    {
 
644
        box = &d->button_windows[i].pos;
 
645
        if (x >= box->x1 && x <= box->x2 &&
 
646
            y >= box->y1 && y <= box->y2)
 
647
        {
 
648
            if (d->last_pos_entered != box)
 
649
            {
 
650
                if (enter)
 
651
                    *enter = TRUE;
 
652
                if (leave && d->last_pos_entered)
 
653
                    *leave = TRUE;
 
654
                if (entered_box)
 
655
                    *entered_box = box;
 
656
            }
 
657
            return d->button_windows[i].callback;
 
658
        }
 
659
    }
 
660
 
 
661
    for (i = 0; i < 3; i++)
 
662
    {
 
663
        for (j = 0; j < 3; j++)
 
664
        {
 
665
            box = &d->event_windows[i][j].pos;
 
666
            if (x >= box->x1 && x <= box->x2 &&
 
667
                y >= box->y1 && y <= box->y2)
 
668
            {
 
669
                if (d->last_pos_entered != box)
 
670
                {
 
671
                    if (enter)
 
672
                        *enter = TRUE;
 
673
                    if (leave && d->last_pos_entered)
 
674
                        *leave = TRUE;
 
675
                    if (entered_box)
 
676
                        *entered_box = box;
 
677
                }
 
678
                return d->event_windows[i][j].callback;
 
679
            }
 
680
        }
 
681
    }
 
682
 
 
683
    return NULL;
 
684
}
 
685
 
 
686
event_callback
 
687
find_leave_event_callback (decor_t *d)
 
688
{
 
689
    int i, j;
 
690
 
 
691
    for (i = 0; i < BUTTON_NUM; i++)
 
692
    {
 
693
        if (d->last_pos_entered == &d->button_windows[i].pos)
 
694
            return d->button_windows[i].callback;
 
695
    }
 
696
 
 
697
    for (i = 0; i < 3; i++)
 
698
    {
 
699
        for (j = 0; j < 3; j++)
 
700
        {
 
701
            if (d->last_pos_entered == &d->event_windows[i][j].pos)
 
702
                return d->event_windows[i][j].callback;
 
703
        }
 
704
    }
 
705
 
 
706
    return NULL;
 
707
}
 
708
 
 
709
void
 
710
frame_handle_button_press (GtkWidget      *widget,
 
711
                           GdkEventButton *event,
 
712
                           gpointer       user_data)
 
713
{
 
714
    decor_t *d = (decor_t *) user_data;
 
715
 
 
716
    if (d)
 
717
    {
 
718
        /* Check to see where the event happened and fill out an appropriate
 
719
         * struct
 
720
         */
 
721
        event_callback cb;
 
722
 
 
723
        cb = find_event_callback_for_point (d, event->x, event->y,
 
724
                                            NULL, NULL, NULL);
 
725
 
 
726
        if (cb && d->decorated)
 
727
        {
 
728
            decor_event gtkwd_event;
 
729
 
 
730
            gtkwd_event.window = GDK_WINDOW_XID (d->frame_window);
 
731
            gtkwd_event.button = event->button;
 
732
            gtkwd_event.x      = event->x;
 
733
            gtkwd_event.y      = event->y;
 
734
            gtkwd_event.x_root = event->x_root;
 
735
            gtkwd_event.y_root = event->y_root;
 
736
            gtkwd_event.time   = event->time;
 
737
 
 
738
            (*cb) (d->win, &gtkwd_event, GButtonPress);
 
739
        }
 
740
    }
 
741
}
 
742
 
 
743
void
 
744
frame_handle_button_release (GtkWidget      *widget,
 
745
                             GdkEventButton *event,
 
746
                             gpointer       user_data)
 
747
{
 
748
    decor_t *d = (decor_t *) user_data;
 
749
 
 
750
    if (d)
 
751
    {
 
752
        event_callback cb;
 
753
 
 
754
        cb = find_event_callback_for_point (d, event->x, event->y,
 
755
                                            NULL, NULL, NULL);
 
756
 
 
757
        if (cb && d->decorated)
 
758
        {
 
759
            decor_event gtkwd_event;
 
760
 
 
761
            gtkwd_event.window = GDK_WINDOW_XID (d->frame_window);
 
762
            gtkwd_event.button = event->button;
 
763
            gtkwd_event.x      = event->x;
 
764
            gtkwd_event.y      = event->y;
 
765
            gtkwd_event.x_root = event->x_root;
 
766
            gtkwd_event.y_root = event->y_root;
 
767
            gtkwd_event.time   = event->time;
 
768
 
 
769
            (*cb) (d->win, &gtkwd_event, GButtonRelease);
 
770
        }
 
771
    }
 
772
}
 
773
 
 
774
void
 
775
frame_handle_motion (GtkWidget      *widget,
 
776
                     GdkEventMotion *event,
 
777
                     gpointer       user_data)
 
778
{
 
779
    decor_t *d = (decor_t *) user_data;
 
780
 
 
781
    if (d)
 
782
    {
 
783
        event_callback cb = NULL;
 
784
        Bool           send_enter = FALSE;
 
785
        Bool           send_leave = FALSE;
 
786
        BoxPtr         entered_box;
 
787
 
 
788
        cb = find_event_callback_for_point (d, event->x, event->y,
 
789
                                            &send_enter, &send_leave,
 
790
                                            &entered_box);
 
791
 
 
792
        if (cb && d->decorated)
 
793
        {
 
794
            decor_event gtkwd_event;
 
795
 
 
796
            gtkwd_event.window = GDK_WINDOW_XID (d->frame_window);
 
797
            gtkwd_event.x      = event->x;
 
798
            gtkwd_event.y      = event->y;
 
799
            gtkwd_event.x_root = event->x_root;
 
800
            gtkwd_event.y_root = event->y_root;
 
801
            gtkwd_event.time   = event->time;
 
802
 
 
803
            if (send_enter)
 
804
                (*cb) (d->win, &gtkwd_event, GEnterNotify);
 
805
 
 
806
            if (send_leave)
 
807
            {
 
808
                event_callback leave_cb;
 
809
 
 
810
                leave_cb = find_leave_event_callback (d);
 
811
 
 
812
                if (leave_cb)
 
813
                    (*leave_cb) (d->win, &gtkwd_event, GLeaveNotify);
 
814
 
 
815
            }
 
816
 
 
817
            if (send_enter)
 
818
                d->last_pos_entered = entered_box;
 
819
        }
 
820
        else if (d->last_pos_entered && d->decorated)
 
821
        {
 
822
            /* We are not in an event / button window but last_pos_entered
 
823
             * is still set, so send a GLeaveNotify to last_pos_entered
 
824
             * and set it to NULL
 
825
             */
 
826
 
 
827
            event_callback leave_cb;
 
828
 
 
829
            leave_cb = find_leave_event_callback (d);
 
830
 
 
831
            if (leave_cb)
 
832
            {
 
833
                decor_event    gtkwd_event;
 
834
 
 
835
                gtkwd_event.window = GDK_WINDOW_XID (d->frame_window);
 
836
                gtkwd_event.x      = event->x;
 
837
                gtkwd_event.y      = event->y;
 
838
                gtkwd_event.x_root = event->x_root;
 
839
                gtkwd_event.y_root = event->y_root;
 
840
                gtkwd_event.time   = event->time;
 
841
 
 
842
                (*leave_cb) (d->win, &gtkwd_event, GLeaveNotify);
 
843
            }
 
844
 
 
845
            d->last_pos_entered = NULL;
 
846
        }
 
847
    }
 
848
}
 
849
 
 
850
GdkFilterReturn
 
851
event_filter_func (GdkXEvent *gdkxevent,
 
852
                   GdkEvent  *event,
 
853
                   gpointer  data)
 
854
{
 
855
    Display    *xdisplay;
 
856
    GdkDisplay *gdkdisplay;
 
857
    XEvent     *xevent = gdkxevent;
 
858
    gulong     xid = 0;
 
859
    Window     select = 0;
 
860
 
 
861
    gdkdisplay = gdk_display_get_default ();
 
862
    xdisplay   = GDK_DISPLAY_XDISPLAY (gdkdisplay);
 
863
 
 
864
    switch (xevent->type) {
 
865
    case CreateNotify:
 
866
        {
 
867
            if (!wnck_window_get (xevent->xcreatewindow.window))
 
868
            {
 
869
                GdkWindow *toplevel = gdk_window_foreign_new_for_display (gdkdisplay,
 
870
                                                                          xevent->xcreatewindow.window);
 
871
 
 
872
                if (toplevel)
 
873
                {
 
874
                    gdk_window_set_events (toplevel,
 
875
                                           gdk_window_get_events (toplevel) |
 
876
                                           GDK_PROPERTY_CHANGE_MASK);
 
877
 
 
878
                    /* check if the window is a switcher and update accordingly */
 
879
 
 
880
                    if (get_window_prop (xevent->xcreatewindow.window, select_window_atom, &select))
 
881
                        update_switcher_window (xevent->xcreatewindow.window, select);
 
882
                }
 
883
            }
 
884
        }
 
885
        break;
 
886
    case ButtonPress:
 
887
    case ButtonRelease:
 
888
        xid = (gulong)
 
889
            g_hash_table_lookup (frame_table,
 
890
                                 GINT_TO_POINTER (xevent->xbutton.window));
 
891
        break;
 
892
    case EnterNotify:
 
893
    case LeaveNotify:
 
894
        xid = (gulong)
 
895
            g_hash_table_lookup (frame_table,
 
896
                                 GINT_TO_POINTER (xevent->xcrossing.window));
 
897
        break;
 
898
    case MotionNotify:
 
899
        xid = (gulong)
 
900
            g_hash_table_lookup (frame_table,
 
901
                                 GINT_TO_POINTER (xevent->xmotion.window));
 
902
        break;
 
903
    case PropertyNotify:
 
904
        if (xevent->xproperty.atom == frame_input_window_atom)
 
905
        {
 
906
            WnckWindow *win;
 
907
 
 
908
            xid = xevent->xproperty.window;
 
909
 
 
910
            win = wnck_window_get (xid);
 
911
            if (win)
 
912
            {
 
913
                Window frame;
 
914
 
 
915
                if (!get_window_prop (xid, select_window_atom, &select))
 
916
                {
 
917
                    if (get_window_prop (xid, frame_input_window_atom, &frame))
 
918
                        add_frame_window (win, frame, FALSE);
 
919
                    else
 
920
                        remove_frame_window (win);
 
921
                }
 
922
            }
 
923
        }
 
924
        if (xevent->xproperty.atom == frame_output_window_atom)
 
925
        {
 
926
            WnckWindow *win;
 
927
 
 
928
            xid = xevent->xproperty.window;
 
929
 
 
930
            win = wnck_window_get (xid);
 
931
            if (win)
 
932
            {
 
933
                Window frame;
 
934
 
 
935
                if (!get_window_prop (xid, select_window_atom, &select))
 
936
                {
 
937
                    if (get_window_prop (xid, frame_output_window_atom, &frame))
 
938
                        add_frame_window (win, frame, TRUE);
 
939
                    else
 
940
                        remove_frame_window (win);
 
941
                }
 
942
            }
 
943
        }
 
944
        else if (xevent->xproperty.atom == compiz_shadow_info_atom ||
 
945
                 xevent->xproperty.atom == compiz_shadow_color_atom)
 
946
        {
 
947
            GdkScreen  *g_screen = gdk_display_get_default_screen (gdkdisplay);
 
948
            Window     root = GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (g_screen));
 
949
            WnckScreen *screen;
 
950
 
 
951
            screen = wnck_screen_get_for_root (root);
 
952
 
 
953
            if (screen)
 
954
            {
 
955
                shadow_property_changed (screen);
 
956
            }
 
957
        }
 
958
        else if (xevent->xproperty.atom == mwm_hints_atom)
 
959
        {
 
960
            WnckWindow *win;
 
961
 
 
962
            xid = xevent->xproperty.window;
 
963
 
 
964
            win = wnck_window_get (xid);
 
965
            if (win)
 
966
            {
 
967
                decor_t  *d = g_object_get_data (G_OBJECT (win), "decor");
 
968
                gboolean decorated = FALSE;
 
969
 
 
970
                if (get_mwm_prop (xid) & (MWM_DECOR_ALL | MWM_DECOR_TITLE))
 
971
                    decorated = TRUE;
 
972
 
 
973
                if (decorated != d->decorated)
 
974
                {
 
975
                    d->decorated = decorated;
 
976
                    if (decorated)
 
977
                    {
 
978
                        d->context = NULL;
 
979
                        d->width = d->height = 0;
 
980
 
 
981
                        update_window_decoration_size (win);
 
982
                        update_event_windows (win);
 
983
                    }
 
984
                    else
 
985
                    {
 
986
                        gdk_error_trap_push ();
 
987
                        XDeleteProperty (xdisplay, xid, win_decor_atom);
 
988
                        gdk_display_sync (gdk_display_get_default ());
 
989
                        gdk_error_trap_pop ();
 
990
                    }
 
991
                }
 
992
            }
 
993
        }
 
994
        else if (xevent->xproperty.atom == select_window_atom)
 
995
        {
 
996
            Window select;
 
997
 
 
998
            if (get_window_prop (xevent->xproperty.window, select_window_atom, &select))
 
999
                update_switcher_window (xevent->xproperty.window, select);
 
1000
        }
 
1001
        else if (xevent->xproperty.atom == XA_WM_TRANSIENT_FOR)
 
1002
        {
 
1003
            WnckWindow *win = wnck_window_get (xevent->xproperty.window);
 
1004
 
 
1005
            if (win &&
 
1006
                wnck_window_get_window_type (win) == WNCK_WINDOW_DIALOG)
 
1007
            {
 
1008
                Window parent;
 
1009
 
 
1010
                if (get_window_prop (xevent->xproperty.window, XA_WM_TRANSIENT_FOR, &parent))
 
1011
                {
 
1012
                    WnckWindow *p = wnck_window_get (parent);
 
1013
                    decor_t *d = g_object_get_data (G_OBJECT (p), "decor");
 
1014
                    decor_t *d_transient = g_object_get_data (G_OBJECT (p), "decor");
 
1015
 
 
1016
                    if (g_slist_find (d->transient_windows, p))
 
1017
                        break;
 
1018
 
 
1019
                    if (d)
 
1020
                    {
 
1021
                        d->transient_windows = g_slist_append (d->transient_windows, win);
 
1022
                        d_transient->transient_parent = p;
 
1023
                    }
 
1024
                }
 
1025
            }
 
1026
        }
 
1027
        break;
 
1028
    case DestroyNotify:
 
1029
    {
 
1030
        g_hash_table_remove (frame_table,
 
1031
                             GINT_TO_POINTER (xevent->xproperty.window));
 
1032
 
 
1033
        break;
 
1034
    }
 
1035
    case ClientMessage:
 
1036
        if (xevent->xclient.message_type == toolkit_action_atom)
 
1037
        {
 
1038
            long action;
 
1039
 
 
1040
            action = xevent->xclient.data.l[0];
 
1041
            if (action == toolkit_action_window_menu_atom)
 
1042
            {
 
1043
                WnckWindow *win;
 
1044
 
 
1045
                win = wnck_window_get (xevent->xclient.window);
 
1046
                if (win)
 
1047
                {
 
1048
                    action_menu_map (win,
 
1049
                                     xevent->xclient.data.l[2],
 
1050
                                     xevent->xclient.data.l[1]);
 
1051
                }
 
1052
            }
 
1053
            else if (action == toolkit_action_force_quit_dialog_atom)
 
1054
            {
 
1055
                WnckWindow *win;
 
1056
 
 
1057
                win = wnck_window_get (xevent->xclient.window);
 
1058
                if (win)
 
1059
                {
 
1060
                    if (xevent->xclient.data.l[2])
 
1061
                        show_force_quit_dialog (win,
 
1062
                                                xevent->xclient.data.l[1]);
 
1063
                    else
 
1064
                        hide_force_quit_dialog (win);
 
1065
                }
 
1066
            }
 
1067
        }
 
1068
    default:
 
1069
        break;
 
1070
    }
 
1071
 
 
1072
    if (xid)
 
1073
    {
 
1074
        WnckWindow *win;
 
1075
 
 
1076
        win = wnck_window_get (xid);
 
1077
        if (win)
 
1078
        {
 
1079
            decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
 
1080
 
 
1081
            if (d->decorated)
 
1082
            {
 
1083
                gint             i, j;
 
1084
                event_callback   cb = NULL;
 
1085
                Window           w = xevent->xany.window;
 
1086
 
 
1087
                for (i = 0; i < 3; i++)
 
1088
                    for (j = 0; j < 3; j++)
 
1089
                        if (d->event_windows[i][j].window == w)
 
1090
                            cb = d->event_windows[i][j].callback;
 
1091
 
 
1092
                if (!cb)
 
1093
                {
 
1094
                    for (i = 0; i < BUTTON_NUM; i++)
 
1095
                        if (d->button_windows[i].window == w)
 
1096
                            cb = d->button_windows[i].callback;
 
1097
                }
 
1098
 
 
1099
                if (cb)
 
1100
                {
 
1101
                    decor_event      gtkwd_event;
 
1102
                    decor_event_type gtkwd_type;
 
1103
 
 
1104
                    gtkwd_event.window = w;
 
1105
 
 
1106
                    switch (xevent->type)
 
1107
                    {
 
1108
                        case ButtonPress:
 
1109
                        case ButtonRelease:
 
1110
                            if (xevent->type == ButtonPress)
 
1111
                                gtkwd_type = GButtonPress;
 
1112
                            else
 
1113
                                gtkwd_type = GButtonRelease;
 
1114
                            gtkwd_event.button = xevent->xbutton.button;
 
1115
                            gtkwd_event.x = xevent->xbutton.x;
 
1116
                            gtkwd_event.y = xevent->xbutton.y;
 
1117
                            gtkwd_event.x_root = xevent->xbutton.x_root;
 
1118
                            gtkwd_event.y_root = xevent->xbutton.y_root;
 
1119
                            gtkwd_event.time = xevent->xbutton.time;
 
1120
                            break;
 
1121
                        case EnterNotify:
 
1122
                        case LeaveNotify:
 
1123
                            if (xevent->type == EnterNotify)
 
1124
                                gtkwd_type = GEnterNotify;
 
1125
                            else
 
1126
                                gtkwd_type = GLeaveNotify;
 
1127
                            gtkwd_event.x = xevent->xcrossing.x;
 
1128
                            gtkwd_event.y = xevent->xcrossing.y;
 
1129
                            gtkwd_event.x_root = xevent->xcrossing.x_root;
 
1130
                            gtkwd_event.y_root = xevent->xcrossing.y_root;
 
1131
                            gtkwd_event.time = xevent->xcrossing.time;
 
1132
                            break;
 
1133
                        default:
 
1134
                            cb = NULL;
 
1135
                            break;
 
1136
                    }
 
1137
                    if (cb)
 
1138
                        (*cb) (win, &gtkwd_event, gtkwd_type);
 
1139
                }
 
1140
            }
 
1141
        }
 
1142
    }
 
1143
 
 
1144
    return GDK_FILTER_CONTINUE;
 
1145
}
 
1146
 
 
1147
GdkFilterReturn
 
1148
selection_event_filter_func (GdkXEvent *gdkxevent,
 
1149
                             GdkEvent  *event,
 
1150
                             gpointer  data)
 
1151
{
 
1152
    Display    *xdisplay;
 
1153
    GdkDisplay *gdkdisplay;
 
1154
    XEvent     *xevent = gdkxevent;
 
1155
    int        status;
 
1156
 
 
1157
    gdkdisplay = gdk_display_get_default ();
 
1158
    xdisplay   = GDK_DISPLAY_XDISPLAY (gdkdisplay);
 
1159
 
 
1160
    switch (xevent->type) {
 
1161
    case SelectionRequest:
 
1162
        decor_handle_selection_request (xdisplay, xevent, dm_sn_timestamp);
 
1163
        break;
 
1164
    case SelectionClear:
 
1165
        status = decor_handle_selection_clear (xdisplay, xevent, 0);
 
1166
        if (status == DECOR_SELECTION_GIVE_UP)
 
1167
            exit (0);
 
1168
    default:
 
1169
        break;
 
1170
    }
 
1171
 
 
1172
    return GDK_FILTER_CONTINUE;
 
1173
}