Skip to content

Instantly share code, notes, and snippets.

@davidjb
Last active August 29, 2015 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davidjb/e6cee3a040b1532e728d to your computer and use it in GitHub Desktop.
Save davidjb/e6cee3a040b1532e728d to your computer and use it in GitHub Desktop.
Example code for listening to multimedia key presses in GNOME
#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;
}
/*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();
#!/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()
#!/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