diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index 3e7cc8112..a79b01cc2 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -217,7 +217,7 @@ StTooltip StLabel {
transition-duration: 100;
}
-.panel-button:active, .panel-button:checked, .panel-button:pressed, .panel-button:focus {
+.panel-button:active, .panel-button:checked, .panel-button:focus {
background-gradient-direction: vertical;
background-gradient-start: #3c3c3c;
background-gradient-end: #131313;
@@ -541,11 +541,6 @@ StTooltip StLabel {
transition-duration: 100;
}
-.app-well-app:active > .overview-icon {
- background-color: #1e1e1e;
- border: 1px solid #5f5f5f;
-}
-
.app-well-menu {
font-size: 12px
}
diff --git a/js/ui/altTab.js b/js/ui/altTab.js
index 03b8fdca7..46c2a09bf 100644
--- a/js/ui/altTab.js
+++ b/js/ui/altTab.js
@@ -593,8 +593,8 @@ SwitcherList.prototype = {
},
addItem : function(item) {
- let bbox = new St.Clickable({ style_class: 'item-box',
- reactive: true });
+ let bbox = new St.Button({ style_class: 'item-box',
+ reactive: true });
bbox.set_child(item);
this._list.add_actor(bbox);
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index c5fe8c6a6..4628a5a7a 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -319,10 +319,11 @@ function AppWellIcon(app, iconParams) {
AppWellIcon.prototype = {
_init : function(app, iconParams) {
this.app = app;
- this.actor = new St.Clickable({ style_class: 'app-well-app',
- reactive: true,
- x_fill: true,
- y_fill: true });
+ this.actor = new St.Button({ style_class: 'app-well-app',
+ reactive: true,
+ button_mask: St.ButtonMask.ONE | St.ButtonMask.TWO,
+ x_fill: true,
+ y_fill: true });
this.actor._delegate = this;
this.icon = new AppIcon(app, iconParams);
@@ -390,12 +391,11 @@ AppWellIcon.prototype = {
return false;
},
- _onClicked: function(actor, event) {
+ _onClicked: function(actor, button) {
this._removeMenuTimeout();
- let button = event.get_button();
if (button == 1) {
- this._onActivate(event);
+ this._onActivate(Clutter.get_current_event());
} else if (button == 2) {
let newWorkspace = Main.overview.workspaces.addWorkspace();
if (newWorkspace != null) {
diff --git a/js/ui/dnd.js b/js/ui/dnd.js
index 71d8c04bc..7c88dc22a 100644
--- a/js/ui/dnd.js
+++ b/js/ui/dnd.js
@@ -112,11 +112,11 @@ _Draggable.prototype = {
return false;
this._buttonDown = true;
- // special case St.Clickable: grabbing the pointer would mess up the
+ // special case St.Button: grabbing the pointer would mess up the
// internal state, so we start the drag manually on hover change
- if (this.actor instanceof St.Clickable)
+ if (this.actor instanceof St.Button)
this.actor.connect('notify::hover',
- Lang.bind(this, this._onClickableHoverChanged));
+ Lang.bind(this, this._onButtonHoverChanged));
else
this._grabActor();
@@ -127,8 +127,8 @@ _Draggable.prototype = {
return false;
},
- _onClickableHoverChanged: function(button) {
- if (button.hover || !button.held)
+ _onButtonHoverChanged: function(button) {
+ if (button.hover || !button.pressed)
return;
button.fake_release();
diff --git a/js/ui/endSessionDialog.js b/js/ui/endSessionDialog.js
index c25633ac2..6b85bd87f 100644
--- a/js/ui/endSessionDialog.js
+++ b/js/ui/endSessionDialog.js
@@ -137,12 +137,12 @@ ListItem.prototype = {
let layout = new St.BoxLayout({ vertical: false});
- this.actor = new St.Clickable({ style_class: 'end-session-dialog-app-list-item',
- can_focus: true,
- child: layout,
- reactive: true,
- x_align: St.Align.START,
- x_fill: true });
+ this.actor = new St.Button({ style_class: 'end-session-dialog-app-list-item',
+ can_focus: true,
+ child: layout,
+ reactive: true,
+ x_align: St.Align.START,
+ x_fill: true });
this._icon = this._app.create_icon_texture(_ITEM_ICON_SIZE);
diff --git a/js/ui/panel.js b/js/ui/panel.js
index 9b7c3b36a..4d0e00145 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -612,10 +612,10 @@ Panel.prototype = {
/* Button on the left side of the panel. */
/* Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview". */
let label = new St.Label({ text: _("Activities") });
- this.button = new St.Clickable({ name: 'panelActivities',
- style_class: 'panel-button',
- reactive: true,
- can_focus: true });
+ this.button = new St.Button({ name: 'panelActivities',
+ style_class: 'panel-button',
+ reactive: true,
+ can_focus: true });
this.button.set_child(label);
this.button._delegate = this.button;
this.button._xdndTimeOut = 0;
@@ -712,7 +712,7 @@ Panel.prototype = {
// We get into the Overview mode on button-press-event as opposed to button-release-event because eventually we'll probably
// have the Overview act like a menu that allows the user to release the mouse on the activity the user wants
// to switch to.
- this.button.connect('clicked', Lang.bind(this, function(b, event) {
+ this.button.connect('clicked', Lang.bind(this, function(b) {
if (!Main.overview.animationInProgress) {
this._maybeToggleOverviewOnClick();
return true;
@@ -724,10 +724,10 @@ Panel.prototype = {
// pressing the System key, Alt+F1 or Esc. We want the button to be pressed in when the Overview is entered
// and to be released when it is exited regardless of how it was triggered.
Main.overview.connect('showing', Lang.bind(this, function() {
- this.button.active = true;
+ this.button.checked = true;
}));
Main.overview.connect('hiding', Lang.bind(this, function() {
- this.button.active = false;
+ this.button.checked = false;
}));
Main.chrome.addActor(this.actor, { visibleInOverview: true });
diff --git a/js/ui/searchDisplay.js b/js/ui/searchDisplay.js
index 3ed60ad5e..44794f6a9 100644
--- a/js/ui/searchDisplay.js
+++ b/js/ui/searchDisplay.js
@@ -24,10 +24,10 @@ SearchResult.prototype = {
_init: function(provider, metaInfo, terms) {
this.provider = provider;
this.metaInfo = metaInfo;
- this.actor = new St.Clickable({ style_class: 'search-result',
- reactive: true,
- x_align: St.Align.START,
- y_fill: true });
+ this.actor = new St.Button({ style_class: 'search-result',
+ reactive: true,
+ x_align: St.Align.START,
+ y_fill: true });
this.actor._delegate = this;
let content = provider.createResultActor(metaInfo, terms);
@@ -69,7 +69,7 @@ SearchResult.prototype = {
Main.overview.toggle();
},
- _onResultClicked: function(actor, event) {
+ _onResultClicked: function(actor) {
this.activate();
},
@@ -221,23 +221,23 @@ SearchResults.prototype = {
},
_createOpenSearchProviderButton: function(provider) {
- let clickable = new St.Clickable({ style_class: 'dash-search-button',
- reactive: true,
- x_fill: true,
- y_align: St.Align.MIDDLE });
+ let button = new St.Button({ style_class: 'dash-search-button',
+ reactive: true,
+ x_fill: true,
+ y_align: St.Align.MIDDLE });
let bin = new St.Bin({ x_fill: false,
x_align:St.Align.MIDDLE });
- clickable.connect('clicked', Lang.bind(this, function() {
+ button.connect('clicked', Lang.bind(this, function() {
this._openSearchSystem.activateResult(provider.id);
}));
let title = new St.Label({ text: provider.name,
style_class: 'dash-search-button-label' });
bin.set_child(title);
- clickable.set_child(bin);
- provider.actor = clickable;
+ button.set_child(bin);
+ provider.actor = button;
- this._searchProvidersBox.add(clickable);
+ this._searchProvidersBox.add(button);
},
createProviderMeta: function(provider) {
diff --git a/src/Makefile-st.am b/src/Makefile-st.am
index cb54ef4ba..ffeeb21b8 100644
--- a/src/Makefile-st.am
+++ b/src/Makefile-st.am
@@ -72,7 +72,6 @@ st_source_h = \
st/st-box-layout.h \
st/st-box-layout-child.h \
st/st-button.h \
- st/st-clickable.h \
st/st-clipboard.h \
st/st-container.h \
st/st-drawing-area.h \
@@ -130,7 +129,6 @@ st_source_c = \
st/st-box-layout.c \
st/st-box-layout-child.c \
st/st-button.c \
- st/st-clickable.c \
st/st-clipboard.c \
st/st-container.c \
st/st-drawing-area.c \
diff --git a/src/st/st-button.c b/src/st/st-button.c
index dfee0265e..c3eca6118 100644
--- a/src/st/st-button.c
+++ b/src/st/st-button.c
@@ -40,6 +40,7 @@
#include "st-button.h"
+#include "st-enum-types.h"
#include "st-marshal.h"
#include "st-texture-cache.h"
#include "st-private.h"
@@ -49,8 +50,10 @@ enum
PROP_0,
PROP_LABEL,
+ PROP_BUTTON_MASK,
PROP_TOGGLE_MODE,
- PROP_CHECKED
+ PROP_CHECKED,
+ PROP_PRESSED
};
enum
@@ -65,14 +68,16 @@ enum
struct _StButtonPrivate
{
- gchar *text;
+ gchar *text;
- guint is_pressed : 1;
- guint is_checked : 1;
- guint is_toggle : 1;
- guint has_grab : 1;
+ guint button_mask : 3;
+ guint is_toggle : 1;
- gint spacing;
+ guint pressed : 3;
+ guint grabbed : 3;
+ guint is_checked : 1;
+
+ gint spacing;
};
static guint button_signals[LAST_SIGNAL] = { 0, };
@@ -119,31 +124,32 @@ st_button_style_changed (StWidget *widget)
}
static void
-st_button_press (StButton *button)
+st_button_press (StButton *button,
+ StButtonMask mask)
{
- if (button->priv->is_pressed)
- return;
+ if (button->priv->pressed == 0)
+ st_widget_add_style_pseudo_class (ST_WIDGET (button), "active");
- button->priv->is_pressed = TRUE;
- st_widget_add_style_pseudo_class (ST_WIDGET (button), "active");
+ button->priv->pressed |= mask;
}
static void
-st_button_release (StButton *button,
- gboolean clicked)
+st_button_release (StButton *button,
+ StButtonMask mask,
+ int clicked_button)
{
- if (!button->priv->is_pressed)
+ button->priv->pressed &= ~mask;
+ if (button->priv->pressed != 0)
return;
- button->priv->is_pressed = FALSE;
st_widget_remove_style_pseudo_class (ST_WIDGET (button), "active");
- if (clicked)
+ if (clicked_button)
{
if (button->priv->is_toggle)
st_button_set_checked (button, !button->priv->is_checked);
- g_signal_emit (button, button_signals[CLICKED], 0);
+ g_signal_emit (button, button_signals[CLICKED], 0, clicked_button);
}
}
@@ -151,15 +157,18 @@ static gboolean
st_button_button_press (ClutterActor *actor,
ClutterButtonEvent *event)
{
+ StButton *button = ST_BUTTON (actor);
+ StButtonMask mask = ST_BUTTON_MASK_FROM_BUTTON (event->button);
+
st_widget_hide_tooltip (ST_WIDGET (actor));
- if (event->button == 1)
+ if (button->priv->button_mask & mask)
{
- StButton *button = ST_BUTTON (actor);
+ if (button->priv->grabbed == 0)
+ clutter_grab_pointer (actor);
- clutter_grab_pointer (actor);
- button->priv->has_grab = TRUE;
- st_button_press (button);
+ button->priv->grabbed |= mask;
+ st_button_press (button, mask);
return TRUE;
}
@@ -171,19 +180,19 @@ static gboolean
st_button_button_release (ClutterActor *actor,
ClutterButtonEvent *event)
{
- if (event->button == 1)
+ StButton *button = ST_BUTTON (actor);
+ StButtonMask mask = ST_BUTTON_MASK_FROM_BUTTON (event->button);
+
+ if (button->priv->button_mask & mask)
{
- StButton *button = ST_BUTTON (actor);
gboolean is_click;
- is_click = button->priv->has_grab && st_widget_get_hover (ST_WIDGET (button));
- st_button_release (button, is_click);
+ is_click = button->priv->grabbed && st_widget_get_hover (ST_WIDGET (button));
+ st_button_release (button, mask, is_click ? event->button : 0);
- if (button->priv->has_grab)
- {
- button->priv->has_grab = FALSE;
- clutter_ungrab_pointer ();
- }
+ button->priv->grabbed &= ~mask;
+ if (button->priv->grabbed == 0)
+ clutter_ungrab_pointer ();
return TRUE;
}
@@ -195,13 +204,18 @@ static gboolean
st_button_key_press (ClutterActor *actor,
ClutterKeyEvent *event)
{
+ StButton *button = ST_BUTTON (actor);
+
st_widget_hide_tooltip (ST_WIDGET (actor));
- if (event->keyval == CLUTTER_KEY_space ||
- event->keyval == CLUTTER_KEY_Return)
+ if (button->priv->button_mask & ST_BUTTON_ONE)
{
- st_button_press (ST_BUTTON (actor));
- return TRUE;
+ if (event->keyval == CLUTTER_KEY_space ||
+ event->keyval == CLUTTER_KEY_Return)
+ {
+ st_button_press (button, ST_BUTTON_ONE);
+ return TRUE;
+ }
}
return FALSE;
@@ -211,16 +225,34 @@ static gboolean
st_button_key_release (ClutterActor *actor,
ClutterKeyEvent *event)
{
- if (event->keyval == CLUTTER_KEY_space ||
- event->keyval == CLUTTER_KEY_Return)
+ StButton *button = ST_BUTTON (actor);
+
+ if (button->priv->button_mask & ST_BUTTON_ONE)
{
- st_button_release (ST_BUTTON (actor), TRUE);
- return TRUE;
+ if (event->keyval == CLUTTER_KEY_space ||
+ event->keyval == CLUTTER_KEY_Return)
+ {
+ st_button_release (button, ST_BUTTON_ONE, 1);
+ return TRUE;
+ }
}
return FALSE;
}
+static void
+st_button_key_focus_out (ClutterActor *actor)
+{
+ StButton *button = ST_BUTTON (actor);
+
+ /* If we lose focus between a key press and release, undo the press */
+ if ((button->priv->pressed & ST_BUTTON_ONE) &&
+ !(button->priv->grabbed & ST_BUTTON_ONE))
+ st_button_release (button, ST_BUTTON_ONE, 0);
+
+ CLUTTER_ACTOR_CLASS (st_button_parent_class)->key_focus_out (actor);
+}
+
static gboolean
st_button_enter (ClutterActor *actor,
ClutterCrossingEvent *event)
@@ -230,12 +262,12 @@ st_button_enter (ClutterActor *actor,
ret = CLUTTER_ACTOR_CLASS (st_button_parent_class)->enter_event (actor, event);
- if (button->priv->has_grab)
+ if (button->priv->grabbed)
{
if (st_widget_get_hover (ST_WIDGET (button)))
- st_button_press (button);
+ st_button_press (button, button->priv->grabbed);
else
- st_button_release (button, FALSE);
+ st_button_release (button, button->priv->grabbed, 0);
}
return ret;
@@ -250,12 +282,12 @@ st_button_leave (ClutterActor *actor,
ret = CLUTTER_ACTOR_CLASS (st_button_parent_class)->leave_event (actor, event);
- if (button->priv->has_grab)
+ if (button->priv->grabbed)
{
if (st_widget_get_hover (ST_WIDGET (button)))
- st_button_press (button);
+ st_button_press (button, button->priv->grabbed);
else
- st_button_release (button, FALSE);
+ st_button_release (button, button->priv->grabbed, 0);
}
return ret;
@@ -274,6 +306,9 @@ st_button_set_property (GObject *gobject,
case PROP_LABEL:
st_button_set_label (button, g_value_get_string (value));
break;
+ case PROP_BUTTON_MASK:
+ st_button_set_button_mask (button, g_value_get_flags (value));
+ break;
case PROP_TOGGLE_MODE:
st_button_set_toggle_mode (button, g_value_get_boolean (value));
break;
@@ -301,12 +336,18 @@ st_button_get_property (GObject *gobject,
case PROP_LABEL:
g_value_set_string (value, priv->text);
break;
+ case PROP_BUTTON_MASK:
+ g_value_set_flags (value, priv->button_mask);
+ break;
case PROP_TOGGLE_MODE:
g_value_set_boolean (value, priv->is_toggle);
break;
case PROP_CHECKED:
g_value_set_boolean (value, priv->is_checked);
break;
+ case PROP_PRESSED:
+ g_value_set_boolean (value, priv->pressed != 0);
+ break;
default:
@@ -343,6 +384,7 @@ st_button_class_init (StButtonClass *klass)
actor_class->button_release_event = st_button_button_release;
actor_class->key_press_event = st_button_key_press;
actor_class->key_release_event = st_button_key_release;
+ actor_class->key_focus_out = st_button_key_focus_out;
actor_class->enter_event = st_button_enter;
actor_class->leave_event = st_button_leave;
@@ -354,6 +396,13 @@ st_button_class_init (StButtonClass *klass)
NULL, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_LABEL, pspec);
+ pspec = g_param_spec_flags ("button-mask",
+ "Button mask",
+ "Which buttons trigger the 'clicked' signal",
+ ST_TYPE_BUTTON_MASK, ST_BUTTON_ONE,
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_BUTTON_MASK, pspec);
+
pspec = g_param_spec_boolean ("toggle-mode",
"Toggle Mode",
"Enable or disable toggling",
@@ -367,23 +416,30 @@ st_button_class_init (StButtonClass *klass)
FALSE, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_CHECKED, pspec);
+ pspec = g_param_spec_boolean ("pressed",
+ "Pressed",
+ "Indicates if the button is pressed in",
+ FALSE, G_PARAM_READABLE);
+ g_object_class_install_property (gobject_class, PROP_PRESSED, pspec);
+
/**
* StButton::clicked:
* @button: the object that received the signal
+ * @clicked_button: the mouse button that was used
*
* Emitted when the user activates the button, either with a mouse press and
* release or with the keyboard.
*/
-
button_signals[CLICKED] =
g_signal_new ("clicked",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (StButtonClass, clicked),
NULL, NULL,
- _st_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
+ _st_marshal_VOID__INT,
+ G_TYPE_NONE, 1,
+ G_TYPE_INT);
}
static void
@@ -391,6 +447,7 @@ st_button_init (StButton *button)
{
button->priv = ST_BUTTON_GET_PRIVATE (button);
button->priv->spacing = 6;
+ button->priv->button_mask = ST_BUTTON_ONE;
clutter_actor_set_reactive (CLUTTER_ACTOR (button), TRUE);
st_widget_set_track_hover (ST_WIDGET (button), TRUE);
@@ -431,7 +488,7 @@ st_button_new_with_label (const gchar *text)
*
* Returns: the text for the button. This must not be freed by the application
*/
-G_CONST_RETURN gchar *
+const gchar *
st_button_get_label (StButton *button)
{
g_return_val_if_fail (ST_IS_BUTTON (button), NULL);
@@ -487,6 +544,42 @@ st_button_set_label (StButton *button,
g_object_notify (G_OBJECT (button), "label");
}
+/**
+ * st_button_get_button_mask:
+ * @button: a #StButton
+ *
+ * Gets the mask of mouse buttons that @button emits the
+ * #StButton::clicked signal for.
+ *
+ * Returns: the mask of mouse buttons that @button emits the
+ * #StButton::clicked signal for.
+ */
+StButtonMask
+st_button_get_button_mask (StButton *button)
+{
+ g_return_val_if_fail (ST_IS_BUTTON (button), 0);
+
+ return button->priv->button_mask;
+}
+
+/**
+ * st_button_set_button_mask:
+ * @button: a #Stbutton
+ * @mask: the mask of mouse buttons that @button responds to
+ *
+ * Sets which mouse buttons @button emits #StButton::clicked for.
+ */
+void
+st_button_set_button_mask (StButton *button,
+ StButtonMask mask)
+{
+ g_return_if_fail (ST_IS_BUTTON (button));
+
+ button->priv->button_mask = mask;
+
+ g_object_notify (G_OBJECT (button), "button-mask");
+}
+
/**
* st_button_get_toggle_mode:
* @button: a #StButton
@@ -564,3 +657,29 @@ st_button_set_checked (StButton *button,
g_object_notify (G_OBJECT (button), "checked");
}
+
+/**
+ * st_button_fake_release:
+ * @button: an #StButton
+ *
+ * If this widget is holding a pointer grab, this function will
+ * will ungrab it, and reset the pressed state. The effect is
+ * similar to if the user had released the mouse button, but without
+ * emitting the clicked signal.
+ *
+ * This function is useful if for example you want to do something
+ * after the user is holding the mouse button for a given period of
+ * time, breaking the grab.
+ */
+void
+st_button_fake_release (StButton *button)
+{
+ if (button->priv->pressed)
+ st_button_release (button, button->priv->pressed, 0);
+
+ if (button->priv->grabbed)
+ {
+ button->priv->grabbed = 0;
+ clutter_ungrab_pointer ();
+ }
+}
diff --git a/src/st/st-button.h b/src/st/st-button.h
index 15a6983dd..23ae81bd1 100644
--- a/src/st/st-button.h
+++ b/src/st/st-button.h
@@ -68,17 +68,39 @@ struct _StButtonClass
GType st_button_get_type (void) G_GNUC_CONST;
-StWidget * st_button_new (void);
-StWidget * st_button_new_with_label (const gchar *text);
-G_CONST_RETURN gchar *st_button_get_label (StButton *button);
-void st_button_set_label (StButton *button,
- const gchar *text);
-void st_button_set_toggle_mode (StButton *button,
- gboolean toggle);
-gboolean st_button_get_toggle_mode (StButton *button);
-void st_button_set_checked (StButton *button,
- gboolean checked);
-gboolean st_button_get_checked (StButton *button);
+StWidget *st_button_new (void);
+StWidget *st_button_new_with_label (const gchar *text);
+const gchar *st_button_get_label (StButton *button);
+void st_button_set_label (StButton *button,
+ const gchar *text);
+void st_button_set_toggle_mode (StButton *button,
+ gboolean toggle);
+gboolean st_button_get_toggle_mode (StButton *button);
+void st_button_set_checked (StButton *button,
+ gboolean checked);
+gboolean st_button_get_checked (StButton *button);
+
+void st_button_fake_release (StButton *button);
+
+/**
+ * StButtonMask:
+ * @ST_BUTTON_ONE: button 1 (left)
+ * @ST_BUTTON_TWO: button 2 (middle)
+ * @ST_BUTTON_THREE: button 3 (right)
+ *
+ * A mask representing which mouse buttons an StButton responds to.
+ */
+typedef enum {
+ ST_BUTTON_ONE = (1 << 0),
+ ST_BUTTON_TWO = (1 << 1),
+ ST_BUTTON_THREE = (1 << 2),
+} StButtonMask;
+
+#define ST_BUTTON_MASK_FROM_BUTTON(button) (1 << ((button) - 1))
+
+void st_button_set_button_mask (StButton *button,
+ StButtonMask mask);
+StButtonMask st_button_get_button_mask (StButton *button);
G_END_DECLS
diff --git a/src/st/st-clickable.c b/src/st/st-clickable.c
deleted file mode 100644
index 5787aaf42..000000000
--- a/src/st/st-clickable.c
+++ /dev/null
@@ -1,363 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/*
- * st-clickable.h: A bin with methods and properties useful for implementing buttons
- *
- * Copyright 2009, 2010 Red Hat, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
- * more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-/**
- * SECTION:st-clickable
- * @short_description: A bin with methods and properties useful for implementing buttons
- *
- * A #StBin subclass which translates lower-level Clutter button events
- * into higher level properties which are useful for implementing "button-like"
- * actors.
- */
-
-#include "st-clickable.h"
-
-#include "st-private.h"
-
-G_DEFINE_TYPE (StClickable, st_clickable, ST_TYPE_BIN);
-
-struct _StClickablePrivate {
- gboolean active;
- gboolean held;
- gboolean pressed;
-
- guint initiating_button;
-};
-
-/* Signals */
-enum
-{
- CLICKED,
- LAST_SIGNAL
-};
-
-enum {
- PROP_0,
-
- PROP_ACTIVE,
- PROP_HELD,
- PROP_PRESSED
-};
-
-static guint st_clickable_signals [LAST_SIGNAL] = { 0 };
-
-static void
-sync_pseudo_class (StClickable *self)
-{
- if (self->priv->pressed || self->priv->active)
- st_widget_add_style_pseudo_class (ST_WIDGET (self), "pressed");
- else
- st_widget_remove_style_pseudo_class (ST_WIDGET (self), "pressed");
-}
-
-static void
-set_active (StClickable *self,
- gboolean active)
-{
- if (self->priv->active == active)
- return;
- self->priv->active = active;
- sync_pseudo_class (self);
- g_object_notify (G_OBJECT (self), "active");
-}
-
-static void
-set_pressed (StClickable *self,
- gboolean pressed)
-{
- if (self->priv->pressed == pressed)
- return;
- self->priv->pressed = pressed;
- sync_pseudo_class (self);
- g_object_notify (G_OBJECT (self), "pressed");
-}
-
-static gboolean
-st_clickable_enter_event (ClutterActor *actor,
- ClutterCrossingEvent *event)
-{
- StClickable *self = ST_CLICKABLE (actor);
- gboolean result;
-
- g_object_freeze_notify (G_OBJECT (actor));
-
- result = CLUTTER_ACTOR_CLASS (st_clickable_parent_class)->enter_event (actor, event);
-
- /* We can't just assume get_hover() is TRUE; see st_widget_enter(). */
- set_pressed (self, self->priv->held && st_widget_get_hover (ST_WIDGET (actor)));
-
- g_object_thaw_notify (G_OBJECT (actor));
-
- return result;
-}
-
-static gboolean
-st_clickable_leave_event (ClutterActor *actor,
- ClutterCrossingEvent *event)
-{
- StClickable *self = ST_CLICKABLE (actor);
- gboolean result;
-
- g_object_freeze_notify (G_OBJECT (actor));
-
- result = CLUTTER_ACTOR_CLASS (st_clickable_parent_class)->leave_event (actor, event);
-
- /* As above, we can't just assume get_hover() is FALSE. */
- set_pressed (self, self->priv->held && st_widget_get_hover (ST_WIDGET (actor)));
-
- g_object_thaw_notify (G_OBJECT (actor));
-
- return result;
-}
-
-static gboolean
-st_clickable_button_press_event (ClutterActor *actor,
- ClutterButtonEvent *event)
-{
- StClickable *self = ST_CLICKABLE (actor);
-
- if (event->click_count != 1)
- return FALSE;
-
- if (self->priv->held)
- return TRUE;
-
- if (!clutter_actor_contains (actor, event->source))
- return FALSE;
-
- self->priv->held = TRUE;
- self->priv->initiating_button = event->button;
- clutter_grab_pointer (CLUTTER_ACTOR (self));
-
- set_pressed (self, TRUE);
-
- return TRUE;
-}
-
-static gboolean
-st_clickable_button_release_event (ClutterActor *actor,
- ClutterButtonEvent *event)
-{
- StClickable *self = ST_CLICKABLE (actor);
-
- if (event->button != self->priv->initiating_button || event->click_count != 1)
- return FALSE;
-
- if (!self->priv->held)
- return TRUE;
-
- self->priv->held = FALSE;
- clutter_ungrab_pointer ();
-
- if (!clutter_actor_contains (actor, event->source))
- return FALSE;
-
- set_pressed (self, FALSE);
-
- g_signal_emit (G_OBJECT (self), st_clickable_signals[CLICKED], 0, event);
-
- return TRUE;
-}
-
-static gboolean
-st_clickable_key_press_event (ClutterActor *actor,
- ClutterKeyEvent *event)
-{
- StClickable *self = ST_CLICKABLE (actor);
-
- if (event->keyval == CLUTTER_KEY_space ||
- event->keyval == CLUTTER_KEY_Return)
- {
- set_pressed (self, TRUE);
- return TRUE;
- }
- return FALSE;
-}
-
-static gboolean
-st_clickable_key_release_event (ClutterActor *actor,
- ClutterKeyEvent *event)
-{
- StClickable *self = ST_CLICKABLE (actor);
-
- if (event->keyval != CLUTTER_KEY_space &&
- event->keyval != CLUTTER_KEY_Return)
- return FALSE;
-
- set_pressed (self, FALSE);
-
- g_signal_emit (G_OBJECT (self), st_clickable_signals[CLICKED], 0, event);
- return TRUE;
-}
-
-/**
- * st_clickable_fake_release:
- * @box:
- *
- * If this widget is holding a pointer grab, this function will
- * will ungrab it, and reset the pressed state. The effect is
- * similar to if the user had released the mouse button, but without
- * emitting the clicked signal.
- *
- * This function is useful if for example you want to do something after the user
- * is holding the mouse button for a given period of time, breaking the
- * grab.
- */
-void
-st_clickable_fake_release (StClickable *self)
-{
- if (!self->priv->held)
- return;
-
- self->priv->held = FALSE;
- clutter_ungrab_pointer ();
-
- set_pressed (self, FALSE);
-}
-
-static void
-st_clickable_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- StClickable *self = ST_CLICKABLE (object);
-
- switch (prop_id)
- {
- case PROP_ACTIVE:
- set_active (self, g_value_get_boolean (value));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-st_clickable_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- StClickable *self = ST_CLICKABLE (object);
-
- switch (prop_id)
- {
- case PROP_ACTIVE:
- g_value_set_boolean (value, self->priv->active);
- break;
- case PROP_HELD:
- g_value_set_boolean (value, self->priv->held);
- break;
- case PROP_PRESSED:
- g_value_set_boolean (value, self->priv->pressed);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-st_clickable_class_init (StClickableClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
-
- gobject_class->get_property = st_clickable_get_property;
- gobject_class->set_property = st_clickable_set_property;
-
- actor_class->enter_event = st_clickable_enter_event;
- actor_class->leave_event = st_clickable_leave_event;
- actor_class->button_press_event = st_clickable_button_press_event;
- actor_class->button_release_event = st_clickable_button_release_event;
- actor_class->key_press_event = st_clickable_key_press_event;
- actor_class->key_release_event = st_clickable_key_release_event;
-
- /**
- * StClickable::clicked
- * @box: The #StClickable
- *
- * This signal is emitted when the button should take the action
- * associated with button click+release.
- */
- st_clickable_signals[CLICKED] =
- g_signal_new ("clicked",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- 0,
- NULL, NULL,
- g_cclosure_marshal_VOID__BOXED,
- G_TYPE_NONE, 1, CLUTTER_TYPE_EVENT);
-
- /**
- * StClickable:active
- *
- * The property allows the button to be used as a "toggle button"; it's up to the
- * application to update the active property in response to the activate signal;
- * it doesn't happen automatically.
- */
- g_object_class_install_property (gobject_class,
- PROP_ACTIVE,
- g_param_spec_boolean ("active",
- "Active",
- "Whether the button persistently active",
- FALSE,
- G_PARAM_READWRITE));
-
- /**
- * StClickable:held
- *
- * This property tracks whether the button has the pointer grabbed,
- * whether or not the pointer is currently hovering over the button.
- */
- g_object_class_install_property (gobject_class,
- PROP_HELD,
- g_param_spec_boolean ("held",
- "Held state",
- "Whether the mouse button is currently pressed",
- FALSE,
- G_PARAM_READABLE));
-
- /**
- * StClickable:pressed
- *
- * This property tracks whether the button should have a "pressed in"
- * effect.
- */
- g_object_class_install_property (gobject_class,
- PROP_PRESSED,
- g_param_spec_boolean ("pressed",
- "Pressed state",
- "Whether the button is currently pressed",
- FALSE,
- G_PARAM_READABLE));
-
- g_type_class_add_private (gobject_class, sizeof (StClickablePrivate));
-}
-
-static void
-st_clickable_init (StClickable *self)
-{
- self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, ST_TYPE_CLICKABLE,
- StClickablePrivate);
- st_widget_set_track_hover (ST_WIDGET (self), TRUE);
-}
diff --git a/src/st/st-clickable.h b/src/st/st-clickable.h
deleted file mode 100644
index 2f1c3b0ee..000000000
--- a/src/st/st-clickable.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
-/*
- * st-clickable.h: A bin with methods and properties useful for implementing buttons
- *
- * Copyright 2009, 2010 Red Hat, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
- * more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see .
- */
-
-#ifndef __ST_CLICKABLE_H__
-#define __ST_CLICKABLE_H__
-
-#include "st-bin.h"
-
-#define ST_TYPE_CLICKABLE (st_clickable_get_type ())
-#define ST_CLICKABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_CLICKABLE, StClickable))
-#define ST_CLICKABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_CLICKABLE, StClickableClass))
-#define ST_IS_CLICKABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_CLICKABLE))
-#define ST_IS_CLICKABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_CLICKABLE))
-#define ST_CLICKABLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_CLICKABLE, StClickableClass))
-
-typedef struct _StClickable StClickable;
-typedef struct _StClickableClass StClickableClass;
-
-typedef struct _StClickablePrivate StClickablePrivate;
-
-struct _StClickable
-{
- StBin parent;
-
- StClickablePrivate *priv;
-};
-
-struct _StClickableClass
-{
- StBinClass parent_class;
-};
-
-GType st_clickable_get_type (void) G_GNUC_CONST;
-
-void st_clickable_fake_release (StClickable *box);
-
-#endif /* __ST_CLICKABLE_H__ */
diff --git a/src/st/st-marshal.list b/src/st/st-marshal.list
index 9b3bed671..69b75cc92 100644
--- a/src/st/st-marshal.list
+++ b/src/st/st-marshal.list
@@ -2,6 +2,7 @@ VOID:OBJECT
VOID:VOID
VOID:PARAM
VOID:POINTER
+VOID:INT
VOID:UINT
VOID:UINT,UINT
VOID:OBJECT,OBJECT