midori/extensions/mouse-gestures.c

314 lines
11 KiB
C
Raw Normal View History

2009-12-24 23:50:19 +00:00
/*
Copyright (C) 2009 Matthias Kruk <mkruk@matthiaskruk.de>
2010-05-30 17:53:33 +00:00
Copyright (C) 2009-2010 Christian Dywan <christian@twotoasts.de>
2009-12-24 23:50:19 +00:00
This library 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.
See the file COPYING for the full license text.
*/
#include <midori/midori.h>
typedef struct _MouseGesture MouseGesture;
typedef enum _MouseButton MouseButton;
enum _MouseButton {
MOUSE_BUTTON_LEFT = 1,
MOUSE_BUTTON_RIGHT = 3,
MOUSE_BUTTON_MIDDLE = 2,
MOUSE_BUTTON_UNSET = 0
};
struct MouseGestureNode {
double x;
double y;
} MouseGestureNode_t;
struct _MouseGesture {
2010-05-30 17:53:33 +00:00
MouseButton button;
2009-12-24 23:50:19 +00:00
struct MouseGestureNode start;
struct MouseGestureNode middle;
struct MouseGestureNode end;
MouseButton last;
};
#define DEVIANCE 20
#define MINLENGTH 50
MouseGesture *gesture;
void mouse_gesture_clear (MouseGesture *g)
{
g->start.x = 0;
g->start.y = 0;
g->middle.x = 0;
g->middle.y = 0;
g->end.x = 0;
g->end.y = 0;
g->last = MOUSE_BUTTON_UNSET;
}
MouseGesture* mouse_gesture_new (void)
{
MouseGesture* g = g_new (MouseGesture, 1);
mouse_gesture_clear (g);
return g;
}
static gboolean
mouse_gestures_button_press_event_cb (GtkWidget* web_view,
GdkEvent* event,
MidoriBrowser* browser)
{
2010-05-30 17:53:33 +00:00
if (event->button.button == gesture->button)
2009-12-24 23:50:19 +00:00
{
/* If the gesture was previously cleaned,
start a new gesture and coordinates. */
if (gesture->last == MOUSE_BUTTON_UNSET)
{
gesture->start.x = event->button.x;
gesture->start.y = event->button.y;
gesture->last = event->button.button;
}
return TRUE;
}
return FALSE;
}
static gboolean
mouse_gestures_motion_notify_event_cb (GtkWidget* web_view,
GdkEvent* event,
MidoriBrowser* browser)
{
if (gesture->last != MOUSE_BUTTON_UNSET)
{
guint x, y;
x = event->motion.x;
y = event->motion.y;
if ((gesture->start.x - x < DEVIANCE && gesture->start.x - x > -DEVIANCE) ||
(gesture->start.y - y < DEVIANCE && gesture->start.y - y > -DEVIANCE))
{
gesture->middle.x = x;
gesture->middle.y = y;
2010-05-30 17:53:33 +00:00
return TRUE;
2009-12-24 23:50:19 +00:00
}
else if ((gesture->middle.x - x < DEVIANCE && gesture->middle.x - x > -DEVIANCE) ||
(gesture->middle.y - y < DEVIANCE && gesture->middle.y - y > -DEVIANCE))
{
gesture->end.x = x;
gesture->end.y = y;
2010-05-30 17:53:33 +00:00
return TRUE;
2009-12-24 23:50:19 +00:00
}
}
return FALSE;
}
static gboolean
2010-05-30 17:53:33 +00:00
mouse_gestures_activate_action (MidoriView* view,
const gchar* name)
{
MidoriBrowser* browser = midori_browser_get_for_widget (GTK_WIDGET (view));
midori_browser_activate_action (browser, name);
return TRUE;
}
static gboolean
mouse_gestures_button_release_event_cb (GtkWidget* web_view,
GdkEventButton* event,
MidoriView* view)
2009-12-24 23:50:19 +00:00
{
/* All mouse gestures will use this mouse button */
2010-05-30 17:53:33 +00:00
if (gesture->last == gesture->button)
2009-12-24 23:50:19 +00:00
{
/* The initial horizontal move is between the bounds */
if ((gesture->middle.x - gesture->start.x < DEVIANCE) &&
(gesture->middle.x - gesture->start.x > -DEVIANCE))
{
/* We initially moved down more than MINLENGTH pixels */
if (gesture->middle.y > gesture->start.y + MINLENGTH)
{
/* Then we the final vertical move is between the bounds and
we moved right more than MINLENGTH pixels */
if ((gesture->middle.y - gesture->end.y < DEVIANCE) &&
(gesture->middle.y - gesture->end.y > -DEVIANCE) &&
(gesture->end.x > gesture->middle.x + MINLENGTH))
/* We moved down then right: close the tab */
2010-05-30 17:53:33 +00:00
return mouse_gestures_activate_action (view, "TabClose");
2009-12-24 23:50:19 +00:00
/* Then we the final vertical move is between the bounds and
we moved left more than MINLENGTH pixels */
else if ((gesture->middle.y - gesture->end.y < DEVIANCE) &&
(gesture->middle.y - gesture->end.y > -DEVIANCE) &&
(gesture->end.x + MINLENGTH < gesture->middle.x))
/* We moved down then left: reload */
2010-05-30 17:53:33 +00:00
return mouse_gestures_activate_action (view, "Reload");
2009-12-24 23:50:19 +00:00
/* The end node was never updated, we only did a vertical move */
else if(gesture->end.y == 0 && gesture->end.x == 0)
/* We moved down then: create a new tab */
2010-05-30 17:53:33 +00:00
return mouse_gestures_activate_action (view, "TabNew");
2009-12-24 23:50:19 +00:00
}
/* We initially moved up more than MINLENGTH pixels */
else if (gesture->middle.y + MINLENGTH < gesture->start.y)
{
/* The end node was never updated, we only did a vertical move */
if (gesture->end.y == 0 && gesture->end.x == 0)
/* We moved up: stop */
2010-05-30 17:53:33 +00:00
return mouse_gestures_activate_action (view, "Stop");
2009-12-24 23:50:19 +00:00
}
}
/* The initial horizontal move is between the bounds */
else if ((gesture->middle.y - gesture->start.y < DEVIANCE) &&
(gesture->middle.y - gesture->start.y > -DEVIANCE))
{
/* We initially moved right more than MINLENGTH pixels */
if (gesture->middle.x > gesture->start.x + MINLENGTH)
{
/* The end node was never updated, we only did an horizontal move */
if (gesture->end.x == 0 && gesture->end.y == 0)
/* We moved right: forward */
2010-05-30 17:53:33 +00:00
return mouse_gestures_activate_action (view, "Forward");
2009-12-24 23:50:19 +00:00
}
/* We initially moved left more than MINLENGTH pixels */
else if (gesture->middle.x + MINLENGTH < gesture->start.x)
{
/* The end node was never updated, we only did an horizontal move */
if (gesture->end.x == 0 && gesture->end.y == 0)
/* We moved left: back */
2010-05-30 17:53:33 +00:00
return mouse_gestures_activate_action (view, "Back");
2009-12-24 23:50:19 +00:00
}
}
mouse_gesture_clear (gesture);
2010-05-30 17:53:33 +00:00
}
2009-12-24 23:50:19 +00:00
2010-05-30 17:53:33 +00:00
if (event->button == 3)
{
GtkWidget* menu = gtk_menu_new ();
midori_view_populate_popup (view, menu, TRUE);
katze_widget_popup (GTK_WIDGET (web_view), GTK_MENU (menu),
event, KATZE_MENU_POSITION_CURSOR);
2009-12-24 23:50:19 +00:00
return TRUE;
}
return FALSE;
}
static void
mouse_gestures_add_tab_cb (MidoriBrowser* browser,
MidoriView* view,
MidoriExtension* extension)
{
2010-05-30 17:53:33 +00:00
GtkWidget* web_view = midori_view_get_web_view (view);
2009-12-24 23:50:19 +00:00
g_object_connect (web_view,
"signal::button-press-event",
mouse_gestures_button_press_event_cb, browser,
"signal::motion-notify-event",
mouse_gestures_motion_notify_event_cb, browser,
"signal::button-release-event",
2010-05-30 17:53:33 +00:00
mouse_gestures_button_release_event_cb, view,
2009-12-24 23:50:19 +00:00
NULL);
}
static void
mouse_gestures_deactivate_cb (MidoriExtension* extension,
MidoriBrowser* browser);
static void
mouse_gestures_add_tab_foreach_cb (MidoriView* view,
MidoriBrowser* browser,
MidoriExtension* extension)
{
mouse_gestures_add_tab_cb (browser, view, extension);
}
static void
mouse_gestures_app_add_browser_cb (MidoriApp* app,
MidoriBrowser* browser,
MidoriExtension* extension)
{
midori_browser_foreach (browser,
(GtkCallback)mouse_gestures_add_tab_foreach_cb, extension);
g_signal_connect (browser, "add-tab",
G_CALLBACK (mouse_gestures_add_tab_cb), extension);
g_signal_connect (extension, "deactivate",
G_CALLBACK (mouse_gestures_deactivate_cb), browser);
}
static void
mouse_gestures_deactivate_tabs (MidoriView* view,
MidoriBrowser* browser)
{
2010-05-30 17:53:33 +00:00
GtkWidget* web_view = midori_view_get_web_view (view);
2009-12-24 23:50:19 +00:00
g_object_disconnect (web_view,
"any_signal::button-press-event",
mouse_gestures_button_press_event_cb, browser,
"any_signal::motion-notify-event",
mouse_gestures_motion_notify_event_cb, browser,
"any_signal::button-release-event",
2010-05-30 17:53:33 +00:00
mouse_gestures_button_release_event_cb, view,
2009-12-24 23:50:19 +00:00
NULL);
}
static void
mouse_gestures_deactivate_cb (MidoriExtension* extension,
MidoriBrowser* browser)
{
MidoriApp* app = midori_extension_get_app (extension);
g_signal_handlers_disconnect_by_func (
extension, mouse_gestures_deactivate_cb, browser);
g_signal_handlers_disconnect_by_func (
app, mouse_gestures_app_add_browser_cb, extension);
g_signal_handlers_disconnect_by_func (
browser, mouse_gestures_add_tab_cb, extension);
midori_browser_foreach (browser,
(GtkCallback)mouse_gestures_deactivate_tabs, browser);
g_free (gesture);
}
static void
mouse_gestures_activate_cb (MidoriExtension* extension,
MidoriApp* app)
{
KatzeArray* browsers;
MidoriBrowser* browser;
guint i;
gesture = mouse_gesture_new ();
2010-05-30 17:53:33 +00:00
gesture->button = midori_extension_get_integer (extension, "button");
2009-12-24 23:50:19 +00:00
browsers = katze_object_get_object (app, "browsers");
i = 0;
while ((browser = katze_array_get_nth_item (browsers, i++)))
mouse_gestures_app_add_browser_cb (app, browser, extension);
g_signal_connect (app, "add-browser",
G_CALLBACK (mouse_gestures_app_add_browser_cb), extension);
g_object_unref (browsers);
}
MidoriExtension*
extension_init (void)
{
MidoriExtension* extension = g_object_new (MIDORI_TYPE_EXTENSION,
"name", _("Mouse Gestures"),
"description", _("Control Midori by moving the mouse"),
"version", "0.1",
"authors", "Matthias Kruk <mkruk@matthiaskruk.de>", NULL);
2010-05-30 17:53:33 +00:00
midori_extension_install_integer (extension, "button", MOUSE_BUTTON_RIGHT);
2009-12-24 23:50:19 +00:00
g_signal_connect (extension, "activate",
G_CALLBACK (mouse_gestures_activate_cb), NULL);
return extension;
}