Permalink
Browse files

initial attempt at being able to use multimedia keys; requires gcc (a…

…nd python-dev on some distros), and may require pygtk2.8, i need to investigate that
  • Loading branch information...
1 parent 730e62e commit 54c65e0c7af43fc28a787494b12727e48235de3f Scott Horowitz committed Sep 18, 2006
Showing with 910 additions and 5 deletions.
  1. +1 −0 TODO
  2. +340 −0 mmkeys/COPYING
  3. +26 −0 mmkeys/Makefile
  4. +36 −0 mmkeys/README
  5. +237 −0 mmkeys/mmkeys.c
  6. +19 −0 mmkeys/mmkeys.defs
  7. +55 −0 mmkeys/mmkeys.h
  8. +15 −0 mmkeys/mmkeys.override
  9. +20 −0 mmkeys/mmkeysmodule.c
  10. +126 −0 mmkeys/mmkeyspy.c
  11. +11 −1 setup.py
  12. +24 −4 sonata.py
View
1 TODO
@@ -2,6 +2,7 @@
optional statusbar (num songs, total length)
dbus - show previous instance if user tries to launch another
support for multimedia keys (possible in pure pygtk? nope)
+ - requires gcc, python-dev (and pygtk 2.8?)
pref to autoplay when using 'replace'?
Future:
View

Large diffs are not rendered by default.

Oops, something went wrong.
View
@@ -0,0 +1,26 @@
+# Copyright 2004 Joe Wreschnig. Released under the terms of the GNU GPL.
+
+PYTHON_DIR = /usr/include/python2.4/
+
+CFLAGS += -fPIC -O2 `pkg-config --cflags gtk+-2.0 pygtk-2.0` -I$(PYTHON_DIR)
+LDFLAGS += `pkg-config --libs gtk+-2.0 pygtk-2.0`
+
+mmkeys.so: mmkeyspy.o mmkeys.o mmkeysmodule.o
+ $(CC) $(LDFLAGS) -shared $^ -o $@
+ strip mmkeys.so
+
+DEFS=`pkg-config --variable=defsdir pygtk-2.0`
+
+mmkeyspy.c: mmkeys.defs mmkeys.override
+ pygtk-codegen-2.0 --prefix mmkeys \
+ --register $(DEFS)/gdk-types.defs \
+ --register $(DEFS)/gtk-types.defs \
+ --override mmkeys.override \
+ mmkeys.defs > gen-tmp
+ mv gen-tmp $@
+
+clean:
+ rm -f mmkeys.so *.o mmkeyspy.c
+
+distclean: clean
+ rm -f *~ gen-tmp
View
@@ -0,0 +1,36 @@
+Multimedia Key support as a PyGTK object
+----------------------------------------
+This module lets you access multimedia keys found on most new keyboards
+from Python; most important it grabs all input events so your program
+doesn't need to be in focus when the key is pressed (which is the
+usual behavior of the keys). You still need something like Acme or
+xmodmap to map the keys before using them.
+
+This code comes from the mmkeys object found in the Muine media player.
+
+Compiling:
+----------
+(Requires the PyGTK and Python development libraries.)
+$ make mmkeys.so
+
+Usage:
+------
+import mmkeys
+keys = mmkeys.Mmkeys()
+keys.connect("mm_prev", previous_cb)
+keys.connect("mm_next", next_cb)
+keys.connect("mm_playpause", playpause_cb)
+
+Make sure the reference to 'keys' sticks around; if it falls out of scope
+it can get GCd and cause segfaults.
+
+License:
+--------
+Copyright (C) 2004 Lee Willis <lee@leewillis.co.uk>
+Borrowed heavily from code by Jan Arne Petersen <jpetersen@uni-bonn.de>
+Python bindings by Joe Wreschnig <piman@sacredchao.net>
+
+This program 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.
View
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2004 Lee Willis <lee@leewillis.co.uk>
+ * Borrowed heavily from code by Jan Arne Petersen <jpetersen@uni-bonn.de>
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+
+#include "mmkeys.h"
+
+static void mmkeys_class_init (MmKeysClass *klass);
+static void mmkeys_init (MmKeys *object);
+static void mmkeys_finalize (GObject *object);
+
+static void grab_mmkey (int key_code, GdkWindow *root);
+
+static GdkFilterReturn filter_mmkeys (GdkXEvent *xevent,
+ GdkEvent *event,
+ gpointer data);
+
+enum {
+ MM_PLAYPAUSE,
+ MM_NEXT,
+ MM_PREV,
+ MM_STOP,
+ LAST_SIGNAL
+};
+
+static GObjectClass *parent_class;
+static guint signals[LAST_SIGNAL];
+
+static GType type = 0;
+
+GType
+mmkeys_get_type (void)
+{
+ if (!type) {
+ static const GTypeInfo info = {
+ sizeof (MmKeysClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) mmkeys_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (MmKeys),
+ 0,
+ (GInstanceInitFunc) mmkeys_init,
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT, "MmKeys",
+ &info, 0);
+ }
+
+ return type;
+}
+
+static void
+mmkeys_class_init (MmKeysClass *klass)
+{
+ GObjectClass *object_class;
+
+ parent_class = g_type_class_peek_parent (klass);
+ object_class = (GObjectClass*) klass;
+
+ object_class->finalize = mmkeys_finalize;
+
+ signals[MM_PLAYPAUSE] =
+ g_signal_new ("mm_playpause",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT);
+ signals[MM_PREV] =
+ g_signal_new ("mm_prev",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT);
+ signals[MM_NEXT] =
+ g_signal_new ("mm_next",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT);
+ signals[MM_STOP] =
+ g_signal_new ("mm_stop",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT,
+ G_TYPE_NONE, 1, G_TYPE_INT);
+}
+
+static void
+mmkeys_finalize (GObject *object)
+{
+ parent_class->finalize (G_OBJECT(object));
+}
+
+#define N_KEYCODES 5
+
+static void
+mmkeys_init (MmKeys *object)
+{
+ int keycodes[N_KEYCODES];
+ GdkDisplay *display;
+ GdkScreen *screen;
+ GdkWindow *root;
+ guint i, j;
+
+ display = gdk_display_get_default ();
+
+ keycodes[0] = XKeysymToKeycode (GDK_DISPLAY (), XF86XK_AudioPrev);
+ keycodes[1] = XKeysymToKeycode (GDK_DISPLAY (), XF86XK_AudioNext);
+ keycodes[2] = XKeysymToKeycode (GDK_DISPLAY (), XF86XK_AudioPlay);
+ keycodes[3] = XKeysymToKeycode (GDK_DISPLAY (), XF86XK_AudioPause);
+ keycodes[4] = XKeysymToKeycode (GDK_DISPLAY (), XF86XK_AudioStop);
+
+ for (i = 0; i < gdk_display_get_n_screens (display); i++) {
+ screen = gdk_display_get_screen (display, i);
+
+ if (screen != NULL) {
+ root = gdk_screen_get_root_window (screen);
+
+ for (j = 0; j < N_KEYCODES; j++) {
+ if (keycodes[j] > 0)
+ grab_mmkey (keycodes[j], root);
+ }
+
+ gdk_window_add_filter (root, filter_mmkeys, object);
+ }
+ }
+}
+
+MmKeys *
+mmkeys_new (void)
+{
+ return MMKEYS (g_object_new (TYPE_MMKEYS, NULL));
+}
+
+static void
+grab_mmkey (int key_code, GdkWindow *root)
+{
+ gdk_error_trap_push ();
+
+ XGrabKey (GDK_DISPLAY (), key_code,
+ 0,
+ GDK_WINDOW_XID (root), True,
+ GrabModeAsync, GrabModeAsync);
+ XGrabKey (GDK_DISPLAY (), key_code,
+ Mod2Mask,
+ GDK_WINDOW_XID (root), True,
+ GrabModeAsync, GrabModeAsync);
+ XGrabKey (GDK_DISPLAY (), key_code,
+ Mod5Mask,
+ GDK_WINDOW_XID (root), True,
+ GrabModeAsync, GrabModeAsync);
+ XGrabKey (GDK_DISPLAY (), key_code,
+ LockMask,
+ GDK_WINDOW_XID (root), True,
+ GrabModeAsync, GrabModeAsync);
+ XGrabKey (GDK_DISPLAY (), key_code,
+ Mod2Mask | Mod5Mask,
+ GDK_WINDOW_XID (root), True,
+ GrabModeAsync, GrabModeAsync);
+ XGrabKey (GDK_DISPLAY (), key_code,
+ Mod2Mask | LockMask,
+ GDK_WINDOW_XID (root), True,
+ GrabModeAsync, GrabModeAsync);
+ XGrabKey (GDK_DISPLAY (), key_code,
+ Mod5Mask | LockMask,
+ GDK_WINDOW_XID (root), True,
+ GrabModeAsync, GrabModeAsync);
+ XGrabKey (GDK_DISPLAY (), key_code,
+ Mod2Mask | Mod5Mask | LockMask,
+ GDK_WINDOW_XID (root), True,
+ GrabModeAsync, GrabModeAsync);
+
+ gdk_flush ();
+ if (gdk_error_trap_pop ()) {
+ fprintf (stderr, "Error grabbing key %d, %p\n", key_code, root);
+ }
+}
+
+static GdkFilterReturn
+filter_mmkeys (GdkXEvent *xevent, GdkEvent *event, gpointer data)
+{
+ XEvent *xev;
+ XKeyEvent *key;
+
+ xev = (XEvent *) xevent;
+ if (xev->type != KeyPress) {
+ return GDK_FILTER_CONTINUE;
+ }
+
+ key = (XKeyEvent *) xevent;
+
+ if (XKeysymToKeycode (GDK_DISPLAY (), XF86XK_AudioPlay) == key->keycode) {
+ g_signal_emit (data, signals[MM_PLAYPAUSE], 0, 0);
+ return GDK_FILTER_REMOVE;
+ } else if (XKeysymToKeycode (GDK_DISPLAY (), XF86XK_AudioPause) == key->keycode) {
+ g_signal_emit (data, signals[MM_PLAYPAUSE], 0, 0);
+ return GDK_FILTER_REMOVE;
+ } else if (XKeysymToKeycode (GDK_DISPLAY (), XF86XK_AudioPrev) == key->keycode) {
+ g_signal_emit (data, signals[MM_PREV], 0, 0);
+ return GDK_FILTER_REMOVE;
+ } else if (XKeysymToKeycode (GDK_DISPLAY (), XF86XK_AudioNext) == key->keycode) {
+ g_signal_emit (data, signals[MM_NEXT], 0, 0);
+ return GDK_FILTER_REMOVE;
+ } else if (XKeysymToKeycode (GDK_DISPLAY (), XF86XK_AudioStop) == key->keycode) {
+ g_signal_emit (data, signals[MM_STOP], 0, 0);
+ return GDK_FILTER_REMOVE;
+ } else {
+ return GDK_FILTER_CONTINUE;
+ }
+}
View
@@ -0,0 +1,19 @@
+; Copyright 2004 Joe Wreschnig. Released under the terms of the GNU GPL.
+
+(define-object MmKeys
+ (in-module "MM")
+ (parent "GtkPlug")
+ (c-name "MmKeys")
+ (gtype-id "TYPE_MMKEYS")
+)
+
+(define-function mmkeys_get_type
+ (c-name "mmkeys_get_type")
+ (return-type "GType")
+)
+
+(define-function mmkeys_new
+ (c-name "mmkeys_new")
+ (is-constructor-of "MmKeys")
+ (return-type "MmKeys*")
+)
View
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2004 Lee Willis <lee@leewillis.co.uk>
+ * Borrowed heavily from code by Jan Arne Petersen <jpetersen@uni-bonn.de>
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <X11/Xlib.h>
+#include <X11/XF86keysym.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <stdio.h>
+#include <gtk/gtktogglebutton.h>
+
+#ifndef __MM_KEYS_H
+#define __MM_KEYS_H
+
+#define TYPE_MMKEYS (mmkeys_get_type ())
+#define MMKEYS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_MMKEYS, MmKeys))
+#define MMKEYS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_MMKEYS, MmKeysClass))
+#define IS_MMKEYS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_MMKEYS))
+#define IS_MMKEYS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_MMKEYS))
+#define MMKEYS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_MMKEYS, MmKeysClass))
+
+typedef struct _MmKeys MmKeys;
+typedef struct _MmKeysClass MmKeysClass;
+
+struct _MmKeys
+{
+ GObject parent;
+};
+
+struct _MmKeysClass
+{
+ GObjectClass parent_class;
+};
+
+GType mmkeys_get_type (void);
+
+MmKeys *mmkeys_new (void);
+
+#endif /* __MM_KEYS_H */
Oops, something went wrong.

0 comments on commit 54c65e0

Please sign in to comment.