Mercurial > audlegacy-plugins
view src/hotkey/plugin.c @ 1731:38375d565192
branch merge
author | Ralf Ertzinger <ralf@skytale.net> |
---|---|
date | Tue, 18 Sep 2007 18:03:11 +0200 |
parents | f6f5603a0954 |
children | b8da6a0b0da2 |
line wrap: on
line source
/* -*- Mode: C; indent-tabs: t; c-basic-offset: 9; tab-width: 9 -*- */ /* * This file is part of audacious-hotkey plugin for audacious * * Copyright (c) 2007 Sascha Hlusiak <contact@saschahlusiak.de> * Name: plugin.c * Description: plugin.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 <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> /* 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); 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); typedef struct { gint vol_increment; gint vol_decrement; /* keyboard */ gint mute, mute_mask; gint vol_down, vol_down_mask; gint vol_up, vol_up_mask; gint play, play_mask; gint stop, stop_mask; gint pause, pause_mask; gint prev_track, prev_track_mask; gint next_track, next_track_mask; gint jump_to_file, jump_to_file_mask; gint toggle_win, toggle_win_mask; gint forward, forward_mask; gint backward, backward_mask; } PluginConfig; PluginConfig plugin_cfg; static Display *xdisplay = NULL; static Window x_root_window = 0; static gint grabbed = 0; 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; gint key, mask; } KeyControls; typedef struct { KeyControls play; KeyControls stop; KeyControls pause; KeyControls prev; KeyControls next; KeyControls up; KeyControls down; KeyControls mute; KeyControls jump_to_file; KeyControls forward; KeyControls backward; KeyControls toggle_win; } ConfigurationControls; static GeneralPlugin audacioushotkey = { .description = "Global Hotkey", .init = init, .about = about, .configure = configure, .cleanup = cleanup }; GeneralPlugin *hotkey_gplist[] = { &audacioushotkey, NULL }; SIMPLE_GENERAL_PLUGIN(hotkey, hotkey_gplist); /* * plugin activated */ static void init (void) { x_display_init ( ); setup_filter(); load_config ( ); 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) { gint current_volume, old_volume; static gint volume_static = 0; gboolean play, mute; /* playing or not */ play = audacious_drct_is_playing (); /* get current volume */ audacious_drct_get_volume_main (¤t_volume); old_volume = current_volume; if (current_volume) { /* volume is not mute */ mute = FALSE; } else { /* volume is mute */ mute = TRUE; } state &= ~(scrolllock_mask | numlock_mask | capslock_mask); /* mute the playback */ if ((keycode == plugin_cfg.mute) && (state == plugin_cfg.mute_mask)) { if (!mute) { volume_static = current_volume; audacious_drct_set_main_volume (0); mute = TRUE; } else { audacious_drct_set_main_volume (volume_static); mute = FALSE; } return TRUE; } /* decreace volume */ if ((keycode == plugin_cfg.vol_down) && (state == plugin_cfg.vol_down_mask)) { if (mute) { current_volume = old_volume; old_volume = 0; mute = FALSE; } if ((current_volume -= plugin_cfg.vol_decrement) < 0) { current_volume = 0; } if (current_volume != old_volume) { audacious_drct_set_main_volume (current_volume); } old_volume = current_volume; return TRUE; } /* increase volume */ if ((keycode == plugin_cfg.vol_up) && (state == plugin_cfg.vol_up_mask)) { if (mute) { current_volume = old_volume; old_volume = 0; mute = FALSE; } if ((current_volume += plugin_cfg.vol_increment) > 100) { current_volume = 100; } if (current_volume != old_volume) { audacious_drct_set_main_volume (current_volume); } old_volume = current_volume; return TRUE; } /* play */ if ((keycode == plugin_cfg.play) && (state == plugin_cfg.play_mask)) { if (!play) { audacious_drct_play (); } else { audacious_drct_pause (); } return TRUE; } /* pause */ if ((keycode == plugin_cfg.pause) && (state == plugin_cfg.pause_mask)) { if (!play) audacious_drct_play (); else audacious_drct_pause (); return TRUE; } /* stop */ if ((keycode == plugin_cfg.stop) && (state == plugin_cfg.stop_mask)) { audacious_drct_stop (); return TRUE; } /* prev track */ if ((keycode == plugin_cfg.prev_track) && (state == plugin_cfg.prev_track_mask)) { audacious_drct_playlist_prev (); return TRUE; } /* next track */ if ((keycode == plugin_cfg.next_track) && (state == plugin_cfg.next_track_mask)) { audacious_drct_playlist_next (); return TRUE; } /* forward */ if ((keycode == plugin_cfg.forward) && (state == plugin_cfg.forward_mask)) { gint time = audacious_drct_get_output_time(); time += 5000; /* Jump 5s into future */ audacious_drct_jump_to_time(time); return TRUE; } /* backward */ if ((keycode == plugin_cfg.backward) && (state == plugin_cfg.backward_mask)) { gint time = audacious_drct_get_output_time(); if (time > 5000) time -= 5000; /* Jump 5s back */ else time = 0; audacious_drct_jump_to_time(time); return TRUE; } /* Open Jump-To-File dialog */ if ((keycode == plugin_cfg.jump_to_file) && (state == plugin_cfg.jump_to_file_mask)) { audacious_drct_show_jtf_box(); return TRUE; } /* Toggle Windows */ if ((keycode == plugin_cfg.toggle_win) && (state == plugin_cfg.toggle_win_mask)) { static gboolean is_main, is_eq, is_pl; is_main = audacious_drct_main_win_is_visible(); if (is_main) { is_pl = audacious_drct_pl_win_is_visible(); is_eq = audacious_drct_eq_win_is_visible(); audacious_drct_main_win_toggle(FALSE); audacious_drct_pl_win_toggle(FALSE); audacious_drct_eq_win_toggle(FALSE); } else { audacious_drct_main_win_toggle(TRUE); audacious_drct_pl_win_toggle(is_pl); audacious_drct_eq_win_toggle(is_eq); } return TRUE; } return FALSE; } static GdkFilterReturn gdk_filter(GdkXEvent *xevent, GdkEvent *event, gpointer data) { XKeyEvent *keyevent = (XKeyEvent*)xevent; if (((XEvent*)keyevent)->type != KeyPress) return -1; if (handle_keyevent(keyevent->keycode, keyevent->state)) return GDK_FILTER_REMOVE; 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) { ConfigDb *cfdb; if (xdisplay == NULL) x_display_init(); /* default volume level */ plugin_cfg.vol_increment = 4; plugin_cfg.vol_decrement = 4; plugin_cfg.mute = XKeysymToKeycode(xdisplay, XF86XK_AudioMute); plugin_cfg.mute_mask = 0; plugin_cfg.vol_down = XKeysymToKeycode(xdisplay, XF86XK_AudioLowerVolume); plugin_cfg.vol_down_mask = 0; plugin_cfg.vol_up = XKeysymToKeycode(xdisplay, XF86XK_AudioRaiseVolume); plugin_cfg.vol_up_mask = 0; plugin_cfg.play = XKeysymToKeycode(xdisplay, XF86XK_AudioPlay); plugin_cfg.play_mask = 0; plugin_cfg.pause = XKeysymToKeycode(xdisplay, XF86XK_AudioPause); plugin_cfg.pause_mask = 0; plugin_cfg.stop = XKeysymToKeycode(xdisplay, XF86XK_AudioStop); plugin_cfg.stop_mask = 0; plugin_cfg.prev_track = XKeysymToKeycode(xdisplay, XF86XK_AudioPrev); plugin_cfg.prev_track_mask = 0; plugin_cfg.next_track = XKeysymToKeycode(xdisplay, XF86XK_AudioNext); plugin_cfg.next_track_mask = 0; plugin_cfg.jump_to_file = XKeysymToKeycode(xdisplay, XF86XK_AudioMedia); plugin_cfg.jump_to_file_mask = 0; plugin_cfg.forward = 0; plugin_cfg.forward_mask = 0; plugin_cfg.backward = XKeysymToKeycode(xdisplay, XF86XK_AudioRewind); plugin_cfg.backward_mask = 0; plugin_cfg.toggle_win = 0; plugin_cfg.toggle_win_mask = 0; /* open configuration database */ cfdb = bmp_cfg_db_open ( ); bmp_cfg_db_get_int (cfdb, "globalHotkey", "mute", &plugin_cfg.mute); bmp_cfg_db_get_int (cfdb, "globalHotkey", "mute_mask", &plugin_cfg.mute_mask); bmp_cfg_db_get_int (cfdb, "globalHotkey", "vol_down", &plugin_cfg.vol_down); bmp_cfg_db_get_int (cfdb, "globalHotkey", "vol_down_mask", &plugin_cfg.vol_down_mask); bmp_cfg_db_get_int (cfdb, "globalHotkey", "vol_up", &plugin_cfg.vol_up); bmp_cfg_db_get_int (cfdb, "globalHotkey", "vol_up_mask", &plugin_cfg.vol_up_mask); bmp_cfg_db_get_int (cfdb, "globalHotkey", "play", &plugin_cfg.play); bmp_cfg_db_get_int (cfdb, "globalHotkey", "play_mask", &plugin_cfg.play_mask); bmp_cfg_db_get_int (cfdb, "globalHotkey", "pause", &plugin_cfg.pause); bmp_cfg_db_get_int (cfdb, "globalHotkey", "pause_mask", &plugin_cfg.pause_mask); bmp_cfg_db_get_int (cfdb, "globalHotkey", "stop", &plugin_cfg.stop); bmp_cfg_db_get_int (cfdb, "globalHotkey", "stop_mask", &plugin_cfg.stop_mask); bmp_cfg_db_get_int (cfdb, "globalHotkey", "prev_track", &plugin_cfg.prev_track); bmp_cfg_db_get_int (cfdb, "globalHotkey", "prev_track_mask", &plugin_cfg.prev_track_mask); bmp_cfg_db_get_int (cfdb, "globalHotkey", "next_track", &plugin_cfg.next_track); bmp_cfg_db_get_int (cfdb, "globalHotkey", "next_track_mask", &plugin_cfg.next_track_mask); bmp_cfg_db_get_int (cfdb, "globalHotkey", "jump_to_file", &plugin_cfg.jump_to_file); bmp_cfg_db_get_int (cfdb, "globalHotkey", "jump_to_file_mask", &plugin_cfg.jump_to_file_mask); bmp_cfg_db_get_int (cfdb, "globalHotkey", "forward", &plugin_cfg.forward); bmp_cfg_db_get_int (cfdb, "globalHotkey", "forward_mask", &plugin_cfg.forward_mask); bmp_cfg_db_get_int (cfdb, "globalHotkey", "backward", &plugin_cfg.backward); bmp_cfg_db_get_int (cfdb, "globalHotkey", "backward_mask", &plugin_cfg.backward_mask); bmp_cfg_db_get_int (cfdb, "globalHotkey", "toggle_win", &plugin_cfg.toggle_win); bmp_cfg_db_get_int (cfdb, "globalHotkey", "toggle_win_mask", &plugin_cfg.toggle_win_mask); bmp_cfg_db_close (cfdb); } /* save plugin configuration */ static void save_config (void) { ConfigDb *cfdb; /* open configuration database */ cfdb = bmp_cfg_db_open ( ); bmp_cfg_db_set_int (cfdb, "globalHotkey", "mute", plugin_cfg.mute); bmp_cfg_db_set_int (cfdb, "globalHotkey", "mute_mask", plugin_cfg.mute_mask); bmp_cfg_db_set_int (cfdb, "globalHotkey", "vol_up", plugin_cfg.vol_up); bmp_cfg_db_set_int (cfdb, "globalHotkey", "vol_up_mask", plugin_cfg.vol_up_mask); bmp_cfg_db_set_int (cfdb, "globalHotkey", "vol_down", plugin_cfg.vol_down); bmp_cfg_db_set_int (cfdb, "globalHotkey", "vol_down_mask", plugin_cfg.vol_down_mask); bmp_cfg_db_set_int (cfdb, "globalHotkey", "play", plugin_cfg.play); bmp_cfg_db_set_int (cfdb, "globalHotkey", "play_mask", plugin_cfg.play_mask); bmp_cfg_db_set_int (cfdb, "globalHotkey", "pause", plugin_cfg.pause); bmp_cfg_db_set_int (cfdb, "globalHotkey", "pause_mask", plugin_cfg.pause_mask); bmp_cfg_db_set_int (cfdb, "globalHotkey", "stop", plugin_cfg.stop); bmp_cfg_db_set_int (cfdb, "globalHotkey", "stop_mask", plugin_cfg.stop_mask); bmp_cfg_db_set_int (cfdb, "globalHotkey", "prev_track", plugin_cfg.prev_track); bmp_cfg_db_set_int (cfdb, "globalHotkey", "prev_track_mask", plugin_cfg.prev_track_mask); bmp_cfg_db_set_int (cfdb, "globalHotkey", "next_track", plugin_cfg.next_track); bmp_cfg_db_set_int (cfdb, "globalHotkey", "next_track_mask", plugin_cfg.next_track_mask); bmp_cfg_db_set_int (cfdb, "globalHotkey", "jump_to_file", plugin_cfg.jump_to_file); bmp_cfg_db_set_int (cfdb, "globalHotkey", "jump_to_file_mask", plugin_cfg.jump_to_file_mask); bmp_cfg_db_set_int (cfdb, "globalHotkey", "forward", plugin_cfg.forward); bmp_cfg_db_set_int (cfdb, "globalHotkey", "forward_mask", plugin_cfg.forward_mask); bmp_cfg_db_set_int (cfdb, "globalHotkey", "backward", plugin_cfg.backward); bmp_cfg_db_set_int (cfdb, "globalHotkey", "backward_mask", plugin_cfg.backward_mask); bmp_cfg_db_set_int (cfdb, "globalHotkey", "toggle_win", plugin_cfg.toggle_win); bmp_cfg_db_set_int (cfdb, "globalHotkey", "toggle_win_mask", plugin_cfg.toggle_win_mask); bmp_cfg_db_close (cfdb); } static int x11_error_handler (Display *dpy, XErrorEvent *error) { return 0; } /* grab requied keys */ static void grab_key(KeyCode keycode, unsigned int modifier) { modifier &= ~(numlock_mask | capslock_mask | scrolllock_mask); XGrabKey (xdisplay, keycode, modifier, x_root_window, False, GrabModeAsync, GrabModeAsync); if (modifier == AnyModifier) return; if (numlock_mask) XGrabKey (xdisplay, keycode, modifier | numlock_mask, x_root_window, False, GrabModeAsync, GrabModeAsync); if (capslock_mask) XGrabKey (xdisplay, keycode, modifier | capslock_mask, x_root_window, False, GrabModeAsync, GrabModeAsync); if (scrolllock_mask) XGrabKey (xdisplay, keycode, modifier | scrolllock_mask, x_root_window, False, GrabModeAsync, GrabModeAsync); if (numlock_mask && capslock_mask) XGrabKey (xdisplay, keycode, modifier | numlock_mask | capslock_mask, x_root_window, False, GrabModeAsync, GrabModeAsync); if (numlock_mask && scrolllock_mask) XGrabKey (xdisplay, keycode, modifier | numlock_mask | scrolllock_mask, x_root_window, False, GrabModeAsync, GrabModeAsync); if (capslock_mask && scrolllock_mask) XGrabKey (xdisplay, keycode, modifier | capslock_mask | scrolllock_mask, x_root_window, False, GrabModeAsync, GrabModeAsync); if (numlock_mask && capslock_mask && scrolllock_mask) XGrabKey (xdisplay, keycode, modifier | numlock_mask | capslock_mask | scrolllock_mask, x_root_window, False, GrabModeAsync, GrabModeAsync); } 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); if (plugin_cfg.mute) grab_key(plugin_cfg.mute, plugin_cfg.mute_mask); if (plugin_cfg.vol_up) grab_key(plugin_cfg.vol_up, plugin_cfg.vol_up_mask); if (plugin_cfg.vol_down) grab_key(plugin_cfg.vol_down, plugin_cfg.vol_down_mask); if (plugin_cfg.play) grab_key(plugin_cfg.play, plugin_cfg.play_mask); if (plugin_cfg.pause) grab_key(plugin_cfg.pause, plugin_cfg.pause_mask); if (plugin_cfg.stop) grab_key(plugin_cfg.stop, plugin_cfg.stop_mask); if (plugin_cfg.prev_track) grab_key(plugin_cfg.prev_track, plugin_cfg.prev_track_mask); if (plugin_cfg.next_track) grab_key(plugin_cfg.next_track, plugin_cfg.next_track_mask); if (plugin_cfg.jump_to_file) grab_key(plugin_cfg.jump_to_file, plugin_cfg.jump_to_file_mask); if (plugin_cfg.forward) grab_key(plugin_cfg.forward, plugin_cfg.forward_mask); if (plugin_cfg.backward) grab_key(plugin_cfg.backward, plugin_cfg.backward_mask); if (plugin_cfg.toggle_win) grab_key(plugin_cfg.toggle_win, plugin_cfg.toggle_win_mask); XSync(xdisplay, False); XSetErrorHandler (old_handler); grabbed = 1; } /* * plugin init end */ static void set_keytext (GtkWidget *entry, gint key, gint mask) { 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; KeySym keysym; keysym = XKeycodeToKeysym(xdisplay, key, 0); if (keysym == 0 || keysym == NoSymbol) { keytext = g_strdup_printf("#%3d", key); } else { keytext = g_strdup(XKeysymToString(keysym)); } 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->key = event->hardware_keycode; controls->mask = mod; } else controls->key = 0; set_keytext(controls->keytext, is_mod ? 0 : event->hardware_keycode, mod); return FALSE; } static gboolean on_entry_key_release_event(GtkWidget * widget, GdkEventKey * event, gpointer user_data) { KeyControls *controls = (KeyControls*) user_data; if (controls->key == 0) { controls->mask = 0; } set_keytext(controls->keytext, controls->key, controls->mask); return FALSE; } static void add_event_controls(GtkWidget *table, KeyControls *controls, int row, char* descr, gint key, gint mask) { GtkWidget *label; GtkWidget *button; controls->key = key; controls->mask = mask; 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, key, mask); 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); 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); } /* 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, 0, _("Previous Track:"), plugin_cfg.prev_track, plugin_cfg.prev_track_mask); add_event_controls(table, &controls->play, 1, _("Play/Pause:"), plugin_cfg.play, plugin_cfg.play_mask); add_event_controls(table, &controls->pause, 2, _("Pause:"), plugin_cfg.pause, plugin_cfg.pause_mask); add_event_controls(table, &controls->stop, 3, _("Stop:"), plugin_cfg.stop, plugin_cfg.stop_mask); add_event_controls(table, &controls->next, 4, _("Next Track:"), plugin_cfg.next_track, plugin_cfg.next_track_mask); add_event_controls(table, &controls->forward, 5, _("Forward 5 sec.:"), plugin_cfg.forward, plugin_cfg.forward_mask); add_event_controls(table, &controls->backward, 6, _("Rewind 5 sec.:"), plugin_cfg.backward, plugin_cfg.backward_mask); 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:"), plugin_cfg.mute, plugin_cfg.mute_mask); add_event_controls(table, &controls->up, 1, _("Volume Up:"), plugin_cfg.vol_up, plugin_cfg.vol_up_mask); add_event_controls(table, &controls->down, 2, _("Volume Down:"), plugin_cfg.vol_down, plugin_cfg.vol_down_mask); 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, 2, 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:"), plugin_cfg.jump_to_file, plugin_cfg.jump_to_file_mask); add_event_controls(table, &controls->toggle_win, 1, _("Toggle Player Windows:"), plugin_cfg.toggle_win, plugin_cfg.toggle_win_mask); 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 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->key = 0; spins->mask = 0; set_keytext(spins->keytext, 0, 0); } 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.key; plugin_cfg.play_mask = controls->play.mask; plugin_cfg.pause = controls->pause.key; plugin_cfg.pause_mask = controls->pause.mask; plugin_cfg.stop = controls->stop.key; plugin_cfg.stop_mask = controls->stop.mask; plugin_cfg.prev_track = controls->prev.key; plugin_cfg.prev_track_mask = controls->prev.mask; plugin_cfg.next_track = controls->next.key; plugin_cfg.next_track_mask = controls->next.mask; plugin_cfg.forward = controls->forward.key; plugin_cfg.forward_mask = controls->forward.mask; plugin_cfg.backward = controls->backward.key; plugin_cfg.backward_mask = controls->backward.mask; plugin_cfg.vol_up = controls->up.key; plugin_cfg.vol_up_mask = controls->up.mask; plugin_cfg.vol_down = controls->down.key; plugin_cfg.vol_down_mask = controls->down.mask; plugin_cfg.mute = controls->mute.key; plugin_cfg.mute_mask = controls->mute.mask; plugin_cfg.jump_to_file = controls->jump_to_file.key; plugin_cfg.jump_to_file_mask = controls->jump_to_file.mask; plugin_cfg.toggle_win= controls->toggle_win.key; plugin_cfg.toggle_win_mask = controls->toggle_win.mask; 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; ungrab_keys (); release_filter(); loaded = FALSE; } static void ungrab_keys () { if (!grabbed) return; if (!xdisplay) return; XUngrabKey (xdisplay, AnyKey, AnyModifier, x_root_window); grabbed = 0; }