1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
3
/* Metacity window frame manager widget */
6
* Copyright (C) 2001 Havoc Pennington
7
* Copyright (C) 2003 Red Hat, Inc.
8
* Copyright (C) 2005, 2006 Elijah Newren
10
* This program is free software; you can redistribute it and/or
11
* modify it under the terms of the GNU General Public License as
12
* published by the Free Software Foundation; either version 2 of the
13
* License, or (at your option) any later version.
15
* This program is distributed in the hope that it will be useful, but
16
* WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18
* General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with this program; if not, write to the Free Software
22
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
39
#include <X11/extensions/shape.h>
42
#define DEFAULT_INNER_BUTTON_BORDER 3
44
static void meta_frames_class_init (MetaFramesClass *klass);
45
static void meta_frames_init (MetaFrames *frames);
46
static void meta_frames_destroy (GtkObject *object);
47
static void meta_frames_finalize (GObject *object);
48
static void meta_frames_style_set (GtkWidget *widget,
49
GtkStyle *prev_style);
50
static void meta_frames_realize (GtkWidget *widget);
51
static void meta_frames_unrealize (GtkWidget *widget);
53
static void meta_frames_update_prelit_control (MetaFrames *frames,
55
MetaFrameControl control);
56
static gboolean meta_frames_button_press_event (GtkWidget *widget,
57
GdkEventButton *event);
58
static gboolean meta_frames_button_release_event (GtkWidget *widget,
59
GdkEventButton *event);
60
static gboolean meta_frames_motion_notify_event (GtkWidget *widget,
61
GdkEventMotion *event);
62
static gboolean meta_frames_destroy_event (GtkWidget *widget,
64
static gboolean meta_frames_expose_event (GtkWidget *widget,
65
GdkEventExpose *event);
66
static gboolean meta_frames_enter_notify_event (GtkWidget *widget,
67
GdkEventCrossing *event);
68
static gboolean meta_frames_leave_notify_event (GtkWidget *widget,
69
GdkEventCrossing *event);
71
static void meta_frames_attach_style (MetaFrames *frames,
74
static void meta_frames_paint_to_drawable (MetaFrames *frames,
76
GdkDrawable *drawable,
81
static void meta_frames_set_window_background (MetaFrames *frames,
84
static void meta_frames_calc_geometry (MetaFrames *frames,
86
MetaFrameGeometry *fgeom);
88
static void meta_frames_ensure_layout (MetaFrames *frames,
91
static MetaUIFrame* meta_frames_lookup_window (MetaFrames *frames,
94
static void meta_frames_font_changed (MetaFrames *frames);
95
static void meta_frames_button_layout_changed (MetaFrames *frames);
98
static GdkRectangle* control_rect (MetaFrameControl control,
99
MetaFrameGeometry *fgeom);
100
static MetaFrameControl get_control (MetaFrames *frames,
104
static void clear_tip (MetaFrames *frames);
105
static void invalidate_all_caches (MetaFrames *frames);
106
static void invalidate_whole_window (MetaFrames *frames,
109
static GtkWidgetClass *parent_class = NULL;
112
meta_frames_get_type (void)
114
static GType frames_type = 0;
118
static const GtkTypeInfo frames_info =
122
sizeof (MetaFramesClass),
123
(GtkClassInitFunc) meta_frames_class_init,
124
(GtkObjectInitFunc) meta_frames_init,
125
/* reserved_1 */ NULL,
126
/* reserved_2 */ NULL,
127
(GtkClassInitFunc) NULL,
130
frames_type = gtk_type_unique (GTK_TYPE_WINDOW, &frames_info);
137
meta_frames_class_init (MetaFramesClass *class)
139
GObjectClass *gobject_class;
140
GtkObjectClass *object_class;
141
GtkWidgetClass *widget_class;
143
gobject_class = G_OBJECT_CLASS (class);
144
object_class = (GtkObjectClass*) class;
145
widget_class = (GtkWidgetClass*) class;
147
parent_class = g_type_class_peek_parent (class);
149
gobject_class->finalize = meta_frames_finalize;
150
object_class->destroy = meta_frames_destroy;
152
widget_class->style_set = meta_frames_style_set;
154
widget_class->realize = meta_frames_realize;
155
widget_class->unrealize = meta_frames_unrealize;
157
widget_class->expose_event = meta_frames_expose_event;
158
widget_class->destroy_event = meta_frames_destroy_event;
159
widget_class->button_press_event = meta_frames_button_press_event;
160
widget_class->button_release_event = meta_frames_button_release_event;
161
widget_class->motion_notify_event = meta_frames_motion_notify_event;
162
widget_class->enter_notify_event = meta_frames_enter_notify_event;
163
widget_class->leave_notify_event = meta_frames_leave_notify_event;
167
unsigned_long_equal (gconstpointer v1,
170
return *((const gulong*) v1) == *((const gulong*) v2);
174
unsigned_long_hash (gconstpointer v)
176
gulong val = * (const gulong *) v;
178
/* I'm not sure this works so well. */
179
#if GLIB_SIZEOF_LONG > 4
180
return (guint) (val ^ (val >> 32));
187
prefs_changed_callback (MetaPreference pref,
192
case META_PREF_TITLEBAR_FONT:
193
meta_frames_font_changed (META_FRAMES (data));
195
case META_PREF_BUTTON_LAYOUT:
196
meta_frames_button_layout_changed (META_FRAMES (data));
204
meta_frames_init (MetaFrames *frames)
206
GTK_WINDOW (frames)->type = GTK_WINDOW_POPUP;
208
frames->text_heights = g_hash_table_new (NULL, NULL);
210
frames->frames = g_hash_table_new (unsigned_long_hash, unsigned_long_equal);
212
frames->tooltip_timeout = 0;
214
frames->expose_delay_count = 0;
216
frames->invalidate_cache_timeout_id = 0;
217
frames->invalidate_frames = NULL;
218
frames->cache = g_hash_table_new (g_direct_hash, g_direct_equal);
220
gtk_widget_set_double_buffered (GTK_WIDGET (frames), FALSE);
222
meta_prefs_add_listener (prefs_changed_callback, frames);
226
listify_func (gpointer key, gpointer value, gpointer data)
231
*listp = g_slist_prepend (*listp, value);
235
meta_frames_destroy (GtkObject *object)
241
frames = META_FRAMES (object);
246
g_hash_table_foreach (frames->frames, listify_func, &winlist);
248
/* Unmanage all frames */
249
for (tmp = winlist; tmp != NULL; tmp = tmp->next)
255
meta_frames_unmanage_window (frames, frame->xwindow);
257
g_slist_free (winlist);
259
GTK_OBJECT_CLASS (parent_class)->destroy (object);
263
meta_frames_finalize (GObject *object)
267
frames = META_FRAMES (object);
269
meta_prefs_remove_listener (prefs_changed_callback, frames);
271
g_hash_table_destroy (frames->text_heights);
273
invalidate_all_caches (frames);
274
if (frames->invalidate_cache_timeout_id)
275
g_source_remove (frames->invalidate_cache_timeout_id);
277
g_assert (g_hash_table_size (frames->frames) == 0);
278
g_hash_table_destroy (frames->frames);
279
g_hash_table_destroy (frames->cache);
281
G_OBJECT_CLASS (parent_class)->finalize (object);
292
/* Caches of the four rendered sides in a MetaFrame.
293
* Order: top (titlebar), left, right, bottom.
295
CachedFramePiece piece[4];
298
static CachedPixels *
299
get_cache (MetaFrames *frames,
302
CachedPixels *pixels;
304
pixels = g_hash_table_lookup (frames->cache, frame);
308
pixels = g_new0 (CachedPixels, 1);
309
g_hash_table_insert (frames->cache, frame, pixels);
316
invalidate_cache (MetaFrames *frames,
319
CachedPixels *pixels = get_cache (frames, frame);
322
for (i = 0; i < 4; i++)
323
if (pixels->piece[i].pixmap)
324
g_object_unref (pixels->piece[i].pixmap);
327
g_hash_table_remove (frames->cache, frame);
331
invalidate_all_caches (MetaFrames *frames)
335
for (l = frames->invalidate_frames; l; l = l->next)
337
MetaUIFrame *frame = l->data;
339
invalidate_cache (frames, frame);
342
g_list_free (frames->invalidate_frames);
343
frames->invalidate_frames = NULL;
347
invalidate_cache_timeout (gpointer data)
349
MetaFrames *frames = data;
351
invalidate_all_caches (frames);
352
frames->invalidate_cache_timeout_id = 0;
357
queue_recalc_func (gpointer key, gpointer value, gpointer data)
362
frames = META_FRAMES (data);
365
/* If a resize occurs it will cause a redraw, but the
366
* resize may not actually be needed so we always redraw
367
* in case of color change.
369
meta_frames_set_window_background (frames, frame);
371
invalidate_whole_window (frames, frame);
372
meta_core_queue_frame_resize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
376
/* save title to recreate layout */
377
g_free (frame->title);
379
frame->title = g_strdup (pango_layout_get_text (frame->layout));
381
g_object_unref (G_OBJECT (frame->layout));
382
frame->layout = NULL;
387
meta_frames_font_changed (MetaFrames *frames)
389
if (g_hash_table_size (frames->text_heights) > 0)
391
g_hash_table_destroy (frames->text_heights);
392
frames->text_heights = g_hash_table_new (NULL, NULL);
395
/* Queue a draw/resize on all frames */
396
g_hash_table_foreach (frames->frames,
397
queue_recalc_func, frames);
402
queue_draw_func (gpointer key, gpointer value, gpointer data)
407
frames = META_FRAMES (data);
410
/* If a resize occurs it will cause a redraw, but the
411
* resize may not actually be needed so we always redraw
412
* in case of color change.
414
meta_frames_set_window_background (frames, frame);
416
invalidate_whole_window (frames, frame);
420
meta_frames_button_layout_changed (MetaFrames *frames)
422
g_hash_table_foreach (frames->frames,
423
queue_draw_func, frames);
427
reattach_style_func (gpointer key, gpointer value, gpointer data)
432
frames = META_FRAMES (data);
435
meta_frames_attach_style (frames, frame);
439
meta_frames_style_set (GtkWidget *widget,
440
GtkStyle *prev_style)
444
frames = META_FRAMES (widget);
446
meta_frames_font_changed (frames);
448
g_hash_table_foreach (frames->frames,
449
reattach_style_func, frames);
451
GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
455
meta_frames_ensure_layout (MetaFrames *frames,
459
MetaFrameFlags flags;
461
MetaFrameStyle *style;
463
g_return_if_fail (GTK_WIDGET_REALIZED (frames));
465
widget = GTK_WIDGET (frames);
467
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
468
META_CORE_GET_FRAME_FLAGS, &flags,
469
META_CORE_GET_FRAME_TYPE, &type,
472
style = meta_theme_get_frame_style (meta_theme_get_current (),
475
if (style != frame->cache_style)
479
/* save title to recreate layout */
480
g_free (frame->title);
482
frame->title = g_strdup (pango_layout_get_text (frame->layout));
484
g_object_unref (G_OBJECT (frame->layout));
485
frame->layout = NULL;
489
frame->cache_style = style;
491
if (frame->layout == NULL)
494
PangoFontDescription *font_desc;
498
scale = meta_theme_get_title_scale (meta_theme_get_current (),
502
frame->layout = gtk_widget_create_pango_layout (widget, frame->title);
504
pango_layout_set_auto_dir (frame->layout, FALSE);
506
font_desc = meta_gtk_widget_get_font_desc (widget, scale,
507
meta_prefs_get_titlebar_font ());
509
size = pango_font_description_get_size (font_desc);
511
if (g_hash_table_lookup_extended (frames->text_heights,
512
GINT_TO_POINTER (size),
515
frame->text_height = GPOINTER_TO_INT (value);
520
meta_pango_font_desc_get_text_height (font_desc,
521
gtk_widget_get_pango_context (widget));
523
g_hash_table_replace (frames->text_heights,
524
GINT_TO_POINTER (size),
525
GINT_TO_POINTER (frame->text_height));
528
pango_layout_set_font_description (frame->layout,
531
pango_font_description_free (font_desc);
534
g_free (frame->title);
540
meta_frames_calc_geometry (MetaFrames *frames,
542
MetaFrameGeometry *fgeom)
545
MetaFrameFlags flags;
547
MetaButtonLayout button_layout;
549
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
550
META_CORE_GET_CLIENT_WIDTH, &width,
551
META_CORE_GET_CLIENT_HEIGHT, &height,
552
META_CORE_GET_FRAME_FLAGS, &flags,
553
META_CORE_GET_FRAME_TYPE, &type,
556
meta_frames_ensure_layout (frames, frame);
558
meta_prefs_get_button_layout (&button_layout);
560
meta_theme_calc_geometry (meta_theme_get_current (),
570
meta_frames_new (int screen_number)
574
screen = gdk_display_get_screen (gdk_display_get_default (),
577
return g_object_new (META_TYPE_FRAMES,
582
/* In order to use a style with a window it has to be attached to that
583
* window. Actually, the colormaps just have to match, but since GTK+
584
* already takes care of making sure that its cheap to attach a style
585
* to multiple windows with the same colormap, we can just go ahead
586
* and attach separately for each window.
589
meta_frames_attach_style (MetaFrames *frames,
592
if (frame->style != NULL)
593
gtk_style_detach (frame->style);
595
/* Weirdly, gtk_style_attach() steals a reference count from the style passed in */
596
g_object_ref (GTK_WIDGET (frames)->style);
597
frame->style = gtk_style_attach (GTK_WIDGET (frames)->style, frame->window);
601
meta_frames_manage_window (MetaFrames *frames,
609
frame = g_new (MetaUIFrame, 1);
611
frame->window = window;
613
gdk_window_set_user_data (frame->window, frames);
616
meta_frames_attach_style (frames, frame);
618
/* Don't set event mask here, it's in frame.c */
620
frame->xwindow = xwindow;
621
frame->cache_style = NULL;
622
frame->layout = NULL;
623
frame->text_height = -1;
625
frame->expose_delayed = FALSE;
626
frame->shape_applied = FALSE;
627
frame->prelit_control = META_FRAME_CONTROL_NONE;
629
/* Don't set the window background yet; we need frame->xwindow to be
630
* registered with its MetaWindow, which happens after this function
631
* and meta_ui_create_frame_window() return to meta_window_ensure_frame().
634
meta_core_grab_buttons (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
636
g_hash_table_replace (frames->frames, &frame->xwindow, frame);
640
meta_frames_unmanage_window (MetaFrames *frames,
647
frame = g_hash_table_lookup (frames->frames, &xwindow);
651
/* invalidating all caches ensures the frame
652
* is not actually referenced anymore
654
invalidate_all_caches (frames);
656
/* restore the cursor */
657
meta_core_set_screen_cursor (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
659
META_CURSOR_DEFAULT);
661
gdk_window_set_user_data (frame->window, NULL);
663
if (frames->last_motion_frame == frame)
664
frames->last_motion_frame = NULL;
666
g_hash_table_remove (frames->frames, &frame->xwindow);
668
gtk_style_detach (frame->style);
670
gdk_window_destroy (frame->window);
673
g_object_unref (G_OBJECT (frame->layout));
676
g_free (frame->title);
681
meta_warning ("Frame 0x%lx not managed, can't unmanage\n", xwindow);
685
meta_frames_realize (GtkWidget *widget)
687
if (GTK_WIDGET_CLASS (parent_class)->realize)
688
GTK_WIDGET_CLASS (parent_class)->realize (widget);
692
meta_frames_unrealize (GtkWidget *widget)
694
if (GTK_WIDGET_CLASS (parent_class)->unrealize)
695
GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
699
meta_frames_lookup_window (MetaFrames *frames,
704
frame = g_hash_table_lookup (frames->frames, &xwindow);
710
meta_frames_get_geometry (MetaFrames *frames,
712
int *top_height, int *bottom_height,
713
int *left_width, int *right_width)
715
MetaFrameFlags flags;
719
frame = meta_frames_lookup_window (frames, xwindow);
722
meta_bug ("No such frame 0x%lx\n", xwindow);
724
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
725
META_CORE_GET_FRAME_FLAGS, &flags,
726
META_CORE_GET_FRAME_TYPE, &type,
729
g_return_if_fail (type < META_FRAME_TYPE_LAST);
731
meta_frames_ensure_layout (frames, frame);
733
/* We can't get the full geometry, because that depends on
734
* the client window size and probably we're being called
735
* by the core move/resize code to decide on the client
738
meta_theme_get_frame_borders (meta_theme_get_current (),
742
top_height, bottom_height,
743
left_width, right_width);
747
meta_frames_reset_bg (MetaFrames *frames,
752
frame = meta_frames_lookup_window (frames, xwindow);
754
meta_frames_set_window_background (frames, frame);
758
set_background_none (Display *xdisplay,
761
XSetWindowAttributes attrs;
763
attrs.background_pixmap = None;
764
XChangeWindowAttributes (xdisplay, xwindow,
765
CWBackPixmap, &attrs);
769
meta_frames_unflicker_bg (MetaFrames *frames,
776
frame = meta_frames_lookup_window (frames, xwindow);
777
g_return_if_fail (frame != NULL);
780
pixmap = gdk_pixmap_new (frame->window,
784
/* Oops, no way to get the background here */
786
meta_frames_paint_to_drawable (frames, frame, pixmap);
789
set_background_none (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
793
meta_frames_apply_shapes (MetaFrames *frames,
795
int new_window_width,
796
int new_window_height,
797
gboolean window_has_shape)
800
/* Apply shapes as if window had new_window_width, new_window_height */
802
MetaFrameGeometry fgeom;
804
Region corners_xregion;
805
Region window_xregion;
807
frame = meta_frames_lookup_window (frames, xwindow);
808
g_return_if_fail (frame != NULL);
810
meta_frames_calc_geometry (frames, frame, &fgeom);
812
if (!(fgeom.top_left_corner_rounded_radius != 0 ||
813
fgeom.top_right_corner_rounded_radius != 0 ||
814
fgeom.bottom_left_corner_rounded_radius != 0 ||
815
fgeom.bottom_right_corner_rounded_radius != 0 ||
818
if (frame->shape_applied)
820
meta_topic (META_DEBUG_SHAPES,
821
"Unsetting shape mask on frame 0x%lx\n",
824
XShapeCombineMask (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
825
ShapeBounding, 0, 0, None, ShapeSet);
826
frame->shape_applied = FALSE;
830
meta_topic (META_DEBUG_SHAPES,
831
"Frame 0x%lx still doesn't need a shape mask\n",
835
return; /* nothing to do */
838
corners_xregion = XCreateRegion ();
840
if (fgeom.top_left_corner_rounded_radius != 0)
842
const int corner = fgeom.top_left_corner_rounded_radius;
843
const float radius = sqrt(corner) + corner;
846
for (i=0; i<corner; i++)
848
const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
854
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
858
if (fgeom.top_right_corner_rounded_radius != 0)
860
const int corner = fgeom.top_right_corner_rounded_radius;
861
const float radius = sqrt(corner) + corner;
864
for (i=0; i<corner; i++)
866
const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
867
xrect.x = new_window_width - width;
872
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
876
if (fgeom.bottom_left_corner_rounded_radius != 0)
878
const int corner = fgeom.bottom_left_corner_rounded_radius;
879
const float radius = sqrt(corner) + corner;
882
for (i=0; i<corner; i++)
884
const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
886
xrect.y = new_window_height - i - 1;
890
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
894
if (fgeom.bottom_right_corner_rounded_radius != 0)
896
const int corner = fgeom.bottom_right_corner_rounded_radius;
897
const float radius = sqrt(corner) + corner;
900
for (i=0; i<corner; i++)
902
const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
903
xrect.x = new_window_width - width;
904
xrect.y = new_window_height - i - 1;
908
XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
912
window_xregion = XCreateRegion ();
916
xrect.width = new_window_width;
917
xrect.height = new_window_height;
919
XUnionRectWithRegion (&xrect, window_xregion, window_xregion);
921
XSubtractRegion (window_xregion, corners_xregion, window_xregion);
923
XDestroyRegion (corners_xregion);
925
if (window_has_shape)
927
/* The client window is oclock or something and has a shape
928
* mask. To avoid a round trip to get its shape region, we
929
* create a fake window that's never mapped, build up our shape
930
* on that, then combine. Wasting the window is assumed cheaper
931
* than a round trip, but who really knows for sure.
933
XSetWindowAttributes attrs;
935
Window client_window;
936
Region client_xregion;
940
meta_topic (META_DEBUG_SHAPES,
941
"Frame 0x%lx needs to incorporate client shape\n",
944
screen = gtk_widget_get_screen (GTK_WIDGET (frames));
945
screen_number = gdk_x11_screen_get_screen_number (screen);
947
attrs.override_redirect = True;
949
shape_window = XCreateWindow (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
950
RootWindow (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), screen_number),
957
(Visual *)CopyFromParent,
961
/* Copy the client's shape to the temporary shape_window */
962
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
963
META_CORE_GET_CLIENT_XWINDOW, &client_window,
966
XShapeCombineShape (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), shape_window, ShapeBounding,
973
/* Punch the client area out of the normal frame shape,
974
* then union it with the shape_window's existing shape
976
client_xregion = XCreateRegion ();
978
xrect.x = fgeom.left_width;
979
xrect.y = fgeom.top_height;
980
xrect.width = new_window_width - fgeom.right_width - xrect.x;
981
xrect.height = new_window_height - fgeom.bottom_height - xrect.y;
983
XUnionRectWithRegion (&xrect, client_xregion, client_xregion);
985
XSubtractRegion (window_xregion, client_xregion, window_xregion);
987
XDestroyRegion (client_xregion);
989
XShapeCombineRegion (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), shape_window,
990
ShapeBounding, 0, 0, window_xregion, ShapeUnion);
992
/* Now copy shape_window shape to the real frame */
993
XShapeCombineShape (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, ShapeBounding,
999
XDestroyWindow (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), shape_window);
1003
/* No shape on the client, so just do simple stuff */
1005
meta_topic (META_DEBUG_SHAPES,
1006
"Frame 0x%lx has shaped corners\n",
1009
XShapeCombineRegion (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
1010
ShapeBounding, 0, 0, window_xregion, ShapeSet);
1013
frame->shape_applied = TRUE;
1015
XDestroyRegion (window_xregion);
1016
#endif /* HAVE_SHAPE */
1020
meta_frames_move_resize_frame (MetaFrames *frames,
1027
MetaUIFrame *frame = meta_frames_lookup_window (frames, xwindow);
1028
int old_x, old_y, old_width, old_height;
1030
gdk_drawable_get_size (frame->window, &old_width, &old_height);
1031
gdk_window_get_position (frame->window, &old_x, &old_y);
1033
gdk_window_move_resize (frame->window, x, y, width, height);
1035
if (old_width != width || old_height != height)
1036
invalidate_whole_window (frames, frame);
1040
meta_frames_queue_draw (MetaFrames *frames,
1045
frame = meta_frames_lookup_window (frames, xwindow);
1047
invalidate_whole_window (frames, frame);
1051
meta_frames_set_title (MetaFrames *frames,
1057
frame = meta_frames_lookup_window (frames, xwindow);
1061
g_free (frame->title);
1062
frame->title = g_strdup (title);
1066
g_object_unref (frame->layout);
1067
frame->layout = NULL;
1070
invalidate_whole_window (frames, frame);
1074
meta_frames_repaint_frame (MetaFrames *frames,
1079
frame = meta_frames_lookup_window (frames, xwindow);
1083
/* repaint everything, so the other frame don't
1084
* lag behind if they are exposed
1086
gdk_window_process_all_updates ();
1090
show_tip_now (MetaFrames *frames)
1092
const char *tiptext;
1094
int x, y, root_x, root_y;
1097
MetaFrameControl control;
1099
frame = frames->last_motion_frame;
1103
if (meta_prefs_get_hide_decorator_tooltip ())
1106
XQueryPointer (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
1113
control = get_control (frames, frame, x, y);
1118
case META_FRAME_CONTROL_TITLE:
1120
case META_FRAME_CONTROL_DELETE:
1121
tiptext = _("Close Window");
1123
case META_FRAME_CONTROL_MENU:
1124
tiptext = _("Window Menu");
1126
case META_FRAME_CONTROL_MINIMIZE:
1127
tiptext = _("Minimize Window");
1129
case META_FRAME_CONTROL_MAXIMIZE:
1130
tiptext = _("Maximize Window");
1132
case META_FRAME_CONTROL_UNMAXIMIZE:
1133
tiptext = _("Restore Window");
1135
case META_FRAME_CONTROL_SHADE:
1136
tiptext = _("Roll Up Window");
1138
case META_FRAME_CONTROL_UNSHADE:
1139
tiptext = _("Unroll Window");
1141
case META_FRAME_CONTROL_ABOVE:
1142
tiptext = _("Keep Window On Top");
1144
case META_FRAME_CONTROL_UNABOVE:
1145
tiptext = _("Remove Window From Top");
1147
case META_FRAME_CONTROL_STICK:
1148
tiptext = _("Always On Visible Workspace");
1150
case META_FRAME_CONTROL_UNSTICK:
1151
tiptext = _("Put Window On Only One Workspace");
1153
case META_FRAME_CONTROL_RESIZE_SE:
1155
case META_FRAME_CONTROL_RESIZE_S:
1157
case META_FRAME_CONTROL_RESIZE_SW:
1159
case META_FRAME_CONTROL_RESIZE_N:
1161
case META_FRAME_CONTROL_RESIZE_NE:
1163
case META_FRAME_CONTROL_RESIZE_NW:
1165
case META_FRAME_CONTROL_RESIZE_W:
1167
case META_FRAME_CONTROL_RESIZE_E:
1169
case META_FRAME_CONTROL_NONE:
1171
case META_FRAME_CONTROL_CLIENT_AREA:
1177
MetaFrameGeometry fgeom;
1182
meta_frames_calc_geometry (frames, frame, &fgeom);
1184
rect = control_rect (control, &fgeom);
1186
/* get conversion delta for root-to-frame coords */
1190
/* Align the tooltip to the button right end if RTL */
1191
if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
1194
screen_number = gdk_screen_get_number (gtk_widget_get_screen (GTK_WIDGET (frames)));
1196
meta_fixed_tip_show (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
1199
rect->y + rect->height + 2 + dy,
1205
tip_timeout_func (gpointer data)
1211
show_tip_now (frames);
1216
#define TIP_DELAY 450
1218
queue_tip (MetaFrames *frames)
1222
frames->tooltip_timeout = g_timeout_add (TIP_DELAY,
1228
clear_tip (MetaFrames *frames)
1230
if (frames->tooltip_timeout)
1232
g_source_remove (frames->tooltip_timeout);
1233
frames->tooltip_timeout = 0;
1235
meta_fixed_tip_hide ();
1239
redraw_control (MetaFrames *frames,
1241
MetaFrameControl control)
1243
MetaFrameGeometry fgeom;
1246
meta_frames_calc_geometry (frames, frame, &fgeom);
1248
rect = control_rect (control, &fgeom);
1250
gdk_window_invalidate_rect (frame->window, rect, FALSE);
1251
invalidate_cache (frames, frame);
1255
meta_frame_titlebar_event (MetaUIFrame *frame,
1256
GdkEventButton *event,
1259
MetaFrameFlags flags;
1263
case META_ACTION_TITLEBAR_TOGGLE_SHADE:
1265
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
1266
META_CORE_GET_FRAME_FLAGS, &flags,
1269
if (flags & META_FRAME_ALLOWS_SHADE)
1271
if (flags & META_FRAME_SHADED)
1272
meta_core_unshade (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
1276
meta_core_shade (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
1283
case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE:
1285
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
1286
META_CORE_GET_FRAME_FLAGS, &flags,
1289
if (flags & META_FRAME_ALLOWS_MAXIMIZE)
1291
meta_core_toggle_maximize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
1296
case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_HORIZONTALLY:
1298
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
1299
META_CORE_GET_FRAME_FLAGS, &flags,
1302
if (flags & META_FRAME_ALLOWS_MAXIMIZE)
1304
meta_core_toggle_maximize_horizontally (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
1309
case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_VERTICALLY:
1311
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
1312
META_CORE_GET_FRAME_FLAGS, &flags,
1315
if (flags & META_FRAME_ALLOWS_MAXIMIZE)
1317
meta_core_toggle_maximize_vertically (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
1322
case META_ACTION_TITLEBAR_MINIMIZE:
1324
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
1325
META_CORE_GET_FRAME_FLAGS, &flags,
1328
if (flags & META_FRAME_ALLOWS_MINIMIZE)
1330
meta_core_minimize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
1335
case META_ACTION_TITLEBAR_NONE:
1336
/* Yaay, a sane user that doesn't use that other weird crap! */
1339
case META_ACTION_TITLEBAR_LOWER:
1340
meta_core_user_lower_and_unfocus (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
1345
case META_ACTION_TITLEBAR_MENU:
1346
meta_core_show_window_menu (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
1354
case META_ACTION_TITLEBAR_LAST:
1362
meta_frame_double_click_event (MetaUIFrame *frame,
1363
GdkEventButton *event)
1365
int action = meta_prefs_get_action_double_click_titlebar ();
1367
return meta_frame_titlebar_event (frame, event, action);
1371
meta_frame_middle_click_event (MetaUIFrame *frame,
1372
GdkEventButton *event)
1374
int action = meta_prefs_get_action_middle_click_titlebar();
1376
return meta_frame_titlebar_event (frame, event, action);
1380
meta_frame_right_click_event(MetaUIFrame *frame,
1381
GdkEventButton *event)
1383
int action = meta_prefs_get_action_right_click_titlebar();
1385
return meta_frame_titlebar_event (frame, event, action);
1389
meta_frames_button_press_event (GtkWidget *widget,
1390
GdkEventButton *event)
1394
MetaFrameControl control;
1396
frames = META_FRAMES (widget);
1398
/* Remember that the display may have already done something with this event.
1399
* If so there's probably a GrabOp in effect.
1402
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
1408
control = get_control (frames, frame, event->x, event->y);
1410
/* focus on click, even if click was on client area */
1411
if (event->button == 1 &&
1412
!(control == META_FRAME_CONTROL_MINIMIZE ||
1413
control == META_FRAME_CONTROL_DELETE ||
1414
control == META_FRAME_CONTROL_MAXIMIZE))
1416
meta_topic (META_DEBUG_FOCUS,
1417
"Focusing window with frame 0x%lx due to button 1 press\n",
1419
meta_core_user_focus (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
1424
/* don't do the rest of this if on client area */
1425
if (control == META_FRAME_CONTROL_CLIENT_AREA)
1426
return FALSE; /* not on the frame, just passed through from client */
1428
/* We want to shade even if we have a GrabOp, since we'll have a move grab
1429
* if we double click the titlebar.
1431
if (control == META_FRAME_CONTROL_TITLE &&
1432
event->button == 1 &&
1433
event->type == GDK_2BUTTON_PRESS)
1435
meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
1436
return meta_frame_double_click_event (frame, event);
1439
if (meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())) !=
1441
return FALSE; /* already up to something */
1443
if (event->button == 1 &&
1444
(control == META_FRAME_CONTROL_MAXIMIZE ||
1445
control == META_FRAME_CONTROL_UNMAXIMIZE ||
1446
control == META_FRAME_CONTROL_MINIMIZE ||
1447
control == META_FRAME_CONTROL_DELETE ||
1448
control == META_FRAME_CONTROL_SHADE ||
1449
control == META_FRAME_CONTROL_UNSHADE ||
1450
control == META_FRAME_CONTROL_ABOVE ||
1451
control == META_FRAME_CONTROL_UNABOVE ||
1452
control == META_FRAME_CONTROL_STICK ||
1453
control == META_FRAME_CONTROL_UNSTICK ||
1454
control == META_FRAME_CONTROL_MENU))
1456
MetaGrabOp op = META_GRAB_OP_NONE;
1460
case META_FRAME_CONTROL_MINIMIZE:
1461
op = META_GRAB_OP_CLICKING_MINIMIZE;
1463
case META_FRAME_CONTROL_MAXIMIZE:
1464
op = META_GRAB_OP_CLICKING_MAXIMIZE;
1466
case META_FRAME_CONTROL_UNMAXIMIZE:
1467
op = META_GRAB_OP_CLICKING_UNMAXIMIZE;
1469
case META_FRAME_CONTROL_DELETE:
1470
op = META_GRAB_OP_CLICKING_DELETE;
1472
case META_FRAME_CONTROL_MENU:
1473
op = META_GRAB_OP_CLICKING_MENU;
1475
case META_FRAME_CONTROL_SHADE:
1476
op = META_GRAB_OP_CLICKING_SHADE;
1478
case META_FRAME_CONTROL_UNSHADE:
1479
op = META_GRAB_OP_CLICKING_UNSHADE;
1481
case META_FRAME_CONTROL_ABOVE:
1482
op = META_GRAB_OP_CLICKING_ABOVE;
1484
case META_FRAME_CONTROL_UNABOVE:
1485
op = META_GRAB_OP_CLICKING_UNABOVE;
1487
case META_FRAME_CONTROL_STICK:
1488
op = META_GRAB_OP_CLICKING_STICK;
1490
case META_FRAME_CONTROL_UNSTICK:
1491
op = META_GRAB_OP_CLICKING_UNSTICK;
1494
g_assert_not_reached ();
1498
meta_core_begin_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
1509
frame->prelit_control = control;
1510
redraw_control (frames, frame, control);
1512
if (op == META_GRAB_OP_CLICKING_MENU)
1514
MetaFrameGeometry fgeom;
1518
meta_frames_calc_geometry (frames, frame, &fgeom);
1520
rect = control_rect (META_FRAME_CONTROL_MENU, &fgeom);
1522
/* get delta to convert to root coords */
1523
dx = event->x_root - event->x;
1524
dy = event->y_root - event->y;
1526
/* Align to the right end of the menu rectangle if RTL */
1527
if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
1530
meta_core_show_window_menu (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
1533
rect->y + rect->height + dy,
1538
else if (event->button == 1 &&
1539
(control == META_FRAME_CONTROL_RESIZE_SE ||
1540
control == META_FRAME_CONTROL_RESIZE_S ||
1541
control == META_FRAME_CONTROL_RESIZE_SW ||
1542
control == META_FRAME_CONTROL_RESIZE_NE ||
1543
control == META_FRAME_CONTROL_RESIZE_N ||
1544
control == META_FRAME_CONTROL_RESIZE_NW ||
1545
control == META_FRAME_CONTROL_RESIZE_E ||
1546
control == META_FRAME_CONTROL_RESIZE_W))
1549
gboolean titlebar_is_onscreen;
1551
op = META_GRAB_OP_NONE;
1555
case META_FRAME_CONTROL_RESIZE_SE:
1556
op = META_GRAB_OP_RESIZING_SE;
1558
case META_FRAME_CONTROL_RESIZE_S:
1559
op = META_GRAB_OP_RESIZING_S;
1561
case META_FRAME_CONTROL_RESIZE_SW:
1562
op = META_GRAB_OP_RESIZING_SW;
1564
case META_FRAME_CONTROL_RESIZE_NE:
1565
op = META_GRAB_OP_RESIZING_NE;
1567
case META_FRAME_CONTROL_RESIZE_N:
1568
op = META_GRAB_OP_RESIZING_N;
1570
case META_FRAME_CONTROL_RESIZE_NW:
1571
op = META_GRAB_OP_RESIZING_NW;
1573
case META_FRAME_CONTROL_RESIZE_E:
1574
op = META_GRAB_OP_RESIZING_E;
1576
case META_FRAME_CONTROL_RESIZE_W:
1577
op = META_GRAB_OP_RESIZING_W;
1580
g_assert_not_reached ();
1584
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
1585
META_CORE_IS_TITLEBAR_ONSCREEN, &titlebar_is_onscreen,
1588
if (!titlebar_is_onscreen)
1589
meta_core_show_window_menu (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
1596
meta_core_begin_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
1607
else if (control == META_FRAME_CONTROL_TITLE &&
1610
MetaFrameFlags flags;
1612
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
1613
META_CORE_GET_FRAME_FLAGS, &flags,
1616
if (flags & META_FRAME_ALLOWS_MOVE)
1618
meta_core_begin_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
1620
META_GRAB_OP_MOVING,
1630
else if (event->button == 2)
1632
return meta_frame_middle_click_event (frame, event);
1634
else if (event->button == 3)
1636
return meta_frame_right_click_event (frame, event);
1643
meta_frames_notify_menu_hide (MetaFrames *frames)
1645
if (meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())) ==
1646
META_GRAB_OP_CLICKING_MENU)
1650
grab_frame = meta_core_get_grab_frame (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
1652
if (grab_frame != None)
1656
frame = meta_frames_lookup_window (frames, grab_frame);
1660
redraw_control (frames, frame,
1661
META_FRAME_CONTROL_MENU);
1662
meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), CurrentTime);
1669
meta_frames_button_release_event (GtkWidget *widget,
1670
GdkEventButton *event)
1676
frames = META_FRAMES (widget);
1678
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
1684
op = meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
1686
if (op == META_GRAB_OP_NONE)
1689
/* We only handle the releases we handled the presses for (things
1690
* involving frame controls). Window ops that don't require a
1691
* frame are handled in the Xlib part of the code, display.c/window.c
1693
if (frame->xwindow == meta_core_get_grab_frame (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())) &&
1694
((int) event->button) == meta_core_get_grab_button (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ())))
1696
MetaFrameControl control;
1698
control = get_control (frames, frame, event->x, event->y);
1702
case META_GRAB_OP_CLICKING_MINIMIZE:
1703
if (control == META_FRAME_CONTROL_MINIMIZE)
1704
meta_core_minimize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
1706
meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
1709
case META_GRAB_OP_CLICKING_MAXIMIZE:
1710
if (control == META_FRAME_CONTROL_MAXIMIZE)
1712
/* Focus the window on the maximize */
1713
meta_core_user_focus (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
1716
meta_core_maximize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
1718
meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
1721
case META_GRAB_OP_CLICKING_UNMAXIMIZE:
1722
if (control == META_FRAME_CONTROL_UNMAXIMIZE)
1723
meta_core_unmaximize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
1725
meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
1728
case META_GRAB_OP_CLICKING_DELETE:
1729
if (control == META_FRAME_CONTROL_DELETE)
1730
meta_core_delete (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, event->time);
1732
meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
1735
case META_GRAB_OP_CLICKING_MENU:
1736
meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
1739
case META_GRAB_OP_CLICKING_SHADE:
1740
if (control == META_FRAME_CONTROL_SHADE)
1741
meta_core_shade (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, event->time);
1743
meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
1746
case META_GRAB_OP_CLICKING_UNSHADE:
1747
if (control == META_FRAME_CONTROL_UNSHADE)
1748
meta_core_unshade (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow, event->time);
1750
meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
1753
case META_GRAB_OP_CLICKING_ABOVE:
1754
if (control == META_FRAME_CONTROL_ABOVE)
1755
meta_core_make_above (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
1757
meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
1760
case META_GRAB_OP_CLICKING_UNABOVE:
1761
if (control == META_FRAME_CONTROL_UNABOVE)
1762
meta_core_unmake_above (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
1764
meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
1767
case META_GRAB_OP_CLICKING_STICK:
1768
if (control == META_FRAME_CONTROL_STICK)
1769
meta_core_stick (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
1771
meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
1774
case META_GRAB_OP_CLICKING_UNSTICK:
1775
if (control == META_FRAME_CONTROL_UNSTICK)
1776
meta_core_unstick (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow);
1778
meta_core_end_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), event->time);
1785
/* Update the prelit control regardless of what button the mouse
1786
* was released over; needed so that the new button can become
1787
* prelit so to let the user know that it can now be pressed.
1790
meta_frames_update_prelit_control (frames, frame, control);
1797
meta_frames_update_prelit_control (MetaFrames *frames,
1799
MetaFrameControl control)
1801
MetaFrameControl old_control;
1805
meta_verbose ("Updating prelit control from %u to %u\n",
1806
frame->prelit_control, control);
1808
cursor = META_CURSOR_DEFAULT;
1812
case META_FRAME_CONTROL_CLIENT_AREA:
1814
case META_FRAME_CONTROL_NONE:
1816
case META_FRAME_CONTROL_TITLE:
1818
case META_FRAME_CONTROL_DELETE:
1820
case META_FRAME_CONTROL_MENU:
1822
case META_FRAME_CONTROL_MINIMIZE:
1824
case META_FRAME_CONTROL_MAXIMIZE:
1826
case META_FRAME_CONTROL_UNMAXIMIZE:
1828
case META_FRAME_CONTROL_SHADE:
1830
case META_FRAME_CONTROL_UNSHADE:
1832
case META_FRAME_CONTROL_ABOVE:
1834
case META_FRAME_CONTROL_UNABOVE:
1836
case META_FRAME_CONTROL_STICK:
1838
case META_FRAME_CONTROL_UNSTICK:
1840
case META_FRAME_CONTROL_RESIZE_SE:
1841
cursor = META_CURSOR_SE_RESIZE;
1843
case META_FRAME_CONTROL_RESIZE_S:
1844
cursor = META_CURSOR_SOUTH_RESIZE;
1846
case META_FRAME_CONTROL_RESIZE_SW:
1847
cursor = META_CURSOR_SW_RESIZE;
1849
case META_FRAME_CONTROL_RESIZE_N:
1850
cursor = META_CURSOR_NORTH_RESIZE;
1852
case META_FRAME_CONTROL_RESIZE_NE:
1853
cursor = META_CURSOR_NE_RESIZE;
1855
case META_FRAME_CONTROL_RESIZE_NW:
1856
cursor = META_CURSOR_NW_RESIZE;
1858
case META_FRAME_CONTROL_RESIZE_W:
1859
cursor = META_CURSOR_WEST_RESIZE;
1861
case META_FRAME_CONTROL_RESIZE_E:
1862
cursor = META_CURSOR_EAST_RESIZE;
1866
/* set/unset the prelight cursor */
1867
meta_core_set_screen_cursor (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()),
1873
case META_FRAME_CONTROL_MENU:
1874
case META_FRAME_CONTROL_MINIMIZE:
1875
case META_FRAME_CONTROL_MAXIMIZE:
1876
case META_FRAME_CONTROL_DELETE:
1877
case META_FRAME_CONTROL_SHADE:
1878
case META_FRAME_CONTROL_UNSHADE:
1879
case META_FRAME_CONTROL_ABOVE:
1880
case META_FRAME_CONTROL_UNABOVE:
1881
case META_FRAME_CONTROL_STICK:
1882
case META_FRAME_CONTROL_UNSTICK:
1883
case META_FRAME_CONTROL_UNMAXIMIZE:
1884
/* leave control set */
1887
/* Only prelight buttons */
1888
control = META_FRAME_CONTROL_NONE;
1892
if (control == frame->prelit_control)
1895
/* Save the old control so we can unprelight it */
1896
old_control = frame->prelit_control;
1898
frame->prelit_control = control;
1900
redraw_control (frames, frame, old_control);
1901
redraw_control (frames, frame, control);
1905
meta_frames_motion_notify_event (GtkWidget *widget,
1906
GdkEventMotion *event)
1912
frames = META_FRAMES (widget);
1914
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
1920
frames->last_motion_frame = frame;
1922
grab_op = meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
1926
case META_GRAB_OP_CLICKING_MENU:
1927
case META_GRAB_OP_CLICKING_DELETE:
1928
case META_GRAB_OP_CLICKING_MINIMIZE:
1929
case META_GRAB_OP_CLICKING_MAXIMIZE:
1930
case META_GRAB_OP_CLICKING_UNMAXIMIZE:
1931
case META_GRAB_OP_CLICKING_SHADE:
1932
case META_GRAB_OP_CLICKING_UNSHADE:
1933
case META_GRAB_OP_CLICKING_ABOVE:
1934
case META_GRAB_OP_CLICKING_UNABOVE:
1935
case META_GRAB_OP_CLICKING_STICK:
1936
case META_GRAB_OP_CLICKING_UNSTICK:
1938
MetaFrameControl control;
1941
gdk_window_get_pointer (frame->window, &x, &y, NULL);
1943
/* Control is set to none unless it matches
1946
control = get_control (frames, frame, x, y);
1947
if (! ((control == META_FRAME_CONTROL_MENU &&
1948
grab_op == META_GRAB_OP_CLICKING_MENU) ||
1949
(control == META_FRAME_CONTROL_DELETE &&
1950
grab_op == META_GRAB_OP_CLICKING_DELETE) ||
1951
(control == META_FRAME_CONTROL_MINIMIZE &&
1952
grab_op == META_GRAB_OP_CLICKING_MINIMIZE) ||
1953
((control == META_FRAME_CONTROL_MAXIMIZE ||
1954
control == META_FRAME_CONTROL_UNMAXIMIZE) &&
1955
(grab_op == META_GRAB_OP_CLICKING_MAXIMIZE ||
1956
grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE)) ||
1957
(control == META_FRAME_CONTROL_SHADE &&
1958
grab_op == META_GRAB_OP_CLICKING_SHADE) ||
1959
(control == META_FRAME_CONTROL_UNSHADE &&
1960
grab_op == META_GRAB_OP_CLICKING_UNSHADE) ||
1961
(control == META_FRAME_CONTROL_ABOVE &&
1962
grab_op == META_GRAB_OP_CLICKING_ABOVE) ||
1963
(control == META_FRAME_CONTROL_UNABOVE &&
1964
grab_op == META_GRAB_OP_CLICKING_UNABOVE) ||
1965
(control == META_FRAME_CONTROL_STICK &&
1966
grab_op == META_GRAB_OP_CLICKING_STICK) ||
1967
(control == META_FRAME_CONTROL_UNSTICK &&
1968
grab_op == META_GRAB_OP_CLICKING_UNSTICK)))
1969
control = META_FRAME_CONTROL_NONE;
1971
/* Update prelit control and cursor */
1972
meta_frames_update_prelit_control (frames, frame, control);
1974
/* No tooltip while in the process of clicking */
1977
case META_GRAB_OP_NONE:
1979
MetaFrameControl control;
1982
gdk_window_get_pointer (frame->window, &x, &y, NULL);
1984
control = get_control (frames, frame, x, y);
1986
/* Update prelit control and cursor */
1987
meta_frames_update_prelit_control (frames, frame, control);
2001
meta_frames_destroy_event (GtkWidget *widget,
2007
frames = META_FRAMES (widget);
2009
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
2016
#if !GTK_CHECK_VERSION(2,21,6)
2017
/* Copied from GDK */
2018
static cairo_surface_t *
2019
_gdk_drawable_ref_cairo_surface (GdkDrawable *drawable)
2021
g_return_val_if_fail (GDK_IS_DRAWABLE (drawable), NULL);
2023
return GDK_DRAWABLE_GET_CLASS (drawable)->ref_cairo_surface (drawable);
2026
static cairo_pattern_t *
2027
gdk_window_get_background_pattern (GdkWindow *window)
2029
GdkWindowObject *private = (GdkWindowObject *) window;
2030
cairo_pattern_t *pattern;
2032
g_return_val_if_fail (GDK_IS_WINDOW (window), NULL);
2034
if (private->bg_pixmap == GDK_PARENT_RELATIVE_BG)
2036
else if (private->bg_pixmap != GDK_NO_BG &&
2037
private->bg_pixmap != NULL)
2039
static cairo_user_data_key_t key;
2040
cairo_surface_t *surface;
2042
surface = _gdk_drawable_ref_cairo_surface (private->bg_pixmap);
2043
pattern = cairo_pattern_create_for_surface (surface);
2044
cairo_surface_destroy (surface);
2046
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
2047
cairo_pattern_set_user_data (pattern,
2049
g_object_ref (private->bg_pixmap),
2055
cairo_pattern_create_rgb (private->bg_color.red / 65535.,
2056
private->bg_color.green / 65535.,
2057
private->bg_color.blue / 65535.);
2065
setup_bg_cr (cairo_t *cr, GdkWindow *window, int x_offset, int y_offset)
2067
GdkWindow *parent = gdk_window_get_parent (window);
2068
cairo_pattern_t *bg_pattern;
2070
bg_pattern = gdk_window_get_background_pattern (window);
2071
if (bg_pattern == NULL && parent)
2073
gint window_x, window_y;
2075
gdk_window_get_position (window, &window_x, &window_y);
2076
setup_bg_cr (cr, parent, x_offset + window_x, y_offset + window_y);
2078
else if (bg_pattern)
2080
cairo_translate (cr, - x_offset, - y_offset);
2081
cairo_set_source (cr, bg_pattern);
2082
cairo_translate (cr, x_offset, y_offset);
2087
clear_backing (GdkPixmap *pixmap,
2089
int xoffset, int yoffset)
2092
cairo_t *cr = gdk_cairo_create (pixmap);
2094
setup_bg_cr (cr, window, xoffset, yoffset);
2096
gdk_drawable_get_size (GDK_DRAWABLE (pixmap), &width, &height);
2097
cairo_rectangle (cr, 0, 0, width, height);
2103
/* Returns a pixmap with a piece of the windows frame painted on it.
2107
generate_pixmap (MetaFrames *frames,
2111
GdkRectangle rectangle;
2115
rectangle.x = rect.x;
2116
rectangle.y = rect.y;
2117
rectangle.width = MAX (rect.width, 1);
2118
rectangle.height = MAX (rect.height, 1);
2120
result = gdk_pixmap_new (frame->window,
2121
rectangle.width, rectangle.height, -1);
2123
clear_backing (result, frame->window, rectangle.x, rectangle.y);
2125
region = gdk_region_rectangle (&rectangle);
2127
meta_frames_paint_to_drawable (frames, frame, result, region,
2128
-rectangle.x, -rectangle.y);
2130
gdk_region_destroy (region);
2137
populate_cache (MetaFrames *frames,
2140
int top, bottom, left, right;
2142
int frame_width, frame_height, screen_width, screen_height;
2143
CachedPixels *pixels;
2144
MetaFrameType frame_type;
2145
MetaFrameFlags frame_flags;
2148
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
2149
META_CORE_GET_FRAME_WIDTH, &frame_width,
2150
META_CORE_GET_FRAME_HEIGHT, &frame_height,
2151
META_CORE_GET_SCREEN_WIDTH, &screen_width,
2152
META_CORE_GET_SCREEN_HEIGHT, &screen_height,
2153
META_CORE_GET_CLIENT_WIDTH, &width,
2154
META_CORE_GET_CLIENT_HEIGHT, &height,
2155
META_CORE_GET_FRAME_TYPE, &frame_type,
2156
META_CORE_GET_FRAME_FLAGS, &frame_flags,
2159
/* don't cache extremely large windows */
2160
if (frame_width > 2 * screen_width ||
2161
frame_height > 2 * screen_height)
2166
meta_theme_get_frame_borders (meta_theme_get_current (),
2170
&top, &bottom, &left, &right);
2172
pixels = get_cache (frames, frame);
2174
/* Setup the rectangles for the four frame borders. First top, then
2175
left, right and bottom. */
2176
pixels->piece[0].rect.x = 0;
2177
pixels->piece[0].rect.y = 0;
2178
pixels->piece[0].rect.width = left + width + right;
2179
pixels->piece[0].rect.height = top;
2181
pixels->piece[1].rect.x = 0;
2182
pixels->piece[1].rect.y = top;
2183
pixels->piece[1].rect.width = left;
2184
pixels->piece[1].rect.height = height;
2186
pixels->piece[2].rect.x = left + width;
2187
pixels->piece[2].rect.y = top;
2188
pixels->piece[2].rect.width = right;
2189
pixels->piece[2].rect.height = height;
2191
pixels->piece[3].rect.x = 0;
2192
pixels->piece[3].rect.y = top + height;
2193
pixels->piece[3].rect.width = left + width + right;
2194
pixels->piece[3].rect.height = bottom;
2196
for (i = 0; i < 4; i++)
2198
CachedFramePiece *piece = &pixels->piece[i];
2200
piece->pixmap = generate_pixmap (frames, frame, piece->rect);
2203
if (frames->invalidate_cache_timeout_id)
2204
g_source_remove (frames->invalidate_cache_timeout_id);
2206
frames->invalidate_cache_timeout_id = g_timeout_add (1000, invalidate_cache_timeout, frames);
2208
if (!g_list_find (frames->invalidate_frames, frame))
2209
frames->invalidate_frames =
2210
g_list_prepend (frames->invalidate_frames, frame);
2214
clip_to_screen (GdkRegion *region, MetaUIFrame *frame)
2216
GdkRectangle frame_area;
2217
GdkRectangle screen_area = { 0, 0, 0, 0 };
2218
GdkRegion *tmp_region;
2220
/* Chop off stuff outside the screen; this optimization
2221
* is crucial to handle huge client windows,
2222
* like "xterm -geometry 1000x1000"
2224
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
2225
META_CORE_GET_FRAME_X, &frame_area.x,
2226
META_CORE_GET_FRAME_Y, &frame_area.y,
2227
META_CORE_GET_FRAME_WIDTH, &frame_area.width,
2228
META_CORE_GET_FRAME_HEIGHT, &frame_area.height,
2229
META_CORE_GET_SCREEN_WIDTH, &screen_area.height,
2230
META_CORE_GET_SCREEN_HEIGHT, &screen_area.height,
2233
gdk_region_offset (region, frame_area.x, frame_area.y);
2235
tmp_region = gdk_region_rectangle (&frame_area);
2236
gdk_region_intersect (region, tmp_region);
2237
gdk_region_destroy (tmp_region);
2239
gdk_region_offset (region, - frame_area.x, - frame_area.y);
2243
subtract_from_region (GdkRegion *region, GdkDrawable *drawable,
2247
GdkRegion *reg_rect;
2249
gdk_drawable_get_size (drawable, &rect.width, &rect.height);
2253
reg_rect = gdk_region_rectangle (&rect);
2254
gdk_region_subtract (region, reg_rect);
2255
gdk_region_destroy (reg_rect);
2259
cached_pixels_draw (CachedPixels *pixels,
2266
cr = gdk_cairo_create (window);
2268
for (i = 0; i < 4; i++)
2270
CachedFramePiece *piece;
2271
piece = &pixels->piece[i];
2275
gdk_cairo_set_source_pixmap (cr, piece->pixmap,
2276
piece->rect.x, piece->rect.y);
2278
subtract_from_region (region, piece->pixmap,
2279
piece->rect.x, piece->rect.y);
2287
meta_frames_expose_event (GtkWidget *widget,
2288
GdkEventExpose *event)
2293
CachedPixels *pixels;
2295
frames = META_FRAMES (widget);
2297
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
2301
if (frames->expose_delay_count > 0)
2303
/* Redraw this entire frame later */
2304
frame->expose_delayed = TRUE;
2308
populate_cache (frames, frame);
2310
region = gdk_region_copy (event->region);
2312
pixels = get_cache (frames, frame);
2314
cached_pixels_draw (pixels, frame->window, region);
2316
clip_to_screen (region, frame);
2317
meta_frames_paint_to_drawable (frames, frame, frame->window, region, 0, 0);
2319
gdk_region_destroy (region);
2324
/* How far off the screen edge the window decorations should
2325
* be drawn. Used only in meta_frames_paint_to_drawable, below.
2327
#define DECORATING_BORDER 100
2330
meta_frames_paint_to_drawable (MetaFrames *frames,
2332
GdkDrawable *drawable,
2338
MetaFrameFlags flags;
2340
GdkPixbuf *mini_icon;
2343
MetaButtonState button_states[META_BUTTON_TYPE_LAST];
2346
MetaButtonLayout button_layout;
2349
widget = GTK_WIDGET (frames);
2351
for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
2352
button_states[i] = META_BUTTON_STATE_NORMAL;
2354
grab_frame = meta_core_get_grab_frame (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
2355
grab_op = meta_core_get_grab_op (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
2356
if (grab_frame != frame->xwindow)
2357
grab_op = META_GRAB_OP_NONE;
2359
/* Set prelight state */
2360
switch (frame->prelit_control)
2362
case META_FRAME_CONTROL_MENU:
2363
if (grab_op == META_GRAB_OP_CLICKING_MENU)
2364
button_states[META_BUTTON_TYPE_MENU] = META_BUTTON_STATE_PRESSED;
2366
button_states[META_BUTTON_TYPE_MENU] = META_BUTTON_STATE_PRELIGHT;
2368
case META_FRAME_CONTROL_MINIMIZE:
2369
if (grab_op == META_GRAB_OP_CLICKING_MINIMIZE)
2370
button_states[META_BUTTON_TYPE_MINIMIZE] = META_BUTTON_STATE_PRESSED;
2372
button_states[META_BUTTON_TYPE_MINIMIZE] = META_BUTTON_STATE_PRELIGHT;
2374
case META_FRAME_CONTROL_MAXIMIZE:
2375
if (grab_op == META_GRAB_OP_CLICKING_MAXIMIZE)
2376
button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRESSED;
2378
button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT;
2380
case META_FRAME_CONTROL_UNMAXIMIZE:
2381
if (grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE)
2382
button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRESSED;
2384
button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT;
2386
case META_FRAME_CONTROL_SHADE:
2387
if (grab_op == META_GRAB_OP_CLICKING_SHADE)
2388
button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRESSED;
2390
button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRELIGHT;
2392
case META_FRAME_CONTROL_UNSHADE:
2393
if (grab_op == META_GRAB_OP_CLICKING_UNSHADE)
2394
button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRESSED;
2396
button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRELIGHT;
2398
case META_FRAME_CONTROL_ABOVE:
2399
if (grab_op == META_GRAB_OP_CLICKING_ABOVE)
2400
button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRESSED;
2402
button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRELIGHT;
2404
case META_FRAME_CONTROL_UNABOVE:
2405
if (grab_op == META_GRAB_OP_CLICKING_UNABOVE)
2406
button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRESSED;
2408
button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRELIGHT;
2410
case META_FRAME_CONTROL_STICK:
2411
if (grab_op == META_GRAB_OP_CLICKING_STICK)
2412
button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRESSED;
2414
button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRELIGHT;
2416
case META_FRAME_CONTROL_UNSTICK:
2417
if (grab_op == META_GRAB_OP_CLICKING_UNSTICK)
2418
button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRESSED;
2420
button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRELIGHT;
2422
case META_FRAME_CONTROL_DELETE:
2423
if (grab_op == META_GRAB_OP_CLICKING_DELETE)
2424
button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRESSED;
2426
button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRELIGHT;
2432
/* Map button function states to button position states */
2433
button_states[META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND] =
2434
button_states[META_BUTTON_TYPE_MENU];
2435
button_states[META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND] =
2436
META_BUTTON_STATE_NORMAL;
2437
button_states[META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND] =
2438
META_BUTTON_STATE_NORMAL;
2439
button_states[META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND] =
2440
button_states[META_BUTTON_TYPE_MINIMIZE];
2441
button_states[META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND] =
2442
button_states[META_BUTTON_TYPE_MAXIMIZE];
2443
button_states[META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND] =
2444
button_states[META_BUTTON_TYPE_CLOSE];
2446
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
2447
META_CORE_GET_FRAME_FLAGS, &flags,
2448
META_CORE_GET_FRAME_TYPE, &type,
2449
META_CORE_GET_MINI_ICON, &mini_icon,
2450
META_CORE_GET_ICON, &icon,
2451
META_CORE_GET_CLIENT_WIDTH, &w,
2452
META_CORE_GET_CLIENT_HEIGHT, &h,
2455
meta_frames_ensure_layout (frames, frame);
2457
meta_prefs_get_button_layout (&button_layout);
2459
if (G_LIKELY (GDK_IS_WINDOW (drawable)))
2461
/* A window; happens about 2/3 of the time */
2463
GdkRectangle area, *areas;
2465
int screen_width, screen_height;
2466
GdkRegion *edges, *tmp_region;
2467
int top, bottom, left, right;
2469
/* Repaint each side of the frame */
2471
meta_theme_get_frame_borders (meta_theme_get_current (),
2472
type, frame->text_height, flags,
2473
&top, &bottom, &left, &right);
2475
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
2476
META_CORE_GET_SCREEN_WIDTH, &screen_width,
2477
META_CORE_GET_SCREEN_HEIGHT, &screen_height,
2480
edges = gdk_region_copy (region);
2482
/* Punch out the client area */
2488
tmp_region = gdk_region_rectangle (&area);
2489
gdk_region_subtract (edges, tmp_region);
2490
gdk_region_destroy (tmp_region);
2492
/* Now draw remaining portion of region */
2494
gdk_region_get_rectangles (edges, &areas, &n_areas);
2496
for (i = 0; i < n_areas; i++)
2498
/* Bug 399529: clamp areas[i] so that it doesn't go too far
2499
* off the edge of the screen. This works around a GDK bug
2500
* which makes gdk_window_begin_paint_rect cause an X error
2501
* if the window is insanely huge. If the client is a GDK program
2502
* and does this, it will still probably cause an X error in that
2503
* program, but the last thing we want is for Metacity to crash
2504
* because it attempted to decorate the silly window.
2507
areas[i].x = MAX (areas[i].x, -DECORATING_BORDER);
2508
areas[i].y = MAX (areas[i].y, -DECORATING_BORDER);
2509
if (areas[i].x+areas[i].width > screen_width + DECORATING_BORDER)
2510
areas[i].width = MIN (0, screen_width - areas[i].x);
2511
if (areas[i].y+areas[i].height > screen_height + DECORATING_BORDER)
2512
areas[i].height = MIN (0, screen_height - areas[i].y);
2514
/* Okay, so let's start painting. */
2516
gdk_window_begin_paint_rect (drawable, &areas[i]);
2518
meta_theme_draw_frame_with_style (meta_theme_get_current (),
2522
NULL, /* &areas[i], */
2533
gdk_window_end_paint (drawable);
2537
gdk_region_destroy (edges);
2542
/* Not a window; happens about 1/3 of the time */
2544
meta_theme_draw_frame_with_style (meta_theme_get_current (),
2563
meta_frames_set_window_background (MetaFrames *frames,
2566
MetaFrameFlags flags;
2568
MetaFrameStyle *style;
2569
gboolean frame_exists;
2571
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
2572
META_CORE_WINDOW_HAS_FRAME, &frame_exists,
2573
META_CORE_GET_FRAME_FLAGS, &flags,
2574
META_CORE_GET_FRAME_TYPE, &type,
2579
style = meta_theme_get_frame_style (meta_theme_get_current (),
2583
if (frame_exists && style->window_background_color != NULL)
2588
meta_color_spec_render (style->window_background_color,
2589
GTK_WIDGET (frames),
2592
/* Set A in ARGB to window_background_alpha, if we have ARGB */
2594
visual = gtk_widget_get_visual (GTK_WIDGET (frames));
2595
if (visual->depth == 32) /* we have ARGB */
2597
color.pixel = (color.pixel & 0xffffff) &
2598
style->window_background_alpha << 24;
2601
gdk_window_set_background (frame->window, &color);
2605
gtk_style_set_background (frame->style,
2606
frame->window, GTK_STATE_NORMAL);
2611
meta_frames_enter_notify_event (GtkWidget *widget,
2612
GdkEventCrossing *event)
2616
MetaFrameControl control;
2618
frames = META_FRAMES (widget);
2620
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
2624
control = get_control (frames, frame, event->x, event->y);
2625
meta_frames_update_prelit_control (frames, frame, control);
2631
meta_frames_leave_notify_event (GtkWidget *widget,
2632
GdkEventCrossing *event)
2637
frames = META_FRAMES (widget);
2639
frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
2643
meta_frames_update_prelit_control (frames, frame, META_FRAME_CONTROL_NONE);
2650
static GdkRectangle*
2651
control_rect (MetaFrameControl control,
2652
MetaFrameGeometry *fgeom)
2659
case META_FRAME_CONTROL_TITLE:
2660
rect = &fgeom->title_rect;
2662
case META_FRAME_CONTROL_DELETE:
2663
rect = &fgeom->close_rect.visible;
2665
case META_FRAME_CONTROL_MENU:
2666
rect = &fgeom->menu_rect.visible;
2668
case META_FRAME_CONTROL_MINIMIZE:
2669
rect = &fgeom->min_rect.visible;
2671
case META_FRAME_CONTROL_MAXIMIZE:
2672
case META_FRAME_CONTROL_UNMAXIMIZE:
2673
rect = &fgeom->max_rect.visible;
2675
case META_FRAME_CONTROL_SHADE:
2676
rect = &fgeom->shade_rect.visible;
2678
case META_FRAME_CONTROL_UNSHADE:
2679
rect = &fgeom->unshade_rect.visible;
2681
case META_FRAME_CONTROL_ABOVE:
2682
rect = &fgeom->above_rect.visible;
2684
case META_FRAME_CONTROL_UNABOVE:
2685
rect = &fgeom->unabove_rect.visible;
2687
case META_FRAME_CONTROL_STICK:
2688
rect = &fgeom->stick_rect.visible;
2690
case META_FRAME_CONTROL_UNSTICK:
2691
rect = &fgeom->unstick_rect.visible;
2693
case META_FRAME_CONTROL_RESIZE_SE:
2695
case META_FRAME_CONTROL_RESIZE_S:
2697
case META_FRAME_CONTROL_RESIZE_SW:
2699
case META_FRAME_CONTROL_RESIZE_N:
2701
case META_FRAME_CONTROL_RESIZE_NE:
2703
case META_FRAME_CONTROL_RESIZE_NW:
2705
case META_FRAME_CONTROL_RESIZE_W:
2707
case META_FRAME_CONTROL_RESIZE_E:
2709
case META_FRAME_CONTROL_NONE:
2711
case META_FRAME_CONTROL_CLIENT_AREA:
2718
#define RESIZE_EXTENDS 15
2719
#define TOP_RESIZE_HEIGHT 2
2720
static MetaFrameControl
2721
get_control (MetaFrames *frames,
2725
MetaFrameGeometry fgeom;
2726
MetaFrameFlags flags;
2727
gboolean has_vert, has_horiz;
2728
GdkRectangle client;
2730
meta_frames_calc_geometry (frames, frame, &fgeom);
2732
client.x = fgeom.left_width;
2733
client.y = fgeom.top_height;
2734
client.width = fgeom.width - fgeom.left_width - fgeom.right_width;
2735
client.height = fgeom.height - fgeom.top_height - fgeom.bottom_height;
2737
if (POINT_IN_RECT (x, y, client))
2738
return META_FRAME_CONTROL_CLIENT_AREA;
2740
if (POINT_IN_RECT (x, y, fgeom.close_rect.clickable))
2741
return META_FRAME_CONTROL_DELETE;
2743
if (POINT_IN_RECT (x, y, fgeom.min_rect.clickable))
2744
return META_FRAME_CONTROL_MINIMIZE;
2746
if (POINT_IN_RECT (x, y, fgeom.menu_rect.clickable))
2747
return META_FRAME_CONTROL_MENU;
2749
meta_core_get (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), frame->xwindow,
2750
META_CORE_GET_FRAME_FLAGS, &flags,
2753
has_vert = (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE) != 0;
2754
has_horiz = (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE) != 0;
2756
if (POINT_IN_RECT (x, y, fgeom.title_rect))
2758
if (has_vert && y <= TOP_RESIZE_HEIGHT)
2759
return META_FRAME_CONTROL_RESIZE_N;
2761
return META_FRAME_CONTROL_TITLE;
2764
if (POINT_IN_RECT (x, y, fgeom.max_rect.clickable))
2766
if (flags & META_FRAME_MAXIMIZED)
2767
return META_FRAME_CONTROL_UNMAXIMIZE;
2769
return META_FRAME_CONTROL_MAXIMIZE;
2772
if (POINT_IN_RECT (x, y, fgeom.shade_rect.clickable))
2774
return META_FRAME_CONTROL_SHADE;
2777
if (POINT_IN_RECT (x, y, fgeom.unshade_rect.clickable))
2779
return META_FRAME_CONTROL_UNSHADE;
2782
if (POINT_IN_RECT (x, y, fgeom.above_rect.clickable))
2784
return META_FRAME_CONTROL_ABOVE;
2787
if (POINT_IN_RECT (x, y, fgeom.unabove_rect.clickable))
2789
return META_FRAME_CONTROL_UNABOVE;
2792
if (POINT_IN_RECT (x, y, fgeom.stick_rect.clickable))
2794
return META_FRAME_CONTROL_STICK;
2797
if (POINT_IN_RECT (x, y, fgeom.unstick_rect.clickable))
2799
return META_FRAME_CONTROL_UNSTICK;
2802
/* South resize always has priority over north resize,
2803
* in case of overlap.
2806
if (y >= (fgeom.height - fgeom.bottom_height - RESIZE_EXTENDS) &&
2807
x >= (fgeom.width - fgeom.right_width - RESIZE_EXTENDS))
2809
if (has_vert && has_horiz)
2810
return META_FRAME_CONTROL_RESIZE_SE;
2812
return META_FRAME_CONTROL_RESIZE_S;
2814
return META_FRAME_CONTROL_RESIZE_E;
2816
else if (y >= (fgeom.height - fgeom.bottom_height - RESIZE_EXTENDS) &&
2817
x <= (fgeom.left_width + RESIZE_EXTENDS))
2819
if (has_vert && has_horiz)
2820
return META_FRAME_CONTROL_RESIZE_SW;
2822
return META_FRAME_CONTROL_RESIZE_S;
2824
return META_FRAME_CONTROL_RESIZE_W;
2826
else if (y < (fgeom.top_height + RESIZE_EXTENDS) &&
2829
if (has_vert && has_horiz)
2830
return META_FRAME_CONTROL_RESIZE_NW;
2832
return META_FRAME_CONTROL_RESIZE_N;
2834
return META_FRAME_CONTROL_RESIZE_W;
2836
else if (y < (fgeom.top_height + RESIZE_EXTENDS) &&
2837
x >= (fgeom.width - RESIZE_EXTENDS))
2839
if (has_vert && has_horiz)
2840
return META_FRAME_CONTROL_RESIZE_NE;
2842
return META_FRAME_CONTROL_RESIZE_N;
2844
return META_FRAME_CONTROL_RESIZE_E;
2846
else if (y >= (fgeom.height - fgeom.bottom_height - RESIZE_EXTENDS))
2849
return META_FRAME_CONTROL_RESIZE_S;
2851
else if (y <= TOP_RESIZE_HEIGHT)
2854
return META_FRAME_CONTROL_RESIZE_N;
2856
return META_FRAME_CONTROL_TITLE;
2858
else if (x <= fgeom.left_width)
2861
return META_FRAME_CONTROL_RESIZE_W;
2863
else if (x >= (fgeom.width - fgeom.right_width))
2866
return META_FRAME_CONTROL_RESIZE_E;
2869
if (y >= fgeom.top_height)
2870
return META_FRAME_CONTROL_NONE;
2872
return META_FRAME_CONTROL_TITLE;
2876
meta_frames_push_delay_exposes (MetaFrames *frames)
2878
if (frames->expose_delay_count == 0)
2880
/* Make sure we've repainted things */
2881
gdk_window_process_all_updates ();
2882
XFlush (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
2885
frames->expose_delay_count += 1;
2889
queue_pending_exposes_func (gpointer key, gpointer value, gpointer data)
2894
frames = META_FRAMES (data);
2897
if (frame->expose_delayed)
2899
invalidate_whole_window (frames, frame);
2900
frame->expose_delayed = FALSE;
2905
meta_frames_pop_delay_exposes (MetaFrames *frames)
2907
g_return_if_fail (frames->expose_delay_count > 0);
2909
frames->expose_delay_count -= 1;
2911
if (frames->expose_delay_count == 0)
2913
g_hash_table_foreach (frames->frames,
2914
queue_pending_exposes_func,
2920
invalidate_whole_window (MetaFrames *frames,
2923
gdk_window_invalidate_rect (frame->window, NULL, FALSE);
2924
invalidate_cache (frames, frame);