1
#include "gtk-window-decorator.h"
4
window_name_changed (WnckWindow *win)
6
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
10
if (!update_window_decoration_size (win))
16
window_geometry_changed (WnckWindow *win)
18
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
24
wnck_window_get_client_window_geometry (win, NULL, NULL,
27
if (width != d->client_width || height != d->client_height)
29
d->client_width = width;
30
d->client_height = height;
32
update_window_decoration_size (win);
33
update_event_windows (win);
39
window_icon_changed (WnckWindow *win)
41
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
45
update_window_decoration_icon (win);
51
window_state_changed (WnckWindow *win)
53
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
57
update_window_decoration_state (win);
58
if (!update_window_decoration_size (win))
61
update_event_windows (win);
66
window_actions_changed (WnckWindow *win)
68
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
72
update_window_decoration_actions (win);
73
if (!update_window_decoration_size (win))
76
update_event_windows (win);
81
decorations_changed (WnckScreen *screen)
83
GdkDisplay *gdkdisplay;
88
gdkdisplay = gdk_display_get_default ();
89
gdkscreen = gdk_display_get_default_screen (gdkdisplay);
91
update_titlebar_font ();
92
(*theme_update_border_extents) (text_height);
95
update_default_decorations (gdkscreen);
100
/* Update all normal windows */
102
windows = wnck_screen_get_windows (screen);
103
while (windows != NULL)
105
decor_t *d = g_object_get_data (G_OBJECT (windows->data), "decor");
111
if (d->draw == draw_window_decoration ||
112
d->draw == meta_draw_window_decoration)
113
d->draw = theme_draw_window_decoration;
118
update_window_decoration (WNCK_WINDOW (windows->data));
119
windows = windows->next;
122
/* Update switcher window */
124
if (switcher_window &&
125
get_window_prop (switcher_window->prop_xid,
126
select_window_atom, &select))
128
decor_t *d = switcher_window;
129
/* force size update */
131
d->width = d->height = 0;
132
switcher_width = switcher_height = 0;
134
update_switcher_window (d->prop_xid, select);
139
restack_window (WnckWindow *win,
143
GdkDisplay *gdkdisplay;
148
gdkdisplay = gdk_display_get_default ();
149
xdisplay = GDK_DISPLAY_XDISPLAY (gdkdisplay);
150
screen = gdk_display_get_default_screen (gdkdisplay);
151
xroot = RootWindowOfScreen (gdk_x11_screen_get_xscreen (screen));
153
if (action_menu_mapped)
155
gtk_object_destroy (GTK_OBJECT (action_menu));
156
action_menu_mapped = FALSE;
161
ev.xclient.type = ClientMessage;
162
ev.xclient.display = xdisplay;
164
ev.xclient.serial = 0;
165
ev.xclient.send_event = TRUE;
167
ev.xclient.window = wnck_window_get_xid (win);
168
ev.xclient.message_type = restack_window_atom;
169
ev.xclient.format = 32;
171
ev.xclient.data.l[0] = 2;
172
ev.xclient.data.l[1] = None;
173
ev.xclient.data.l[2] = stack_mode;
174
ev.xclient.data.l[3] = 0;
175
ev.xclient.data.l[4] = 0;
177
XSendEvent (xdisplay, xroot, FALSE,
178
SubstructureRedirectMask | SubstructureNotifyMask,
181
XSync (xdisplay, FALSE);
186
add_frame_window (WnckWindow *win,
191
XSetWindowAttributes attr;
192
gulong xid = wnck_window_get_xid (win);
193
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
196
xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
198
/* If we have already done this, there is no need to do it again, except
199
* if the property changed.
201
* The reason this check is here is because sometimes the PropertyNotify X
202
* event can come a bit after the property on the window is actually set
203
* which might result in this function being called twice - once by
204
* wnck through window_opened and once through our X event handler
208
if (d->created && mode && d->frame_window)
211
d->active = wnck_window_is_active (win);
213
d->last_pos_entered = NULL;
215
attr.event_mask = ButtonPressMask | EnterWindowMask |
216
LeaveWindowMask | ExposureMask;
217
attr.override_redirect = TRUE;
219
gdk_error_trap_push ();
223
GdkColormap *colormap;
225
d->frame_window = create_gdk_window (frame);
226
d->decor_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
228
colormap = get_colormap_for_drawable (GDK_DRAWABLE (d->frame_window));
230
d->decor_image = gtk_image_new ();
232
gtk_widget_set_colormap (d->decor_window, colormap);
233
gtk_widget_set_colormap (d->decor_image, colormap);
235
d->decor_event_box = gtk_event_box_new ();
236
gtk_event_box_set_visible_window (GTK_EVENT_BOX (d->decor_event_box),
238
gtk_widget_set_events (d->decor_event_box, GDK_BUTTON_PRESS_MASK |
239
GDK_BUTTON_RELEASE_MASK |
240
GDK_POINTER_MOTION_MASK);
242
g_signal_connect (G_OBJECT (d->decor_event_box), "button-press-event",
243
G_CALLBACK (frame_handle_button_press),
246
g_signal_connect (G_OBJECT (d->decor_event_box), "button-release-event",
247
G_CALLBACK (frame_handle_button_release),
250
g_signal_connect (G_OBJECT (d->decor_event_box), "motion-notify-event",
251
G_CALLBACK (frame_handle_motion),
254
gtk_container_add (GTK_CONTAINER (d->decor_event_box), d->decor_image);
255
gtk_event_box_set_above_child (GTK_EVENT_BOX (d->decor_event_box), TRUE);
256
gtk_widget_show_all (d->decor_event_box);
257
gtk_window_set_decorated (GTK_WINDOW (d->decor_window), FALSE);
258
gtk_window_set_default_size (GTK_WINDOW (d->decor_window), 1000, 1000);
259
gtk_container_add (GTK_CONTAINER (d->decor_window), d->decor_event_box);
261
/* Assumed realization happens here */
263
g_signal_connect (G_OBJECT (d->decor_window), "realize",
264
G_CALLBACK (frame_window_realized), (gpointer) d);
266
gtk_widget_show_all (d->decor_window);
267
gtk_widget_show (d->decor_window);
269
g_object_set_data (G_OBJECT (d->frame_window),
270
"client_wnck_window", win);
274
d->frame_window = NULL;
276
for (i = 0; i < 3; i++)
278
for (j = 0; j < 3; j++)
280
d->event_windows[i][j].window =
281
XCreateWindow (xdisplay,
284
CopyFromParent, CopyFromParent, CopyFromParent,
285
CWOverrideRedirect | CWEventMask, &attr);
287
if (cursor[i][j].cursor)
288
XDefineCursor (xdisplay, d->event_windows[i][j].window,
289
cursor[i][j].cursor);
293
attr.event_mask |= ButtonReleaseMask;
295
for (i = 0; i < BUTTON_NUM; i++)
297
d->button_windows[i].window =
298
XCreateWindow (xdisplay,
301
CopyFromParent, CopyFromParent, CopyFromParent,
302
CWOverrideRedirect | CWEventMask, &attr);
304
d->button_states[i] = 0;
308
gdk_display_sync (gdk_display_get_default ());
309
if (!gdk_error_trap_pop ())
311
if (get_mwm_prop (xid) & (MWM_DECOR_ALL | MWM_DECOR_TITLE))
314
for (i = 0; i < 3; i++)
315
for (j = 0; j < 3; j++)
317
Window win = d->event_windows[i][j].window;
318
g_hash_table_insert (frame_table,
319
GINT_TO_POINTER (win),
320
GINT_TO_POINTER (xid));
323
for (i = 0; i < BUTTON_NUM; i++)
324
g_hash_table_insert (frame_table,
325
GINT_TO_POINTER (d->button_windows[i].window),
326
GINT_TO_POINTER (xid));
330
g_hash_table_insert (frame_table,
331
GINT_TO_POINTER (frame),
332
GINT_TO_POINTER (xid));
334
update_window_decoration_state (win);
335
update_window_decoration_actions (win);
336
update_window_decoration_icon (win);
337
update_window_decoration_size (win);
339
update_event_windows (win);
343
for (i = 0; i < 3; i++)
344
for (j = 0; j < 3; j++)
345
d->event_windows[i][j].window = None;
352
remove_frame_window (WnckWindow *win)
354
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
357
xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
361
g_object_unref (G_OBJECT (d->pixmap));
365
if (d->buffer_pixmap)
367
g_object_unref (G_OBJECT (d->buffer_pixmap));
368
d->buffer_pixmap = NULL;
373
cairo_destroy (d->cr);
377
if (d->picture && !d->frame_window)
379
XRenderFreePicture (xdisplay, d->picture);
391
g_object_unref (G_OBJECT (d->layout));
397
cairo_pattern_destroy (d->icon);
403
g_object_unref (G_OBJECT (d->icon_pixmap));
404
d->icon_pixmap = NULL;
409
g_object_unref (G_OBJECT (d->icon_pixbuf));
410
d->icon_pixbuf = NULL;
413
if (d->force_quit_dialog)
415
GtkWidget *dialog = d->force_quit_dialog;
417
d->force_quit_dialog = NULL;
418
gtk_widget_destroy (dialog);
423
gdk_window_destroy (d->frame_window);
424
d->frame_window = NULL;
429
g_object_unref (d->decor_image);
430
d->decor_image = NULL;
433
if (d->decor_event_box)
435
g_object_unref (d->decor_event_box);
436
d->decor_event_box = NULL;
441
g_object_unref (d->decor_window);
442
d->decor_window = NULL;
448
d->decorated = FALSE;
456
draw_list = g_slist_remove (draw_list, d);
460
connect_window (WnckWindow *win)
462
g_signal_connect_object (win, "name_changed",
463
G_CALLBACK (window_name_changed),
465
g_signal_connect_object (win, "geometry_changed",
466
G_CALLBACK (window_geometry_changed),
468
g_signal_connect_object (win, "icon_changed",
469
G_CALLBACK (window_icon_changed),
471
g_signal_connect_object (win, "state_changed",
472
G_CALLBACK (window_state_changed),
474
g_signal_connect_object (win, "actions_changed",
475
G_CALLBACK (window_actions_changed),
480
active_window_changed (WnckScreen *screen)
485
win = wnck_screen_get_previously_active_window (screen);
488
d = g_object_get_data (G_OBJECT (win), "decor");
491
d->active = wnck_window_is_active (win);
493
if ((d->state & META_MAXIMIZED) == META_MAXIMIZED)
495
if (!d->frame_window)
499
d->context = &max_window_active_context;
500
d->shadow = max_border_active_shadow;
504
d->context = &max_window_inactive_context;
505
d->shadow = max_border_inactive_shadow;
510
d->shadow = max_border_no_shadow;
515
if (!d->frame_window)
519
d->context = &window_active_context;
520
d->shadow = border_active_shadow;
524
d->context = &window_inactive_context;
525
d->shadow = border_inactive_shadow;
530
d->shadow = border_no_shadow;
534
/* We need to update the decoration size here
535
* since the shadow size might have changed and
536
* in that case the decoration will be redrawn,
537
* however if the shadow size doesn't change
538
* then we need to redraw the decoration anyways
539
* since the image would have changed */
540
if (!update_window_decoration_size (d->win))
541
queue_decor_draw (d);
543
/* Also update any parents of this window
544
* since they won't get a notification here
546
if (d->transient_parent)
548
decor_t *d_parent = g_object_get_data (d->transient_parent, "decor");
549
queue_decor_draw (d_parent);
555
win = wnck_screen_get_active_window (screen);
558
d = g_object_get_data (G_OBJECT (win), "decor");
561
d->active = wnck_window_is_active (win);
563
if ((d->state & META_MAXIMIZED) == META_MAXIMIZED)
565
if (!d->frame_window)
569
d->context = &max_window_active_context;
570
d->shadow = max_border_active_shadow;
574
d->context = &max_window_inactive_context;
575
d->shadow = max_border_inactive_shadow;
580
d->shadow = max_border_no_shadow;
585
if (!d->frame_window)
589
d->context = &window_active_context;
590
d->shadow = border_active_shadow;
594
d->context = &window_inactive_context;
595
d->shadow = border_inactive_shadow;
600
d->shadow = border_no_shadow;
604
/* We need to update the decoration size here
605
* since the shadow size might have changed and
606
* in that case the decoration will be redrawn,
607
* however if the shadow size doesn't change
608
* then we need to redraw the decoration anyways
609
* since the image would have changed */
610
if (!update_window_decoration_size (d->win))
611
queue_decor_draw (d);
613
/* Also update any parents of this window
614
* since they won't get a notification here
616
if (d->transient_parent)
618
decor_t *d_parent = g_object_get_data (d->transient_parent, "decor");
619
queue_decor_draw (d_parent);
626
window_opened (WnckScreen *screen,
634
static event_callback callback[3][3] = {
635
{ top_left_event, top_event, top_right_event },
636
{ left_event, title_event, right_event },
637
{ bottom_left_event, bottom_event, bottom_right_event }
639
static event_callback button_callback[BUTTON_NUM] = {
647
unshade_button_event,
648
unabove_button_event,
652
d = calloc (1, sizeof (decor_t));
656
for (i = 0; i < 3; i++)
657
for (j = 0; j < 3; j++)
658
d->event_windows[i][j].callback = callback[i][j];
660
for (i = 0; i < BUTTON_NUM; i++)
661
d->button_windows[i].callback = button_callback[i];
663
wnck_window_get_client_window_geometry (win, NULL, NULL,
667
d->draw = theme_draw_window_decoration;
672
d->buffer_pixmap = NULL;
674
d->transient_windows = NULL;
676
connect_window (win);
678
g_object_set_data (G_OBJECT (win), "decor", d);
680
xid = wnck_window_get_xid (win);
682
if (get_window_prop (xid, frame_input_window_atom, &window))
684
add_frame_window (win, window, FALSE);
686
else if (get_window_prop (xid, frame_output_window_atom, &window))
688
add_frame_window (win, window, TRUE);
691
if (wnck_window_get_window_type (win) == WNCK_WINDOW_DIALOG)
695
if (get_window_prop (xid, XA_WM_TRANSIENT_FOR, &parent))
697
WnckWindow *p = wnck_window_get (parent);
698
decor_t *d = g_object_get_data (G_OBJECT (p), "decor");
699
decor_t *d_transient = g_object_get_data (G_OBJECT (win), "decor");
703
d->transient_windows = g_slist_append (d->transient_windows, win);
704
d_transient->transient_parent = p;
711
window_closed (WnckScreen *screen,
714
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
715
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
718
for (list = d->transient_windows; list; list = list->next)
720
WnckWindow *win = (WnckWindow *) list->data;
721
decor_t *d_transient = g_object_get_data (G_OBJECT (win), "decor");
723
d_transient->transient_parent = NULL;
726
g_slist_free (d->transient_windows);
727
d->transient_windows = NULL;
729
if (d->transient_parent)
731
decor_t *d_parent = g_object_get_data (G_OBJECT (d->transient_parent), "decor");
733
d_parent->transient_windows = g_slist_remove (d_parent->transient_windows, win);
735
if (!g_slist_length (d_parent->transient_windows))
736
d_parent->transient_windows = NULL;
739
remove_frame_window (win);
741
g_object_set_data (G_OBJECT (win), "decor", NULL);
743
gdk_error_trap_push ();
744
XDeleteProperty (xdisplay, wnck_window_get_xid (win), win_decor_atom);
745
gdk_display_sync (gdk_display_get_default ());
746
gdk_error_trap_pop ();
752
connect_screen (WnckScreen *screen)
756
g_signal_connect_object (G_OBJECT (screen), "active_window_changed",
757
G_CALLBACK (active_window_changed),
759
g_signal_connect_object (G_OBJECT (screen), "window_opened",
760
G_CALLBACK (window_opened),
762
g_signal_connect_object (G_OBJECT (screen), "window_closed",
763
G_CALLBACK (window_closed),
766
windows = wnck_screen_get_windows (screen);
767
while (windows != NULL)
769
window_opened (screen, windows->data);
770
windows = windows->next;