changeset 2330:0be42d832217

Splitted core/gui/grabbing sources; Fixed memory leak when closing configuration dialog.
author Sascha Hlusiak <contact@saschahlusiak.de>
date Sun, 20 Jan 2008 14:52:44 +0100
parents 62391135da44
children 5b37a9f2d0cc
files src/hotkey/Makefile src/hotkey/grab.c src/hotkey/grab.h src/hotkey/gui.c src/hotkey/gui.h src/hotkey/plugin.c src/hotkey/plugin.h
diffstat 7 files changed, 1017 insertions(+), 904 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotkey/Makefile	Tue Jan 15 12:35:54 2008 +0200
+++ b/src/hotkey/Makefile	Sun Jan 20 14:52:44 2008 +0100
@@ -1,6 +1,6 @@
 PLUGIN = hotkey${PLUGIN_SUFFIX}
 
-SRCS = plugin.c
+SRCS = plugin.c gui.c grab.c
 
 include ../../buildsys.mk
 include ../../extra.mk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotkey/grab.c	Sun Jan 20 14:52:44 2008 +0100
@@ -0,0 +1,372 @@
+/*
+ *  This file is part of audacious-hotkey plugin for audacious
+ *
+ *  Copyright (c) 2007 - 2008  Sascha Hlusiak <contact@saschahlusiak.de>
+ *  Name: grab.c
+ *  Description: grab.c
+ * 
+ *  Part of this code is from itouch-ctrl plugin.
+ *  Authors of itouch-ctrl are listed below:
+ *
+ *  Copyright (c) 2006 - 2007 Vladimir Paskov <vlado.paskov@gmail.com>
+ *
+ *  Part of this code are from xmms-itouch plugin.
+ *  Authors of xmms-itouch are listed below:
+ *
+ *  Copyright (C) 2000-2002 Ville Syrjälä <syrjala@sci.fi>
+ *                         Bryn Davies <curious@ihug.com.au>
+ *                         Jonathan A. Davis <davis@jdhouse.org>
+ *                         Jeremy Tan <nsx@nsx.homeip.net>
+ *
+ *  audacious-hotkey 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  audacious-hotkey 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 audacious-hotkey; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+
+#include "grab.h"
+#include "plugin.h"
+
+
+static gint grabbed = 0;
+static unsigned int numlock_mask = 0;
+static unsigned int scrolllock_mask = 0;
+static unsigned int capslock_mask = 0;
+
+
+/* Taken from xbindkeys */
+static void get_offending_modifiers (Display * dpy)
+{
+	int i;
+	XModifierKeymap *modmap;
+	KeyCode nlock, slock;
+
+	static int mask_table[8] = {
+		ShiftMask, LockMask, ControlMask, Mod1Mask,
+		Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
+	};
+	
+	nlock = XKeysymToKeycode (dpy, XK_Num_Lock);
+	slock = XKeysymToKeycode (dpy, XK_Scroll_Lock);
+	
+	/*
+	* Find out the masks for the NumLock and ScrollLock modifiers,
+	* so that we can bind the grabs for when they are enabled too.
+	*/
+	modmap = XGetModifierMapping (dpy);
+	
+	if (modmap != NULL && modmap->max_keypermod > 0)
+	{
+		for (i = 0; i < 8 * modmap->max_keypermod; i++)
+		{
+			if (modmap->modifiermap[i] == nlock && nlock != 0)
+				numlock_mask = mask_table[i / modmap->max_keypermod];
+			else if (modmap->modifiermap[i] == slock && slock != 0)
+				scrolllock_mask = mask_table[i / modmap->max_keypermod];
+		}
+	}
+	
+	capslock_mask = LockMask;
+	
+	if (modmap)
+		XFreeModifiermap (modmap);
+}
+
+
+static int x11_error_handler (Display *dpy, XErrorEvent *error)
+{
+	return 0;
+}
+
+/* grab required keys */
+static void grab_key(HotkeyConfiguration hotkey, Display *xdisplay, Window x_root_window)
+{
+	unsigned int modifier = hotkey.mask & ~(numlock_mask | capslock_mask | scrolllock_mask);
+	
+	if (hotkey.key == 0) return;
+
+	if (hotkey.type == TYPE_KEY)
+	{
+		XGrabKey (xdisplay, hotkey.key, modifier, x_root_window,
+			False, GrabModeAsync, GrabModeAsync);
+		
+		if (modifier == AnyModifier)
+			return;
+		
+		if (numlock_mask)
+			XGrabKey (xdisplay, hotkey.key, modifier | numlock_mask,
+				x_root_window,
+				False, GrabModeAsync, GrabModeAsync);
+		
+		if (capslock_mask)
+			XGrabKey (xdisplay, hotkey.key, modifier | capslock_mask,
+				x_root_window,
+				False, GrabModeAsync, GrabModeAsync);
+		
+		if (scrolllock_mask)
+			XGrabKey (xdisplay, hotkey.key, modifier | scrolllock_mask,
+				x_root_window,
+				False, GrabModeAsync, GrabModeAsync);
+		
+		if (numlock_mask && capslock_mask)
+			XGrabKey (xdisplay, hotkey.key, modifier | numlock_mask | capslock_mask,
+				x_root_window,
+				False, GrabModeAsync, GrabModeAsync);
+		
+		if (numlock_mask && scrolllock_mask)
+			XGrabKey (xdisplay, hotkey.key, modifier | numlock_mask | scrolllock_mask,
+				x_root_window,
+				False, GrabModeAsync, GrabModeAsync);
+		
+		if (capslock_mask && scrolllock_mask)
+			XGrabKey (xdisplay, hotkey.key, modifier | capslock_mask | scrolllock_mask,
+				x_root_window,
+				False, GrabModeAsync, GrabModeAsync);
+		
+		if (numlock_mask && capslock_mask && scrolllock_mask)
+			XGrabKey (xdisplay, hotkey.key,
+				modifier | numlock_mask | capslock_mask | scrolllock_mask,
+				x_root_window, False, GrabModeAsync,
+				GrabModeAsync);
+	}
+	if (hotkey.type == TYPE_MOUSE)
+	{
+		XGrabButton (xdisplay, hotkey.key, modifier, x_root_window,
+			False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
+		
+		if (modifier == AnyModifier)
+			return;
+		
+		if (numlock_mask)
+			XGrabButton (xdisplay, hotkey.key, modifier | numlock_mask,
+				x_root_window,
+				False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
+		
+		if (capslock_mask)
+			XGrabButton (xdisplay, hotkey.key, modifier | capslock_mask,
+				x_root_window,
+				False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
+		
+		if (scrolllock_mask)
+			XGrabButton (xdisplay, hotkey.key, modifier | scrolllock_mask,
+				x_root_window,
+				False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
+		
+		if (numlock_mask && capslock_mask)
+			XGrabButton (xdisplay, hotkey.key, modifier | numlock_mask | capslock_mask,
+				x_root_window,
+				False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
+		
+		if (numlock_mask && scrolllock_mask)
+			XGrabButton (xdisplay, hotkey.key, modifier | numlock_mask | scrolllock_mask,
+				x_root_window,
+				False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
+		
+		if (capslock_mask && scrolllock_mask)
+			XGrabButton (xdisplay, hotkey.key, modifier | capslock_mask | scrolllock_mask,
+				x_root_window,
+				False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
+		
+		if (numlock_mask && capslock_mask && scrolllock_mask)
+			XGrabButton (xdisplay, hotkey.key,
+				modifier | numlock_mask | capslock_mask | scrolllock_mask,
+				x_root_window, False, ButtonPressMask, GrabModeAsync,
+				GrabModeAsync, None, None);
+	}
+}
+
+void grab_keys ( )
+{
+	Display* xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+	Window x_root_window = GDK_WINDOW_XID(gdk_get_default_root_window());
+	PluginConfig* plugin_cfg = get_config();
+	XErrorHandler old_handler = 0;
+
+	if (grabbed) return;
+
+
+	XSync(xdisplay, False);
+	old_handler = XSetErrorHandler (x11_error_handler);
+
+	get_offending_modifiers(xdisplay);
+
+	grab_key(plugin_cfg->mute, xdisplay, x_root_window);
+	grab_key(plugin_cfg->vol_up, xdisplay, x_root_window);
+	grab_key(plugin_cfg->vol_down, xdisplay, x_root_window);
+	grab_key(plugin_cfg->play, xdisplay, x_root_window);
+	grab_key(plugin_cfg->pause, xdisplay, x_root_window);
+	grab_key(plugin_cfg->stop, xdisplay, x_root_window);
+	grab_key(plugin_cfg->prev_track, xdisplay, x_root_window);
+	grab_key(plugin_cfg->next_track, xdisplay, x_root_window);
+	grab_key(plugin_cfg->jump_to_file, xdisplay, x_root_window);
+	grab_key(plugin_cfg->forward, xdisplay, x_root_window);
+	grab_key(plugin_cfg->backward, xdisplay, x_root_window);
+	grab_key(plugin_cfg->toggle_win, xdisplay, x_root_window);
+	grab_key(plugin_cfg->show_aosd, xdisplay, x_root_window);
+	
+	XSync(xdisplay, False);
+	XSetErrorHandler (old_handler);
+
+	grabbed = 1;
+}
+
+
+
+/* grab required keys */
+static void ungrab_key(HotkeyConfiguration hotkey, Display* xdisplay, Window x_root_window)
+{
+	unsigned int modifier = hotkey.mask & ~(numlock_mask | capslock_mask | scrolllock_mask);
+	
+	if (hotkey.key == 0) return;
+	
+	if (hotkey.type == TYPE_KEY)
+	{
+		XUngrabKey (xdisplay, hotkey.key, modifier, x_root_window);
+		
+		if (modifier == AnyModifier)
+			return;
+		
+		if (numlock_mask)
+			XUngrabKey (xdisplay, hotkey.key, modifier | numlock_mask, x_root_window);
+	
+		if (capslock_mask)
+			XUngrabKey (xdisplay, hotkey.key, modifier | capslock_mask, x_root_window);
+	
+		if (scrolllock_mask)
+			XUngrabKey (xdisplay, hotkey.key, modifier | scrolllock_mask, x_root_window);
+	
+		if (numlock_mask && capslock_mask)
+			XUngrabKey (xdisplay, hotkey.key, modifier | numlock_mask | capslock_mask, x_root_window);
+	
+		if (numlock_mask && scrolllock_mask)
+			XUngrabKey (xdisplay, hotkey.key, modifier | numlock_mask | scrolllock_mask, x_root_window);
+	
+		if (capslock_mask && scrolllock_mask)
+			XUngrabKey (xdisplay, hotkey.key, modifier | capslock_mask | scrolllock_mask, x_root_window);
+	
+		if (numlock_mask && capslock_mask && scrolllock_mask)
+			XUngrabKey (xdisplay, hotkey.key, modifier | numlock_mask | capslock_mask | scrolllock_mask, x_root_window);
+	}
+	if (hotkey.type == TYPE_MOUSE)
+	{
+		XUngrabButton (xdisplay, hotkey.key, modifier, x_root_window);
+		
+		if (modifier == AnyModifier)
+			return;
+		
+		if (numlock_mask)
+			XUngrabButton (xdisplay, hotkey.key, modifier | numlock_mask, x_root_window);
+	
+		if (capslock_mask)
+			XUngrabButton (xdisplay, hotkey.key, modifier | capslock_mask, x_root_window);
+	
+		if (scrolllock_mask)
+			XUngrabButton (xdisplay, hotkey.key, modifier | scrolllock_mask, x_root_window);
+	
+		if (numlock_mask && capslock_mask)
+			XUngrabButton (xdisplay, hotkey.key, modifier | numlock_mask | capslock_mask, x_root_window);
+	
+		if (numlock_mask && scrolllock_mask)
+			XUngrabButton (xdisplay, hotkey.key, modifier | numlock_mask | scrolllock_mask, x_root_window);
+	
+		if (capslock_mask && scrolllock_mask)
+			XUngrabButton (xdisplay, hotkey.key, modifier | capslock_mask | scrolllock_mask, x_root_window);
+	
+		if (numlock_mask && capslock_mask && scrolllock_mask)
+			XUngrabButton (xdisplay, hotkey.key, modifier | numlock_mask | capslock_mask | scrolllock_mask, x_root_window);
+	}
+}
+
+void ungrab_keys ( )
+{
+	XErrorHandler old_handler = 0;
+	Display* xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
+	Window x_root_window = GDK_WINDOW_XID(gdk_get_default_root_window());
+	PluginConfig* plugin_cfg = get_config();
+
+	if (!grabbed) return;
+	if (!xdisplay) return;
+
+	XSync(xdisplay, False);
+	old_handler = XSetErrorHandler (x11_error_handler);
+
+	get_offending_modifiers(xdisplay);
+
+	ungrab_key(plugin_cfg->mute, xdisplay, x_root_window);
+	ungrab_key(plugin_cfg->vol_up, xdisplay, x_root_window);
+	ungrab_key(plugin_cfg->vol_down, xdisplay, x_root_window);
+	ungrab_key(plugin_cfg->play, xdisplay, x_root_window);
+	ungrab_key(plugin_cfg->pause, xdisplay, x_root_window);
+	ungrab_key(plugin_cfg->stop, xdisplay, x_root_window);
+	ungrab_key(plugin_cfg->prev_track, xdisplay, x_root_window);
+	ungrab_key(plugin_cfg->next_track, xdisplay, x_root_window);
+	ungrab_key(plugin_cfg->jump_to_file, xdisplay, x_root_window);
+	ungrab_key(plugin_cfg->forward, xdisplay, x_root_window);
+	ungrab_key(plugin_cfg->backward, xdisplay, x_root_window);
+	ungrab_key(plugin_cfg->toggle_win, xdisplay, x_root_window);
+	ungrab_key(plugin_cfg->show_aosd, xdisplay, x_root_window);
+	
+	XSync(xdisplay, False);
+	XSetErrorHandler (old_handler);
+
+	grabbed = 0;
+}
+
+
+static GdkFilterReturn
+gdk_filter(GdkXEvent *xevent,
+	   GdkEvent *event,
+	   gpointer data)
+{
+	switch (((XEvent*)xevent)->type)
+	{
+	case KeyPress:
+		{
+			XKeyEvent *keyevent = (XKeyEvent*)xevent;
+			if (handle_keyevent(keyevent->keycode, keyevent->state & ~(scrolllock_mask | numlock_mask | capslock_mask), TYPE_KEY))
+				return GDK_FILTER_REMOVE;
+			break;
+		}
+	case ButtonPress:
+		{
+			XButtonEvent *buttonevent = (XButtonEvent*)xevent;
+			if (handle_keyevent(buttonevent->button, buttonevent->state, TYPE_MOUSE))
+				return GDK_FILTER_REMOVE;
+			break;
+		}
+	default:
+		return -1;
+	}
+	
+	return GDK_FILTER_CONTINUE;
+}
+
+gboolean setup_filter()
+{
+	gdk_window_add_filter(gdk_get_default_root_window(),
+				gdk_filter,
+				NULL);
+
+	return TRUE;
+}
+
+void release_filter()
+{
+	gdk_window_remove_filter(gdk_get_default_root_window(),
+				gdk_filter,
+				NULL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotkey/grab.h	Sun Jan 20 14:52:44 2008 +0100
@@ -0,0 +1,11 @@
+#ifndef _GRAB_H_INCLUDED_
+#define _GRAB_H_INCLUDED_
+
+#include <glib.h>
+
+void grab_keys ();
+void ungrab_keys ();
+gboolean setup_filter();
+void release_filter();
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotkey/gui.c	Sun Jan 20 14:52:44 2008 +0100
@@ -0,0 +1,566 @@
+/*
+ *  This file is part of audacious-hotkey plugin for audacious
+ *
+ *  Copyright (c) 2007 - 2008  Sascha Hlusiak <contact@saschahlusiak.de>
+ *  Name: gui.c
+ *  Description: gui.c
+ * 
+ *  Part of this code is from itouch-ctrl plugin.
+ *  Authors of itouch-ctrl are listed below:
+ *
+ *  Copyright (c) 2006 - 2007 Vladimir Paskov <vlado.paskov@gmail.com>
+ *
+ *  Part of this code are from xmms-itouch plugin.
+ *  Authors of xmms-itouch are listed below:
+ *
+ *  Copyright (C) 2000-2002 Ville Syrjälä <syrjala@sci.fi>
+ *                         Bryn Davies <curious@ihug.com.au>
+ *                         Jonathan A. Davis <davis@jdhouse.org>
+ *                         Jeremy Tan <nsx@nsx.homeip.net>
+ *
+ *  audacious-hotkey 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 of the License, or
+ *  (at your option) any later version.
+ *
+ *  audacious-hotkey 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 audacious-hotkey; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkkeysyms.h>
+
+#include <audacious/i18n.h>
+#include <audacious/util.h>
+
+#include "plugin.h"
+#include "gui.h"
+#include "grab.h"
+
+
+typedef struct {
+	GtkWidget *keytext;
+	HotkeyConfiguration hotkey;
+} KeyControls;
+
+typedef struct {
+	KeyControls play;
+	KeyControls stop;
+	KeyControls pause;
+	KeyControls prev_track;
+	KeyControls next_track;
+	KeyControls vol_up;
+	KeyControls vol_down;
+	KeyControls mute;
+	KeyControls jump_to_file;
+	KeyControls forward;
+	KeyControls backward;
+	KeyControls toggle_win;
+	KeyControls show_aosd;
+} ConfigurationControls;
+
+
+
+static void clear_keyboard (GtkWidget *widget, gpointer data);
+static void cancel_callback (GtkWidget *widget, gpointer data);
+static void destroy_callback (GtkWidget *widget, gpointer data);
+static void ok_callback (GtkWidget *widget, gpointer data);
+
+
+static void set_keytext (GtkWidget *entry, gint key, gint mask, gint type)
+{
+	gchar *text = NULL;
+
+	if (key == 0 && mask == 0)
+	{
+		text = g_strdup(_("(none)"));
+	} else {
+		static char *modifier_string[] = { "Control", "Shift", "Alt", "Mod2", "Mod3", "Super", "Mod5" };
+		static unsigned int modifiers[] = { ControlMask, ShiftMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask };
+		gchar *strings[9];
+		gchar *keytext = NULL;
+		int i, j;
+		if (type == TYPE_KEY)
+		{
+			KeySym keysym;
+			keysym = XKeycodeToKeysym(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), key, 0);
+			if (keysym == 0 || keysym == NoSymbol)
+			{
+				keytext = g_strdup_printf("#%d", key);
+			} else {
+				keytext = g_strdup(XKeysymToString(keysym));
+			}
+		}
+		if (type == TYPE_MOUSE)
+		{
+			keytext = g_strdup_printf("Button%d", key);
+		}
+
+		for (i = 0, j=0; j<7; j++)
+		{
+			if (mask & modifiers[j])
+ 				strings[i++] = modifier_string[j];
+		}
+		if (key != 0) strings[i++] = keytext;
+		strings[i] = NULL;
+
+		text = g_strjoinv(" + ", strings);
+		g_free(keytext);
+	}
+
+	gtk_entry_set_text(GTK_ENTRY(entry), text);
+	gtk_editable_set_position(GTK_EDITABLE(entry), -1);
+	if (text) g_free(text);
+}
+
+static gboolean
+on_entry_key_press_event(GtkWidget * widget,
+                         GdkEventKey * event,
+                         gpointer user_data)
+{
+	KeyControls *controls = (KeyControls*) user_data;
+	int is_mod;
+	int mod;
+
+	if (event->keyval == GDK_Tab) return FALSE;
+
+	mod = 0;
+	is_mod = 0;
+
+	if ((event->state & GDK_CONTROL_MASK) | (!is_mod && (is_mod = (event->keyval == GDK_Control_L || event->keyval == GDK_Control_R))))
+        	mod |= ControlMask;
+
+	if ((event->state & GDK_MOD1_MASK) | (!is_mod && (is_mod = (event->keyval == GDK_Alt_L || event->keyval == GDK_Alt_R))))
+        	mod |= Mod1Mask;
+
+	if ((event->state & GDK_SHIFT_MASK) | (!is_mod && (is_mod = (event->keyval == GDK_Shift_L || event->keyval == GDK_Shift_R))))
+        	mod |= ShiftMask;
+
+	if ((event->state & GDK_MOD5_MASK) | (!is_mod && (is_mod = (event->keyval == GDK_ISO_Level3_Shift))))
+        	mod |= Mod5Mask;
+
+	if ((event->state & GDK_MOD4_MASK) | (!is_mod && (is_mod = (event->keyval == GDK_Super_L || event->keyval == GDK_Super_R))))
+        	mod |= Mod4Mask;
+
+	if (!is_mod) {
+		controls->hotkey.key = event->hardware_keycode;
+		controls->hotkey.mask = mod;
+		controls->hotkey.type = TYPE_KEY;
+	} else controls->hotkey.key = 0;
+
+	set_keytext(controls->keytext, is_mod ? 0 : event->hardware_keycode, mod, TYPE_KEY);
+	return TRUE;
+}
+
+static gboolean
+on_entry_key_release_event(GtkWidget * widget,
+                           GdkEventKey * event,
+                           gpointer user_data)
+{
+	KeyControls *controls = (KeyControls*) user_data;
+	if (controls->hotkey.key == 0) {
+		controls->hotkey.mask = 0;
+		return TRUE;
+	}
+	set_keytext(controls->keytext, controls->hotkey.key, controls->hotkey.mask, controls->hotkey.type);
+	return TRUE;
+}
+
+static gboolean
+on_entry_button_press_event(GtkWidget * widget,
+                            GdkEventButton * event,
+                            gpointer user_data)
+{
+	KeyControls *controls = (KeyControls*) user_data;
+	int mod;
+	
+	if (!gtk_widget_is_focus(widget)) return FALSE;
+
+	mod = 0;
+	if (event->state & GDK_CONTROL_MASK)
+        	mod |= ControlMask;
+
+	if (event->state & GDK_MOD1_MASK)
+        	mod |= Mod1Mask;
+
+	if (event->state & GDK_SHIFT_MASK)
+        	mod |= ShiftMask;
+
+	if (event->state & GDK_MOD5_MASK)
+        	mod |= Mod5Mask;
+
+	if (event->state & GDK_MOD4_MASK)
+        	mod |= Mod4Mask;
+
+	if ((event->button <= 3) && (mod == 0))
+	{
+		GtkWidget* dialog;
+		GtkResponseType response;
+		dialog = gtk_message_dialog_new (GTK_WINDOW(gtk_widget_get_toplevel(widget)),
+			GTK_DIALOG_MODAL,
+			GTK_MESSAGE_WARNING,
+			GTK_BUTTONS_YES_NO,
+			_("It is not recommended to bind the primary mouse buttons without modificators.\n\n"
+			  "Do you want to continue?"));
+		gtk_window_set_title(GTK_WINDOW(dialog), _("Binding mouse buttons"));
+		response = gtk_dialog_run(GTK_DIALOG(dialog));
+		gtk_widget_destroy (dialog);
+		if (response != GTK_RESPONSE_YES) return TRUE;
+	}
+
+	controls->hotkey.key = event->button;
+	controls->hotkey.mask = mod;
+        controls->hotkey.type = TYPE_MOUSE;
+	set_keytext(controls->keytext, controls->hotkey.key, controls->hotkey.mask, controls->hotkey.type);
+	return TRUE;
+}
+
+static gboolean
+on_entry_scroll_event(GtkWidget * widget,
+                            GdkEventScroll * event,
+                            gpointer user_data)
+{
+	KeyControls *controls = (KeyControls*) user_data;
+	int mod;
+	
+	if (!gtk_widget_is_focus(widget)) return FALSE;
+
+	mod = 0;
+	if (event->state & GDK_CONTROL_MASK)
+        	mod |= ControlMask;
+
+	if (event->state & GDK_MOD1_MASK)
+        	mod |= Mod1Mask;
+
+	if (event->state & GDK_SHIFT_MASK)
+        	mod |= ShiftMask;
+
+	if (event->state & GDK_MOD5_MASK)
+        	mod |= Mod5Mask;
+
+	if (event->state & GDK_MOD4_MASK)
+        	mod |= Mod4Mask;
+
+	if (event->direction == GDK_SCROLL_UP)
+		controls->hotkey.key = 4;
+	else if (event->direction == GDK_SCROLL_DOWN)
+		controls->hotkey.key = 5;
+	else if (event->direction == GDK_SCROLL_LEFT)
+		controls->hotkey.key = 6;
+	else if (event->direction == GDK_SCROLL_RIGHT)
+		controls->hotkey.key = 7;
+	else return FALSE;
+
+	controls->hotkey.mask = mod;
+        controls->hotkey.type = TYPE_MOUSE;
+	set_keytext(controls->keytext, controls->hotkey.key, controls->hotkey.mask, controls->hotkey.type);
+	return TRUE;
+}
+
+static void add_event_controls(GtkWidget *table, 
+				KeyControls *controls, 
+				int row, 
+				char* descr,
+				char* tooltip,
+				HotkeyConfiguration hotkey)
+{
+	GtkWidget *label;
+	GtkWidget *button;
+
+	controls->hotkey.key = hotkey.key;
+	controls->hotkey.mask = hotkey.mask;
+	controls->hotkey.type = hotkey.type;
+	if (controls->hotkey.key == 0)
+		controls->hotkey.mask = 0;
+
+	label = gtk_label_new (_(descr));
+	gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row+1, 
+			(GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
+	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+	gtk_misc_set_padding (GTK_MISC (label), 3, 3);
+	
+	controls->keytext = gtk_entry_new ();
+	gtk_table_attach (GTK_TABLE (table), controls->keytext, 1, 2, row, row+1, 
+			(GtkAttachOptions) (GTK_FILL|GTK_EXPAND), (GtkAttachOptions) (GTK_EXPAND), 0, 0);
+	gtk_entry_set_editable (GTK_ENTRY (controls->keytext), FALSE);
+
+	set_keytext(controls->keytext, hotkey.key, hotkey.mask, hotkey.type);
+	g_signal_connect((gpointer)controls->keytext, "key_press_event",
+                         G_CALLBACK(on_entry_key_press_event), controls);
+	g_signal_connect((gpointer)controls->keytext, "key_release_event",
+                         G_CALLBACK(on_entry_key_release_event), controls);
+	g_signal_connect((gpointer)controls->keytext, "button_press_event",
+                         G_CALLBACK(on_entry_button_press_event), controls);
+	g_signal_connect((gpointer)controls->keytext, "scroll_event",
+                         G_CALLBACK(on_entry_scroll_event), controls);
+
+	button = gtk_button_new_with_label (_("None"));
+	gtk_table_attach (GTK_TABLE (table), button, 2, 3, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
+	g_signal_connect (G_OBJECT (button), "clicked",
+			G_CALLBACK (clear_keyboard), controls);
+
+	if (tooltip != NULL) {
+		GtkTooltips *tip = gtk_tooltips_new();
+		gtk_tooltips_set_tip(tip, controls->keytext, tooltip, NULL);
+		gtk_tooltips_set_tip(tip, button, tooltip, NULL);
+		gtk_tooltips_set_tip(tip, label, tooltip, NULL);
+	}
+}
+
+void show_configure ()
+{
+	ConfigurationControls *controls;
+	GtkWidget *window;
+	GtkWidget *main_vbox, *vbox;
+	GtkWidget *hbox;
+	GtkWidget *alignment;
+	GtkWidget *frame;
+	GtkWidget *label;
+	GtkWidget *image;
+	GtkWidget *table;
+	GtkWidget *button_box, *button;
+	PluginConfig* plugin_cfg;
+	
+	load_config ( );
+
+	plugin_cfg = get_config();
+
+	ungrab_keys();
+	
+	controls = (ConfigurationControls*)g_malloc(sizeof(ConfigurationControls));
+	if (!controls)
+	{
+		printf ("Faild to allocate memory for ConfigurationControls structure!\n"
+			"Aborting!");
+		return;
+	}
+	
+	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+	gtk_window_set_title (GTK_WINDOW (window), _("Global Hotkey Plugin Configuration"));
+	gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER_ALWAYS);
+	gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DIALOG);
+	gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
+	gtk_container_set_border_width (GTK_CONTAINER (window), 5);
+	
+	main_vbox = gtk_vbox_new (FALSE, 4);
+	gtk_container_add (GTK_CONTAINER (window), main_vbox);
+	
+	alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
+	gtk_box_pack_start (GTK_BOX (main_vbox), alignment, FALSE, TRUE, 0);
+	gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 4, 0, 0, 0);
+	hbox = gtk_hbox_new (FALSE, 2);
+	gtk_container_add (GTK_CONTAINER (alignment), hbox);
+	image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG);
+	gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0);
+	label = gtk_label_new (_("Press a key combination inside a text field."));
+	gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
+	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
+	
+	label = gtk_label_new (NULL);
+	gtk_label_set_markup (GTK_LABEL (label), _("<b>Playback:</b>"));
+	frame = gtk_frame_new (NULL);
+	gtk_frame_set_label_widget (GTK_FRAME (frame), label);
+	gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, TRUE, 0);
+	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
+	alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
+	gtk_container_add (GTK_CONTAINER (frame), alignment);
+	gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 3, 3, 3, 3);
+	vbox = gtk_vbox_new (FALSE, 2);
+	gtk_container_add (GTK_CONTAINER (alignment), vbox);
+	label = gtk_label_new (NULL);
+	gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0);
+	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
+	gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
+	gtk_label_set_markup (GTK_LABEL (label), 
+			_("<i>Configure keys which controls Audacious playback.</i>"));
+	table = gtk_table_new (4, 3, FALSE);
+	gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
+	gtk_table_set_col_spacings (GTK_TABLE (table), 2);
+	gtk_table_set_row_spacings (GTK_TABLE (table), 2);
+
+	/* prev track */
+	add_event_controls(table, &controls->prev_track, 0, _("Previous Track:"), NULL, 
+			plugin_cfg->prev_track);
+
+	add_event_controls(table, &controls->play, 1, _("Play:"), NULL, 
+			plugin_cfg->play);
+
+	add_event_controls(table, &controls->pause, 2, _("Pause/Resume:"), NULL,
+			plugin_cfg->pause);
+
+	add_event_controls(table, &controls->stop, 3, _("Stop:"), NULL,
+			plugin_cfg->stop);
+
+	add_event_controls(table, &controls->next_track, 4, _("Next Track:"), NULL,
+			plugin_cfg->next_track);
+
+	add_event_controls(table, &controls->forward, 5, _("Forward 5 sec.:"), NULL,
+			plugin_cfg->forward);
+
+	add_event_controls(table, &controls->backward, 6, _("Rewind 5 sec.:"), NULL,
+			plugin_cfg->backward);
+
+
+	label = gtk_label_new (NULL);
+	gtk_label_set_markup (GTK_LABEL (label), _("<b>Volume Control:</b>"));
+	frame = gtk_frame_new (NULL);
+	gtk_frame_set_label_widget (GTK_FRAME (frame), label);
+	gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, TRUE, 0);
+	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
+	alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
+	gtk_container_add (GTK_CONTAINER (frame), alignment);
+	gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 3, 3, 3, 3);
+	vbox = gtk_vbox_new (FALSE, 2);
+	gtk_container_add (GTK_CONTAINER (alignment), vbox);
+	label = gtk_label_new (NULL);
+	gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0);
+	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
+	gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
+	gtk_label_set_markup (GTK_LABEL (label), 
+			_("<i>Configure keys which controls music volume.</i>"));
+	table = gtk_table_new (3, 3, FALSE);
+	gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
+	gtk_table_set_col_spacings (GTK_TABLE (table), 2);
+	gtk_table_set_row_spacings (GTK_TABLE (table), 2);
+
+	add_event_controls(table, &controls->mute, 0, _("Mute:"),NULL, 
+			plugin_cfg->mute);
+
+	add_event_controls(table, &controls->vol_up, 1, _("Volume Up:"), NULL,
+			plugin_cfg->vol_up);
+
+	add_event_controls(table, &controls->vol_down, 2, _("Volume Down:"), NULL,
+			plugin_cfg->vol_down);
+
+
+	label = gtk_label_new (NULL);
+	gtk_label_set_markup (GTK_LABEL (label), _("<b>Player:</b>"));
+	frame = gtk_frame_new (NULL);
+	gtk_frame_set_label_widget (GTK_FRAME (frame), label);
+	gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, TRUE, 0);
+	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
+	alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
+	gtk_container_add (GTK_CONTAINER (frame), alignment);
+	gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 3, 3, 3, 3);
+	vbox = gtk_vbox_new (FALSE, 2);
+	gtk_container_add (GTK_CONTAINER (alignment), vbox);
+	label = gtk_label_new (NULL);
+	gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0);
+	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
+	gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
+	gtk_label_set_markup (GTK_LABEL (label), 
+			_("<i>Configure keys which control the player.</i>"));
+	table = gtk_table_new (3, 3, FALSE);
+	gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
+	gtk_table_set_col_spacings (GTK_TABLE (table), 2);
+	gtk_table_set_row_spacings (GTK_TABLE (table), 2);
+
+	add_event_controls(table, &controls->jump_to_file, 0, _("Jump to File:"), NULL,
+			plugin_cfg->jump_to_file);
+
+	add_event_controls(table, &controls->toggle_win, 1, _("Toggle Player Windows:"), NULL,
+			plugin_cfg->toggle_win);
+
+	add_event_controls(table, &controls->show_aosd, 2, _("Show On-Screen-Display:"), 
+			_("For this, the Audacious OSD plugin must be activated."),
+			plugin_cfg->show_aosd);
+
+	button_box = gtk_hbutton_box_new ( );
+	gtk_box_pack_start (GTK_BOX (main_vbox), button_box, FALSE, TRUE, 6);
+	gtk_button_box_set_layout (GTK_BUTTON_BOX (button_box), GTK_BUTTONBOX_END);
+	gtk_box_set_spacing (GTK_BOX (button_box), 4);
+	
+	button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
+	gtk_container_add (GTK_CONTAINER (button_box), button);
+	g_signal_connect (G_OBJECT (button), "clicked",
+			G_CALLBACK (cancel_callback), controls);
+	
+	button = gtk_button_new_from_stock (GTK_STOCK_OK);
+	gtk_container_add (GTK_CONTAINER (button_box), button);
+	g_signal_connect (G_OBJECT (button), "clicked",
+			G_CALLBACK (ok_callback), controls);
+
+	g_signal_connect (G_OBJECT (window), "destroy",
+		G_CALLBACK (destroy_callback), controls);
+
+	gtk_widget_show_all (GTK_WIDGET (window));
+}
+
+static void clear_keyboard (GtkWidget *widget, gpointer data)
+{
+	KeyControls *spins = (KeyControls*)data;
+	spins->hotkey.key = 0;
+	spins->hotkey.mask = 0;
+	spins->hotkey.type = TYPE_KEY;
+	set_keytext(spins->keytext, 0, 0, TYPE_KEY);
+}
+
+void destroy_callback (GtkWidget *widget, gpointer data)
+{
+	if (is_loaded())
+	{
+		grab_keys ();
+	}
+	if (data) g_free(data);
+}
+
+void cancel_callback (GtkWidget *widget, gpointer data)
+{
+	gtk_widget_destroy (gtk_widget_get_toplevel (GTK_WIDGET (widget)));
+}
+
+void ok_callback (GtkWidget *widget, gpointer data)
+{
+	ConfigurationControls *controls= (ConfigurationControls*)data;
+	PluginConfig* plugin_cfg = get_config();
+
+	plugin_cfg->play = controls->play.hotkey;
+	plugin_cfg->pause = controls->pause.hotkey;
+	plugin_cfg->stop= controls->stop.hotkey;
+	plugin_cfg->prev_track= controls->prev_track.hotkey;
+	plugin_cfg->next_track = controls->next_track.hotkey;
+	plugin_cfg->forward = controls->forward.hotkey;
+	plugin_cfg->backward = controls->backward.hotkey;
+	plugin_cfg->vol_up= controls->vol_up.hotkey;
+	plugin_cfg->vol_down = controls->vol_down.hotkey;
+	plugin_cfg->mute = controls->mute.hotkey;
+	plugin_cfg->jump_to_file= controls->jump_to_file.hotkey;
+	plugin_cfg->toggle_win = controls->toggle_win.hotkey;
+	plugin_cfg->show_aosd = controls->show_aosd.hotkey;
+	
+	save_config ( );
+	
+	gtk_widget_destroy (gtk_widget_get_toplevel (GTK_WIDGET (widget)));
+}
+
+
+
+void show_about (void)
+{
+	static GtkWidget *dialog;
+
+	dialog = audacious_info_dialog (_("About Global Hotkey Plugin"),
+				_("Global Hotkey Plugin\n"
+				"Control the player with global key combinations or multimedia keys.\n\n"
+				"Copyright (C) 2007-2008 Sascha Hlusiak <contact@saschahlusiak.de>\n\n"
+				"Contributers include:\n"
+				"Copyright (C) 2006-2007 Vladimir Paskov <vlado.paskov@gmail.com>\n"
+				"Copyright (C) 2000-2002 Ville Syrjälä <syrjala@sci.fi>\n"
+                         	"			Bryn Davies <curious@ihug.com.au>\n"
+                        	"			Jonathan A. Davis <davis@jdhouse.org>\n"
+                         	"			Jeremy Tan <nsx@nsx.homeip.net>\n\n"
+                         	),
+                         	_("OK"), TRUE, NULL, NULL);
+
+	gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
+			   GTK_SIGNAL_FUNC(gtk_widget_destroyed), &dialog);						
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotkey/gui.h	Sun Jan 20 14:52:44 2008 +0100
@@ -0,0 +1,7 @@
+#ifndef _GUI_H_INCLUDED_
+#define _GUI_H_INCLUDED_
+
+void show_configure (void);
+void show_about (void);
+
+#endif
--- a/src/hotkey/plugin.c	Tue Jan 15 12:35:54 2008 +0200
+++ b/src/hotkey/plugin.c	Sun Jan 20 14:52:44 2008 +0100
@@ -1,4 +1,3 @@
-/* -*- Mode: C; indent-tabs: t; c-basic-offset: 9; tab-width: 9 -*- */
 /*
  *  This file is part of audacious-hotkey plugin for audacious
  *
@@ -37,112 +36,37 @@
 #include <config.h>
 
 #include <stdio.h>
-#include <stdlib.h>
-#include <X11/Xlib.h>
-#include <X11/keysym.h>
 #include <X11/XF86keysym.h>
 
-#include <gtk/gtk.h>
 #include <gdk/gdkx.h>
-#include <gdk/gdkkeysyms.h>
 #include <audacious/plugin.h>
 #include <audacious/auddrct.h>
 #include <audacious/configdb.h>
 
 #include <audacious/i18n.h>
 
-/* for audacious_info_dialog () */
-#include <audacious/util.h>
+#include "plugin.h"
+#include "gui.h"
+#include "grab.h"
 
 
 /* func defs */
-void x_display_init (void);
-static void get_offending_modifiers (Display * dpy);
 static void init (void);
-static void grab_keys ();
-static void ungrab_keys ();
-static gboolean handle_keyevent(int keycode, int state, int type);
-static gboolean setup_filter();
-static void release_filter();
-
-static void load_config (void);
-static void save_config (void);
-static void configure (void);
-static void clear_keyboard (GtkWidget *widget, gpointer data);
-
-void cancel_callback (GtkWidget *widget, gpointer data);
-void ok_callback (GtkWidget *widget, gpointer data);
-static void about (void);
 static void cleanup (void);
 
-#define TYPE_KEY 0
-#define TYPE_MOUSE 1
-
 
-typedef struct {
-	gint key, mask;
-	gint type;
-} HotkeyConfiguration;
-
-typedef struct {
-	gint vol_increment;
-	gint vol_decrement;
-	
-	/* keyboard */
-	HotkeyConfiguration mute;
-	HotkeyConfiguration vol_down;
-	HotkeyConfiguration vol_up;
-	HotkeyConfiguration play;
-	HotkeyConfiguration stop;
-	HotkeyConfiguration pause;
-	HotkeyConfiguration prev_track;
-	HotkeyConfiguration next_track;
-	HotkeyConfiguration jump_to_file;
-	HotkeyConfiguration toggle_win;
-	HotkeyConfiguration forward;
-	HotkeyConfiguration backward;
-	HotkeyConfiguration show_aosd;
-} PluginConfig;
-
-PluginConfig plugin_cfg;
-
-static Display *xdisplay = NULL;
-static Window x_root_window = 0;
-static gint grabbed = 0;
+/* global vars */
+static PluginConfig plugin_cfg;
 static gboolean loaded = FALSE;
-static unsigned int numlock_mask = 0;
-static unsigned int scrolllock_mask = 0;
-static unsigned int capslock_mask = 0;
 
 
 
-typedef struct {
-	GtkWidget *keytext;
-	HotkeyConfiguration hotkey;
-} KeyControls;
-
-typedef struct {
-	KeyControls play;
-	KeyControls stop;
-	KeyControls pause;
-	KeyControls prev_track;
-	KeyControls next_track;
-	KeyControls vol_up;
-	KeyControls vol_down;
-	KeyControls mute;
-	KeyControls jump_to_file;
-	KeyControls forward;
-	KeyControls backward;
-	KeyControls toggle_win;
-	KeyControls show_aosd;
-} ConfigurationControls;
-
 static GeneralPlugin audacioushotkey =
 {
 	.description = "Global Hotkey",
 	.init = init,
-	.about = about,
-	.configure = configure,
+	.about = show_about,
+	.configure = show_configure,
 	.cleanup = cleanup
 };
 
@@ -151,67 +75,26 @@
 
 
 
+PluginConfig* get_config(void)
+{
+	return &plugin_cfg;
+}
+
+
 /* 
  * plugin activated
  */
 static void init (void)
 {
-	x_display_init ( );
 	setup_filter();
 	load_config ( );
-	grab_keys ();
+	grab_keys ( );
 
 	loaded = TRUE;
 }
 
-/* check X display */
-void x_display_init (void)
-{
-	if (xdisplay != NULL) return;
-	xdisplay = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
-	x_root_window = GDK_WINDOW_XID(gdk_get_default_root_window());
-	get_offending_modifiers(xdisplay);
-}
-
-/* Taken from xbindkeys */
-static void get_offending_modifiers (Display * dpy)
-{
-	int i;
-	XModifierKeymap *modmap;
-	KeyCode nlock, slock;
-	static int mask_table[8] = {
-		ShiftMask, LockMask, ControlMask, Mod1Mask,
-		Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
-	};
-	
-	nlock = XKeysymToKeycode (dpy, XK_Num_Lock);
-	slock = XKeysymToKeycode (dpy, XK_Scroll_Lock);
-	
-	/*
-	* Find out the masks for the NumLock and ScrollLock modifiers,
-	* so that we can bind the grabs for when they are enabled too.
-	*/
-	modmap = XGetModifierMapping (dpy);
-	
-	if (modmap != NULL && modmap->max_keypermod > 0)
-	{
-		for (i = 0; i < 8 * modmap->max_keypermod; i++)
-		{
-			if (modmap->modifiermap[i] == nlock && nlock != 0)
-				numlock_mask = mask_table[i / modmap->max_keypermod];
-			else if (modmap->modifiermap[i] == slock && slock != 0)
-				scrolllock_mask = mask_table[i / modmap->max_keypermod];
-		}
-	}
-	
-	capslock_mask = LockMask;
-	
-	if (modmap)
-		XFreeModifiermap (modmap);
-}
-
 /* handle keys */
-static gboolean handle_keyevent (int keycode, int state, int type)
+gboolean handle_keyevent (int keycode, int state, int type)
 {
 	gint current_volume, old_volume;
 	static gint volume_static = 0;
@@ -232,8 +115,6 @@
 		mute = TRUE;
 	}
 
-	state &= ~(scrolllock_mask | numlock_mask | capslock_mask);
-	
 	/* mute the playback */
 	if ((keycode == plugin_cfg.mute.key) && (state == plugin_cfg.mute.mask) && (type == plugin_cfg.mute.type))
 	{
@@ -390,64 +271,17 @@
 	return FALSE;
 }
 
-static GdkFilterReturn
-gdk_filter(GdkXEvent *xevent,
-	   GdkEvent *event,
-	   gpointer data)
-{
-	switch (((XEvent*)xevent)->type)
-	{
-	case KeyPress:
-		{
-			XKeyEvent *keyevent = (XKeyEvent*)xevent;
-			if (handle_keyevent(keyevent->keycode, keyevent->state, TYPE_KEY))
-				return GDK_FILTER_REMOVE;
-			break;
-		}
-	case ButtonPress:
-		{
-			XButtonEvent *buttonevent = (XButtonEvent*)xevent;
-			if (handle_keyevent(buttonevent->button, buttonevent->state, TYPE_MOUSE))
-				return GDK_FILTER_REMOVE;
-			break;
-		}
-	default:
-		return -1;
-	}
-	
-	return GDK_FILTER_CONTINUE;
-}
-
-static gboolean
-setup_filter()
-{
-	gdk_window_add_filter(gdk_get_default_root_window(),
-				gdk_filter,
-				NULL);
-
-	return TRUE;
-}
-
-static void release_filter()
-{
-	gdk_window_remove_filter(gdk_get_default_root_window(),
-				gdk_filter,
-				NULL);
-}
-
 /* load plugin configuration */
-static void load_config (void)
+void load_config (void)
 {
 	ConfigDb *cfdb;
 	
-	if (xdisplay == NULL) x_display_init();
-
 	/* default volume level */
 	plugin_cfg.vol_increment = 4;
 	plugin_cfg.vol_decrement = 4;
 
 #define load_key(hotkey,default) \
-	plugin_cfg.hotkey.key = (default)?(XKeysymToKeycode(xdisplay, (default))):0; \
+	plugin_cfg.hotkey.key = (default)?(XKeysymToKeycode(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), (default))):0; \
 	plugin_cfg.hotkey.mask = 0; \
 	plugin_cfg.hotkey.type = TYPE_KEY; \
 	aud_cfg_db_get_int (cfdb, "globalHotkey", #hotkey, &plugin_cfg.hotkey.key); \
@@ -476,7 +310,7 @@
 }
 
 /* save plugin configuration */
-static void save_config (void)
+void save_config (void)
 {
 	ConfigDb *cfdb;
 
@@ -505,633 +339,6 @@
 	aud_cfg_db_close (cfdb);
 }
 
-static int x11_error_handler (Display *dpy, XErrorEvent *error)
-{
-	return 0;
-}
-
-/* grab required keys */
-static void grab_key(HotkeyConfiguration hotkey)
-{
-	unsigned int modifier = hotkey.mask & ~(numlock_mask | capslock_mask | scrolllock_mask);
-	
-	if (hotkey.key == 0) return;
-
-	if (hotkey.type == TYPE_KEY)
-	{
-		XGrabKey (xdisplay, hotkey.key, modifier, x_root_window,
-			False, GrabModeAsync, GrabModeAsync);
-		
-		if (modifier == AnyModifier)
-			return;
-		
-		if (numlock_mask)
-			XGrabKey (xdisplay, hotkey.key, modifier | numlock_mask,
-				x_root_window,
-				False, GrabModeAsync, GrabModeAsync);
-		
-		if (capslock_mask)
-			XGrabKey (xdisplay, hotkey.key, modifier | capslock_mask,
-				x_root_window,
-				False, GrabModeAsync, GrabModeAsync);
-		
-		if (scrolllock_mask)
-			XGrabKey (xdisplay, hotkey.key, modifier | scrolllock_mask,
-				x_root_window,
-				False, GrabModeAsync, GrabModeAsync);
-		
-		if (numlock_mask && capslock_mask)
-			XGrabKey (xdisplay, hotkey.key, modifier | numlock_mask | capslock_mask,
-				x_root_window,
-				False, GrabModeAsync, GrabModeAsync);
-		
-		if (numlock_mask && scrolllock_mask)
-			XGrabKey (xdisplay, hotkey.key, modifier | numlock_mask | scrolllock_mask,
-				x_root_window,
-				False, GrabModeAsync, GrabModeAsync);
-		
-		if (capslock_mask && scrolllock_mask)
-			XGrabKey (xdisplay, hotkey.key, modifier | capslock_mask | scrolllock_mask,
-				x_root_window,
-				False, GrabModeAsync, GrabModeAsync);
-		
-		if (numlock_mask && capslock_mask && scrolllock_mask)
-			XGrabKey (xdisplay, hotkey.key,
-				modifier | numlock_mask | capslock_mask | scrolllock_mask,
-				x_root_window, False, GrabModeAsync,
-				GrabModeAsync);
-	}
-	if (hotkey.type == TYPE_MOUSE)
-	{
-		XGrabButton (xdisplay, hotkey.key, modifier, x_root_window,
-			False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
-		
-		if (modifier == AnyModifier)
-			return;
-		
-		if (numlock_mask)
-			XGrabButton (xdisplay, hotkey.key, modifier | numlock_mask,
-				x_root_window,
-				False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
-		
-		if (capslock_mask)
-			XGrabButton (xdisplay, hotkey.key, modifier | capslock_mask,
-				x_root_window,
-				False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
-		
-		if (scrolllock_mask)
-			XGrabButton (xdisplay, hotkey.key, modifier | scrolllock_mask,
-				x_root_window,
-				False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
-		
-		if (numlock_mask && capslock_mask)
-			XGrabButton (xdisplay, hotkey.key, modifier | numlock_mask | capslock_mask,
-				x_root_window,
-				False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
-		
-		if (numlock_mask && scrolllock_mask)
-			XGrabButton (xdisplay, hotkey.key, modifier | numlock_mask | scrolllock_mask,
-				x_root_window,
-				False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
-		
-		if (capslock_mask && scrolllock_mask)
-			XGrabButton (xdisplay, hotkey.key, modifier | capslock_mask | scrolllock_mask,
-				x_root_window,
-				False, ButtonPressMask, GrabModeAsync, GrabModeAsync, None, None);
-		
-		if (numlock_mask && capslock_mask && scrolllock_mask)
-			XGrabButton (xdisplay, hotkey.key,
-				modifier | numlock_mask | capslock_mask | scrolllock_mask,
-				x_root_window, False, ButtonPressMask, GrabModeAsync,
-				GrabModeAsync, None, None);
-	}
-}
-
-static void grab_keys ()
-{
-	if (grabbed) return;
-	if (xdisplay == NULL) x_display_init();
-
-	XErrorHandler old_handler = 0;
-
-	XSync(xdisplay, False);
-	old_handler = XSetErrorHandler (x11_error_handler);
-
-	grab_key(plugin_cfg.mute);
-	grab_key(plugin_cfg.vol_up);
-	grab_key(plugin_cfg.vol_down);
-	grab_key(plugin_cfg.play);
-	grab_key(plugin_cfg.pause);
-	grab_key(plugin_cfg.stop);
-	grab_key(plugin_cfg.prev_track);
-	grab_key(plugin_cfg.next_track);
-	grab_key(plugin_cfg.jump_to_file);
-	grab_key(plugin_cfg.forward);
-	grab_key(plugin_cfg.backward);
-	grab_key(plugin_cfg.toggle_win);
-	grab_key(plugin_cfg.show_aosd);
-	
-	XSync(xdisplay, False);
-	XSetErrorHandler (old_handler);
-
-	grabbed = 1;
-}
-/*
- * plugin init end
- */
-
-static void set_keytext (GtkWidget *entry, gint key, gint mask, gint type)
-{
-	gchar *text = NULL;
-
-	if (key == 0 && mask == 0)
-	{
-		text = g_strdup(_("(none)"));
-	} else {
-		static char *modifier_string[] = { "Control", "Shift", "Alt", "Mod2", "Mod3", "Super", "Mod5" };
-		static unsigned int modifiers[] = { ControlMask, ShiftMask, Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask };
-		gchar *strings[9];
-		gchar *keytext = NULL;
-		int i, j;
-		if (type == TYPE_KEY)
-		{
-			KeySym keysym;
-			keysym = XKeycodeToKeysym(xdisplay, key, 0);
-			if (keysym == 0 || keysym == NoSymbol)
-			{
-				keytext = g_strdup_printf("#%d", key);
-			} else {
-				keytext = g_strdup(XKeysymToString(keysym));
-			}
-		}
-		if (type == TYPE_MOUSE)
-		{
-			keytext = g_strdup_printf("Button%d", key);
-		}
-
-		for (i = 0, j=0; j<7; j++)
-		{
-			if (mask & modifiers[j])
- 				strings[i++] = modifier_string[j];
-		}
-		if (key != 0) strings[i++] = keytext;
-		strings[i] = NULL;
-
-		text = g_strjoinv(" + ", strings);
-		g_free(keytext);
-	}
-
-	gtk_entry_set_text(GTK_ENTRY(entry), text);
-	gtk_editable_set_position(GTK_EDITABLE(entry), -1);
-	if (text) g_free(text);
-}
-
-static gboolean
-on_entry_key_press_event(GtkWidget * widget,
-                         GdkEventKey * event,
-                         gpointer user_data)
-{
-	KeyControls *controls = (KeyControls*) user_data;
-	int is_mod;
-	int mod;
-
-	if (event->keyval == GDK_Tab) return FALSE;
-
-	mod = 0;
-	is_mod = 0;
-
-	if ((event->state & GDK_CONTROL_MASK) | (!is_mod && (is_mod = (event->keyval == GDK_Control_L || event->keyval == GDK_Control_R))))
-        	mod |= ControlMask;
-
-	if ((event->state & GDK_MOD1_MASK) | (!is_mod && (is_mod = (event->keyval == GDK_Alt_L || event->keyval == GDK_Alt_R))))
-        	mod |= Mod1Mask;
-
-	if ((event->state & GDK_SHIFT_MASK) | (!is_mod && (is_mod = (event->keyval == GDK_Shift_L || event->keyval == GDK_Shift_R))))
-        	mod |= ShiftMask;
-
-	if ((event->state & GDK_MOD5_MASK) | (!is_mod && (is_mod = (event->keyval == GDK_ISO_Level3_Shift))))
-        	mod |= Mod5Mask;
-
-	if ((event->state & GDK_MOD4_MASK) | (!is_mod && (is_mod = (event->keyval == GDK_Super_L || event->keyval == GDK_Super_R))))
-        	mod |= Mod4Mask;
-
-	if (!is_mod) {
-		controls->hotkey.key = event->hardware_keycode;
-		controls->hotkey.mask = mod;
-		controls->hotkey.type = TYPE_KEY;
-	} else controls->hotkey.key = 0;
-
-	set_keytext(controls->keytext, is_mod ? 0 : event->hardware_keycode, mod, TYPE_KEY);
-	return TRUE;
-}
-
-static gboolean
-on_entry_key_release_event(GtkWidget * widget,
-                           GdkEventKey * event,
-                           gpointer user_data)
-{
-	KeyControls *controls = (KeyControls*) user_data;
-	if (controls->hotkey.key == 0) {
-		controls->hotkey.mask = 0;
-		return TRUE;
-	}
-	set_keytext(controls->keytext, controls->hotkey.key, controls->hotkey.mask, controls->hotkey.type);
-	return TRUE;
-}
-
-static gboolean
-on_entry_button_press_event(GtkWidget * widget,
-                            GdkEventButton * event,
-                            gpointer user_data)
-{
-	KeyControls *controls = (KeyControls*) user_data;
-	int mod;
-	
-	if (!gtk_widget_is_focus(widget)) return FALSE;
-
-	mod = 0;
-	if (event->state & GDK_CONTROL_MASK)
-        	mod |= ControlMask;
-
-	if (event->state & GDK_MOD1_MASK)
-        	mod |= Mod1Mask;
-
-	if (event->state & GDK_SHIFT_MASK)
-        	mod |= ShiftMask;
-
-	if (event->state & GDK_MOD5_MASK)
-        	mod |= Mod5Mask;
-
-	if (event->state & GDK_MOD4_MASK)
-        	mod |= Mod4Mask;
-
-	if ((event->button <= 3) && (mod == 0))
-	{
-		GtkWidget* dialog;
-		GtkResponseType response;
-		dialog = gtk_message_dialog_new (GTK_WINDOW(gtk_widget_get_toplevel(widget)),
-			GTK_DIALOG_MODAL,
-			GTK_MESSAGE_WARNING,
-			GTK_BUTTONS_YES_NO,
-			_("It is not recommended to bind the primary mouse buttons without modificators.\n\n"
-			  "Do you want to continue?"));
-		gtk_window_set_title(GTK_WINDOW(dialog), _("Binding mouse buttons"));
-		response = gtk_dialog_run(GTK_DIALOG(dialog));
-		gtk_widget_destroy (dialog);
-		if (response != GTK_RESPONSE_YES) return TRUE;
-	}
-
-	controls->hotkey.key = event->button;
-	controls->hotkey.mask = mod;
-        controls->hotkey.type = TYPE_MOUSE;
-	set_keytext(controls->keytext, controls->hotkey.key, controls->hotkey.mask, controls->hotkey.type);
-	return TRUE;
-}
-
-static gboolean
-on_entry_scroll_event(GtkWidget * widget,
-                            GdkEventScroll * event,
-                            gpointer user_data)
-{
-	KeyControls *controls = (KeyControls*) user_data;
-	int mod;
-	
-	if (!gtk_widget_is_focus(widget)) return FALSE;
-
-	mod = 0;
-	if (event->state & GDK_CONTROL_MASK)
-        	mod |= ControlMask;
-
-	if (event->state & GDK_MOD1_MASK)
-        	mod |= Mod1Mask;
-
-	if (event->state & GDK_SHIFT_MASK)
-        	mod |= ShiftMask;
-
-	if (event->state & GDK_MOD5_MASK)
-        	mod |= Mod5Mask;
-
-	if (event->state & GDK_MOD4_MASK)
-        	mod |= Mod4Mask;
-
-	if (event->direction == GDK_SCROLL_UP)
-		controls->hotkey.key = 4;
-	else if (event->direction == GDK_SCROLL_DOWN)
-		controls->hotkey.key = 5;
-	else if (event->direction == GDK_SCROLL_LEFT)
-		controls->hotkey.key = 6;
-	else if (event->direction == GDK_SCROLL_RIGHT)
-		controls->hotkey.key = 7;
-	else return FALSE;
-
-	controls->hotkey.mask = mod;
-        controls->hotkey.type = TYPE_MOUSE;
-	set_keytext(controls->keytext, controls->hotkey.key, controls->hotkey.mask, controls->hotkey.type);
-	return TRUE;
-}
-
-static void add_event_controls(GtkWidget *table, 
-				KeyControls *controls, 
-				int row, 
-				char* descr,
-				char* tooltip,
-				HotkeyConfiguration hotkey)
-{
-	GtkWidget *label;
-	GtkWidget *button;
-
-	controls->hotkey.key = hotkey.key;
-	controls->hotkey.mask = hotkey.mask;
-	controls->hotkey.type = hotkey.type;
-	if (controls->hotkey.key == 0)
-		controls->hotkey.mask = 0;
-
-	label = gtk_label_new (_(descr));
-	gtk_table_attach (GTK_TABLE (table), label, 0, 1, row, row+1, 
-			(GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
-	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
-	gtk_misc_set_padding (GTK_MISC (label), 3, 3);
-	
-	controls->keytext = gtk_entry_new ();
-	gtk_table_attach (GTK_TABLE (table), controls->keytext, 1, 2, row, row+1, 
-			(GtkAttachOptions) (GTK_FILL|GTK_EXPAND), (GtkAttachOptions) (GTK_EXPAND), 0, 0);
-	gtk_entry_set_editable (GTK_ENTRY (controls->keytext), FALSE);
-
-	set_keytext(controls->keytext, hotkey.key, hotkey.mask, hotkey.type);
-	g_signal_connect((gpointer)controls->keytext, "key_press_event",
-                         G_CALLBACK(on_entry_key_press_event), controls);
-	g_signal_connect((gpointer)controls->keytext, "key_release_event",
-                         G_CALLBACK(on_entry_key_release_event), controls);
-	g_signal_connect((gpointer)controls->keytext, "button_press_event",
-                         G_CALLBACK(on_entry_button_press_event), controls);
-	g_signal_connect((gpointer)controls->keytext, "scroll_event",
-                         G_CALLBACK(on_entry_scroll_event), controls);
-
-	button = gtk_button_new_with_label (_("None"));
-	gtk_table_attach (GTK_TABLE (table), button, 2, 3, row, row+1, (GtkAttachOptions) (GTK_FILL), (GtkAttachOptions) (0), 0, 0);
-	g_signal_connect (G_OBJECT (button), "clicked",
-			G_CALLBACK (clear_keyboard), controls);
-
-	if (tooltip != NULL) {
-		GtkTooltips *tip = gtk_tooltips_new();
-		gtk_tooltips_set_tip(tip, controls->keytext, tooltip, NULL);
-		gtk_tooltips_set_tip(tip, button, tooltip, NULL);
-		gtk_tooltips_set_tip(tip, label, tooltip, NULL);
-	}
-}
-
-/* configuration window */
-static void configure (void)
-{
-	ConfigurationControls *controls;
-	GtkWidget *window;
-	GtkWidget *main_vbox, *vbox;
-	GtkWidget *hbox;
-	GtkWidget *alignment;
-	GtkWidget *frame;
-	GtkWidget *label;
-	GtkWidget *image;
-	GtkWidget *table;
-	GtkWidget *button_box, *button;
-	
-	if (!xdisplay) x_display_init();
-
-	load_config ( );
-
-	ungrab_keys();
-	
-	controls = (ConfigurationControls*)g_malloc(sizeof(ConfigurationControls));
-	if (!controls)
-	{
-		printf ("Faild to allocate memory for ConfigurationControls structure!\n"
-			"Aborting!");
-		return;
-	}
-	
-	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-	gtk_window_set_title (GTK_WINDOW (window), _("Global Hotkey Plugin Configuration"));
-	gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER_ALWAYS);
-	gtk_window_set_type_hint (GTK_WINDOW (window), GDK_WINDOW_TYPE_HINT_DIALOG);
-	gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
-	gtk_container_set_border_width (GTK_CONTAINER (window), 5);
-	
-	main_vbox = gtk_vbox_new (FALSE, 4);
-	gtk_container_add (GTK_CONTAINER (window), main_vbox);
-	
-	alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
-	gtk_box_pack_start (GTK_BOX (main_vbox), alignment, FALSE, TRUE, 0);
-	gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 4, 0, 0, 0);
-	hbox = gtk_hbox_new (FALSE, 2);
-	gtk_container_add (GTK_CONTAINER (alignment), hbox);
-	image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO, GTK_ICON_SIZE_DIALOG);
-	gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0);
-	label = gtk_label_new (_("Press a key combination inside a text field."));
-	gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
-	gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
-	
-	label = gtk_label_new (NULL);
-	gtk_label_set_markup (GTK_LABEL (label), _("<b>Playback:</b>"));
-	frame = gtk_frame_new (NULL);
-	gtk_frame_set_label_widget (GTK_FRAME (frame), label);
-	gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, TRUE, 0);
-	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
-	alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
-	gtk_container_add (GTK_CONTAINER (frame), alignment);
-	gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 3, 3, 3, 3);
-	vbox = gtk_vbox_new (FALSE, 2);
-	gtk_container_add (GTK_CONTAINER (alignment), vbox);
-	label = gtk_label_new (NULL);
-	gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0);
-	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
-	gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
-	gtk_label_set_markup (GTK_LABEL (label), 
-			_("<i>Configure keys which controls Audacious playback.</i>"));
-	table = gtk_table_new (4, 3, FALSE);
-	gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
-	gtk_table_set_col_spacings (GTK_TABLE (table), 2);
-	gtk_table_set_row_spacings (GTK_TABLE (table), 2);
-
-	/* prev track */
-	add_event_controls(table, &controls->prev_track, 0, _("Previous Track:"), NULL, 
-			plugin_cfg.prev_track);
-
-	add_event_controls(table, &controls->play, 1, _("Play:"), NULL, 
-			plugin_cfg.play);
-
-	add_event_controls(table, &controls->pause, 2, _("Pause/Resume:"), NULL,
-			plugin_cfg.pause);
-
-	add_event_controls(table, &controls->stop, 3, _("Stop:"), NULL,
-			plugin_cfg.stop);
-
-	add_event_controls(table, &controls->next_track, 4, _("Next Track:"), NULL,
-			plugin_cfg.next_track);
-
-	add_event_controls(table, &controls->forward, 5, _("Forward 5 sec.:"), NULL,
-			plugin_cfg.forward);
-
-	add_event_controls(table, &controls->backward, 6, _("Rewind 5 sec.:"), NULL,
-			plugin_cfg.backward);
-
-
-	label = gtk_label_new (NULL);
-	gtk_label_set_markup (GTK_LABEL (label), _("<b>Volume Control:</b>"));
-	frame = gtk_frame_new (NULL);
-	gtk_frame_set_label_widget (GTK_FRAME (frame), label);
-	gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, TRUE, 0);
-	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
-	alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
-	gtk_container_add (GTK_CONTAINER (frame), alignment);
-	gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 3, 3, 3, 3);
-	vbox = gtk_vbox_new (FALSE, 2);
-	gtk_container_add (GTK_CONTAINER (alignment), vbox);
-	label = gtk_label_new (NULL);
-	gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0);
-	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
-	gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
-	gtk_label_set_markup (GTK_LABEL (label), 
-			_("<i>Configure keys which controls music volume.</i>"));
-	table = gtk_table_new (3, 3, FALSE);
-	gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
-	gtk_table_set_col_spacings (GTK_TABLE (table), 2);
-	gtk_table_set_row_spacings (GTK_TABLE (table), 2);
-
-	add_event_controls(table, &controls->mute, 0, _("Mute:"),NULL, 
-			plugin_cfg.mute);
-
-	add_event_controls(table, &controls->vol_up, 1, _("Volume Up:"), NULL,
-			plugin_cfg.vol_up);
-
-	add_event_controls(table, &controls->vol_down, 2, _("Volume Down:"), NULL,
-			plugin_cfg.vol_down);
-
-
-	label = gtk_label_new (NULL);
-	gtk_label_set_markup (GTK_LABEL (label), _("<b>Player:</b>"));
-	frame = gtk_frame_new (NULL);
-	gtk_frame_set_label_widget (GTK_FRAME (frame), label);
-	gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, TRUE, 0);
-	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
-	alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
-	gtk_container_add (GTK_CONTAINER (frame), alignment);
-	gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 3, 3, 3, 3);
-	vbox = gtk_vbox_new (FALSE, 2);
-	gtk_container_add (GTK_CONTAINER (alignment), vbox);
-	label = gtk_label_new (NULL);
-	gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0);
-	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_CENTER);
-	gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
-	gtk_label_set_markup (GTK_LABEL (label), 
-			_("<i>Configure keys which control the player.</i>"));
-	table = gtk_table_new (3, 3, FALSE);
-	gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
-	gtk_table_set_col_spacings (GTK_TABLE (table), 2);
-	gtk_table_set_row_spacings (GTK_TABLE (table), 2);
-
-	add_event_controls(table, &controls->jump_to_file, 0, _("Jump to File:"), NULL,
-			plugin_cfg.jump_to_file);
-
-	add_event_controls(table, &controls->toggle_win, 1, _("Toggle Player Windows:"), NULL,
-			plugin_cfg.toggle_win);
-
-	add_event_controls(table, &controls->show_aosd, 2, _("Show On-Screen-Display:"), 
-			_("For this, the Audacious OSD plugin must be activated."),
-			plugin_cfg.show_aosd);
-
-	button_box = gtk_hbutton_box_new ( );
-	gtk_box_pack_start (GTK_BOX (main_vbox), button_box, FALSE, TRUE, 6);
-	gtk_button_box_set_layout (GTK_BUTTON_BOX (button_box), GTK_BUTTONBOX_END);
-	gtk_box_set_spacing (GTK_BOX (button_box), 4);
-	
-	button = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
-	gtk_container_add (GTK_CONTAINER (button_box), button);
-	g_signal_connect (G_OBJECT (button), "clicked",
-			G_CALLBACK (cancel_callback), controls);
-	
-	button = gtk_button_new_from_stock (GTK_STOCK_OK);
-	gtk_container_add (GTK_CONTAINER (button_box), button);
-	g_signal_connect (G_OBJECT (button), "clicked",
-			G_CALLBACK (ok_callback), controls);
-	
-	gtk_widget_show_all (GTK_WIDGET (window));
-}
-/* configuration window end */
-
-static void about (void)
-{
-	static GtkWidget *dialog;
-
-	dialog = audacious_info_dialog (_("About Global Hotkey Plugin"),
-				_("Global Hotkey Plugin\n"
-				"Control the player with global key combinations or multimedia keys.\n\n"
-				"Copyright (C) 2007-2008 Sascha Hlusiak <contact@saschahlusiak.de>\n\n"
-				"Contributers include:\n"
-				"Copyright (C) 2006-2007 Vladimir Paskov <vlado.paskov@gmail.com>\n"
-				"Copyright (C) 2000-2002 Ville Syrjälä <syrjala@sci.fi>\n"
-                         	"			Bryn Davies <curious@ihug.com.au>\n"
-                        	"			Jonathan A. Davis <davis@jdhouse.org>\n"
-                         	"			Jeremy Tan <nsx@nsx.homeip.net>\n\n"
-                         	),
-                         	_("OK"), TRUE, NULL, NULL);
-
-	gtk_signal_connect(GTK_OBJECT(dialog), "destroy",
-			   GTK_SIGNAL_FUNC(gtk_widget_destroyed), &dialog);						
-}
-
-/* Clear keys */
-static void clear_keyboard (GtkWidget *widget, gpointer data)
-{
-	KeyControls *spins = (KeyControls*)data;
-	spins->hotkey.key = 0;
-	spins->hotkey.mask = 0;
-	spins->hotkey.type = TYPE_KEY;
-	set_keytext(spins->keytext, 0, 0, TYPE_KEY);
-}
-
-void cancel_callback (GtkWidget *widget, gpointer data)
-{
-	if (loaded)
-	{
-		grab_keys ();
-	}
-	if (data) g_free(data);
-
-	gtk_widget_destroy (gtk_widget_get_toplevel (GTK_WIDGET (widget)));
-}
-
-void ok_callback (GtkWidget *widget, gpointer data)
-{
-	ConfigurationControls *controls= (ConfigurationControls*)data;
-	
-	plugin_cfg.play = controls->play.hotkey;
-	plugin_cfg.pause = controls->pause.hotkey;
-	plugin_cfg.stop= controls->stop.hotkey;
-	plugin_cfg.prev_track= controls->prev_track.hotkey;
-	plugin_cfg.next_track = controls->next_track.hotkey;
-	plugin_cfg.forward = controls->forward.hotkey;
-	plugin_cfg.backward = controls->backward.hotkey;
-	plugin_cfg.vol_up= controls->vol_up.hotkey;
-	plugin_cfg.vol_down = controls->vol_down.hotkey;
-	plugin_cfg.mute = controls->mute.hotkey;
-	plugin_cfg.jump_to_file= controls->jump_to_file.hotkey;
-	plugin_cfg.toggle_win = controls->toggle_win.hotkey;
-	plugin_cfg.show_aosd = controls->show_aosd.hotkey;
-	
-	save_config ( );
-	
-	if (loaded)
-	{
-		grab_keys ();
-	}
-
-	if (data) g_free(data);
-	
-	gtk_widget_destroy (gtk_widget_get_toplevel (GTK_WIDGET (widget)));
-}
-
-/* 
- * plugin cleanup 
- */
 static void cleanup (void)
 {
 	if (!loaded) return;
@@ -1140,97 +347,7 @@
 	loaded = FALSE;
 }
 
-/* grab required keys */
-static void ungrab_key(HotkeyConfiguration hotkey)
+gboolean is_loaded (void)
 {
-	unsigned int modifier = hotkey.mask & ~(numlock_mask | capslock_mask | scrolllock_mask);
-	
-	if (hotkey.key == 0) return;
-	
-	if (hotkey.type == TYPE_KEY)
-	{
-		XUngrabKey (xdisplay, hotkey.key, modifier, x_root_window);
-		
-		if (modifier == AnyModifier)
-			return;
-		
-		if (numlock_mask)
-			XUngrabKey (xdisplay, hotkey.key, modifier | numlock_mask, x_root_window);
-	
-		if (capslock_mask)
-			XUngrabKey (xdisplay, hotkey.key, modifier | capslock_mask, x_root_window);
-	
-		if (scrolllock_mask)
-			XUngrabKey (xdisplay, hotkey.key, modifier | scrolllock_mask, x_root_window);
-	
-		if (numlock_mask && capslock_mask)
-			XUngrabKey (xdisplay, hotkey.key, modifier | numlock_mask | capslock_mask, x_root_window);
-	
-		if (numlock_mask && scrolllock_mask)
-			XUngrabKey (xdisplay, hotkey.key, modifier | numlock_mask | scrolllock_mask, x_root_window);
-	
-		if (capslock_mask && scrolllock_mask)
-			XUngrabKey (xdisplay, hotkey.key, modifier | capslock_mask | scrolllock_mask, x_root_window);
-	
-		if (numlock_mask && capslock_mask && scrolllock_mask)
-			XUngrabKey (xdisplay, hotkey.key, modifier | numlock_mask | capslock_mask | scrolllock_mask, x_root_window);
-	}
-	if (hotkey.type == TYPE_MOUSE)
-	{
-		XUngrabButton (xdisplay, hotkey.key, modifier, x_root_window);
-		
-		if (modifier == AnyModifier)
-			return;
-		
-		if (numlock_mask)
-			XUngrabButton (xdisplay, hotkey.key, modifier | numlock_mask, x_root_window);
-	
-		if (capslock_mask)
-			XUngrabButton (xdisplay, hotkey.key, modifier | capslock_mask, x_root_window);
-	
-		if (scrolllock_mask)
-			XUngrabButton (xdisplay, hotkey.key, modifier | scrolllock_mask, x_root_window);
-	
-		if (numlock_mask && capslock_mask)
-			XUngrabButton (xdisplay, hotkey.key, modifier | numlock_mask | capslock_mask, x_root_window);
-	
-		if (numlock_mask && scrolllock_mask)
-			XUngrabButton (xdisplay, hotkey.key, modifier | numlock_mask | scrolllock_mask, x_root_window);
-	
-		if (capslock_mask && scrolllock_mask)
-			XUngrabButton (xdisplay, hotkey.key, modifier | capslock_mask | scrolllock_mask, x_root_window);
-	
-		if (numlock_mask && capslock_mask && scrolllock_mask)
-			XUngrabButton (xdisplay, hotkey.key, modifier | numlock_mask | capslock_mask | scrolllock_mask, x_root_window);
-	}
+	return loaded;
 }
-
-static void ungrab_keys ()
-{
-	XErrorHandler old_handler = 0;
-
-	if (!grabbed) return;
-	if (!xdisplay) return;
-
-	XSync(xdisplay, False);
-	old_handler = XSetErrorHandler (x11_error_handler);
-
-	ungrab_key(plugin_cfg.mute);
-	ungrab_key(plugin_cfg.vol_up);
-	ungrab_key(plugin_cfg.vol_down);
-	ungrab_key(plugin_cfg.play);
-	ungrab_key(plugin_cfg.pause);
-	ungrab_key(plugin_cfg.stop);
-	ungrab_key(plugin_cfg.prev_track);
-	ungrab_key(plugin_cfg.next_track);
-	ungrab_key(plugin_cfg.jump_to_file);
-	ungrab_key(plugin_cfg.forward);
-	ungrab_key(plugin_cfg.backward);
-	ungrab_key(plugin_cfg.toggle_win);
-	ungrab_key(plugin_cfg.show_aosd);
-	
-	XSync(xdisplay, False);
-	XSetErrorHandler (old_handler);
-
-	grabbed = 0;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotkey/plugin.h	Sun Jan 20 14:52:44 2008 +0100
@@ -0,0 +1,40 @@
+#ifndef _PLUGIN_H_INCLUDED_
+#define _PLUGIN_H_INCLUDED_
+
+#include <glib.h>
+
+#define TYPE_KEY 0
+#define TYPE_MOUSE 1
+
+typedef struct {
+	gint key, mask;
+	gint type;
+} HotkeyConfiguration;
+
+typedef struct {
+	gint vol_increment;
+	gint vol_decrement;
+	
+	/* keyboard */
+	HotkeyConfiguration mute;
+	HotkeyConfiguration vol_down;
+	HotkeyConfiguration vol_up;
+	HotkeyConfiguration play;
+	HotkeyConfiguration stop;
+	HotkeyConfiguration pause;
+	HotkeyConfiguration prev_track;
+	HotkeyConfiguration next_track;
+	HotkeyConfiguration jump_to_file;
+	HotkeyConfiguration toggle_win;
+	HotkeyConfiguration forward;
+	HotkeyConfiguration backward;
+	HotkeyConfiguration show_aosd;
+} PluginConfig;
+
+void load_config (void);
+void save_config (void);
+PluginConfig* get_config(void);
+gboolean is_loaded (void);
+gboolean handle_keyevent(int keycode, int state, int type);
+
+#endif