00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <config.h>
00027 #include <math.h>
00028 #include "boxes.h"
00029 #include "frames.h"
00030 #include "util.h"
00031 #include "core.h"
00032 #include "menu.h"
00033 #include "fixedtip.h"
00034 #include "theme.h"
00035 #include "prefs.h"
00036 #include "ui.h"
00037
00038 #ifdef HAVE_SHAPE
00039 #include <X11/extensions/shape.h>
00040 #endif
00041
00042 #define DEFAULT_INNER_BUTTON_BORDER 3
00043
00044 static void meta_frames_class_init (MetaFramesClass *klass);
00045 static void meta_frames_init (MetaFrames *frames);
00046 static void meta_frames_destroy (GtkObject *object);
00047 static void meta_frames_finalize (GObject *object);
00048 static void meta_frames_style_set (GtkWidget *widget,
00049 GtkStyle *prev_style);
00050 static void meta_frames_realize (GtkWidget *widget);
00051 static void meta_frames_unrealize (GtkWidget *widget);
00052
00053 static void meta_frames_update_prelit_control (MetaFrames *frames,
00054 MetaUIFrame *frame,
00055 MetaFrameControl control);
00056 static gboolean meta_frames_button_press_event (GtkWidget *widget,
00057 GdkEventButton *event);
00058 static gboolean meta_frames_button_release_event (GtkWidget *widget,
00059 GdkEventButton *event);
00060 static gboolean meta_frames_motion_notify_event (GtkWidget *widget,
00061 GdkEventMotion *event);
00062 static gboolean meta_frames_destroy_event (GtkWidget *widget,
00063 GdkEventAny *event);
00064 static gboolean meta_frames_expose_event (GtkWidget *widget,
00065 GdkEventExpose *event);
00066 static gboolean meta_frames_enter_notify_event (GtkWidget *widget,
00067 GdkEventCrossing *event);
00068 static gboolean meta_frames_leave_notify_event (GtkWidget *widget,
00069 GdkEventCrossing *event);
00070
00071 static void meta_frames_paint_to_drawable (MetaFrames *frames,
00072 MetaUIFrame *frame,
00073 GdkDrawable *drawable,
00074 GdkRegion *region,
00075 int x_offset,
00076 int y_offset);
00077
00078 static void meta_frames_set_window_background (MetaFrames *frames,
00079 MetaUIFrame *frame);
00080
00081 static void meta_frames_calc_geometry (MetaFrames *frames,
00082 MetaUIFrame *frame,
00083 MetaFrameGeometry *fgeom);
00084
00085 static void meta_frames_ensure_layout (MetaFrames *frames,
00086 MetaUIFrame *frame);
00087
00088 static MetaUIFrame* meta_frames_lookup_window (MetaFrames *frames,
00089 Window xwindow);
00090
00091 static void meta_frames_font_changed (MetaFrames *frames);
00092 static void meta_frames_button_layout_changed (MetaFrames *frames);
00093
00094
00095 static GdkRectangle* control_rect (MetaFrameControl control,
00096 MetaFrameGeometry *fgeom);
00097 static MetaFrameControl get_control (MetaFrames *frames,
00098 MetaUIFrame *frame,
00099 int x,
00100 int y);
00101 static void clear_tip (MetaFrames *frames);
00102 static void invalidate_all_caches (MetaFrames *frames);
00103 static void invalidate_whole_window (MetaFrames *frames,
00104 MetaUIFrame *frame);
00105
00106 static GtkWidgetClass *parent_class = NULL;
00107
00108 GtkType
00109 meta_frames_get_type (void)
00110 {
00111 static GtkType frames_type = 0;
00112
00113 if (!frames_type)
00114 {
00115 static const GtkTypeInfo frames_info =
00116 {
00117 "MetaFrames",
00118 sizeof (MetaFrames),
00119 sizeof (MetaFramesClass),
00120 (GtkClassInitFunc) meta_frames_class_init,
00121 (GtkObjectInitFunc) meta_frames_init,
00122 NULL,
00123 NULL,
00124 (GtkClassInitFunc) NULL,
00125 };
00126
00127 frames_type = gtk_type_unique (GTK_TYPE_WINDOW, &frames_info);
00128 }
00129
00130 return frames_type;
00131 }
00132
00133 static void
00134 meta_frames_class_init (MetaFramesClass *class)
00135 {
00136 GObjectClass *gobject_class;
00137 GtkObjectClass *object_class;
00138 GtkWidgetClass *widget_class;
00139
00140 gobject_class = G_OBJECT_CLASS (class);
00141 object_class = (GtkObjectClass*) class;
00142 widget_class = (GtkWidgetClass*) class;
00143
00144 parent_class = g_type_class_peek_parent (class);
00145
00146 gobject_class->finalize = meta_frames_finalize;
00147 object_class->destroy = meta_frames_destroy;
00148
00149 widget_class->style_set = meta_frames_style_set;
00150
00151 widget_class->realize = meta_frames_realize;
00152 widget_class->unrealize = meta_frames_unrealize;
00153
00154 widget_class->expose_event = meta_frames_expose_event;
00155 widget_class->destroy_event = meta_frames_destroy_event;
00156 widget_class->button_press_event = meta_frames_button_press_event;
00157 widget_class->button_release_event = meta_frames_button_release_event;
00158 widget_class->motion_notify_event = meta_frames_motion_notify_event;
00159 widget_class->enter_notify_event = meta_frames_enter_notify_event;
00160 widget_class->leave_notify_event = meta_frames_leave_notify_event;
00161 }
00162
00163 static gint
00164 unsigned_long_equal (gconstpointer v1,
00165 gconstpointer v2)
00166 {
00167 return *((const gulong*) v1) == *((const gulong*) v2);
00168 }
00169
00170 static guint
00171 unsigned_long_hash (gconstpointer v)
00172 {
00173 gulong val = * (const gulong *) v;
00174
00175
00176 #if GLIB_SIZEOF_LONG > 4
00177 return (guint) (val ^ (val >> 32));
00178 #else
00179 return val;
00180 #endif
00181 }
00182
00183 static void
00184 prefs_changed_callback (MetaPreference pref,
00185 void *data)
00186 {
00187 switch (pref)
00188 {
00189 case META_PREF_TITLEBAR_FONT:
00190 meta_frames_font_changed (META_FRAMES (data));
00191 break;
00192 case META_PREF_BUTTON_LAYOUT:
00193 meta_frames_button_layout_changed (META_FRAMES (data));
00194 break;
00195 default:
00196 break;
00197 }
00198 }
00199
00200 static void
00201 meta_frames_init (MetaFrames *frames)
00202 {
00203 GTK_WINDOW (frames)->type = GTK_WINDOW_POPUP;
00204
00205 frames->text_heights = g_hash_table_new (NULL, NULL);
00206
00207 frames->frames = g_hash_table_new (unsigned_long_hash, unsigned_long_equal);
00208
00209 frames->tooltip_timeout = 0;
00210
00211 frames->expose_delay_count = 0;
00212
00213 frames->invalidate_cache_timeout_id = 0;
00214 frames->invalidate_frames = NULL;
00215 frames->cache = g_hash_table_new (g_direct_hash, g_direct_equal);
00216
00217 gtk_widget_set_double_buffered (GTK_WIDGET (frames), FALSE);
00218
00219 meta_prefs_add_listener (prefs_changed_callback, frames);
00220 }
00221
00222 static void
00223 listify_func (gpointer key, gpointer value, gpointer data)
00224 {
00225 GSList **listp;
00226
00227 listp = data;
00228 *listp = g_slist_prepend (*listp, value);
00229 }
00230
00231 static void
00232 meta_frames_destroy (GtkObject *object)
00233 {
00234 GSList *winlist;
00235 GSList *tmp;
00236 MetaFrames *frames;
00237
00238 frames = META_FRAMES (object);
00239
00240 clear_tip (frames);
00241
00242 winlist = NULL;
00243 g_hash_table_foreach (frames->frames, listify_func, &winlist);
00244
00245
00246 for (tmp = winlist; tmp != NULL; tmp = tmp->next)
00247 {
00248 MetaUIFrame *frame;
00249
00250 frame = tmp->data;
00251
00252 meta_frames_unmanage_window (frames, frame->xwindow);
00253 }
00254 g_slist_free (winlist);
00255
00256 GTK_OBJECT_CLASS (parent_class)->destroy (object);
00257 }
00258
00259 static void
00260 meta_frames_finalize (GObject *object)
00261 {
00262 MetaFrames *frames;
00263
00264 frames = META_FRAMES (object);
00265
00266 meta_prefs_remove_listener (prefs_changed_callback, frames);
00267
00268 g_hash_table_destroy (frames->text_heights);
00269
00270 invalidate_all_caches (frames);
00271 if (frames->invalidate_cache_timeout_id)
00272 g_source_remove (frames->invalidate_cache_timeout_id);
00273
00274 g_assert (g_hash_table_size (frames->frames) == 0);
00275 g_hash_table_destroy (frames->frames);
00276 g_hash_table_destroy (frames->cache);
00277
00278 G_OBJECT_CLASS (parent_class)->finalize (object);
00279 }
00280
00281 typedef struct
00282 {
00283 MetaRectangle rect;
00284 GdkPixmap *pixmap;
00285 } CachedFramePiece;
00286
00287 typedef struct
00288 {
00289
00290
00291
00292 CachedFramePiece piece[4];
00293 } CachedPixels;
00294
00295 static CachedPixels *
00296 get_cache (MetaFrames *frames,
00297 MetaUIFrame *frame)
00298 {
00299 CachedPixels *pixels;
00300
00301 pixels = g_hash_table_lookup (frames->cache, frame);
00302
00303 if (!pixels)
00304 {
00305 pixels = g_new0 (CachedPixels, 1);
00306 g_hash_table_insert (frames->cache, frame, pixels);
00307 }
00308
00309 return pixels;
00310 }
00311
00312 static void
00313 invalidate_cache (MetaFrames *frames,
00314 MetaUIFrame *frame)
00315 {
00316 CachedPixels *pixels = get_cache (frames, frame);
00317 int i;
00318
00319 for (i = 0; i < 4; i++)
00320 if (pixels->piece[i].pixmap)
00321 g_object_unref (pixels->piece[i].pixmap);
00322
00323 g_free (pixels);
00324 g_hash_table_remove (frames->cache, frame);
00325 }
00326
00327 static void
00328 invalidate_all_caches (MetaFrames *frames)
00329 {
00330 GList *l;
00331
00332 for (l = frames->invalidate_frames; l; l = l->next)
00333 {
00334 MetaUIFrame *frame = l->data;
00335
00336 invalidate_cache (frames, frame);
00337 }
00338
00339 g_list_free (frames->invalidate_frames);
00340 frames->invalidate_frames = NULL;
00341 }
00342
00343 static gboolean
00344 invalidate_cache_timeout (gpointer data)
00345 {
00346 MetaFrames *frames = data;
00347
00348 invalidate_all_caches (frames);
00349 frames->invalidate_cache_timeout_id = 0;
00350 return FALSE;
00351 }
00352
00353 static void
00354 queue_recalc_func (gpointer key, gpointer value, gpointer data)
00355 {
00356 MetaUIFrame *frame;
00357 MetaFrames *frames;
00358
00359 frames = META_FRAMES (data);
00360 frame = value;
00361
00362
00363
00364
00365
00366 meta_frames_set_window_background (frames, frame);
00367
00368 invalidate_whole_window (frames, frame);
00369 meta_core_queue_frame_resize (gdk_display,
00370 frame->xwindow);
00371 if (frame->layout)
00372 {
00373
00374 g_free (frame->title);
00375
00376 frame->title = g_strdup (pango_layout_get_text (frame->layout));
00377
00378 g_object_unref (G_OBJECT (frame->layout));
00379 frame->layout = NULL;
00380 }
00381 }
00382
00383 static void
00384 meta_frames_font_changed (MetaFrames *frames)
00385 {
00386 if (g_hash_table_size (frames->text_heights) > 0)
00387 {
00388 g_hash_table_destroy (frames->text_heights);
00389 frames->text_heights = g_hash_table_new (NULL, NULL);
00390 }
00391
00392
00393 g_hash_table_foreach (frames->frames,
00394 queue_recalc_func, frames);
00395
00396 }
00397
00398 static void
00399 queue_draw_func (gpointer key, gpointer value, gpointer data)
00400 {
00401 MetaUIFrame *frame;
00402 MetaFrames *frames;
00403
00404 frames = META_FRAMES (data);
00405 frame = value;
00406
00407
00408
00409
00410
00411 meta_frames_set_window_background (frames, frame);
00412
00413 invalidate_whole_window (frames, frame);
00414 }
00415
00416 static void
00417 meta_frames_button_layout_changed (MetaFrames *frames)
00418 {
00419 g_hash_table_foreach (frames->frames,
00420 queue_draw_func, frames);
00421 }
00422
00423 static void
00424 meta_frames_style_set (GtkWidget *widget,
00425 GtkStyle *prev_style)
00426 {
00427 MetaFrames *frames;
00428
00429 frames = META_FRAMES (widget);
00430
00431 meta_frames_font_changed (frames);
00432
00433 GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
00434 }
00435
00436 static void
00437 meta_frames_ensure_layout (MetaFrames *frames,
00438 MetaUIFrame *frame)
00439 {
00440 GtkWidget *widget;
00441 MetaFrameFlags flags;
00442 MetaFrameType type;
00443 MetaFrameStyle *style;
00444
00445 g_return_if_fail (GTK_WIDGET_REALIZED (frames));
00446
00447 widget = GTK_WIDGET (frames);
00448
00449 meta_core_get (gdk_display, frame->xwindow,
00450 META_CORE_GET_FRAME_FLAGS, &flags,
00451 META_CORE_GET_FRAME_TYPE, &type,
00452 META_CORE_GET_END);
00453
00454 style = meta_theme_get_frame_style (meta_theme_get_current (),
00455 type, flags);
00456
00457 if (style != frame->cache_style)
00458 {
00459 if (frame->layout)
00460 {
00461
00462 g_free (frame->title);
00463
00464 frame->title = g_strdup (pango_layout_get_text (frame->layout));
00465
00466 g_object_unref (G_OBJECT (frame->layout));
00467 frame->layout = NULL;
00468 }
00469 }
00470
00471 frame->cache_style = style;
00472
00473 if (frame->layout == NULL)
00474 {
00475 gpointer key, value;
00476 PangoFontDescription *font_desc;
00477 double scale;
00478 int size;
00479
00480 scale = meta_theme_get_title_scale (meta_theme_get_current (),
00481 type,
00482 flags);
00483
00484 frame->layout = gtk_widget_create_pango_layout (widget, frame->title);
00485
00486 pango_layout_set_auto_dir (frame->layout, FALSE);
00487
00488 font_desc = meta_gtk_widget_get_font_desc (widget, scale,
00489 meta_prefs_get_titlebar_font ());
00490
00491 size = pango_font_description_get_size (font_desc);
00492
00493 if (g_hash_table_lookup_extended (frames->text_heights,
00494 GINT_TO_POINTER (size),
00495 &key, &value))
00496 {
00497 frame->text_height = GPOINTER_TO_INT (value);
00498 }
00499 else
00500 {
00501 frame->text_height =
00502 meta_pango_font_desc_get_text_height (font_desc,
00503 gtk_widget_get_pango_context (widget));
00504
00505 g_hash_table_replace (frames->text_heights,
00506 GINT_TO_POINTER (size),
00507 GINT_TO_POINTER (frame->text_height));
00508 }
00509
00510 pango_layout_set_font_description (frame->layout,
00511 font_desc);
00512
00513 pango_font_description_free (font_desc);
00514
00515
00516 g_free (frame->title);
00517 frame->title = NULL;
00518 }
00519 }
00520
00521 static void
00522 meta_frames_calc_geometry (MetaFrames *frames,
00523 MetaUIFrame *frame,
00524 MetaFrameGeometry *fgeom)
00525 {
00526 int width, height;
00527 MetaFrameFlags flags;
00528 MetaFrameType type;
00529 MetaButtonLayout button_layout;
00530
00531 meta_core_get (gdk_display, frame->xwindow,
00532 META_CORE_GET_CLIENT_WIDTH, &width,
00533 META_CORE_GET_CLIENT_HEIGHT, &height,
00534 META_CORE_GET_FRAME_FLAGS, &flags,
00535 META_CORE_GET_FRAME_TYPE, &type,
00536 META_CORE_GET_END);
00537
00538 meta_frames_ensure_layout (frames, frame);
00539
00540 meta_prefs_get_button_layout (&button_layout);
00541
00542 meta_theme_calc_geometry (meta_theme_get_current (),
00543 type,
00544 frame->text_height,
00545 flags,
00546 width, height,
00547 &button_layout,
00548 fgeom);
00549 }
00550
00551 MetaFrames*
00552 meta_frames_new (int screen_number)
00553 {
00554 GdkScreen *screen;
00555
00556 screen = gdk_display_get_screen (gdk_display_get_default (),
00557 screen_number);
00558
00559 return g_object_new (META_TYPE_FRAMES,
00560 "screen", screen,
00561 NULL);
00562 }
00563
00564 void
00565 meta_frames_manage_window (MetaFrames *frames,
00566 Window xwindow,
00567 GdkWindow *window)
00568 {
00569 MetaUIFrame *frame;
00570
00571 g_assert (window);
00572
00573 frame = g_new (MetaUIFrame, 1);
00574
00575 frame->window = window;
00576
00577 gdk_window_set_user_data (frame->window, frames);
00578
00579
00580
00581 frame->xwindow = xwindow;
00582 frame->cache_style = NULL;
00583 frame->layout = NULL;
00584 frame->text_height = -1;
00585 frame->title = NULL;
00586 frame->expose_delayed = FALSE;
00587 frame->shape_applied = FALSE;
00588 frame->prelit_control = META_FRAME_CONTROL_NONE;
00589
00590
00591
00592
00593
00594
00595 meta_core_grab_buttons (gdk_display, frame->xwindow);
00596
00597 g_hash_table_replace (frames->frames, &frame->xwindow, frame);
00598 }
00599
00600 void
00601 meta_frames_unmanage_window (MetaFrames *frames,
00602 Window xwindow)
00603 {
00604 MetaUIFrame *frame;
00605
00606 clear_tip (frames);
00607
00608 frame = g_hash_table_lookup (frames->frames, &xwindow);
00609
00610 if (frame)
00611 {
00612
00613
00614
00615 invalidate_all_caches (frames);
00616
00617
00618 meta_core_set_screen_cursor (gdk_display,
00619 frame->xwindow,
00620 META_CURSOR_DEFAULT);
00621
00622 gdk_window_set_user_data (frame->window, NULL);
00623
00624 if (frames->last_motion_frame == frame)
00625 frames->last_motion_frame = NULL;
00626
00627 g_hash_table_remove (frames->frames, &frame->xwindow);
00628
00629 gdk_window_destroy (frame->window);
00630
00631 if (frame->layout)
00632 g_object_unref (G_OBJECT (frame->layout));
00633
00634 if (frame->title)
00635 g_free (frame->title);
00636
00637 g_free (frame);
00638 }
00639 else
00640 meta_warning ("Frame 0x%lx not managed, can't unmanage\n", xwindow);
00641 }
00642
00643 static void
00644 meta_frames_realize (GtkWidget *widget)
00645 {
00646 if (GTK_WIDGET_CLASS (parent_class)->realize)
00647 GTK_WIDGET_CLASS (parent_class)->realize (widget);
00648 }
00649
00650 static void
00651 meta_frames_unrealize (GtkWidget *widget)
00652 {
00653 if (GTK_WIDGET_CLASS (parent_class)->unrealize)
00654 GTK_WIDGET_CLASS (parent_class)->unrealize (widget);
00655 }
00656
00657 static MetaUIFrame*
00658 meta_frames_lookup_window (MetaFrames *frames,
00659 Window xwindow)
00660 {
00661 MetaUIFrame *frame;
00662
00663 frame = g_hash_table_lookup (frames->frames, &xwindow);
00664
00665 return frame;
00666 }
00667
00668 void
00669 meta_frames_get_geometry (MetaFrames *frames,
00670 Window xwindow,
00671 int *top_height, int *bottom_height,
00672 int *left_width, int *right_width)
00673 {
00674 MetaFrameFlags flags;
00675 MetaUIFrame *frame;
00676 MetaFrameType type;
00677
00678 frame = meta_frames_lookup_window (frames, xwindow);
00679
00680 if (frame == NULL)
00681 meta_bug ("No such frame 0x%lx\n", xwindow);
00682
00683 meta_core_get (gdk_display, frame->xwindow,
00684 META_CORE_GET_FRAME_FLAGS, &flags,
00685 META_CORE_GET_FRAME_TYPE, &type,
00686 META_CORE_GET_END);
00687
00688 g_return_if_fail (type < META_FRAME_TYPE_LAST);
00689
00690 meta_frames_ensure_layout (frames, frame);
00691
00692
00693
00694
00695
00696
00697 meta_theme_get_frame_borders (meta_theme_get_current (),
00698 type,
00699 frame->text_height,
00700 flags,
00701 top_height, bottom_height,
00702 left_width, right_width);
00703 }
00704
00705 void
00706 meta_frames_reset_bg (MetaFrames *frames,
00707 Window xwindow)
00708 {
00709 MetaUIFrame *frame;
00710
00711 frame = meta_frames_lookup_window (frames, xwindow);
00712
00713 meta_frames_set_window_background (frames, frame);
00714 }
00715
00716 static void
00717 set_background_none (Display *xdisplay,
00718 Window xwindow)
00719 {
00720 XSetWindowAttributes attrs;
00721
00722 attrs.background_pixmap = None;
00723 XChangeWindowAttributes (xdisplay, xwindow,
00724 CWBackPixmap, &attrs);
00725 }
00726
00727 void
00728 meta_frames_unflicker_bg (MetaFrames *frames,
00729 Window xwindow,
00730 int target_width,
00731 int target_height)
00732 {
00733 MetaUIFrame *frame;
00734
00735 frame = meta_frames_lookup_window (frames, xwindow);
00736 g_return_if_fail (frame != NULL);
00737
00738 #if 0
00739 pixmap = gdk_pixmap_new (frame->window,
00740 width, height,
00741 -1);
00742
00743
00744
00745 meta_frames_paint_to_drawable (frames, frame, pixmap);
00746 #endif
00747
00748 set_background_none (gdk_display, frame->xwindow);
00749 }
00750
00751 void
00752 meta_frames_apply_shapes (MetaFrames *frames,
00753 Window xwindow,
00754 int new_window_width,
00755 int new_window_height,
00756 gboolean window_has_shape)
00757 {
00758 #ifdef HAVE_SHAPE
00759
00760 MetaUIFrame *frame;
00761 MetaFrameGeometry fgeom;
00762 XRectangle xrect;
00763 Region corners_xregion;
00764 Region window_xregion;
00765
00766 frame = meta_frames_lookup_window (frames, xwindow);
00767 g_return_if_fail (frame != NULL);
00768
00769 meta_frames_calc_geometry (frames, frame, &fgeom);
00770
00771 if (!(fgeom.top_left_corner_rounded_radius != 0 ||
00772 fgeom.top_right_corner_rounded_radius != 0 ||
00773 fgeom.bottom_left_corner_rounded_radius != 0 ||
00774 fgeom.bottom_right_corner_rounded_radius != 0 ||
00775 window_has_shape))
00776 {
00777 if (frame->shape_applied)
00778 {
00779 meta_topic (META_DEBUG_SHAPES,
00780 "Unsetting shape mask on frame 0x%lx\n",
00781 frame->xwindow);
00782
00783 XShapeCombineMask (gdk_display, frame->xwindow,
00784 ShapeBounding, 0, 0, None, ShapeSet);
00785 frame->shape_applied = FALSE;
00786 }
00787 else
00788 {
00789 meta_topic (META_DEBUG_SHAPES,
00790 "Frame 0x%lx still doesn't need a shape mask\n",
00791 frame->xwindow);
00792 }
00793
00794 return;
00795 }
00796
00797 corners_xregion = XCreateRegion ();
00798
00799 if (fgeom.top_left_corner_rounded_radius != 0)
00800 {
00801 const int corner = fgeom.top_left_corner_rounded_radius;
00802 const float radius = sqrt(corner) + corner;
00803 int i;
00804
00805 for (i=0; i<corner; i++)
00806 {
00807 const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
00808 xrect.x = 0;
00809 xrect.y = i;
00810 xrect.width = width;
00811 xrect.height = 1;
00812
00813 XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
00814 }
00815 }
00816
00817 if (fgeom.top_right_corner_rounded_radius != 0)
00818 {
00819 const int corner = fgeom.top_right_corner_rounded_radius;
00820 const float radius = sqrt(corner) + corner;
00821 int i;
00822
00823 for (i=0; i<corner; i++)
00824 {
00825 const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
00826 xrect.x = new_window_width - width;
00827 xrect.y = i;
00828 xrect.width = width;
00829 xrect.height = 1;
00830
00831 XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
00832 }
00833 }
00834
00835 if (fgeom.bottom_left_corner_rounded_radius != 0)
00836 {
00837 const int corner = fgeom.bottom_left_corner_rounded_radius;
00838 const float radius = sqrt(corner) + corner;
00839 int i;
00840
00841 for (i=0; i<corner; i++)
00842 {
00843 const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
00844 xrect.x = 0;
00845 xrect.y = new_window_height - i - 1;
00846 xrect.width = width;
00847 xrect.height = 1;
00848
00849 XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
00850 }
00851 }
00852
00853 if (fgeom.bottom_right_corner_rounded_radius != 0)
00854 {
00855 const int corner = fgeom.bottom_right_corner_rounded_radius;
00856 const float radius = sqrt(corner) + corner;
00857 int i;
00858
00859 for (i=0; i<corner; i++)
00860 {
00861 const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5))));
00862 xrect.x = new_window_width - width;
00863 xrect.y = new_window_height - i - 1;
00864 xrect.width = width;
00865 xrect.height = 1;
00866
00867 XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion);
00868 }
00869 }
00870
00871 window_xregion = XCreateRegion ();
00872
00873 xrect.x = 0;
00874 xrect.y = 0;
00875 xrect.width = new_window_width;
00876 xrect.height = new_window_height;
00877
00878 XUnionRectWithRegion (&xrect, window_xregion, window_xregion);
00879
00880 XSubtractRegion (window_xregion, corners_xregion, window_xregion);
00881
00882 XDestroyRegion (corners_xregion);
00883
00884 if (window_has_shape)
00885 {
00886
00887
00888
00889
00890
00891
00892 XSetWindowAttributes attrs;
00893 Window shape_window;
00894 Window client_window;
00895 Region client_xregion;
00896 GdkScreen *screen;
00897 int screen_number;
00898
00899 meta_topic (META_DEBUG_SHAPES,
00900 "Frame 0x%lx needs to incorporate client shape\n",
00901 frame->xwindow);
00902
00903 screen = gtk_widget_get_screen (GTK_WIDGET (frames));
00904 screen_number = gdk_x11_screen_get_screen_number (screen);
00905
00906 attrs.override_redirect = True;
00907
00908 shape_window = XCreateWindow (gdk_display,
00909 RootWindow (gdk_display, screen_number),
00910 -5000, -5000,
00911 new_window_width,
00912 new_window_height,
00913 0,
00914 CopyFromParent,
00915 CopyFromParent,
00916 (Visual *)CopyFromParent,
00917 CWOverrideRedirect,
00918 &attrs);
00919
00920
00921 meta_core_get (gdk_display, frame->xwindow,
00922 META_CORE_GET_CLIENT_XWINDOW, &client_window,
00923 META_CORE_GET_END);
00924
00925 XShapeCombineShape (gdk_display, shape_window, ShapeBounding,
00926 fgeom.left_width,
00927 fgeom.top_height,
00928 client_window,
00929 ShapeBounding,
00930 ShapeSet);
00931
00932
00933
00934
00935 client_xregion = XCreateRegion ();
00936
00937 xrect.x = fgeom.left_width;
00938 xrect.y = fgeom.top_height;
00939 xrect.width = new_window_width - fgeom.right_width - xrect.x;
00940 xrect.height = new_window_height - fgeom.bottom_height - xrect.y;
00941
00942 XUnionRectWithRegion (&xrect, client_xregion, client_xregion);
00943
00944 XSubtractRegion (window_xregion, client_xregion, window_xregion);
00945
00946 XDestroyRegion (client_xregion);
00947
00948 XShapeCombineRegion (gdk_display, shape_window,
00949 ShapeBounding, 0, 0, window_xregion, ShapeUnion);
00950
00951
00952 XShapeCombineShape (gdk_display, frame->xwindow, ShapeBounding,
00953 0, 0,
00954 shape_window,
00955 ShapeBounding,
00956 ShapeSet);
00957
00958 XDestroyWindow (gdk_display, shape_window);
00959 }
00960 else
00961 {
00962
00963
00964 meta_topic (META_DEBUG_SHAPES,
00965 "Frame 0x%lx has shaped corners\n",
00966 frame->xwindow);
00967
00968 XShapeCombineRegion (gdk_display, frame->xwindow,
00969 ShapeBounding, 0, 0, window_xregion, ShapeSet);
00970 }
00971
00972 frame->shape_applied = TRUE;
00973
00974 XDestroyRegion (window_xregion);
00975 #endif
00976 }
00977
00978 void
00979 meta_frames_move_resize_frame (MetaFrames *frames,
00980 Window xwindow,
00981 int x,
00982 int y,
00983 int width,
00984 int height)
00985 {
00986 MetaUIFrame *frame = meta_frames_lookup_window (frames, xwindow);
00987 int old_x, old_y, old_width, old_height;
00988
00989 gdk_drawable_get_size (frame->window, &old_width, &old_height);
00990 gdk_window_get_position (frame->window, &old_x, &old_y);
00991
00992 gdk_window_move_resize (frame->window, x, y, width, height);
00993
00994 if (old_width != width || old_height != height)
00995 invalidate_whole_window (frames, frame);
00996 }
00997
00998 void
00999 meta_frames_queue_draw (MetaFrames *frames,
01000 Window xwindow)
01001 {
01002 MetaUIFrame *frame;
01003
01004 frame = meta_frames_lookup_window (frames, xwindow);
01005
01006 invalidate_whole_window (frames, frame);
01007 }
01008
01009 void
01010 meta_frames_set_title (MetaFrames *frames,
01011 Window xwindow,
01012 const char *title)
01013 {
01014 MetaUIFrame *frame;
01015
01016 frame = meta_frames_lookup_window (frames, xwindow);
01017
01018 g_assert (frame);
01019
01020 g_free (frame->title);
01021 frame->title = g_strdup (title);
01022
01023 if (frame->layout)
01024 {
01025 g_object_unref (frame->layout);
01026 frame->layout = NULL;
01027 }
01028
01029 invalidate_whole_window (frames, frame);
01030 }
01031
01032 void
01033 meta_frames_repaint_frame (MetaFrames *frames,
01034 Window xwindow)
01035 {
01036 MetaUIFrame *frame;
01037
01038 frame = meta_frames_lookup_window (frames, xwindow);
01039
01040 g_assert (frame);
01041
01042
01043
01044
01045 gdk_window_process_all_updates ();
01046 }
01047
01048 static void
01049 show_tip_now (MetaFrames *frames)
01050 {
01051 const char *tiptext;
01052 MetaUIFrame *frame;
01053 int x, y, root_x, root_y;
01054 Window root, child;
01055 guint mask;
01056 MetaFrameControl control;
01057
01058 frame = frames->last_motion_frame;
01059 if (frame == NULL)
01060 return;
01061
01062 XQueryPointer (gdk_display,
01063 frame->xwindow,
01064 &root, &child,
01065 &root_x, &root_y,
01066 &x, &y,
01067 &mask);
01068
01069 control = get_control (frames, frame, x, y);
01070
01071 tiptext = NULL;
01072 switch (control)
01073 {
01074 case META_FRAME_CONTROL_TITLE:
01075 break;
01076 case META_FRAME_CONTROL_DELETE:
01077 tiptext = _("Close Window");
01078 break;
01079 case META_FRAME_CONTROL_MENU:
01080 tiptext = _("Window Menu");
01081 break;
01082 case META_FRAME_CONTROL_MINIMIZE:
01083 tiptext = _("Minimize Window");
01084 break;
01085 case META_FRAME_CONTROL_MAXIMIZE:
01086 tiptext = _("Maximize Window");
01087 break;
01088 case META_FRAME_CONTROL_UNMAXIMIZE:
01089 tiptext = _("Unmaximize Window");
01090 break;
01091 case META_FRAME_CONTROL_SHADE:
01092 tiptext = _("Roll Up Window");
01093 break;
01094 case META_FRAME_CONTROL_UNSHADE:
01095 tiptext = _("Unroll Window");
01096 break;
01097 case META_FRAME_CONTROL_ABOVE:
01098 tiptext = _("Keep Window On Top");
01099 break;
01100 case META_FRAME_CONTROL_UNABOVE:
01101 tiptext = _("Remove Window From Top");
01102 break;
01103 case META_FRAME_CONTROL_STICK:
01104 tiptext = _("Always On Visible Workspace");
01105 break;
01106 case META_FRAME_CONTROL_UNSTICK:
01107 tiptext = _("Put Window On Only One Workspace");
01108 break;
01109 case META_FRAME_CONTROL_RESIZE_SE:
01110 break;
01111 case META_FRAME_CONTROL_RESIZE_S:
01112 break;
01113 case META_FRAME_CONTROL_RESIZE_SW:
01114 break;
01115 case META_FRAME_CONTROL_RESIZE_N:
01116 break;
01117 case META_FRAME_CONTROL_RESIZE_NE:
01118 break;
01119 case META_FRAME_CONTROL_RESIZE_NW:
01120 break;
01121 case META_FRAME_CONTROL_RESIZE_W:
01122 break;
01123 case META_FRAME_CONTROL_RESIZE_E:
01124 break;
01125 case META_FRAME_CONTROL_NONE:
01126 break;
01127 case META_FRAME_CONTROL_CLIENT_AREA:
01128 break;
01129 }
01130
01131 if (tiptext)
01132 {
01133 MetaFrameGeometry fgeom;
01134 GdkRectangle *rect;
01135 int dx, dy;
01136 int screen_number;
01137
01138 meta_frames_calc_geometry (frames, frame, &fgeom);
01139
01140 rect = control_rect (control, &fgeom);
01141
01142
01143 dx = root_x - x;
01144 dy = root_y - y;
01145
01146
01147 if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
01148 dx += rect->width;
01149
01150 screen_number = gdk_screen_get_number (gtk_widget_get_screen (GTK_WIDGET (frames)));
01151
01152 meta_fixed_tip_show (gdk_display,
01153 screen_number,
01154 rect->x + dx,
01155 rect->y + rect->height + 2 + dy,
01156 tiptext);
01157 }
01158 }
01159
01160 static gboolean
01161 tip_timeout_func (gpointer data)
01162 {
01163 MetaFrames *frames;
01164
01165 frames = data;
01166
01167 show_tip_now (frames);
01168
01169 return FALSE;
01170 }
01171
01172 #define TIP_DELAY 450
01173 static void
01174 queue_tip (MetaFrames *frames)
01175 {
01176 clear_tip (frames);
01177
01178 frames->tooltip_timeout = g_timeout_add (TIP_DELAY,
01179 tip_timeout_func,
01180 frames);
01181 }
01182
01183 static void
01184 clear_tip (MetaFrames *frames)
01185 {
01186 if (frames->tooltip_timeout)
01187 {
01188 g_source_remove (frames->tooltip_timeout);
01189 frames->tooltip_timeout = 0;
01190 }
01191 meta_fixed_tip_hide ();
01192 }
01193
01194 static void
01195 redraw_control (MetaFrames *frames,
01196 MetaUIFrame *frame,
01197 MetaFrameControl control)
01198 {
01199 MetaFrameGeometry fgeom;
01200 GdkRectangle *rect;
01201
01202 meta_frames_calc_geometry (frames, frame, &fgeom);
01203
01204 rect = control_rect (control, &fgeom);
01205
01206 gdk_window_invalidate_rect (frame->window, rect, FALSE);
01207 invalidate_cache (frames, frame);
01208 }
01209
01210 static gboolean
01211 meta_frame_titlebar_event (MetaUIFrame *frame,
01212 GdkEventButton *event,
01213 int action)
01214 {
01215 MetaFrameFlags flags;
01216
01217 switch (action)
01218 {
01219 case META_ACTION_TITLEBAR_TOGGLE_SHADE:
01220 {
01221 meta_core_get (gdk_display, frame->xwindow,
01222 META_CORE_GET_FRAME_FLAGS, &flags,
01223 META_CORE_GET_END);
01224
01225 if (flags & META_FRAME_ALLOWS_SHADE)
01226 {
01227 if (flags & META_FRAME_SHADED)
01228 meta_core_unshade (gdk_display,
01229 frame->xwindow,
01230 event->time);
01231 else
01232 meta_core_shade (gdk_display,
01233 frame->xwindow,
01234 event->time);
01235 }
01236 }
01237 break;
01238
01239 case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE:
01240 {
01241 meta_core_get (gdk_display, frame->xwindow,
01242 META_CORE_GET_FRAME_FLAGS, &flags,
01243 META_CORE_GET_END);
01244
01245 if (flags & META_FRAME_ALLOWS_MAXIMIZE)
01246 {
01247 meta_core_toggle_maximize (gdk_display, frame->xwindow);
01248 }
01249 }
01250 break;
01251
01252 case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_HORIZONTALLY:
01253 {
01254 meta_core_get (gdk_display, frame->xwindow,
01255 META_CORE_GET_FRAME_FLAGS, &flags,
01256 META_CORE_GET_END);
01257
01258 if (flags & META_FRAME_ALLOWS_MAXIMIZE)
01259 {
01260 meta_core_toggle_maximize_horizontally (gdk_display, frame->xwindow);
01261 }
01262 }
01263 break;
01264
01265 case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_VERTICALLY:
01266 {
01267 meta_core_get (gdk_display, frame->xwindow,
01268 META_CORE_GET_FRAME_FLAGS, &flags,
01269 META_CORE_GET_END);
01270
01271 if (flags & META_FRAME_ALLOWS_MAXIMIZE)
01272 {
01273 meta_core_toggle_maximize_vertically (gdk_display, frame->xwindow);
01274 }
01275 }
01276 break;
01277
01278 case META_ACTION_TITLEBAR_MINIMIZE:
01279 {
01280 meta_core_get (gdk_display, frame->xwindow,
01281 META_CORE_GET_FRAME_FLAGS, &flags,
01282 META_CORE_GET_END);
01283
01284 if (flags & META_FRAME_ALLOWS_MINIMIZE)
01285 {
01286 meta_core_minimize (gdk_display, frame->xwindow);
01287 }
01288 }
01289 break;
01290
01291 case META_ACTION_TITLEBAR_NONE:
01292
01293 break;
01294
01295 case META_ACTION_TITLEBAR_LOWER:
01296 meta_core_user_lower_and_unfocus (gdk_display,
01297 frame->xwindow,
01298 event->time);
01299 break;
01300
01301 case META_ACTION_TITLEBAR_MENU:
01302 meta_core_show_window_menu (gdk_display,
01303 frame->xwindow,
01304 event->x_root,
01305 event->y_root,
01306 event->button,
01307 event->time);
01308 break;
01309
01310 case META_ACTION_TITLEBAR_LAST:
01311 break;
01312 }
01313
01314 return TRUE;
01315 }
01316
01317 static gboolean
01318 meta_frame_double_click_event (MetaUIFrame *frame,
01319 GdkEventButton *event)
01320 {
01321 int action = meta_prefs_get_action_double_click_titlebar ();
01322
01323 return meta_frame_titlebar_event (frame, event, action);
01324 }
01325
01326 static gboolean
01327 meta_frame_middle_click_event (MetaUIFrame *frame,
01328 GdkEventButton *event)
01329 {
01330 int action = meta_prefs_get_action_middle_click_titlebar();
01331
01332 return meta_frame_titlebar_event (frame, event, action);
01333 }
01334
01335 static gboolean
01336 meta_frame_right_click_event(MetaUIFrame *frame,
01337 GdkEventButton *event)
01338 {
01339 int action = meta_prefs_get_action_right_click_titlebar();
01340
01341 return meta_frame_titlebar_event (frame, event, action);
01342 }
01343
01344 static gboolean
01345 meta_frames_button_press_event (GtkWidget *widget,
01346 GdkEventButton *event)
01347 {
01348 MetaUIFrame *frame;
01349 MetaFrames *frames;
01350 MetaFrameControl control;
01351
01352 frames = META_FRAMES (widget);
01353
01354
01355
01356
01357
01358 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
01359 if (frame == NULL)
01360 return FALSE;
01361
01362 clear_tip (frames);
01363
01364 control = get_control (frames, frame, event->x, event->y);
01365
01366
01367 if (event->button == 1 &&
01368 !(control == META_FRAME_CONTROL_MINIMIZE ||
01369 control == META_FRAME_CONTROL_DELETE ||
01370 control == META_FRAME_CONTROL_MAXIMIZE))
01371 {
01372 meta_topic (META_DEBUG_FOCUS,
01373 "Focusing window with frame 0x%lx due to button 1 press\n",
01374 frame->xwindow);
01375 meta_core_user_focus (gdk_display,
01376 frame->xwindow,
01377 event->time);
01378 }
01379
01380
01381 if (control == META_FRAME_CONTROL_CLIENT_AREA)
01382 return FALSE;
01383
01384
01385
01386
01387 if (control == META_FRAME_CONTROL_TITLE &&
01388 event->button == 1 &&
01389 event->type == GDK_2BUTTON_PRESS)
01390 {
01391 return meta_frame_double_click_event (frame, event);
01392 }
01393
01394 if (meta_core_get_grab_op (gdk_display) !=
01395 META_GRAB_OP_NONE)
01396 return FALSE;
01397
01398 if (event->button == 1 &&
01399 (control == META_FRAME_CONTROL_MAXIMIZE ||
01400 control == META_FRAME_CONTROL_UNMAXIMIZE ||
01401 control == META_FRAME_CONTROL_MINIMIZE ||
01402 control == META_FRAME_CONTROL_DELETE ||
01403 control == META_FRAME_CONTROL_SHADE ||
01404 control == META_FRAME_CONTROL_UNSHADE ||
01405 control == META_FRAME_CONTROL_ABOVE ||
01406 control == META_FRAME_CONTROL_UNABOVE ||
01407 control == META_FRAME_CONTROL_STICK ||
01408 control == META_FRAME_CONTROL_UNSTICK ||
01409 control == META_FRAME_CONTROL_MENU))
01410 {
01411 MetaGrabOp op = META_GRAB_OP_NONE;
01412
01413 switch (control)
01414 {
01415 case META_FRAME_CONTROL_MINIMIZE:
01416 op = META_GRAB_OP_CLICKING_MINIMIZE;
01417 break;
01418 case META_FRAME_CONTROL_MAXIMIZE:
01419 op = META_GRAB_OP_CLICKING_MAXIMIZE;
01420 break;
01421 case META_FRAME_CONTROL_UNMAXIMIZE:
01422 op = META_GRAB_OP_CLICKING_UNMAXIMIZE;
01423 break;
01424 case META_FRAME_CONTROL_DELETE:
01425 op = META_GRAB_OP_CLICKING_DELETE;
01426 break;
01427 case META_FRAME_CONTROL_MENU:
01428 op = META_GRAB_OP_CLICKING_MENU;
01429 break;
01430 case META_FRAME_CONTROL_SHADE:
01431 op = META_GRAB_OP_CLICKING_SHADE;
01432 break;
01433 case META_FRAME_CONTROL_UNSHADE:
01434 op = META_GRAB_OP_CLICKING_UNSHADE;
01435 break;
01436 case META_FRAME_CONTROL_ABOVE:
01437 op = META_GRAB_OP_CLICKING_ABOVE;
01438 break;
01439 case META_FRAME_CONTROL_UNABOVE:
01440 op = META_GRAB_OP_CLICKING_UNABOVE;
01441 break;
01442 case META_FRAME_CONTROL_STICK:
01443 op = META_GRAB_OP_CLICKING_STICK;
01444 break;
01445 case META_FRAME_CONTROL_UNSTICK:
01446 op = META_GRAB_OP_CLICKING_UNSTICK;
01447 break;
01448 default:
01449 g_assert_not_reached ();
01450 break;
01451 }
01452
01453 meta_core_begin_grab_op (gdk_display,
01454 frame->xwindow,
01455 op,
01456 TRUE,
01457 TRUE,
01458 event->button,
01459 0,
01460 event->time,
01461 event->x_root,
01462 event->y_root);
01463
01464 frame->prelit_control = control;
01465 redraw_control (frames, frame, control);
01466
01467 if (op == META_GRAB_OP_CLICKING_MENU)
01468 {
01469 MetaFrameGeometry fgeom;
01470 GdkRectangle *rect;
01471 int dx, dy;
01472
01473 meta_frames_calc_geometry (frames, frame, &fgeom);
01474
01475 rect = control_rect (META_FRAME_CONTROL_MENU, &fgeom);
01476
01477
01478 dx = event->x_root - event->x;
01479 dy = event->y_root - event->y;
01480
01481
01482 if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
01483 dx += rect->width;
01484
01485 meta_core_show_window_menu (gdk_display,
01486 frame->xwindow,
01487 rect->x + dx,
01488 rect->y + rect->height + dy,
01489 event->button,
01490 event->time);
01491 }
01492 }
01493 else if (event->button == 1 &&
01494 (control == META_FRAME_CONTROL_RESIZE_SE ||
01495 control == META_FRAME_CONTROL_RESIZE_S ||
01496 control == META_FRAME_CONTROL_RESIZE_SW ||
01497 control == META_FRAME_CONTROL_RESIZE_NE ||
01498 control == META_FRAME_CONTROL_RESIZE_N ||
01499 control == META_FRAME_CONTROL_RESIZE_NW ||
01500 control == META_FRAME_CONTROL_RESIZE_E ||
01501 control == META_FRAME_CONTROL_RESIZE_W))
01502 {
01503 MetaGrabOp op;
01504 gboolean titlebar_is_onscreen;
01505
01506 op = META_GRAB_OP_NONE;
01507
01508 switch (control)
01509 {
01510 case META_FRAME_CONTROL_RESIZE_SE:
01511 op = META_GRAB_OP_RESIZING_SE;
01512 break;
01513 case META_FRAME_CONTROL_RESIZE_S:
01514 op = META_GRAB_OP_RESIZING_S;
01515 break;
01516 case META_FRAME_CONTROL_RESIZE_SW:
01517 op = META_GRAB_OP_RESIZING_SW;
01518 break;
01519 case META_FRAME_CONTROL_RESIZE_NE:
01520 op = META_GRAB_OP_RESIZING_NE;
01521 break;
01522 case META_FRAME_CONTROL_RESIZE_N:
01523 op = META_GRAB_OP_RESIZING_N;
01524 break;
01525 case META_FRAME_CONTROL_RESIZE_NW:
01526 op = META_GRAB_OP_RESIZING_NW;
01527 break;
01528 case META_FRAME_CONTROL_RESIZE_E:
01529 op = META_GRAB_OP_RESIZING_E;
01530 break;
01531 case META_FRAME_CONTROL_RESIZE_W:
01532 op = META_GRAB_OP_RESIZING_W;
01533 break;
01534 default:
01535 g_assert_not_reached ();
01536 break;
01537 }
01538
01539 meta_core_get (gdk_display, frame->xwindow,
01540 META_CORE_IS_TITLEBAR_ONSCREEN, &titlebar_is_onscreen,
01541 META_CORE_GET_END);
01542
01543 if (!titlebar_is_onscreen)
01544 meta_core_show_window_menu (gdk_display,
01545 frame->xwindow,
01546 event->x_root,
01547 event->y_root,
01548 event->button,
01549 event->time);
01550 else
01551 meta_core_begin_grab_op (gdk_display,
01552 frame->xwindow,
01553 op,
01554 TRUE,
01555 TRUE,
01556 event->button,
01557 0,
01558 event->time,
01559 event->x_root,
01560 event->y_root);
01561 }
01562 else if (control == META_FRAME_CONTROL_TITLE &&
01563 event->button == 1)
01564 {
01565 MetaFrameFlags flags;
01566
01567 meta_core_get (gdk_display, frame->xwindow,
01568 META_CORE_GET_FRAME_FLAGS, &flags,
01569 META_CORE_GET_END);
01570
01571 if (flags & META_FRAME_ALLOWS_MOVE)
01572 {
01573 meta_core_begin_grab_op (gdk_display,
01574 frame->xwindow,
01575 META_GRAB_OP_MOVING,
01576 TRUE,
01577 TRUE,
01578 event->button,
01579 0,
01580 event->time,
01581 event->x_root,
01582 event->y_root);
01583 }
01584 }
01585 else if (event->button == 2)
01586 {
01587 return meta_frame_middle_click_event (frame, event);
01588 }
01589 else if (event->button == 3)
01590 {
01591 return meta_frame_right_click_event (frame, event);
01592 }
01593
01594 return TRUE;
01595 }
01596
01597 void
01598 meta_frames_notify_menu_hide (MetaFrames *frames)
01599 {
01600 if (meta_core_get_grab_op (gdk_display) ==
01601 META_GRAB_OP_CLICKING_MENU)
01602 {
01603 Window grab_frame;
01604
01605 grab_frame = meta_core_get_grab_frame (gdk_display);
01606
01607 if (grab_frame != None)
01608 {
01609 MetaUIFrame *frame;
01610
01611 frame = meta_frames_lookup_window (frames, grab_frame);
01612
01613 if (frame)
01614 {
01615 redraw_control (frames, frame,
01616 META_FRAME_CONTROL_MENU);
01617 meta_core_end_grab_op (gdk_display, CurrentTime);
01618 }
01619 }
01620 }
01621 }
01622
01623 static gboolean
01624 meta_frames_button_release_event (GtkWidget *widget,
01625 GdkEventButton *event)
01626 {
01627 MetaUIFrame *frame;
01628 MetaFrames *frames;
01629 MetaGrabOp op;
01630
01631 frames = META_FRAMES (widget);
01632
01633 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
01634 if (frame == NULL)
01635 return FALSE;
01636
01637 clear_tip (frames);
01638
01639 op = meta_core_get_grab_op (gdk_display);
01640
01641 if (op == META_GRAB_OP_NONE)
01642 return FALSE;
01643
01644
01645
01646
01647
01648 if (frame->xwindow == meta_core_get_grab_frame (gdk_display) &&
01649 ((int) event->button) == meta_core_get_grab_button (gdk_display))
01650 {
01651 MetaFrameControl control;
01652
01653 control = get_control (frames, frame, event->x, event->y);
01654
01655 switch (op)
01656 {
01657 case META_GRAB_OP_CLICKING_MINIMIZE:
01658 if (control == META_FRAME_CONTROL_MINIMIZE)
01659 meta_core_minimize (gdk_display, frame->xwindow);
01660
01661 meta_core_end_grab_op (gdk_display, event->time);
01662 break;
01663
01664 case META_GRAB_OP_CLICKING_MAXIMIZE:
01665 if (control == META_FRAME_CONTROL_MAXIMIZE)
01666 {
01667
01668 meta_core_user_focus (gdk_display,
01669 frame->xwindow,
01670 event->time);
01671 meta_core_maximize (gdk_display, frame->xwindow);
01672 }
01673 meta_core_end_grab_op (gdk_display, event->time);
01674 break;
01675
01676 case META_GRAB_OP_CLICKING_UNMAXIMIZE:
01677 if (control == META_FRAME_CONTROL_UNMAXIMIZE)
01678 meta_core_unmaximize (gdk_display, frame->xwindow);
01679
01680 meta_core_end_grab_op (gdk_display, event->time);
01681 break;
01682
01683 case META_GRAB_OP_CLICKING_DELETE:
01684 if (control == META_FRAME_CONTROL_DELETE)
01685 meta_core_delete (gdk_display, frame->xwindow, event->time);
01686
01687 meta_core_end_grab_op (gdk_display, event->time);
01688 break;
01689
01690 case META_GRAB_OP_CLICKING_MENU:
01691 meta_core_end_grab_op (gdk_display, event->time);
01692 break;
01693
01694 case META_GRAB_OP_CLICKING_SHADE:
01695 if (control == META_FRAME_CONTROL_SHADE)
01696 meta_core_shade (gdk_display, frame->xwindow, event->time);
01697
01698 meta_core_end_grab_op (gdk_display, event->time);
01699 break;
01700
01701 case META_GRAB_OP_CLICKING_UNSHADE:
01702 if (control == META_FRAME_CONTROL_UNSHADE)
01703 meta_core_unshade (gdk_display, frame->xwindow, event->time);
01704
01705 meta_core_end_grab_op (gdk_display, event->time);
01706 break;
01707
01708 case META_GRAB_OP_CLICKING_ABOVE:
01709 if (control == META_FRAME_CONTROL_ABOVE)
01710 meta_core_make_above (gdk_display, frame->xwindow);
01711
01712 meta_core_end_grab_op (gdk_display, event->time);
01713 break;
01714
01715 case META_GRAB_OP_CLICKING_UNABOVE:
01716 if (control == META_FRAME_CONTROL_UNABOVE)
01717 meta_core_unmake_above (gdk_display, frame->xwindow);
01718
01719 meta_core_end_grab_op (gdk_display, event->time);
01720 break;
01721
01722 case META_GRAB_OP_CLICKING_STICK:
01723 if (control == META_FRAME_CONTROL_STICK)
01724 meta_core_stick (gdk_display, frame->xwindow);
01725
01726 meta_core_end_grab_op (gdk_display, event->time);
01727 break;
01728
01729 case META_GRAB_OP_CLICKING_UNSTICK:
01730 if (control == META_FRAME_CONTROL_UNSTICK)
01731 meta_core_unstick (gdk_display, frame->xwindow);
01732
01733 meta_core_end_grab_op (gdk_display, event->time);
01734 break;
01735
01736 default:
01737 break;
01738 }
01739
01740
01741
01742
01743
01744
01745 meta_frames_update_prelit_control (frames, frame, control);
01746 }
01747
01748 return TRUE;
01749 }
01750
01751 static void
01752 meta_frames_update_prelit_control (MetaFrames *frames,
01753 MetaUIFrame *frame,
01754 MetaFrameControl control)
01755 {
01756 MetaFrameControl old_control;
01757 MetaCursor cursor;
01758
01759
01760 meta_verbose ("Updating prelit control from %u to %u\n",
01761 frame->prelit_control, control);
01762
01763 cursor = META_CURSOR_DEFAULT;
01764
01765 switch (control)
01766 {
01767 case META_FRAME_CONTROL_CLIENT_AREA:
01768 break;
01769 case META_FRAME_CONTROL_NONE:
01770 break;
01771 case META_FRAME_CONTROL_TITLE:
01772 break;
01773 case META_FRAME_CONTROL_DELETE:
01774 break;
01775 case META_FRAME_CONTROL_MENU:
01776 break;
01777 case META_FRAME_CONTROL_MINIMIZE:
01778 break;
01779 case META_FRAME_CONTROL_MAXIMIZE:
01780 break;
01781 case META_FRAME_CONTROL_UNMAXIMIZE:
01782 break;
01783 case META_FRAME_CONTROL_SHADE:
01784 break;
01785 case META_FRAME_CONTROL_UNSHADE:
01786 break;
01787 case META_FRAME_CONTROL_ABOVE:
01788 break;
01789 case META_FRAME_CONTROL_UNABOVE:
01790 break;
01791 case META_FRAME_CONTROL_STICK:
01792 break;
01793 case META_FRAME_CONTROL_UNSTICK:
01794 break;
01795 case META_FRAME_CONTROL_RESIZE_SE:
01796 cursor = META_CURSOR_SE_RESIZE;
01797 break;
01798 case META_FRAME_CONTROL_RESIZE_S:
01799 cursor = META_CURSOR_SOUTH_RESIZE;
01800 break;
01801 case META_FRAME_CONTROL_RESIZE_SW:
01802 cursor = META_CURSOR_SW_RESIZE;
01803 break;
01804 case META_FRAME_CONTROL_RESIZE_N:
01805 cursor = META_CURSOR_NORTH_RESIZE;
01806 break;
01807 case META_FRAME_CONTROL_RESIZE_NE:
01808 cursor = META_CURSOR_NE_RESIZE;
01809 break;
01810 case META_FRAME_CONTROL_RESIZE_NW:
01811 cursor = META_CURSOR_NW_RESIZE;
01812 break;
01813 case META_FRAME_CONTROL_RESIZE_W:
01814 cursor = META_CURSOR_WEST_RESIZE;
01815 break;
01816 case META_FRAME_CONTROL_RESIZE_E:
01817 cursor = META_CURSOR_EAST_RESIZE;
01818 break;
01819 }
01820
01821
01822 meta_core_set_screen_cursor (gdk_display,
01823 frame->xwindow,
01824 cursor);
01825
01826 switch (control)
01827 {
01828 case META_FRAME_CONTROL_MENU:
01829 case META_FRAME_CONTROL_MINIMIZE:
01830 case META_FRAME_CONTROL_MAXIMIZE:
01831 case META_FRAME_CONTROL_DELETE:
01832 case META_FRAME_CONTROL_SHADE:
01833 case META_FRAME_CONTROL_UNSHADE:
01834 case META_FRAME_CONTROL_ABOVE:
01835 case META_FRAME_CONTROL_UNABOVE:
01836 case META_FRAME_CONTROL_STICK:
01837 case META_FRAME_CONTROL_UNSTICK:
01838 case META_FRAME_CONTROL_UNMAXIMIZE:
01839
01840 break;
01841 default:
01842
01843 control = META_FRAME_CONTROL_NONE;
01844 break;
01845 }
01846
01847 if (control == frame->prelit_control)
01848 return;
01849
01850
01851 old_control = frame->prelit_control;
01852
01853 frame->prelit_control = control;
01854
01855 redraw_control (frames, frame, old_control);
01856 redraw_control (frames, frame, control);
01857 }
01858
01859 static gboolean
01860 meta_frames_motion_notify_event (GtkWidget *widget,
01861 GdkEventMotion *event)
01862 {
01863 MetaUIFrame *frame;
01864 MetaFrames *frames;
01865 MetaGrabOp grab_op;
01866
01867 frames = META_FRAMES (widget);
01868
01869 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
01870 if (frame == NULL)
01871 return FALSE;
01872
01873 clear_tip (frames);
01874
01875 frames->last_motion_frame = frame;
01876
01877 grab_op = meta_core_get_grab_op (gdk_display);
01878
01879 switch (grab_op)
01880 {
01881 case META_GRAB_OP_CLICKING_MENU:
01882 case META_GRAB_OP_CLICKING_DELETE:
01883 case META_GRAB_OP_CLICKING_MINIMIZE:
01884 case META_GRAB_OP_CLICKING_MAXIMIZE:
01885 case META_GRAB_OP_CLICKING_UNMAXIMIZE:
01886 case META_GRAB_OP_CLICKING_SHADE:
01887 case META_GRAB_OP_CLICKING_UNSHADE:
01888 case META_GRAB_OP_CLICKING_ABOVE:
01889 case META_GRAB_OP_CLICKING_UNABOVE:
01890 case META_GRAB_OP_CLICKING_STICK:
01891 case META_GRAB_OP_CLICKING_UNSTICK:
01892 {
01893 MetaFrameControl control;
01894 int x, y;
01895
01896 gdk_window_get_pointer (frame->window, &x, &y, NULL);
01897
01898
01899
01900
01901 control = get_control (frames, frame, x, y);
01902 if (! ((control == META_FRAME_CONTROL_MENU &&
01903 grab_op == META_GRAB_OP_CLICKING_MENU) ||
01904 (control == META_FRAME_CONTROL_DELETE &&
01905 grab_op == META_GRAB_OP_CLICKING_DELETE) ||
01906 (control == META_FRAME_CONTROL_MINIMIZE &&
01907 grab_op == META_GRAB_OP_CLICKING_MINIMIZE) ||
01908 ((control == META_FRAME_CONTROL_MAXIMIZE ||
01909 control == META_FRAME_CONTROL_UNMAXIMIZE) &&
01910 (grab_op == META_GRAB_OP_CLICKING_MAXIMIZE ||
01911 grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE)) ||
01912 (control == META_FRAME_CONTROL_SHADE &&
01913 grab_op == META_GRAB_OP_CLICKING_SHADE) ||
01914 (control == META_FRAME_CONTROL_UNSHADE &&
01915 grab_op == META_GRAB_OP_CLICKING_UNSHADE) ||
01916 (control == META_FRAME_CONTROL_ABOVE &&
01917 grab_op == META_GRAB_OP_CLICKING_ABOVE) ||
01918 (control == META_FRAME_CONTROL_UNABOVE &&
01919 grab_op == META_GRAB_OP_CLICKING_UNABOVE) ||
01920 (control == META_FRAME_CONTROL_STICK &&
01921 grab_op == META_GRAB_OP_CLICKING_STICK) ||
01922 (control == META_FRAME_CONTROL_UNSTICK &&
01923 grab_op == META_GRAB_OP_CLICKING_UNSTICK)))
01924 control = META_FRAME_CONTROL_NONE;
01925
01926
01927 meta_frames_update_prelit_control (frames, frame, control);
01928
01929
01930 }
01931 break;
01932 case META_GRAB_OP_NONE:
01933 {
01934 MetaFrameControl control;
01935 int x, y;
01936
01937 gdk_window_get_pointer (frame->window, &x, &y, NULL);
01938
01939 control = get_control (frames, frame, x, y);
01940
01941
01942 meta_frames_update_prelit_control (frames, frame, control);
01943
01944 queue_tip (frames);
01945 }
01946 break;
01947
01948 default:
01949 break;
01950 }
01951
01952 return TRUE;
01953 }
01954
01955 static gboolean
01956 meta_frames_destroy_event (GtkWidget *widget,
01957 GdkEventAny *event)
01958 {
01959 MetaUIFrame *frame;
01960 MetaFrames *frames;
01961
01962 frames = META_FRAMES (widget);
01963
01964 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
01965 if (frame == NULL)
01966 return FALSE;
01967
01968 return TRUE;
01969 }
01970
01971
01972 static GdkGC *
01973 get_bg_gc (GdkWindow *window, int x_offset, int y_offset)
01974 {
01975 GdkWindowObject *private = (GdkWindowObject *)window;
01976 guint gc_mask = 0;
01977 GdkGCValues gc_values;
01978
01979 if (private->bg_pixmap == GDK_PARENT_RELATIVE_BG && private->parent)
01980 {
01981 return get_bg_gc (GDK_WINDOW (private->parent),
01982 x_offset + private->x,
01983 y_offset + private->y);
01984 }
01985 else if (private->bg_pixmap &&
01986 private->bg_pixmap != GDK_PARENT_RELATIVE_BG &&
01987 private->bg_pixmap != GDK_NO_BG)
01988 {
01989 gc_values.fill = GDK_TILED;
01990 gc_values.tile = private->bg_pixmap;
01991 gc_values.ts_x_origin = x_offset;
01992 gc_values.ts_y_origin = y_offset;
01993
01994 gc_mask = GDK_GC_FILL | GDK_GC_TILE | GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN;
01995
01996 return gdk_gc_new_with_values (window, &gc_values, gc_mask);
01997 }
01998 else
01999 {
02000 GdkGC *gc = gdk_gc_new (window);
02001
02002 gdk_gc_set_foreground (gc, &(private->bg_color));
02003
02004 return gc;
02005 }
02006 }
02007
02008 static void
02009 clear_backing (GdkPixmap *pixmap,
02010 GdkWindow *window,
02011 int xoffset, int yoffset)
02012 {
02013 GdkGC *tmp_gc = get_bg_gc (window, xoffset, yoffset);
02014
02015 gdk_draw_rectangle (pixmap, tmp_gc, TRUE,
02016 0, 0, -1, -1);
02017
02018 g_object_unref (tmp_gc);
02019 }
02020
02021
02022
02023
02024 static GdkPixmap *
02025 generate_pixmap (MetaFrames *frames,
02026 MetaUIFrame *frame,
02027 MetaRectangle rect)
02028 {
02029 GdkRectangle rectangle;
02030 GdkRegion *region;
02031 GdkPixmap *result;
02032
02033 rectangle.x = rect.x;
02034 rectangle.y = rect.y;
02035 rectangle.width = MAX (rect.width, 1);
02036 rectangle.height = MAX (rect.height, 1);
02037
02038 result = gdk_pixmap_new (frame->window,
02039 rectangle.width, rectangle.height, -1);
02040
02041 clear_backing (result, frame->window, rectangle.x, rectangle.y);
02042
02043 region = gdk_region_rectangle (&rectangle);
02044
02045 meta_frames_paint_to_drawable (frames, frame, result, region,
02046 -rectangle.x, -rectangle.y);
02047
02048 gdk_region_destroy (region);
02049
02050 return result;
02051 }
02052
02053
02054 static void
02055 populate_cache (MetaFrames *frames,
02056 MetaUIFrame *frame)
02057 {
02058 int top, bottom, left, right;
02059 int width, height;
02060 int frame_width, frame_height, screen_width, screen_height;
02061 CachedPixels *pixels;
02062 MetaFrameType frame_type;
02063 MetaFrameFlags frame_flags;
02064 int i;
02065
02066 meta_core_get (gdk_display, frame->xwindow,
02067 META_CORE_GET_FRAME_WIDTH, &frame_width,
02068 META_CORE_GET_FRAME_HEIGHT, &frame_height,
02069 META_CORE_GET_SCREEN_WIDTH, &screen_width,
02070 META_CORE_GET_SCREEN_HEIGHT, &screen_height,
02071 META_CORE_GET_CLIENT_WIDTH, &width,
02072 META_CORE_GET_CLIENT_HEIGHT, &height,
02073 META_CORE_GET_FRAME_TYPE, &frame_type,
02074 META_CORE_GET_FRAME_FLAGS, &frame_flags,
02075 META_CORE_GET_END);
02076
02077
02078 if (frame_width > 2 * screen_width ||
02079 frame_height > 2 * screen_height)
02080 {
02081 return;
02082 }
02083
02084 meta_theme_get_frame_borders (meta_theme_get_current (),
02085 frame_type,
02086 frame->text_height,
02087 frame_flags,
02088 &top, &bottom, &left, &right);
02089
02090 pixels = get_cache (frames, frame);
02091
02092
02093
02094 pixels->piece[0].rect.x = 0;
02095 pixels->piece[0].rect.y = 0;
02096 pixels->piece[0].rect.width = left + width + right;
02097 pixels->piece[0].rect.height = top;
02098
02099 pixels->piece[1].rect.x = 0;
02100 pixels->piece[1].rect.y = top;
02101 pixels->piece[1].rect.width = left;
02102 pixels->piece[1].rect.height = height;
02103
02104 pixels->piece[2].rect.x = left + width;
02105 pixels->piece[2].rect.y = top;
02106 pixels->piece[2].rect.width = right;
02107 pixels->piece[2].rect.height = height;
02108
02109 pixels->piece[3].rect.x = 0;
02110 pixels->piece[3].rect.y = top + height;
02111 pixels->piece[3].rect.width = left + width + right;
02112 pixels->piece[3].rect.height = bottom;
02113
02114 for (i = 0; i < 4; i++)
02115 {
02116 CachedFramePiece *piece = &pixels->piece[i];
02117 if (!piece->pixmap)
02118 piece->pixmap = generate_pixmap (frames, frame, piece->rect);
02119 }
02120
02121 if (frames->invalidate_cache_timeout_id)
02122 g_source_remove (frames->invalidate_cache_timeout_id);
02123
02124 frames->invalidate_cache_timeout_id = g_timeout_add (1000, invalidate_cache_timeout, frames);
02125
02126 if (!g_list_find (frames->invalidate_frames, frame))
02127 frames->invalidate_frames =
02128 g_list_prepend (frames->invalidate_frames, frame);
02129 }
02130
02131 static void
02132 clip_to_screen (GdkRegion *region, MetaUIFrame *frame)
02133 {
02134 GdkRectangle frame_area;
02135 GdkRectangle screen_area = { 0, 0, 0, 0 };
02136 GdkRegion *tmp_region;
02137
02138
02139
02140
02141
02142 meta_core_get (gdk_display, frame->xwindow,
02143 META_CORE_GET_FRAME_X, &frame_area.x,
02144 META_CORE_GET_FRAME_Y, &frame_area.y,
02145 META_CORE_GET_FRAME_WIDTH, &frame_area.width,
02146 META_CORE_GET_FRAME_HEIGHT, &frame_area.height,
02147 META_CORE_GET_SCREEN_WIDTH, &screen_area.height,
02148 META_CORE_GET_SCREEN_HEIGHT, &screen_area.height,
02149 META_CORE_GET_END);
02150
02151 gdk_region_offset (region, frame_area.x, frame_area.y);
02152
02153 tmp_region = gdk_region_rectangle (&frame_area);
02154 gdk_region_intersect (region, tmp_region);
02155 gdk_region_destroy (tmp_region);
02156
02157 gdk_region_offset (region, - frame_area.x, - frame_area.y);
02158 }
02159
02160 static void
02161 subtract_from_region (GdkRegion *region, GdkDrawable *drawable,
02162 gint x, gint y)
02163 {
02164 GdkRectangle rect;
02165 GdkRegion *reg_rect;
02166
02167 gdk_drawable_get_size (drawable, &rect.width, &rect.height);
02168 rect.x = x;
02169 rect.y = y;
02170
02171 reg_rect = gdk_region_rectangle (&rect);
02172 gdk_region_subtract (region, reg_rect);
02173 gdk_region_destroy (reg_rect);
02174 }
02175
02176 static void
02177 cached_pixels_draw (CachedPixels *pixels,
02178 GdkWindow *window,
02179 GdkRegion *region)
02180 {
02181 GdkGC *gc;
02182 int i;
02183
02184 gc = gdk_gc_new (window);
02185
02186 for (i = 0; i < 4; i++)
02187 {
02188 CachedFramePiece *piece;
02189 piece = &pixels->piece[i];
02190
02191 if (piece->pixmap)
02192 {
02193 gdk_draw_drawable (window, gc, piece->pixmap,
02194 0, 0,
02195 piece->rect.x, piece->rect.y,
02196 -1, -1);
02197 subtract_from_region (region, piece->pixmap,
02198 piece->rect.x, piece->rect.y);
02199 }
02200 }
02201
02202 g_object_unref (gc);
02203 }
02204
02205 static gboolean
02206 meta_frames_expose_event (GtkWidget *widget,
02207 GdkEventExpose *event)
02208 {
02209 MetaUIFrame *frame;
02210 MetaFrames *frames;
02211 GdkRegion *region;
02212 CachedPixels *pixels;
02213
02214 frames = META_FRAMES (widget);
02215
02216 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
02217 if (frame == NULL)
02218 return FALSE;
02219
02220 if (frames->expose_delay_count > 0)
02221 {
02222
02223 frame->expose_delayed = TRUE;
02224 return TRUE;
02225 }
02226
02227 populate_cache (frames, frame);
02228
02229 region = gdk_region_copy (event->region);
02230
02231 pixels = get_cache (frames, frame);
02232
02233 cached_pixels_draw (pixels, frame->window, region);
02234
02235 clip_to_screen (region, frame);
02236 meta_frames_paint_to_drawable (frames, frame, frame->window, region, 0, 0);
02237
02238 gdk_region_destroy (region);
02239
02240 return TRUE;
02241 }
02242
02243
02244
02245
02246 #define DECORATING_BORDER 100
02247
02248 static void
02249 meta_frames_paint_to_drawable (MetaFrames *frames,
02250 MetaUIFrame *frame,
02251 GdkDrawable *drawable,
02252 GdkRegion *region,
02253 int x_offset,
02254 int y_offset)
02255 {
02256 GtkWidget *widget;
02257 MetaFrameFlags flags;
02258 MetaFrameType type;
02259 GdkPixbuf *mini_icon;
02260 GdkPixbuf *icon;
02261 int w, h;
02262 MetaButtonState button_states[META_BUTTON_TYPE_LAST];
02263 Window grab_frame;
02264 int i;
02265 MetaButtonLayout button_layout;
02266 MetaGrabOp grab_op;
02267
02268 widget = GTK_WIDGET (frames);
02269
02270 for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
02271 button_states[i] = META_BUTTON_STATE_NORMAL;
02272
02273 grab_frame = meta_core_get_grab_frame (gdk_display);
02274 grab_op = meta_core_get_grab_op (gdk_display);
02275 if (grab_frame != frame->xwindow)
02276 grab_op = META_GRAB_OP_NONE;
02277
02278
02279 switch (frame->prelit_control)
02280 {
02281 case META_FRAME_CONTROL_MENU:
02282 if (grab_op == META_GRAB_OP_CLICKING_MENU)
02283 button_states[META_BUTTON_TYPE_MENU] = META_BUTTON_STATE_PRESSED;
02284 else
02285 button_states[META_BUTTON_TYPE_MENU] = META_BUTTON_STATE_PRELIGHT;
02286 break;
02287 case META_FRAME_CONTROL_MINIMIZE:
02288 if (grab_op == META_GRAB_OP_CLICKING_MINIMIZE)
02289 button_states[META_BUTTON_TYPE_MINIMIZE] = META_BUTTON_STATE_PRESSED;
02290 else
02291 button_states[META_BUTTON_TYPE_MINIMIZE] = META_BUTTON_STATE_PRELIGHT;
02292 break;
02293 case META_FRAME_CONTROL_MAXIMIZE:
02294 if (grab_op == META_GRAB_OP_CLICKING_MAXIMIZE)
02295 button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRESSED;
02296 else
02297 button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT;
02298 break;
02299 case META_FRAME_CONTROL_UNMAXIMIZE:
02300 if (grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE)
02301 button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRESSED;
02302 else
02303 button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT;
02304 break;
02305 case META_FRAME_CONTROL_SHADE:
02306 if (grab_op == META_GRAB_OP_CLICKING_SHADE)
02307 button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRESSED;
02308 else
02309 button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRELIGHT;
02310 break;
02311 case META_FRAME_CONTROL_UNSHADE:
02312 if (grab_op == META_GRAB_OP_CLICKING_UNSHADE)
02313 button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRESSED;
02314 else
02315 button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRELIGHT;
02316 break;
02317 case META_FRAME_CONTROL_ABOVE:
02318 if (grab_op == META_GRAB_OP_CLICKING_ABOVE)
02319 button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRESSED;
02320 else
02321 button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRELIGHT;
02322 break;
02323 case META_FRAME_CONTROL_UNABOVE:
02324 if (grab_op == META_GRAB_OP_CLICKING_UNABOVE)
02325 button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRESSED;
02326 else
02327 button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRELIGHT;
02328 break;
02329 case META_FRAME_CONTROL_STICK:
02330 if (grab_op == META_GRAB_OP_CLICKING_STICK)
02331 button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRESSED;
02332 else
02333 button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRELIGHT;
02334 break;
02335 case META_FRAME_CONTROL_UNSTICK:
02336 if (grab_op == META_GRAB_OP_CLICKING_UNSTICK)
02337 button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRESSED;
02338 else
02339 button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRELIGHT;
02340 break;
02341 case META_FRAME_CONTROL_DELETE:
02342 if (grab_op == META_GRAB_OP_CLICKING_DELETE)
02343 button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRESSED;
02344 else
02345 button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRELIGHT;
02346 break;
02347 default:
02348 break;
02349 }
02350
02351
02352 button_states[META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND] =
02353 button_states[META_BUTTON_TYPE_MENU];
02354 button_states[META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND] =
02355 META_BUTTON_STATE_NORMAL;
02356 button_states[META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND] =
02357 META_BUTTON_STATE_NORMAL;
02358 button_states[META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND] =
02359 button_states[META_BUTTON_TYPE_MINIMIZE];
02360 button_states[META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND] =
02361 button_states[META_BUTTON_TYPE_MAXIMIZE];
02362 button_states[META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND] =
02363 button_states[META_BUTTON_TYPE_CLOSE];
02364
02365 meta_core_get (gdk_display, frame->xwindow,
02366 META_CORE_GET_FRAME_FLAGS, &flags,
02367 META_CORE_GET_FRAME_TYPE, &type,
02368 META_CORE_GET_MINI_ICON, &mini_icon,
02369 META_CORE_GET_ICON, &icon,
02370 META_CORE_GET_CLIENT_WIDTH, &w,
02371 META_CORE_GET_CLIENT_HEIGHT, &h,
02372 META_CORE_GET_END);
02373
02374 meta_frames_ensure_layout (frames, frame);
02375
02376 meta_prefs_get_button_layout (&button_layout);
02377
02378 if (G_LIKELY (GDK_IS_WINDOW (drawable)))
02379 {
02380
02381
02382 GdkRectangle area, *areas;
02383 int n_areas;
02384 int screen_width, screen_height;
02385 GdkRegion *edges, *tmp_region;
02386 int top, bottom, left, right;
02387
02388
02389
02390 meta_theme_get_frame_borders (meta_theme_get_current (),
02391 type, frame->text_height, flags,
02392 &top, &bottom, &left, &right);
02393
02394 meta_core_get (gdk_display, frame->xwindow,
02395 META_CORE_GET_SCREEN_WIDTH, &screen_width,
02396 META_CORE_GET_SCREEN_HEIGHT, &screen_height,
02397 META_CORE_GET_END);
02398
02399 edges = gdk_region_copy (region);
02400
02401
02402
02403 area.x = left;
02404 area.y = top;
02405 area.width = w;
02406 area.height = h;
02407 tmp_region = gdk_region_rectangle (&area);
02408 gdk_region_subtract (edges, tmp_region);
02409 gdk_region_destroy (tmp_region);
02410
02411
02412
02413 gdk_region_get_rectangles (edges, &areas, &n_areas);
02414
02415 for (i = 0; i < n_areas; i++)
02416 {
02417
02418
02419
02420
02421
02422
02423
02424
02425
02426 areas[i].x = MAX (areas[i].x, -DECORATING_BORDER);
02427 areas[i].y = MAX (areas[i].y, -DECORATING_BORDER);
02428 if (areas[i].x+areas[i].width > screen_width + DECORATING_BORDER)
02429 areas[i].width = MIN (0, screen_width - areas[i].x);
02430 if (areas[i].y+areas[i].height > screen_height + DECORATING_BORDER)
02431 areas[i].height = MIN (0, screen_height - areas[i].y);
02432
02433
02434
02435 gdk_window_begin_paint_rect (drawable, &areas[i]);
02436
02437 meta_theme_draw_frame (meta_theme_get_current (),
02438 widget,
02439 drawable,
02440 NULL,
02441 x_offset, y_offset,
02442 type,
02443 flags,
02444 w, h,
02445 frame->layout,
02446 frame->text_height,
02447 &button_layout,
02448 button_states,
02449 mini_icon, icon);
02450
02451 gdk_window_end_paint (drawable);
02452 }
02453
02454 g_free (areas);
02455 gdk_region_destroy (edges);
02456
02457 }
02458 else
02459 {
02460
02461
02462 meta_theme_draw_frame (meta_theme_get_current (),
02463 widget,
02464 drawable,
02465 NULL,
02466 x_offset, y_offset,
02467 type,
02468 flags,
02469 w, h,
02470 frame->layout,
02471 frame->text_height,
02472 &button_layout,
02473 button_states,
02474 mini_icon, icon);
02475 }
02476
02477 }
02478
02479 static void
02480 meta_frames_set_window_background (MetaFrames *frames,
02481 MetaUIFrame *frame)
02482 {
02483 MetaFrameFlags flags;
02484 MetaFrameType type;
02485 MetaFrameStyle *style;
02486 gboolean frame_exists;
02487
02488 meta_core_get (gdk_display, frame->xwindow,
02489 META_CORE_WINDOW_HAS_FRAME, &frame_exists,
02490 META_CORE_GET_FRAME_FLAGS, &flags,
02491 META_CORE_GET_FRAME_TYPE, &type,
02492 META_CORE_GET_END);
02493
02494 if (frame_exists)
02495 {
02496 style = meta_theme_get_frame_style (meta_theme_get_current (),
02497 type, flags);
02498 }
02499
02500 if (frame_exists && style->window_background_color != NULL)
02501 {
02502 GdkColor color;
02503 GdkVisual *visual;
02504
02505 meta_color_spec_render (style->window_background_color,
02506 GTK_WIDGET (frames),
02507 &color);
02508
02509
02510
02511 gdk_rgb_find_color (gtk_widget_get_colormap (GTK_WIDGET (frames)),
02512 &color);
02513
02514
02515
02516 visual = gtk_widget_get_visual (GTK_WIDGET (frames));
02517 if (visual->depth == 32)
02518 {
02519 color.pixel = (color.pixel & 0xffffff) &
02520 style->window_background_alpha << 24;
02521 }
02522
02523 gdk_window_set_background (frame->window, &color);
02524 }
02525 else
02526 {
02527 gtk_style_set_background (GTK_WIDGET (frames)->style,
02528 frame->window, GTK_STATE_NORMAL);
02529 }
02530 }
02531
02532 static gboolean
02533 meta_frames_enter_notify_event (GtkWidget *widget,
02534 GdkEventCrossing *event)
02535 {
02536 MetaUIFrame *frame;
02537 MetaFrames *frames;
02538 MetaFrameControl control;
02539
02540 frames = META_FRAMES (widget);
02541
02542 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
02543 if (frame == NULL)
02544 return FALSE;
02545
02546 control = get_control (frames, frame, event->x, event->y);
02547 meta_frames_update_prelit_control (frames, frame, control);
02548
02549 return TRUE;
02550 }
02551
02552 static gboolean
02553 meta_frames_leave_notify_event (GtkWidget *widget,
02554 GdkEventCrossing *event)
02555 {
02556 MetaUIFrame *frame;
02557 MetaFrames *frames;
02558
02559 frames = META_FRAMES (widget);
02560
02561 frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window));
02562 if (frame == NULL)
02563 return FALSE;
02564
02565 meta_frames_update_prelit_control (frames, frame, META_FRAME_CONTROL_NONE);
02566
02567 clear_tip (frames);
02568
02569 return TRUE;
02570 }
02571
02572 static GdkRectangle*
02573 control_rect (MetaFrameControl control,
02574 MetaFrameGeometry *fgeom)
02575 {
02576 GdkRectangle *rect;
02577
02578 rect = NULL;
02579 switch (control)
02580 {
02581 case META_FRAME_CONTROL_TITLE:
02582 rect = &fgeom->title_rect;
02583 break;
02584 case META_FRAME_CONTROL_DELETE:
02585 rect = &fgeom->close_rect.visible;
02586 break;
02587 case META_FRAME_CONTROL_MENU:
02588 rect = &fgeom->menu_rect.visible;
02589 break;
02590 case META_FRAME_CONTROL_MINIMIZE:
02591 rect = &fgeom->min_rect.visible;
02592 break;
02593 case META_FRAME_CONTROL_MAXIMIZE:
02594 case META_FRAME_CONTROL_UNMAXIMIZE:
02595 rect = &fgeom->max_rect.visible;
02596 break;
02597 case META_FRAME_CONTROL_SHADE:
02598 rect = &fgeom->shade_rect.visible;
02599 break;
02600 case META_FRAME_CONTROL_UNSHADE:
02601 rect = &fgeom->unshade_rect.visible;
02602 break;
02603 case META_FRAME_CONTROL_ABOVE:
02604 rect = &fgeom->above_rect.visible;
02605 break;
02606 case META_FRAME_CONTROL_UNABOVE:
02607 rect = &fgeom->unabove_rect.visible;
02608 break;
02609 case META_FRAME_CONTROL_STICK:
02610 rect = &fgeom->stick_rect.visible;
02611 break;
02612 case META_FRAME_CONTROL_UNSTICK:
02613 rect = &fgeom->unstick_rect.visible;
02614 break;
02615 case META_FRAME_CONTROL_RESIZE_SE:
02616 break;
02617 case META_FRAME_CONTROL_RESIZE_S:
02618 break;
02619 case META_FRAME_CONTROL_RESIZE_SW:
02620 break;
02621 case META_FRAME_CONTROL_RESIZE_N:
02622 break;
02623 case META_FRAME_CONTROL_RESIZE_NE:
02624 break;
02625 case META_FRAME_CONTROL_RESIZE_NW:
02626 break;
02627 case META_FRAME_CONTROL_RESIZE_W:
02628 break;
02629 case META_FRAME_CONTROL_RESIZE_E:
02630 break;
02631 case META_FRAME_CONTROL_NONE:
02632 break;
02633 case META_FRAME_CONTROL_CLIENT_AREA:
02634 break;
02635 }
02636
02637 return rect;
02638 }
02639
02640 #define RESIZE_EXTENDS 15
02641 #define TOP_RESIZE_HEIGHT 2
02642 static MetaFrameControl
02643 get_control (MetaFrames *frames,
02644 MetaUIFrame *frame,
02645 int x, int y)
02646 {
02647 MetaFrameGeometry fgeom;
02648 MetaFrameFlags flags;
02649 gboolean has_vert, has_horiz;
02650 GdkRectangle client;
02651
02652 meta_frames_calc_geometry (frames, frame, &fgeom);
02653
02654 client.x = fgeom.left_width;
02655 client.y = fgeom.top_height;
02656 client.width = fgeom.width - fgeom.left_width - fgeom.right_width;
02657 client.height = fgeom.height - fgeom.top_height - fgeom.bottom_height;
02658
02659 if (POINT_IN_RECT (x, y, client))
02660 return META_FRAME_CONTROL_CLIENT_AREA;
02661
02662 if (POINT_IN_RECT (x, y, fgeom.close_rect.clickable))
02663 return META_FRAME_CONTROL_DELETE;
02664
02665 if (POINT_IN_RECT (x, y, fgeom.min_rect.clickable))
02666 return META_FRAME_CONTROL_MINIMIZE;
02667
02668 if (POINT_IN_RECT (x, y, fgeom.menu_rect.clickable))
02669 return META_FRAME_CONTROL_MENU;
02670
02671 meta_core_get (gdk_display, frame->xwindow,
02672 META_CORE_GET_FRAME_FLAGS, &flags,
02673 META_CORE_GET_END);
02674
02675 has_vert = (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE) != 0;
02676 has_horiz = (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE) != 0;
02677
02678 if (POINT_IN_RECT (x, y, fgeom.title_rect))
02679 {
02680 if (has_vert && y <= TOP_RESIZE_HEIGHT)
02681 return META_FRAME_CONTROL_RESIZE_N;
02682 else
02683 return META_FRAME_CONTROL_TITLE;
02684 }
02685
02686 if (POINT_IN_RECT (x, y, fgeom.max_rect.clickable))
02687 {
02688 if (flags & META_FRAME_MAXIMIZED)
02689 return META_FRAME_CONTROL_UNMAXIMIZE;
02690 else
02691 return META_FRAME_CONTROL_MAXIMIZE;
02692 }
02693
02694 if (POINT_IN_RECT (x, y, fgeom.shade_rect.clickable))
02695 {
02696 return META_FRAME_CONTROL_SHADE;
02697 }
02698
02699 if (POINT_IN_RECT (x, y, fgeom.unshade_rect.clickable))
02700 {
02701 return META_FRAME_CONTROL_UNSHADE;
02702 }
02703
02704 if (POINT_IN_RECT (x, y, fgeom.above_rect.clickable))
02705 {
02706 return META_FRAME_CONTROL_ABOVE;
02707 }
02708
02709 if (POINT_IN_RECT (x, y, fgeom.unabove_rect.clickable))
02710 {
02711 return META_FRAME_CONTROL_UNABOVE;
02712 }
02713
02714 if (POINT_IN_RECT (x, y, fgeom.stick_rect.clickable))
02715 {
02716 return META_FRAME_CONTROL_STICK;
02717 }
02718
02719 if (POINT_IN_RECT (x, y, fgeom.unstick_rect.clickable))
02720 {
02721 return META_FRAME_CONTROL_UNSTICK;
02722 }
02723
02724
02725
02726
02727
02728 if (y >= (fgeom.height - fgeom.bottom_height - RESIZE_EXTENDS) &&
02729 x >= (fgeom.width - fgeom.right_width - RESIZE_EXTENDS))
02730 {
02731 if (has_vert && has_horiz)
02732 return META_FRAME_CONTROL_RESIZE_SE;
02733 else if (has_vert)
02734 return META_FRAME_CONTROL_RESIZE_S;
02735 else if (has_horiz)
02736 return META_FRAME_CONTROL_RESIZE_E;
02737 }
02738 else if (y >= (fgeom.height - fgeom.bottom_height - RESIZE_EXTENDS) &&
02739 x <= (fgeom.left_width + RESIZE_EXTENDS))
02740 {
02741 if (has_vert && has_horiz)
02742 return META_FRAME_CONTROL_RESIZE_SW;
02743 else if (has_vert)
02744 return META_FRAME_CONTROL_RESIZE_S;
02745 else if (has_horiz)
02746 return META_FRAME_CONTROL_RESIZE_W;
02747 }
02748 else if (y < (fgeom.top_height + RESIZE_EXTENDS) &&
02749 x < RESIZE_EXTENDS)
02750 {
02751 if (has_vert && has_horiz)
02752 return META_FRAME_CONTROL_RESIZE_NW;
02753 else if (has_vert)
02754 return META_FRAME_CONTROL_RESIZE_N;
02755 else if (has_horiz)
02756 return META_FRAME_CONTROL_RESIZE_W;
02757 }
02758 else if (y < (fgeom.top_height + RESIZE_EXTENDS) &&
02759 x >= (fgeom.width - RESIZE_EXTENDS))
02760 {
02761 if (has_vert && has_horiz)
02762 return META_FRAME_CONTROL_RESIZE_NE;
02763 else if (has_vert)
02764 return META_FRAME_CONTROL_RESIZE_N;
02765 else if (has_horiz)
02766 return META_FRAME_CONTROL_RESIZE_E;
02767 }
02768 else if (y >= (fgeom.height - fgeom.bottom_height - RESIZE_EXTENDS))
02769 {
02770 if (has_vert)
02771 return META_FRAME_CONTROL_RESIZE_S;
02772 }
02773 else if (y <= TOP_RESIZE_HEIGHT)
02774 {
02775 if (has_vert)
02776 return META_FRAME_CONTROL_RESIZE_N;
02777 else if (has_horiz)
02778 return META_FRAME_CONTROL_TITLE;
02779 }
02780 else if (x <= fgeom.left_width)
02781 {
02782 if (has_horiz)
02783 return META_FRAME_CONTROL_RESIZE_W;
02784 }
02785 else if (x >= (fgeom.width - fgeom.right_width))
02786 {
02787 if (has_horiz)
02788 return META_FRAME_CONTROL_RESIZE_E;
02789 }
02790
02791 if (y >= fgeom.top_height)
02792 return META_FRAME_CONTROL_NONE;
02793 else
02794 return META_FRAME_CONTROL_TITLE;
02795 }
02796
02797 void
02798 meta_frames_push_delay_exposes (MetaFrames *frames)
02799 {
02800 if (frames->expose_delay_count == 0)
02801 {
02802
02803 gdk_window_process_all_updates ();
02804 XFlush (gdk_display);
02805 }
02806
02807 frames->expose_delay_count += 1;
02808 }
02809
02810 static void
02811 queue_pending_exposes_func (gpointer key, gpointer value, gpointer data)
02812 {
02813 MetaUIFrame *frame;
02814 MetaFrames *frames;
02815
02816 frames = META_FRAMES (data);
02817 frame = value;
02818
02819 if (frame->expose_delayed)
02820 {
02821 invalidate_whole_window (frames, frame);
02822 frame->expose_delayed = FALSE;
02823 }
02824 }
02825
02826 void
02827 meta_frames_pop_delay_exposes (MetaFrames *frames)
02828 {
02829 g_return_if_fail (frames->expose_delay_count > 0);
02830
02831 frames->expose_delay_count -= 1;
02832
02833 if (frames->expose_delay_count == 0)
02834 {
02835 g_hash_table_foreach (frames->frames,
02836 queue_pending_exposes_func,
02837 frames);
02838 }
02839 }
02840
02841 static void
02842 invalidate_whole_window (MetaFrames *frames,
02843 MetaUIFrame *frame)
02844 {
02845 gdk_window_invalidate_rect (frame->window, NULL, FALSE);
02846 invalidate_cache (frames, frame);
02847 }