2
* Copyright © 2006 Novell, Inc.
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.
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.
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.
19
* Author: David Reveman <davidr@novell.com>
21
* 2D Mode: Copyright © 2010 Sam Spilsbury <smspillaz@gmail.com>
22
* Frames Management: Copright © 2011 Canonical Ltd.
23
* Authored By: Sam Spilsbury <sam.spilsbury@canonical.com>
26
#include "gtk-window-decorator.h"
29
get_frame_type (WnckWindow *win)
31
WnckWindowType wnck_type = wnck_window_get_window_type (win);
35
case WNCK_WINDOW_NORMAL:
37
case WNCK_WINDOW_DIALOG:
41
unsigned long n, left;
44
result = XGetWindowProperty (gdk_x11_get_default_xdisplay (), wnck_window_get_xid (win),
46
0L, 1024L, FALSE, XA_ATOM, &actual, &format,
49
if (result == Success && data)
51
Atom *a = (Atom *) data;
54
if (*a++ == net_wm_state_modal_atom)
56
XFree ((void *) data);
57
return "modal_dialog";
65
case WNCK_WINDOW_MENU:
67
case WNCK_WINDOW_UTILITY:
77
window_name_changed (WnckWindow *win)
79
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
83
if (!request_update_window_decoration_size (win))
89
window_geometry_changed (WnckWindow *win)
91
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
97
wnck_window_get_client_window_geometry (win, NULL, NULL,
100
if (width != d->client_width || height != d->client_height)
102
d->client_width = width;
103
d->client_height = height;
105
request_update_window_decoration_size (win);
106
update_event_windows (win);
112
window_icon_changed (WnckWindow *win)
114
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
118
update_window_decoration_icon (win);
119
queue_decor_draw (d);
124
window_state_changed (WnckWindow *win)
126
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
130
update_window_decoration_state (win);
131
if (!request_update_window_decoration_size (win))
132
queue_decor_draw (d);
134
update_event_windows (win);
139
window_actions_changed (WnckWindow *win)
141
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
145
update_window_decoration_actions (win);
146
if (!request_update_window_decoration_size (win))
147
queue_decor_draw (d);
149
update_event_windows (win);
154
update_frames_border_extents (gpointer key,
158
decor_frame_t *frame = (decor_frame_t *) value;
160
(*theme_update_border_extents) (frame);
164
decorations_changed (WnckScreen *screen)
166
GdkDisplay *gdkdisplay;
167
GdkScreen *gdkscreen;
171
gdkdisplay = gdk_display_get_default ();
172
gdkscreen = gdk_display_get_default_screen (gdkdisplay);
174
gwd_frames_foreach (set_frames_scales, (gpointer) settings->font);
176
update_titlebar_font ();
177
gwd_process_frames (update_frames_border_extents,
179
WINDOW_TYPE_FRAMES_NUM,
183
update_default_decorations (gdkscreen);
188
/* Update all normal windows */
190
windows = wnck_screen_get_windows (screen);
191
while (windows != NULL)
193
decor_t *d = g_object_get_data (G_OBJECT (windows->data), "decor");
199
if (d->draw == draw_window_decoration ||
200
d->draw == meta_draw_window_decoration)
201
d->draw = theme_draw_window_decoration;
206
update_window_decoration (WNCK_WINDOW (windows->data));
207
windows = windows->next;
210
/* Update switcher window */
212
if (switcher_window &&
213
get_window_prop (switcher_window->prop_xid,
214
select_window_atom, &select))
216
decor_t *d = switcher_window;
217
/* force size update */
219
d->width = d->height = 0;
221
update_switcher_window (d->prop_xid, select);
226
restack_window (WnckWindow *win,
230
GdkDisplay *gdkdisplay;
235
gdkdisplay = gdk_display_get_default ();
236
xdisplay = GDK_DISPLAY_XDISPLAY (gdkdisplay);
237
screen = gdk_display_get_default_screen (gdkdisplay);
238
xroot = RootWindowOfScreen (gdk_x11_screen_get_xscreen (screen));
240
if (action_menu_mapped)
242
gtk_object_destroy (GTK_OBJECT (action_menu));
243
action_menu_mapped = FALSE;
248
ev.xclient.type = ClientMessage;
249
ev.xclient.display = xdisplay;
251
ev.xclient.serial = 0;
252
ev.xclient.send_event = TRUE;
254
ev.xclient.window = wnck_window_get_xid (win);
255
ev.xclient.message_type = restack_window_atom;
256
ev.xclient.format = 32;
258
ev.xclient.data.l[0] = 2;
259
ev.xclient.data.l[1] = None;
260
ev.xclient.data.l[2] = stack_mode;
261
ev.xclient.data.l[3] = 0;
262
ev.xclient.data.l[4] = 0;
264
XSendEvent (xdisplay, xroot, FALSE,
265
SubstructureRedirectMask | SubstructureNotifyMask,
268
XSync (xdisplay, FALSE);
273
add_frame_window (WnckWindow *win,
278
XSetWindowAttributes attr;
279
gulong xid = wnck_window_get_xid (win);
280
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
283
xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
285
/* If we have already done this, there is no need to do it again, except
286
* if the property changed.
288
* The reason this check is here is because sometimes the PropertyNotify X
289
* event can come a bit after the property on the window is actually set
290
* which might result in this function being called twice - once by
291
* wnck through window_opened and once through our X event handler
295
if (d->created && mode && d->frame_window)
298
d->active = wnck_window_is_active (win);
300
d->frame = gwd_get_decor_frame (get_frame_type (win));
301
d->last_pos_entered = NULL;
303
attr.event_mask = ButtonPressMask | EnterWindowMask |
304
LeaveWindowMask | ExposureMask;
305
attr.override_redirect = TRUE;
307
gdk_error_trap_push ();
311
GdkColormap *colormap;
313
d->frame_window = create_gdk_window (frame);
314
d->decor_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
316
colormap = get_colormap_for_drawable (GDK_DRAWABLE (d->frame_window));
318
d->decor_image = gtk_image_new ();
320
gtk_widget_set_colormap (d->decor_window, colormap);
321
gtk_widget_set_colormap (d->decor_image, colormap);
323
d->decor_event_box = gtk_event_box_new ();
324
gtk_event_box_set_visible_window (GTK_EVENT_BOX (d->decor_event_box),
326
gtk_widget_set_events (d->decor_event_box, GDK_BUTTON_PRESS_MASK |
327
GDK_BUTTON_RELEASE_MASK |
328
GDK_POINTER_MOTION_MASK);
330
g_signal_connect (G_OBJECT (d->decor_event_box), "button-press-event",
331
G_CALLBACK (frame_handle_button_press),
334
g_signal_connect (G_OBJECT (d->decor_event_box), "button-release-event",
335
G_CALLBACK (frame_handle_button_release),
338
g_signal_connect (G_OBJECT (d->decor_event_box), "motion-notify-event",
339
G_CALLBACK (frame_handle_motion),
342
gtk_container_add (GTK_CONTAINER (d->decor_event_box), d->decor_image);
343
gtk_event_box_set_above_child (GTK_EVENT_BOX (d->decor_event_box), TRUE);
344
gtk_widget_show_all (d->decor_event_box);
345
gtk_window_set_decorated (GTK_WINDOW (d->decor_window), FALSE);
346
gtk_window_set_default_size (GTK_WINDOW (d->decor_window), 1000, 1000);
347
gtk_container_add (GTK_CONTAINER (d->decor_window), d->decor_event_box);
349
/* Assumed realization happens here */
351
g_signal_connect (G_OBJECT (d->decor_window), "realize",
352
G_CALLBACK (frame_window_realized), (gpointer) d);
354
gtk_widget_show_all (d->decor_window);
355
gtk_widget_show (d->decor_window);
357
g_object_set_data (G_OBJECT (d->frame_window),
358
"client_wnck_window", win);
362
d->frame_window = NULL;
364
for (i = 0; i < 3; i++)
366
for (j = 0; j < 3; j++)
368
d->event_windows[i][j].window =
369
XCreateWindow (xdisplay,
372
CopyFromParent, CopyFromParent, CopyFromParent,
373
CWOverrideRedirect | CWEventMask, &attr);
375
if (cursor[i][j].cursor)
376
XDefineCursor (xdisplay, d->event_windows[i][j].window,
377
cursor[i][j].cursor);
381
attr.event_mask |= ButtonReleaseMask;
383
for (i = 0; i < BUTTON_NUM; i++)
385
d->button_windows[i].window =
386
XCreateWindow (xdisplay,
389
CopyFromParent, CopyFromParent, CopyFromParent,
390
CWOverrideRedirect | CWEventMask, &attr);
392
d->button_states[i] = 0;
396
gdk_display_sync (gdk_display_get_default ());
397
if (!gdk_error_trap_pop ())
399
if (get_mwm_prop (xid) & (MWM_DECOR_ALL | MWM_DECOR_TITLE))
402
for (i = 0; i < 3; i++)
403
for (j = 0; j < 3; j++)
405
Window win = d->event_windows[i][j].window;
406
g_hash_table_insert (frame_table,
407
GINT_TO_POINTER (win),
408
GINT_TO_POINTER (xid));
411
for (i = 0; i < BUTTON_NUM; i++)
412
g_hash_table_insert (frame_table,
413
GINT_TO_POINTER (d->button_windows[i].window),
414
GINT_TO_POINTER (xid));
418
g_hash_table_insert (frame_table,
419
GINT_TO_POINTER (frame),
420
GINT_TO_POINTER (xid));
425
update_window_decoration_state (win);
426
update_window_decoration_actions (win);
427
update_window_decoration_icon (win);
428
request_update_window_decoration_size (win);
430
update_event_windows (win);
435
for (i = 0; i < 3; i++)
436
for (j = 0; j < 3; j++)
437
d->event_windows[i][j].window = None;
444
remove_frame_window (WnckWindow *win)
446
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
449
xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
453
g_object_unref (G_OBJECT (d->pixmap));
457
if (d->buffer_pixmap)
459
g_object_unref (G_OBJECT (d->buffer_pixmap));
460
d->buffer_pixmap = NULL;
465
cairo_destroy (d->cr);
469
if (d->picture && !d->frame_window)
471
XRenderFreePicture (xdisplay, d->picture);
483
g_object_unref (G_OBJECT (d->layout));
489
cairo_pattern_destroy (d->icon);
495
g_object_unref (G_OBJECT (d->icon_pixmap));
496
d->icon_pixmap = NULL;
501
g_object_unref (G_OBJECT (d->icon_pixbuf));
502
d->icon_pixbuf = NULL;
505
if (d->force_quit_dialog)
507
GtkWidget *dialog = d->force_quit_dialog;
509
d->force_quit_dialog = NULL;
510
gtk_widget_destroy (dialog);
515
gdk_window_destroy (d->frame_window);
516
d->frame_window = NULL;
521
g_object_unref (d->decor_image);
522
d->decor_image = NULL;
525
if (d->decor_event_box)
527
g_object_unref (d->decor_event_box);
528
d->decor_event_box = NULL;
533
g_object_unref (d->decor_window);
534
d->decor_window = NULL;
539
gwd_decor_frame_unref (d->frame);
543
gdk_error_trap_push ();
544
XDeleteProperty (xdisplay, wnck_window_get_xid (win), win_decor_atom);
545
gdk_display_sync (gdk_display_get_default ());
546
gdk_error_trap_pop ();
551
d->decorated = FALSE;
559
draw_list = g_slist_remove (draw_list, d);
563
connect_window (WnckWindow *win)
565
g_signal_connect_object (win, "name_changed",
566
G_CALLBACK (window_name_changed),
568
g_signal_connect_object (win, "geometry_changed",
569
G_CALLBACK (window_geometry_changed),
571
g_signal_connect_object (win, "icon_changed",
572
G_CALLBACK (window_icon_changed),
574
g_signal_connect_object (win, "state_changed",
575
G_CALLBACK (window_state_changed),
577
g_signal_connect_object (win, "actions_changed",
578
G_CALLBACK (window_actions_changed),
583
active_window_changed (WnckScreen *screen)
588
win = wnck_screen_get_previously_active_window (screen);
591
d = g_object_get_data (G_OBJECT (win), "decor");
594
d->active = wnck_window_is_active (win);
596
decor_frame_t *frame = d->decorated ? d->frame : gwd_get_decor_frame (get_frame_type (win));
598
if ((d->state & META_MAXIMIZED) == META_MAXIMIZED)
600
if (!d->frame_window)
604
d->context = &frame->max_window_context_active;
605
d->shadow = frame->max_border_shadow_active;
609
d->context = &frame->max_window_context_inactive;
610
d->shadow = frame->max_border_shadow_inactive;
615
d->shadow = d->frame->max_border_no_shadow;
620
if (!d->frame_window)
624
d->context = &frame->window_context_active;
625
d->shadow = frame->border_shadow_active;
629
d->context = &frame->window_context_inactive;
630
d->shadow = frame->border_shadow_inactive;
635
d->shadow = d->frame->border_no_shadow;
640
gwd_decor_frame_unref (frame);
642
/* We need to update the decoration size here
643
* since the shadow size might have changed and
644
* in that case the decoration will be redrawn,
645
* however if the shadow size doesn't change
646
* then we need to redraw the decoration anyways
647
* since the image would have changed */
648
if (d->win != NULL &&
649
!request_update_window_decoration_size (d->win) &&
652
queue_decor_draw (d);
657
win = wnck_screen_get_active_window (screen);
660
d = g_object_get_data (G_OBJECT (win), "decor");
663
d->active = wnck_window_is_active (win);
665
decor_frame_t *frame = d->decorated ? d->frame : gwd_get_decor_frame (get_frame_type (win));
667
if ((d->state & META_MAXIMIZED) == META_MAXIMIZED)
669
if (!d->frame_window)
673
d->context = &frame->max_window_context_active;
674
d->shadow = frame->max_border_shadow_active;
678
d->context = &frame->max_window_context_inactive;
679
d->shadow = frame->max_border_shadow_inactive;
684
d->shadow = frame->max_border_no_shadow;
689
if (!d->frame_window)
693
d->context = &frame->window_context_active;
694
d->shadow = frame->border_shadow_active;
698
d->context = &frame->window_context_inactive;
699
d->shadow = frame->border_shadow_inactive;
704
d->shadow = frame->border_no_shadow;
709
gwd_decor_frame_unref (frame);
711
/* We need to update the decoration size here
712
* since the shadow size might have changed and
713
* in that case the decoration will be redrawn,
714
* however if the shadow size doesn't change
715
* then we need to redraw the decoration anyways
716
* since the image would have changed */
717
if (d->win != NULL &&
718
!request_update_window_decoration_size (d->win) &&
721
queue_decor_draw (d);
728
window_opened (WnckScreen *screen,
736
static event_callback callback[3][3] = {
737
{ top_left_event, top_event, top_right_event },
738
{ left_event, title_event, right_event },
739
{ bottom_left_event, bottom_event, bottom_right_event }
741
static event_callback button_callback[BUTTON_NUM] = {
749
unshade_button_event,
750
unabove_button_event,
754
d = calloc (1, sizeof (decor_t));
758
for (i = 0; i < 3; i++)
759
for (j = 0; j < 3; j++)
760
d->event_windows[i][j].callback = callback[i][j];
762
for (i = 0; i < BUTTON_NUM; i++)
763
d->button_windows[i].callback = button_callback[i];
765
wnck_window_get_client_window_geometry (win, NULL, NULL,
769
d->draw = theme_draw_window_decoration;
774
d->buffer_pixmap = NULL;
777
connect_window (win);
779
g_object_set_data (G_OBJECT (win), "decor", d);
781
xid = wnck_window_get_xid (win);
783
if (get_window_prop (xid, frame_input_window_atom, &window))
785
add_frame_window (win, window, FALSE);
787
else if (get_window_prop (xid, frame_output_window_atom, &window))
789
add_frame_window (win, window, TRUE);
794
window_closed (WnckScreen *screen,
797
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
801
remove_frame_window (win);
802
g_object_set_data (G_OBJECT (win), "decor", NULL);
808
connect_screen (WnckScreen *screen)
812
g_signal_connect_object (G_OBJECT (screen), "active_window_changed",
813
G_CALLBACK (active_window_changed),
815
g_signal_connect_object (G_OBJECT (screen), "window_opened",
816
G_CALLBACK (window_opened),
818
g_signal_connect_object (G_OBJECT (screen), "window_closed",
819
G_CALLBACK (window_closed),
822
windows = wnck_screen_get_windows (screen);
823
while (windows != NULL)
825
window_opened (screen, windows->data);
826
windows = windows->next;