/* Copyright (C) 2009 Matthias Kruk 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 #include "mouse-gestures.h" #define MOUSE_GESTURES_VERSION "0.1" #define DEVIANCE 20 #define MINLENGTH 50 /* #define __MOUSE_GESTURES_DEBUG__ */ 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_handle_events (GtkWidget *widget, GdkEvent *event, MidoriBrowser *browser) { /* A button was pressed */ if (event->type == GDK_BUTTON_PRESS && event->button.button == 2) { /* 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; } else if (event->type == GDK_MOTION_NOTIFY) { 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; } 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; } } return TRUE; } else if (event->type == GDK_BUTTON_RELEASE) { /* All mouse gestures will use the middle mouse button */ if (gesture->last == MOUSE_BUTTON_MIDDLE) { /* 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 */ midori_browser_activate_action (browser, "TabClose"); } /* 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 */ midori_browser_activate_action (browser, "Reload"); } /* 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 */ midori_browser_activate_action (browser, "TabNew"); } } /* 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 */ midori_browser_activate_action (browser, "Stop"); } } } /* 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 */ midori_browser_activate_action (browser, "Forward"); } } /* 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 */ midori_browser_activate_action (browser, "Back"); } } } } mouse_gesture_clear (gesture); return TRUE; } else return FALSE; } static void mouse_gestures_tab_cb (MidoriBrowser* browser, GtkWidget *view) { g_signal_connect (view, "event", G_CALLBACK (mouse_gestures_handle_events), browser); } static void mouse_gestures_browser_cb (MidoriApp *app, MidoriBrowser *browser) { g_signal_connect (browser, "add-tab", G_CALLBACK (mouse_gestures_tab_cb), NULL); } static void mouse_gestures_deactivate (MidoriExtension *extension, MidoriApp *app) { gulong signal_id; KatzeArray* browsers; MidoriBrowser* browser; guint i; signal_id = g_signal_handler_find (app, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, mouse_gestures_browser_cb, NULL); if (signal_id != 0) g_signal_handler_disconnect (app, signal_id); browsers = katze_object_get_object (app, "browsers"); i = 0; while ((browser = katze_array_get_nth_item (browsers, i++))) { gint j; GtkWidget* notebook; signal_id = g_signal_handler_find (browser, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, mouse_gestures_tab_cb, NULL); if (signal_id != 0) g_signal_handler_disconnect (browser, signal_id); notebook = katze_object_get_object (browser, "notebook"); for (j = 0; j < gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook)); j++) { GtkWidget *page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), j); signal_id = g_signal_handler_find (page, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, mouse_gestures_handle_events, NULL); if (signal_id != 0) g_signal_handler_disconnect (page, signal_id); } } g_object_unref (browsers); g_signal_handlers_disconnect_by_func (extension, mouse_gestures_deactivate, app); g_free (gesture); } static void mouse_gestures_activate (MidoriExtension *extension, MidoriApp *app) { KatzeArray* browsers; MidoriBrowser* browser; guint i; gesture = mouse_gesture_new (); browsers = katze_object_get_object (app, "browsers"); i = 0; while ((browser = katze_array_get_nth_item (browsers, i++))) mouse_gestures_browser_cb (app, browser); g_object_unref (browsers); g_signal_connect (app, "add-browser", G_CALLBACK (mouse_gestures_browser_cb), NULL); g_signal_connect (extension, "deactivate", G_CALLBACK (mouse_gestures_deactivate), app); } MidoriExtension* extension_init (void) { MidoriExtension* extension; extension = g_object_new (MIDORI_TYPE_EXTENSION, "name", _("Mouse Gestures"), "description", _("Control Midori by moving the mouse"), "version", MOUSE_GESTURES_VERSION, "authors", "Matthias Kruk ", NULL); g_signal_connect (extension, "activate", G_CALLBACK (mouse_gestures_activate), NULL); return extension; }