[epiphany] Fake middle clicks without gtk_button_{press, release}, which are deprecated



commit d5b4f4ba1d31e368e23ddd77774e285a13908622
Author: Xan Lopez <xan igalia com>
Date:   Sun Jan 1 00:09:35 2012 +0100

    Fake middle clicks without gtk_button_{press,release}, which are deprecated
    
    Factor the logic that fakes clicks from a middle click in
    EphyMiddleClick(Tool)Button by forwarding a left click to GTK+ when we
    receive a middle click. Since ephy_gui_is_middle_click stops working
    in this case, add the minimal logic in EphyLinkAction to make it work
    again (basically, cache the button that activated the action inside
    the action itself).
    
    The EphyMiddleClickable(Tool)Button classes were written by Alexandre
    Mazari.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=628364

 lib/widgets/Makefile.am                         |    4 +
 lib/widgets/ephy-middle-clickable-button.c      |   68 +++++++++++++++++++++++
 lib/widgets/ephy-middle-clickable-button.h      |   56 +++++++++++++++++++
 lib/widgets/ephy-middle-clickable-tool-button.c |   46 +++++++++++++++
 lib/widgets/ephy-middle-clickable-tool-button.h |   55 ++++++++++++++++++
 src/ephy-link-action.c                          |   63 +++++++++++----------
 src/ephy-link-action.h                          |    6 ++-
 src/ephy-navigation-action.c                    |    3 +-
 src/ephy-navigation-history-action.c            |   10 +++-
 9 files changed, 278 insertions(+), 33 deletions(-)
---
diff --git a/lib/widgets/Makefile.am b/lib/widgets/Makefile.am
index 941a954..57d5c73 100644
--- a/lib/widgets/Makefile.am
+++ b/lib/widgets/Makefile.am
@@ -5,6 +5,10 @@ libephywidgets_la_SOURCES = \
 	ephy-download-widget.h			\
 	ephy-location-entry.c			\
 	ephy-location-entry.h			\
+	ephy-middle-clickable-button.c		\
+	ephy-middle-clickable-button.h		\
+	ephy-middle-clickable-tool-button.c	\
+	ephy-middle-clickable-tool-button.h	\
 	ephy-node-view.c			\
 	ephy-node-view.h			\
 	ephy-search-entry.c			\
diff --git a/lib/widgets/ephy-middle-clickable-button.c b/lib/widgets/ephy-middle-clickable-button.c
new file mode 100644
index 0000000..1e6f53e
--- /dev/null
+++ b/lib/widgets/ephy-middle-clickable-button.c
@@ -0,0 +1,68 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright  2011 Alexandre Mazari
+ *  Copyright  2011 Igalia S.L.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "ephy-middle-clickable-button.h"
+
+G_DEFINE_TYPE (EphyMiddleClickableButton, ephy_middle_clickable_button, GTK_TYPE_BUTTON)
+
+static gboolean 
+ephy_middle_clickable_button_handle_event (GtkWidget * widget,
+                                           GdkEventButton * event)
+{
+  gboolean ret;
+  int actual_button;
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (ephy_middle_clickable_button_parent_class);
+
+  actual_button = event->button;
+
+  if (actual_button == 2)
+    event->button = 1;
+
+  if (event->type == GDK_BUTTON_PRESS)
+    ret = widget_class->button_press_event (widget, event);
+  else
+    ret = widget_class->button_release_event (widget, event);
+  
+  event->button = actual_button;
+
+  return ret;
+}
+
+static void
+ephy_middle_clickable_button_class_init (EphyMiddleClickableButtonClass *class)
+{
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
+  widget_class->button_press_event = ephy_middle_clickable_button_handle_event;
+  widget_class->button_release_event = ephy_middle_clickable_button_handle_event;
+}
+
+static void
+ephy_middle_clickable_button_init (EphyMiddleClickableButton *class)
+{
+}
+
+GtkWidget *
+ephy_middle_clickable_button_new ()
+{
+  return gtk_widget_new (EPHY_TYPE_MIDDLE_CLICKABLE_BUTTON, NULL);
+}
diff --git a/lib/widgets/ephy-middle-clickable-button.h b/lib/widgets/ephy-middle-clickable-button.h
new file mode 100644
index 0000000..e346a14
--- /dev/null
+++ b/lib/widgets/ephy-middle-clickable-button.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright  2011 Alexandre Mazari
+ *  Copyright  2011 Igalia S.L.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+ 
+#if !defined (__EPHY_EPIPHANY_H_INSIDE__) && !defined (EPIPHANY_COMPILATION)
+#error "Only <epiphany/epiphany.h> can be included directly."
+#endif
+
+#ifndef __EPHY_MIDDLE_CLICKABLE_BUTTON_H__
+#define __EPHY_MIDDLE_CLICKABLE_BUTTON_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_MIDDLE_CLICKABLE_BUTTON             (ephy_middle_clickable_button_get_type ())
+#define EPHY_MIDDLE_CLICKABLE_BUTTON(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj),EPHY_TYPE_MIDDLE_CLICKABLE_BUTTN, EphyMiddleClickableButton))
+#define EPHY_MIDDLE_CLICKABLE_BUTTON_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), EPHY_TYPE_MIDDLE_CLICKABLE_BUTTN, EphyMiddleClickableButtonClass))
+#define EPHY_IS_MIDDLE_CLICKABLE_BUTTON(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPHY_TYPE_MIDDLE_CLICKABLE_BUTON))
+#define EPHY_IS_MIDDLE_CLICKABLE_BUTTON_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), EPHY_TYPE_MIDDLE_CLICKABLE_BUTTN))
+#define EPHY_MIDDLE_CLICKABLE_BUTTON_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), EPHY_TYPE_MIDDLE_CLICKABLE_BUTTN, EphyMiddleClickableButtonClass))
+
+typedef struct _EphyMiddleClickableButton       EphyMiddleClickableButton;
+typedef struct _EphyMiddleClickableButtonClass  EphyMiddleClickableButtonClass;
+
+struct _EphyMiddleClickableButton {
+  GtkButton parent;
+};
+
+struct _EphyMiddleClickableButtonClass {
+  GtkButtonClass parent_class;
+};
+
+GType      ephy_middle_clickable_button_get_type (void) G_GNUC_CONST;
+GtkWidget *ephy_middle_clickable_button_new      (void);
+
+G_END_DECLS
+
+#endif
diff --git a/lib/widgets/ephy-middle-clickable-tool-button.c b/lib/widgets/ephy-middle-clickable-tool-button.c
new file mode 100644
index 0000000..6bcce5e
--- /dev/null
+++ b/lib/widgets/ephy-middle-clickable-tool-button.c
@@ -0,0 +1,46 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright  2011 Alexandre Mazari
+ *  Copyright  2011 Igalia S.L.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "ephy-middle-clickable-tool-button.h"
+
+#include "ephy-middle-clickable-button.h"
+
+G_DEFINE_TYPE (EphyMiddleClickableToolButton, ephy_middle_clickable_tool_button, GTK_TYPE_TOOL_BUTTON)
+
+static void
+ephy_middle_clickable_tool_button_class_init (EphyMiddleClickableToolButtonClass *class)
+{
+  GtkToolButtonClass *tool_button_class = GTK_TOOL_BUTTON_CLASS (class);
+
+  tool_button_class->button_type = EPHY_TYPE_MIDDLE_CLICKABLE_BUTTON;
+}
+
+static void
+ephy_middle_clickable_tool_button_init (EphyMiddleClickableToolButton *class)
+{
+}
+
+GtkWidget *
+ephy_middle_clickable_tool_button_new ()
+{
+  return gtk_widget_new (EPHY_TYPE_MIDDLE_CLICKABLE_TOOL_BUTTON, NULL);
+}
diff --git a/lib/widgets/ephy-middle-clickable-tool-button.h b/lib/widgets/ephy-middle-clickable-tool-button.h
new file mode 100644
index 0000000..a5863b9
--- /dev/null
+++ b/lib/widgets/ephy-middle-clickable-tool-button.h
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ *  Copyright  2011 Igalia S.L.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+ 
+#if !defined (__EPHY_EPIPHANY_H_INSIDE__) && !defined (EPIPHANY_COMPILATION)
+#error "Only <epiphany/epiphany.h> can be included directly."
+#endif
+
+#ifndef __EPHY_MIDDLE_CLICKABLE_TOOL_BUTTON_H__
+#define __EPHY_MIDDLE_CLICKABLE_TOOL_BUTTON_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define EPHY_TYPE_MIDDLE_CLICKABLE_TOOL_BUTTON             (ephy_middle_clickable_tool_button_get_type ())
+#define EPHY_MIDDLE_CLICKABLE_TOOL_BUTTON(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj),EPHY_TYPE_MIDDLE_CLICKABLE_TOOL_BUTTON, EphyMiddleClickableToolBtton))
+#define EPHY_MIDDLE_CLICKABLE_TOOL_BUTTON_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), EPHY_TYPE_MIDDLE_CLICKABLE_TOOL_BUTTON, EphyMiddleClickableToolBttonClass))
+#define EPHY_IS_MIDDLE_CLICKABLE_TOOL_BUTTON(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EPHY_TYPE_MIDDLE_CLICKABLE_TOOL_BUTTON))
+#define EPHY_IS_MIDDLE_CLICKABLE_TOOL_BUTTON_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), EPHY_TYPE_MIDDLE_CLICKABLE_TOOL_BUTTON))
+#define EPHY_MIDDLE_CLICKABLE_TOOL_BUTTON_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), EPHY_TYPE_MIDDLE_CLICKABLE_TOOL_BUTTON, EphyMiddleClickableToolBttonClass))
+
+typedef struct _EphyMiddleClickableToolButton       EphyMiddleClickableToolButton;
+typedef struct _EphyMiddleClickableToolButtonClass  EphyMiddleClickableToolButtonClass;
+
+struct _EphyMiddleClickableToolButton {
+  GtkToolButton parent;
+};
+
+struct _EphyMiddleClickableToolButtonClass {
+  GtkToolButtonClass parent_class;
+};
+
+GType      ephy_middle_clickable_tool_button_get_type (void) G_GNUC_CONST;
+GtkWidget *ephy_middle_clickable_tool_button_new      (void);
+
+G_END_DECLS
+
+#endif
diff --git a/src/ephy-link-action.c b/src/ephy-link-action.c
index 160b253..804aae7 100644
--- a/src/ephy-link-action.c
+++ b/src/ephy-link-action.c
@@ -32,33 +32,19 @@ G_DEFINE_TYPE_WITH_CODE (EphyLinkAction, ephy_link_action, GTK_TYPE_ACTION,
 			 G_IMPLEMENT_INTERFACE (EPHY_TYPE_LINK,
 						NULL))
 
+#define EPHY_LINK_ACTION_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), EPHY_TYPE_LINK_ACTION, EphyLinkActionPrivate))
+
+struct _EphyLinkActionPrivate
+{
+	guint button;
+};
+
 static gboolean
 proxy_button_press_event_cb (GtkButton *button,
 			     GdkEventButton *event,
 			     EphyLinkAction *action)
 {
-	if (event->button == 2)
-	{
-		gtk_button_pressed (button);
-	}
-
-	return FALSE;
-}
-
-static gboolean
-proxy_button_release_event_cb (GtkButton *button,
-			       GdkEventButton *event,
-			       EphyLinkAction *action)
-{
-	/*
-	 * We do not use ephy_gui_is_middle_click() here because
-	 * that also catches ctrl + left_click which already
-	 * triggers an activate event for all proxies.
-	 */
-	if (event->button == 2)
-	{
-		gtk_button_released (button);
-	}
+	action->priv->button = event->button;
 
 	return FALSE;
 }
@@ -109,9 +95,6 @@ ephy_link_action_connect_proxy (GtkAction *action, GtkWidget *proxy)
 		g_signal_connect (widget, "button-press-event",
 				  G_CALLBACK (proxy_button_press_event_cb),
 				  action);
-		g_signal_connect (widget, "button-release-event",
-				  G_CALLBACK (proxy_button_release_event_cb),
-				  action);
 	}
 
 	GTK_ACTION_CLASS (ephy_link_action_parent_class)->connect_proxy (action, proxy);
@@ -130,9 +113,6 @@ ephy_link_action_disconnect_proxy (GtkAction *action, GtkWidget *proxy)
 		g_signal_handlers_disconnect_by_func (widget,
 						      G_CALLBACK (proxy_button_press_event_cb),
 						      action);
-		g_signal_handlers_disconnect_by_func (widget,
-						      G_CALLBACK (proxy_button_release_event_cb),
-						      action);
 	}
 
 	GTK_ACTION_CLASS (ephy_link_action_parent_class)->disconnect_proxy (action, proxy);
@@ -141,7 +121,7 @@ ephy_link_action_disconnect_proxy (GtkAction *action, GtkWidget *proxy)
 static void
 ephy_link_action_init (EphyLinkAction *action)
 {
-	/* Empty, needed for G_DEFINE_TYPE macro */
+	action->priv = EPHY_LINK_ACTION_GET_PRIVATE (action);
 }
 
 static void
@@ -151,6 +131,31 @@ ephy_link_action_class_init (EphyLinkActionClass *class)
 
 	action_class->connect_proxy = ephy_link_action_connect_proxy;
 	action_class->disconnect_proxy = ephy_link_action_disconnect_proxy;
+
+	g_type_class_add_private (G_OBJECT_CLASS (class), sizeof (EphyLinkActionPrivate));
+}
+
+/**
+ * ephy_link_action_get_button:
+ * @action: an #EphyLinkAction
+ * 
+ * This method stores the mouse button number that last activated, or
+ * is activating, the @action. This is useful because #GtkButton's
+ * cannot be clicked with a middle click by default, so inside
+ * Epiphany we fake this by forwarding a left click (button 1) event
+ * instead of a middle click (button 2) to the button. That makes the
+ * EphyGUI methods like ephy_gui_is_middle_click not work here, so we
+ * need to ask the @action directly about the button that activated
+ * it.
+ * 
+ * Returns: the button number that last activated (or is activating) the @action
+ **/
+guint
+ephy_link_action_get_button (EphyLinkAction *action)
+{
+	g_return_val_if_fail (EPHY_IS_LINK_ACTION (action), 0);
+
+	return action->priv->button;
 }
 
 static void
diff --git a/src/ephy-link-action.h b/src/ephy-link-action.h
index 6dbf037..a6b4419 100644
--- a/src/ephy-link-action.h
+++ b/src/ephy-link-action.h
@@ -44,6 +44,7 @@ G_BEGIN_DECLS
 
 typedef struct _EphyLinkAction			EphyLinkAction;
 typedef struct _EphyLinkActionClass		EphyLinkActionClass;
+typedef struct _EphyLinkActionPrivate		EphyLinkActionPrivate;
 
 typedef struct _EphyLinkActionGroup		EphyLinkActionGroup;
 typedef struct _EphyLinkActionGroupClass	EphyLinkActionGroupClass;
@@ -51,6 +52,8 @@ typedef struct _EphyLinkActionGroupClass	EphyLinkActionGroupClass;
 struct _EphyLinkAction
 {
 	GtkAction parent_instance;
+
+	EphyLinkActionPrivate *priv;
 };
 
 struct _EphyLinkActionClass
@@ -68,7 +71,8 @@ struct _EphyLinkActionGroupClass
 	GtkActionGroupClass parent_class;
 };
 
-GType ephy_link_action_get_type	(void);
+GType ephy_link_action_get_type	  (void);
+guint ephy_link_action_get_button (EphyLinkAction *action);
 
 GType ephy_link_action_group_get_type (void);
 
diff --git a/src/ephy-navigation-action.c b/src/ephy-navigation-action.c
index ed54443..438e6cf 100644
--- a/src/ephy-navigation-action.c
+++ b/src/ephy-navigation-action.c
@@ -24,6 +24,7 @@
 #include "config.h"
 #include "ephy-navigation-action.h"
 
+#include "ephy-middle-clickable-tool-button.h"
 #include "ephy-window.h"
 
 #include <gtk/gtk.h>
@@ -93,7 +94,7 @@ ephy_navigation_action_class_init (EphyNavigationActionClass *class)
 	object_class->set_property = ephy_navigation_action_set_property;
 	object_class->get_property = ephy_navigation_action_get_property;
 
-	action_class->toolbar_item_type = GTK_TYPE_TOOL_BUTTON;
+	action_class->toolbar_item_type = EPHY_TYPE_MIDDLE_CLICKABLE_TOOL_BUTTON;
 
 	g_object_class_install_property (object_class,
 					 PROP_WINDOW,
diff --git a/src/ephy-navigation-history-action.c b/src/ephy-navigation-history-action.c
index daf98ad..7c8d9f3 100644
--- a/src/ephy-navigation-history-action.c
+++ b/src/ephy-navigation-history-action.c
@@ -87,8 +87,13 @@ action_activate (GtkAction *action)
 
   web_view = EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (embed);
 
+  /* We use ephy_link_action_get_button on top of
+   * ephy_gui_is_middle_click because of the hacks we have to do to
+   * fake middle clicks on tool buttons. Read the documentation of
+   * ephy_link_action_get_button for more details. */
   if (history_action->priv->direction == EPHY_NAVIGATION_HISTORY_DIRECTION_BACK) {
-    if (ephy_gui_is_middle_click ()) {
+    if (ephy_gui_is_middle_click () ||
+        ephy_link_action_get_button (EPHY_LINK_ACTION (history_action)) == 2) {
       embed = ephy_shell_new_tab (ephy_shell_get_default (),
                                   EPHY_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (embed))),
                                   embed,
@@ -98,7 +103,8 @@ action_activate (GtkAction *action)
     }
     webkit_web_view_go_back (web_view);
   } else if (history_action->priv->direction == EPHY_NAVIGATION_HISTORY_DIRECTION_FORWARD) {
-    if (ephy_gui_is_middle_click ()) {
+    if (ephy_gui_is_middle_click () ||
+        ephy_link_action_get_button (EPHY_LINK_ACTION (history_action)) == 2) {
       const char *forward_uri;
       WebKitWebHistoryItem *forward_item;
       WebKitWebBackForwardList *history;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]