diff src/hotkey/gui.c @ 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
children ad45d65e9ae7
line wrap: on
line diff
--- /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);						
+}