Bug Summary

File:ui/frames.c
Warning:line 1696, column 16
This statement is never executed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name frames.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/rootdir/src -resource-dir /usr/lib/llvm-16/lib/clang/16 -D HAVE_CONFIG_H -I . -I .. -I ./include -D CROMA_LIBEXECDIR="/usr/libexec" -D HOST_ALIAS="" -D CROMA_LOCALEDIR="/usr/share/locale" -D CROMA_PKGDATADIR="/usr/share/croma" -D CROMA_DATADIR="/usr/share" -D G_LOG_DOMAIN="croma" -D SN_API_NOT_YET_FROZEN=1 -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -D _REENTRANT -D _REENTRANT -I /usr/include/startup-notification-1.0 -I /usr/include/libgtop-2.0 -D PIC -internal-isystem /usr/lib/llvm-16/lib/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/13/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir=/rootdir/src -ferror-limit 19 -fgnuc-version=4.2.1 -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2024-02-14-231308-31150-1 -x c ui/frames.c
1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3/* Croma window frame manager widget */
4
5/*
6 * Copyright (C) 2001 Havoc Pennington
7 * Copyright (C) 2003 Red Hat, Inc.
8 * Copyright (C) 2005, 2006 Elijah Newren
9 *
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.
14 *
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.
19 *
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., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301, USA.
24 */
25
26#include <config.h>
27#include <math.h>
28#include <string.h>
29#include "boxes.h"
30#include "frames.h"
31#include "util.h"
32#include "core.h"
33#include "menu.h"
34#include "fixedtip.h"
35#include "theme.h"
36#include "prefs.h"
37#include "ui.h"
38
39#ifdef HAVE_SHAPE
40#include <X11/extensions/shape.h>
41#endif
42
43#include <cairo-xlib.h>
44
45G_DEFINE_TYPE (MetaFrames, meta_frames, CTK_TYPE_WINDOW)static void meta_frames_init (MetaFrames *self); static void meta_frames_class_init
(MetaFramesClass *klass); static GType meta_frames_get_type_once
(void); static gpointer meta_frames_parent_class = ((void*)0
); static gint MetaFrames_private_offset; static void meta_frames_class_intern_init
(gpointer klass) { meta_frames_parent_class = g_type_class_peek_parent
(klass); if (MetaFrames_private_offset != 0) g_type_class_adjust_private_offset
(klass, &MetaFrames_private_offset); meta_frames_class_init
((MetaFramesClass*) klass); } __attribute__ ((__unused__)) static
inline gpointer meta_frames_get_instance_private (MetaFrames
*self) { return (((gpointer) ((guint8*) (self) + (glong) (MetaFrames_private_offset
)))); } GType meta_frames_get_type (void) { static gsize static_g_define_type_id
= 0; if ((__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); (void
) (0 ? (gpointer) *(&static_g_define_type_id) : ((void*)0
)); (!(__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); __typeof__
(*(&static_g_define_type_id)) gapg_temp_newval; __typeof__
((&static_g_define_type_id)) gapg_temp_atomic = (&static_g_define_type_id
); __atomic_load (gapg_temp_atomic, &gapg_temp_newval, 5)
; gapg_temp_newval; })) && g_once_init_enter (&static_g_define_type_id
)); }))) { GType g_define_type_id = meta_frames_get_type_once
(); (__extension__ ({ _Static_assert (sizeof *(&static_g_define_type_id
) == sizeof (gpointer), "Expression evaluates to false"); 0 ?
(void) (*(&static_g_define_type_id) = (g_define_type_id)
) : (void) 0; g_once_init_leave ((&static_g_define_type_id
), (gsize) (g_define_type_id)); })); } return static_g_define_type_id
; } __attribute__ ((__noinline__)) static GType meta_frames_get_type_once
(void) { GType g_define_type_id = g_type_register_static_simple
((ctk_window_get_type ()), g_intern_static_string ("MetaFrames"
), sizeof (MetaFramesClass), (GClassInitFunc)(void (*)(void))
meta_frames_class_intern_init, sizeof (MetaFrames), (GInstanceInitFunc
)(void (*)(void)) meta_frames_init, (GTypeFlags) 0); { {{};} }
return g_define_type_id; }
;
46
47#define DEFAULT_INNER_BUTTON_BORDER3 3
48
49static void meta_frames_class_init (MetaFramesClass *klass);
50static void meta_frames_init (MetaFrames *frames);
51static void meta_frames_destroy (CtkWidget *object);
52static void meta_frames_finalize (GObject *object);
53static void meta_frames_style_updated (CtkWidget *widget);
54
55static void meta_frames_update_prelit_control (MetaFrames *frames,
56 MetaUIFrame *frame,
57 MetaFrameControl control);
58static gboolean meta_frames_button_press_event (CtkWidget *widget,
59 CdkEventButton *event);
60static gboolean meta_frames_button_release_event (CtkWidget *widget,
61 CdkEventButton *event);
62static gboolean meta_frames_motion_notify_event (CtkWidget *widget,
63 CdkEventMotion *event);
64static gboolean meta_frames_destroy_event (CtkWidget *widget,
65 CdkEventAny *event);
66static gboolean meta_frames_draw (CtkWidget *widget,
67 cairo_t *cr);
68static gboolean meta_frames_enter_notify_event (CtkWidget *widget,
69 CdkEventCrossing *event);
70static gboolean meta_frames_leave_notify_event (CtkWidget *widget,
71 CdkEventCrossing *event);
72
73static void meta_frames_attach_style (MetaFrames *frames,
74 MetaUIFrame *frame);
75
76static void meta_frames_paint_to_drawable (MetaFrames *frames,
77 MetaUIFrame *frame,
78 cairo_t *cr);
79
80static void meta_frames_calc_geometry (MetaFrames *frames,
81 MetaUIFrame *frame,
82 MetaFrameGeometry *fgeom);
83
84static void meta_frames_ensure_layout (MetaFrames *frames,
85 MetaUIFrame *frame);
86
87static MetaUIFrame* meta_frames_lookup_window (MetaFrames *frames,
88 Window xwindow);
89
90static void meta_frames_font_changed (MetaFrames *frames);
91static void meta_frames_button_layout_changed (MetaFrames *frames);
92
93
94static CdkRectangle* control_rect (MetaFrameControl control,
95 MetaFrameGeometry *fgeom);
96static MetaFrameControl get_control (MetaFrames *frames,
97 MetaUIFrame *frame,
98 int x,
99 int y);
100static void clear_tip (MetaFrames *frames);
101static void invalidate_all_caches (MetaFrames *frames);
102static void invalidate_whole_window (MetaFrames *frames,
103 MetaUIFrame *frame);
104
105static GObject *
106meta_frames_constructor (GType gtype,
107 guint n_properties,
108 GObjectConstructParam *properties)
109{
110 GObject *object;
111 GObjectClass *gobject_class;
112
113 gobject_class = G_OBJECT_CLASS (meta_frames_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((meta_frames_parent_class)), (((GType) ((20) << (2)
)))))))
;
114 object = gobject_class->constructor (gtype, n_properties, properties);
115
116 return object;
117}
118
119static void
120meta_frames_class_init (MetaFramesClass *class)
121{
122 GObjectClass *gobject_class;
123 CtkWidgetClass *widget_class;
124
125 gobject_class = G_OBJECT_CLASS (class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((class)), (((GType) ((20) << (2))))))))
;
126 widget_class = (CtkWidgetClass*) class;
127
128 gobject_class->constructor = meta_frames_constructor;
129 gobject_class->finalize = meta_frames_finalize;
130 widget_class->destroy = meta_frames_destroy;
131 widget_class->style_updated = meta_frames_style_updated;
132
133 widget_class->draw = meta_frames_draw;
134 widget_class->destroy_event = meta_frames_destroy_event;
135 widget_class->button_press_event = meta_frames_button_press_event;
136 widget_class->button_release_event = meta_frames_button_release_event;
137 widget_class->motion_notify_event = meta_frames_motion_notify_event;
138 widget_class->enter_notify_event = meta_frames_enter_notify_event;
139 widget_class->leave_notify_event = meta_frames_leave_notify_event;
140}
141
142static gint
143unsigned_long_equal (gconstpointer v1,
144 gconstpointer v2)
145{
146 return *((const gulong*) v1) == *((const gulong*) v2);
147}
148
149static guint
150unsigned_long_hash (gconstpointer v)
151{
152 gulong val = * (const gulong *) v;
153
154 /* I'm not sure this works so well. */
155#if GLIB_SIZEOF_LONG8 > 4
156 return (guint) (val ^ (val >> 32));
157#else
158 return val;
159#endif
160}
161
162static void
163prefs_changed_callback (MetaPreference pref,
164 void *data)
165{
166 switch (pref)
167 {
168 case META_PREF_TITLEBAR_FONT:
169 meta_frames_font_changed (META_FRAMES (data)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((meta_frames_get_type ()))))))
);
170 break;
171 case META_PREF_BUTTON_LAYOUT:
172 meta_frames_button_layout_changed (META_FRAMES (data)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((meta_frames_get_type ()))))))
);
173 break;
174 default:
175 break;
176 }
177}
178
179static CtkStyleContext *
180create_style_context (MetaFrames *frames,
181 const gchar *variant)
182{
183 CtkStyleContext *style;
184 CdkScreen *screen;
185 char *theme_name;
186
187 screen = ctk_widget_get_screen (CTK_WIDGET (frames)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frames)), ((ctk_widget_get_type ()))))))
);
188 g_object_get (ctk_settings_get_for_screen (screen),
189 "ctk-theme-name", &theme_name,
190 NULL((void*)0));
191
192 style = ctk_style_context_new ();
193 ctk_style_context_set_path (style,
194 ctk_widget_get_path (CTK_WIDGET (frames)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frames)), ((ctk_widget_get_type ()))))))
));
195
196 if (theme_name && *theme_name)
197 {
198 CtkCssProvider *provider;
199
200 provider = ctk_css_provider_get_named (theme_name, variant);
201 ctk_style_context_add_provider (style,
202 CTK_STYLE_PROVIDER (provider)((((CtkStyleProvider*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((provider)), ((ctk_style_provider_get_type (
)))))))
,
203 CTK_STYLE_PROVIDER_PRIORITY_SETTINGS400);
204 }
205
206 if (theme_name)
207 g_free (theme_name);
208
209 return style;
210}
211
212static CtkStyleContext *
213meta_frames_get_theme_variant (MetaFrames *frames,
214 const gchar *variant)
215{
216 CtkStyleContext *style;
217
218 style = g_hash_table_lookup (frames->style_variants, variant);
219 if (style == NULL((void*)0))
220 {
221 style = create_style_context (frames, variant);
222 g_hash_table_insert (frames->style_variants, g_strdup (variant)g_strdup_inline (variant), style);
223 }
224
225 return style;
226}
227
228static void
229update_style_contexts (MetaFrames *frames)
230{
231 GList *variant_list, *variant;
232
233 if (frames->normal_style)
234 g_object_unref (frames->normal_style);
235 frames->normal_style = create_style_context (frames, NULL((void*)0));
236
237 variant_list = g_hash_table_get_keys (frames->style_variants);
238 for (variant = variant_list; variant; variant = variant->next)
239 {
240 CtkStyleContext *style;
241
242 style = create_style_context (frames, (char *)variant->data);
243 g_hash_table_insert (frames->style_variants,
244 g_strdup (variant->data)g_strdup_inline (variant->data), style);
245 }
246 g_list_free (variant_list);
247}
248static void
249meta_frames_init (MetaFrames *frames)
250{
251 frames->text_heights = g_hash_table_new (NULL((void*)0), NULL((void*)0));
252
253 frames->frames = g_hash_table_new (unsigned_long_hash, unsigned_long_equal);
254
255 frames->tooltip_timeout = 0;
256
257 frames->expose_delay_count = 0;
258
259 frames->invalidate_cache_timeout_id = 0;
260 frames->invalidate_frames = NULL((void*)0);
261 frames->cache = g_hash_table_new (g_direct_hash, g_direct_equal);
262 frames->style_variants = g_hash_table_new_full (g_str_hash, g_str_equal,
263 g_free, g_object_unref);
264 update_style_contexts (frames);
265
266 meta_prefs_add_listener (prefs_changed_callback, frames);
267}
268
269static void
270listify_func (gpointer key, gpointer value, gpointer data)
271{
272 GSList **listp;
273
274 listp = data;
275 *listp = g_slist_prepend (*listp, value);
276}
277
278static void
279meta_frames_destroy (CtkWidget *widget)
280{
281 GSList *winlist;
282 GSList *tmp;
283 MetaFrames *frames;
284
285 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
286
287 clear_tip (frames);
288
289 winlist = NULL((void*)0);
290 g_hash_table_foreach (frames->frames, listify_func, &winlist);
291
292 /* Unmanage all frames */
293 for (tmp = winlist; tmp != NULL((void*)0); tmp = tmp->next)
294 {
295 MetaUIFrame *frame;
296
297 frame = tmp->data;
298
299 meta_frames_unmanage_window (frames, frame->xwindow);
300 }
301 g_slist_free (winlist);
302
303 if (frames->normal_style)
304 {
305 g_object_unref (frames->normal_style);
306 frames->normal_style = NULL((void*)0);
307 }
308
309 if (frames->style_variants)
310 {
311 g_hash_table_destroy (frames->style_variants);
312 frames->style_variants = NULL((void*)0);
313 }
314
315 CTK_WIDGET_CLASS (meta_frames_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((meta_frames_parent_class)), ((ctk_widget_get_type ()))))
))
->destroy (widget);
316}
317
318static void
319meta_frames_finalize (GObject *object)
320{
321 MetaFrames *frames;
322
323 frames = META_FRAMES (object)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((object)), ((meta_frames_get_type ()))))))
;
324
325 meta_prefs_remove_listener (prefs_changed_callback, frames);
326
327 g_hash_table_destroy (frames->text_heights);
328
329 invalidate_all_caches (frames);
330 if (frames->invalidate_cache_timeout_id)
331 g_source_remove (frames->invalidate_cache_timeout_id);
332
333 g_assert (g_hash_table_size (frames->frames) == 0)do { if (g_hash_table_size (frames->frames) == 0) ; else g_assertion_message_expr
("croma", "ui/frames.c", 333, ((const char*) (__func__)), "g_hash_table_size (frames->frames) == 0"
); } while (0)
;
334 g_hash_table_destroy (frames->frames);
335 g_hash_table_destroy (frames->cache);
336
337 G_OBJECT_CLASS (meta_frames_parent_class)((((GObjectClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((meta_frames_parent_class)), (((GType) ((20) << (2)
)))))))
->finalize (object);
338}
339
340typedef struct
341{
342 cairo_rectangle_int_t rect;
343 cairo_surface_t *pixmap;
344} CachedFramePiece;
345
346typedef struct
347{
348 /* Caches of the four rendered sides in a MetaFrame.
349 * Order: top (titlebar), left, right, bottom.
350 */
351 CachedFramePiece piece[4];
352} CachedPixels;
353
354static CachedPixels *
355get_cache (MetaFrames *frames,
356 MetaUIFrame *frame)
357{
358 CachedPixels *pixels;
359
360 pixels = g_hash_table_lookup (frames->cache, frame);
361
362 if (!pixels)
363 {
364 pixels = g_new0 (CachedPixels, 1)((CachedPixels *) g_malloc0_n ((1), sizeof (CachedPixels)));
365 g_hash_table_insert (frames->cache, frame, pixels);
366 }
367
368 return pixels;
369}
370
371static void
372invalidate_cache (MetaFrames *frames,
373 MetaUIFrame *frame)
374{
375 CachedPixels *pixels = get_cache (frames, frame);
376 int i;
377
378 for (i = 0; i < 4; i++)
379 if (pixels->piece[i].pixmap)
380 cairo_surface_destroy (pixels->piece[i].pixmap);
381
382 g_free (pixels);
383 g_hash_table_remove (frames->cache, frame);
384}
385
386static void
387invalidate_all_caches (MetaFrames *frames)
388{
389 GList *l;
390
391 for (l = frames->invalidate_frames; l; l = l->next)
392 {
393 MetaUIFrame *frame = l->data;
394
395 invalidate_cache (frames, frame);
396 }
397
398 g_list_free (frames->invalidate_frames);
399 frames->invalidate_frames = NULL((void*)0);
400}
401
402static gboolean
403invalidate_cache_timeout (gpointer data)
404{
405 MetaFrames *frames = data;
406
407 invalidate_all_caches (frames);
408 frames->invalidate_cache_timeout_id = 0;
409 return FALSE(0);
410}
411
412static void
413queue_recalc_func (gpointer key, gpointer value, gpointer data)
414{
415 MetaUIFrame *frame;
416 MetaFrames *frames;
417
418 frames = META_FRAMES (data)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((meta_frames_get_type ()))))))
;
419 frame = value;
420
421 invalidate_whole_window (frames, frame);
422 meta_core_queue_frame_resize (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())),
423 frame->xwindow);
424 if (frame->text_layout)
425 {
426 /* save title to recreate layout */
427 g_free (frame->title);
428
429 frame->title = g_strdup (pango_layout_get_text (frame->text_layout))g_strdup_inline (pango_layout_get_text (frame->text_layout
))
;
430
431 g_clear_object (&frame->text_layout)do { _Static_assert (sizeof *((&frame->text_layout)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&frame->text_layout))) _pp = ((&frame->text_layout
)); __typeof__ (*((&frame->text_layout))) _ptr = *_pp;
*_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while
(0)
;
432 }
433}
434
435static void
436meta_frames_font_changed (MetaFrames *frames)
437{
438 if (g_hash_table_size (frames->text_heights) > 0)
439 {
440 g_hash_table_destroy (frames->text_heights);
441 frames->text_heights = g_hash_table_new (NULL((void*)0), NULL((void*)0));
442 }
443
444 /* Queue a draw/resize on all frames */
445 g_hash_table_foreach (frames->frames,
446 queue_recalc_func, frames);
447
448}
449
450static void
451queue_draw_func (gpointer key, gpointer value, gpointer data)
452{
453 MetaUIFrame *frame;
454 MetaFrames *frames;
455
456 frames = META_FRAMES (data)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((meta_frames_get_type ()))))))
;
457 frame = value;
458
459 invalidate_whole_window (frames, frame);
460}
461
462static void
463meta_frames_button_layout_changed (MetaFrames *frames)
464{
465 g_hash_table_foreach (frames->frames,
466 queue_draw_func, frames);
467}
468
469static void
470reattach_style_func (gpointer key, gpointer value, gpointer data)
471{
472 MetaUIFrame *frame;
473 MetaFrames *frames;
474
475 frames = META_FRAMES (data)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((meta_frames_get_type ()))))))
;
476 frame = value;
477
478 meta_frames_attach_style (frames, frame);
479}
480
481static void
482meta_frames_style_updated (CtkWidget *widget)
483{
484 MetaFrames *frames;
485
486 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
487
488 meta_frames_font_changed (frames);
489
490 update_style_contexts (frames);
491 g_hash_table_foreach (frames->frames,
492 reattach_style_func, frames);
493
494 CTK_WIDGET_CLASS (meta_frames_parent_class)((((CtkWidgetClass*) (void *) g_type_check_class_cast ((GTypeClass
*) ((meta_frames_parent_class)), ((ctk_widget_get_type ()))))
))
->style_updated (widget);
495}
496
497static void
498meta_frames_ensure_layout (MetaFrames *frames,
499 MetaUIFrame *frame)
500{
501 CtkWidget *widget;
502 MetaFrameFlags flags;
503 MetaFrameType type;
504 MetaFrameStyle *style;
505
506 g_return_if_fail (ctk_widget_get_realized (CTK_WIDGET (frames)))do { if ((ctk_widget_get_realized (((((CtkWidget*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((frames)), ((ctk_widget_get_type ()))))))
))) { } else { g_return_if_fail_warning ("croma", ((const char
*) (__func__)), "ctk_widget_get_realized (CTK_WIDGET (frames))"
); return; } } while (0)
;
507
508 widget = CTK_WIDGET (frames)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frames)), ((ctk_widget_get_type ()))))))
;
509
510 meta_core_get (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow,
511 META_CORE_GET_FRAME_FLAGS, &flags,
512 META_CORE_GET_FRAME_TYPE, &type,
513 META_CORE_GET_END);
514
515 style = meta_theme_get_frame_style (meta_theme_get_current (),
516 type, flags);
517
518 if (style != frame->cache_style)
519 {
520 if (frame->text_layout)
521 {
522 /* save title to recreate layout */
523 g_free (frame->title);
524
525 frame->title = g_strdup (pango_layout_get_text (frame->text_layout))g_strdup_inline (pango_layout_get_text (frame->text_layout
))
;
526
527 g_clear_object (&frame->text_layout)do { _Static_assert (sizeof *((&frame->text_layout)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&frame->text_layout))) _pp = ((&frame->text_layout
)); __typeof__ (*((&frame->text_layout))) _ptr = *_pp;
*_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while
(0)
;
528 }
529 }
530
531 frame->cache_style = style;
532
533 if (frame->text_layout == NULL((void*)0))
534 {
535 gpointer key, value;
536 PangoFontDescription *font_desc;
537 double scale;
538 int size;
539
540 scale = meta_theme_get_title_scale (meta_theme_get_current (),
541 type,
542 flags);
543
544 frame->text_layout = ctk_widget_create_pango_layout (widget, frame->title);
545
546 pango_layout_set_ellipsize (frame->text_layout, PANGO_ELLIPSIZE_END);
547 pango_layout_set_auto_dir (frame->text_layout, FALSE(0));
548
549 pango_layout_set_single_paragraph_mode (frame->text_layout, TRUE(!(0)));
550
551 font_desc = meta_ctk_widget_get_font_desc (widget, scale,
552 meta_prefs_get_titlebar_font ());
553
554 size = pango_font_description_get_size (font_desc);
555
556 if (g_hash_table_lookup_extended (frames->text_heights,
557 GINT_TO_POINTER (size)((gpointer) (glong) (size)),
558 &key, &value))
559 {
560 frame->text_height = GPOINTER_TO_INT (value)((gint) (glong) (value));
561 }
562 else
563 {
564 frame->text_height =
565 meta_pango_font_desc_get_text_height (font_desc,
566 ctk_widget_get_pango_context (widget));
567
568 g_hash_table_replace (frames->text_heights,
569 GINT_TO_POINTER (size)((gpointer) (glong) (size)),
570 GINT_TO_POINTER (frame->text_height)((gpointer) (glong) (frame->text_height)));
571 }
572
573 pango_layout_set_font_description (frame->text_layout,
574 font_desc);
575
576 pango_font_description_free (font_desc);
577
578 /* Save some RAM */
579 g_free (frame->title);
580 frame->title = NULL((void*)0);
581 }
582}
583
584static void
585meta_frames_calc_geometry (MetaFrames *frames,
586 MetaUIFrame *frame,
587 MetaFrameGeometry *fgeom)
588{
589 int width, height, scale;
590 MetaFrameFlags flags;
591 MetaFrameType type;
592 MetaButtonLayout button_layout;
593
594 scale = cdk_window_get_scale_factor (frame->window);
595
596 meta_core_get (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow,
597 META_CORE_GET_CLIENT_WIDTH, &width,
598 META_CORE_GET_CLIENT_HEIGHT, &height,
599 META_CORE_GET_FRAME_FLAGS, &flags,
600 META_CORE_GET_FRAME_TYPE, &type,
601 META_CORE_GET_END);
602
603 meta_frames_ensure_layout (frames, frame);
604
605 meta_prefs_get_button_layout (&button_layout);
606
607 meta_theme_calc_geometry (meta_theme_get_current (),
608 type,
609 frame->text_height,
610 flags,
611 width / scale, height / scale,
612 &button_layout,
613 fgeom);
614}
615
616MetaFrames*
617meta_frames_new (void)
618{
619 CdkScreen *screen;
620 MetaFrames *frames;
621
622 screen = cdk_display_get_default_screen (cdk_display_get_default ());
623
624 frames = g_object_new (META_TYPE_FRAMES(meta_frames_get_type ()),
625 "screen", screen,
626 "type", CTK_WINDOW_POPUP,
627 NULL((void*)0));
628
629 /* Put the window at an arbitrary offscreen location; the one place
630 * it can't be is at -100x-100, since the meta_window_new() will
631 * mistake it for a window created via meta_create_offscreen_window()
632 * and ignore it, and we need this window to get frame-synchronization
633 * messages so that CTK+'s style change handling works.
634 */
635 ctk_window_move (CTK_WINDOW (frames)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frames)), ((ctk_window_get_type ()))))))
, -200, -200);
636 ctk_window_resize (CTK_WINDOW (frames)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frames)), ((ctk_window_get_type ()))))))
, 1, 1);
637
638 return frames;
639}
640
641/* In order to use a style with a window it has to be attached to that
642 * window. Actually, the colormaps just have to match, but since CTK+
643 * already takes care of making sure that its cheap to attach a style
644 * to multiple windows with the same colormap, we can just go ahead
645 * and attach separately for each window.
646 */
647static void
648meta_frames_attach_style (MetaFrames *frames,
649 MetaUIFrame *frame)
650{
651 gboolean has_frame;
652 char *variant = NULL((void*)0);
653 if (frame->style != NULL((void*)0))
654 g_object_unref (frame->style);
655
656 meta_core_get (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())),
657 frame->xwindow,
658 META_CORE_WINDOW_HAS_FRAME, &has_frame,
659 META_CORE_GET_THEME_VARIANT, &variant,
660 META_CORE_GET_END);
661
662 if (variant == NULL((void*)0) || strcmp(variant, "normal") == 0)
663 frame->style = g_object_ref (frames->normal_style)((__typeof__ (frames->normal_style)) (g_object_ref) (frames
->normal_style))
;
664 else
665 frame->style = g_object_ref (meta_frames_get_theme_variant (frames,((__typeof__ (meta_frames_get_theme_variant (frames, variant)
)) (g_object_ref) (meta_frames_get_theme_variant (frames, variant
)))
666 variant))((__typeof__ (meta_frames_get_theme_variant (frames, variant)
)) (g_object_ref) (meta_frames_get_theme_variant (frames, variant
)))
;
667}
668
669void
670meta_frames_manage_window (MetaFrames *frames,
671 Window xwindow,
672 CdkWindow *window)
673{
674 MetaUIFrame *frame;
675
676 g_assert (window)do { if (window) ; else g_assertion_message_expr ("croma", "ui/frames.c"
, 676, ((const char*) (__func__)), "window"); } while (0)
;
677
678 frame = g_new (MetaUIFrame, 1)((MetaUIFrame *) g_malloc_n ((1), sizeof (MetaUIFrame)));
679
680 frame->window = window;
681
682 cdk_window_set_user_data (frame->window, frames);
683
684 frame->style = NULL((void*)0);
685
686 /* Don't set event mask here, it's in frame.c */
687
688 frame->xwindow = xwindow;
689 frame->cache_style = NULL((void*)0);
690 frame->text_layout = NULL((void*)0);
691 frame->text_height = -1;
692 frame->title = NULL((void*)0);
693 frame->expose_delayed = FALSE(0);
694 frame->shape_applied = FALSE(0);
695 frame->prelit_control = META_FRAME_CONTROL_NONE;
696
697 meta_core_grab_buttons (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow);
698
699 g_hash_table_replace (frames->frames, &frame->xwindow, frame);
700}
701
702void
703meta_frames_unmanage_window (MetaFrames *frames,
704 Window xwindow)
705{
706 MetaUIFrame *frame;
707
708 clear_tip (frames);
709
710 frame = g_hash_table_lookup (frames->frames, &xwindow);
711
712 if (frame)
713 {
714 /* invalidating all caches ensures the frame
715 * is not actually referenced anymore
716 */
717 invalidate_all_caches (frames);
718
719 /* restore the cursor */
720 meta_core_set_screen_cursor (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())),
721 frame->xwindow,
722 META_CURSOR_DEFAULT);
723
724 cdk_window_set_user_data (frame->window, NULL((void*)0));
725
726 if (frames->last_motion_frame == frame)
727 frames->last_motion_frame = NULL((void*)0);
728
729 g_hash_table_remove (frames->frames, &frame->xwindow);
730
731 g_object_unref (frame->style);
732
733 cdk_window_destroy (frame->window);
734
735 if (frame->text_layout)
736 g_object_unref (G_OBJECT (frame->text_layout)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frame->text_layout)), (((GType) ((20) << (2))))
))))
);
737
738 if (frame->title)
739 g_free (frame->title);
740
741 g_free (frame);
742 }
743 else
744 meta_warning ("Frame 0x%lx not managed, can't unmanage\n", xwindow);
745}
746
747static MetaUIFrame*
748meta_frames_lookup_window (MetaFrames *frames,
749 Window xwindow)
750{
751 MetaUIFrame *frame;
752
753 frame = g_hash_table_lookup (frames->frames, &xwindow);
754
755 return frame;
756}
757
758static void
759meta_ui_frame_get_borders (MetaFrames *frames,
760 MetaUIFrame *frame,
761 MetaFrameBorders *borders)
762{
763 MetaFrameFlags flags;
764 MetaFrameType type;
765 gint scale;
766
767 meta_core_get (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow,
768 META_CORE_GET_FRAME_FLAGS, &flags,
769 META_CORE_GET_FRAME_TYPE, &type,
770 META_CORE_GET_END);
771
772 g_return_if_fail (type < META_FRAME_TYPE_LAST)do { if ((type < META_FRAME_TYPE_LAST)) { } else { g_return_if_fail_warning
("croma", ((const char*) (__func__)), "type < META_FRAME_TYPE_LAST"
); return; } } while (0)
;
773
774 scale = cdk_window_get_scale_factor (frame->window);
775
776 meta_frames_ensure_layout (frames, frame);
777
778 /* We can't get the full geometry, because that depends on
779 * the client window size and probably we're being called
780 * by the core move/resize code to decide on the client
781 * window size
782 */
783 meta_theme_get_frame_borders (meta_theme_get_current (),
784 type,
785 frame->text_height,
786 flags,
787 borders);
788
789 /* Scale frame geometry to ensure proper frame position */
790 borders->visible.top *= scale;
791 borders->visible.bottom *= scale;
792 borders->visible.left *= scale;
793 borders->visible.right *= scale;
794
795 borders->invisible.top *= scale;
796 borders->invisible.bottom *= scale;
797 borders->invisible.left *= scale;
798 borders->invisible.right *= scale;
799
800 borders->total.top *= scale;
801 borders->total.bottom *= scale;
802 borders->total.left *= scale;
803 borders->total.right *= scale;
804}
805
806void
807meta_frames_get_borders (MetaFrames *frames,
808 Window xwindow,
809 MetaFrameBorders *borders)
810{
811 MetaUIFrame *frame;
812
813 frame = meta_frames_lookup_window (frames, xwindow);
814
815 if (frame == NULL((void*)0))
816 g_error ("No such frame 0x%lx\n", xwindow);
817
818 meta_ui_frame_get_borders (frames, frame, borders);
819}
820
821static void
822meta_ui_frame_get_corner_radiuses (MetaFrames *frames,
823 MetaUIFrame *frame,
824 float *top_left,
825 float *top_right,
826 float *bottom_left,
827 float *bottom_right)
828{
829 MetaFrameGeometry fgeom;
830
831 meta_frames_calc_geometry (frames, frame, &fgeom);
832
833 /* For compatibility with the code in get_visible_rect(), there's
834 * a mysterious sqrt() added to the corner radiuses:
835 *
836 * const float radius = sqrt(corner) + corner;
837 *
838 * It's unclear why the radius is calculated like this, but we
839 * need to be consistent with it.
840 */
841
842 if (top_left)
843 *top_left = fgeom.top_left_corner_rounded_radius + sqrt(fgeom.top_left_corner_rounded_radius);
844 if (top_right)
845 *top_right = fgeom.top_right_corner_rounded_radius + sqrt(fgeom.top_right_corner_rounded_radius);
846 if (bottom_left)
847 *bottom_left = fgeom.bottom_left_corner_rounded_radius + sqrt(fgeom.bottom_left_corner_rounded_radius);
848 if (bottom_right)
849 *bottom_right = fgeom.bottom_right_corner_rounded_radius + sqrt(fgeom.bottom_right_corner_rounded_radius);
850}
851
852void
853meta_frames_get_corner_radiuses (MetaFrames *frames,
854 Window xwindow,
855 float *top_left,
856 float *top_right,
857 float *bottom_left,
858 float *bottom_right)
859{
860 MetaUIFrame *frame;
861
862 frame = meta_frames_lookup_window (frames, xwindow);
863
864 meta_ui_frame_get_corner_radiuses (frames, frame, top_left, top_right,
865 bottom_left, bottom_right);
866}
867
868#ifdef HAVE_SHAPE
869static void
870apply_cairo_region_to_window (Display *display,
871 Window xwindow,
872 cairo_region_t *region,
873 int op)
874{
875 int n_rects, i;
876 XRectangle *rects;
877
878 n_rects = cairo_region_num_rectangles (region);
879 rects = g_new (XRectangle, n_rects)((XRectangle *) g_malloc_n ((n_rects), sizeof (XRectangle)));
880
881 for (i = 0; i < n_rects; i++)
882 {
883 cairo_rectangle_int_t rect;
884
885 cairo_region_get_rectangle (region, i, &rect);
886
887 rects[i].x = rect.x;
888 rects[i].y = rect.y;
889 rects[i].width = rect.width;
890 rects[i].height = rect.height;
891 }
892
893 XShapeCombineRectangles (display, xwindow,
894 ShapeBounding0, 0, 0, rects, n_rects,
895 op, YXBanded3);
896
897 g_free (rects);
898}
899#endif
900
901/* The client rectangle surrounds client window; it subtracts both
902 * the visible and invisible borders from the frame window's size.
903 */
904static void
905get_client_rect (MetaFrameGeometry *fgeom,
906 int window_width,
907 int window_height,
908 cairo_rectangle_int_t *rect)
909{
910 rect->x = fgeom->borders.total.left;
911 rect->y = fgeom->borders.total.top;
912 rect->width = window_width - fgeom->borders.total.right - rect->x;
913 rect->height = window_height - fgeom->borders.total.bottom - rect->y;
914}
915
916/* The visible frame rectangle surrounds the visible portion of the
917 * frame window; it subtracts only the invisible borders from the frame
918 * window's size.
919 */
920static void
921get_visible_frame_rect (MetaFrameGeometry *fgeom,
922 int window_width,
923 int window_height,
924 cairo_rectangle_int_t *rect)
925{
926 rect->x = fgeom->borders.invisible.left;
927 rect->y = fgeom->borders.invisible.top;
928 rect->width = window_width - fgeom->borders.invisible.right - rect->x;
929 rect->height = window_height - fgeom->borders.invisible.bottom - rect->y;
930}
931
932static cairo_region_t *
933get_visible_region (MetaFrames *frames,
934 MetaUIFrame *frame,
935 MetaFrameGeometry *fgeom,
936 int window_width,
937 int window_height)
938{
939 cairo_region_t *corners_region;
940 cairo_region_t *visible_region;
941 cairo_rectangle_int_t rect;
942 cairo_rectangle_int_t frame_rect;
943 gint scale;
944
945 corners_region = cairo_region_create ();
946 scale = cdk_window_get_scale_factor (frame->window);
947
948 fgeom->borders.invisible.top *= scale;
949 fgeom->borders.invisible.bottom *= scale;
950 fgeom->borders.invisible.left *= scale;
951 fgeom->borders.invisible.right *= scale;
952
953 get_visible_frame_rect (fgeom, window_width, window_height, &frame_rect);
954
955 if (fgeom->top_left_corner_rounded_radius != 0)
956 {
957 const int corner = fgeom->top_left_corner_rounded_radius * scale;
958 const float radius = sqrt(corner) + corner;
959 int i;
960
961 for (i=0; i<corner; i++)
962 {
963 const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
964 rect.x = frame_rect.x;
965 rect.y = frame_rect.y + i;
966 rect.width = width;
967 rect.height = 1;
968
969 cairo_region_union_rectangle (corners_region, &rect);
970 }
971 }
972
973 if (fgeom->top_right_corner_rounded_radius != 0)
974 {
975 const int corner = fgeom->top_right_corner_rounded_radius * scale;
976 const float radius = sqrt(corner) + corner;
977 int i;
978
979 for (i=0; i<corner; i++)
980 {
981 const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
982 rect.x = frame_rect.x + frame_rect.width - width;
983 rect.y = frame_rect.y + i;
984 rect.width = width;
985 rect.height = 1;
986
987 cairo_region_union_rectangle (corners_region, &rect);
988 }
989 }
990
991 if (fgeom->bottom_left_corner_rounded_radius != 0)
992 {
993 const int corner = fgeom->bottom_left_corner_rounded_radius * scale;
994 const float radius = sqrt(corner) + corner;
995 int i;
996
997 for (i=0; i<corner; i++)
998 {
999 const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
1000 rect.x = frame_rect.x;
1001 rect.y = frame_rect.y + frame_rect.height - i - 1;
1002 rect.width = width;
1003 rect.height = 1;
1004
1005 cairo_region_union_rectangle (corners_region, &rect);
1006 }
1007 }
1008
1009 if (fgeom->bottom_right_corner_rounded_radius != 0)
1010 {
1011 const int corner = fgeom->bottom_right_corner_rounded_radius * scale;
1012 const float radius = sqrt(corner) + corner;
1013 int i;
1014
1015 for (i=0; i<corner; i++)
1016 {
1017 const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
1018 rect.x = frame_rect.x + frame_rect.width - width;
1019 rect.y = frame_rect.y + frame_rect.height - i - 1;
1020 rect.width = width;
1021 rect.height = 1;
1022
1023 cairo_region_union_rectangle (corners_region, &rect);
1024 }
1025 }
1026
1027 visible_region = cairo_region_create_rectangle (&frame_rect);
1028 cairo_region_subtract (visible_region, corners_region);
1029 cairo_region_destroy (corners_region);
1030
1031 return visible_region;
1032}
1033
1034static cairo_region_t *
1035get_client_region (MetaFrameGeometry *fgeom,
1036 int window_width,
1037 int window_height)
1038{
1039 cairo_rectangle_int_t rect;
1040
1041 rect.x = fgeom->borders.total.left;
1042 rect.y = fgeom->borders.total.top;
1043 rect.width = window_width - fgeom->borders.total.right - rect.x;
1044 rect.height = window_height - fgeom->borders.total.bottom - rect.y;
1045
1046 return cairo_region_create_rectangle (&rect);
1047}
1048
1049static cairo_region_t *
1050get_frame_region (int window_width,
1051 int window_height)
1052{
1053 cairo_rectangle_int_t rect;
1054
1055 rect.x = 0;
1056 rect.y = 0;
1057 rect.width = window_width;
1058 rect.height = window_height;
1059
1060 return cairo_region_create_rectangle (&rect);
1061}
1062
1063void
1064meta_frames_apply_shapes (MetaFrames *frames,
1065 Window xwindow,
1066 int new_window_width,
1067 int new_window_height,
1068 gboolean window_has_shape)
1069{
1070#ifdef HAVE_SHAPE
1071 /* Apply shapes as if window had new_window_width, new_window_height */
1072 MetaUIFrame *frame;
1073 MetaFrameGeometry fgeom;
1074 cairo_region_t *window_region;
1075 Display *display;
1076 gboolean compositing_manager;
1077
1078 frame = meta_frames_lookup_window (frames, xwindow);
1079 g_return_if_fail (frame != NULL)do { if ((frame != ((void*)0))) { } else { g_return_if_fail_warning
("croma", ((const char*) (__func__)), "frame != NULL"); return
; } } while (0)
;
1080
1081 display = CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ()));
1082
1083 if (frame->shape_applied)
1084 {
1085 meta_topicmeta_topic_real (META_DEBUG_SHAPES,
1086 "Unsetting shape mask on frame 0x%lx\n",
1087 frame->xwindow);
1088
1089 XShapeCombineMask (display, frame->xwindow,
1090 ShapeBounding0, 0, 0, None0L, ShapeSet0);
1091 frame->shape_applied = FALSE(0);
1092 }
1093
1094 meta_frames_calc_geometry (frames, frame, &fgeom);
1095
1096 compositing_manager = meta_prefs_get_compositing_manager ();
1097
1098 if (!window_has_shape && compositing_manager)
1099 return;
1100
1101 window_region = get_visible_region (frames,
1102 frame,
1103 &fgeom,
1104 new_window_width,
1105 new_window_height);
1106
1107 if (window_has_shape)
1108 {
1109 /* The client window is oclock or something and has a shape
1110 * mask. To avoid a round trip to get its shape region, we
1111 * create a fake window that's never mapped, build up our shape
1112 * on that, then combine. Wasting the window is assumed cheaper
1113 * than a round trip, but who really knows for sure.
1114 */
1115 XSetWindowAttributes attrs;
1116 Window shape_window;
1117 Window client_window;
1118 cairo_region_t *frame_region;
1119 cairo_region_t *client_region;
1120 cairo_region_t *tmp_region;
1121 CdkScreen *screen;
1122 int screen_number;
1123
1124 meta_topicmeta_topic_real (META_DEBUG_SHAPES,
1125 "Frame 0x%lx needs to incorporate client shape\n",
1126 frame->xwindow);
1127
1128 screen = ctk_widget_get_screen (CTK_WIDGET (frames)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((frames)), ((ctk_widget_get_type ()))))))
);
1129 screen_number = cdk_x11_screen_get_screen_number (screen);
1130
1131 attrs.override_redirect = True1;
1132
1133 shape_window = XCreateWindow (display,
1134 RootWindow (display, screen_number)((&((_XPrivDisplay)(display))->screens[screen_number])
->root)
,
1135 -5000, -5000,
1136 new_window_width,
1137 new_window_height,
1138 0,
1139 CopyFromParent0L,
1140 CopyFromParent0L,
1141 (Visual *)CopyFromParent0L,
1142 CWOverrideRedirect(1L<<9),
1143 &attrs);
1144
1145 /* Copy the client's shape to the temporary shape_window */
1146 meta_core_get (display, frame->xwindow,
1147 META_CORE_GET_CLIENT_XWINDOW, &client_window,
1148 META_CORE_GET_END);
1149
1150 XShapeCombineShape (display, shape_window, ShapeBounding0,
1151 fgeom.borders.total.left,
1152 fgeom.borders.total.top,
1153 client_window,
1154 ShapeBounding0,
1155 ShapeSet0);
1156
1157 /* Punch the client area out of the normal frame shape,
1158 * then union it with the shape_window's existing shape
1159 */
1160 frame_region = get_frame_region (new_window_width,
1161 new_window_height);
1162 client_region = get_client_region (&fgeom,
1163 new_window_width,
1164 new_window_height);
1165
1166 tmp_region = compositing_manager ? frame_region : window_region;
1167
1168 cairo_region_subtract (tmp_region, client_region);
1169
1170 cairo_region_destroy (client_region);
1171
1172 apply_cairo_region_to_window (display, shape_window,
1173 tmp_region, ShapeUnion1);
1174
1175 cairo_region_destroy (frame_region);
1176
1177 /* Now copy shape_window shape to the real frame */
1178 XShapeCombineShape (display, frame->xwindow, ShapeBounding0,
1179 0, 0,
1180 shape_window,
1181 ShapeBounding0,
1182 ShapeSet0);
1183
1184 XDestroyWindow (display, shape_window);
1185 }
1186 else
1187 {
1188 /* No shape on the client, so just do simple stuff */
1189
1190 meta_topicmeta_topic_real (META_DEBUG_SHAPES,
1191 "Frame 0x%lx has shaped corners\n",
1192 frame->xwindow);
1193
1194 if (!compositing_manager)
1195 apply_cairo_region_to_window (display,
1196 frame->xwindow, window_region,
1197 ShapeSet0);
1198 }
1199
1200 frame->shape_applied = TRUE(!(0));
1201
1202 cairo_region_destroy (window_region);
1203#endif /* HAVE_SHAPE */
1204}
1205
1206cairo_region_t *
1207meta_frames_get_frame_bounds (MetaFrames *frames,
1208 Window xwindow,
1209 int window_width,
1210 int window_height)
1211{
1212 MetaUIFrame *frame;
1213 MetaFrameGeometry fgeom;
1214
1215 frame = meta_frames_lookup_window (frames, xwindow);
1216 g_return_val_if_fail (frame != NULL, NULL)do { if ((frame != ((void*)0))) { } else { g_return_if_fail_warning
("croma", ((const char*) (__func__)), "frame != NULL"); return
(((void*)0)); } } while (0)
;
1217
1218 meta_frames_calc_geometry (frames, frame, &fgeom);
1219
1220 return get_visible_region (frames,
1221 frame,
1222 &fgeom,
1223 window_width,
1224 window_height);
1225}
1226
1227void
1228meta_frames_move_resize_frame (MetaFrames *frames,
1229 Window xwindow,
1230 int x,
1231 int y,
1232 int width,
1233 int height)
1234{
1235 MetaUIFrame *frame = meta_frames_lookup_window (frames, xwindow);
1236 int old_width, old_height;
1237 gint scale;
1238
1239 old_width = cdk_window_get_width (frame->window);
1240 old_height = cdk_window_get_height (frame->window);
1241
1242 scale = cdk_window_get_scale_factor (frame->window);
1243
1244 cdk_window_move_resize (frame->window, x / scale, y / scale, width / scale, height / scale);
1245
1246 if (old_width != width || old_height != height)
1247 invalidate_whole_window (frames, frame);
1248}
1249
1250void
1251meta_frames_queue_draw (MetaFrames *frames,
1252 Window xwindow)
1253{
1254 MetaUIFrame *frame;
1255
1256 frame = meta_frames_lookup_window (frames, xwindow);
1257
1258 invalidate_whole_window (frames, frame);
1259}
1260
1261void
1262meta_frames_set_title (MetaFrames *frames,
1263 Window xwindow,
1264 const char *title)
1265{
1266 MetaUIFrame *frame;
1267
1268 frame = meta_frames_lookup_window (frames, xwindow);
1269
1270 g_assert (frame)do { if (frame) ; else g_assertion_message_expr ("croma", "ui/frames.c"
, 1270, ((const char*) (__func__)), "frame"); } while (0)
;
1271
1272 g_free (frame->title);
1273 frame->title = g_strdup (title)g_strdup_inline (title);
1274
1275 g_clear_object (&frame->text_layout)do { _Static_assert (sizeof *((&frame->text_layout)) ==
sizeof (gpointer), "Expression evaluates to false"); __typeof__
(((&frame->text_layout))) _pp = ((&frame->text_layout
)); __typeof__ (*((&frame->text_layout))) _ptr = *_pp;
*_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while
(0)
;
1276
1277 invalidate_whole_window (frames, frame);
1278}
1279
1280void
1281meta_frames_update_frame_style (MetaFrames *frames,
1282 Window xwindow)
1283{
1284 MetaUIFrame *frame;
1285
1286 frame = meta_frames_lookup_window (frames, xwindow);
1287
1288 g_assert (frame)do { if (frame) ; else g_assertion_message_expr ("croma", "ui/frames.c"
, 1288, ((const char*) (__func__)), "frame"); } while (0)
;
1289
1290 meta_frames_attach_style (frames, frame);
1291 invalidate_whole_window (frames, frame);
1292}
1293
1294void
1295meta_frames_repaint_frame (MetaFrames *frames,
1296 Window xwindow)
1297{
1298 MetaUIFrame *frame;
1299
1300 frame = meta_frames_lookup_window (frames, xwindow);
1301
1302 g_assert (frame)do { if (frame) ; else g_assertion_message_expr ("croma", "ui/frames.c"
, 1302, ((const char*) (__func__)), "frame"); } while (0)
;
1303
1304 /* repaint everything, so the other frame don't
1305 * lag behind if they are exposed
1306 */
1307 cdk_window_process_all_updates ();
1308}
1309
1310static void
1311show_tip_now (MetaFrames *frames)
1312{
1313 const char *tiptext;
1314 MetaUIFrame *frame;
1315 int x, y, root_x, root_y;
1316 Window root, child;
1317 guint mask;
1318 MetaFrameControl control;
1319
1320 frame = frames->last_motion_frame;
1321 if (frame == NULL((void*)0))
1322 return;
1323
1324 XQueryPointer (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())),
1325 frame->xwindow,
1326 &root, &child,
1327 &root_x, &root_y,
1328 &x, &y,
1329 &mask);
1330
1331 control = get_control (frames, frame, x, y);
1332
1333 tiptext = NULL((void*)0);
1334 switch (control)
1335 {
1336 case META_FRAME_CONTROL_TITLE:
1337 break;
1338 case META_FRAME_CONTROL_DELETE:
1339 tiptext = _("Close Window")dgettext ("croma", "Close Window");
1340 break;
1341 case META_FRAME_CONTROL_MENU:
1342 tiptext = _("Window Menu")dgettext ("croma", "Window Menu");
1343 break;
1344 case META_FRAME_CONTROL_APPMENU:
1345 tiptext = _("Window App Menu")dgettext ("croma", "Window App Menu");
1346 break;
1347 case META_FRAME_CONTROL_MINIMIZE:
1348 tiptext = _("Minimize Window")dgettext ("croma", "Minimize Window");
1349 break;
1350 case META_FRAME_CONTROL_MAXIMIZE:
1351 tiptext = _("Maximize Window")dgettext ("croma", "Maximize Window");
1352 break;
1353 case META_FRAME_CONTROL_UNMAXIMIZE:
1354 tiptext = _("Restore Window")dgettext ("croma", "Restore Window");
1355 break;
1356 case META_FRAME_CONTROL_SHADE:
1357 tiptext = _("Roll Up Window")dgettext ("croma", "Roll Up Window");
1358 break;
1359 case META_FRAME_CONTROL_UNSHADE:
1360 tiptext = _("Unroll Window")dgettext ("croma", "Unroll Window");
1361 break;
1362 case META_FRAME_CONTROL_ABOVE:
1363 tiptext = _("Keep Window On Top")dgettext ("croma", "Keep Window On Top");
1364 break;
1365 case META_FRAME_CONTROL_UNABOVE:
1366 tiptext = _("Remove Window From Top")dgettext ("croma", "Remove Window From Top");
1367 break;
1368 case META_FRAME_CONTROL_STICK:
1369 tiptext = _("Always On Visible Workspace")dgettext ("croma", "Always On Visible Workspace");
1370 break;
1371 case META_FRAME_CONTROL_UNSTICK:
1372 tiptext = _("Put Window On Only One Workspace")dgettext ("croma", "Put Window On Only One Workspace");
1373 break;
1374 case META_FRAME_CONTROL_RESIZE_SE:
1375 break;
1376 case META_FRAME_CONTROL_RESIZE_S:
1377 break;
1378 case META_FRAME_CONTROL_RESIZE_SW:
1379 break;
1380 case META_FRAME_CONTROL_RESIZE_N:
1381 break;
1382 case META_FRAME_CONTROL_RESIZE_NE:
1383 break;
1384 case META_FRAME_CONTROL_RESIZE_NW:
1385 break;
1386 case META_FRAME_CONTROL_RESIZE_W:
1387 break;
1388 case META_FRAME_CONTROL_RESIZE_E:
1389 break;
1390 case META_FRAME_CONTROL_NONE:
1391 break;
1392 case META_FRAME_CONTROL_CLIENT_AREA:
1393 break;
1394 }
1395
1396 if (tiptext)
1397 {
1398 MetaFrameGeometry fgeom;
1399 CdkRectangle *rect;
1400 int dx, dy, scale;
1401
1402 meta_frames_calc_geometry (frames, frame, &fgeom);
1403
1404 rect = control_rect (control, &fgeom);
1405 scale = cdk_window_get_scale_factor (frame->window);
1406
1407 /* get conversion delta for root-to-frame coords */
1408 dx = (root_x - x) / scale;
1409 dy = (root_y - y) / scale;
1410
1411 /* Align the tooltip to the button right end if RTL */
1412 if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
1413 dx += rect->width;
1414
1415 meta_fixed_tip_show (rect->x + dx,
1416 rect->y + rect->height + 2 + dy,
1417 tiptext);
1418 }
1419}
1420
1421static gboolean
1422tip_timeout_func (gpointer data)
1423{
1424 MetaFrames *frames;
1425
1426 frames = data;
1427
1428 show_tip_now (frames);
1429
1430 frames->tooltip_timeout = 0;
1431
1432 return FALSE(0);
1433}
1434
1435#define TIP_DELAY450 450
1436static void
1437queue_tip (MetaFrames *frames)
1438{
1439 clear_tip (frames);
1440
1441 frames->tooltip_timeout = g_timeout_add (TIP_DELAY450,
1442 tip_timeout_func,
1443 frames);
1444}
1445
1446static void
1447clear_tip (MetaFrames *frames)
1448{
1449 if (frames->tooltip_timeout)
1450 {
1451 g_source_remove (frames->tooltip_timeout);
1452 frames->tooltip_timeout = 0;
1453 }
1454 meta_fixed_tip_hide ();
1455}
1456
1457static void
1458redraw_control (MetaFrames *frames,
1459 MetaUIFrame *frame,
1460 MetaFrameControl control)
1461{
1462 MetaFrameGeometry fgeom;
1463 CdkRectangle *rect;
1464
1465 meta_frames_calc_geometry (frames, frame, &fgeom);
1466
1467 rect = control_rect (control, &fgeom);
1468
1469 cdk_window_invalidate_rect (frame->window, rect, FALSE(0));
1470 invalidate_cache (frames, frame);
1471}
1472
1473static gboolean
1474meta_frame_titlebar_event (MetaUIFrame *frame,
1475 CdkEventButton *event,
1476 int action)
1477{
1478 MetaFrameFlags flags;
1479
1480 switch (action)
1481 {
1482 case META_ACTION_TITLEBAR_TOGGLE_SHADE:
1483 {
1484 meta_core_get (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow,
1485 META_CORE_GET_FRAME_FLAGS, &flags,
1486 META_CORE_GET_END);
1487
1488 if (flags & META_FRAME_ALLOWS_SHADE)
1489 {
1490 if (flags & META_FRAME_SHADED)
1491 meta_core_unshade (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())),
1492 frame->xwindow,
1493 event->time);
1494 else
1495 meta_core_shade (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())),
1496 frame->xwindow,
1497 event->time);
1498 }
1499 }
1500 break;
1501
1502 case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE:
1503 {
1504 meta_core_get (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow,
1505 META_CORE_GET_FRAME_FLAGS, &flags,
1506 META_CORE_GET_END);
1507
1508 if (flags & META_FRAME_ALLOWS_MAXIMIZE)
1509 {
1510 meta_core_toggle_maximize (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow);
1511 }
1512 }
1513 break;
1514
1515 case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_HORIZONTALLY:
1516 {
1517 meta_core_get (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow,
1518 META_CORE_GET_FRAME_FLAGS, &flags,
1519 META_CORE_GET_END);
1520
1521 if (flags & META_FRAME_ALLOWS_MAXIMIZE)
1522 {
1523 meta_core_toggle_maximize_horizontally (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow);
1524 }
1525 }
1526 break;
1527
1528 case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_VERTICALLY:
1529 {
1530 meta_core_get (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow,
1531 META_CORE_GET_FRAME_FLAGS, &flags,
1532 META_CORE_GET_END);
1533
1534 if (flags & META_FRAME_ALLOWS_MAXIMIZE)
1535 {
1536 meta_core_toggle_maximize_vertically (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow);
1537 }
1538 }
1539 break;
1540
1541 case META_ACTION_TITLEBAR_MINIMIZE:
1542 {
1543 meta_core_get (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow,
1544 META_CORE_GET_FRAME_FLAGS, &flags,
1545 META_CORE_GET_END);
1546
1547 if (flags & META_FRAME_ALLOWS_MINIMIZE)
1548 {
1549 meta_core_minimize (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow);
1550 }
1551 }
1552 break;
1553
1554 case META_ACTION_TITLEBAR_NONE:
1555 /* Yaay, a sane user that doesn't use that other weird crap! */
1556 break;
1557
1558 case META_ACTION_TITLEBAR_LOWER:
1559 meta_core_user_lower_and_unfocus (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())),
1560 frame->xwindow,
1561 event->time);
1562 break;
1563
1564 case META_ACTION_TITLEBAR_MENU:
1565 meta_core_show_window_menu (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())),
1566 frame->xwindow,
1567 event->x_root,
1568 event->y_root,
1569 event->button,
1570 event->time);
1571 break;
1572
1573 case META_ACTION_TITLEBAR_LAST:
1574 break;
1575 }
1576
1577 return TRUE(!(0));
1578}
1579
1580static gboolean
1581meta_frame_double_click_event (MetaUIFrame *frame,
1582 CdkEventButton *event)
1583{
1584 int action = meta_prefs_get_action_double_click_titlebar ();
1585
1586 return meta_frame_titlebar_event (frame, event, action);
1587}
1588
1589static gboolean
1590meta_frame_middle_click_event (MetaUIFrame *frame,
1591 CdkEventButton *event)
1592{
1593 int action = meta_prefs_get_action_middle_click_titlebar();
1594
1595 return meta_frame_titlebar_event (frame, event, action);
1596}
1597
1598static gboolean
1599meta_frame_right_click_event(MetaUIFrame *frame,
1600 CdkEventButton *event)
1601{
1602 int action = meta_prefs_get_action_right_click_titlebar();
1603
1604 return meta_frame_titlebar_event (frame, event, action);
1605}
1606
1607static gboolean
1608meta_frames_button_press_event (CtkWidget *widget,
1609 CdkEventButton *event)
1610{
1611 MetaUIFrame *frame;
1612 MetaFrames *frames;
1613 MetaFrameControl control;
1614
1615 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
1616
1617 /* Remember that the display may have already done something with this event.
1618 * If so there's probably a GrabOp in effect.
1619 */
1620
1621 frame = meta_frames_lookup_window (frames, CDK_WINDOW_XID (event->window)(cdk_x11_window_get_xid (event->window)));
1622 if (frame == NULL((void*)0))
1623 return FALSE(0);
1624
1625 clear_tip (frames);
1626
1627 control = get_control (frames, frame, event->x, event->y);
1628
1629 /* focus on click, even if click was on client area */
1630 if (event->button == 1 &&
1631 !(control == META_FRAME_CONTROL_MINIMIZE ||
1632 control == META_FRAME_CONTROL_DELETE ||
1633 control == META_FRAME_CONTROL_MAXIMIZE))
1634 {
1635 meta_topicmeta_topic_real (META_DEBUG_FOCUS,
1636 "Focusing window with frame 0x%lx due to button 1 press\n",
1637 frame->xwindow);
1638 meta_core_user_focus (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())),
1639 frame->xwindow,
1640 event->time);
1641 }
1642
1643 /* don't do the rest of this if on client area */
1644 if (control == META_FRAME_CONTROL_CLIENT_AREA)
1645 return FALSE(0); /* not on the frame, just passed through from client */
1646
1647 /* We want to shade even if we have a GrabOp, since we'll have a move grab
1648 * if we double click the titlebar.
1649 */
1650 if (control == META_FRAME_CONTROL_TITLE &&
1651 event->button == 1 &&
1652 event->type == CDK_2BUTTON_PRESS)
1653 {
1654 meta_core_end_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), event->time);
1655 return meta_frame_double_click_event (frame, event);
1656 }
1657
1658 if (meta_core_get_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ()))) !=
1659 META_GRAB_OP_NONE)
1660 return FALSE(0); /* already up to something */
1661
1662 if ((event->button == 1 &&
1663 (control == META_FRAME_CONTROL_MINIMIZE ||
1664 control == META_FRAME_CONTROL_DELETE ||
1665 control == META_FRAME_CONTROL_SHADE ||
1666 control == META_FRAME_CONTROL_UNSHADE ||
1667 control == META_FRAME_CONTROL_ABOVE ||
1668 control == META_FRAME_CONTROL_UNABOVE ||
1669 control == META_FRAME_CONTROL_STICK ||
1670 control == META_FRAME_CONTROL_UNSTICK ||
1671 control == META_FRAME_CONTROL_MENU)) ||
1672 (control == META_FRAME_CONTROL_MAXIMIZE ||
1673 control == META_FRAME_CONTROL_UNMAXIMIZE))
1674 {
1675 MetaGrabOp op;
1676
1677 switch (control)
1678 {
1679 case META_FRAME_CONTROL_MINIMIZE:
1680 op = META_GRAB_OP_CLICKING_MINIMIZE;
1681 break;
1682 case META_FRAME_CONTROL_MAXIMIZE:
1683 op = META_GRAB_OP_CLICKING_MAXIMIZE + event->button - 1;
1684 op = op > META_GRAB_OP_CLICKING_MAXIMIZE_HORIZONTAL ? META_GRAB_OP_CLICKING_MAXIMIZE : op;
1685 break;
1686 case META_FRAME_CONTROL_UNMAXIMIZE:
1687 op = META_GRAB_OP_CLICKING_UNMAXIMIZE;
1688 break;
1689 case META_FRAME_CONTROL_DELETE:
1690 op = META_GRAB_OP_CLICKING_DELETE;
1691 break;
1692 case META_FRAME_CONTROL_MENU:
1693 op = META_GRAB_OP_CLICKING_MENU;
1694 break;
1695 case META_FRAME_CONTROL_APPMENU:
1696 op = META_GRAB_OP_CLICKING_APPMENU;
This statement is never executed
1697 break;
1698 case META_FRAME_CONTROL_SHADE:
1699 op = META_GRAB_OP_CLICKING_SHADE;
1700 break;
1701 case META_FRAME_CONTROL_UNSHADE:
1702 op = META_GRAB_OP_CLICKING_UNSHADE;
1703 break;
1704 case META_FRAME_CONTROL_ABOVE:
1705 op = META_GRAB_OP_CLICKING_ABOVE;
1706 break;
1707 case META_FRAME_CONTROL_UNABOVE:
1708 op = META_GRAB_OP_CLICKING_UNABOVE;
1709 break;
1710 case META_FRAME_CONTROL_STICK:
1711 op = META_GRAB_OP_CLICKING_STICK;
1712 break;
1713 case META_FRAME_CONTROL_UNSTICK:
1714 op = META_GRAB_OP_CLICKING_UNSTICK;
1715 break;
1716 default:
1717 g_assert_not_reached ()do { g_assertion_message_expr ("croma", "ui/frames.c", 1717, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
1718 op = META_GRAB_OP_NONE;
1719 }
1720
1721 meta_core_begin_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())),
1722 frame->xwindow,
1723 op,
1724 TRUE(!(0)),
1725 TRUE(!(0)),
1726 event->button,
1727 0,
1728 event->time,
1729 event->x_root,
1730 event->y_root);
1731
1732 frame->prelit_control = control;
1733 redraw_control (frames, frame, control);
1734
1735 if (op == META_GRAB_OP_CLICKING_MENU)
1736 {
1737 MetaFrameGeometry fgeom;
1738 CdkRectangle *rect;
1739 int dx, dy;
1740
1741 meta_frames_calc_geometry (frames, frame, &fgeom);
1742
1743 rect = control_rect (META_FRAME_CONTROL_MENU, &fgeom);
1744
1745 /* get delta to convert to root coords */
1746 dx = event->x_root - event->x;
1747 dy = event->y_root - event->y;
1748
1749 /* Align to the right end of the menu rectangle if RTL */
1750 if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
1751 dx += rect->width;
1752
1753 meta_core_show_window_menu (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())),
1754 frame->xwindow,
1755 rect->x + dx,
1756 rect->y + rect->height + dy,
1757 event->button,
1758 event->time);
1759 }
1760 }
1761 else if (event->button == 1 &&
1762 (control == META_FRAME_CONTROL_RESIZE_SE ||
1763 control == META_FRAME_CONTROL_RESIZE_S ||
1764 control == META_FRAME_CONTROL_RESIZE_SW ||
1765 control == META_FRAME_CONTROL_RESIZE_NE ||
1766 control == META_FRAME_CONTROL_RESIZE_N ||
1767 control == META_FRAME_CONTROL_RESIZE_NW ||
1768 control == META_FRAME_CONTROL_RESIZE_E ||
1769 control == META_FRAME_CONTROL_RESIZE_W))
1770 {
1771 MetaGrabOp op;
1772
1773 op = META_GRAB_OP_NONE;
1774
1775 switch (control)
1776 {
1777 case META_FRAME_CONTROL_RESIZE_SE:
1778 op = META_GRAB_OP_RESIZING_SE;
1779 break;
1780 case META_FRAME_CONTROL_RESIZE_S:
1781 op = META_GRAB_OP_RESIZING_S;
1782 break;
1783 case META_FRAME_CONTROL_RESIZE_SW:
1784 op = META_GRAB_OP_RESIZING_SW;
1785 break;
1786 case META_FRAME_CONTROL_RESIZE_NE:
1787 op = META_GRAB_OP_RESIZING_NE;
1788 break;
1789 case META_FRAME_CONTROL_RESIZE_N:
1790 op = META_GRAB_OP_RESIZING_N;
1791 break;
1792 case META_FRAME_CONTROL_RESIZE_NW:
1793 op = META_GRAB_OP_RESIZING_NW;
1794 break;
1795 case META_FRAME_CONTROL_RESIZE_E:
1796 op = META_GRAB_OP_RESIZING_E;
1797 break;
1798 case META_FRAME_CONTROL_RESIZE_W:
1799 op = META_GRAB_OP_RESIZING_W;
1800 break;
1801 default:
1802 g_assert_not_reached ()do { g_assertion_message_expr ("croma", "ui/frames.c", 1802, (
(const char*) (__func__)), ((void*)0)); } while (0)
;
1803 break;
1804 }
1805
1806 meta_core_begin_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())),
1807 frame->xwindow,
1808 op,
1809 TRUE(!(0)),
1810 TRUE(!(0)),
1811 event->button,
1812 0,
1813 event->time,
1814 event->x_root,
1815 event->y_root);
1816 }
1817 else if (control == META_FRAME_CONTROL_TITLE &&
1818 event->button == 1)
1819 {
1820 MetaFrameFlags flags;
1821
1822 meta_core_get (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow,
1823 META_CORE_GET_FRAME_FLAGS, &flags,
1824 META_CORE_GET_END);
1825
1826 if (flags & META_FRAME_ALLOWS_MOVE)
1827 {
1828 meta_core_begin_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())),
1829 frame->xwindow,
1830 META_GRAB_OP_MOVING,
1831 TRUE(!(0)),
1832 TRUE(!(0)),
1833 event->button,
1834 0,
1835 event->time,
1836 event->x_root,
1837 event->y_root);
1838 }
1839 }
1840 else if (event->button == 2)
1841 {
1842 return meta_frame_middle_click_event (frame, event);
1843 }
1844 else if (event->button == 3)
1845 {
1846 return meta_frame_right_click_event (frame, event);
1847 }
1848
1849 return TRUE(!(0));
1850}
1851
1852void
1853meta_frames_notify_menu_hide (MetaFrames *frames)
1854{
1855 if (meta_core_get_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ()))) ==
1856 META_GRAB_OP_CLICKING_MENU)
1857 {
1858 Window grab_frame;
1859
1860 grab_frame = meta_core_get_grab_frame (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())));
1861
1862 if (grab_frame != None0L)
1863 {
1864 MetaUIFrame *frame;
1865
1866 frame = meta_frames_lookup_window (frames, grab_frame);
1867
1868 if (frame)
1869 {
1870 redraw_control (frames, frame,
1871 META_FRAME_CONTROL_MENU);
1872 meta_core_end_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), CurrentTime0L);
1873 }
1874 }
1875 }
1876}
1877
1878static gboolean
1879meta_frames_button_release_event (CtkWidget *widget,
1880 CdkEventButton *event)
1881{
1882 MetaUIFrame *frame;
1883 MetaFrames *frames;
1884 MetaGrabOp op;
1885
1886 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
1887
1888 frame = meta_frames_lookup_window (frames, CDK_WINDOW_XID (event->window)(cdk_x11_window_get_xid (event->window)));
1889 if (frame == NULL((void*)0))
1890 return FALSE(0);
1891
1892 clear_tip (frames);
1893
1894 op = meta_core_get_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())));
1895
1896 if (op == META_GRAB_OP_NONE)
1897 return FALSE(0);
1898
1899 /* We only handle the releases we handled the presses for (things
1900 * involving frame controls). Window ops that don't require a
1901 * frame are handled in the Xlib part of the code, display.c/window.c
1902 */
1903 if (frame->xwindow == meta_core_get_grab_frame (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ()))) &&
1904 ((int) event->button) == meta_core_get_grab_button (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ()))))
1905 {
1906 MetaFrameControl control;
1907
1908 control = get_control (frames, frame, event->x, event->y);
1909
1910 switch (op)
1911 {
1912 case META_GRAB_OP_CLICKING_MINIMIZE:
1913 if (control == META_FRAME_CONTROL_MINIMIZE)
1914 meta_core_minimize (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow);
1915
1916 meta_core_end_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), event->time);
1917 break;
1918
1919 case META_GRAB_OP_CLICKING_MAXIMIZE:
1920 case META_GRAB_OP_CLICKING_MAXIMIZE_VERTICAL:
1921 case META_GRAB_OP_CLICKING_MAXIMIZE_HORIZONTAL:
1922 if (control == META_FRAME_CONTROL_MAXIMIZE)
1923 {
1924 /* Focus the window on the maximize */
1925 meta_core_user_focus (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())),
1926 frame->xwindow,
1927 event->time);
1928
1929 if (op == META_GRAB_OP_CLICKING_MAXIMIZE)
1930 meta_core_maximize (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow);
1931 if (op == META_GRAB_OP_CLICKING_MAXIMIZE_VERTICAL)
1932 meta_core_toggle_maximize_vertically (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow);
1933 if (op == META_GRAB_OP_CLICKING_MAXIMIZE_HORIZONTAL)
1934 meta_core_toggle_maximize_horizontally (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow);
1935 }
1936 meta_core_end_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), event->time);
1937 break;
1938
1939 case META_GRAB_OP_CLICKING_UNMAXIMIZE:
1940 case META_GRAB_OP_CLICKING_UNMAXIMIZE_VERTICAL:
1941 case META_GRAB_OP_CLICKING_UNMAXIMIZE_HORIZONTAL:
1942 if (control == META_FRAME_CONTROL_UNMAXIMIZE) {
1943 if (op == META_GRAB_OP_CLICKING_UNMAXIMIZE)
1944 meta_core_unmaximize (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow);
1945 if (op == META_GRAB_OP_CLICKING_UNMAXIMIZE_VERTICAL)
1946 meta_core_toggle_maximize_vertically (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow);
1947 if (op == META_GRAB_OP_CLICKING_UNMAXIMIZE_HORIZONTAL)
1948 meta_core_toggle_maximize_horizontally (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow);
1949 }
1950
1951 meta_core_end_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), event->time);
1952 break;
1953
1954 case META_GRAB_OP_CLICKING_DELETE:
1955 if (control == META_FRAME_CONTROL_DELETE)
1956 meta_core_delete (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow, event->time);
1957
1958 meta_core_end_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), event->time);
1959 break;
1960
1961 case META_GRAB_OP_CLICKING_MENU:
1962 case META_GRAB_OP_CLICKING_APPMENU:
1963 meta_core_end_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), event->time);
1964 break;
1965
1966 case META_GRAB_OP_CLICKING_SHADE:
1967 if (control == META_FRAME_CONTROL_SHADE)
1968 meta_core_shade (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow, event->time);
1969
1970 meta_core_end_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), event->time);
1971 break;
1972
1973 case META_GRAB_OP_CLICKING_UNSHADE:
1974 if (control == META_FRAME_CONTROL_UNSHADE)
1975 meta_core_unshade (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow, event->time);
1976
1977 meta_core_end_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), event->time);
1978 break;
1979
1980 case META_GRAB_OP_CLICKING_ABOVE:
1981 if (control == META_FRAME_CONTROL_ABOVE)
1982 meta_core_make_above (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow);
1983
1984 meta_core_end_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), event->time);
1985 break;
1986
1987 case META_GRAB_OP_CLICKING_UNABOVE:
1988 if (control == META_FRAME_CONTROL_UNABOVE)
1989 meta_core_unmake_above (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow);
1990
1991 meta_core_end_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), event->time);
1992 break;
1993
1994 case META_GRAB_OP_CLICKING_STICK:
1995 if (control == META_FRAME_CONTROL_STICK)
1996 meta_core_stick (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow);
1997
1998 meta_core_end_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), event->time);
1999 break;
2000
2001 case META_GRAB_OP_CLICKING_UNSTICK:
2002 if (control == META_FRAME_CONTROL_UNSTICK)
2003 meta_core_unstick (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow);
2004
2005 meta_core_end_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), event->time);
2006 break;
2007
2008 default:
2009 break;
2010 }
2011
2012 /* Update the prelit control regardless of what button the mouse
2013 * was released over; needed so that the new button can become
2014 * prelit so to let the user know that it can now be pressed.
2015 * :)
2016 */
2017 meta_frames_update_prelit_control (frames, frame, control);
2018 }
2019
2020 return TRUE(!(0));
2021}
2022
2023static void
2024meta_frames_update_prelit_control (MetaFrames *frames,
2025 MetaUIFrame *frame,
2026 MetaFrameControl control)
2027{
2028 MetaFrameControl old_control;
2029 MetaCursor cursor;
2030
2031
2032 meta_verbosemeta_verbose_real ("Updating prelit control from %u to %u\n",
2033 frame->prelit_control, control);
2034
2035 cursor = META_CURSOR_DEFAULT;
2036
2037 switch (control)
2038 {
2039 case META_FRAME_CONTROL_CLIENT_AREA:
2040 break;
2041 case META_FRAME_CONTROL_NONE:
2042 break;
2043 case META_FRAME_CONTROL_TITLE:
2044 break;
2045 case META_FRAME_CONTROL_DELETE:
2046 break;
2047 case META_FRAME_CONTROL_MENU:
2048 break;
2049 case META_FRAME_CONTROL_APPMENU:
2050 break;
2051 case META_FRAME_CONTROL_MINIMIZE:
2052 break;
2053 case META_FRAME_CONTROL_MAXIMIZE:
2054 break;
2055 case META_FRAME_CONTROL_UNMAXIMIZE:
2056 break;
2057 case META_FRAME_CONTROL_SHADE:
2058 break;
2059 case META_FRAME_CONTROL_UNSHADE:
2060 break;
2061 case META_FRAME_CONTROL_ABOVE:
2062 break;
2063 case META_FRAME_CONTROL_UNABOVE:
2064 break;
2065 case META_FRAME_CONTROL_STICK:
2066 break;
2067 case META_FRAME_CONTROL_UNSTICK:
2068 break;
2069 case META_FRAME_CONTROL_RESIZE_SE:
2070 cursor = META_CURSOR_SE_RESIZE;
2071 break;
2072 case META_FRAME_CONTROL_RESIZE_S:
2073 cursor = META_CURSOR_SOUTH_RESIZE;
2074 break;
2075 case META_FRAME_CONTROL_RESIZE_SW:
2076 cursor = META_CURSOR_SW_RESIZE;
2077 break;
2078 case META_FRAME_CONTROL_RESIZE_N:
2079 cursor = META_CURSOR_NORTH_RESIZE;
2080 break;
2081 case META_FRAME_CONTROL_RESIZE_NE:
2082 cursor = META_CURSOR_NE_RESIZE;
2083 break;
2084 case META_FRAME_CONTROL_RESIZE_NW:
2085 cursor = META_CURSOR_NW_RESIZE;
2086 break;
2087 case META_FRAME_CONTROL_RESIZE_W:
2088 cursor = META_CURSOR_WEST_RESIZE;
2089 break;
2090 case META_FRAME_CONTROL_RESIZE_E:
2091 cursor = META_CURSOR_EAST_RESIZE;
2092 break;
2093 }
2094
2095 /* set/unset the prelight cursor */
2096 meta_core_set_screen_cursor (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())),
2097 frame->xwindow,
2098 cursor);
2099
2100 switch (control)
2101 {
2102 case META_FRAME_CONTROL_MENU:
2103 case META_FRAME_CONTROL_APPMENU:
2104 case META_FRAME_CONTROL_MINIMIZE:
2105 case META_FRAME_CONTROL_MAXIMIZE:
2106 case META_FRAME_CONTROL_DELETE:
2107 case META_FRAME_CONTROL_SHADE:
2108 case META_FRAME_CONTROL_UNSHADE:
2109 case META_FRAME_CONTROL_ABOVE:
2110 case META_FRAME_CONTROL_UNABOVE:
2111 case META_FRAME_CONTROL_STICK:
2112 case META_FRAME_CONTROL_UNSTICK:
2113 case META_FRAME_CONTROL_UNMAXIMIZE:
2114 /* leave control set */
2115 break;
2116 default:
2117 /* Only prelight buttons */
2118 control = META_FRAME_CONTROL_NONE;
2119 break;
2120 }
2121
2122 if (control == frame->prelit_control)
2123 return;
2124
2125 /* Save the old control so we can unprelight it */
2126 old_control = frame->prelit_control;
2127
2128 frame->prelit_control = control;
2129
2130 redraw_control (frames, frame, old_control);
2131 redraw_control (frames, frame, control);
2132}
2133
2134static gboolean
2135meta_frames_motion_notify_event (CtkWidget *widget,
2136 CdkEventMotion *event)
2137{
2138 MetaUIFrame *frame;
2139 MetaFrames *frames;
2140 MetaGrabOp grab_op;
2141
2142 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
2143
2144 frame = meta_frames_lookup_window (frames, CDK_WINDOW_XID (event->window)(cdk_x11_window_get_xid (event->window)));
2145 if (frame == NULL((void*)0))
2146 return FALSE(0);
2147
2148 clear_tip (frames);
2149
2150 frames->last_motion_frame = frame;
2151
2152 grab_op = meta_core_get_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())));
2153
2154 switch (grab_op)
2155 {
2156 case META_GRAB_OP_CLICKING_MENU:
2157 case META_GRAB_OP_CLICKING_APPMENU:
2158 case META_GRAB_OP_CLICKING_DELETE:
2159 case META_GRAB_OP_CLICKING_MINIMIZE:
2160 case META_GRAB_OP_CLICKING_MAXIMIZE:
2161 case META_GRAB_OP_CLICKING_MAXIMIZE_VERTICAL:
2162 case META_GRAB_OP_CLICKING_MAXIMIZE_HORIZONTAL:
2163 case META_GRAB_OP_CLICKING_UNMAXIMIZE:
2164 case META_GRAB_OP_CLICKING_UNMAXIMIZE_VERTICAL:
2165 case META_GRAB_OP_CLICKING_UNMAXIMIZE_HORIZONTAL:
2166 case META_GRAB_OP_CLICKING_SHADE:
2167 case META_GRAB_OP_CLICKING_UNSHADE:
2168 case META_GRAB_OP_CLICKING_ABOVE:
2169 case META_GRAB_OP_CLICKING_UNABOVE:
2170 case META_GRAB_OP_CLICKING_STICK:
2171 case META_GRAB_OP_CLICKING_UNSTICK:
2172 {
2173 MetaFrameControl control;
2174 int x, y, scale;
2175
2176 cdk_window_get_device_position (frame->window, event->device,
2177 &x, &y, NULL((void*)0));
2178 scale = cdk_window_get_scale_factor (frame->window);
2179 x *= scale;
2180 y *= scale;
2181
2182 /* Control is set to none unless it matches
2183 * the current grab
2184 */
2185 control = get_control (frames, frame, x, y);
2186 if (! ((control == META_FRAME_CONTROL_MENU &&
2187 grab_op == META_GRAB_OP_CLICKING_MENU) ||
2188 (control == META_FRAME_CONTROL_APPMENU &&
2189 grab_op == META_GRAB_OP_CLICKING_APPMENU) ||
2190 (control == META_FRAME_CONTROL_DELETE &&
2191 grab_op == META_GRAB_OP_CLICKING_DELETE) ||
2192 (control == META_FRAME_CONTROL_MINIMIZE &&
2193 grab_op == META_GRAB_OP_CLICKING_MINIMIZE) ||
2194 ((control == META_FRAME_CONTROL_MAXIMIZE ||
2195 control == META_FRAME_CONTROL_UNMAXIMIZE) &&
2196 (grab_op == META_GRAB_OP_CLICKING_MAXIMIZE ||
2197 grab_op == META_GRAB_OP_CLICKING_MAXIMIZE_VERTICAL ||
2198 grab_op == META_GRAB_OP_CLICKING_MAXIMIZE_HORIZONTAL ||
2199 grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE ||
2200 grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE_VERTICAL ||
2201 grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE_HORIZONTAL)) ||
2202 (control == META_FRAME_CONTROL_SHADE &&
2203 grab_op == META_GRAB_OP_CLICKING_SHADE) ||
2204 (control == META_FRAME_CONTROL_UNSHADE &&
2205 grab_op == META_GRAB_OP_CLICKING_UNSHADE) ||
2206 (control == META_FRAME_CONTROL_ABOVE &&
2207 grab_op == META_GRAB_OP_CLICKING_ABOVE) ||
2208 (control == META_FRAME_CONTROL_UNABOVE &&
2209 grab_op == META_GRAB_OP_CLICKING_UNABOVE) ||
2210 (control == META_FRAME_CONTROL_STICK &&
2211 grab_op == META_GRAB_OP_CLICKING_STICK) ||
2212 (control == META_FRAME_CONTROL_UNSTICK &&
2213 grab_op == META_GRAB_OP_CLICKING_UNSTICK)))
2214 control = META_FRAME_CONTROL_NONE;
2215
2216 /* Update prelit control and cursor */
2217 meta_frames_update_prelit_control (frames, frame, control);
2218
2219 /* No tooltip while in the process of clicking */
2220 }
2221 break;
2222 case META_GRAB_OP_NONE:
2223 {
2224 MetaFrameControl control;
2225 int x, y, scale;
2226
2227 cdk_window_get_device_position (frame->window, event->device,
2228 &x, &y, NULL((void*)0));
2229 scale = cdk_window_get_scale_factor (frame->window);
2230 x *= scale;
2231 y *= scale;
2232
2233 control = get_control (frames, frame, x, y);
2234
2235 /* Update prelit control and cursor */
2236 meta_frames_update_prelit_control (frames, frame, control);
2237
2238 queue_tip (frames);
2239 }
2240 break;
2241
2242 default:
2243 break;
2244 }
2245
2246 return TRUE(!(0));
2247}
2248
2249static gboolean
2250meta_frames_destroy_event (CtkWidget *widget,
2251 CdkEventAny *event)
2252{
2253 MetaUIFrame *frame;
2254 MetaFrames *frames;
2255
2256 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
2257
2258 frame = meta_frames_lookup_window (frames, CDK_WINDOW_XID (event->window)(cdk_x11_window_get_xid (event->window)));
2259 if (frame == NULL((void*)0))
2260 return FALSE(0);
2261
2262 return TRUE(!(0));
2263}
2264
2265/* Returns a pixmap with a piece of the windows frame painted on it.
2266*/
2267static cairo_surface_t *
2268generate_pixmap (MetaFrames *frames,
2269 MetaUIFrame *frame,
2270 cairo_rectangle_int_t *rect)
2271{
2272 cairo_surface_t *result;
2273 cairo_t *cr;
2274
2275 /* do not create a pixmap for nonexisting areas */
2276 if (rect->width <= 0 || rect->height <= 0)
2277 return NULL((void*)0);
2278
2279 result = cdk_window_create_similar_surface (frame->window,
2280 CAIRO_CONTENT_COLOR_ALPHA,
2281 rect->width, rect->height);
2282
2283 cr = cairo_create (result);
2284 cairo_translate (cr, -rect->x, -rect->y);
2285
2286 cairo_paint (cr);
2287
2288 meta_frames_paint_to_drawable (frames, frame, cr);
2289
2290 cairo_destroy (cr);
2291
2292 return result;
2293}
2294
2295static void
2296populate_cache (MetaFrames *frames,
2297 MetaUIFrame *frame)
2298{
2299 MetaFrameBorders borders;
2300 int width, height;
2301 int frame_width, frame_height, screen_width, screen_height;
2302 CachedPixels *pixels;
2303 MetaFrameType frame_type;
2304 MetaFrameFlags frame_flags;
2305 int i;
2306
2307 meta_core_get (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow,
2308 META_CORE_GET_FRAME_WIDTH, &frame_width,
2309 META_CORE_GET_FRAME_HEIGHT, &frame_height,
2310 META_CORE_GET_SCREEN_WIDTH, &screen_width,
2311 META_CORE_GET_SCREEN_HEIGHT, &screen_height,
2312 META_CORE_GET_CLIENT_WIDTH, &width,
2313 META_CORE_GET_CLIENT_HEIGHT, &height,
2314 META_CORE_GET_FRAME_TYPE, &frame_type,
2315 META_CORE_GET_FRAME_FLAGS, &frame_flags,
2316 META_CORE_GET_END);
2317
2318 /* don't cache extremely large windows */
2319 if (frame_width > 2 * screen_width ||
2320 frame_height > 2 * screen_height)
2321 {
2322 return;
2323 }
2324
2325 meta_theme_get_frame_borders (meta_theme_get_current (),
2326 frame_type,
2327 frame->text_height,
2328 frame_flags,
2329 &borders);
2330
2331 pixels = get_cache (frames, frame);
2332
2333 /* Setup the rectangles for the four visible frame borders. First top, then
2334 * left, right and bottom. Top and bottom extend to the invisible borders
2335 * while left and right snugly fit in between:
2336 * -----
2337 * | |
2338 * -----
2339 */
2340
2341 /* width and height refer to the client window's
2342 * size without any border added. */
2343
2344 /* top */
2345 pixels->piece[0].rect.x = 0;
2346 pixels->piece[0].rect.y = 0;
2347 pixels->piece[0].rect.width = width + borders.total.left + borders.total.right;
2348 pixels->piece[0].rect.height = borders.total.top;
2349
2350 /* left */
2351 pixels->piece[1].rect.x = 0;
2352 pixels->piece[1].rect.y = borders.total.top;
2353 pixels->piece[1].rect.width = borders.total.left;
2354 pixels->piece[1].rect.height = height;
2355
2356 /* right */
2357 pixels->piece[2].rect.x = borders.total.left + width;
2358 pixels->piece[2].rect.y = borders.total.top;
2359 pixels->piece[2].rect.width = borders.total.right;
2360 pixels->piece[2].rect.height = height;
2361
2362 /* bottom */
2363 pixels->piece[3].rect.x = 0;
2364 pixels->piece[3].rect.y = borders.total.top + height;
2365 pixels->piece[3].rect.width = width + borders.total.left + borders.total.right;
2366 pixels->piece[3].rect.height = borders.total.bottom;
2367
2368 for (i = 0; i < 4; i++)
2369 {
2370 CachedFramePiece *piece = &pixels->piece[i];
2371 if (!piece->pixmap)
2372 piece->pixmap = generate_pixmap (frames, frame, &piece->rect);
2373 }
2374
2375 if (frames->invalidate_cache_timeout_id)
2376 g_source_remove (frames->invalidate_cache_timeout_id);
2377
2378 frames->invalidate_cache_timeout_id = g_timeout_add (1000, invalidate_cache_timeout, frames);
2379
2380 if (!g_list_find (frames->invalidate_frames, frame))
2381 frames->invalidate_frames =
2382 g_list_prepend (frames->invalidate_frames, frame);
2383}
2384
2385static void
2386clip_to_screen (cairo_region_t *region, MetaUIFrame *frame)
2387{
2388 CdkRectangle frame_area;
2389 CdkRectangle screen_area = { 0, 0, 0, 0 };
2390 cairo_region_t *tmp_region;
2391
2392 /* Chop off stuff outside the screen; this optimization
2393 * is crucial to handle huge client windows,
2394 * like "xterm -geometry 1000x1000"
2395 */
2396 meta_core_get (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow,
2397 META_CORE_GET_FRAME_X, &frame_area.x,
2398 META_CORE_GET_FRAME_Y, &frame_area.y,
2399 META_CORE_GET_FRAME_WIDTH, &frame_area.width,
2400 META_CORE_GET_FRAME_HEIGHT, &frame_area.height,
2401 META_CORE_GET_SCREEN_WIDTH, &screen_area.width,
2402 META_CORE_GET_SCREEN_HEIGHT, &screen_area.height,
2403 META_CORE_GET_END);
2404
2405 cairo_region_translate (region, frame_area.x, frame_area.y);
2406
2407 tmp_region = cairo_region_create_rectangle (&frame_area);
2408 cairo_region_intersect (region, tmp_region);
2409 cairo_region_destroy (tmp_region);
2410
2411 cairo_region_translate (region, - frame_area.x, - frame_area.y);
2412}
2413
2414static void
2415subtract_client_area (cairo_region_t *region,
2416 MetaUIFrame *frame)
2417{
2418 cairo_rectangle_int_t area;
2419 MetaFrameFlags flags;
2420 MetaFrameType type;
2421 MetaFrameBorders borders;
2422 cairo_region_t *tmp_region;
2423 Display *display;
2424 gint scale;
2425
2426 display = CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ()));
2427 scale = cdk_window_get_scale_factor (frame->window);
2428
2429 meta_core_get (display, frame->xwindow,
2430 META_CORE_GET_FRAME_FLAGS, &flags,
2431 META_CORE_GET_FRAME_TYPE, &type,
2432 META_CORE_GET_CLIENT_WIDTH, &area.width,
2433 META_CORE_GET_CLIENT_HEIGHT, &area.height,
2434 META_CORE_GET_END);
2435 meta_theme_get_frame_borders (meta_theme_get_current (),
2436 type, frame->text_height, flags,
2437 &borders);
2438
2439 area.width /= scale;
2440 area.height /= scale;
2441 area.x = borders.total.left / scale;
2442 area.y = borders.total.top / scale;
2443
2444 tmp_region = cairo_region_create_rectangle (&area);
2445 cairo_region_subtract (region, tmp_region);
2446 cairo_region_destroy (tmp_region);
2447}
2448
2449static void
2450cached_pixels_draw (CachedPixels *pixels,
2451 cairo_t *cr,
2452 cairo_region_t *region)
2453{
2454 cairo_region_t *region_piece;
2455 int i;
2456
2457 for (i = 0; i < 4; i++)
2458 {
2459 CachedFramePiece *piece;
2460 piece = &pixels->piece[i];
2461
2462 if (piece->pixmap)
2463 {
2464 cairo_set_source_surface (cr, piece->pixmap,
2465 piece->rect.x, piece->rect.y);
2466 cairo_paint (cr);
2467
2468 region_piece = cairo_region_create_rectangle (&piece->rect);
2469 cairo_region_subtract (region, region_piece);
2470 cairo_region_destroy (region_piece);
2471 }
2472 }
2473}
2474
2475static MetaUIFrame *
2476find_frame_to_draw (MetaFrames *frames,
2477 cairo_t *cr)
2478{
2479 GHashTableIter iter;
2480 MetaUIFrame *frame;
2481
2482 g_hash_table_iter_init (&iter, frames->frames);
2483 while (g_hash_table_iter_next (&iter, NULL((void*)0), (gpointer *) &frame))
2484 if (ctk_cairo_should_draw_window (cr, frame->window))
2485 return frame;
2486
2487 return NULL((void*)0);
2488}
2489
2490static gboolean
2491meta_frames_draw (CtkWidget *widget,
2492 cairo_t *cr)
2493{
2494 MetaUIFrame *frame;
2495 MetaFrames *frames;
2496 CachedPixels *pixels;
2497 cairo_region_t *region;
2498 cairo_rectangle_int_t clip;
2499 int i, n_areas;
2500
2501 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
2502 cdk_cairo_get_clip_rectangle (cr, &clip);
2503
2504 frame = find_frame_to_draw (frames, cr);
2505
2506 if (frame == NULL((void*)0))
2507 return FALSE(0);
2508
2509 if (frames->expose_delay_count > 0)
2510 {
2511 /* Redraw this entire frame later */
2512 frame->expose_delayed = TRUE(!(0));
2513 return TRUE(!(0));
2514 }
2515
2516 populate_cache (frames, frame);
2517
2518 region = cairo_region_create_rectangle (&clip);
2519
2520 pixels = get_cache (frames, frame);
2521
2522 cached_pixels_draw (pixels, cr, region);
2523
2524 clip_to_screen (region, frame);
2525 subtract_client_area (region, frame);
2526
2527 n_areas = cairo_region_num_rectangles (region);
2528
2529 for (i = 0; i < n_areas; i++)
2530 {
2531 cairo_rectangle_int_t area;
2532
2533 cairo_region_get_rectangle (region, i, &area);
2534
2535 cairo_save (cr);
2536
2537 cairo_rectangle (cr, area.x, area.y, area.width, area.height);
2538 cairo_clip (cr);
2539
2540 cairo_push_group (cr);
2541
2542 meta_frames_paint_to_drawable (frames, frame, cr);
2543
2544 cairo_pop_group_to_source (cr);
2545 cairo_paint (cr);
2546
2547 cairo_restore (cr);
2548 }
2549
2550 cairo_region_destroy (region);
2551
2552 return TRUE(!(0));
2553}
2554
2555/* How far off the screen edge the window decorations should
2556 * be drawn. Used only in meta_frames_paint_to_drawable, below.
2557 */
2558#define DECORATING_BORDER100 100
2559
2560static void
2561meta_frames_paint_to_drawable (MetaFrames *frames,
2562 MetaUIFrame *frame,
2563 cairo_t *cr)
2564{
2565 MetaFrameFlags flags;
2566 MetaFrameType type;
2567 GdkPixbuf *mini_icon;
2568 GdkPixbuf *icon;
2569 int w, h, scale;
2570 MetaButtonState button_states[META_BUTTON_TYPE_LAST];
2571 Window grab_frame;
2572 int i;
2573 MetaButtonLayout button_layout;
2574 MetaGrabOp grab_op;
2575
2576 for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
2577 button_states[i] = META_BUTTON_STATE_NORMAL;
2578
2579 grab_frame = meta_core_get_grab_frame (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())));
2580 grab_op = meta_core_get_grab_op (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())));
2581 if (grab_frame != frame->xwindow)
2582 grab_op = META_GRAB_OP_NONE;
2583
2584 /* Set prelight state */
2585 switch (frame->prelit_control)
2586 {
2587 case META_FRAME_CONTROL_MENU:
2588 if (grab_op == META_GRAB_OP_CLICKING_MENU)
2589 button_states[META_BUTTON_TYPE_MENU] = META_BUTTON_STATE_PRESSED;
2590 else
2591 button_states[META_BUTTON_TYPE_MENU] = META_BUTTON_STATE_PRELIGHT;
2592 break;
2593 case META_FRAME_CONTROL_APPMENU:
2594 if (grab_op == META_GRAB_OP_CLICKING_MENU)
2595 button_states[META_BUTTON_TYPE_APPMENU] = META_BUTTON_STATE_PRESSED;
2596 else
2597 button_states[META_BUTTON_TYPE_APPMENU] = META_BUTTON_STATE_PRELIGHT;
2598 break;
2599 case META_FRAME_CONTROL_MINIMIZE:
2600 if (grab_op == META_GRAB_OP_CLICKING_MINIMIZE)
2601 button_states[META_BUTTON_TYPE_MINIMIZE] = META_BUTTON_STATE_PRESSED;
2602 else
2603 button_states[META_BUTTON_TYPE_MINIMIZE] = META_BUTTON_STATE_PRELIGHT;
2604 break;
2605 case META_FRAME_CONTROL_MAXIMIZE:
2606 if (grab_op == META_GRAB_OP_CLICKING_MAXIMIZE || grab_op == META_GRAB_OP_CLICKING_MAXIMIZE_VERTICAL ||
2607 grab_op == META_GRAB_OP_CLICKING_MAXIMIZE_HORIZONTAL)
2608 button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRESSED;
2609 else
2610 button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT;
2611 break;
2612 case META_FRAME_CONTROL_UNMAXIMIZE:
2613 if (grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE || grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE_VERTICAL ||
2614 grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE_HORIZONTAL)
2615 button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRESSED;
2616 else
2617 button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT;
2618 break;
2619 case META_FRAME_CONTROL_SHADE:
2620 if (grab_op == META_GRAB_OP_CLICKING_SHADE)
2621 button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRESSED;
2622 else
2623 button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRELIGHT;
2624 break;
2625 case META_FRAME_CONTROL_UNSHADE:
2626 if (grab_op == META_GRAB_OP_CLICKING_UNSHADE)
2627 button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRESSED;
2628 else
2629 button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRELIGHT;
2630 break;
2631 case META_FRAME_CONTROL_ABOVE:
2632 if (grab_op == META_GRAB_OP_CLICKING_ABOVE)
2633 button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRESSED;
2634 else
2635 button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRELIGHT;
2636 break;
2637 case META_FRAME_CONTROL_UNABOVE:
2638 if (grab_op == META_GRAB_OP_CLICKING_UNABOVE)
2639 button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRESSED;
2640 else
2641 button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRELIGHT;
2642 break;
2643 case META_FRAME_CONTROL_STICK:
2644 if (grab_op == META_GRAB_OP_CLICKING_STICK)
2645 button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRESSED;
2646 else
2647 button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRELIGHT;
2648 break;
2649 case META_FRAME_CONTROL_UNSTICK:
2650 if (grab_op == META_GRAB_OP_CLICKING_UNSTICK)
2651 button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRESSED;
2652 else
2653 button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRELIGHT;
2654 break;
2655 case META_FRAME_CONTROL_DELETE:
2656 if (grab_op == META_GRAB_OP_CLICKING_DELETE)
2657 button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRESSED;
2658 else
2659 button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRELIGHT;
2660 break;
2661 default:
2662 break;
2663 }
2664
2665 meta_core_get (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow,
2666 META_CORE_GET_FRAME_FLAGS, &flags,
2667 META_CORE_GET_FRAME_TYPE, &type,
2668 META_CORE_GET_MINI_ICON, &mini_icon,
2669 META_CORE_GET_ICON, &icon,
2670 META_CORE_GET_CLIENT_WIDTH, &w,
2671 META_CORE_GET_CLIENT_HEIGHT, &h,
2672 META_CORE_GET_END);
2673
2674 meta_frames_ensure_layout (frames, frame);
2675
2676 meta_prefs_get_button_layout (&button_layout);
2677
2678 scale = cdk_window_get_scale_factor (frame->window);
2679 meta_theme_draw_frame (meta_theme_get_current (),
2680 frame->style,
2681 cr,
2682 type,
2683 flags,
2684 w / scale,
2685 h / scale,
2686 frame->text_layout,
2687 frame->text_height,
2688 &button_layout,
2689 button_states,
2690 mini_icon,
2691 icon);
2692}
2693
2694static gboolean
2695meta_frames_enter_notify_event (CtkWidget *widget,
2696 CdkEventCrossing *event)
2697{
2698 MetaUIFrame *frame;
2699 MetaFrames *frames;
2700 MetaFrameControl control;
2701
2702 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
2703
2704 frame = meta_frames_lookup_window (frames, CDK_WINDOW_XID (event->window)(cdk_x11_window_get_xid (event->window)));
2705 if (frame == NULL((void*)0))
2706 return FALSE(0);
2707
2708 control = get_control (frames, frame, event->x, event->y);
2709 meta_frames_update_prelit_control (frames, frame, control);
2710
2711 return TRUE(!(0));
2712}
2713
2714static gboolean
2715meta_frames_leave_notify_event (CtkWidget *widget,
2716 CdkEventCrossing *event)
2717{
2718 MetaUIFrame *frame;
2719 MetaFrames *frames;
2720
2721 frames = META_FRAMES (widget)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((widget)), ((meta_frames_get_type ()))))))
;
2722
2723 frame = meta_frames_lookup_window (frames, CDK_WINDOW_XID (event->window)(cdk_x11_window_get_xid (event->window)));
2724 if (frame == NULL((void*)0))
2725 return FALSE(0);
2726
2727 meta_frames_update_prelit_control (frames, frame, META_FRAME_CONTROL_NONE);
2728
2729 clear_tip (frames);
2730
2731 return TRUE(!(0));
2732}
2733
2734static CdkRectangle*
2735control_rect (MetaFrameControl control,
2736 MetaFrameGeometry *fgeom)
2737{
2738 CdkRectangle *rect;
2739
2740 rect = NULL((void*)0);
2741 switch (control)
2742 {
2743 case META_FRAME_CONTROL_TITLE:
2744 rect = &fgeom->title_rect;
2745 break;
2746 case META_FRAME_CONTROL_DELETE:
2747 rect = &fgeom->close_rect.visible;
2748 break;
2749 case META_FRAME_CONTROL_MENU:
2750 rect = &fgeom->menu_rect.visible;
2751 break;
2752 case META_FRAME_CONTROL_APPMENU:
2753 rect = &fgeom->appmenu_rect.visible;
2754 break;
2755 case META_FRAME_CONTROL_MINIMIZE:
2756 rect = &fgeom->min_rect.visible;
2757 break;
2758 case META_FRAME_CONTROL_MAXIMIZE:
2759 case META_FRAME_CONTROL_UNMAXIMIZE:
2760 rect = &fgeom->max_rect.visible;
2761 break;
2762 case META_FRAME_CONTROL_SHADE:
2763 rect = &fgeom->shade_rect.visible;
2764 break;
2765 case META_FRAME_CONTROL_UNSHADE:
2766 rect = &fgeom->unshade_rect.visible;
2767 break;
2768 case META_FRAME_CONTROL_ABOVE:
2769 rect = &fgeom->above_rect.visible;
2770 break;
2771 case META_FRAME_CONTROL_UNABOVE:
2772 rect = &fgeom->unabove_rect.visible;
2773 break;
2774 case META_FRAME_CONTROL_STICK:
2775 rect = &fgeom->stick_rect.visible;
2776 break;
2777 case META_FRAME_CONTROL_UNSTICK:
2778 rect = &fgeom->unstick_rect.visible;
2779 break;
2780 case META_FRAME_CONTROL_RESIZE_SE:
2781 break;
2782 case META_FRAME_CONTROL_RESIZE_S:
2783 break;
2784 case META_FRAME_CONTROL_RESIZE_SW:
2785 break;
2786 case META_FRAME_CONTROL_RESIZE_N:
2787 break;
2788 case META_FRAME_CONTROL_RESIZE_NE:
2789 break;
2790 case META_FRAME_CONTROL_RESIZE_NW:
2791 break;
2792 case META_FRAME_CONTROL_RESIZE_W:
2793 break;
2794 case META_FRAME_CONTROL_RESIZE_E:
2795 break;
2796 case META_FRAME_CONTROL_NONE:
2797 break;
2798 case META_FRAME_CONTROL_CLIENT_AREA:
2799 break;
2800 }
2801
2802 return rect;
2803}
2804
2805#define RESIZE_EXTENDS15 15
2806#define TOP_RESIZE_HEIGHT4 4
2807static MetaFrameControl
2808get_control (MetaFrames *frames,
2809 MetaUIFrame *frame,
2810 int x, int y)
2811{
2812 MetaFrameGeometry fgeom;
2813 MetaFrameFlags flags;
2814 gboolean has_vert, has_horiz;
2815 CdkRectangle client;
2816 gint scale;
2817
2818 scale = cdk_window_get_scale_factor (frame->window);
2819 x /= scale;
2820 y /= scale;
2821
2822 meta_frames_calc_geometry (frames, frame, &fgeom);
2823 get_client_rect (&fgeom, fgeom.width, fgeom.height, &client);
2824
2825 if (POINT_IN_RECT (x, y, client)((x) >= (client).x && (x) < ((client).x + (client
).width) && (y) >= (client).y && (y) < (
(client).y + (client).height))
)
2826 return META_FRAME_CONTROL_CLIENT_AREA;
2827
2828 if (POINT_IN_RECT (x, y, fgeom.close_rect.clickable)((x) >= (fgeom.close_rect.clickable).x && (x) <
((fgeom.close_rect.clickable).x + (fgeom.close_rect.clickable
).width) && (y) >= (fgeom.close_rect.clickable).y &&
(y) < ((fgeom.close_rect.clickable).y + (fgeom.close_rect
.clickable).height))
)
2829 return META_FRAME_CONTROL_DELETE;
2830
2831 if (POINT_IN_RECT (x, y, fgeom.min_rect.clickable)((x) >= (fgeom.min_rect.clickable).x && (x) < (
(fgeom.min_rect.clickable).x + (fgeom.min_rect.clickable).width
) && (y) >= (fgeom.min_rect.clickable).y &&
(y) < ((fgeom.min_rect.clickable).y + (fgeom.min_rect.clickable
).height))
)
2832 return META_FRAME_CONTROL_MINIMIZE;
2833
2834 if (POINT_IN_RECT (x, y, fgeom.menu_rect.clickable)((x) >= (fgeom.menu_rect.clickable).x && (x) < (
(fgeom.menu_rect.clickable).x + (fgeom.menu_rect.clickable).width
) && (y) >= (fgeom.menu_rect.clickable).y &&
(y) < ((fgeom.menu_rect.clickable).y + (fgeom.menu_rect.clickable
).height))
)
2835 return META_FRAME_CONTROL_MENU;
2836
2837 if (POINT_IN_RECT (x, y, fgeom.appmenu_rect.clickable)((x) >= (fgeom.appmenu_rect.clickable).x && (x) <
((fgeom.appmenu_rect.clickable).x + (fgeom.appmenu_rect.clickable
).width) && (y) >= (fgeom.appmenu_rect.clickable).
y && (y) < ((fgeom.appmenu_rect.clickable).y + (fgeom
.appmenu_rect.clickable).height))
)
2838 return META_FRAME_CONTROL_APPMENU;
2839
2840 meta_core_get (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())), frame->xwindow,
2841 META_CORE_GET_FRAME_FLAGS, &flags,
2842 META_CORE_GET_END);
2843
2844 has_vert = (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE) != 0;
2845 has_horiz = (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE) != 0;
2846
2847 if (POINT_IN_RECT (x, y, fgeom.title_rect)((x) >= (fgeom.title_rect).x && (x) < ((fgeom.title_rect
).x + (fgeom.title_rect).width) && (y) >= (fgeom.title_rect
).y && (y) < ((fgeom.title_rect).y + (fgeom.title_rect
).height))
)
2848 {
2849 if (has_vert && y <= TOP_RESIZE_HEIGHT4 * scale)
2850 return META_FRAME_CONTROL_RESIZE_N;
2851 else
2852 return META_FRAME_CONTROL_TITLE;
2853 }
2854
2855 if (POINT_IN_RECT (x, y, fgeom.max_rect.clickable)((x) >= (fgeom.max_rect.clickable).x && (x) < (
(fgeom.max_rect.clickable).x + (fgeom.max_rect.clickable).width
) && (y) >= (fgeom.max_rect.clickable).y &&
(y) < ((fgeom.max_rect.clickable).y + (fgeom.max_rect.clickable
).height))
)
2856 {
2857 if (flags & META_FRAME_MAXIMIZED)
2858 return META_FRAME_CONTROL_UNMAXIMIZE;
2859 else
2860 return META_FRAME_CONTROL_MAXIMIZE;
2861 }
2862
2863 if (POINT_IN_RECT (x, y, fgeom.shade_rect.clickable)((x) >= (fgeom.shade_rect.clickable).x && (x) <
((fgeom.shade_rect.clickable).x + (fgeom.shade_rect.clickable
).width) && (y) >= (fgeom.shade_rect.clickable).y &&
(y) < ((fgeom.shade_rect.clickable).y + (fgeom.shade_rect
.clickable).height))
)
2864 {
2865 return META_FRAME_CONTROL_SHADE;
2866 }
2867
2868 if (POINT_IN_RECT (x, y, fgeom.unshade_rect.clickable)((x) >= (fgeom.unshade_rect.clickable).x && (x) <
((fgeom.unshade_rect.clickable).x + (fgeom.unshade_rect.clickable
).width) && (y) >= (fgeom.unshade_rect.clickable).
y && (y) < ((fgeom.unshade_rect.clickable).y + (fgeom
.unshade_rect.clickable).height))
)
2869 {
2870 return META_FRAME_CONTROL_UNSHADE;
2871 }
2872
2873 if (POINT_IN_RECT (x, y, fgeom.above_rect.clickable)((x) >= (fgeom.above_rect.clickable).x && (x) <
((fgeom.above_rect.clickable).x + (fgeom.above_rect.clickable
).width) && (y) >= (fgeom.above_rect.clickable).y &&
(y) < ((fgeom.above_rect.clickable).y + (fgeom.above_rect
.clickable).height))
)
2874 {
2875 return META_FRAME_CONTROL_ABOVE;
2876 }
2877
2878 if (POINT_IN_RECT (x, y, fgeom.unabove_rect.clickable)((x) >= (fgeom.unabove_rect.clickable).x && (x) <
((fgeom.unabove_rect.clickable).x + (fgeom.unabove_rect.clickable
).width) && (y) >= (fgeom.unabove_rect.clickable).
y && (y) < ((fgeom.unabove_rect.clickable).y + (fgeom
.unabove_rect.clickable).height))
)
2879 {
2880 return META_FRAME_CONTROL_UNABOVE;
2881 }
2882
2883 if (POINT_IN_RECT (x, y, fgeom.stick_rect.clickable)((x) >= (fgeom.stick_rect.clickable).x && (x) <
((fgeom.stick_rect.clickable).x + (fgeom.stick_rect.clickable
).width) && (y) >= (fgeom.stick_rect.clickable).y &&
(y) < ((fgeom.stick_rect.clickable).y + (fgeom.stick_rect
.clickable).height))
)
2884 {
2885 return META_FRAME_CONTROL_STICK;
2886 }
2887
2888 if (POINT_IN_RECT (x, y, fgeom.unstick_rect.clickable)((x) >= (fgeom.unstick_rect.clickable).x && (x) <
((fgeom.unstick_rect.clickable).x + (fgeom.unstick_rect.clickable
).width) && (y) >= (fgeom.unstick_rect.clickable).
y && (y) < ((fgeom.unstick_rect.clickable).y + (fgeom
.unstick_rect.clickable).height))
)
2889 {
2890 return META_FRAME_CONTROL_UNSTICK;
2891 }
2892
2893 /* South resize always has priority over north resize,
2894 * in case of overlap.
2895 */
2896
2897 if (y >= (fgeom.height - fgeom.borders.total.bottom - RESIZE_EXTENDS15) &&
2898 x >= (fgeom.width - fgeom.borders.total.right - RESIZE_EXTENDS15))
2899 {
2900 if (has_vert && has_horiz)
2901 return META_FRAME_CONTROL_RESIZE_SE;
2902 else if (has_vert)
2903 return META_FRAME_CONTROL_RESIZE_S;
2904 else if (has_horiz)
2905 return META_FRAME_CONTROL_RESIZE_E;
2906 }
2907 else if (y >= (fgeom.height - fgeom.borders.total.bottom - RESIZE_EXTENDS15) &&
2908 x <= (fgeom.borders.total.left + RESIZE_EXTENDS15))
2909 {
2910 if (has_vert && has_horiz)
2911 return META_FRAME_CONTROL_RESIZE_SW;
2912 else if (has_vert)
2913 return META_FRAME_CONTROL_RESIZE_S;
2914 else if (has_horiz)
2915 return META_FRAME_CONTROL_RESIZE_W;
2916 }
2917 else if (y < (fgeom.borders.invisible.top + RESIZE_EXTENDS15) &&
2918 x <= (fgeom.borders.total.left + RESIZE_EXTENDS15))
2919 {
2920 if (has_vert && has_horiz)
2921 return META_FRAME_CONTROL_RESIZE_NW;
2922 else if (has_vert)
2923 return META_FRAME_CONTROL_RESIZE_N;
2924 else if (has_horiz)
2925 return META_FRAME_CONTROL_RESIZE_W;
2926 }
2927 else if (y < (fgeom.borders.invisible.top + RESIZE_EXTENDS15) &&
2928 x >= (fgeom.width - fgeom.borders.total.right - RESIZE_EXTENDS15))
2929 {
2930 if (has_vert && has_horiz)
2931 return META_FRAME_CONTROL_RESIZE_NE;
2932 else if (has_vert)
2933 return META_FRAME_CONTROL_RESIZE_N;
2934 else if (has_horiz)
2935 return META_FRAME_CONTROL_RESIZE_E;
2936 }
2937 else if (y < (fgeom.borders.invisible.top + TOP_RESIZE_HEIGHT4 * scale))
2938 {
2939 if (has_vert)
2940 return META_FRAME_CONTROL_RESIZE_N;
2941 }
2942 else if (y >= (fgeom.height - fgeom.borders.total.bottom - RESIZE_EXTENDS15))
2943 {
2944 if (has_vert)
2945 return META_FRAME_CONTROL_RESIZE_S;
2946 }
2947 else if (x <= fgeom.borders.total.left + RESIZE_EXTENDS15)
2948 {
2949 if (has_horiz)
2950 return META_FRAME_CONTROL_RESIZE_W;
2951 }
2952 else if (x >= (fgeom.width - fgeom.borders.total.right - RESIZE_EXTENDS15))
2953 {
2954 if (has_horiz)
2955 return META_FRAME_CONTROL_RESIZE_E;
2956 }
2957
2958 if (y >= fgeom.borders.total.top)
2959 return META_FRAME_CONTROL_NONE;
2960 else
2961 return META_FRAME_CONTROL_TITLE;
2962}
2963
2964void
2965meta_frames_push_delay_exposes (MetaFrames *frames)
2966{
2967 if (frames->expose_delay_count == 0)
2968 {
2969 /* Make sure we've repainted things */
2970 cdk_window_process_all_updates ();
2971 XFlush (CDK_DISPLAY_XDISPLAY (cdk_display_get_default ())(cdk_x11_display_get_xdisplay (cdk_display_get_default ())));
2972 }
2973
2974 frames->expose_delay_count += 1;
2975}
2976
2977static void
2978queue_pending_exposes_func (gpointer key, gpointer value, gpointer data)
2979{
2980 MetaUIFrame *frame;
2981 MetaFrames *frames;
2982
2983 frames = META_FRAMES (data)((((MetaFrames*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((meta_frames_get_type ()))))))
;
2984 frame = value;
2985
2986 if (frame->expose_delayed)
2987 {
2988 invalidate_whole_window (frames, frame);
2989 frame->expose_delayed = FALSE(0);
2990 }
2991}
2992
2993void
2994meta_frames_pop_delay_exposes (MetaFrames *frames)
2995{
2996 g_return_if_fail (frames->expose_delay_count > 0)do { if ((frames->expose_delay_count > 0)) { } else { g_return_if_fail_warning
("croma", ((const char*) (__func__)), "frames->expose_delay_count > 0"
); return; } } while (0)
;
2997
2998 frames->expose_delay_count -= 1;
2999
3000 if (frames->expose_delay_count == 0)
3001 {
3002 g_hash_table_foreach (frames->frames,
3003 queue_pending_exposes_func,
3004 frames);
3005 }
3006}
3007
3008static void
3009invalidate_whole_window (MetaFrames *frames,
3010 MetaUIFrame *frame)
3011{
3012 cdk_window_invalidate_rect (frame->window, NULL((void*)0), FALSE(0));
3013 invalidate_cache (frames, frame);
3014}