summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlberts Muktupāvels <alberts.muktupavels@gmail.com>2016-08-18 02:37:25 +0300
committerAlberts Muktupāvels <alberts.muktupavels@gmail.com>2016-08-18 02:37:25 +0300
commitb2106b20993ad67e71a913acffb729445911b007 (patch)
tree6f4cac16ae3993a477fafd3cefe7f63556c08036
parent619f814293e1a19a34d3ac80cced5c9c3392570d (diff)
downloadmetacity-b2106b20993ad67e71a913acffb729445911b007.tar.gz
libmetacity: redo button layout code
-rw-r--r--libmetacity/Makefile.am4
-rw-r--r--libmetacity/meta-button-layout-private.h16
-rw-r--r--libmetacity/meta-button-layout.c184
-rw-r--r--libmetacity/meta-button.h (renamed from libmetacity/meta-button-enums.h)27
-rw-r--r--libmetacity/meta-frame-style-private.h2
-rw-r--r--libmetacity/meta-theme-gtk.c503
-rw-r--r--libmetacity/meta-theme-impl-private.h19
-rw-r--r--libmetacity/meta-theme-impl.c195
-rw-r--r--libmetacity/meta-theme-metacity.c750
-rw-r--r--libmetacity/meta-theme.c109
-rw-r--r--libmetacity/meta-theme.h50
-rw-r--r--src/ui/frames.c859
-rw-r--r--src/ui/frames.h2
13 files changed, 1323 insertions, 1397 deletions
diff --git a/libmetacity/Makefile.am b/libmetacity/Makefile.am
index 426cb8c3..785e3e30 100644
--- a/libmetacity/Makefile.am
+++ b/libmetacity/Makefile.am
@@ -3,7 +3,7 @@ NULL =
lib_LTLIBRARIES = libmetacity.la
libmetacity_la_SOURCES = \
- meta-button-enums.h \
+ meta-button.h \
meta-button-layout.c \
meta-button-layout-private.h \
meta-button-private.h \
@@ -69,7 +69,7 @@ libmetacity_la_LIBADD = \
libmetacity_includedir = $(includedir)/metacity/libmetacity
libmetacity_include_HEADERS = \
- meta-button-enums.h \
+ meta-button.h \
meta-color.h \
meta-enum-types.h \
meta-frame-borders.h \
diff --git a/libmetacity/meta-button-layout-private.h b/libmetacity/meta-button-layout-private.h
index 62c62df1..4926b1dc 100644
--- a/libmetacity/meta-button-layout-private.h
+++ b/libmetacity/meta-button-layout-private.h
@@ -19,23 +19,17 @@
#ifndef META_BUTTON_LAYOUT_PRIVATE_H
#define META_BUTTON_LAYOUT_PRIVATE_H
-#include "meta-button-enums.h"
+#include "meta-button.h"
G_BEGIN_DECLS
typedef struct
{
- /* buttons in the group on the left side */
- MetaButtonType left_buttons[META_BUTTON_TYPE_LAST];
- gboolean left_buttons_has_spacer[META_BUTTON_TYPE_LAST];
- gint n_left_buttons;
+ MetaButton *left_buttons;
+ gint n_left_buttons;
- /* buttons in the group on the right side */
- MetaButtonType right_buttons[META_BUTTON_TYPE_LAST];
- gboolean right_buttons_has_spacer[META_BUTTON_TYPE_LAST];
- gint n_right_buttons;
-
- MetaButtonState button_states[META_BUTTON_TYPE_LAST];
+ MetaButton *right_buttons;
+ gint n_right_buttons;
} MetaButtonLayout;
MetaButtonLayout *meta_button_layout_new (const gchar *str,
diff --git a/libmetacity/meta-button-layout.c b/libmetacity/meta-button-layout.c
index fb92712d..4679cbf8 100644
--- a/libmetacity/meta-button-layout.c
+++ b/libmetacity/meta-button-layout.c
@@ -21,7 +21,7 @@
#include "meta-button-layout-private.h"
static MetaButtonType
-meta_button_type_from_string (const gchar *str)
+type_from_string (const gchar *str)
{
if (g_strcmp0 (str, "menu") == 0)
return META_BUTTON_TYPE_MENU;
@@ -45,12 +45,14 @@ meta_button_type_from_string (const gchar *str)
return META_BUTTON_TYPE_STICK;
else if (g_strcmp0 (str, "unstick") == 0)
return META_BUTTON_TYPE_UNSTICK;
+ else if (g_strcmp0 (str, "spacer") == 0)
+ return META_BUTTON_TYPE_SPACER;
return META_BUTTON_TYPE_LAST;
}
static MetaButtonType
-meta_button_type_get_opposite (MetaButtonType type)
+get_opposite_type (MetaButtonType type)
{
switch (type)
{
@@ -74,155 +76,141 @@ meta_button_type_get_opposite (MetaButtonType type)
case META_BUTTON_TYPE_MINIMIZE:
case META_BUTTON_TYPE_MAXIMIZE:
case META_BUTTON_TYPE_CLOSE:
+ case META_BUTTON_TYPE_SPACER:
case META_BUTTON_TYPE_LAST:
- return META_BUTTON_TYPE_LAST;
-
default:
- return META_BUTTON_TYPE_LAST;
+ break;
}
-}
-
-static void
-meta_button_layout_init (MetaButtonLayout *layout)
-{
- gint i;
-
- for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
- {
- layout->left_buttons[i] = META_BUTTON_TYPE_LAST;
- layout->left_buttons_has_spacer[i] = FALSE;
- layout->right_buttons[i] = META_BUTTON_TYPE_LAST;
- layout->right_buttons_has_spacer[i] = FALSE;
- }
+ return META_BUTTON_TYPE_LAST;
}
-static void
-string_to_buttons (const gchar *str,
- MetaButtonType side_buttons[META_BUTTON_TYPE_LAST],
- gboolean side_has_spacer[META_BUTTON_TYPE_LAST])
+static MetaButton *
+string_to_buttons (const gchar *str,
+ gint *n_buttons)
{
- gint i;
- gint b;
- gboolean used[META_BUTTON_TYPE_LAST];
gchar **buttons;
+ MetaButton *retval;
+ gint index;
+ gint i;
+
+ *n_buttons = 0;
- i = 0;
- while (i < META_BUTTON_TYPE_LAST)
- used[i++] = FALSE;
+ if (str == NULL)
+ return NULL;
buttons = g_strsplit (str, ",", -1);
- i = b = 0;
- while (buttons[b] != NULL)
+ for (i = 0; buttons[i] != NULL; i++)
{
MetaButtonType type;
- type = meta_button_type_from_string (buttons[b]);
+ type = type_from_string (buttons[i]);
- if (i > 0 && g_strcmp0 ("spacer", buttons[b]) == 0)
+ if (type != META_BUTTON_TYPE_LAST)
{
- side_has_spacer[i - 1] = TRUE;
-
- type = meta_button_type_get_opposite (type);
- if (type != META_BUTTON_TYPE_LAST)
- side_has_spacer[i - 2] = TRUE;
+ if (get_opposite_type (type) != META_BUTTON_TYPE_LAST)
+ *n_buttons += 2;
+ else
+ *n_buttons += 1;
}
else
{
- if (type != META_BUTTON_TYPE_LAST && !used[type])
- {
- side_buttons[i] = type;
- used[type] = TRUE;
- i++;
+ g_debug ("Ignoring unknown button name - '%s'", buttons[i]);
+ }
+ }
- type = meta_button_type_get_opposite (type);
- if (type != META_BUTTON_TYPE_LAST)
- side_buttons[i++] = type;
- }
- else
+ retval = g_new0 (MetaButton, *n_buttons);
+ index = 0;
+
+ for (i = 0; buttons[i] != NULL; i++)
+ {
+ MetaButtonType type;
+
+ type = type_from_string (buttons[i]);
+
+ if (type != META_BUTTON_TYPE_LAST)
+ {
+ GdkRectangle empty;
+ MetaButton tmp;
+
+ empty.x = 0;
+ empty.y = 0;
+ empty.width = 0;
+ empty.height = 0;
+
+ tmp.type = type;
+ tmp.state = META_BUTTON_STATE_NORMAL;
+ tmp.rect.visible = empty;
+ tmp.rect.clickable = empty;
+ tmp.visible = TRUE;
+
+ retval[index++] = tmp;
+
+ type = get_opposite_type (type);
+ if (type != META_BUTTON_TYPE_LAST)
{
- g_debug ("Ignoring unknown or already-used button name - '%s'",
- buttons[b]);
+ tmp.type = type;
+ retval[index++] = tmp;
}
}
-
- b++;
}
g_strfreev (buttons);
+
+ return retval;
}
MetaButtonLayout *
meta_button_layout_new (const gchar *str,
gboolean invert)
{
- gchar **sides;
MetaButtonLayout *layout;
- MetaButtonLayout *rtl_layout;
- gint i;
- gint j;
+ gchar **sides;
+ const gchar *buttons;
+ gint n_buttons;
layout = g_new0 (MetaButtonLayout, 1);
- meta_button_layout_init (layout);
-
sides = g_strsplit (str, ":", 2);
- if (sides[0] != NULL)
- {
- string_to_buttons (sides[0], layout->left_buttons,
- layout->left_buttons_has_spacer);
- }
+ buttons = sides[0];
+ layout->left_buttons = string_to_buttons (buttons, &n_buttons);
+ layout->n_left_buttons = n_buttons;
- if (sides[0] != NULL && sides[1] != NULL)
- {
- string_to_buttons (sides[1], layout->right_buttons,
- layout->right_buttons_has_spacer);
- }
+ buttons = sides[0] != NULL ? sides[1] : NULL;
+ layout->right_buttons = string_to_buttons (buttons, &n_buttons);
+ layout->n_right_buttons = n_buttons;
g_strfreev (sides);
- if (!invert)
- return layout;
-
- rtl_layout = g_new0 (MetaButtonLayout, 1);
- meta_button_layout_init (rtl_layout);
-
- i = 0;
- while (rtl_layout->left_buttons[i] != META_BUTTON_TYPE_LAST)
- i++;
-
- for (j = 0; j < i; j++)
+ if (invert)
{
- rtl_layout->right_buttons[j] = layout->left_buttons[i - j - 1];
+ MetaButtonLayout *rtl_layout;
+ gint i;
- if (j == 0)
- rtl_layout->right_buttons_has_spacer[i - 1] = layout->left_buttons_has_spacer[i - j - 1];
- else
- rtl_layout->right_buttons_has_spacer[j - 1] = layout->left_buttons_has_spacer[i - j - 1];
- }
+ rtl_layout = g_new0 (MetaButtonLayout, 1);
+ rtl_layout->left_buttons = g_new0 (MetaButton, layout->n_right_buttons);
+ rtl_layout->right_buttons = g_new0 (MetaButton, layout->n_left_buttons);
- i = 0;
- while (rtl_layout->left_buttons[i] != META_BUTTON_TYPE_LAST)
- i++;
+ for (i = 0; i < layout->n_left_buttons; i++)
+ rtl_layout->right_buttons[i] = rtl_layout->left_buttons[layout->n_left_buttons - i];
- for (j = 0; j < i; j++)
- {
- rtl_layout->left_buttons[j] = layout->right_buttons[i - j - 1];
+ for (i = 0; i < layout->n_right_buttons; i++)
+ rtl_layout->left_buttons[i] = rtl_layout->right_buttons[layout->n_right_buttons - i];
- if (j == 0)
- rtl_layout->left_buttons_has_spacer[i - 1] = layout->right_buttons_has_spacer[i - j - 1];
- else
- rtl_layout->left_buttons_has_spacer[j - 1] = layout->right_buttons_has_spacer[i - j - 1];
- }
+ meta_button_layout_free (layout);
- meta_button_layout_free (layout);
+ return rtl_layout;
+ }
- return rtl_layout;
+ return layout;
}
void
meta_button_layout_free (MetaButtonLayout *layout)
{
+ g_free (layout->left_buttons);
+ g_free (layout->right_buttons);
+
g_free (layout);
}
diff --git a/libmetacity/meta-button-enums.h b/libmetacity/meta-button.h
index 4ef4505e..a087e147 100644
--- a/libmetacity/meta-button-enums.h
+++ b/libmetacity/meta-button.h
@@ -16,10 +16,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef META_BUTTON_ENUMS_H
-#define META_BUTTON_ENUMS_H
+#ifndef META_BUTTON_H
+#define META_BUTTON_H
-#include <glib.h>
+#include <gdk/gdk.h>
G_BEGIN_DECLS
@@ -36,6 +36,7 @@ typedef enum
META_BUTTON_TYPE_UNABOVE,
META_BUTTON_TYPE_STICK,
META_BUTTON_TYPE_UNSTICK,
+ META_BUTTON_TYPE_SPACER,
META_BUTTON_TYPE_LAST
} MetaButtonType;
@@ -47,6 +48,26 @@ typedef enum
META_BUTTON_STATE_LAST
} MetaButtonState;
+typedef struct
+{
+ MetaButtonType type;
+ MetaButtonState state;
+
+ /* The computed size of a button (really just a way of tying its visible
+ * and clickable areas together). The reason for two different rectangles
+ * here is Fitts' law & maximized windows; See bug #97703 for more details.
+ */
+ struct {
+ /* The area where the button's image is drawn. */
+ GdkRectangle visible;
+
+ /* The area where the button can be activated by clicking */
+ GdkRectangle clickable;
+ } rect;
+
+ gboolean visible;
+} MetaButton;
+
G_END_DECLS
#endif
diff --git a/libmetacity/meta-frame-style-private.h b/libmetacity/meta-frame-style-private.h
index f3351b34..380ac188 100644
--- a/libmetacity/meta-frame-style-private.h
+++ b/libmetacity/meta-frame-style-private.h
@@ -19,7 +19,7 @@
#ifndef META_FRAME_STYLE_PRIVATE_H
#define META_FRAME_STYLE_PRIVATE_H
-#include "meta-button-enums.h"
+#include "meta-button.h"
#include "meta-button-private.h"
#include "meta-color-spec-private.h"
#include "meta-draw-op-private.h"
diff --git a/libmetacity/meta-theme-gtk.c b/libmetacity/meta-theme-gtk.c
index 94fba18d..22a8f67f 100644
--- a/libmetacity/meta-theme-gtk.c
+++ b/libmetacity/meta-theme-gtk.c
@@ -288,120 +288,6 @@ meta_theme_gtk_get_frame_borders (MetaThemeImpl *impl,
scale_border (&borders->total, scale);
}
-static MetaButtonSpace *
-rect_for_type (MetaFrameGeometry *fgeom,
- MetaFrameFlags flags,
- MetaButtonType type)
-{
- switch (type)
- {
- case META_BUTTON_TYPE_MENU:
- if (flags & META_FRAME_ALLOWS_MENU)
- return &fgeom->menu_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_APPMENU:
- if (flags & META_FRAME_ALLOWS_APPMENU)
- return &fgeom->appmenu_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_MINIMIZE:
- if (flags & META_FRAME_ALLOWS_MINIMIZE)
- return &fgeom->min_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_MAXIMIZE:
- if (flags & META_FRAME_ALLOWS_MAXIMIZE)
- return &fgeom->max_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_CLOSE:
- if (flags & META_FRAME_ALLOWS_DELETE)
- return &fgeom->close_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_SHADE:
- if ((flags & META_FRAME_ALLOWS_SHADE) && !(flags & META_FRAME_SHADED))
- return &fgeom->shade_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_ABOVE:
- if (!(flags & META_FRAME_ABOVE))
- return &fgeom->above_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_STICK:
- if (!(flags & META_FRAME_STUCK))
- return &fgeom->stick_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_UNSHADE:
- if ((flags & META_FRAME_ALLOWS_SHADE) && (flags & META_FRAME_SHADED))
- return &fgeom->unshade_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_UNABOVE:
- if (flags & META_FRAME_ABOVE)
- return &fgeom->unabove_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_UNSTICK:
- if (flags & META_FRAME_STUCK)
- return &fgeom->unstick_rect;
- else
- return NULL;
-
- case META_BUTTON_TYPE_LAST:
- default:
- break;
- }
-
- return NULL;
-}
-
-static gboolean
-strip_button (MetaButtonSpace *func_rects[META_BUTTON_TYPE_LAST],
- int *n_rects,
- MetaButtonSpace *to_strip)
-{
- int i;
-
- i = 0;
- while (i < *n_rects)
- {
- if (func_rects[i] == to_strip)
- {
- *n_rects -= 1;
-
- /* shift the other rects back in the array */
- while (i < *n_rects)
- {
- func_rects[i] = func_rects[i+1];
-
- ++i;
- }
-
- func_rects[i] = NULL;
-
- return TRUE;
- }
-
- ++i;
- }
-
- return FALSE; /* did not strip anything */
-}
-
static void
meta_theme_gtk_calc_geometry (MetaThemeImpl *impl,
MetaFrameLayout *layout,
@@ -425,14 +311,6 @@ meta_theme_gtk_calc_geometry (MetaThemeImpl *impl,
int button_width, button_height;
int min_size_for_rounding;
- /* the left/right rects in order; the max # of rects
- * is the number of button functions
- */
- MetaButtonSpace *left_func_rects[META_BUTTON_TYPE_LAST];
- MetaButtonSpace *right_func_rects[META_BUTTON_TYPE_LAST];
- gboolean left_buttons_has_spacer[META_BUTTON_TYPE_LAST];
- gboolean right_buttons_has_spacer[META_BUTTON_TYPE_LAST];
-
META_THEME_IMPL_GET_CLASS (impl)->get_frame_borders (impl, layout,
style_info, text_height,
flags, type, &borders);
@@ -464,16 +342,6 @@ meta_theme_gtk_calc_geometry (MetaThemeImpl *impl,
button_width *= scale;
button_height *= scale;
- /* FIXME all this code sort of pretends that duplicate buttons
- * with the same function are allowed, but that breaks the
- * code in frames.c, so isn't really allowed right now.
- * Would need left_close_rect, right_close_rect, etc.
- */
-
- /* Init all button rects to 0, lame hack */
- memset (ADDRESS_OF_BUTTON_RECTS (fgeom), '\0',
- LENGTH_OF_BUTTON_RECTS);
-
n_left = 0;
n_right = 0;
n_left_spacers = 0;
@@ -481,35 +349,44 @@ meta_theme_gtk_calc_geometry (MetaThemeImpl *impl,
if (!layout->hide_buttons)
{
- /* Try to fill in rects */
- for (i = 0; i < META_BUTTON_TYPE_LAST && button_layout->left_buttons[i] != META_BUTTON_TYPE_LAST; i++)
+ MetaButton *button;
+
+ for (i = 0; i < button_layout->n_left_buttons; i++)
{
- left_func_rects[n_left] = rect_for_type (fgeom, flags,
- button_layout->left_buttons[i]);
- if (left_func_rects[n_left] != NULL)
- {
- left_buttons_has_spacer[n_left] = button_layout->left_buttons_has_spacer[i];
- if (button_layout->left_buttons_has_spacer[i])
- ++n_left_spacers;
+ button = &button_layout->left_buttons[i];
+ button->visible = is_button_visible (button, flags);
- ++n_left;
+ if (button->visible)
+ {
+ if (button->type != META_BUTTON_TYPE_SPACER)
+ n_left++;
+ else
+ n_left_spacers++;
}
}
- for (i = 0; i < META_BUTTON_TYPE_LAST && button_layout->right_buttons[i] != META_BUTTON_TYPE_LAST; i++)
+ for (i = 0; i < button_layout->n_right_buttons; i++)
{
- right_func_rects[n_right] = rect_for_type (fgeom, flags,
- button_layout->right_buttons[i]);
- if (right_func_rects[n_right] != NULL)
- {
- right_buttons_has_spacer[n_right] = button_layout->right_buttons_has_spacer[i];
- if (button_layout->right_buttons_has_spacer[i])
- ++n_right_spacers;
+ button = &button_layout->right_buttons[i];
+ button->visible = is_button_visible (button, flags);
- ++n_right;
+ if (button->visible)
+ {
+ if (button->type != META_BUTTON_TYPE_SPACER)
+ n_left++;
+ else
+ n_left_spacers++;
}
}
}
+ else
+ {
+ for (i = 0; i < button_layout->n_left_buttons; i++)
+ button_layout->left_buttons[i].visible = FALSE;
+
+ for (i = 0; i < button_layout->n_right_buttons; i++)
+ button_layout->right_buttons[i].visible = FALSE;
+ }
/* Be sure buttons fit */
while (n_left > 0 || n_right > 0)
@@ -536,51 +413,41 @@ meta_theme_gtk_calc_geometry (MetaThemeImpl *impl,
/* First try to remove separators */
if (n_left_spacers > 0)
{
- left_buttons_has_spacer[--n_left_spacers] = FALSE;
- continue;
+ if (strip_button (button_layout->left_buttons,
+ button_layout->n_left_buttons,
+ META_BUTTON_TYPE_SPACER))
+ {
+ n_left_spacers--;
+ continue;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
}
else if (n_right_spacers > 0)
{
- right_buttons_has_spacer[--n_right_spacers] = FALSE;
- continue;
+ if (strip_button (button_layout->right_buttons,
+ button_layout->n_right_buttons,
+ META_BUTTON_TYPE_SPACER))
+ {
+ n_right_spacers--;
+ continue;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
}
/* Otherwise we need to shave out a button. Shave
* above, stick, shade, min, max, close, then menu (menu is most useful);
* prefer the default button locations.
*/
- if (strip_button (left_func_rects, &n_left, &fgeom->above_rect))
- continue;
- else if (strip_button (right_func_rects, &n_right, &fgeom->above_rect))
- continue;
- else if (strip_button (left_func_rects, &n_left, &fgeom->stick_rect))
- continue;
- else if (strip_button (right_func_rects, &n_right, &fgeom->stick_rect))
- continue;
- else if (strip_button (left_func_rects, &n_left, &fgeom->shade_rect))
- continue;
- else if (strip_button (right_func_rects, &n_right, &fgeom->shade_rect))
- continue;
- else if (strip_button (left_func_rects, &n_left, &fgeom->min_rect))
- continue;
- else if (strip_button (right_func_rects, &n_right, &fgeom->min_rect))
- continue;
- else if (strip_button (left_func_rects, &n_left, &fgeom->max_rect))
- continue;
- else if (strip_button (right_func_rects, &n_right, &fgeom->max_rect))
- continue;
- else if (strip_button (left_func_rects, &n_left, &fgeom->close_rect))
- continue;
- else if (strip_button (right_func_rects, &n_right, &fgeom->close_rect))
- continue;
- else if (strip_button (right_func_rects, &n_right, &fgeom->menu_rect))
- continue;
- else if (strip_button (left_func_rects, &n_left, &fgeom->menu_rect))
- continue;
- else if (strip_button (right_func_rects, &n_right, &fgeom->appmenu_rect))
- continue;
- else if (strip_button (left_func_rects, &n_left, &fgeom->appmenu_rect))
- continue;
+ if (strip_buttons (button_layout, &n_left, &n_right))
+ {
+ continue;
+ }
else
{
g_error ("Could not find a button to strip. n_left = %d n_right = %d",
@@ -588,10 +455,6 @@ meta_theme_gtk_calc_geometry (MetaThemeImpl *impl,
}
}
- /* Save the button layout */
- button_layout->n_left_buttons = n_left;
- button_layout->n_right_buttons = n_right;
-
/* center buttons vertically */
button_y = borders.invisible.top + layout->gtk.frame_border.top * scale +
(content_height - button_height) / 2;
@@ -600,48 +463,61 @@ meta_theme_gtk_calc_geometry (MetaThemeImpl *impl,
x = width - borders.invisible.right - layout->gtk.frame_border.right * scale -
layout->gtk.titlebar_border.right * scale;
- i = n_right - 1;
- while (i >= 0)
+ for (i = button_layout->n_right_buttons - 1; i >= 0; i--)
{
- MetaButtonSpace *rect;
+ MetaButton *button;
+ GdkRectangle rect;
+
+ button = &button_layout->right_buttons[i];
+
+ if (button->visible == FALSE)
+ continue;
- if (x < 0) /* if we go negative, leave the buttons we don't get to as 0-width */
+ /* if we go negative, leave the buttons we don't get to as 0 - width */
+ if (x < 0)
break;
x -= layout->gtk.button_margin.right * scale;
- rect = right_func_rects[i];
+ rect.y = button_y;
+ rect.width = button_width;
+ rect.height = button_height;
- rect->visible.x = x - button_width;
- if (right_buttons_has_spacer[i])
- rect->visible.x -= (button_width * 0.75);
+ if (button->type == META_BUTTON_TYPE_SPACER)
+ {
+ rect.x = x - button_width * 0.75;
+ rect.width *= 0.75;
+ }
+ else
+ {
+ rect.x = x - button_width;
+ }
- rect->visible.y = button_y;
- rect->visible.width = button_width;
- rect->visible.height = button_height;
+ button->rect.visible = rect;
+ button->rect.clickable = rect;
- if (flags & META_FRAME_MAXIMIZED ||
- flags & META_FRAME_TILED_LEFT ||
- flags & META_FRAME_TILED_RIGHT)
+ if ((flags & META_FRAME_MAXIMIZED || flags & META_FRAME_TILED_RIGHT) &&
+ i == button_layout->n_right_buttons - 1)
{
- rect->clickable.x = rect->visible.x;
- rect->clickable.y = rect->visible.y;
- rect->clickable.width = button_width;
- rect->clickable.height = button_height;
-
- if (i == n_right - 1)
- rect->clickable.width += layout->gtk.frame_border.right * scale +
- layout->gtk.titlebar_border.right * scale;
+ gint extra_width;
+ gint extra_height;
+
+ extra_width = layout->gtk.button_margin.right * scale +
+ layout->gtk.frame_border.right * scale +
+ layout->gtk.titlebar_border.right * scale;
+
+ /* FIXME: */
+ extra_height = 0;
+
+ button->rect.clickable.y -= extra_height;
+ button->rect.clickable.width += extra_width;
+ button->rect.clickable.height += extra_height;
}
- else
- g_memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
- x = rect->visible.x - layout->gtk.button_margin.left * scale;
+ x = rect.x - layout->gtk.button_margin.left * scale;
if (i > 0)
x -= layout->gtk.titlebar_spacing * scale;
-
- --i;
}
/* save right edge of titlebar for later use */
@@ -653,34 +529,50 @@ meta_theme_gtk_calc_geometry (MetaThemeImpl *impl,
x = borders.invisible.left + layout->gtk.frame_border.left * scale +
layout->gtk.titlebar_border.left * scale;
- for (i = 0; i < n_left; i++)
+ for (i = 0; i < button_layout->n_left_buttons; i++)
{
- MetaButtonSpace *rect;
+ MetaButton *button;
+ GdkRectangle rect;
+
+ button = &button_layout->left_buttons[i];
+
+ if (button->visible == FALSE)
+ continue;
- x += layout->gtk.button_margin.left * scale;
+ rect.x = x + layout->gtk.button_margin.left * scale;
+ rect.y = button_y;
+ rect.width = button_width;
+ rect.height = button_height;
- rect = left_func_rects[i];
+ if (button->type == META_BUTTON_TYPE_SPACER)
+ rect.width *= 0.75;
- rect->visible.x = x;
- rect->visible.y = button_y;
- rect->visible.width = button_width;
- rect->visible.height = button_height;
+ button->rect.visible = rect;
+ button->rect.clickable = rect;
- if (flags & META_FRAME_MAXIMIZED)
+ if ((flags & META_FRAME_MAXIMIZED || flags & META_FRAME_TILED_LEFT) &&
+ i == 0)
{
- rect->clickable.x = rect->visible.x;
- rect->clickable.y = rect->visible.y;
- rect->clickable.width = button_width;
- rect->clickable.height = button_height;
+ gint extra_width;
+ gint extra_height;
+
+ extra_width = layout->gtk.button_margin.left * scale +
+ layout->gtk.frame_border.left * scale +
+ layout->gtk.titlebar_border.left * scale;
+
+ /* FIXME: */
+ extra_height = 0;
+
+ button->rect.clickable.x -= extra_width;
+ button->rect.clickable.y -= extra_height;
+ button->rect.clickable.width += extra_width;
+ button->rect.clickable.height += extra_height;
}
- else
- g_memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
- x = rect->visible.x + rect->visible.width + layout->gtk.button_margin.right * scale;
- if (i < n_left - 1)
+ x = rect.x + rect.width + layout->gtk.button_margin.right * scale;
+
+ if (i < button_layout->n_left_buttons - 1)
x += layout->gtk.titlebar_spacing * scale;
- if (left_buttons_has_spacer[i])
- x += (button_width * 0.75);
}
/* Center vertically in the available content area */
@@ -747,10 +639,10 @@ meta_theme_gtk_draw_frame (MetaThemeImpl *impl,
gdouble scale;
GtkStyleContext *context;
GtkStateFlags state;
- MetaButtonType button_type;
MetaRectangleDouble visible_rect;
MetaRectangleDouble titlebar_rect;
const MetaFrameBorders *borders;
+ gint side;
/* We opt out of GTK+ HiDPI handling, so we have to do the scaling
* ourselves; the nitty-gritty is a bit confusing, so here is an overview:
@@ -827,49 +719,73 @@ meta_theme_gtk_draw_frame (MetaThemeImpl *impl,
context = meta_style_info_get_style (style_info, META_STYLE_ELEMENT_BUTTON);
state = gtk_style_context_get_state (context);
- for (button_type = 0; button_type < META_BUTTON_TYPE_LAST; button_type++)
- {
- MetaButtonState button_state;
- const char *button_class;
- GdkRectangle tmp_rect;
- MetaRectangleDouble button_rect;
- button_class = get_class_from_button_type (button_type);
+ for (side = 0; side < 2; side++)
+ {
+ MetaButton *buttons;
+ gint n_buttons;
+ gint i;
- if (button_class)
- gtk_style_context_add_class (context, button_class);
+ if (side == 0)
+ {
+ buttons = button_layout->left_buttons;
+ n_buttons = button_layout->n_left_buttons;
+ }
+ else if (side == 1)
+ {
+ buttons = button_layout->right_buttons;
+ n_buttons = button_layout->n_right_buttons;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
- button_state = button_layout->button_states[button_type];
+ for (i = 0; i < n_buttons; i++)
+ {
+ MetaButton *button;
+ gdouble x;
+ gdouble y;
+ gdouble width;
+ gdouble height;
+ const gchar *button_class;
+ const gchar *icon_name;
+ GdkPixbuf *pixbuf;
+
+ button = &buttons[i];
+
+ x = button->rect.visible.x / scale;
+ y = button->rect.visible.y / scale;
+ width = button->rect.visible.width / scale;
+ height = button->rect.visible.height / scale;
+
+ if (!button->visible || button->type == META_BUTTON_TYPE_SPACER ||
+ width <= 0 || height <= 0)
+ {
+ continue;
+ }
- if (button_state == META_BUTTON_STATE_PRELIGHT)
- gtk_style_context_set_state (context, state | GTK_STATE_PRELIGHT);
- else if (button_state == META_BUTTON_STATE_PRESSED)
- gtk_style_context_set_state (context, state | GTK_STATE_ACTIVE);
- else
- gtk_style_context_set_state (context, state);
+ button_class = get_class_from_button_type (button->type);
- cairo_save (cr);
+ if (button_class)
+ gtk_style_context_add_class (context, button_class);
- get_button_rect_for_type (button_type, fgeom, &tmp_rect);
+ if (button->state == META_BUTTON_STATE_PRELIGHT)
+ gtk_style_context_set_state (context, state | GTK_STATE_PRELIGHT);
+ else if (button->state == META_BUTTON_STATE_PRESSED)
+ gtk_style_context_set_state (context, state | GTK_STATE_ACTIVE);
+ else
+ gtk_style_context_set_state (context, state);
- button_rect.x = tmp_rect.x / scale;
- button_rect.y = tmp_rect.y / scale;
- button_rect.width = tmp_rect.width / scale;
- button_rect.height = tmp_rect.height / scale;
+ cairo_save (cr);
- if (button_rect.width > 0 && button_rect.height > 0)
- {
- GdkPixbuf *pixbuf = NULL;
- const char *icon_name = NULL;
+ gtk_render_background (context, cr, x, y, width, height);
+ gtk_render_frame (context, cr, x, y, width, height);
- gtk_render_background (context, cr,
- button_rect.x, button_rect.y,
- button_rect.width, button_rect.height);
- gtk_render_frame (context, cr,
- button_rect.x, button_rect.y,
- button_rect.width, button_rect.height);
+ icon_name = NULL;
+ pixbuf = NULL;
- switch (button_type)
+ switch (button->type)
{
case META_BUTTON_TYPE_CLOSE:
icon_name = "window-close-symbolic";
@@ -895,49 +811,58 @@ meta_theme_gtk_draw_frame (MetaThemeImpl *impl,
case META_BUTTON_TYPE_UNSHADE:
case META_BUTTON_TYPE_UNABOVE:
case META_BUTTON_TYPE_UNSTICK:
+ case META_BUTTON_TYPE_SPACER:
case META_BUTTON_TYPE_LAST:
default:
- icon_name = NULL;
break;
}
if (icon_name)
{
- GtkIconTheme *theme = gtk_icon_theme_get_default ();
+ GtkIconTheme *theme;
GtkIconInfo *info;
+ theme = gtk_icon_theme_get_default ();
info = gtk_icon_theme_lookup_icon_for_scale (theme, icon_name,
style->layout->gtk.icon_size,
scale, 0);
+ g_assert (pixbuf == NULL);
pixbuf = gtk_icon_info_load_symbolic_for_context (info, context, NULL, NULL);
}
if (pixbuf)
{
- float width, height;
- gdouble x, y;
-
- width = gdk_pixbuf_get_width (pixbuf) / scale;
- height = gdk_pixbuf_get_height (pixbuf) / scale;
- x = button_rect.x + (button_rect.width - width) / 2;
- y = button_rect.y + (button_rect.height - height) / 2;
-
- cairo_translate (cr, x, y);
- cairo_scale (cr,
- width / style->layout->gtk.icon_size / scale,
- height / style->layout->gtk.icon_size / scale);
+ gdouble pwidth;
+ gdouble pheight;
+ gdouble px;
+ gdouble py;
+ gdouble scale_x;
+ gdouble scale_y;
+
+ pwidth = gdk_pixbuf_get_width (pixbuf) / scale;
+ pheight = gdk_pixbuf_get_height (pixbuf) / scale;
+ px = x + (width - pwidth) / 2;
+ py = y + (height - pheight) / 2;
+
+ scale_x = pwidth / style->layout->gtk.icon_size / scale;
+ scale_y = pheight / style->layout->gtk.icon_size / scale;
+
+ cairo_translate (cr, px, py);
+ cairo_scale (cr, scale_x, scale_y);
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
cairo_paint (cr);
g_object_unref (pixbuf);
}
- }
- cairo_restore (cr);
+ cairo_restore (cr);
+
+ if (button_class)
+ gtk_style_context_remove_class (context, button_class);
- if (button_class)
- gtk_style_context_remove_class (context, button_class);
+ gtk_style_context_set_state (context, state);
+ }
}
}
diff --git a/libmetacity/meta-theme-impl-private.h b/libmetacity/meta-theme-impl-private.h
index 77cba2c5..1112fc3b 100644
--- a/libmetacity/meta-theme-impl-private.h
+++ b/libmetacity/meta-theme-impl-private.h
@@ -89,17 +89,26 @@ MetaFrameStyleSet *meta_theme_impl_get_style_set (MetaThemeImpl *impl
MetaFrameType type);
G_GNUC_INTERNAL
-void get_button_rect_for_type (MetaButtonType type,
- const MetaFrameGeometry *fgeom,
- GdkRectangle *rect);
-
-G_GNUC_INTERNAL
void scale_border (GtkBorder *border,
double factor);
G_GNUC_INTERNAL
int get_window_scaling_factor (void);
+G_GNUC_INTERNAL
+gboolean is_button_visible (MetaButton *button,
+ MetaFrameFlags flags);
+
+G_GNUC_INTERNAL
+gboolean strip_button (MetaButton *buttons,
+ gint n_buttons,
+ MetaButtonType type);
+
+G_GNUC_INTERNAL
+gboolean strip_buttons (MetaButtonLayout *layout,
+ gint *n_left,
+ gint *n_right);
+
G_END_DECLS
#endif
diff --git a/libmetacity/meta-theme-impl.c b/libmetacity/meta-theme-impl.c
index ac2735c5..1a1da9e9 100644
--- a/libmetacity/meta-theme-impl.c
+++ b/libmetacity/meta-theme-impl.c
@@ -132,64 +132,6 @@ meta_theme_impl_get_style_set (MetaThemeImpl *impl,
}
void
-get_button_rect_for_type (MetaButtonType type,
- const MetaFrameGeometry *fgeom,
- GdkRectangle *rect)
-{
- switch (type)
- {
- case META_BUTTON_TYPE_CLOSE:
- *rect = fgeom->close_rect.visible;
- break;
-
- case META_BUTTON_TYPE_SHADE:
- *rect = fgeom->shade_rect.visible;
- break;
-
- case META_BUTTON_TYPE_UNSHADE:
- *rect = fgeom->unshade_rect.visible;
- break;
-
- case META_BUTTON_TYPE_ABOVE:
- *rect = fgeom->above_rect.visible;
- break;
-
- case META_BUTTON_TYPE_UNABOVE:
- *rect = fgeom->unabove_rect.visible;
- break;
-
- case META_BUTTON_TYPE_STICK:
- *rect = fgeom->stick_rect.visible;
- break;
-
- case META_BUTTON_TYPE_UNSTICK:
- *rect = fgeom->unstick_rect.visible;
- break;
-
- case META_BUTTON_TYPE_MAXIMIZE:
- *rect = fgeom->max_rect.visible;
- break;
-
- case META_BUTTON_TYPE_MINIMIZE:
- *rect = fgeom->min_rect.visible;
- break;
-
- case META_BUTTON_TYPE_MENU:
- *rect = fgeom->menu_rect.visible;
- break;
-
- case META_BUTTON_TYPE_APPMENU:
- *rect = fgeom->appmenu_rect.visible;
- break;
-
- case META_BUTTON_TYPE_LAST:
- default:
- g_assert_not_reached ();
- break;
- }
-}
-
-void
scale_border (GtkBorder *border,
double factor)
{
@@ -214,3 +156,140 @@ get_window_scaling_factor (void)
else
return 1;
}
+
+gboolean
+is_button_visible (MetaButton *button,
+ MetaFrameFlags flags)
+{
+ gboolean visible;
+
+ visible = FALSE;
+
+ switch (button->type)
+ {
+ case META_BUTTON_TYPE_MENU:
+ if (flags & META_FRAME_ALLOWS_MENU)
+ visible = TRUE;
+ break;
+
+ case META_BUTTON_TYPE_APPMENU:
+ if (flags & META_FRAME_ALLOWS_APPMENU)
+ visible = TRUE;
+ break;
+
+ case META_BUTTON_TYPE_MINIMIZE:
+ if (flags & META_FRAME_ALLOWS_MINIMIZE)
+ visible = TRUE;
+ break;
+
+ case META_BUTTON_TYPE_MAXIMIZE:
+ if (flags & META_FRAME_ALLOWS_MAXIMIZE)
+ visible = TRUE;
+ break;
+
+ case META_BUTTON_TYPE_CLOSE:
+ if (flags & META_FRAME_ALLOWS_DELETE)
+ visible = TRUE;
+ break;
+
+ case META_BUTTON_TYPE_SHADE:
+ if ((flags & META_FRAME_ALLOWS_SHADE) && !(flags & META_FRAME_SHADED))
+ visible = TRUE;
+ break;
+
+ case META_BUTTON_TYPE_ABOVE:
+ if (!(flags & META_FRAME_ABOVE))
+ visible = TRUE;
+ break;
+
+ case META_BUTTON_TYPE_STICK:
+ if (!(flags & META_FRAME_STUCK))
+ visible = TRUE;
+ break;
+
+ case META_BUTTON_TYPE_UNSHADE:
+ if ((flags & META_FRAME_ALLOWS_SHADE) && (flags & META_FRAME_SHADED))
+ visible = TRUE;
+ break;
+
+ case META_BUTTON_TYPE_UNABOVE:
+ if (flags & META_FRAME_ABOVE)
+ visible = TRUE;
+ break;
+
+ case META_BUTTON_TYPE_UNSTICK:
+ if (flags & META_FRAME_STUCK)
+ visible = TRUE;
+ break;
+
+ case META_BUTTON_TYPE_SPACER:
+ visible = TRUE;
+ break;
+
+ case META_BUTTON_TYPE_LAST:
+ default:
+ break;
+ }
+
+ return visible;
+}
+
+gboolean
+strip_button (MetaButton *buttons,
+ gint n_buttons,
+ MetaButtonType type)
+{
+ gint i;
+
+ for (i = 0; i < n_buttons; i++)
+ {
+ if (buttons[i].type == type && buttons[i].visible)
+ {
+ buttons[i].visible = FALSE;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+gboolean
+strip_buttons (MetaButtonLayout *layout,
+ gint *n_left,
+ gint *n_right)
+{
+ gint count;
+ MetaButtonType types[META_BUTTON_TYPE_LAST];
+ gint i;
+
+ count = 0;
+ types[count++] = META_BUTTON_TYPE_ABOVE;
+ types[count++] = META_BUTTON_TYPE_UNABOVE;
+ types[count++] = META_BUTTON_TYPE_STICK;
+ types[count++] = META_BUTTON_TYPE_UNSTICK;
+ types[count++] = META_BUTTON_TYPE_SHADE;
+ types[count++] = META_BUTTON_TYPE_UNSHADE;
+ types[count++] = META_BUTTON_TYPE_MINIMIZE;
+ types[count++] = META_BUTTON_TYPE_MAXIMIZE;
+ types[count++] = META_BUTTON_TYPE_CLOSE;
+ types[count++] = META_BUTTON_TYPE_MENU;
+ types[count++] = META_BUTTON_TYPE_APPMENU;
+
+ for (i = 0; i < count; i++)
+ {
+ if (strip_button (layout->left_buttons, layout->n_left_buttons,
+ types[i]))
+ {
+ *n_left -= 1;
+ return TRUE;
+ }
+ else if (strip_button (layout->right_buttons, layout->n_right_buttons,
+ types[i]))
+ {
+ *n_left -= 1;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
diff --git a/libmetacity/meta-theme-metacity.c b/libmetacity/meta-theme-metacity.c
index 7d41ec20..d39a2ddb 100644
--- a/libmetacity/meta-theme-metacity.c
+++ b/libmetacity/meta-theme-metacity.c
@@ -4697,57 +4697,28 @@ meta_theme_metacity_get_frame_borders (MetaThemeImpl *impl,
scale_border (&borders->total, scale);
}
-static MetaButtonSpace *
-rect_for_type (MetaThemeMetacity *metacity,
- MetaFrameGeometry *fgeom,
- MetaFrameFlags flags,
- MetaButtonType type)
+static gboolean
+is_button_allowed (MetaThemeMetacity *metacity,
+ MetaButtonType type)
{
if (theme_allows (metacity, META_THEME_SHADE_STICK_ABOVE_BUTTONS))
{
switch (type)
{
case META_BUTTON_TYPE_SHADE:
- if ((flags & META_FRAME_ALLOWS_SHADE) && !(flags & META_FRAME_SHADED))
- return &fgeom->shade_rect;
- else
- return NULL;
-
case META_BUTTON_TYPE_ABOVE:
- if (!(flags & META_FRAME_ABOVE))
- return &fgeom->above_rect;
- else
- return NULL;
-
case META_BUTTON_TYPE_STICK:
- if (!(flags & META_FRAME_STUCK))
- return &fgeom->stick_rect;
- else
- return NULL;
-
case META_BUTTON_TYPE_UNSHADE:
- if ((flags & META_FRAME_ALLOWS_SHADE) && (flags & META_FRAME_SHADED))
- return &fgeom->unshade_rect;
- else
- return NULL;
-
case META_BUTTON_TYPE_UNABOVE:
- if (flags & META_FRAME_ABOVE)
- return &fgeom->unabove_rect;
- else
- return NULL;
-
case META_BUTTON_TYPE_UNSTICK:
- if (flags & META_FRAME_STUCK)
- return &fgeom->unstick_rect;
- else
- return NULL;
+ return TRUE;
case META_BUTTON_TYPE_MENU:
case META_BUTTON_TYPE_APPMENU:
case META_BUTTON_TYPE_MINIMIZE:
case META_BUTTON_TYPE_MAXIMIZE:
case META_BUTTON_TYPE_CLOSE:
+ case META_BUTTON_TYPE_SPACER:
case META_BUTTON_TYPE_LAST:
default:
break;
@@ -4758,34 +4729,12 @@ rect_for_type (MetaThemeMetacity *metacity,
switch (type)
{
case META_BUTTON_TYPE_MENU:
- if (flags & META_FRAME_ALLOWS_MENU)
- return &fgeom->menu_rect;
- else
- return NULL;
-
case META_BUTTON_TYPE_APPMENU:
- if (flags & META_FRAME_ALLOWS_APPMENU)
- return &fgeom->appmenu_rect;
- else
- return NULL;
-
case META_BUTTON_TYPE_MINIMIZE:
- if (flags & META_FRAME_ALLOWS_MINIMIZE)
- return &fgeom->min_rect;
- else
- return NULL;
-
case META_BUTTON_TYPE_MAXIMIZE:
- if (flags & META_FRAME_ALLOWS_MAXIMIZE)
- return &fgeom->max_rect;
- else
- return NULL;
-
case META_BUTTON_TYPE_CLOSE:
- if (flags & META_FRAME_ALLOWS_DELETE)
- return &fgeom->close_rect;
- else
- return NULL;
+ case META_BUTTON_TYPE_SPACER:
+ return TRUE;
case META_BUTTON_TYPE_STICK:
case META_BUTTON_TYPE_SHADE:
@@ -4798,50 +4747,14 @@ rect_for_type (MetaThemeMetacity *metacity,
* therefore, we don't show the button. return NULL and all will
* be well.
*/
- return NULL;
+ break;
case META_BUTTON_TYPE_LAST:
default:
break;
}
- return NULL;
-}
-
-static gboolean
-strip_button (MetaButtonSpace *func_rects[META_BUTTON_TYPE_LAST],
- GdkRectangle *bg_rects[META_BUTTON_TYPE_LAST],
- int *n_rects,
- MetaButtonSpace *to_strip)
-{
- int i;
-
- i = 0;
- while (i < *n_rects)
- {
- if (func_rects[i] == to_strip)
- {
- *n_rects -= 1;
-
- /* shift the other rects back in the array */
- while (i < *n_rects)
- {
- func_rects[i] = func_rects[i+1];
- bg_rects[i] = bg_rects[i+1];
-
- ++i;
- }
-
- func_rects[i] = NULL;
- bg_rects[i] = NULL;
-
- return TRUE;
- }
-
- ++i;
- }
-
- return FALSE; /* did not strip anything */
+ return FALSE;
}
static void
@@ -4867,16 +4780,6 @@ meta_theme_metacity_calc_geometry (MetaThemeImpl *impl,
int min_size_for_rounding;
int scale;
- /* the left/right rects in order; the max # of rects
- * is the number of button functions
- */
- MetaButtonSpace *left_func_rects[META_BUTTON_TYPE_LAST];
- MetaButtonSpace *right_func_rects[META_BUTTON_TYPE_LAST];
- GdkRectangle *left_bg_rects[META_BUTTON_TYPE_LAST];
- gboolean left_buttons_has_spacer[META_BUTTON_TYPE_LAST];
- GdkRectangle *right_bg_rects[META_BUTTON_TYPE_LAST];
- gboolean right_buttons_has_spacer[META_BUTTON_TYPE_LAST];
-
META_THEME_IMPL_GET_CLASS (impl)->get_frame_borders (impl, layout,
style_info, text_height,
flags, type, &borders);
@@ -4914,16 +4817,6 @@ meta_theme_metacity_calc_geometry (MetaThemeImpl *impl,
break;
}
- /* FIXME all this code sort of pretends that duplicate buttons
- * with the same function are allowed, but that breaks the
- * code in frames.c, so isn't really allowed right now.
- * Would need left_close_rect, right_close_rect, etc.
- */
-
- /* Init all button rects to 0, lame hack */
- memset (ADDRESS_OF_BUTTON_RECTS (fgeom), '\0',
- LENGTH_OF_BUTTON_RECTS);
-
n_left = 0;
n_right = 0;
n_left_spacers = 0;
@@ -4933,64 +4826,45 @@ meta_theme_metacity_calc_geometry (MetaThemeImpl *impl,
if (!layout->hide_buttons)
{
- /* Try to fill in rects */
- for (i = 0; i < META_BUTTON_TYPE_LAST && button_layout->left_buttons[i] != META_BUTTON_TYPE_LAST; i++)
+ MetaButton *button;
+
+ for (i = 0; i < button_layout->n_left_buttons; i++)
{
- left_func_rects[n_left] = rect_for_type (metacity, fgeom, flags,
- button_layout->left_buttons[i]);
- if (left_func_rects[n_left] != NULL)
- {
- left_buttons_has_spacer[n_left] = button_layout->left_buttons_has_spacer[i];
- if (button_layout->left_buttons_has_spacer[i])
- ++n_left_spacers;
+ button = &button_layout->left_buttons[i];
+ button->visible = is_button_visible (button, flags) &&
+ is_button_allowed (metacity, button->type);
- ++n_left;
+ if (button->visible)
+ {
+ if (button->type != META_BUTTON_TYPE_SPACER)
+ n_left++;
+ else
+ n_left_spacers++;
}
}
- for (i = 0; i < META_BUTTON_TYPE_LAST && button_layout->right_buttons[i] != META_BUTTON_TYPE_LAST; i++)
+ for (i = 0; i < button_layout->n_right_buttons; i++)
{
- right_func_rects[n_right] = rect_for_type (metacity, fgeom, flags,
- button_layout->right_buttons[i]);
- if (right_func_rects[n_right] != NULL)
- {
- right_buttons_has_spacer[n_right] = button_layout->right_buttons_has_spacer[i];
- if (button_layout->right_buttons_has_spacer[i])
- ++n_right_spacers;
+ button = &button_layout->right_buttons[i];
+ button->visible = is_button_visible (button, flags) &&
+ is_button_allowed (metacity, button->type);
- ++n_right;
+ if (button->visible)
+ {
+ if (button->type != META_BUTTON_TYPE_SPACER)
+ n_left++;
+ else
+ n_left_spacers++;
}
}
}
-
- for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
+ else
{
- left_bg_rects[i] = NULL;
- right_bg_rects[i] = NULL;
- }
+ for (i = 0; i < button_layout->n_left_buttons; i++)
+ button_layout->left_buttons[i].visible = FALSE;
- for (i = 0; i < n_left; i++)
- {
- if (n_left == 1)
- left_bg_rects[i] = &fgeom->left_single_background;
- else if (i == 0)
- left_bg_rects[i] = &fgeom->left_left_background;
- else if (i == (n_left - 1))
- left_bg_rects[i] = &fgeom->left_right_background;
- else
- left_bg_rects[i] = &fgeom->left_middle_backgrounds[i - 1];
- }
-
- for (i = 0; i < n_right; i++)
- {
- if (n_right == 1)
- right_bg_rects[i] = &fgeom->right_single_background;
- else if (i == (n_right - 1))
- right_bg_rects[i] = &fgeom->right_right_background;
- else if (i == 0)
- right_bg_rects[i] = &fgeom->right_left_background;
- else
- right_bg_rects[i] = &fgeom->right_middle_backgrounds[i - 1];
+ for (i = 0; i < button_layout->n_right_buttons; i++)
+ button_layout->right_buttons[i].visible = FALSE;
}
/* Be sure buttons fit */
@@ -5021,67 +4895,41 @@ meta_theme_metacity_calc_geometry (MetaThemeImpl *impl,
/* First try to remove separators */
if (n_left_spacers > 0)
{
- left_buttons_has_spacer[--n_left_spacers] = FALSE;
- continue;
+ if (strip_button (button_layout->left_buttons,
+ button_layout->n_left_buttons,
+ META_BUTTON_TYPE_SPACER))
+ {
+ n_left_spacers--;
+ continue;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
}
else if (n_right_spacers > 0)
{
- right_buttons_has_spacer[--n_right_spacers] = FALSE;
- continue;
+ if (strip_button (button_layout->right_buttons,
+ button_layout->n_right_buttons,
+ META_BUTTON_TYPE_SPACER))
+ {
+ n_right_spacers--;
+ continue;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
}
/* Otherwise we need to shave out a button. Shave
* above, stick, shade, min, max, close, then menu (menu is most useful);
* prefer the default button locations.
*/
- if (strip_button (left_func_rects, left_bg_rects,
- &n_left, &fgeom->above_rect))
- continue;
- else if (strip_button (right_func_rects, right_bg_rects,
- &n_right, &fgeom->above_rect))
- continue;
- else if (strip_button (left_func_rects, left_bg_rects,
- &n_left, &fgeom->stick_rect))
- continue;
- else if (strip_button (right_func_rects, right_bg_rects,
- &n_right, &fgeom->stick_rect))
- continue;
- else if (strip_button (left_func_rects, left_bg_rects,
- &n_left, &fgeom->shade_rect))
- continue;
- else if (strip_button (right_func_rects, right_bg_rects,
- &n_right, &fgeom->shade_rect))
- continue;
- else if (strip_button (left_func_rects, left_bg_rects,
- &n_left, &fgeom->min_rect))
- continue;
- else if (strip_button (right_func_rects, right_bg_rects,
- &n_right, &fgeom->min_rect))
- continue;
- else if (strip_button (left_func_rects, left_bg_rects,
- &n_left, &fgeom->max_rect))
- continue;
- else if (strip_button (right_func_rects, right_bg_rects,
- &n_right, &fgeom->max_rect))
- continue;
- else if (strip_button (left_func_rects, left_bg_rects,
- &n_left, &fgeom->close_rect))
- continue;
- else if (strip_button (right_func_rects, right_bg_rects,
- &n_right, &fgeom->close_rect))
- continue;
- else if (strip_button (right_func_rects, right_bg_rects,
- &n_right, &fgeom->menu_rect))
- continue;
- else if (strip_button (left_func_rects, left_bg_rects,
- &n_left, &fgeom->menu_rect))
- continue;
- else if (strip_button (right_func_rects, right_bg_rects,
- &n_right, &fgeom->appmenu_rect))
- continue;
- else if (strip_button (left_func_rects, left_bg_rects,
- &n_left, &fgeom->appmenu_rect))
- continue;
+ if (strip_buttons (button_layout, &n_left, &n_right))
+ {
+ continue;
+ }
else
{
g_error ("Could not find a button to strip. n_left = %d n_right = %d",
@@ -5089,10 +4937,6 @@ meta_theme_metacity_calc_geometry (MetaThemeImpl *impl,
}
}
- /* Save the button layout */
- button_layout->n_left_buttons = n_left;
- button_layout->n_right_buttons = n_right;
-
/* center buttons vertically */
button_y = (borders.visible.top -
(button_height + layout->button_border.top * scale + layout->button_border.bottom * scale)) / 2 + layout->button_border.top * scale + borders.invisible.top;
@@ -5100,45 +4944,56 @@ meta_theme_metacity_calc_geometry (MetaThemeImpl *impl,
/* right edge of farthest-right button */
x = width - layout->metacity.right_titlebar_edge * scale - borders.invisible.right;
- i = n_right - 1;
- while (i >= 0)
+ for (i = button_layout->n_right_buttons - 1; i >= 0; i--)
{
- MetaButtonSpace *rect;
+ MetaButton *button;
+ GdkRectangle rect;
- if (x < 0) /* if we go negative, leave the buttons we don't get to as 0-width */
- break;
+ button = &button_layout->right_buttons[i];
+
+ if (button->visible == FALSE)
+ continue;
- rect = right_func_rects[i];
- rect->visible.x = x - layout->button_border.right * scale - button_width;
- if (right_buttons_has_spacer[i])
- rect->visible.x -= (button_width * 0.75);
+ /* if we go negative, leave the buttons we don't get to as 0 - width */
+ if (x < 0)
+ break;
- rect->visible.y = button_y;
- rect->visible.width = button_width;
- rect->visible.height = button_height;
+ rect.y = button_y;
+ rect.width = button_width;
+ rect.height = button_height;
- if (flags & META_FRAME_MAXIMIZED ||
- flags & META_FRAME_TILED_LEFT ||
- flags & META_FRAME_TILED_RIGHT)
+ if (button->type == META_BUTTON_TYPE_SPACER)
{
- rect->clickable.x = rect->visible.x;
- rect->clickable.y = rect->visible.y;
- rect->clickable.width = button_width;
- rect->clickable.height = button_height;
-
- if (i == n_right - 1)
- rect->clickable.width += layout->metacity.right_titlebar_edge * scale +
- layout->metacity.right_width * scale +
- layout->button_border.right * scale;
+ rect.x = x - button_width * 0.75;
+ rect.width *= 0.75;
}
else
- g_memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
+ {
+ rect.x = x - layout->button_border.right * scale - button_width;
+ }
+
+ button->rect.visible = rect;
+ button->rect.clickable = rect;
- *(right_bg_rects[i]) = rect->visible;
+ if ((flags & META_FRAME_MAXIMIZED || flags & META_FRAME_TILED_RIGHT) &&
+ i == button_layout->n_right_buttons - 1)
+ {
+ gint extra_width;
+ gint extra_height;
+
+ extra_width = layout->metacity.right_titlebar_edge * scale +
+ layout->metacity.right_width * scale +
+ layout->button_border.right * scale;
- x = rect->visible.x - layout->button_border.left * scale;
+ /* FIXME: */
+ extra_height = 0;
+
+ button->rect.clickable.y -= extra_height;
+ button->rect.clickable.width += extra_width;
+ button->rect.clickable.height += extra_height;
+ }
- --i;
+ x = rect.x - layout->button_border.left * scale;
}
/* save right edge of titlebar for later use */
@@ -5148,32 +5003,48 @@ meta_theme_metacity_calc_geometry (MetaThemeImpl *impl,
* the left-side buttons
*/
x = layout->metacity.left_titlebar_edge * scale + borders.invisible.left;
- for (i = 0; i < n_left; i++)
+
+ for (i = 0; i < button_layout->n_left_buttons; i++)
{
- MetaButtonSpace *rect;
+ MetaButton *button;
+ GdkRectangle rect;
+
+ button = &button_layout->left_buttons[i];
+
+ if (button->visible == FALSE)
+ continue;
- rect = left_func_rects[i];
+ rect.x = x + layout->button_border.left * scale;;
+ rect.y = button_y;
+ rect.width = button_width;
+ rect.height = button_height;
- rect->visible.x = x + layout->button_border.left * scale;
- rect->visible.y = button_y;
- rect->visible.width = button_width;
- rect->visible.height = button_height;
+ if (button->type == META_BUTTON_TYPE_SPACER)
+ rect.width *= 0.75;
- if (flags & META_FRAME_MAXIMIZED)
+ button->rect.visible = rect;
+ button->rect.clickable = rect;
+
+ if ((flags & META_FRAME_MAXIMIZED || flags & META_FRAME_TILED_LEFT) &&
+ i == 0)
{
- rect->clickable.x = rect->visible.x;
- rect->clickable.y = rect->visible.y;
- rect->clickable.width = button_width;
- rect->clickable.height = button_height;
- }
- else
- g_memmove (&(rect->clickable), &(rect->visible), sizeof(rect->clickable));
+ gint extra_width;
+ gint extra_height;
+
+ extra_width = layout->metacity.left_titlebar_edge * scale +
+ layout->metacity.left_width * scale +
+ layout->button_border.left * scale;
- x = rect->visible.x + rect->visible.width + layout->button_border.right * scale;
- if (left_buttons_has_spacer[i])
- x += (button_width * 0.75);
+ /* FIXME: */
+ extra_height = 0;
- *(left_bg_rects[i]) = rect->visible;
+ button->rect.clickable.x -= extra_width;
+ button->rect.clickable.y -= extra_height;
+ button->rect.clickable.width += extra_width;
+ button->rect.clickable.height += extra_height;
+ }
+
+ x = rect.x + rect.width + layout->button_border.right * scale;
}
/* We always fill as much vertical space as possible with title rect,
@@ -5286,179 +5157,111 @@ clip_to_rounded_corners (cairo_t *cr,
cairo_clip (cr);
}
-static void
-get_button_rect (MetaButtonFunction function,
- const MetaFrameGeometry *fgeom,
- gint middle_background_offset,
- GdkRectangle *rect)
+static MetaButtonFunction
+get_button_function (MetaButtonType type,
+ gboolean background,
+ gint button,
+ gint n_buttons,
+ gint side)
{
- switch (function)
+ if (background)
{
- case META_BUTTON_FUNCTION_LEFT_LEFT_BACKGROUND:
- *rect = fgeom->left_left_background;
- break;
-
- case META_BUTTON_FUNCTION_LEFT_MIDDLE_BACKGROUND:
- *rect = fgeom->left_middle_backgrounds[middle_background_offset];
- break;
-
- case META_BUTTON_FUNCTION_LEFT_RIGHT_BACKGROUND:
- *rect = fgeom->left_right_background;
- break;
-
- case META_BUTTON_FUNCTION_LEFT_SINGLE_BACKGROUND:
- *rect = fgeom->left_single_background;
- break;
-
- case META_BUTTON_FUNCTION_RIGHT_LEFT_BACKGROUND:
- *rect = fgeom->right_left_background;
- break;
-
- case META_BUTTON_FUNCTION_RIGHT_MIDDLE_BACKGROUND:
- *rect = fgeom->right_middle_backgrounds[middle_background_offset];
- break;
-
- case META_BUTTON_FUNCTION_RIGHT_RIGHT_BACKGROUND:
- *rect = fgeom->right_right_background;
- break;
-
- case META_BUTTON_FUNCTION_RIGHT_SINGLE_BACKGROUND:
- *rect = fgeom->right_single_background;
- break;
-
- case META_BUTTON_FUNCTION_CLOSE:
- *rect = fgeom->close_rect.visible;
- break;
-
- case META_BUTTON_FUNCTION_SHADE:
- *rect = fgeom->shade_rect.visible;
- break;
-
- case META_BUTTON_FUNCTION_UNSHADE:
- *rect = fgeom->unshade_rect.visible;
- break;
-
- case META_BUTTON_FUNCTION_ABOVE:
- *rect = fgeom->above_rect.visible;
- break;
+ if (side == 0) /* left */
+ {
+ if (n_buttons == 1)
+ {
+ return META_BUTTON_FUNCTION_LEFT_SINGLE_BACKGROUND;
+ }
+ else if (n_buttons == 2)
+ {
+ if (button == 0)
+ return META_BUTTON_FUNCTION_LEFT_LEFT_BACKGROUND;
+ else
+ return META_BUTTON_FUNCTION_LEFT_RIGHT_BACKGROUND;
+ }
+ else if (n_buttons > 2)
+ {
+ if (button == 0)
+ return META_BUTTON_FUNCTION_LEFT_LEFT_BACKGROUND;
+ else if (button == n_buttons - 1)
+ return META_BUTTON_FUNCTION_LEFT_RIGHT_BACKGROUND;
+ else
+ return META_BUTTON_FUNCTION_LEFT_MIDDLE_BACKGROUND;
+ }
+ }
+ else if (side == 1) /* right */
+ {
+ if (n_buttons == 1)
+ {
+ return META_BUTTON_FUNCTION_RIGHT_SINGLE_BACKGROUND;
+ }
+ else if (n_buttons == 2)
+ {
+ if (button == 0)
+ return META_BUTTON_FUNCTION_RIGHT_LEFT_BACKGROUND;
+ else
+ return META_BUTTON_FUNCTION_RIGHT_RIGHT_BACKGROUND;
+ }
+ else if (n_buttons > 2)
+ {
+ if (button == 0)
+ return META_BUTTON_FUNCTION_RIGHT_LEFT_BACKGROUND;
+ else if (button == n_buttons - 1)
+ return META_BUTTON_FUNCTION_RIGHT_RIGHT_BACKGROUND;
+ else
+ return META_BUTTON_FUNCTION_RIGHT_MIDDLE_BACKGROUND;
+ }
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+ }
+ else
+ {
+ switch (type)
+ {
+ case META_BUTTON_TYPE_SHADE:
+ return META_BUTTON_FUNCTION_SHADE;
- case META_BUTTON_FUNCTION_UNABOVE:
- *rect = fgeom->unabove_rect.visible;
- break;
+ case META_BUTTON_TYPE_UNSHADE:
+ return META_BUTTON_FUNCTION_UNSHADE;
- case META_BUTTON_FUNCTION_STICK:
- *rect = fgeom->stick_rect.visible;
- break;
+ case META_BUTTON_TYPE_ABOVE:
+ return META_BUTTON_FUNCTION_ABOVE;
- case META_BUTTON_FUNCTION_UNSTICK:
- *rect = fgeom->unstick_rect.visible;
- break;
+ case META_BUTTON_TYPE_UNABOVE:
+ return META_BUTTON_FUNCTION_UNABOVE;
- case META_BUTTON_FUNCTION_MAXIMIZE:
- *rect = fgeom->max_rect.visible;
- break;
+ case META_BUTTON_TYPE_STICK:
+ return META_BUTTON_FUNCTION_STICK;
- case META_BUTTON_FUNCTION_MINIMIZE:
- *rect = fgeom->min_rect.visible;
- break;
+ case META_BUTTON_TYPE_UNSTICK:
+ return META_BUTTON_FUNCTION_UNSTICK;
- case META_BUTTON_FUNCTION_MENU:
- *rect = fgeom->menu_rect.visible;
- break;
+ case META_BUTTON_TYPE_MENU:
+ return META_BUTTON_FUNCTION_MENU;
- case META_BUTTON_FUNCTION_APPMENU:
- *rect = fgeom->appmenu_rect.visible;
- break;
+ case META_BUTTON_TYPE_APPMENU:
+ return META_BUTTON_FUNCTION_APPMENU;
- case META_BUTTON_FUNCTION_LAST:
- default:
- g_assert_not_reached ();
- break;
- }
-}
+ case META_BUTTON_TYPE_MINIMIZE:
+ return META_BUTTON_FUNCTION_MINIMIZE;
-static MetaButtonState
-map_button_state (MetaButtonFunction button_function,
- const MetaFrameGeometry *fgeom,
- gint middle_bg_offset,
- const MetaButtonLayout *button_layout)
-{
- MetaButtonType type = META_BUTTON_TYPE_LAST;
+ case META_BUTTON_TYPE_MAXIMIZE:
+ return META_BUTTON_FUNCTION_MAXIMIZE;
- switch (button_function)
- {
- /* First handle types, which map directly */
- case META_BUTTON_FUNCTION_SHADE:
- type = META_BUTTON_TYPE_SHADE;
- break;
- case META_BUTTON_FUNCTION_ABOVE:
- type = META_BUTTON_TYPE_ABOVE;
- break;
- case META_BUTTON_FUNCTION_STICK:
- type = META_BUTTON_TYPE_STICK;
- break;
- case META_BUTTON_FUNCTION_UNSHADE:
- type = META_BUTTON_TYPE_UNSHADE;
- break;
- case META_BUTTON_FUNCTION_UNABOVE:
- type = META_BUTTON_TYPE_UNABOVE;
- break;;
- case META_BUTTON_FUNCTION_UNSTICK:
- type = META_BUTTON_TYPE_UNSTICK;
- break;
- case META_BUTTON_FUNCTION_MENU:
- type = META_BUTTON_TYPE_MENU;
- break;
- case META_BUTTON_FUNCTION_APPMENU:
- type = META_BUTTON_TYPE_APPMENU;
- break;
- case META_BUTTON_FUNCTION_MINIMIZE:
- type = META_BUTTON_TYPE_MINIMIZE;
- break;
- case META_BUTTON_FUNCTION_MAXIMIZE:
- type = META_BUTTON_TYPE_MAXIMIZE;
- break;
- case META_BUTTON_FUNCTION_CLOSE:
- type = META_BUTTON_TYPE_CLOSE;
- break;
+ case META_BUTTON_TYPE_CLOSE:
+ return META_BUTTON_FUNCTION_CLOSE;
- /* Map position buttons to the corresponding type */
- case META_BUTTON_FUNCTION_RIGHT_LEFT_BACKGROUND:
- case META_BUTTON_FUNCTION_RIGHT_SINGLE_BACKGROUND:
- if (button_layout->n_right_buttons > 0)
- type = button_layout->right_buttons[0];
- break;
- case META_BUTTON_FUNCTION_RIGHT_RIGHT_BACKGROUND:
- if (button_layout->n_right_buttons > 0)
- type = button_layout->right_buttons[button_layout->n_right_buttons - 1];
- break;
- case META_BUTTON_FUNCTION_RIGHT_MIDDLE_BACKGROUND:
- if (middle_bg_offset + 1 < button_layout->n_right_buttons)
- type = button_layout->right_buttons[middle_bg_offset + 1];
- break;
- case META_BUTTON_FUNCTION_LEFT_LEFT_BACKGROUND:
- case META_BUTTON_FUNCTION_LEFT_SINGLE_BACKGROUND:
- if (button_layout->n_left_buttons > 0)
- type = button_layout->left_buttons[0];
- break;
- case META_BUTTON_FUNCTION_LEFT_RIGHT_BACKGROUND:
- if (button_layout->n_left_buttons > 0)
- type = button_layout->left_buttons[button_layout->n_left_buttons - 1];
- break;
- case META_BUTTON_FUNCTION_LEFT_MIDDLE_BACKGROUND:
- if (middle_bg_offset + 1 < button_layout->n_left_buttons)
- type = button_layout->left_buttons[middle_bg_offset + 1];
- break;
- case META_BUTTON_FUNCTION_LAST:
- break;
- default:
- break;
+ case META_BUTTON_TYPE_SPACER:
+ case META_BUTTON_TYPE_LAST:
+ default:
+ break;
+ }
}
- if (type != META_BUTTON_TYPE_LAST)
- return button_layout->button_states[type];
-
- return META_BUTTON_STATE_LAST;
+ return META_BUTTON_FUNCTION_LAST;
}
static void
@@ -5474,7 +5277,7 @@ meta_theme_metacity_draw_frame (MetaThemeImpl *impl,
GdkPixbuf *icon)
{
gdouble scale;
- int i, j;
+ gint i;
MetaRectangleDouble visible_rect;
MetaRectangleDouble titlebar_rect;
MetaRectangleDouble left_titlebar_edge;
@@ -5685,55 +5488,78 @@ meta_theme_metacity_draw_frame (MetaThemeImpl *impl,
/* Draw buttons just before overlay */
if ((i + 1) == META_FRAME_PIECE_OVERLAY)
{
- MetaDrawOpList *op_list;
- int middle_bg_offset;
+ gint side;
- middle_bg_offset = 0;
- j = 0;
- while (j < META_BUTTON_FUNCTION_LAST)
+ for (side = 0; side < 2; side++)
{
- GdkRectangle tmp_rect;
- MetaButtonState button_state;
+ MetaButton *buttons;
+ gint n_buttons;
+ gint j;
- get_button_rect (j, fgeom, middle_bg_offset, &tmp_rect);
-
- rect.x = tmp_rect.x / scale;
- rect.y = tmp_rect.y / scale;
- rect.width = tmp_rect.width / scale;
- rect.height = tmp_rect.height / scale;
-
- button_state = map_button_state (j, fgeom, middle_bg_offset,
- button_layout);
-
- op_list = meta_frame_style_get_button (style, j, button_state);
+ if (side == 0)
+ {
+ buttons = button_layout->left_buttons;
+ n_buttons = button_layout->n_left_buttons;
+ }
+ else if (side == 1)
+ {
+ buttons = button_layout->right_buttons;
+ n_buttons = button_layout->n_right_buttons;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
- if (op_list)
+ for (j = 0; j < n_buttons; j++)
{
- cairo_save (cr);
+ MetaButton *button;
+ gint op;
- cairo_rectangle (cr, rect.x, rect.y, rect.width, rect.height);
- cairo_clip (cr);
+ button = &buttons[j];
- if (gdk_cairo_get_clip_rectangle (cr, NULL))
+ rect.x = button->rect.visible.x / scale;
+ rect.y = button->rect.visible.y / scale;
+ rect.width = button->rect.visible.width / scale;
+ rect.height = button->rect.visible.height / scale;
+
+ if (!button->visible ||
+ button->type == META_BUTTON_TYPE_SPACER ||
+ rect.width <= 0 || rect.height <= 0)
{
- meta_draw_op_list_draw_with_style (op_list, context, cr,
- &draw_info, rect);
+ continue;
}
- cairo_restore (cr);
- }
+ for (op = 0; op < 2; op++)
+ {
+ MetaButtonFunction function;
+ MetaDrawOpList *op_list;
- /* MIDDLE_BACKGROUND type may get drawn more than once */
- if ((j == META_BUTTON_FUNCTION_RIGHT_MIDDLE_BACKGROUND ||
- j == META_BUTTON_FUNCTION_LEFT_MIDDLE_BACKGROUND) &&
- (middle_bg_offset < (MAX_MIDDLE_BACKGROUNDS - 1)))
- {
- ++middle_bg_offset;
- }
- else
- {
- middle_bg_offset = 0;
- ++j;
+ function = get_button_function (button->type, op == 0,
+ j, n_buttons, op);
+
+ op_list = meta_frame_style_get_button (style, function,
+ button->state);
+
+ if (op_list)
+ {
+ cairo_save (cr);
+
+ cairo_rectangle (cr, rect.x, rect.y,
+ rect.width, rect.height);
+ cairo_clip (cr);
+
+ if (gdk_cairo_get_clip_rectangle (cr, NULL))
+ {
+ meta_draw_op_list_draw_with_style (op_list,
+ context, cr,
+ &draw_info,
+ rect);
+ }
+
+ cairo_restore (cr);
+ }
+ }
}
}
}
diff --git a/libmetacity/meta-theme.c b/libmetacity/meta-theme.c
index efabb3f5..7084ef49 100644
--- a/libmetacity/meta-theme.c
+++ b/libmetacity/meta-theme.c
@@ -570,6 +570,63 @@ meta_theme_set_button_layout (MetaTheme *theme,
theme->button_layout = meta_button_layout_new (button_layout, invert);
}
+gboolean
+meta_theme_get_button (MetaTheme *theme,
+ gint x,
+ gint y,
+ MetaButton *button)
+{
+ gint side;
+
+ for (side = 0; side < 2; side++)
+ {
+ MetaButton *buttons;
+ gint n_buttons;
+ gint i;
+
+ if (side == 0)
+ {
+ buttons = theme->button_layout->left_buttons;
+ n_buttons = theme->button_layout->n_left_buttons;
+ }
+ else if (side == 1)
+ {
+ buttons = theme->button_layout->right_buttons;
+ n_buttons = theme->button_layout->n_right_buttons;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+
+ for (i = 0; i < n_buttons; i++)
+ {
+ MetaButton *btn;
+ GdkRectangle rect;
+
+ btn = &buttons[i];
+ rect = btn->rect.visible;
+
+ if (!btn->visible || btn->type == META_BUTTON_TYPE_SPACER ||
+ rect.width <= 0 || rect.height <= 0)
+ {
+ continue;
+ }
+
+ rect = btn->rect.clickable;
+
+ if (x >= rect.x && x < (rect.x + rect.width) &&
+ y >= rect.y && y < (rect.y + rect.height))
+ {
+ *button = *btn;
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
void
meta_theme_set_composited (MetaTheme *theme,
gboolean composited)
@@ -694,20 +751,50 @@ meta_theme_draw_frame (MetaTheme *theme,
title_height, flags, client_width, client_height,
theme->button_layout, type, &fgeom);
- for (i = 0; i < META_BUTTON_TYPE_LAST; i++)
+ for (i = 0; i < 2; i++)
{
- MetaButtonState state;
- GdkRectangle rect;
+ MetaButton *buttons;
+ gint n_buttons;
+ gint j;
- get_button_rect_for_type (i, &fgeom, &rect);
-
- state = META_BUTTON_STATE_NORMAL;
- if (func != NULL)
- state = (* func) (i, rect, user_data);
-
- g_assert (state >= META_BUTTON_STATE_NORMAL && state < META_BUTTON_STATE_LAST);
+ if (i == 0)
+ {
+ buttons = theme->button_layout->left_buttons;
+ n_buttons = theme->button_layout->n_left_buttons;
+ }
+ else if (i == 1)
+ {
+ buttons = theme->button_layout->right_buttons;
+ n_buttons = theme->button_layout->n_right_buttons;
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
- theme->button_layout->button_states[i] = state;
+ for (j = 0; j < n_buttons; j++)
+ {
+ MetaButton *button;
+ MetaButtonState state;
+ GdkRectangle rect;
+
+ button = &buttons[j];
+ state = META_BUTTON_STATE_NORMAL;
+ rect = button->rect.visible;
+
+ if (!button->visible || button->type == META_BUTTON_TYPE_SPACER ||
+ rect.width <= 0 || rect.height <= 0)
+ {
+ button->state = state;
+ continue;
+ }
+
+ if (func != NULL)
+ state = (* func) (button->type, button->rect.clickable, user_data);
+
+ g_assert (state >= META_BUTTON_STATE_NORMAL && state < META_BUTTON_STATE_LAST);
+ button->state = state;
+ }
}
impl_class->draw_frame (theme->impl, style, style_info, cr, &fgeom,
diff --git a/libmetacity/meta-theme.h b/libmetacity/meta-theme.h
index 4ee1d7c5..4174ffe6 100644
--- a/libmetacity/meta-theme.h
+++ b/libmetacity/meta-theme.h
@@ -20,13 +20,12 @@
#define META_THEME_H
#include <gtk/gtk.h>
-#include <libmetacity/meta-button-enums.h>
+#include <libmetacity/meta-button.h>
#include <libmetacity/meta-frame-borders.h>
#include <libmetacity/meta-frame-enums.h>
G_BEGIN_DECLS
-typedef struct _MetaButtonSpace MetaButtonSpace;
typedef struct _MetaFrameGeometry MetaFrameGeometry;
typedef MetaButtonState (* MetaButtonStateFunc) (MetaButtonType type,
@@ -82,20 +81,6 @@ typedef enum
} MetaThemeType;
/**
- * The computed size of a button (really just a way of tying its
- * visible and clickable areas together).
- * The reason for two different rectangles here is Fitts' law & maximized
- * windows; see bug #97703 for more details.
- */
-struct _MetaButtonSpace
-{
- /** The screen area where the button's image is drawn */
- GdkRectangle visible;
- /** The screen area where the button can be activated by clicking */
- GdkRectangle clickable;
-};
-
-/**
* Calculated actual geometry of the frame
*/
struct _MetaFrameGeometry
@@ -107,34 +92,6 @@ struct _MetaFrameGeometry
GdkRectangle title_rect;
- /* used for a memset hack */
-#define ADDRESS_OF_BUTTON_RECTS(fgeom) (((char*)(fgeom)) + G_STRUCT_OFFSET (MetaFrameGeometry, close_rect))
-#define LENGTH_OF_BUTTON_RECTS (G_STRUCT_OFFSET (MetaFrameGeometry, right_single_background) + sizeof (GdkRectangle) - G_STRUCT_OFFSET (MetaFrameGeometry, close_rect))
-
- /* The button rects (if changed adjust memset hack) */
- MetaButtonSpace close_rect;
- MetaButtonSpace max_rect;
- MetaButtonSpace min_rect;
- MetaButtonSpace menu_rect;
- MetaButtonSpace appmenu_rect;
- MetaButtonSpace shade_rect;
- MetaButtonSpace above_rect;
- MetaButtonSpace stick_rect;
- MetaButtonSpace unshade_rect;
- MetaButtonSpace unabove_rect;
- MetaButtonSpace unstick_rect;
-
-#define MAX_MIDDLE_BACKGROUNDS (META_BUTTON_TYPE_LAST - 2)
- GdkRectangle left_left_background;
- GdkRectangle left_middle_backgrounds[MAX_MIDDLE_BACKGROUNDS];
- GdkRectangle left_right_background;
- GdkRectangle left_single_background;
- GdkRectangle right_left_background;
- GdkRectangle right_middle_backgrounds[MAX_MIDDLE_BACKGROUNDS];
- GdkRectangle right_right_background;
- GdkRectangle right_single_background;
- /* End of button rects (if changed adjust memset hack) */
-
/* Round corners */
guint top_left_corner_rounded_radius;
guint top_right_corner_rounded_radius;
@@ -156,6 +113,11 @@ void meta_theme_set_button_layout (MetaTheme *theme,
const gchar *button_layout,
gboolean invert);
+gboolean meta_theme_get_button (MetaTheme *theme,
+ gint x,
+ gint y,
+ MetaButton *button);
+
void meta_theme_set_composited (MetaTheme *theme,
gboolean composited);
diff --git a/src/ui/frames.c b/src/ui/frames.c
index e639abbb..7c25b2cc 100644
--- a/src/ui/frames.c
+++ b/src/ui/frames.c
@@ -48,9 +48,6 @@ static void meta_frames_destroy (GtkWidget *widget);
static void meta_frames_finalize (GObject *object);
static void meta_frames_style_updated (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,
@@ -81,13 +78,6 @@ static MetaUIFrame* meta_frames_lookup_window (MetaFrames *frames,
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,
@@ -114,6 +104,277 @@ struct _MetaFrames
G_DEFINE_TYPE (MetaFrames, meta_frames, GTK_TYPE_WINDOW)
static void
+get_client_rect (MetaFrameGeometry *fgeom,
+ GdkRectangle *rect)
+{
+ rect->x = fgeom->borders.total.left;
+ rect->y = fgeom->borders.total.top;
+ rect->width = fgeom->width - fgeom->borders.total.right - rect->x;
+ rect->height = fgeom->height - fgeom->borders.total.bottom - rect->y;
+}
+
+#define RESIZE_EXTENDS 15
+#define TOP_RESIZE_HEIGHT 4
+static MetaFrameControl
+get_control (MetaFrames *frames,
+ MetaUIFrame *frame,
+ gint x,
+ gint y)
+{
+ MetaFrameGeometry fgeom;
+ MetaFrameFlags flags;
+ MetaFrameType type;
+ gboolean has_vert, has_horiz;
+ gboolean has_north_resize;
+ GdkRectangle client;
+ MetaFrameBorders borders;
+ MetaTheme *theme;
+ MetaButton button;
+
+ meta_frames_calc_geometry (frames, frame, &fgeom);
+ get_client_rect (&fgeom, &client);
+
+ borders = fgeom.borders;
+ theme = meta_ui_get_theme ();
+
+ if (x < borders.invisible.left - borders.resize.left ||
+ y < borders.invisible.top - borders.resize.top ||
+ x > fgeom.width - borders.invisible.right + borders.resize.right ||
+ y > fgeom.height - borders.invisible.bottom + borders.resize.bottom)
+ return META_FRAME_CONTROL_NONE;
+
+ if (POINT_IN_RECT (x, y, client))
+ return META_FRAME_CONTROL_CLIENT_AREA;
+
+ meta_core_get (frames->xdisplay, frame->xwindow,
+ META_CORE_GET_FRAME_FLAGS, &flags,
+ META_CORE_GET_FRAME_TYPE, &type,
+ META_CORE_GET_END);
+
+ if (meta_theme_get_button (theme, x, y, &button))
+ {
+ switch (button.type)
+ {
+ case META_BUTTON_TYPE_CLOSE:
+ return META_FRAME_CONTROL_DELETE;
+
+ case META_BUTTON_TYPE_MINIMIZE:
+ return META_FRAME_CONTROL_MINIMIZE;
+
+ case META_BUTTON_TYPE_MENU:
+ return META_FRAME_CONTROL_MENU;
+
+ case META_BUTTON_TYPE_APPMENU:
+ return META_FRAME_CONTROL_APPMENU;
+
+ case META_BUTTON_TYPE_MAXIMIZE:
+ if (flags & META_FRAME_MAXIMIZED)
+ return META_FRAME_CONTROL_UNMAXIMIZE;
+ else
+ return META_FRAME_CONTROL_MAXIMIZE;
+
+ case META_BUTTON_TYPE_SHADE:
+ return META_FRAME_CONTROL_SHADE;
+
+ case META_BUTTON_TYPE_UNSHADE:
+ return META_FRAME_CONTROL_UNSHADE;
+
+ case META_BUTTON_TYPE_ABOVE:
+ return META_FRAME_CONTROL_ABOVE;
+
+ case META_BUTTON_TYPE_UNABOVE:
+ return META_FRAME_CONTROL_UNABOVE;
+
+ case META_BUTTON_TYPE_STICK:
+ return META_FRAME_CONTROL_STICK;
+
+ case META_BUTTON_TYPE_UNSTICK:
+ return META_FRAME_CONTROL_UNSTICK;
+
+ case META_BUTTON_TYPE_SPACER:
+ case META_BUTTON_TYPE_LAST:
+ default:
+ break;
+ }
+ }
+
+ has_north_resize = (type != META_FRAME_TYPE_ATTACHED);
+ 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 <= (fgeom.borders.invisible.top + TOP_RESIZE_HEIGHT) && has_north_resize)
+ return META_FRAME_CONTROL_RESIZE_N;
+ else
+ return META_FRAME_CONTROL_TITLE;
+ }
+
+ /* South resize always has priority over north resize,
+ * in case of overlap.
+ */
+
+ if (y >= (fgeom.height - fgeom.borders.total.bottom - RESIZE_EXTENDS) &&
+ x >= (fgeom.width - fgeom.borders.total.right - 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.borders.total.bottom - RESIZE_EXTENDS) &&
+ x <= (fgeom.borders.total.left + 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.borders.invisible.top + RESIZE_EXTENDS) &&
+ x <= (fgeom.borders.total.left + RESIZE_EXTENDS) && has_north_resize)
+ {
+ 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.borders.invisible.top + RESIZE_EXTENDS) &&
+ x >= (fgeom.width - fgeom.borders.total.right - RESIZE_EXTENDS) && has_north_resize)
+ {
+ 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.borders.invisible.top + TOP_RESIZE_HEIGHT))
+ {
+ if (has_vert && has_north_resize)
+ return META_FRAME_CONTROL_RESIZE_N;
+ }
+ else if (y >= (fgeom.height - fgeom.borders.total.bottom - RESIZE_EXTENDS))
+ {
+ if (has_vert)
+ return META_FRAME_CONTROL_RESIZE_S;
+ }
+ else if (x <= fgeom.borders.total.left + RESIZE_EXTENDS)
+ {
+ if (has_horiz)
+ return META_FRAME_CONTROL_RESIZE_W;
+ }
+ else if (x >= (fgeom.width - fgeom.borders.total.right - RESIZE_EXTENDS))
+ {
+ if (has_horiz)
+ return META_FRAME_CONTROL_RESIZE_E;
+ }
+
+ if (y >= fgeom.borders.total.top)
+ return META_FRAME_CONTROL_NONE;
+ else
+ return META_FRAME_CONTROL_TITLE;
+}
+
+static gboolean
+get_control_rect (MetaFrameControl control,
+ MetaFrameGeometry *fgeom,
+ gint x,
+ gint y,
+ GdkRectangle *rect)
+{
+ MetaButtonType type;
+ MetaTheme *theme;
+ MetaButton button;
+
+ type = META_BUTTON_TYPE_LAST;
+
+ switch (control)
+ {
+ case META_FRAME_CONTROL_TITLE:
+ *rect = fgeom->title_rect;
+ return TRUE;
+
+ case META_FRAME_CONTROL_DELETE:
+ type = META_BUTTON_TYPE_CLOSE;
+ break;
+
+ case META_FRAME_CONTROL_MENU:
+ type = META_BUTTON_TYPE_MENU;
+ break;
+
+ case META_FRAME_CONTROL_APPMENU:
+ type = META_BUTTON_TYPE_APPMENU;
+ break;
+
+ case META_FRAME_CONTROL_MINIMIZE:
+ type = META_BUTTON_TYPE_MINIMIZE;
+ break;
+
+ case META_FRAME_CONTROL_MAXIMIZE:
+ case META_FRAME_CONTROL_UNMAXIMIZE:
+ type = META_BUTTON_TYPE_MAXIMIZE;
+ break;
+
+ case META_FRAME_CONTROL_SHADE:
+ type = META_BUTTON_TYPE_SHADE;
+ break;
+
+ case META_FRAME_CONTROL_UNSHADE:
+ type = META_BUTTON_TYPE_UNSHADE;
+ break;
+
+ case META_FRAME_CONTROL_ABOVE:
+ type = META_BUTTON_TYPE_ABOVE;
+ break;
+
+ case META_FRAME_CONTROL_UNABOVE:
+ type = META_BUTTON_TYPE_UNABOVE;
+ break;
+
+ case META_FRAME_CONTROL_STICK:
+ type = META_BUTTON_TYPE_STICK;
+ break;
+
+ case META_FRAME_CONTROL_UNSTICK:
+ type = META_BUTTON_TYPE_UNSTICK;
+ break;
+
+ case META_FRAME_CONTROL_CLIENT_AREA:
+ case META_FRAME_CONTROL_RESIZE_SE:
+ case META_FRAME_CONTROL_RESIZE_S:
+ case META_FRAME_CONTROL_RESIZE_SW:
+ case META_FRAME_CONTROL_RESIZE_N:
+ case META_FRAME_CONTROL_RESIZE_NE:
+ case META_FRAME_CONTROL_RESIZE_NW:
+ case META_FRAME_CONTROL_RESIZE_W:
+ case META_FRAME_CONTROL_RESIZE_E:
+ case META_FRAME_CONTROL_NONE:
+ default:
+ break;
+ }
+
+ theme = meta_ui_get_theme ();
+
+ if (type != META_BUTTON_TYPE_LAST &&
+ meta_theme_get_button (theme, x, y, &button))
+ {
+ if (type == button.type)
+ {
+ *rect = button.rect.clickable;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static void
meta_frames_class_init (MetaFramesClass *frames_class)
{
GObjectClass *object_class;
@@ -514,6 +775,8 @@ meta_frames_manage_window (MetaFrames *frames,
frame->expose_delayed = FALSE;
frame->shape_applied = FALSE;
frame->prelit_control = META_FRAME_CONTROL_NONE;
+ frame->prelit_x = 0;
+ frame->prelit_y = 0;
meta_core_grab_buttons (frames->xdisplay, frame->xwindow);
@@ -642,21 +905,6 @@ apply_cairo_region_to_window (Display *display,
g_free (rects);
}
-/* The client rectangle surrounds client window; it subtracts both
- * the visible and invisible borders from the frame window's size.
- */
-static void
-get_client_rect (MetaFrameGeometry *fgeom,
- int window_width,
- int window_height,
- cairo_rectangle_int_t *rect)
-{
- rect->x = fgeom->borders.total.left;
- rect->y = fgeom->borders.total.top;
- rect->width = window_width - fgeom->borders.total.right - rect->x;
- rect->height = window_height - fgeom->borders.total.bottom - rect->y;
-}
-
/* The visible frame rectangle surrounds the visible portion of the
* frame window; it subtracts only the invisible borders from the frame
* window's size.
@@ -1120,12 +1368,13 @@ show_tip_now (MetaFrames *frames)
if (tiptext)
{
MetaFrameGeometry fgeom;
- GdkRectangle *rect;
+ GdkRectangle rect;
int dx, dy;
meta_frames_calc_geometry (frames, frame, &fgeom);
- rect = control_rect (control, &fgeom);
+ if (!get_control_rect (control, &fgeom, x, y, &rect))
+ return;
/* get conversion delta for root-to-frame coords */
dx = root_x - x;
@@ -1133,10 +1382,10 @@ show_tip_now (MetaFrames *frames)
/* Align the tooltip to the button right end if RTL */
if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
- dx += rect->width;
+ dx += rect.width;
- meta_fixed_tip_show (rect->x + dx,
- rect->y + rect->height + 2 + dy,
+ meta_fixed_tip_show (rect.x + dx,
+ rect.y + rect.height + 2 + dy,
tiptext);
}
}
@@ -1178,21 +1427,146 @@ clear_tip (MetaFrames *frames)
}
static void
-redraw_control (MetaFrames *frames,
- MetaUIFrame *frame,
- MetaFrameControl control)
+redraw_control (MetaFrames *frames,
+ MetaUIFrame *frame,
+ MetaFrameControl control,
+ gint x,
+ gint y)
{
MetaFrameGeometry fgeom;
- GdkRectangle *rect;
+ GdkRectangle rect;
meta_frames_calc_geometry (frames, frame, &fgeom);
- rect = control_rect (control, &fgeom);
+ if (!get_control_rect (control, &fgeom, x, y, &rect))
+ return;
- gdk_window_invalidate_rect (frame->window, rect, FALSE);
+ gdk_window_invalidate_rect (frame->window, &rect, FALSE);
invalidate_cache (frames, frame);
}
+static void
+update_prelit_control (MetaFrames *frames,
+ MetaUIFrame *frame,
+ MetaFrameControl control,
+ gint x,
+ gint y)
+{
+ MetaCursor cursor;
+ MetaFrameControl old_control;
+ gint old_x;
+ gint old_y;
+
+ meta_verbose ("Updating prelit control from %u to %u\n",
+ frame->prelit_control, control);
+
+ switch (control)
+ {
+ 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;
+
+ case META_FRAME_CONTROL_CLIENT_AREA:
+ case META_FRAME_CONTROL_NONE:
+ case META_FRAME_CONTROL_TITLE:
+ case META_FRAME_CONTROL_DELETE:
+ case META_FRAME_CONTROL_MENU:
+ case META_FRAME_CONTROL_APPMENU:
+ case META_FRAME_CONTROL_MINIMIZE:
+ case META_FRAME_CONTROL_MAXIMIZE:
+ case META_FRAME_CONTROL_UNMAXIMIZE:
+ 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:
+ default:
+ cursor = META_CURSOR_DEFAULT;
+ break;
+ }
+
+ /* set/unset the prelight cursor */
+ meta_core_set_screen_cursor (frames->xdisplay, frame->xwindow, cursor);
+
+ switch (control)
+ {
+ case META_FRAME_CONTROL_MENU:
+ case META_FRAME_CONTROL_APPMENU:
+ 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;
+
+ case META_FRAME_CONTROL_NONE:
+ case META_FRAME_CONTROL_TITLE:
+ case META_FRAME_CONTROL_RESIZE_SE:
+ case META_FRAME_CONTROL_RESIZE_S:
+ case META_FRAME_CONTROL_RESIZE_SW:
+ case META_FRAME_CONTROL_RESIZE_N:
+ case META_FRAME_CONTROL_RESIZE_NE:
+ case META_FRAME_CONTROL_RESIZE_NW:
+ case META_FRAME_CONTROL_RESIZE_W:
+ case META_FRAME_CONTROL_RESIZE_E:
+ case META_FRAME_CONTROL_CLIENT_AREA:
+ 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;
+ old_x = frame->prelit_x;
+ old_y = frame->prelit_y;
+
+ frame->prelit_control = control;
+ frame->prelit_x = x;
+ frame->prelit_y = y;
+
+ redraw_control (frames, frame, old_control, old_x, old_y);
+ redraw_control (frames, frame, control, x, y);
+}
+
static gboolean
meta_frame_titlebar_event (MetaFrames *frames,
MetaUIFrame *frame,
@@ -1428,17 +1802,24 @@ meta_frames_button_press_event (GtkWidget *widget,
event->y_root);
frame->prelit_control = control;
- redraw_control (frames, frame, control);
+ frame->prelit_x = event->x;
+ frame->prelit_y = event->y;
+
+ redraw_control (frames, frame, control, event->x, event->y);
if (op == META_GRAB_OP_CLICKING_MENU)
{
MetaFrameGeometry fgeom;
- GdkRectangle *rect;
+ GdkRectangle rect;
int dx, dy;
meta_frames_calc_geometry (frames, frame, &fgeom);
- rect = control_rect (META_FRAME_CONTROL_MENU, &fgeom);
+ if (!get_control_rect (META_FRAME_CONTROL_MENU, &fgeom,
+ event->x, event->y, &rect))
+ {
+ return FALSE;
+ }
/* get delta to convert to root coords */
dx = event->x_root - event->x;
@@ -1446,12 +1827,12 @@ meta_frames_button_press_event (GtkWidget *widget,
/* Align to the right end of the menu rectangle if RTL */
if (meta_ui_get_direction() == META_UI_DIRECTION_RTL)
- dx += rect->width;
+ dx += rect.width;
meta_core_show_window_menu (frames->xdisplay,
frame->xwindow,
- rect->x + dx,
- rect->y + rect->height + dy,
+ rect.x + dx,
+ rect.y + rect.height + dy,
event->button,
event->time);
}
@@ -1552,7 +1933,9 @@ meta_frames_notify_menu_hide (MetaFrames *frames)
if (frame)
{
- redraw_control (frames, frame, META_FRAME_CONTROL_MENU);
+ redraw_control (frames, frame, META_FRAME_CONTROL_MENU,
+ frame->prelit_x, frame->prelit_y);
+
meta_core_end_grab_op (frames->xdisplay, CurrentTime);
}
}
@@ -1709,137 +2092,12 @@ meta_frames_button_release_event (GtkWidget *widget,
* prelit so to let the user know that it can now be pressed.
* :)
*/
- meta_frames_update_prelit_control (frames, frame, control);
+ update_prelit_control (frames, frame, control, event->x, event->y);
}
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_APPMENU:
- 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;
- default:
- break;
- }
-
- /* set/unset the prelight cursor */
- meta_core_set_screen_cursor (frames->xdisplay, frame->xwindow, cursor);
-
- switch (control)
- {
- case META_FRAME_CONTROL_MENU:
- case META_FRAME_CONTROL_APPMENU:
- 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;
- case META_FRAME_CONTROL_NONE:
- case META_FRAME_CONTROL_TITLE:
- case META_FRAME_CONTROL_RESIZE_SE:
- case META_FRAME_CONTROL_RESIZE_S:
- case META_FRAME_CONTROL_RESIZE_SW:
- case META_FRAME_CONTROL_RESIZE_N:
- case META_FRAME_CONTROL_RESIZE_NE:
- case META_FRAME_CONTROL_RESIZE_NW:
- case META_FRAME_CONTROL_RESIZE_W:
- case META_FRAME_CONTROL_RESIZE_E:
- case META_FRAME_CONTROL_CLIENT_AREA:
- /* Only prelight buttons */
- control = META_FRAME_CONTROL_NONE;
- 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)
@@ -1912,7 +2170,7 @@ meta_frames_motion_notify_event (GtkWidget *widget,
control = META_FRAME_CONTROL_NONE;
/* Update prelit control and cursor */
- meta_frames_update_prelit_control (frames, frame, control);
+ update_prelit_control (frames, frame, control, x, y);
/* No tooltip while in the process of clicking */
}
@@ -1928,7 +2186,7 @@ meta_frames_motion_notify_event (GtkWidget *widget,
control = get_control (frames, frame, x, y);
/* Update prelit control and cursor */
- meta_frames_update_prelit_control (frames, frame, control);
+ update_prelit_control (frames, frame, control, x, y);
queue_tip (frames);
}
@@ -2284,6 +2542,11 @@ update_button_state (MetaButtonType type,
Window grab_frame;
MetaGrabOp grab_op;
MetaFrameControl control;
+ GdkDisplay *display;
+ GdkSeat *seat;
+ GdkDevice *device;
+ gint x;
+ gint y;
data = (ButtonStateData *) user_data;
@@ -2296,6 +2559,15 @@ update_button_state (MetaButtonType type,
control = data->frame->prelit_control;
+ display = gdk_display_get_default ();
+ seat = gdk_display_get_default_seat (display);
+ device = gdk_seat_get_pointer (seat);
+
+ gdk_window_get_device_position (data->frame->window, device, &x, &y, NULL);
+
+ if (!POINT_IN_RECT (x, y, rect))
+ return state;
+
/* Set prelight state */
if (control == META_FRAME_CONTROL_MENU &&
type == META_BUTTON_TYPE_MENU)
@@ -2441,7 +2713,7 @@ meta_frames_enter_notify_event (GtkWidget *widget,
return FALSE;
control = get_control (frames, frame, event->x, event->y);
- meta_frames_update_prelit_control (frames, frame, control);
+ update_prelit_control (frames, frame, control, event->x, event->y);
return TRUE;
}
@@ -2459,253 +2731,14 @@ meta_frames_leave_notify_event (GtkWidget *widget,
if (frame == NULL)
return FALSE;
- meta_frames_update_prelit_control (frames, frame, META_FRAME_CONTROL_NONE);
+ update_prelit_control (frames, frame, META_FRAME_CONTROL_NONE,
+ event->x, event->y);
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_APPMENU:
- rect = &fgeom->appmenu_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;
- default:
- break;
- }
-
- return rect;
-}
-
-#define RESIZE_EXTENDS 15
-#define TOP_RESIZE_HEIGHT 4
-static MetaFrameControl
-get_control (MetaFrames *frames,
- MetaUIFrame *frame,
- int x, int y)
-{
- MetaFrameGeometry fgeom;
- MetaFrameFlags flags;
- MetaFrameType type;
- gboolean has_vert, has_horiz;
- gboolean has_north_resize;
- GdkRectangle client;
- MetaFrameBorders borders;
-
- meta_frames_calc_geometry (frames, frame, &fgeom);
- get_client_rect (&fgeom, fgeom.width, fgeom.height, &client);
-
- borders = fgeom.borders;
-
- if (x < borders.invisible.left - borders.resize.left ||
- y < borders.invisible.top - borders.resize.top ||
- x > fgeom.width - borders.invisible.right + borders.resize.right ||
- y > fgeom.height - borders.invisible.bottom + borders.resize.bottom)
- return META_FRAME_CONTROL_NONE;
-
- 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;
-
- if (POINT_IN_RECT (x, y, fgeom.appmenu_rect.clickable))
- return META_FRAME_CONTROL_APPMENU;
-
- meta_core_get (frames->xdisplay, frame->xwindow,
- META_CORE_GET_FRAME_FLAGS, &flags,
- META_CORE_GET_FRAME_TYPE, &type,
- META_CORE_GET_END);
-
- has_north_resize = (type != META_FRAME_TYPE_ATTACHED);
- 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 <= (fgeom.borders.invisible.top + TOP_RESIZE_HEIGHT) && has_north_resize)
- 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.borders.total.bottom - RESIZE_EXTENDS) &&
- x >= (fgeom.width - fgeom.borders.total.right - 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.borders.total.bottom - RESIZE_EXTENDS) &&
- x <= (fgeom.borders.total.left + 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.borders.invisible.top + RESIZE_EXTENDS) &&
- x <= (fgeom.borders.total.left + RESIZE_EXTENDS) && has_north_resize)
- {
- 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.borders.invisible.top + RESIZE_EXTENDS) &&
- x >= (fgeom.width - fgeom.borders.total.right - RESIZE_EXTENDS) && has_north_resize)
- {
- 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.borders.invisible.top + TOP_RESIZE_HEIGHT))
- {
- if (has_vert && has_north_resize)
- return META_FRAME_CONTROL_RESIZE_N;
- }
- else if (y >= (fgeom.height - fgeom.borders.total.bottom - RESIZE_EXTENDS))
- {
- if (has_vert)
- return META_FRAME_CONTROL_RESIZE_S;
- }
- else if (x <= fgeom.borders.total.left + RESIZE_EXTENDS)
- {
- if (has_horiz)
- return META_FRAME_CONTROL_RESIZE_W;
- }
- else if (x >= (fgeom.width - fgeom.borders.total.right - RESIZE_EXTENDS))
- {
- if (has_horiz)
- return META_FRAME_CONTROL_RESIZE_E;
- }
-
- if (y >= fgeom.borders.total.top)
- return META_FRAME_CONTROL_NONE;
- else
- return META_FRAME_CONTROL_TITLE;
-}
-
void
meta_frames_push_delay_exposes (MetaFrames *frames)
{
diff --git a/src/ui/frames.h b/src/ui/frames.h
index 251e6421..5d30c9a7 100644
--- a/src/ui/frames.h
+++ b/src/ui/frames.h
@@ -74,6 +74,8 @@ struct _MetaUIFrame
/* FIXME get rid of this, it can just be in the MetaFrames struct */
MetaFrameControl prelit_control;
+ gint prelit_x;
+ gint prelit_y;
};
MetaFrames *meta_frames_new (void);