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 (WnckWindowType wnck_type)
33
case WNCK_WINDOW_NORMAL:
35
case WNCK_WINDOW_DIALOG:
37
case WNCK_WINDOW_MENU:
39
case WNCK_WINDOW_UTILITY:
49
window_name_changed (WnckWindow *win)
51
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
55
if (!update_window_decoration_size (win))
61
window_geometry_changed (WnckWindow *win)
63
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
69
wnck_window_get_client_window_geometry (win, NULL, NULL,
72
if (width != d->client_width || height != d->client_height)
74
d->client_width = width;
75
d->client_height = height;
77
update_window_decoration_size (win);
78
update_event_windows (win);
84
window_icon_changed (WnckWindow *win)
86
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
90
update_window_decoration_icon (win);
96
window_state_changed (WnckWindow *win)
98
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
102
update_window_decoration_state (win);
103
if (!update_window_decoration_size (win))
104
queue_decor_draw (d);
106
update_event_windows (win);
111
window_actions_changed (WnckWindow *win)
113
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
117
update_window_decoration_actions (win);
118
if (!update_window_decoration_size (win))
119
queue_decor_draw (d);
121
update_event_windows (win);
126
update_frames_border_extents (gpointer key,
130
decor_frame_t *frame = (decor_frame_t *) value;
132
(*theme_update_border_extents) (frame);
136
decorations_changed (WnckScreen *screen)
138
GdkDisplay *gdkdisplay;
139
GdkScreen *gdkscreen;
143
gdkdisplay = gdk_display_get_default ();
144
gdkscreen = gdk_display_get_default_screen (gdkdisplay);
146
gwd_frames_foreach (set_frames_scales, (gpointer) settings->font);
148
update_titlebar_font ();
149
gwd_process_frames (update_frames_border_extents,
151
WINDOW_TYPE_FRAMES_NUM,
155
update_default_decorations (gdkscreen);
160
/* Update all normal windows */
162
windows = wnck_screen_get_windows (screen);
163
while (windows != NULL)
165
decor_t *d = g_object_get_data (G_OBJECT (windows->data), "decor");
171
if (d->draw == draw_window_decoration ||
172
d->draw == meta_draw_window_decoration)
173
d->draw = theme_draw_window_decoration;
178
update_window_decoration (WNCK_WINDOW (windows->data));
179
windows = windows->next;
182
/* Update switcher window */
184
if (switcher_window &&
185
get_window_prop (switcher_window->prop_xid,
186
select_window_atom, &select))
188
decor_t *d = switcher_window;
189
/* force size update */
191
d->width = d->height = 0;
193
update_switcher_window (d->prop_xid, select);
198
restack_window (WnckWindow *win,
202
GdkDisplay *gdkdisplay;
207
gdkdisplay = gdk_display_get_default ();
208
xdisplay = GDK_DISPLAY_XDISPLAY (gdkdisplay);
209
screen = gdk_display_get_default_screen (gdkdisplay);
210
xroot = RootWindowOfScreen (gdk_x11_screen_get_xscreen (screen));
212
if (action_menu_mapped)
214
gtk_object_destroy (GTK_OBJECT (action_menu));
215
action_menu_mapped = FALSE;
220
ev.xclient.type = ClientMessage;
221
ev.xclient.display = xdisplay;
223
ev.xclient.serial = 0;
224
ev.xclient.send_event = TRUE;
226
ev.xclient.window = wnck_window_get_xid (win);
227
ev.xclient.message_type = restack_window_atom;
228
ev.xclient.format = 32;
230
ev.xclient.data.l[0] = 2;
231
ev.xclient.data.l[1] = None;
232
ev.xclient.data.l[2] = stack_mode;
233
ev.xclient.data.l[3] = 0;
234
ev.xclient.data.l[4] = 0;
236
XSendEvent (xdisplay, xroot, FALSE,
237
SubstructureRedirectMask | SubstructureNotifyMask,
240
XSync (xdisplay, FALSE);
245
add_frame_window (WnckWindow *win,
250
XSetWindowAttributes attr;
251
gulong xid = wnck_window_get_xid (win);
252
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
255
xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
257
/* If we have already done this, there is no need to do it again, except
258
* if the property changed.
260
* The reason this check is here is because sometimes the PropertyNotify X
261
* event can come a bit after the property on the window is actually set
262
* which might result in this function being called twice - once by
263
* wnck through window_opened and once through our X event handler
267
if (d->created && mode && d->frame_window)
270
d->active = wnck_window_is_active (win);
272
d->frame = gwd_get_decor_frame (get_frame_type (wnck_window_get_window_type (win)));
273
d->last_pos_entered = NULL;
275
attr.event_mask = ButtonPressMask | EnterWindowMask |
276
LeaveWindowMask | ExposureMask;
277
attr.override_redirect = TRUE;
279
gdk_error_trap_push ();
283
GdkColormap *colormap;
285
d->frame_window = create_gdk_window (frame);
286
d->decor_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
288
colormap = get_colormap_for_drawable (GDK_DRAWABLE (d->frame_window));
290
d->decor_image = gtk_image_new ();
292
gtk_widget_set_colormap (d->decor_window, colormap);
293
gtk_widget_set_colormap (d->decor_image, colormap);
295
d->decor_event_box = gtk_event_box_new ();
296
gtk_event_box_set_visible_window (GTK_EVENT_BOX (d->decor_event_box),
298
gtk_widget_set_events (d->decor_event_box, GDK_BUTTON_PRESS_MASK |
299
GDK_BUTTON_RELEASE_MASK |
300
GDK_POINTER_MOTION_MASK);
302
g_signal_connect (G_OBJECT (d->decor_event_box), "button-press-event",
303
G_CALLBACK (frame_handle_button_press),
306
g_signal_connect (G_OBJECT (d->decor_event_box), "button-release-event",
307
G_CALLBACK (frame_handle_button_release),
310
g_signal_connect (G_OBJECT (d->decor_event_box), "motion-notify-event",
311
G_CALLBACK (frame_handle_motion),
314
gtk_container_add (GTK_CONTAINER (d->decor_event_box), d->decor_image);
315
gtk_event_box_set_above_child (GTK_EVENT_BOX (d->decor_event_box), TRUE);
316
gtk_widget_show_all (d->decor_event_box);
317
gtk_window_set_decorated (GTK_WINDOW (d->decor_window), FALSE);
318
gtk_window_set_default_size (GTK_WINDOW (d->decor_window), 1000, 1000);
319
gtk_container_add (GTK_CONTAINER (d->decor_window), d->decor_event_box);
321
/* Assumed realization happens here */
323
g_signal_connect (G_OBJECT (d->decor_window), "realize",
324
G_CALLBACK (frame_window_realized), (gpointer) d);
326
gtk_widget_show_all (d->decor_window);
327
gtk_widget_show (d->decor_window);
329
g_object_set_data (G_OBJECT (d->frame_window),
330
"client_wnck_window", win);
334
d->frame_window = NULL;
336
for (i = 0; i < 3; i++)
338
for (j = 0; j < 3; j++)
340
d->event_windows[i][j].window =
341
XCreateWindow (xdisplay,
344
CopyFromParent, CopyFromParent, CopyFromParent,
345
CWOverrideRedirect | CWEventMask, &attr);
347
if (cursor[i][j].cursor)
348
XDefineCursor (xdisplay, d->event_windows[i][j].window,
349
cursor[i][j].cursor);
353
attr.event_mask |= ButtonReleaseMask;
355
for (i = 0; i < BUTTON_NUM; i++)
357
d->button_windows[i].window =
358
XCreateWindow (xdisplay,
361
CopyFromParent, CopyFromParent, CopyFromParent,
362
CWOverrideRedirect | CWEventMask, &attr);
364
d->button_states[i] = 0;
368
gdk_display_sync (gdk_display_get_default ());
369
if (!gdk_error_trap_pop ())
371
if (get_mwm_prop (xid) & (MWM_DECOR_ALL | MWM_DECOR_TITLE))
374
for (i = 0; i < 3; i++)
375
for (j = 0; j < 3; j++)
377
Window win = d->event_windows[i][j].window;
378
g_hash_table_insert (frame_table,
379
GINT_TO_POINTER (win),
380
GINT_TO_POINTER (xid));
383
for (i = 0; i < BUTTON_NUM; i++)
384
g_hash_table_insert (frame_table,
385
GINT_TO_POINTER (d->button_windows[i].window),
386
GINT_TO_POINTER (xid));
390
g_hash_table_insert (frame_table,
391
GINT_TO_POINTER (frame),
392
GINT_TO_POINTER (xid));
394
update_window_decoration_state (win);
395
update_window_decoration_actions (win);
396
update_window_decoration_icon (win);
397
update_window_decoration_size (win);
399
update_event_windows (win);
403
for (i = 0; i < 3; i++)
404
for (j = 0; j < 3; j++)
405
d->event_windows[i][j].window = None;
412
remove_frame_window (WnckWindow *win)
414
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
417
xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
421
g_object_unref (G_OBJECT (d->pixmap));
425
if (d->buffer_pixmap)
427
g_object_unref (G_OBJECT (d->buffer_pixmap));
428
d->buffer_pixmap = NULL;
433
cairo_destroy (d->cr);
437
if (d->picture && !d->frame_window)
439
XRenderFreePicture (xdisplay, d->picture);
451
g_object_unref (G_OBJECT (d->layout));
457
cairo_pattern_destroy (d->icon);
463
g_object_unref (G_OBJECT (d->icon_pixmap));
464
d->icon_pixmap = NULL;
469
g_object_unref (G_OBJECT (d->icon_pixbuf));
470
d->icon_pixbuf = NULL;
473
if (d->force_quit_dialog)
475
GtkWidget *dialog = d->force_quit_dialog;
477
d->force_quit_dialog = NULL;
478
gtk_widget_destroy (dialog);
483
gdk_window_destroy (d->frame_window);
484
d->frame_window = NULL;
489
g_object_unref (d->decor_image);
490
d->decor_image = NULL;
493
if (d->decor_event_box)
495
g_object_unref (d->decor_event_box);
496
d->decor_event_box = NULL;
501
g_object_unref (d->decor_window);
502
d->decor_window = NULL;
507
gwd_decor_frame_unref (d->frame);
511
gdk_error_trap_push ();
512
XDeleteProperty (xdisplay, wnck_window_get_xid (win), win_decor_atom);
513
gdk_display_sync (gdk_display_get_default ());
514
gdk_error_trap_pop ();
519
d->decorated = FALSE;
527
draw_list = g_slist_remove (draw_list, d);
531
connect_window (WnckWindow *win)
533
g_signal_connect_object (win, "name_changed",
534
G_CALLBACK (window_name_changed),
536
g_signal_connect_object (win, "geometry_changed",
537
G_CALLBACK (window_geometry_changed),
539
g_signal_connect_object (win, "icon_changed",
540
G_CALLBACK (window_icon_changed),
542
g_signal_connect_object (win, "state_changed",
543
G_CALLBACK (window_state_changed),
545
g_signal_connect_object (win, "actions_changed",
546
G_CALLBACK (window_actions_changed),
551
active_window_changed (WnckScreen *screen)
556
win = wnck_screen_get_previously_active_window (screen);
559
d = g_object_get_data (G_OBJECT (win), "decor");
562
d->active = wnck_window_is_active (win);
563
queue_decor_draw (d);
567
win = wnck_screen_get_active_window (screen);
570
d = g_object_get_data (G_OBJECT (win), "decor");
573
d->active = wnck_window_is_active (win);
574
queue_decor_draw (d);
580
window_opened (WnckScreen *screen,
588
g_return_if_fail (WNCK_IS_WINDOW (win));
590
static event_callback callback[3][3] = {
591
{ top_left_event, top_event, top_right_event },
592
{ left_event, title_event, right_event },
593
{ bottom_left_event, bottom_event, bottom_right_event }
595
static event_callback button_callback[BUTTON_NUM] = {
603
unshade_button_event,
604
unabove_button_event,
608
d = calloc (1, sizeof (decor_t));
612
for (i = 0; i < 3; i++)
613
for (j = 0; j < 3; j++)
614
d->event_windows[i][j].callback = callback[i][j];
616
for (i = 0; i < BUTTON_NUM; i++)
617
d->button_windows[i].callback = button_callback[i];
619
wnck_window_get_client_window_geometry (win, NULL, NULL,
623
d->draw = theme_draw_window_decoration;
628
d->buffer_pixmap = NULL;
631
connect_window (win);
633
g_object_set_data (G_OBJECT (win), "decor", d);
635
xid = wnck_window_get_xid (win);
637
if (get_window_prop (xid, frame_input_window_atom, &window))
639
add_frame_window (win, window, FALSE);
641
else if (get_window_prop (xid, frame_output_window_atom, &window))
643
add_frame_window (win, window, TRUE);
648
window_closed (WnckScreen *screen,
651
g_return_if_fail (WNCK_IS_WINDOW (win));
652
decor_t *d = g_object_get_data (G_OBJECT (win), "decor");
656
remove_frame_window (win);
657
g_object_set_data (G_OBJECT (win), "decor", NULL);
663
connect_screen (WnckScreen *screen)
667
g_signal_connect_object (G_OBJECT (screen), "active_window_changed",
668
G_CALLBACK (active_window_changed),
670
g_signal_connect_object (G_OBJECT (screen), "window_opened",
671
G_CALLBACK (window_opened),
673
g_signal_connect_object (G_OBJECT (screen), "window_closed",
674
G_CALLBACK (window_closed),
677
windows = wnck_screen_get_windows (screen);
678
while (windows != NULL)
680
window_opened (screen, windows->data);
681
windows = windows->next;