diff options
Diffstat (limited to 'src/ui/frames.c')
-rw-r--r-- | src/ui/frames.c | 2847 |
1 files changed, 0 insertions, 2847 deletions
diff --git a/src/ui/frames.c b/src/ui/frames.c deleted file mode 100644 index 093af921..00000000 --- a/src/ui/frames.c +++ /dev/null @@ -1,2847 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -/* Metacity window frame manager widget */ - -/* - * Copyright (C) 2001 Havoc Pennington - * Copyright (C) 2003 Red Hat, Inc. - * Copyright (C) 2005, 2006 Elijah Newren - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. - */ - -#include <config.h> -#include <math.h> -#include "boxes.h" -#include "frames.h" -#include "util.h" -#include "core.h" -#include "menu.h" -#include "fixedtip.h" -#include "theme.h" -#include "prefs.h" -#include "ui.h" - -#ifdef HAVE_SHAPE -#include <X11/extensions/shape.h> -#endif - -#define DEFAULT_INNER_BUTTON_BORDER 3 - -static void meta_frames_class_init (MetaFramesClass *klass); -static void meta_frames_init (MetaFrames *frames); -static void meta_frames_destroy (GtkObject *object); -static void meta_frames_finalize (GObject *object); -static void meta_frames_style_set (GtkWidget *widget, - GtkStyle *prev_style); -static void meta_frames_realize (GtkWidget *widget); -static void meta_frames_unrealize (GtkWidget *widget); - -static void meta_frames_update_prelit_control (MetaFrames *frames, - MetaUIFrame *frame, - MetaFrameControl control); -static gboolean meta_frames_button_press_event (GtkWidget *widget, - GdkEventButton *event); -static gboolean meta_frames_button_release_event (GtkWidget *widget, - GdkEventButton *event); -static gboolean meta_frames_motion_notify_event (GtkWidget *widget, - GdkEventMotion *event); -static gboolean meta_frames_destroy_event (GtkWidget *widget, - GdkEventAny *event); -static gboolean meta_frames_expose_event (GtkWidget *widget, - GdkEventExpose *event); -static gboolean meta_frames_enter_notify_event (GtkWidget *widget, - GdkEventCrossing *event); -static gboolean meta_frames_leave_notify_event (GtkWidget *widget, - GdkEventCrossing *event); - -static void meta_frames_paint_to_drawable (MetaFrames *frames, - MetaUIFrame *frame, - GdkDrawable *drawable, - GdkRegion *region, - int x_offset, - int y_offset); - -static void meta_frames_set_window_background (MetaFrames *frames, - MetaUIFrame *frame); - -static void meta_frames_calc_geometry (MetaFrames *frames, - MetaUIFrame *frame, - MetaFrameGeometry *fgeom); - -static void meta_frames_ensure_layout (MetaFrames *frames, - MetaUIFrame *frame); - -static MetaUIFrame* meta_frames_lookup_window (MetaFrames *frames, - Window xwindow); - -static void meta_frames_font_changed (MetaFrames *frames); -static void meta_frames_button_layout_changed (MetaFrames *frames); - - -static GdkRectangle* control_rect (MetaFrameControl control, - MetaFrameGeometry *fgeom); -static MetaFrameControl get_control (MetaFrames *frames, - MetaUIFrame *frame, - int x, - int y); -static void clear_tip (MetaFrames *frames); -static void invalidate_all_caches (MetaFrames *frames); -static void invalidate_whole_window (MetaFrames *frames, - MetaUIFrame *frame); - -static GtkWidgetClass *parent_class = NULL; - -GtkType -meta_frames_get_type (void) -{ - static GtkType frames_type = 0; - - if (!frames_type) - { - static const GtkTypeInfo frames_info = - { - "MetaFrames", - sizeof (MetaFrames), - sizeof (MetaFramesClass), - (GtkClassInitFunc) meta_frames_class_init, - (GtkObjectInitFunc) meta_frames_init, - /* reserved_1 */ NULL, - /* reserved_2 */ NULL, - (GtkClassInitFunc) NULL, - }; - - frames_type = gtk_type_unique (GTK_TYPE_WINDOW, &frames_info); - } - - return frames_type; -} - -static void -meta_frames_class_init (MetaFramesClass *class) -{ - GObjectClass *gobject_class; - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; - - gobject_class = G_OBJECT_CLASS (class); - object_class = (GtkObjectClass*) class; - widget_class = (GtkWidgetClass*) class; - - parent_class = g_type_class_peek_parent (class); - - gobject_class->finalize = meta_frames_finalize; - object_class->destroy = meta_frames_destroy; - - widget_class->style_set = meta_frames_style_set; - - widget_class->realize = meta_frames_realize; - widget_class->unrealize = meta_frames_unrealize; - - widget_class->expose_event = meta_frames_expose_event; - widget_class->destroy_event = meta_frames_destroy_event; - widget_class->button_press_event = meta_frames_button_press_event; - widget_class->button_release_event = meta_frames_button_release_event; - widget_class->motion_notify_event = meta_frames_motion_notify_event; - widget_class->enter_notify_event = meta_frames_enter_notify_event; - widget_class->leave_notify_event = meta_frames_leave_notify_event; -} - -static gint -unsigned_long_equal (gconstpointer v1, - gconstpointer v2) -{ - return *((const gulong*) v1) == *((const gulong*) v2); -} - -static guint -unsigned_long_hash (gconstpointer v) -{ - gulong val = * (const gulong *) v; - - /* I'm not sure this works so well. */ -#if GLIB_SIZEOF_LONG > 4 - return (guint) (val ^ (val >> 32)); -#else - return val; -#endif -} - -static void -prefs_changed_callback (MetaPreference pref, - void *data) -{ - switch (pref) - { - case META_PREF_TITLEBAR_FONT: - meta_frames_font_changed (META_FRAMES (data)); - break; - case META_PREF_BUTTON_LAYOUT: - meta_frames_button_layout_changed (META_FRAMES (data)); - break; - default: - break; - } -} - -static void -meta_frames_init (MetaFrames *frames) -{ - GTK_WINDOW (frames)->type = GTK_WINDOW_POPUP; - - frames->text_heights = g_hash_table_new (NULL, NULL); - - frames->frames = g_hash_table_new (unsigned_long_hash, unsigned_long_equal); - - frames->tooltip_timeout = 0; - - frames->expose_delay_count = 0; - - frames->invalidate_cache_timeout_id = 0; - frames->invalidate_frames = NULL; - frames->cache = g_hash_table_new (g_direct_hash, g_direct_equal); - - gtk_widget_set_double_buffered (GTK_WIDGET (frames), FALSE); - - meta_prefs_add_listener (prefs_changed_callback, frames); -} - -static void -listify_func (gpointer key, gpointer value, gpointer data) -{ - GSList **listp; - - listp = data; - *listp = g_slist_prepend (*listp, value); -} - -static void -meta_frames_destroy (GtkObject *object) -{ - GSList *winlist; - GSList *tmp; - MetaFrames *frames; - - frames = META_FRAMES (object); - - clear_tip (frames); - - winlist = NULL; - g_hash_table_foreach (frames->frames, listify_func, &winlist); - - /* Unmanage all frames */ - for (tmp = winlist; tmp != NULL; tmp = tmp->next) - { - MetaUIFrame *frame; - - frame = tmp->data; - - meta_frames_unmanage_window (frames, frame->xwindow); - } - g_slist_free (winlist); - - GTK_OBJECT_CLASS (parent_class)->destroy (object); -} - -static void -meta_frames_finalize (GObject *object) -{ - MetaFrames *frames; - - frames = META_FRAMES (object); - - meta_prefs_remove_listener (prefs_changed_callback, frames); - - g_hash_table_destroy (frames->text_heights); - - invalidate_all_caches (frames); - if (frames->invalidate_cache_timeout_id) - g_source_remove (frames->invalidate_cache_timeout_id); - - g_assert (g_hash_table_size (frames->frames) == 0); - g_hash_table_destroy (frames->frames); - g_hash_table_destroy (frames->cache); - - G_OBJECT_CLASS (parent_class)->finalize (object); -} - -typedef struct -{ - MetaRectangle rect; - GdkPixmap *pixmap; -} CachedFramePiece; - -typedef struct -{ - /* Caches of the four rendered sides in a MetaFrame. - * Order: top (titlebar), left, right, bottom. - */ - CachedFramePiece piece[4]; -} CachedPixels; - -static CachedPixels * -get_cache (MetaFrames *frames, - MetaUIFrame *frame) -{ - CachedPixels *pixels; - - pixels = g_hash_table_lookup (frames->cache, frame); - - if (!pixels) - { - pixels = g_new0 (CachedPixels, 1); - g_hash_table_insert (frames->cache, frame, pixels); - } - - return pixels; -} - -static void -invalidate_cache (MetaFrames *frames, - MetaUIFrame *frame) -{ - CachedPixels *pixels = get_cache (frames, frame); - int i; - - for (i = 0; i < 4; i++) - if (pixels->piece[i].pixmap) - g_object_unref (pixels->piece[i].pixmap); - - g_free (pixels); - g_hash_table_remove (frames->cache, frame); -} - -static void -invalidate_all_caches (MetaFrames *frames) -{ - GList *l; - - for (l = frames->invalidate_frames; l; l = l->next) - { - MetaUIFrame *frame = l->data; - - invalidate_cache (frames, frame); - } - - g_list_free (frames->invalidate_frames); - frames->invalidate_frames = NULL; -} - -static gboolean -invalidate_cache_timeout (gpointer data) -{ - MetaFrames *frames = data; - - invalidate_all_caches (frames); - frames->invalidate_cache_timeout_id = 0; - return FALSE; -} - -static void -queue_recalc_func (gpointer key, gpointer value, gpointer data) -{ - MetaUIFrame *frame; - MetaFrames *frames; - - frames = META_FRAMES (data); - frame = value; - - /* If a resize occurs it will cause a redraw, but the - * resize may not actually be needed so we always redraw - * in case of color change. - */ - meta_frames_set_window_background (frames, frame); - - invalidate_whole_window (frames, frame); - meta_core_queue_frame_resize (gdk_display, - frame->xwindow); - if (frame->layout) - { - /* save title to recreate layout */ - g_free (frame->title); - - frame->title = g_strdup (pango_layout_get_text (frame->layout)); - - g_object_unref (G_OBJECT (frame->layout)); - frame->layout = NULL; - } -} - -static void -meta_frames_font_changed (MetaFrames *frames) -{ - if (g_hash_table_size (frames->text_heights) > 0) - { - g_hash_table_destroy (frames->text_heights); - frames->text_heights = g_hash_table_new (NULL, NULL); - } - - /* Queue a draw/resize on all frames */ - g_hash_table_foreach (frames->frames, - queue_recalc_func, frames); - -} - -static void -queue_draw_func (gpointer key, gpointer value, gpointer data) -{ - MetaUIFrame *frame; - MetaFrames *frames; - - frames = META_FRAMES (data); - frame = value; - - /* If a resize occurs it will cause a redraw, but the - * resize may not actually be needed so we always redraw - * in case of color change. - */ - meta_frames_set_window_background (frames, frame); - - invalidate_whole_window (frames, frame); -} - -static void -meta_frames_button_layout_changed (MetaFrames *frames) -{ - g_hash_table_foreach (frames->frames, - queue_draw_func, frames); -} - -static void -meta_frames_style_set (GtkWidget *widget, - GtkStyle *prev_style) -{ - MetaFrames *frames; - - frames = META_FRAMES (widget); - - meta_frames_font_changed (frames); - - GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style); -} - -static void -meta_frames_ensure_layout (MetaFrames *frames, - MetaUIFrame *frame) -{ - GtkWidget *widget; - MetaFrameFlags flags; - MetaFrameType type; - MetaFrameStyle *style; - - g_return_if_fail (GTK_WIDGET_REALIZED (frames)); - - widget = GTK_WIDGET (frames); - - meta_core_get (gdk_display, frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_FRAME_TYPE, &type, - META_CORE_GET_END); - - style = meta_theme_get_frame_style (meta_theme_get_current (), - type, flags); - - if (style != frame->cache_style) - { - if (frame->layout) - { - /* save title to recreate layout */ - g_free (frame->title); - - frame->title = g_strdup (pango_layout_get_text (frame->layout)); - - g_object_unref (G_OBJECT (frame->layout)); - frame->layout = NULL; - } - } - - frame->cache_style = style; - - if (frame->layout == NULL) - { - gpointer key, value; - PangoFontDescription *font_desc; - double scale; - int size; - - scale = meta_theme_get_title_scale (meta_theme_get_current (), - type, - flags); - - frame->layout = gtk_widget_create_pango_layout (widget, frame->title); - - pango_layout_set_auto_dir (frame->layout, FALSE); - - font_desc = meta_gtk_widget_get_font_desc (widget, scale, - meta_prefs_get_titlebar_font ()); - - size = pango_font_description_get_size (font_desc); - - if (g_hash_table_lookup_extended (frames->text_heights, - GINT_TO_POINTER (size), - &key, &value)) - { - frame->text_height = GPOINTER_TO_INT (value); - } - else - { - frame->text_height = - meta_pango_font_desc_get_text_height (font_desc, - gtk_widget_get_pango_context (widget)); - - g_hash_table_replace (frames->text_heights, - GINT_TO_POINTER (size), - GINT_TO_POINTER (frame->text_height)); - } - - pango_layout_set_font_description (frame->layout, - font_desc); - - pango_font_description_free (font_desc); - - /* Save some RAM */ - g_free (frame->title); - frame->title = NULL; - } -} - -static void -meta_frames_calc_geometry (MetaFrames *frames, - MetaUIFrame *frame, - MetaFrameGeometry *fgeom) -{ - int width, height; - MetaFrameFlags flags; - MetaFrameType type; - MetaButtonLayout button_layout; - - meta_core_get (gdk_display, frame->xwindow, - META_CORE_GET_CLIENT_WIDTH, &width, - META_CORE_GET_CLIENT_HEIGHT, &height, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_FRAME_TYPE, &type, - META_CORE_GET_END); - - meta_frames_ensure_layout (frames, frame); - - meta_prefs_get_button_layout (&button_layout); - - meta_theme_calc_geometry (meta_theme_get_current (), - type, - frame->text_height, - flags, - width, height, - &button_layout, - fgeom); -} - -MetaFrames* -meta_frames_new (int screen_number) -{ - GdkScreen *screen; - - screen = gdk_display_get_screen (gdk_display_get_default (), - screen_number); - - return g_object_new (META_TYPE_FRAMES, - "screen", screen, - NULL); -} - -void -meta_frames_manage_window (MetaFrames *frames, - Window xwindow, - GdkWindow *window) -{ - MetaUIFrame *frame; - - g_assert (window); - - frame = g_new (MetaUIFrame, 1); - - frame->window = window; - - gdk_window_set_user_data (frame->window, frames); - - /* Don't set event mask here, it's in frame.c */ - - frame->xwindow = xwindow; - frame->cache_style = NULL; - frame->layout = NULL; - frame->text_height = -1; - frame->title = NULL; - frame->expose_delayed = FALSE; - frame->shape_applied = FALSE; - frame->prelit_control = META_FRAME_CONTROL_NONE; - - /* Don't set the window background yet; we need frame->xwindow to be - * registered with its MetaWindow, which happens after this function - * and meta_ui_create_frame_window() return to meta_window_ensure_frame(). - */ - - meta_core_grab_buttons (gdk_display, frame->xwindow); - - g_hash_table_replace (frames->frames, &frame->xwindow, frame); -} - -void -meta_frames_unmanage_window (MetaFrames *frames, - Window xwindow) -{ - MetaUIFrame *frame; - - clear_tip (frames); - - frame = g_hash_table_lookup (frames->frames, &xwindow); - - if (frame) - { - /* invalidating all caches ensures the frame - * is not actually referenced anymore - */ - invalidate_all_caches (frames); - - /* restore the cursor */ - meta_core_set_screen_cursor (gdk_display, - frame->xwindow, - META_CURSOR_DEFAULT); - - gdk_window_set_user_data (frame->window, NULL); - - if (frames->last_motion_frame == frame) - frames->last_motion_frame = NULL; - - g_hash_table_remove (frames->frames, &frame->xwindow); - - gdk_window_destroy (frame->window); - - if (frame->layout) - g_object_unref (G_OBJECT (frame->layout)); - - if (frame->title) - g_free (frame->title); - - g_free (frame); - } - else - meta_warning ("Frame 0x%lx not managed, can't unmanage\n", xwindow); -} - -static void -meta_frames_realize (GtkWidget *widget) -{ - if (GTK_WIDGET_CLASS (parent_class)->realize) - GTK_WIDGET_CLASS (parent_class)->realize (widget); -} - -static void -meta_frames_unrealize (GtkWidget *widget) -{ - if (GTK_WIDGET_CLASS (parent_class)->unrealize) - GTK_WIDGET_CLASS (parent_class)->unrealize (widget); -} - -static MetaUIFrame* -meta_frames_lookup_window (MetaFrames *frames, - Window xwindow) -{ - MetaUIFrame *frame; - - frame = g_hash_table_lookup (frames->frames, &xwindow); - - return frame; -} - -void -meta_frames_get_geometry (MetaFrames *frames, - Window xwindow, - int *top_height, int *bottom_height, - int *left_width, int *right_width) -{ - MetaFrameFlags flags; - MetaUIFrame *frame; - MetaFrameType type; - - frame = meta_frames_lookup_window (frames, xwindow); - - if (frame == NULL) - meta_bug ("No such frame 0x%lx\n", xwindow); - - meta_core_get (gdk_display, frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_FRAME_TYPE, &type, - META_CORE_GET_END); - - g_return_if_fail (type < META_FRAME_TYPE_LAST); - - meta_frames_ensure_layout (frames, frame); - - /* We can't get the full geometry, because that depends on - * the client window size and probably we're being called - * by the core move/resize code to decide on the client - * window size - */ - meta_theme_get_frame_borders (meta_theme_get_current (), - type, - frame->text_height, - flags, - top_height, bottom_height, - left_width, right_width); -} - -void -meta_frames_reset_bg (MetaFrames *frames, - Window xwindow) -{ - MetaUIFrame *frame; - - frame = meta_frames_lookup_window (frames, xwindow); - - meta_frames_set_window_background (frames, frame); -} - -static void -set_background_none (Display *xdisplay, - Window xwindow) -{ - XSetWindowAttributes attrs; - - attrs.background_pixmap = None; - XChangeWindowAttributes (xdisplay, xwindow, - CWBackPixmap, &attrs); -} - -void -meta_frames_unflicker_bg (MetaFrames *frames, - Window xwindow, - int target_width, - int target_height) -{ - MetaUIFrame *frame; - - frame = meta_frames_lookup_window (frames, xwindow); - g_return_if_fail (frame != NULL); - -#if 0 - pixmap = gdk_pixmap_new (frame->window, - width, height, - -1); - - /* Oops, no way to get the background here */ - - meta_frames_paint_to_drawable (frames, frame, pixmap); -#endif - - set_background_none (gdk_display, frame->xwindow); -} - -void -meta_frames_apply_shapes (MetaFrames *frames, - Window xwindow, - int new_window_width, - int new_window_height, - gboolean window_has_shape) -{ -#ifdef HAVE_SHAPE - /* Apply shapes as if window had new_window_width, new_window_height */ - MetaUIFrame *frame; - MetaFrameGeometry fgeom; - XRectangle xrect; - Region corners_xregion; - Region window_xregion; - - frame = meta_frames_lookup_window (frames, xwindow); - g_return_if_fail (frame != NULL); - - meta_frames_calc_geometry (frames, frame, &fgeom); - - if (!(fgeom.top_left_corner_rounded_radius != 0 || - fgeom.top_right_corner_rounded_radius != 0 || - fgeom.bottom_left_corner_rounded_radius != 0 || - fgeom.bottom_right_corner_rounded_radius != 0 || - window_has_shape)) - { - if (frame->shape_applied) - { - meta_topic (META_DEBUG_SHAPES, - "Unsetting shape mask on frame 0x%lx\n", - frame->xwindow); - - XShapeCombineMask (gdk_display, frame->xwindow, - ShapeBounding, 0, 0, None, ShapeSet); - frame->shape_applied = FALSE; - } - else - { - meta_topic (META_DEBUG_SHAPES, - "Frame 0x%lx still doesn't need a shape mask\n", - frame->xwindow); - } - - return; /* nothing to do */ - } - - corners_xregion = XCreateRegion (); - - if (fgeom.top_left_corner_rounded_radius != 0) - { - const int corner = fgeom.top_left_corner_rounded_radius; - const float radius = sqrt(corner) + corner; - int i; - - for (i=0; i<corner; i++) - { - const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5)))); - xrect.x = 0; - xrect.y = i; - xrect.width = width; - xrect.height = 1; - - XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion); - } - } - - if (fgeom.top_right_corner_rounded_radius != 0) - { - const int corner = fgeom.top_right_corner_rounded_radius; - const float radius = sqrt(corner) + corner; - int i; - - for (i=0; i<corner; i++) - { - const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5)))); - xrect.x = new_window_width - width; - xrect.y = i; - xrect.width = width; - xrect.height = 1; - - XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion); - } - } - - if (fgeom.bottom_left_corner_rounded_radius != 0) - { - const int corner = fgeom.bottom_left_corner_rounded_radius; - const float radius = sqrt(corner) + corner; - int i; - - for (i=0; i<corner; i++) - { - const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5)))); - xrect.x = 0; - xrect.y = new_window_height - i - 1; - xrect.width = width; - xrect.height = 1; - - XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion); - } - } - - if (fgeom.bottom_right_corner_rounded_radius != 0) - { - const int corner = fgeom.bottom_right_corner_rounded_radius; - const float radius = sqrt(corner) + corner; - int i; - - for (i=0; i<corner; i++) - { - const int width = floor(0.5 + radius - sqrt(radius*radius - (radius-(i+0.5))*(radius-(i+0.5)))); - xrect.x = new_window_width - width; - xrect.y = new_window_height - i - 1; - xrect.width = width; - xrect.height = 1; - - XUnionRectWithRegion (&xrect, corners_xregion, corners_xregion); - } - } - - window_xregion = XCreateRegion (); - - xrect.x = 0; - xrect.y = 0; - xrect.width = new_window_width; - xrect.height = new_window_height; - - XUnionRectWithRegion (&xrect, window_xregion, window_xregion); - - XSubtractRegion (window_xregion, corners_xregion, window_xregion); - - XDestroyRegion (corners_xregion); - - if (window_has_shape) - { - /* The client window is oclock or something and has a shape - * mask. To avoid a round trip to get its shape region, we - * create a fake window that's never mapped, build up our shape - * on that, then combine. Wasting the window is assumed cheaper - * than a round trip, but who really knows for sure. - */ - XSetWindowAttributes attrs; - Window shape_window; - Window client_window; - Region client_xregion; - GdkScreen *screen; - int screen_number; - - meta_topic (META_DEBUG_SHAPES, - "Frame 0x%lx needs to incorporate client shape\n", - frame->xwindow); - - screen = gtk_widget_get_screen (GTK_WIDGET (frames)); - screen_number = gdk_x11_screen_get_screen_number (screen); - - attrs.override_redirect = True; - - shape_window = XCreateWindow (gdk_display, - RootWindow (gdk_display, screen_number), - -5000, -5000, - new_window_width, - new_window_height, - 0, - CopyFromParent, - CopyFromParent, - (Visual *)CopyFromParent, - CWOverrideRedirect, - &attrs); - - /* Copy the client's shape to the temporary shape_window */ - meta_core_get (gdk_display, frame->xwindow, - META_CORE_GET_CLIENT_XWINDOW, &client_window, - META_CORE_GET_END); - - XShapeCombineShape (gdk_display, shape_window, ShapeBounding, - fgeom.left_width, - fgeom.top_height, - client_window, - ShapeBounding, - ShapeSet); - - /* Punch the client area out of the normal frame shape, - * then union it with the shape_window's existing shape - */ - client_xregion = XCreateRegion (); - - xrect.x = fgeom.left_width; - xrect.y = fgeom.top_height; - xrect.width = new_window_width - fgeom.right_width - xrect.x; - xrect.height = new_window_height - fgeom.bottom_height - xrect.y; - - XUnionRectWithRegion (&xrect, client_xregion, client_xregion); - - XSubtractRegion (window_xregion, client_xregion, window_xregion); - - XDestroyRegion (client_xregion); - - XShapeCombineRegion (gdk_display, shape_window, - ShapeBounding, 0, 0, window_xregion, ShapeUnion); - - /* Now copy shape_window shape to the real frame */ - XShapeCombineShape (gdk_display, frame->xwindow, ShapeBounding, - 0, 0, - shape_window, - ShapeBounding, - ShapeSet); - - XDestroyWindow (gdk_display, shape_window); - } - else - { - /* No shape on the client, so just do simple stuff */ - - meta_topic (META_DEBUG_SHAPES, - "Frame 0x%lx has shaped corners\n", - frame->xwindow); - - XShapeCombineRegion (gdk_display, frame->xwindow, - ShapeBounding, 0, 0, window_xregion, ShapeSet); - } - - frame->shape_applied = TRUE; - - XDestroyRegion (window_xregion); -#endif /* HAVE_SHAPE */ -} - -void -meta_frames_move_resize_frame (MetaFrames *frames, - Window xwindow, - int x, - int y, - int width, - int height) -{ - MetaUIFrame *frame = meta_frames_lookup_window (frames, xwindow); - int old_x, old_y, old_width, old_height; - - gdk_drawable_get_size (frame->window, &old_width, &old_height); - gdk_window_get_position (frame->window, &old_x, &old_y); - - gdk_window_move_resize (frame->window, x, y, width, height); - - if (old_width != width || old_height != height) - invalidate_whole_window (frames, frame); -} - -void -meta_frames_queue_draw (MetaFrames *frames, - Window xwindow) -{ - MetaUIFrame *frame; - - frame = meta_frames_lookup_window (frames, xwindow); - - invalidate_whole_window (frames, frame); -} - -void -meta_frames_set_title (MetaFrames *frames, - Window xwindow, - const char *title) -{ - MetaUIFrame *frame; - - frame = meta_frames_lookup_window (frames, xwindow); - - g_assert (frame); - - g_free (frame->title); - frame->title = g_strdup (title); - - if (frame->layout) - { - g_object_unref (frame->layout); - frame->layout = NULL; - } - - invalidate_whole_window (frames, frame); -} - -void -meta_frames_repaint_frame (MetaFrames *frames, - Window xwindow) -{ - MetaUIFrame *frame; - - frame = meta_frames_lookup_window (frames, xwindow); - - g_assert (frame); - - /* repaint everything, so the other frame don't - * lag behind if they are exposed - */ - gdk_window_process_all_updates (); -} - -static void -show_tip_now (MetaFrames *frames) -{ - const char *tiptext; - MetaUIFrame *frame; - int x, y, root_x, root_y; - Window root, child; - guint mask; - MetaFrameControl control; - - frame = frames->last_motion_frame; - if (frame == NULL) - return; - - XQueryPointer (gdk_display, - frame->xwindow, - &root, &child, - &root_x, &root_y, - &x, &y, - &mask); - - control = get_control (frames, frame, x, y); - - tiptext = NULL; - switch (control) - { - case META_FRAME_CONTROL_TITLE: - break; - case META_FRAME_CONTROL_DELETE: - tiptext = _("Close Window"); - break; - case META_FRAME_CONTROL_MENU: - tiptext = _("Window Menu"); - break; - case META_FRAME_CONTROL_MINIMIZE: - tiptext = _("Minimize Window"); - break; - case META_FRAME_CONTROL_MAXIMIZE: - tiptext = _("Maximize Window"); - break; - case META_FRAME_CONTROL_UNMAXIMIZE: - tiptext = _("Unmaximize Window"); - break; - case META_FRAME_CONTROL_SHADE: - tiptext = _("Roll Up Window"); - break; - case META_FRAME_CONTROL_UNSHADE: - tiptext = _("Unroll Window"); - break; - case META_FRAME_CONTROL_ABOVE: - tiptext = _("Keep Window On Top"); - break; - case META_FRAME_CONTROL_UNABOVE: - tiptext = _("Remove Window From Top"); - break; - case META_FRAME_CONTROL_STICK: - tiptext = _("Always On Visible Workspace"); - break; - case META_FRAME_CONTROL_UNSTICK: - tiptext = _("Put Window On Only One Workspace"); - break; - case META_FRAME_CONTROL_RESIZE_SE: - break; - case META_FRAME_CONTROL_RESIZE_S: - break; - case META_FRAME_CONTROL_RESIZE_SW: - break; - case META_FRAME_CONTROL_RESIZE_N: - break; - case META_FRAME_CONTROL_RESIZE_NE: - break; - case META_FRAME_CONTROL_RESIZE_NW: - break; - case META_FRAME_CONTROL_RESIZE_W: - break; - case META_FRAME_CONTROL_RESIZE_E: - break; - case META_FRAME_CONTROL_NONE: - break; - case META_FRAME_CONTROL_CLIENT_AREA: - break; - } - - if (tiptext) - { - MetaFrameGeometry fgeom; - GdkRectangle *rect; - int dx, dy; - int screen_number; - - meta_frames_calc_geometry (frames, frame, &fgeom); - - rect = control_rect (control, &fgeom); - - /* get conversion delta for root-to-frame coords */ - dx = root_x - x; - dy = root_y - y; - - /* Align the tooltip to the button right end if RTL */ - if (meta_ui_get_direction() == META_UI_DIRECTION_RTL) - dx += rect->width; - - screen_number = gdk_screen_get_number (gtk_widget_get_screen (GTK_WIDGET (frames))); - - meta_fixed_tip_show (gdk_display, - screen_number, - rect->x + dx, - rect->y + rect->height + 2 + dy, - tiptext); - } -} - -static gboolean -tip_timeout_func (gpointer data) -{ - MetaFrames *frames; - - frames = data; - - show_tip_now (frames); - - return FALSE; -} - -#define TIP_DELAY 450 -static void -queue_tip (MetaFrames *frames) -{ - clear_tip (frames); - - frames->tooltip_timeout = g_timeout_add (TIP_DELAY, - tip_timeout_func, - frames); -} - -static void -clear_tip (MetaFrames *frames) -{ - if (frames->tooltip_timeout) - { - g_source_remove (frames->tooltip_timeout); - frames->tooltip_timeout = 0; - } - meta_fixed_tip_hide (); -} - -static void -redraw_control (MetaFrames *frames, - MetaUIFrame *frame, - MetaFrameControl control) -{ - MetaFrameGeometry fgeom; - GdkRectangle *rect; - - meta_frames_calc_geometry (frames, frame, &fgeom); - - rect = control_rect (control, &fgeom); - - gdk_window_invalidate_rect (frame->window, rect, FALSE); - invalidate_cache (frames, frame); -} - -static gboolean -meta_frame_titlebar_event (MetaUIFrame *frame, - GdkEventButton *event, - int action) -{ - MetaFrameFlags flags; - - switch (action) - { - case META_ACTION_TITLEBAR_TOGGLE_SHADE: - { - meta_core_get (gdk_display, frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_END); - - if (flags & META_FRAME_ALLOWS_SHADE) - { - if (flags & META_FRAME_SHADED) - meta_core_unshade (gdk_display, - frame->xwindow, - event->time); - else - meta_core_shade (gdk_display, - frame->xwindow, - event->time); - } - } - break; - - case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE: - { - meta_core_get (gdk_display, frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_END); - - if (flags & META_FRAME_ALLOWS_MAXIMIZE) - { - meta_core_toggle_maximize (gdk_display, frame->xwindow); - } - } - break; - - case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_HORIZONTALLY: - { - meta_core_get (gdk_display, frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_END); - - if (flags & META_FRAME_ALLOWS_MAXIMIZE) - { - meta_core_toggle_maximize_horizontally (gdk_display, frame->xwindow); - } - } - break; - - case META_ACTION_TITLEBAR_TOGGLE_MAXIMIZE_VERTICALLY: - { - meta_core_get (gdk_display, frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_END); - - if (flags & META_FRAME_ALLOWS_MAXIMIZE) - { - meta_core_toggle_maximize_vertically (gdk_display, frame->xwindow); - } - } - break; - - case META_ACTION_TITLEBAR_MINIMIZE: - { - meta_core_get (gdk_display, frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_END); - - if (flags & META_FRAME_ALLOWS_MINIMIZE) - { - meta_core_minimize (gdk_display, frame->xwindow); - } - } - break; - - case META_ACTION_TITLEBAR_NONE: - /* Yaay, a sane user that doesn't use that other weird crap! */ - break; - - case META_ACTION_TITLEBAR_LOWER: - meta_core_user_lower_and_unfocus (gdk_display, - frame->xwindow, - event->time); - break; - - case META_ACTION_TITLEBAR_MENU: - meta_core_show_window_menu (gdk_display, - frame->xwindow, - event->x_root, - event->y_root, - event->button, - event->time); - break; - - case META_ACTION_TITLEBAR_LAST: - break; - } - - return TRUE; -} - -static gboolean -meta_frame_double_click_event (MetaUIFrame *frame, - GdkEventButton *event) -{ - int action = meta_prefs_get_action_double_click_titlebar (); - - return meta_frame_titlebar_event (frame, event, action); -} - -static gboolean -meta_frame_middle_click_event (MetaUIFrame *frame, - GdkEventButton *event) -{ - int action = meta_prefs_get_action_middle_click_titlebar(); - - return meta_frame_titlebar_event (frame, event, action); -} - -static gboolean -meta_frame_right_click_event(MetaUIFrame *frame, - GdkEventButton *event) -{ - int action = meta_prefs_get_action_right_click_titlebar(); - - return meta_frame_titlebar_event (frame, event, action); -} - -static gboolean -meta_frames_button_press_event (GtkWidget *widget, - GdkEventButton *event) -{ - MetaUIFrame *frame; - MetaFrames *frames; - MetaFrameControl control; - - frames = META_FRAMES (widget); - - /* Remember that the display may have already done something with this event. - * If so there's probably a GrabOp in effect. - */ - - frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); - if (frame == NULL) - return FALSE; - - clear_tip (frames); - - control = get_control (frames, frame, event->x, event->y); - - /* focus on click, even if click was on client area */ - if (event->button == 1 && - !(control == META_FRAME_CONTROL_MINIMIZE || - control == META_FRAME_CONTROL_DELETE || - control == META_FRAME_CONTROL_MAXIMIZE)) - { - meta_topic (META_DEBUG_FOCUS, - "Focusing window with frame 0x%lx due to button 1 press\n", - frame->xwindow); - meta_core_user_focus (gdk_display, - frame->xwindow, - event->time); - } - - /* don't do the rest of this if on client area */ - if (control == META_FRAME_CONTROL_CLIENT_AREA) - return FALSE; /* not on the frame, just passed through from client */ - - /* We want to shade even if we have a GrabOp, since we'll have a move grab - * if we double click the titlebar. - */ - if (control == META_FRAME_CONTROL_TITLE && - event->button == 1 && - event->type == GDK_2BUTTON_PRESS) - { - return meta_frame_double_click_event (frame, event); - } - - if (meta_core_get_grab_op (gdk_display) != - META_GRAB_OP_NONE) - return FALSE; /* already up to something */ - - if (event->button == 1 && - (control == META_FRAME_CONTROL_MAXIMIZE || - control == META_FRAME_CONTROL_UNMAXIMIZE || - control == META_FRAME_CONTROL_MINIMIZE || - control == META_FRAME_CONTROL_DELETE || - control == META_FRAME_CONTROL_SHADE || - control == META_FRAME_CONTROL_UNSHADE || - control == META_FRAME_CONTROL_ABOVE || - control == META_FRAME_CONTROL_UNABOVE || - control == META_FRAME_CONTROL_STICK || - control == META_FRAME_CONTROL_UNSTICK || - control == META_FRAME_CONTROL_MENU)) - { - MetaGrabOp op = META_GRAB_OP_NONE; - - switch (control) - { - case META_FRAME_CONTROL_MINIMIZE: - op = META_GRAB_OP_CLICKING_MINIMIZE; - break; - case META_FRAME_CONTROL_MAXIMIZE: - op = META_GRAB_OP_CLICKING_MAXIMIZE; - break; - case META_FRAME_CONTROL_UNMAXIMIZE: - op = META_GRAB_OP_CLICKING_UNMAXIMIZE; - break; - case META_FRAME_CONTROL_DELETE: - op = META_GRAB_OP_CLICKING_DELETE; - break; - case META_FRAME_CONTROL_MENU: - op = META_GRAB_OP_CLICKING_MENU; - break; - case META_FRAME_CONTROL_SHADE: - op = META_GRAB_OP_CLICKING_SHADE; - break; - case META_FRAME_CONTROL_UNSHADE: - op = META_GRAB_OP_CLICKING_UNSHADE; - break; - case META_FRAME_CONTROL_ABOVE: - op = META_GRAB_OP_CLICKING_ABOVE; - break; - case META_FRAME_CONTROL_UNABOVE: - op = META_GRAB_OP_CLICKING_UNABOVE; - break; - case META_FRAME_CONTROL_STICK: - op = META_GRAB_OP_CLICKING_STICK; - break; - case META_FRAME_CONTROL_UNSTICK: - op = META_GRAB_OP_CLICKING_UNSTICK; - break; - default: - g_assert_not_reached (); - break; - } - - meta_core_begin_grab_op (gdk_display, - frame->xwindow, - op, - TRUE, - TRUE, - event->button, - 0, - event->time, - event->x_root, - event->y_root); - - frame->prelit_control = control; - redraw_control (frames, frame, control); - - if (op == META_GRAB_OP_CLICKING_MENU) - { - MetaFrameGeometry fgeom; - GdkRectangle *rect; - int dx, dy; - - meta_frames_calc_geometry (frames, frame, &fgeom); - - rect = control_rect (META_FRAME_CONTROL_MENU, &fgeom); - - /* get delta to convert to root coords */ - dx = event->x_root - event->x; - dy = event->y_root - event->y; - - /* Align to the right end of the menu rectangle if RTL */ - if (meta_ui_get_direction() == META_UI_DIRECTION_RTL) - dx += rect->width; - - meta_core_show_window_menu (gdk_display, - frame->xwindow, - rect->x + dx, - rect->y + rect->height + dy, - event->button, - event->time); - } - } - else if (event->button == 1 && - (control == META_FRAME_CONTROL_RESIZE_SE || - control == META_FRAME_CONTROL_RESIZE_S || - control == META_FRAME_CONTROL_RESIZE_SW || - control == META_FRAME_CONTROL_RESIZE_NE || - control == META_FRAME_CONTROL_RESIZE_N || - control == META_FRAME_CONTROL_RESIZE_NW || - control == META_FRAME_CONTROL_RESIZE_E || - control == META_FRAME_CONTROL_RESIZE_W)) - { - MetaGrabOp op; - gboolean titlebar_is_onscreen; - - op = META_GRAB_OP_NONE; - - switch (control) - { - case META_FRAME_CONTROL_RESIZE_SE: - op = META_GRAB_OP_RESIZING_SE; - break; - case META_FRAME_CONTROL_RESIZE_S: - op = META_GRAB_OP_RESIZING_S; - break; - case META_FRAME_CONTROL_RESIZE_SW: - op = META_GRAB_OP_RESIZING_SW; - break; - case META_FRAME_CONTROL_RESIZE_NE: - op = META_GRAB_OP_RESIZING_NE; - break; - case META_FRAME_CONTROL_RESIZE_N: - op = META_GRAB_OP_RESIZING_N; - break; - case META_FRAME_CONTROL_RESIZE_NW: - op = META_GRAB_OP_RESIZING_NW; - break; - case META_FRAME_CONTROL_RESIZE_E: - op = META_GRAB_OP_RESIZING_E; - break; - case META_FRAME_CONTROL_RESIZE_W: - op = META_GRAB_OP_RESIZING_W; - break; - default: - g_assert_not_reached (); - break; - } - - meta_core_get (gdk_display, frame->xwindow, - META_CORE_IS_TITLEBAR_ONSCREEN, &titlebar_is_onscreen, - META_CORE_GET_END); - - if (!titlebar_is_onscreen) - meta_core_show_window_menu (gdk_display, - frame->xwindow, - event->x_root, - event->y_root, - event->button, - event->time); - else - meta_core_begin_grab_op (gdk_display, - frame->xwindow, - op, - TRUE, - TRUE, - event->button, - 0, - event->time, - event->x_root, - event->y_root); - } - else if (control == META_FRAME_CONTROL_TITLE && - event->button == 1) - { - MetaFrameFlags flags; - - meta_core_get (gdk_display, frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_END); - - if (flags & META_FRAME_ALLOWS_MOVE) - { - meta_core_begin_grab_op (gdk_display, - frame->xwindow, - META_GRAB_OP_MOVING, - TRUE, - TRUE, - event->button, - 0, - event->time, - event->x_root, - event->y_root); - } - } - else if (event->button == 2) - { - return meta_frame_middle_click_event (frame, event); - } - else if (event->button == 3) - { - return meta_frame_right_click_event (frame, event); - } - - return TRUE; -} - -void -meta_frames_notify_menu_hide (MetaFrames *frames) -{ - if (meta_core_get_grab_op (gdk_display) == - META_GRAB_OP_CLICKING_MENU) - { - Window grab_frame; - - grab_frame = meta_core_get_grab_frame (gdk_display); - - if (grab_frame != None) - { - MetaUIFrame *frame; - - frame = meta_frames_lookup_window (frames, grab_frame); - - if (frame) - { - redraw_control (frames, frame, - META_FRAME_CONTROL_MENU); - meta_core_end_grab_op (gdk_display, CurrentTime); - } - } - } -} - -static gboolean -meta_frames_button_release_event (GtkWidget *widget, - GdkEventButton *event) -{ - MetaUIFrame *frame; - MetaFrames *frames; - MetaGrabOp op; - - frames = META_FRAMES (widget); - - frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); - if (frame == NULL) - return FALSE; - - clear_tip (frames); - - op = meta_core_get_grab_op (gdk_display); - - if (op == META_GRAB_OP_NONE) - return FALSE; - - /* We only handle the releases we handled the presses for (things - * involving frame controls). Window ops that don't require a - * frame are handled in the Xlib part of the code, display.c/window.c - */ - if (frame->xwindow == meta_core_get_grab_frame (gdk_display) && - ((int) event->button) == meta_core_get_grab_button (gdk_display)) - { - MetaFrameControl control; - - control = get_control (frames, frame, event->x, event->y); - - switch (op) - { - case META_GRAB_OP_CLICKING_MINIMIZE: - if (control == META_FRAME_CONTROL_MINIMIZE) - meta_core_minimize (gdk_display, frame->xwindow); - - meta_core_end_grab_op (gdk_display, event->time); - break; - - case META_GRAB_OP_CLICKING_MAXIMIZE: - if (control == META_FRAME_CONTROL_MAXIMIZE) - { - /* Focus the window on the maximize */ - meta_core_user_focus (gdk_display, - frame->xwindow, - event->time); - meta_core_maximize (gdk_display, frame->xwindow); - } - meta_core_end_grab_op (gdk_display, event->time); - break; - - case META_GRAB_OP_CLICKING_UNMAXIMIZE: - if (control == META_FRAME_CONTROL_UNMAXIMIZE) - meta_core_unmaximize (gdk_display, frame->xwindow); - - meta_core_end_grab_op (gdk_display, event->time); - break; - - case META_GRAB_OP_CLICKING_DELETE: - if (control == META_FRAME_CONTROL_DELETE) - meta_core_delete (gdk_display, frame->xwindow, event->time); - - meta_core_end_grab_op (gdk_display, event->time); - break; - - case META_GRAB_OP_CLICKING_MENU: - meta_core_end_grab_op (gdk_display, event->time); - break; - - case META_GRAB_OP_CLICKING_SHADE: - if (control == META_FRAME_CONTROL_SHADE) - meta_core_shade (gdk_display, frame->xwindow, event->time); - - meta_core_end_grab_op (gdk_display, event->time); - break; - - case META_GRAB_OP_CLICKING_UNSHADE: - if (control == META_FRAME_CONTROL_UNSHADE) - meta_core_unshade (gdk_display, frame->xwindow, event->time); - - meta_core_end_grab_op (gdk_display, event->time); - break; - - case META_GRAB_OP_CLICKING_ABOVE: - if (control == META_FRAME_CONTROL_ABOVE) - meta_core_make_above (gdk_display, frame->xwindow); - - meta_core_end_grab_op (gdk_display, event->time); - break; - - case META_GRAB_OP_CLICKING_UNABOVE: - if (control == META_FRAME_CONTROL_UNABOVE) - meta_core_unmake_above (gdk_display, frame->xwindow); - - meta_core_end_grab_op (gdk_display, event->time); - break; - - case META_GRAB_OP_CLICKING_STICK: - if (control == META_FRAME_CONTROL_STICK) - meta_core_stick (gdk_display, frame->xwindow); - - meta_core_end_grab_op (gdk_display, event->time); - break; - - case META_GRAB_OP_CLICKING_UNSTICK: - if (control == META_FRAME_CONTROL_UNSTICK) - meta_core_unstick (gdk_display, frame->xwindow); - - meta_core_end_grab_op (gdk_display, event->time); - break; - - default: - break; - } - - /* Update the prelit control regardless of what button the mouse - * was released over; needed so that the new button can become - * prelit so to let the user know that it can now be pressed. - * :) - */ - meta_frames_update_prelit_control (frames, frame, control); - } - - return TRUE; -} - -static void -meta_frames_update_prelit_control (MetaFrames *frames, - MetaUIFrame *frame, - MetaFrameControl control) -{ - MetaFrameControl old_control; - MetaCursor cursor; - - - meta_verbose ("Updating prelit control from %u to %u\n", - frame->prelit_control, control); - - cursor = META_CURSOR_DEFAULT; - - switch (control) - { - case META_FRAME_CONTROL_CLIENT_AREA: - break; - case META_FRAME_CONTROL_NONE: - break; - case META_FRAME_CONTROL_TITLE: - break; - case META_FRAME_CONTROL_DELETE: - break; - case META_FRAME_CONTROL_MENU: - break; - case META_FRAME_CONTROL_MINIMIZE: - break; - case META_FRAME_CONTROL_MAXIMIZE: - break; - case META_FRAME_CONTROL_UNMAXIMIZE: - break; - case META_FRAME_CONTROL_SHADE: - break; - case META_FRAME_CONTROL_UNSHADE: - break; - case META_FRAME_CONTROL_ABOVE: - break; - case META_FRAME_CONTROL_UNABOVE: - break; - case META_FRAME_CONTROL_STICK: - break; - case META_FRAME_CONTROL_UNSTICK: - break; - case META_FRAME_CONTROL_RESIZE_SE: - cursor = META_CURSOR_SE_RESIZE; - break; - case META_FRAME_CONTROL_RESIZE_S: - cursor = META_CURSOR_SOUTH_RESIZE; - break; - case META_FRAME_CONTROL_RESIZE_SW: - cursor = META_CURSOR_SW_RESIZE; - break; - case META_FRAME_CONTROL_RESIZE_N: - cursor = META_CURSOR_NORTH_RESIZE; - break; - case META_FRAME_CONTROL_RESIZE_NE: - cursor = META_CURSOR_NE_RESIZE; - break; - case META_FRAME_CONTROL_RESIZE_NW: - cursor = META_CURSOR_NW_RESIZE; - break; - case META_FRAME_CONTROL_RESIZE_W: - cursor = META_CURSOR_WEST_RESIZE; - break; - case META_FRAME_CONTROL_RESIZE_E: - cursor = META_CURSOR_EAST_RESIZE; - break; - } - - /* set/unset the prelight cursor */ - meta_core_set_screen_cursor (gdk_display, - frame->xwindow, - cursor); - - switch (control) - { - case META_FRAME_CONTROL_MENU: - case META_FRAME_CONTROL_MINIMIZE: - case META_FRAME_CONTROL_MAXIMIZE: - case META_FRAME_CONTROL_DELETE: - case META_FRAME_CONTROL_SHADE: - case META_FRAME_CONTROL_UNSHADE: - case META_FRAME_CONTROL_ABOVE: - case META_FRAME_CONTROL_UNABOVE: - case META_FRAME_CONTROL_STICK: - case META_FRAME_CONTROL_UNSTICK: - case META_FRAME_CONTROL_UNMAXIMIZE: - /* leave control set */ - break; - default: - /* Only prelight buttons */ - control = META_FRAME_CONTROL_NONE; - break; - } - - if (control == frame->prelit_control) - return; - - /* Save the old control so we can unprelight it */ - old_control = frame->prelit_control; - - frame->prelit_control = control; - - redraw_control (frames, frame, old_control); - redraw_control (frames, frame, control); -} - -static gboolean -meta_frames_motion_notify_event (GtkWidget *widget, - GdkEventMotion *event) -{ - MetaUIFrame *frame; - MetaFrames *frames; - MetaGrabOp grab_op; - - frames = META_FRAMES (widget); - - frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); - if (frame == NULL) - return FALSE; - - clear_tip (frames); - - frames->last_motion_frame = frame; - - grab_op = meta_core_get_grab_op (gdk_display); - - switch (grab_op) - { - case META_GRAB_OP_CLICKING_MENU: - case META_GRAB_OP_CLICKING_DELETE: - case META_GRAB_OP_CLICKING_MINIMIZE: - case META_GRAB_OP_CLICKING_MAXIMIZE: - case META_GRAB_OP_CLICKING_UNMAXIMIZE: - case META_GRAB_OP_CLICKING_SHADE: - case META_GRAB_OP_CLICKING_UNSHADE: - case META_GRAB_OP_CLICKING_ABOVE: - case META_GRAB_OP_CLICKING_UNABOVE: - case META_GRAB_OP_CLICKING_STICK: - case META_GRAB_OP_CLICKING_UNSTICK: - { - MetaFrameControl control; - int x, y; - - gdk_window_get_pointer (frame->window, &x, &y, NULL); - - /* Control is set to none unless it matches - * the current grab - */ - control = get_control (frames, frame, x, y); - if (! ((control == META_FRAME_CONTROL_MENU && - grab_op == META_GRAB_OP_CLICKING_MENU) || - (control == META_FRAME_CONTROL_DELETE && - grab_op == META_GRAB_OP_CLICKING_DELETE) || - (control == META_FRAME_CONTROL_MINIMIZE && - grab_op == META_GRAB_OP_CLICKING_MINIMIZE) || - ((control == META_FRAME_CONTROL_MAXIMIZE || - control == META_FRAME_CONTROL_UNMAXIMIZE) && - (grab_op == META_GRAB_OP_CLICKING_MAXIMIZE || - grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE)) || - (control == META_FRAME_CONTROL_SHADE && - grab_op == META_GRAB_OP_CLICKING_SHADE) || - (control == META_FRAME_CONTROL_UNSHADE && - grab_op == META_GRAB_OP_CLICKING_UNSHADE) || - (control == META_FRAME_CONTROL_ABOVE && - grab_op == META_GRAB_OP_CLICKING_ABOVE) || - (control == META_FRAME_CONTROL_UNABOVE && - grab_op == META_GRAB_OP_CLICKING_UNABOVE) || - (control == META_FRAME_CONTROL_STICK && - grab_op == META_GRAB_OP_CLICKING_STICK) || - (control == META_FRAME_CONTROL_UNSTICK && - grab_op == META_GRAB_OP_CLICKING_UNSTICK))) - control = META_FRAME_CONTROL_NONE; - - /* Update prelit control and cursor */ - meta_frames_update_prelit_control (frames, frame, control); - - /* No tooltip while in the process of clicking */ - } - break; - case META_GRAB_OP_NONE: - { - MetaFrameControl control; - int x, y; - - gdk_window_get_pointer (frame->window, &x, &y, NULL); - - control = get_control (frames, frame, x, y); - - /* Update prelit control and cursor */ - meta_frames_update_prelit_control (frames, frame, control); - - queue_tip (frames); - } - break; - - default: - break; - } - - return TRUE; -} - -static gboolean -meta_frames_destroy_event (GtkWidget *widget, - GdkEventAny *event) -{ - MetaUIFrame *frame; - MetaFrames *frames; - - frames = META_FRAMES (widget); - - frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); - if (frame == NULL) - return FALSE; - - return TRUE; -} - -/* Cut and paste from GDK */ -static GdkGC * -get_bg_gc (GdkWindow *window, int x_offset, int y_offset) -{ - GdkWindowObject *private = (GdkWindowObject *)window; - guint gc_mask = 0; - GdkGCValues gc_values; - - if (private->bg_pixmap == GDK_PARENT_RELATIVE_BG && private->parent) - { - return get_bg_gc (GDK_WINDOW (private->parent), - x_offset + private->x, - y_offset + private->y); - } - else if (private->bg_pixmap && - private->bg_pixmap != GDK_PARENT_RELATIVE_BG && - private->bg_pixmap != GDK_NO_BG) - { - gc_values.fill = GDK_TILED; - gc_values.tile = private->bg_pixmap; - gc_values.ts_x_origin = x_offset; - gc_values.ts_y_origin = y_offset; - - gc_mask = GDK_GC_FILL | GDK_GC_TILE | GDK_GC_TS_X_ORIGIN | GDK_GC_TS_Y_ORIGIN; - - return gdk_gc_new_with_values (window, &gc_values, gc_mask); - } - else - { - GdkGC *gc = gdk_gc_new (window); - - gdk_gc_set_foreground (gc, &(private->bg_color)); - - return gc; - } -} - -static void -clear_backing (GdkPixmap *pixmap, - GdkWindow *window, - int xoffset, int yoffset) -{ - GdkGC *tmp_gc = get_bg_gc (window, xoffset, yoffset); - - gdk_draw_rectangle (pixmap, tmp_gc, TRUE, - 0, 0, -1, -1); - - g_object_unref (tmp_gc); -} - -/* Returns a pixmap with a piece of the windows frame painted on it. -*/ - -static GdkPixmap * -generate_pixmap (MetaFrames *frames, - MetaUIFrame *frame, - MetaRectangle rect) -{ - GdkRectangle rectangle; - GdkRegion *region; - GdkPixmap *result; - - rectangle.x = rect.x; - rectangle.y = rect.y; - rectangle.width = MAX (rect.width, 1); - rectangle.height = MAX (rect.height, 1); - - result = gdk_pixmap_new (frame->window, - rectangle.width, rectangle.height, -1); - - clear_backing (result, frame->window, rectangle.x, rectangle.y); - - region = gdk_region_rectangle (&rectangle); - - meta_frames_paint_to_drawable (frames, frame, result, region, - -rectangle.x, -rectangle.y); - - gdk_region_destroy (region); - - return result; -} - - -static void -populate_cache (MetaFrames *frames, - MetaUIFrame *frame) -{ - int top, bottom, left, right; - int width, height; - int frame_width, frame_height, screen_width, screen_height; - CachedPixels *pixels; - MetaFrameType frame_type; - MetaFrameFlags frame_flags; - int i; - - meta_core_get (gdk_display, frame->xwindow, - META_CORE_GET_FRAME_WIDTH, &frame_width, - META_CORE_GET_FRAME_HEIGHT, &frame_height, - META_CORE_GET_SCREEN_WIDTH, &screen_width, - META_CORE_GET_SCREEN_HEIGHT, &screen_height, - META_CORE_GET_CLIENT_WIDTH, &width, - META_CORE_GET_CLIENT_HEIGHT, &height, - META_CORE_GET_FRAME_TYPE, &frame_type, - META_CORE_GET_FRAME_FLAGS, &frame_flags, - META_CORE_GET_END); - - /* don't cache extremely large windows */ - if (frame_width > 2 * screen_width || - frame_height > 2 * screen_height) - { - return; - } - - meta_theme_get_frame_borders (meta_theme_get_current (), - frame_type, - frame->text_height, - frame_flags, - &top, &bottom, &left, &right); - - pixels = get_cache (frames, frame); - - /* Setup the rectangles for the four frame borders. First top, then - left, right and bottom. */ - pixels->piece[0].rect.x = 0; - pixels->piece[0].rect.y = 0; - pixels->piece[0].rect.width = left + width + right; - pixels->piece[0].rect.height = top; - - pixels->piece[1].rect.x = 0; - pixels->piece[1].rect.y = top; - pixels->piece[1].rect.width = left; - pixels->piece[1].rect.height = height; - - pixels->piece[2].rect.x = left + width; - pixels->piece[2].rect.y = top; - pixels->piece[2].rect.width = right; - pixels->piece[2].rect.height = height; - - pixels->piece[3].rect.x = 0; - pixels->piece[3].rect.y = top + height; - pixels->piece[3].rect.width = left + width + right; - pixels->piece[3].rect.height = bottom; - - for (i = 0; i < 4; i++) - { - CachedFramePiece *piece = &pixels->piece[i]; - if (!piece->pixmap) - piece->pixmap = generate_pixmap (frames, frame, piece->rect); - } - - if (frames->invalidate_cache_timeout_id) - g_source_remove (frames->invalidate_cache_timeout_id); - - frames->invalidate_cache_timeout_id = g_timeout_add (1000, invalidate_cache_timeout, frames); - - if (!g_list_find (frames->invalidate_frames, frame)) - frames->invalidate_frames = - g_list_prepend (frames->invalidate_frames, frame); -} - -static void -clip_to_screen (GdkRegion *region, MetaUIFrame *frame) -{ - GdkRectangle frame_area; - GdkRectangle screen_area = { 0, 0, 0, 0 }; - GdkRegion *tmp_region; - - /* Chop off stuff outside the screen; this optimization - * is crucial to handle huge client windows, - * like "xterm -geometry 1000x1000" - */ - meta_core_get (gdk_display, frame->xwindow, - META_CORE_GET_FRAME_X, &frame_area.x, - META_CORE_GET_FRAME_Y, &frame_area.y, - META_CORE_GET_FRAME_WIDTH, &frame_area.width, - META_CORE_GET_FRAME_HEIGHT, &frame_area.height, - META_CORE_GET_SCREEN_WIDTH, &screen_area.height, - META_CORE_GET_SCREEN_HEIGHT, &screen_area.height, - META_CORE_GET_END); - - gdk_region_offset (region, frame_area.x, frame_area.y); - - tmp_region = gdk_region_rectangle (&frame_area); - gdk_region_intersect (region, tmp_region); - gdk_region_destroy (tmp_region); - - gdk_region_offset (region, - frame_area.x, - frame_area.y); -} - -static void -subtract_from_region (GdkRegion *region, GdkDrawable *drawable, - gint x, gint y) -{ - GdkRectangle rect; - GdkRegion *reg_rect; - - gdk_drawable_get_size (drawable, &rect.width, &rect.height); - rect.x = x; - rect.y = y; - - reg_rect = gdk_region_rectangle (&rect); - gdk_region_subtract (region, reg_rect); - gdk_region_destroy (reg_rect); -} - -static void -cached_pixels_draw (CachedPixels *pixels, - GdkWindow *window, - GdkRegion *region) -{ - GdkGC *gc; - int i; - - gc = gdk_gc_new (window); - - for (i = 0; i < 4; i++) - { - CachedFramePiece *piece; - piece = &pixels->piece[i]; - - if (piece->pixmap) - { - gdk_draw_drawable (window, gc, piece->pixmap, - 0, 0, - piece->rect.x, piece->rect.y, - -1, -1); - subtract_from_region (region, piece->pixmap, - piece->rect.x, piece->rect.y); - } - } - - g_object_unref (gc); -} - -static gboolean -meta_frames_expose_event (GtkWidget *widget, - GdkEventExpose *event) -{ - MetaUIFrame *frame; - MetaFrames *frames; - GdkRegion *region; - CachedPixels *pixels; - - frames = META_FRAMES (widget); - - frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); - if (frame == NULL) - return FALSE; - - if (frames->expose_delay_count > 0) - { - /* Redraw this entire frame later */ - frame->expose_delayed = TRUE; - return TRUE; - } - - populate_cache (frames, frame); - - region = gdk_region_copy (event->region); - - pixels = get_cache (frames, frame); - - cached_pixels_draw (pixels, frame->window, region); - - clip_to_screen (region, frame); - meta_frames_paint_to_drawable (frames, frame, frame->window, region, 0, 0); - - gdk_region_destroy (region); - - return TRUE; -} - -/* How far off the screen edge the window decorations should - * be drawn. Used only in meta_frames_paint_to_drawable, below. - */ -#define DECORATING_BORDER 100 - -static void -meta_frames_paint_to_drawable (MetaFrames *frames, - MetaUIFrame *frame, - GdkDrawable *drawable, - GdkRegion *region, - int x_offset, - int y_offset) -{ - GtkWidget *widget; - MetaFrameFlags flags; - MetaFrameType type; - GdkPixbuf *mini_icon; - GdkPixbuf *icon; - int w, h; - MetaButtonState button_states[META_BUTTON_TYPE_LAST]; - Window grab_frame; - int i; - MetaButtonLayout button_layout; - MetaGrabOp grab_op; - - widget = GTK_WIDGET (frames); - - for (i = 0; i < META_BUTTON_TYPE_LAST; i++) - button_states[i] = META_BUTTON_STATE_NORMAL; - - grab_frame = meta_core_get_grab_frame (gdk_display); - grab_op = meta_core_get_grab_op (gdk_display); - if (grab_frame != frame->xwindow) - grab_op = META_GRAB_OP_NONE; - - /* Set prelight state */ - switch (frame->prelit_control) - { - case META_FRAME_CONTROL_MENU: - if (grab_op == META_GRAB_OP_CLICKING_MENU) - button_states[META_BUTTON_TYPE_MENU] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_MENU] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_MINIMIZE: - if (grab_op == META_GRAB_OP_CLICKING_MINIMIZE) - button_states[META_BUTTON_TYPE_MINIMIZE] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_MINIMIZE] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_MAXIMIZE: - if (grab_op == META_GRAB_OP_CLICKING_MAXIMIZE) - button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_UNMAXIMIZE: - if (grab_op == META_GRAB_OP_CLICKING_UNMAXIMIZE) - button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_MAXIMIZE] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_SHADE: - if (grab_op == META_GRAB_OP_CLICKING_SHADE) - button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_SHADE] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_UNSHADE: - if (grab_op == META_GRAB_OP_CLICKING_UNSHADE) - button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_UNSHADE] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_ABOVE: - if (grab_op == META_GRAB_OP_CLICKING_ABOVE) - button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_ABOVE] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_UNABOVE: - if (grab_op == META_GRAB_OP_CLICKING_UNABOVE) - button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_UNABOVE] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_STICK: - if (grab_op == META_GRAB_OP_CLICKING_STICK) - button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_STICK] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_UNSTICK: - if (grab_op == META_GRAB_OP_CLICKING_UNSTICK) - button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_UNSTICK] = META_BUTTON_STATE_PRELIGHT; - break; - case META_FRAME_CONTROL_DELETE: - if (grab_op == META_GRAB_OP_CLICKING_DELETE) - button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRESSED; - else - button_states[META_BUTTON_TYPE_CLOSE] = META_BUTTON_STATE_PRELIGHT; - break; - default: - break; - } - - /* Map button function states to button position states */ - button_states[META_BUTTON_TYPE_LEFT_LEFT_BACKGROUND] = - button_states[META_BUTTON_TYPE_MENU]; - button_states[META_BUTTON_TYPE_LEFT_MIDDLE_BACKGROUND] = - META_BUTTON_STATE_NORMAL; - button_states[META_BUTTON_TYPE_LEFT_RIGHT_BACKGROUND] = - META_BUTTON_STATE_NORMAL; - button_states[META_BUTTON_TYPE_RIGHT_LEFT_BACKGROUND] = - button_states[META_BUTTON_TYPE_MINIMIZE]; - button_states[META_BUTTON_TYPE_RIGHT_MIDDLE_BACKGROUND] = - button_states[META_BUTTON_TYPE_MAXIMIZE]; - button_states[META_BUTTON_TYPE_RIGHT_RIGHT_BACKGROUND] = - button_states[META_BUTTON_TYPE_CLOSE]; - - meta_core_get (gdk_display, frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_FRAME_TYPE, &type, - META_CORE_GET_MINI_ICON, &mini_icon, - META_CORE_GET_ICON, &icon, - META_CORE_GET_CLIENT_WIDTH, &w, - META_CORE_GET_CLIENT_HEIGHT, &h, - META_CORE_GET_END); - - meta_frames_ensure_layout (frames, frame); - - meta_prefs_get_button_layout (&button_layout); - - if (G_LIKELY (GDK_IS_WINDOW (drawable))) - { - /* A window; happens about 2/3 of the time */ - - GdkRectangle area, *areas; - int n_areas; - int screen_width, screen_height; - GdkRegion *edges, *tmp_region; - int top, bottom, left, right; - - /* Repaint each side of the frame */ - - meta_theme_get_frame_borders (meta_theme_get_current (), - type, frame->text_height, flags, - &top, &bottom, &left, &right); - - meta_core_get (gdk_display, frame->xwindow, - META_CORE_GET_SCREEN_WIDTH, &screen_width, - META_CORE_GET_SCREEN_HEIGHT, &screen_height, - META_CORE_GET_END); - - edges = gdk_region_copy (region); - - /* Punch out the client area */ - - area.x = left; - area.y = top; - area.width = w; - area.height = h; - tmp_region = gdk_region_rectangle (&area); - gdk_region_subtract (edges, tmp_region); - gdk_region_destroy (tmp_region); - - /* Now draw remaining portion of region */ - - gdk_region_get_rectangles (edges, &areas, &n_areas); - - for (i = 0; i < n_areas; i++) - { - /* Bug 399529: clamp areas[i] so that it doesn't go too far - * off the edge of the screen. This works around a GDK bug - * which makes gdk_window_begin_paint_rect cause an X error - * if the window is insanely huge. If the client is a GDK program - * and does this, it will still probably cause an X error in that - * program, but the last thing we want is for Metacity to crash - * because it attempted to decorate the silly window. - */ - - areas[i].x = MAX (areas[i].x, -DECORATING_BORDER); - areas[i].y = MAX (areas[i].y, -DECORATING_BORDER); - if (areas[i].x+areas[i].width > screen_width + DECORATING_BORDER) - areas[i].width = MIN (0, screen_width - areas[i].x); - if (areas[i].y+areas[i].height > screen_height + DECORATING_BORDER) - areas[i].height = MIN (0, screen_height - areas[i].y); - - /* Okay, so let's start painting. */ - - gdk_window_begin_paint_rect (drawable, &areas[i]); - - meta_theme_draw_frame (meta_theme_get_current (), - widget, - drawable, - NULL, /* &areas[i], */ - x_offset, y_offset, - type, - flags, - w, h, - frame->layout, - frame->text_height, - &button_layout, - button_states, - mini_icon, icon); - - gdk_window_end_paint (drawable); - } - - g_free (areas); - gdk_region_destroy (edges); - - } - else - { - /* Not a window; happens about 1/3 of the time */ - - meta_theme_draw_frame (meta_theme_get_current (), - widget, - drawable, - NULL, - x_offset, y_offset, - type, - flags, - w, h, - frame->layout, - frame->text_height, - &button_layout, - button_states, - mini_icon, icon); - } - -} - -static void -meta_frames_set_window_background (MetaFrames *frames, - MetaUIFrame *frame) -{ - MetaFrameFlags flags; - MetaFrameType type; - MetaFrameStyle *style; - gboolean frame_exists; - - meta_core_get (gdk_display, frame->xwindow, - META_CORE_WINDOW_HAS_FRAME, &frame_exists, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_FRAME_TYPE, &type, - META_CORE_GET_END); - - if (frame_exists) - { - style = meta_theme_get_frame_style (meta_theme_get_current (), - type, flags); - } - - if (frame_exists && style->window_background_color != NULL) - { - GdkColor color; - GdkVisual *visual; - - meta_color_spec_render (style->window_background_color, - GTK_WIDGET (frames), - &color); - - /* Fill in color.pixel */ - - gdk_rgb_find_color (gtk_widget_get_colormap (GTK_WIDGET (frames)), - &color); - - /* Set A in ARGB to window_background_alpha, if we have ARGB */ - - visual = gtk_widget_get_visual (GTK_WIDGET (frames)); - if (visual->depth == 32) /* we have ARGB */ - { - color.pixel = (color.pixel & 0xffffff) & - style->window_background_alpha << 24; - } - - gdk_window_set_background (frame->window, &color); - } - else - { - gtk_style_set_background (GTK_WIDGET (frames)->style, - frame->window, GTK_STATE_NORMAL); - } - } - -static gboolean -meta_frames_enter_notify_event (GtkWidget *widget, - GdkEventCrossing *event) -{ - MetaUIFrame *frame; - MetaFrames *frames; - MetaFrameControl control; - - frames = META_FRAMES (widget); - - frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); - if (frame == NULL) - return FALSE; - - control = get_control (frames, frame, event->x, event->y); - meta_frames_update_prelit_control (frames, frame, control); - - return TRUE; -} - -static gboolean -meta_frames_leave_notify_event (GtkWidget *widget, - GdkEventCrossing *event) -{ - MetaUIFrame *frame; - MetaFrames *frames; - - frames = META_FRAMES (widget); - - frame = meta_frames_lookup_window (frames, GDK_WINDOW_XID (event->window)); - if (frame == NULL) - return FALSE; - - meta_frames_update_prelit_control (frames, frame, META_FRAME_CONTROL_NONE); - - clear_tip (frames); - - return TRUE; -} - -static GdkRectangle* -control_rect (MetaFrameControl control, - MetaFrameGeometry *fgeom) -{ - GdkRectangle *rect; - - rect = NULL; - switch (control) - { - case META_FRAME_CONTROL_TITLE: - rect = &fgeom->title_rect; - break; - case META_FRAME_CONTROL_DELETE: - rect = &fgeom->close_rect.visible; - break; - case META_FRAME_CONTROL_MENU: - rect = &fgeom->menu_rect.visible; - break; - case META_FRAME_CONTROL_MINIMIZE: - rect = &fgeom->min_rect.visible; - break; - case META_FRAME_CONTROL_MAXIMIZE: - case META_FRAME_CONTROL_UNMAXIMIZE: - rect = &fgeom->max_rect.visible; - break; - case META_FRAME_CONTROL_SHADE: - rect = &fgeom->shade_rect.visible; - break; - case META_FRAME_CONTROL_UNSHADE: - rect = &fgeom->unshade_rect.visible; - break; - case META_FRAME_CONTROL_ABOVE: - rect = &fgeom->above_rect.visible; - break; - case META_FRAME_CONTROL_UNABOVE: - rect = &fgeom->unabove_rect.visible; - break; - case META_FRAME_CONTROL_STICK: - rect = &fgeom->stick_rect.visible; - break; - case META_FRAME_CONTROL_UNSTICK: - rect = &fgeom->unstick_rect.visible; - break; - case META_FRAME_CONTROL_RESIZE_SE: - break; - case META_FRAME_CONTROL_RESIZE_S: - break; - case META_FRAME_CONTROL_RESIZE_SW: - break; - case META_FRAME_CONTROL_RESIZE_N: - break; - case META_FRAME_CONTROL_RESIZE_NE: - break; - case META_FRAME_CONTROL_RESIZE_NW: - break; - case META_FRAME_CONTROL_RESIZE_W: - break; - case META_FRAME_CONTROL_RESIZE_E: - break; - case META_FRAME_CONTROL_NONE: - break; - case META_FRAME_CONTROL_CLIENT_AREA: - break; - } - - return rect; -} - -#define RESIZE_EXTENDS 15 -#define TOP_RESIZE_HEIGHT 2 -static MetaFrameControl -get_control (MetaFrames *frames, - MetaUIFrame *frame, - int x, int y) -{ - MetaFrameGeometry fgeom; - MetaFrameFlags flags; - gboolean has_vert, has_horiz; - GdkRectangle client; - - meta_frames_calc_geometry (frames, frame, &fgeom); - - client.x = fgeom.left_width; - client.y = fgeom.top_height; - client.width = fgeom.width - fgeom.left_width - fgeom.right_width; - client.height = fgeom.height - fgeom.top_height - fgeom.bottom_height; - - if (POINT_IN_RECT (x, y, client)) - return META_FRAME_CONTROL_CLIENT_AREA; - - if (POINT_IN_RECT (x, y, fgeom.close_rect.clickable)) - return META_FRAME_CONTROL_DELETE; - - if (POINT_IN_RECT (x, y, fgeom.min_rect.clickable)) - return META_FRAME_CONTROL_MINIMIZE; - - if (POINT_IN_RECT (x, y, fgeom.menu_rect.clickable)) - return META_FRAME_CONTROL_MENU; - - meta_core_get (gdk_display, frame->xwindow, - META_CORE_GET_FRAME_FLAGS, &flags, - META_CORE_GET_END); - - has_vert = (flags & META_FRAME_ALLOWS_VERTICAL_RESIZE) != 0; - has_horiz = (flags & META_FRAME_ALLOWS_HORIZONTAL_RESIZE) != 0; - - if (POINT_IN_RECT (x, y, fgeom.title_rect)) - { - if (has_vert && y <= TOP_RESIZE_HEIGHT) - return META_FRAME_CONTROL_RESIZE_N; - else - return META_FRAME_CONTROL_TITLE; - } - - if (POINT_IN_RECT (x, y, fgeom.max_rect.clickable)) - { - if (flags & META_FRAME_MAXIMIZED) - return META_FRAME_CONTROL_UNMAXIMIZE; - else - return META_FRAME_CONTROL_MAXIMIZE; - } - - if (POINT_IN_RECT (x, y, fgeom.shade_rect.clickable)) - { - return META_FRAME_CONTROL_SHADE; - } - - if (POINT_IN_RECT (x, y, fgeom.unshade_rect.clickable)) - { - return META_FRAME_CONTROL_UNSHADE; - } - - if (POINT_IN_RECT (x, y, fgeom.above_rect.clickable)) - { - return META_FRAME_CONTROL_ABOVE; - } - - if (POINT_IN_RECT (x, y, fgeom.unabove_rect.clickable)) - { - return META_FRAME_CONTROL_UNABOVE; - } - - if (POINT_IN_RECT (x, y, fgeom.stick_rect.clickable)) - { - return META_FRAME_CONTROL_STICK; - } - - if (POINT_IN_RECT (x, y, fgeom.unstick_rect.clickable)) - { - return META_FRAME_CONTROL_UNSTICK; - } - - /* South resize always has priority over north resize, - * in case of overlap. - */ - - if (y >= (fgeom.height - fgeom.bottom_height - RESIZE_EXTENDS) && - x >= (fgeom.width - fgeom.right_width - RESIZE_EXTENDS)) - { - if (has_vert && has_horiz) - return META_FRAME_CONTROL_RESIZE_SE; - else if (has_vert) - return META_FRAME_CONTROL_RESIZE_S; - else if (has_horiz) - return META_FRAME_CONTROL_RESIZE_E; - } - else if (y >= (fgeom.height - fgeom.bottom_height - RESIZE_EXTENDS) && - x <= (fgeom.left_width + RESIZE_EXTENDS)) - { - if (has_vert && has_horiz) - return META_FRAME_CONTROL_RESIZE_SW; - else if (has_vert) - return META_FRAME_CONTROL_RESIZE_S; - else if (has_horiz) - return META_FRAME_CONTROL_RESIZE_W; - } - else if (y < (fgeom.top_height + RESIZE_EXTENDS) && - x < RESIZE_EXTENDS) - { - if (has_vert && has_horiz) - return META_FRAME_CONTROL_RESIZE_NW; - else if (has_vert) - return META_FRAME_CONTROL_RESIZE_N; - else if (has_horiz) - return META_FRAME_CONTROL_RESIZE_W; - } - else if (y < (fgeom.top_height + RESIZE_EXTENDS) && - x >= (fgeom.width - RESIZE_EXTENDS)) - { - if (has_vert && has_horiz) - return META_FRAME_CONTROL_RESIZE_NE; - else if (has_vert) - return META_FRAME_CONTROL_RESIZE_N; - else if (has_horiz) - return META_FRAME_CONTROL_RESIZE_E; - } - else if (y >= (fgeom.height - fgeom.bottom_height - RESIZE_EXTENDS)) - { - if (has_vert) - return META_FRAME_CONTROL_RESIZE_S; - } - else if (y <= TOP_RESIZE_HEIGHT) - { - if (has_vert) - return META_FRAME_CONTROL_RESIZE_N; - else if (has_horiz) - return META_FRAME_CONTROL_TITLE; - } - else if (x <= fgeom.left_width) - { - if (has_horiz) - return META_FRAME_CONTROL_RESIZE_W; - } - else if (x >= (fgeom.width - fgeom.right_width)) - { - if (has_horiz) - return META_FRAME_CONTROL_RESIZE_E; - } - - if (y >= fgeom.top_height) - return META_FRAME_CONTROL_NONE; - else - return META_FRAME_CONTROL_TITLE; -} - -void -meta_frames_push_delay_exposes (MetaFrames *frames) -{ - if (frames->expose_delay_count == 0) - { - /* Make sure we've repainted things */ - gdk_window_process_all_updates (); - XFlush (gdk_display); - } - - frames->expose_delay_count += 1; -} - -static void -queue_pending_exposes_func (gpointer key, gpointer value, gpointer data) -{ - MetaUIFrame *frame; - MetaFrames *frames; - - frames = META_FRAMES (data); - frame = value; - - if (frame->expose_delayed) - { - invalidate_whole_window (frames, frame); - frame->expose_delayed = FALSE; - } -} - -void -meta_frames_pop_delay_exposes (MetaFrames *frames) -{ - g_return_if_fail (frames->expose_delay_count > 0); - - frames->expose_delay_count -= 1; - - if (frames->expose_delay_count == 0) - { - g_hash_table_foreach (frames->frames, - queue_pending_exposes_func, - frames); - } -} - -static void -invalidate_whole_window (MetaFrames *frames, - MetaUIFrame *frame) -{ - gdk_window_invalidate_rect (frame->window, NULL, FALSE); - invalidate_cache (frames, frame); -} |