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));
422
update_window_decoration_state (win);
423
update_window_decoration_actions (win);
424
update_window_decoration_icon (win);
425
request_update_window_decoration_size (win);
427
update_event_windows (win);
431
for (i = 0; i < 3; i++)
432
for (j = 0; j < 3; j++)
433
d->event_windows[i][j].window = None;
440
remove_frame_window (WnckWindow *win)
442
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
445
xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
449
g_object_unref (G_OBJECT (d->pixmap));
453
if (d->buffer_pixmap)
455
g_object_unref (G_OBJECT (d->buffer_pixmap));
456
d->buffer_pixmap = NULL;
461
cairo_destroy (d->cr);
465
if (d->picture && !d->frame_window)
467
XRenderFreePicture (xdisplay, d->picture);
479
g_object_unref (G_OBJECT (d->layout));
485
cairo_pattern_destroy (d->icon);
491
g_object_unref (G_OBJECT (d->icon_pixmap));
492
d->icon_pixmap = NULL;
497
g_object_unref (G_OBJECT (d->icon_pixbuf));
498
d->icon_pixbuf = NULL;
501
if (d->force_quit_dialog)
503
GtkWidget *dialog = d->force_quit_dialog;
505
d->force_quit_dialog = NULL;
506
gtk_widget_destroy (dialog);
511
gdk_window_destroy (d->frame_window);
512
d->frame_window = NULL;
517
g_object_unref (d->decor_image);
518
d->decor_image = NULL;
521
if (d->decor_event_box)
523
g_object_unref (d->decor_event_box);
524
d->decor_event_box = NULL;
529
g_object_unref (d->decor_window);
530
d->decor_window = NULL;
535
gwd_decor_frame_unref (d->frame);
539
gdk_error_trap_push ();
540
XDeleteProperty (xdisplay, wnck_window_get_xid (win), win_decor_atom);
541
gdk_display_sync (gdk_display_get_default ());
542
gdk_error_trap_pop ();
547
d->decorated = FALSE;
555
draw_list = g_slist_remove (draw_list, d);
559
connect_window (WnckWindow *win)
561
g_signal_connect_object (win, "name_changed",
562
G_CALLBACK (window_name_changed),
564
g_signal_connect_object (win, "geometry_changed",
565
G_CALLBACK (window_geometry_changed),
567
g_signal_connect_object (win, "icon_changed",
568
G_CALLBACK (window_icon_changed),
570
g_signal_connect_object (win, "state_changed",
571
G_CALLBACK (window_state_changed),
573
g_signal_connect_object (win, "actions_changed",
574
G_CALLBACK (window_actions_changed),
579
active_window_changed (WnckScreen *screen)
584
win = wnck_screen_get_previously_active_window (screen);
587
d = g_object_get_data (G_OBJECT (win), "decor");
590
d->active = wnck_window_is_active (win);
592
decor_frame_t *frame = d->decorated ? d->frame : gwd_get_decor_frame (get_frame_type (win));
594
if ((d->state & META_MAXIMIZED) == META_MAXIMIZED)
596
if (!d->frame_window)
600
d->context = &frame->max_window_context_active;
601
d->shadow = frame->max_border_shadow_active;
605
d->context = &frame->max_window_context_inactive;
606
d->shadow = frame->max_border_shadow_inactive;
611
d->shadow = d->frame->max_border_no_shadow;
616
if (!d->frame_window)
620
d->context = &frame->window_context_active;
621
d->shadow = frame->border_shadow_active;
625
d->context = &frame->window_context_inactive;
626
d->shadow = frame->border_shadow_inactive;
631
d->shadow = d->frame->border_no_shadow;
636
gwd_decor_frame_unref (frame);
638
/* We need to update the decoration size here
639
* since the shadow size might have changed and
640
* in that case the decoration will be redrawn,
641
* however if the shadow size doesn't change
642
* then we need to redraw the decoration anyways
643
* since the image would have changed */
644
if (d->win != NULL &&
645
!request_update_window_decoration_size (d->win) &&
648
queue_decor_draw (d);
653
win = wnck_screen_get_active_window (screen);
656
d = g_object_get_data (G_OBJECT (win), "decor");
659
d->active = wnck_window_is_active (win);
661
decor_frame_t *frame = d->decorated ? d->frame : gwd_get_decor_frame (get_frame_type (win));
663
if ((d->state & META_MAXIMIZED) == META_MAXIMIZED)
665
if (!d->frame_window)
669
d->context = &frame->max_window_context_active;
670
d->shadow = frame->max_border_shadow_active;
674
d->context = &frame->max_window_context_inactive;
675
d->shadow = frame->max_border_shadow_inactive;
680
d->shadow = frame->max_border_no_shadow;
685
if (!d->frame_window)
689
d->context = &frame->window_context_active;
690
d->shadow = frame->border_shadow_active;
694
d->context = &frame->window_context_inactive;
695
d->shadow = frame->border_shadow_inactive;
700
d->shadow = frame->border_no_shadow;
705
gwd_decor_frame_unref (frame);
707
/* We need to update the decoration size here
708
* since the shadow size might have changed and
709
* in that case the decoration will be redrawn,
710
* however if the shadow size doesn't change
711
* then we need to redraw the decoration anyways
712
* since the image would have changed */
713
if (d->win != NULL &&
714
!request_update_window_decoration_size (d->win) &&
717
queue_decor_draw (d);
724
window_opened (WnckScreen *screen,
732
static event_callback callback[3][3] = {
733
{ top_left_event, top_event, top_right_event },
734
{ left_event, title_event, right_event },
735
{ bottom_left_event, bottom_event, bottom_right_event }
737
static event_callback button_callback[BUTTON_NUM] = {
745
unshade_button_event,
746
unabove_button_event,
750
d = calloc (1, sizeof (decor_t));
754
for (i = 0; i < 3; i++)
755
for (j = 0; j < 3; j++)
756
d->event_windows[i][j].callback = callback[i][j];
758
for (i = 0; i < BUTTON_NUM; i++)
759
d->button_windows[i].callback = button_callback[i];
761
wnck_window_get_client_window_geometry (win, NULL, NULL,
765
d->draw = theme_draw_window_decoration;
770
d->buffer_pixmap = NULL;
773
connect_window (win);
775
g_object_set_data (G_OBJECT (win), "decor", d);
777
xid = wnck_window_get_xid (win);
779
if (get_window_prop (xid, frame_input_window_atom, &window))
781
add_frame_window (win, window, FALSE);
783
else if (get_window_prop (xid, frame_output_window_atom, &window))
785
add_frame_window (win, window, TRUE);
790
window_closed (WnckScreen *screen,
793
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
797
remove_frame_window (win);
798
g_object_set_data (G_OBJECT (win), "decor", NULL);
804
connect_screen (WnckScreen *screen)
808
g_signal_connect_object (G_OBJECT (screen), "active_window_changed",
809
G_CALLBACK (active_window_changed),
811
g_signal_connect_object (G_OBJECT (screen), "window_opened",
812
G_CALLBACK (window_opened),
814
g_signal_connect_object (G_OBJECT (screen), "window_closed",
815
G_CALLBACK (window_closed),
818
windows = wnck_screen_get_windows (screen);
819
while (windows != NULL)
821
window_opened (screen, windows->data);
822
windows = windows->next;