Last active
August 29, 2015 14:22
-
-
Save davidjb/e6cee3a040b1532e728d to your computer and use it in GitHub Desktop.
Example code for listening to multimedia key presses in GNOME
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <gio/gio.h> | |
static void | |
on_signal (GDBusProxy *proxy, | |
gchar *sender_name, | |
gchar *signal_name, | |
GVariant *parameters, | |
gpointer user_data) | |
{ | |
gchar *parameters_str; | |
parameters_str = g_variant_print (parameters, TRUE); | |
g_print (" *** Received Signal: %s: %s\n", signal_name, parameters_str); | |
g_free (parameters_str); | |
} | |
int | |
main (int argc, char *argv[]) | |
{ | |
GMainLoop *loop; | |
GError *error; | |
GDBusProxyFlags flags; | |
GDBusProxy *proxy; | |
loop = NULL; | |
error = NULL; | |
loop = g_main_loop_new (NULL, FALSE); | |
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, | |
flags, | |
NULL, /* GDBusInterfaceInfo */ | |
"org.gnome.SettingsDaemon", | |
"/org/gnome/SettingsDaemon/MediaKeys", | |
"org.gnome.SettingsDaemon.MediaKeys", | |
NULL, /* GCancellable */ | |
&error); | |
g_signal_connect (proxy, | |
"g-signal", | |
G_CALLBACK (on_signal), | |
NULL); | |
g_dbus_proxy_call (proxy, | |
"GrabMediaPlayerKeys", | |
g_variant_new ("(su)", "ExampleCCode", 0), | |
G_DBUS_CALL_FLAGS_NO_AUTO_START, | |
-1, | |
NULL, NULL, NULL); | |
g_main_loop_run (loop); | |
out: | |
// Release may not be necessary | |
g_dbus_proxy_call (proxy, | |
"ReleaseMediaPlayerKeys", | |
g_variant_new ("(s)", "ExampleCCode"), | |
G_DBUS_CALL_FLAGS_NO_AUTO_START, | |
-1, | |
NULL, NULL, NULL); | |
if (proxy != NULL) | |
g_object_unref (proxy); | |
if (loop != NULL) | |
g_main_loop_unref (loop); | |
g_free ("org.gnome.SettingsDaemon"); | |
g_free ("/org/gnome/SettingsDaemon/MediaKeys"); | |
g_free ("org.gnome.SettingsDaemon.MediaKeys"); | |
return 0; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*jshint moz: true, undef: true, unused: true */ | |
/*global ctypes, Components */ | |
// Here be dragons... by @davidjb | |
// TODO: Figure out what's causing firefox to crash with SIGSEV after several button presses... | |
// | |
// Based on the following: | |
// https://github.com/foudfou/FireTray/tree/master/src/modules/ctypes/linux (with minor fixes) | |
// http://bazaar.launchpad.net/~mozillateam/ubufox/2.1/view/head:/modules/libs/glib.jsm | |
// http://bazaar.launchpad.net/~mozillateam/ubufox/trunk/view/head:/res/libs/gio.jsm | |
// https://bugzilla.mozilla.org/show_bug.cgi?id=554790#c20 - for variadic ctypes functions | |
// | |
// Ctypes loaders exist: http://bazaar.launchpad.net/~mozillateam/ubufox/trunk/view/head:/res/modules/utils.jsm | |
// We could/should consider using something like that. | |
Components.utils.import("resource://gre/modules/ctypes.jsm"); | |
var gpointer = ctypes.voidptr_t; | |
var gulong = ctypes.unsigned_long; | |
var guint = ctypes.unsigned_int; | |
var guint32 = ctypes.uint32_t; | |
var guint16 = ctypes.uint16_t; | |
var gint = ctypes.int; | |
var gint8 = ctypes.int8_t; | |
var gint16 = ctypes.int16_t; | |
var gchar = ctypes.char; | |
var guchar = ctypes.unsigned_char; | |
var gboolean = gint; | |
var gfloat = ctypes.float; | |
var gdouble = ctypes.double; | |
var gsize = ctypes.unsigned_long; | |
var GCallback = ctypes.voidptr_t; | |
var GClosureNotify = gpointer; | |
var GFunc = ctypes.void_t.ptr; | |
var GList = ctypes.StructType("GList"); | |
var GConnectFlags = guint; // enum | |
var G_CONNECT_AFTER = 1 << 0; | |
var G_CONNECT_SWAPPED = 1 << 1; | |
var GCallback_t = ctypes.FunctionType( | |
ctypes.default_abi, ctypes.void_t, [gpointer]).ptr; | |
var GClosure = ctypes.StructType("GClosure", [ | |
{ in_marshal: guint }, | |
{ is_invalid: guint }, | |
]); | |
var GCancellable = ctypes.StructType("GCancellable"); | |
var GQuark = ctypes.uint32_t; // this.GQuark = gobject.guint32; | |
var GError = ctypes.StructType("GError", [ | |
{ domain: GQuark }, | |
{ code: ctypes.int }, // gint | |
{ message: ctypes.char.ptr } // gchar.ptr | |
]); | |
var GDBusProxy = ctypes.StructType('GDBusProxy'); | |
var GDBusInterfaceInfo = ctypes.StructType('GDBusInterfaceInfo'); | |
var GVariant = ctypes.StructType("GVariant"); | |
var GVariantType = ctypes.char; | |
var GObject = ctypes.StructType("GObject"); | |
var GAsyncResult = ctypes.StructType("GAsyncResult"); | |
var GAsyncReadyCallback = ctypes.FunctionType( | |
ctypes.default_abi, | |
ctypes.void_t, | |
[GObject.ptr, GAsyncResult.ptr, gpointer]).ptr; | |
var G_CALLBACK = function(f) { return ctypes.cast(f, GCallback); }; //? | |
var GDBusProxyFlags = ctypes.int; // enum | |
var G_DBUS_PROXY_FLAGS_NONE = 0; | |
var G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES = (1<<0); | |
var G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS = (1<<1); | |
var G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START = (1<<2); | |
var GBusType = ctypes.int; // enum | |
var G_BUS_TYPE_STARTER = -1; | |
var G_BUS_TYPE_NONE = 0; | |
var G_BUS_TYPE_SYSTEM = 1; | |
var G_BUS_TYPE_SESSION = 2; | |
var GDBusCallFlags = ctypes.int; // enum | |
var G_DBUS_CALL_FLAGS_NONE = 0; | |
var G_DBUS_CALL_FLAGS_NO_AUTO_START = (1<<0); | |
// JS helper methods | |
var toCharArray = function(str) { | |
return ctypes.char.array()(str); | |
}; | |
// These libraries might not be available on all systems. | |
var gLibsExist = false; | |
try { | |
// GC is responsible for closing these libraries if they exist. | |
var glib = ctypes.open("libglib-2.0.so.0"); | |
var gobject = ctypes.open("libgobject-2.0.so.0"); | |
var gio = ctypes.open("libgio-2.0.so.0"); | |
gLibsExist = true; | |
} catch (ex) {} | |
if (gLibsExist) { | |
var g_free = glib.declare( | |
"g_free", | |
ctypes.default_abi, | |
ctypes.void_t, | |
gpointer | |
); | |
var g_object_unref = gobject.declare( | |
"g_object_unref", | |
ctypes.default_abi, | |
ctypes.void_t, | |
gpointer | |
); | |
// Can't use g_signal_connect because it's #define | |
var g_signal_connect_data = gobject.declare( | |
'g_signal_connect_data', | |
ctypes.default_abi, | |
gulong, // return status | |
gpointer, //instance | |
gchar.ptr, //detailed_signal | |
GCallback, //c_handler | |
gpointer, //data to pass handler, | |
GClosureNotify, //destory_data | |
GConnectFlags //connect_flags | |
); | |
var g_dbus_proxy_new_for_bus_sync = gio.declare( | |
'g_dbus_proxy_new_for_bus_sync', | |
ctypes.default_abi, | |
GDBusProxy.ptr, //return | |
GBusType, //bus_type | |
GDBusProxyFlags, //flags | |
GDBusInterfaceInfo.ptr, //info | |
gchar.ptr, //name | |
gchar.ptr, //object_path | |
gchar.ptr, //interface_name | |
GCancellable.ptr, //cancellable | |
GError.ptr.ptr //error | |
); | |
var g_dbus_proxy_call = gio.declare( | |
'g_dbus_proxy_call', | |
ctypes.default_abi, | |
ctypes.void_t, //return | |
GDBusProxy.ptr, //proxy | |
gchar.ptr, //method_name | |
GVariant.ptr, //parameters | |
GDBusCallFlags, //flags | |
gint, //timeout_msec | |
GCancellable.ptr, //cancellable | |
GAsyncReadyCallback, //callback | |
gpointer //user_data | |
); | |
var g_variant_new = glib.declare( | |
"g_variant_new", | |
ctypes.default_abi, | |
GVariant.ptr, //return | |
gchar.ptr, //format_string | |
"..." //varags | |
); | |
var g_variant_print = glib.declare( | |
"g_variant_print", | |
ctypes.default_abi, | |
gchar.ptr, //return | |
GVariant.ptr, //value | |
gboolean //type_annotate | |
); | |
} | |
var releaseMediaKeys; | |
var main = function() { | |
var error = null; //GError | |
var proxy = null; //GDBusProxy | |
var flags = G_DBUS_PROXY_FLAGS_NONE; //GDBusProxyFlags | |
//loop = g_main_loop_new (NULL, FALSE); | |
// | |
proxy = g_dbus_proxy_new_for_bus_sync( | |
G_BUS_TYPE_SESSION, | |
flags, | |
null, /* GDBusInterfaceInfo */ | |
"org.gnome.SettingsDaemon", | |
"/org/gnome/SettingsDaemon/MediaKeys", | |
"org.gnome.SettingsDaemon.MediaKeys", | |
null, /* GCancellable */ | |
error); | |
// Convert to C callback | |
var onSignalDeclaration = ctypes.FunctionType( | |
ctypes.default_abi, | |
ctypes.void_t, //return | |
[GDBusProxy.ptr, //proxy | |
gchar.ptr, //sender_name | |
gchar.ptr, //signal_name | |
GVariant.ptr, //parameters | |
gpointer //user_data | |
]); | |
var on_signal = function(proxy, sender_name, signal_name, parameters, user_data) { | |
var parameters_str = g_variant_print(parameters, true); | |
console.log("Parameters: " + parameters_str.readString()); | |
console.log("Signal name: " + signal_name.readString()); | |
g_free(parameters_str); | |
return; | |
}; | |
// Connect callback to listen | |
g_signal_connect_data( | |
proxy, | |
"g-signal", | |
G_CALLBACK(onSignalDeclaration.ptr(on_signal)), | |
null, | |
null, | |
0); | |
// Ask settings daemon to grab media keys for this application | |
g_dbus_proxy_call( | |
proxy, | |
"GrabMediaPlayerKeys", | |
g_variant_new(toCharArray("(su)"), toCharArray("FirefoxMediaKeys"), gint(0)), | |
G_DBUS_CALL_FLAGS_NO_AUTO_START, | |
-1, | |
null, | |
null, | |
null); | |
releaseMediaKeys = function() { | |
g_dbus_proxy_call (proxy, | |
"ReleaseMediaPlayerKeys", | |
g_variant_new(toCharArray("(s)"), | |
toCharArray("FirefoxMediaKeys")), | |
G_DBUS_CALL_FLAGS_NO_AUTO_START, | |
-1, | |
null, null, null); | |
if (proxy) { | |
g_object_unref(proxy); | |
} | |
// TODO Any other C objects need to be cleaned up | |
//if (loop) { | |
//g_main_loop_unref(loop); | |
//} | |
return 0; | |
}; | |
//g_main_loop_run (loop); | |
}; | |
main(); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
"""Printing out gnome multi media keys via dbus-python. | |
From https://stackoverflow.com/questions/5744041/cant-get-dbus-signal-listener-to-work-in-c-with-gnome-multimedia-keys | |
""" | |
import gobject | |
import dbus | |
import dbus.service | |
import dbus.mainloop.glib | |
def on_mediakey(comes_from, what): | |
""" gets called when multimedia keys are pressed down. | |
""" | |
print ('comes from:%s what:%s') % (comes_from, what) | |
if what in ['Stop','Play','Next','Previous']: | |
print ('Got a multimedia key!') | |
else: | |
print ('Got a multimedia key...') | |
# set up the glib main loop. | |
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) | |
bus = dbus.Bus(dbus.Bus.TYPE_SESSION) | |
bus_object = bus.get_object('org.gnome.SettingsDaemon', | |
'/org/gnome/SettingsDaemon/MediaKeys') | |
# this is what gives us the multi media keys. | |
dbus_interface='org.gnome.SettingsDaemon.MediaKeys' | |
bus_object.GrabMediaPlayerKeys("MyMultimediaThingy", 0, | |
dbus_interface=dbus_interface) | |
# connect_to_signal registers our callback function. | |
bus_object.connect_to_signal('MediaPlayerKeyPressed', | |
on_mediakey) | |
# and we start the main loop. | |
mainloop = gobject.MainLoop() | |
mainloop.run() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
cc $(pkg-config --cflags gio-2.0) gnome_mediakeys.c -o gnome_mediakeys.o $(pkg-config --libs gio-2.0) | |
#./gnome_mediakeys.o |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment