summaryrefslogtreecommitdiff
path: root/plugins/media-keys
diff options
context:
space:
mode:
authorPerberos <[email protected]>2011-12-01 23:53:21 -0300
committerPerberos <[email protected]>2011-12-01 23:53:21 -0300
commit505cabbd3036081f26586cabc64c26e7769c0ec9 (patch)
tree09e0498bf572128f5c9ab551531cb28d6d75e992 /plugins/media-keys
downloadmate-settings-daemon-505cabbd3036081f26586cabc64c26e7769c0ec9.tar.bz2
mate-settings-daemon-505cabbd3036081f26586cabc64c26e7769c0ec9.tar.xz
moving from https://github.com/perberos/mate-desktop-environment
Diffstat (limited to 'plugins/media-keys')
-rw-r--r--plugins/media-keys/Makefile.am207
-rw-r--r--plugins/media-keys/Makefile.in1159
-rw-r--r--plugins/media-keys/acme.h78
-rw-r--r--plugins/media-keys/acme.ui33
-rw-r--r--plugins/media-keys/cut-n-paste/Makefile.am39
-rw-r--r--plugins/media-keys/cut-n-paste/Makefile.in586
-rw-r--r--plugins/media-keys/cut-n-paste/gvc-channel-map.c292
-rw-r--r--plugins/media-keys/cut-n-paste/gvc-channel-map.h83
-rw-r--r--plugins/media-keys/cut-n-paste/gvc-mixer-card.c493
-rw-r--r--plugins/media-keys/cut-n-paste/gvc-mixer-card.h90
-rw-r--r--plugins/media-keys/cut-n-paste/gvc-mixer-control.c2123
-rw-r--r--plugins/media-keys/cut-n-paste/gvc-mixer-control.h102
-rw-r--r--plugins/media-keys/cut-n-paste/gvc-mixer-event-role.c239
-rw-r--r--plugins/media-keys/cut-n-paste/gvc-mixer-event-role.h61
-rw-r--r--plugins/media-keys/cut-n-paste/gvc-mixer-sink-input.c188
-rw-r--r--plugins/media-keys/cut-n-paste/gvc-mixer-sink-input.h61
-rw-r--r--plugins/media-keys/cut-n-paste/gvc-mixer-sink.c220
-rw-r--r--plugins/media-keys/cut-n-paste/gvc-mixer-sink.h61
-rw-r--r--plugins/media-keys/cut-n-paste/gvc-mixer-source-output.c128
-rw-r--r--plugins/media-keys/cut-n-paste/gvc-mixer-source-output.h61
-rw-r--r--plugins/media-keys/cut-n-paste/gvc-mixer-source.c220
-rw-r--r--plugins/media-keys/cut-n-paste/gvc-mixer-source.h61
-rw-r--r--plugins/media-keys/cut-n-paste/gvc-mixer-stream.c875
-rw-r--r--plugins/media-keys/cut-n-paste/gvc-mixer-stream.h128
-rw-r--r--plugins/media-keys/gsd-marshal.list1
-rw-r--r--plugins/media-keys/gsd-media-keys-manager.c1373
-rw-r--r--plugins/media-keys/gsd-media-keys-manager.h72
-rw-r--r--plugins/media-keys/gsd-media-keys-manager.xml14
-rw-r--r--plugins/media-keys/gsd-media-keys-plugin.c104
-rw-r--r--plugins/media-keys/gsd-media-keys-plugin.h63
-rw-r--r--plugins/media-keys/gsd-media-keys-window.c714
-rw-r--r--plugins/media-keys/gsd-media-keys-window.h78
-rw-r--r--plugins/media-keys/libmedia-keys.la41
-rw-r--r--plugins/media-keys/media-keys.mate-settings-plugin136
-rw-r--r--plugins/media-keys/media-keys.mate-settings-plugin.in8
-rw-r--r--plugins/media-keys/test-media-keys.c64
-rw-r--r--plugins/media-keys/test-media-window.c152
-rw-r--r--plugins/media-keys/touchpad-disabled-16.pngbin0 -> 610 bytes
-rw-r--r--plugins/media-keys/touchpad-disabled-22.pngbin0 -> 957 bytes
-rw-r--r--plugins/media-keys/touchpad-disabled-24.pngbin0 -> 985 bytes
-rw-r--r--plugins/media-keys/touchpad-disabled-32.pngbin0 -> 1610 bytes
-rw-r--r--plugins/media-keys/touchpad-disabled-48.pngbin0 -> 2208 bytes
-rw-r--r--plugins/media-keys/touchpad-disabled-template.svg1172
-rw-r--r--plugins/media-keys/touchpad-disabled.svg833
-rw-r--r--plugins/media-keys/touchpad-enabled-16.pngbin0 -> 626 bytes
-rw-r--r--plugins/media-keys/touchpad-enabled-22.pngbin0 -> 938 bytes
-rw-r--r--plugins/media-keys/touchpad-enabled-24.pngbin0 -> 949 bytes
-rw-r--r--plugins/media-keys/touchpad-enabled-32.pngbin0 -> 1494 bytes
-rw-r--r--plugins/media-keys/touchpad-enabled-48.pngbin0 -> 2041 bytes
-rw-r--r--plugins/media-keys/touchpad-enabled-template.svg936
-rw-r--r--plugins/media-keys/touchpad-enabled.svg581
51 files changed, 13930 insertions, 0 deletions
diff --git a/plugins/media-keys/Makefile.am b/plugins/media-keys/Makefile.am
new file mode 100644
index 0000000..d8bff08
--- /dev/null
+++ b/plugins/media-keys/Makefile.am
@@ -0,0 +1,207 @@
+icondir = $(datadir)/icons/mate
+context = actions
+
+NULL =
+
+SUBDIRS =
+plugin_LTLIBRARIES =
+
+if HAVE_PULSE
+SUBDIRS += cut-n-paste
+plugin_LTLIBRARIES += libmedia-keys.la
+endif
+
+BUILT_SOURCES = \
+ gsd-media-keys-manager-glue.h \
+ gsd-marshal.h \
+ gsd-marshal.c \
+ $(NULL)
+
+ICON_FILES = \
+ touchpad-disabled-16.png \
+ touchpad-enabled-16.png \
+ touchpad-disabled-22.png \
+ touchpad-enabled-22.png \
+ touchpad-disabled-24.png \
+ touchpad-enabled-24.png \
+ touchpad-disabled-32.png \
+ touchpad-enabled-32.png \
+ touchpad-disabled-48.png \
+ touchpad-enabled-48.png \
+ touchpad-disabled.svg \
+ touchpad-enabled.svg
+
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/16x16/$(context)
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/22x22/$(context)
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/24x24/$(context)
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/32x32/$(context)
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/scalable/$(context)
+ $(INSTALL_DATA) $(srcdir)/touchpad-enabled-16.png $(DESTDIR)$(icondir)/16x16/$(context)/touchpad-enabled.png
+ $(INSTALL_DATA) $(srcdir)/touchpad-enabled-22.png $(DESTDIR)$(icondir)/22x22/$(context)/touchpad-enabled.png
+ $(INSTALL_DATA) $(srcdir)/touchpad-enabled-24.png $(DESTDIR)$(icondir)/24x24/$(context)/touchpad-enabled.png
+ $(INSTALL_DATA) $(srcdir)/touchpad-enabled-32.png $(DESTDIR)$(icondir)/32x32/$(context)/touchpad-enabled.png
+ $(INSTALL_DATA) $(srcdir)/touchpad-enabled.svg $(DESTDIR)$(icondir)/scalable/$(context)/touchpad-enabled.svg
+ $(INSTALL_DATA) $(srcdir)/touchpad-disabled-16.png $(DESTDIR)$(icondir)/16x16/$(context)/touchpad-disabled.png
+ $(INSTALL_DATA) $(srcdir)/touchpad-disabled-22.png $(DESTDIR)$(icondir)/22x22/$(context)/touchpad-disabled.png
+ $(INSTALL_DATA) $(srcdir)/touchpad-disabled-24.png $(DESTDIR)$(icondir)/24x24/$(context)/touchpad-disabled.png
+ $(INSTALL_DATA) $(srcdir)/touchpad-disabled-32.png $(DESTDIR)$(icondir)/32x32/$(context)/touchpad-disabled.png
+ $(INSTALL_DATA) $(srcdir)/touchpad-disabled.svg $(DESTDIR)$(icondir)/scalable/$(context)/touchpad-disabled.svg
+
+uninstall-local:
+ rm -f $(DESTDIR)$(icondir)/16x16/$(context)/touchpad-enabled.png
+ rm -f $(DESTDIR)$(icondir)/22x22/$(context)/touchpad-enabled.png
+ rm -f $(DESTDIR)$(icondir)/24x24/$(context)/touchpad-enabled.png
+ rm -f $(DESTDIR)$(icondir)/32x32/$(context)/touchpad-enabled.png
+ rm -f $(DESTDIR)$(icondir)/scalable/$(context)/touchpad-enabled.svg
+ rm -f $(DESTDIR)$(icondir)/16x16/$(context)/touchpad-disabled.png
+ rm -f $(DESTDIR)$(icondir)/22x22/$(context)/touchpad-disabled.png
+ rm -f $(DESTDIR)$(icondir)/24x24/$(context)/touchpad-disabled.png
+ rm -f $(DESTDIR)$(icondir)/32x32/$(context)/touchpad-disabled.png
+ rm -f $(DESTDIR)$(icondir)/scalable/$(context)/touchpad-disabled.svg
+
+gsd-media-keys-manager-glue.h: gsd-media-keys-manager.xml Makefile
+ dbus-binding-tool --prefix=gsd_media_keys_manager --mode=glib-server $< > xgen-$(@F) \
+ && ( cmp -s xgen-$(@F) $@ || cp xgen-$(@F) $@ ) \
+ && rm -f xgen-$(@F)
+
+gsd-marshal.c: gsd-marshal.list
+ $(GLIB_GENMARSHAL) --prefix=gsd_marshal $< --header --body --internal > $@
+
+gsd-marshal.h: gsd-marshal.list
+ $(GLIB_GENMARSHAL) --prefix=gsd_marshal $< --header --internal > $@
+
+libmedia_keys_la_SOURCES = \
+ gsd-media-keys-plugin.h \
+ gsd-media-keys-plugin.c \
+ gsd-media-keys-manager.h \
+ gsd-media-keys-manager.c \
+ gsd-media-keys-window.h \
+ gsd-media-keys-window.c \
+ acme.h \
+ $(BUILT_SOURCES) \
+ $(NULL)
+
+libmedia_keys_la_CPPFLAGS = \
+ -I$(top_srcdir)/mate-settings-daemon \
+ -I$(top_srcdir)/plugins/common \
+ -I$(top_srcdir)/plugins/media-keys/cut-n-paste \
+ -DPIXMAPDIR=\""$(pkgdatadir)"\" \
+ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \
+ -DMATE_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
+ $(AM_CPPFLAGS)
+
+libmedia_keys_la_CFLAGS = \
+ $(SETTINGS_PLUGIN_CFLAGS) \
+ $(AM_CFLAGS)
+
+libmedia_keys_la_LDFLAGS = \
+ $(GSD_PLUGIN_LDFLAGS)
+
+libmedia_keys_la_LIBADD = \
+ $(top_builddir)/plugins/common/libcommon.la \
+ $(top_builddir)/plugins/media-keys/cut-n-paste/libgvc.la \
+ $(SETTINGS_PLUGIN_LIBS) \
+ $(XF86MISC_LIBS) \
+ -lm
+
+plugin_in_files = \
+ media-keys.mate-settings-plugin.in
+
+if HAVE_PULSE
+plugin_DATA = $(plugin_in_files:.mate-settings-plugin.in=.mate-settings-plugin)
+endif
+
+noinst_PROGRAMS = \
+ test-media-keys \
+ test-media-window \
+ $(NULL)
+
+test_media_window_SOURCES = \
+ gsd-media-keys-window.c \
+ gsd-media-keys-window.h \
+ test-media-window.c \
+ $(NULL)
+
+test_media_window_CPPFLAGS = \
+ -I$(top_srcdir)/mate-settings-daemon \
+ -I$(top_srcdir)/plugins/common \
+ -I$(top_srcdir)/plugins/media-keys/cut-n-paste \
+ -DDATADIR=\""$(datadir)"\" \
+ -DPIXMAPDIR=\""$(pkgdatadir)"\" \
+ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \
+ -DMATE_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
+ $(AM_CPPFLAGS)
+
+test_media_window_CFLAGS = \
+ $(SETTINGS_PLUGIN_CFLAGS) \
+ $(AM_CFLAGS)
+
+test_media_window_LDADD = \
+ $(top_builddir)/plugins/common/libcommon.la \
+ $(SETTINGS_DAEMON_LIBS) \
+ $(SETTINGS_PLUGIN_LIBS) \
+ $(XF86MISC_LIBS) \
+ $(GST_LIBS) \
+ -lm
+
+test_media_keys_SOURCES = \
+ gsd-media-keys-manager.c \
+ gsd-media-keys-manager.h \
+ gsd-media-keys-window.h \
+ gsd-media-keys-window.c \
+ test-media-keys.c \
+ $(BUILT_SOURCES) \
+ $(NULL)
+
+test_media_keys_CPPFLAGS = \
+ -I$(top_srcdir)/mate-settings-daemon \
+ -I$(top_srcdir)/plugins/common \
+ -I$(top_srcdir)/plugins/media-keys/cut-n-paste \
+ -DPIXMAPDIR=\""$(pkgdatadir)"\" \
+ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \
+ -DMATE_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
+ $(AM_CPPFLAGS)
+
+test_media_keys_CFLAGS = \
+ $(SETTINGS_PLUGIN_CFLAGS) \
+ $(AM_CFLAGS)
+
+test_media_keys_LDADD = \
+ $(top_builddir)/mate-settings-daemon/libgsd-profile.la \
+ $(top_builddir)/plugins/common/libcommon.la \
+ $(SETTINGS_DAEMON_LIBS) \
+ $(SETTINGS_PLUGIN_LIBS) \
+ $(XF86MISC_LIBS) \
+ $(GST_LIBS) \
+ -lm
+
+if HAVE_PULSE
+test_media_keys_LDADD += $(top_builddir)/plugins/media-keys/cut-n-paste/libgvc.la
+endif
+
+gtkbuilderdir = $(pkgdatadir)
+gtkbuilder_DATA = \
+ acme.ui \
+ $(NULL)
+
+DIST_SUBDIRS = cut-n-paste
+
+EXTRA_DIST = \
+ gsd-media-keys-manager.xml \
+ gsd-marshal.list \
+ $(plugin_in_files) \
+ $(gtkbuilder_DATA) \
+ $(pixmaps_DATA) \
+ touchpad-enabled-template.svg \
+ touchpad-disabled-template.svg \
+ $(ICON_FILES)
+
+CLEANFILES = \
+ $(BUILT_SOURCES) \
+ $(plugin_DATA)
+
+DISTCLEANFILES = \
+ $(plugin_DATA)
+
+@GSD_INTLTOOL_PLUGIN_RULE@
diff --git a/plugins/media-keys/Makefile.in b/plugins/media-keys/Makefile.in
new file mode 100644
index 0000000..3a0cec7
--- /dev/null
+++ b/plugins/media-keys/Makefile.in
@@ -0,0 +1,1159 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@HAVE_PULSE_TRUE@am__append_1 = cut-n-paste
+@HAVE_PULSE_TRUE@am__append_2 = libmedia-keys.la
+noinst_PROGRAMS = test-media-keys$(EXEEXT) test-media-window$(EXEEXT) \
+ $(am__EXEEXT_1)
+@HAVE_PULSE_TRUE@am__append_3 = $(top_builddir)/plugins/media-keys/cut-n-paste/libgvc.la
+subdir = plugins/media-keys
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(plugindir)" \
+ "$(DESTDIR)$(gtkbuilderdir)" "$(DESTDIR)$(plugindir)"
+LTLIBRARIES = $(plugin_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libmedia_keys_la_DEPENDENCIES = \
+ $(top_builddir)/plugins/common/libcommon.la \
+ $(top_builddir)/plugins/media-keys/cut-n-paste/libgvc.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am__objects_1 =
+am__objects_2 = libmedia_keys_la-gsd-marshal.lo $(am__objects_1)
+am_libmedia_keys_la_OBJECTS = \
+ libmedia_keys_la-gsd-media-keys-plugin.lo \
+ libmedia_keys_la-gsd-media-keys-manager.lo \
+ libmedia_keys_la-gsd-media-keys-window.lo $(am__objects_2) \
+ $(am__objects_1)
+libmedia_keys_la_OBJECTS = $(am_libmedia_keys_la_OBJECTS)
+libmedia_keys_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libmedia_keys_la_CFLAGS) \
+ $(CFLAGS) $(libmedia_keys_la_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_PULSE_TRUE@am_libmedia_keys_la_rpath = -rpath $(plugindir)
+am__EXEEXT_1 =
+PROGRAMS = $(noinst_PROGRAMS)
+am__objects_3 = test_media_keys-gsd-marshal.$(OBJEXT) $(am__objects_1)
+am_test_media_keys_OBJECTS = \
+ test_media_keys-gsd-media-keys-manager.$(OBJEXT) \
+ test_media_keys-gsd-media-keys-window.$(OBJEXT) \
+ test_media_keys-test-media-keys.$(OBJEXT) $(am__objects_3) \
+ $(am__objects_1)
+test_media_keys_OBJECTS = $(am_test_media_keys_OBJECTS)
+test_media_keys_DEPENDENCIES = \
+ $(top_builddir)/mate-settings-daemon/libgsd-profile.la \
+ $(top_builddir)/plugins/common/libcommon.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__append_3)
+test_media_keys_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(test_media_keys_CFLAGS) \
+ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+am_test_media_window_OBJECTS = \
+ test_media_window-gsd-media-keys-window.$(OBJEXT) \
+ test_media_window-test-media-window.$(OBJEXT) $(am__objects_1)
+test_media_window_OBJECTS = $(am_test_media_window_OBJECTS)
+test_media_window_DEPENDENCIES = \
+ $(top_builddir)/plugins/common/libcommon.la \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+test_media_window_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(test_media_window_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
+ -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libmedia_keys_la_SOURCES) $(test_media_keys_SOURCES) \
+ $(test_media_window_SOURCES)
+DIST_SOURCES = $(libmedia_keys_la_SOURCES) $(test_media_keys_SOURCES) \
+ $(test_media_window_SOURCES)
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
+DATA = $(gtkbuilder_DATA) $(plugin_DATA)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+ distdir
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DBUS_SYS_DIR = @DBUS_SYS_DIR@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
+FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIOUNIX_CFLAGS = @GIOUNIX_CFLAGS@
+GIOUNIX_LIBS = @GIOUNIX_LIBS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GREP = @GREP@
+GSD_INTLTOOL_PLUGIN_RULE = @GSD_INTLTOOL_PLUGIN_RULE@
+GSD_PLUGIN_LDFLAGS = @GSD_PLUGIN_LDFLAGS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBEXECDIR = @LIBEXECDIR@
+LIBMATEKBDUI_CFLAGS = @LIBMATEKBDUI_CFLAGS@
+LIBMATEKBDUI_LIBS = @LIBMATEKBDUI_LIBS@
+LIBMATENOTIFY_CFLAGS = @LIBMATENOTIFY_CFLAGS@
+LIBMATENOTIFY_LIBS = @LIBMATENOTIFY_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MATECONFTOOL = @MATECONFTOOL@
+MATECONF_SCHEMA_CONFIG_SOURCE = @MATECONF_SCHEMA_CONFIG_SOURCE@
+MATECONF_SCHEMA_FILE_DIR = @MATECONF_SCHEMA_FILE_DIR@
+MATE_KEYBINDINGS_KEYSDIR = @MATE_KEYBINDINGS_KEYSDIR@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_DATABASE = @NSS_DATABASE@
+NSS_LIBS = @NSS_LIBS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POFILES = @POFILES@
+POLKIT_CFLAGS = @POLKIT_CFLAGS@
+POLKIT_LIBS = @POLKIT_LIBS@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SETTINGS_DAEMON_CFLAGS = @SETTINGS_DAEMON_CFLAGS@
+SETTINGS_DAEMON_LIBS = @SETTINGS_DAEMON_LIBS@
+SETTINGS_PLUGIN_CFLAGS = @SETTINGS_PLUGIN_CFLAGS@
+SETTINGS_PLUGIN_LIBS = @SETTINGS_PLUGIN_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+X11_LIBS = @X11_LIBS@
+XF86MISC_LIBS = @XF86MISC_LIBS@
+XGETTEXT = @XGETTEXT@
+XINPUT_LIBS = @XINPUT_LIBS@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+icondir = $(datadir)/icons/mate
+context = actions
+NULL =
+SUBDIRS = $(am__append_1)
+plugin_LTLIBRARIES = $(am__append_2)
+BUILT_SOURCES = \
+ gsd-media-keys-manager-glue.h \
+ gsd-marshal.h \
+ gsd-marshal.c \
+ $(NULL)
+
+ICON_FILES = \
+ touchpad-disabled-16.png \
+ touchpad-enabled-16.png \
+ touchpad-disabled-22.png \
+ touchpad-enabled-22.png \
+ touchpad-disabled-24.png \
+ touchpad-enabled-24.png \
+ touchpad-disabled-32.png \
+ touchpad-enabled-32.png \
+ touchpad-disabled-48.png \
+ touchpad-enabled-48.png \
+ touchpad-disabled.svg \
+ touchpad-enabled.svg
+
+libmedia_keys_la_SOURCES = \
+ gsd-media-keys-plugin.h \
+ gsd-media-keys-plugin.c \
+ gsd-media-keys-manager.h \
+ gsd-media-keys-manager.c \
+ gsd-media-keys-window.h \
+ gsd-media-keys-window.c \
+ acme.h \
+ $(BUILT_SOURCES) \
+ $(NULL)
+
+libmedia_keys_la_CPPFLAGS = \
+ -I$(top_srcdir)/mate-settings-daemon \
+ -I$(top_srcdir)/plugins/common \
+ -I$(top_srcdir)/plugins/media-keys/cut-n-paste \
+ -DPIXMAPDIR=\""$(pkgdatadir)"\" \
+ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \
+ -DMATE_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
+ $(AM_CPPFLAGS)
+
+libmedia_keys_la_CFLAGS = \
+ $(SETTINGS_PLUGIN_CFLAGS) \
+ $(AM_CFLAGS)
+
+libmedia_keys_la_LDFLAGS = \
+ $(GSD_PLUGIN_LDFLAGS)
+
+libmedia_keys_la_LIBADD = \
+ $(top_builddir)/plugins/common/libcommon.la \
+ $(top_builddir)/plugins/media-keys/cut-n-paste/libgvc.la \
+ $(SETTINGS_PLUGIN_LIBS) \
+ $(XF86MISC_LIBS) \
+ -lm
+
+plugin_in_files = \
+ media-keys.mate-settings-plugin.in
+
+@HAVE_PULSE_TRUE@plugin_DATA = $(plugin_in_files:.mate-settings-plugin.in=.mate-settings-plugin)
+test_media_window_SOURCES = \
+ gsd-media-keys-window.c \
+ gsd-media-keys-window.h \
+ test-media-window.c \
+ $(NULL)
+
+test_media_window_CPPFLAGS = \
+ -I$(top_srcdir)/mate-settings-daemon \
+ -I$(top_srcdir)/plugins/common \
+ -I$(top_srcdir)/plugins/media-keys/cut-n-paste \
+ -DDATADIR=\""$(datadir)"\" \
+ -DPIXMAPDIR=\""$(pkgdatadir)"\" \
+ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \
+ -DMATE_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
+ $(AM_CPPFLAGS)
+
+test_media_window_CFLAGS = \
+ $(SETTINGS_PLUGIN_CFLAGS) \
+ $(AM_CFLAGS)
+
+test_media_window_LDADD = \
+ $(top_builddir)/plugins/common/libcommon.la \
+ $(SETTINGS_DAEMON_LIBS) \
+ $(SETTINGS_PLUGIN_LIBS) \
+ $(XF86MISC_LIBS) \
+ $(GST_LIBS) \
+ -lm
+
+test_media_keys_SOURCES = \
+ gsd-media-keys-manager.c \
+ gsd-media-keys-manager.h \
+ gsd-media-keys-window.h \
+ gsd-media-keys-window.c \
+ test-media-keys.c \
+ $(BUILT_SOURCES) \
+ $(NULL)
+
+test_media_keys_CPPFLAGS = \
+ -I$(top_srcdir)/mate-settings-daemon \
+ -I$(top_srcdir)/plugins/common \
+ -I$(top_srcdir)/plugins/media-keys/cut-n-paste \
+ -DPIXMAPDIR=\""$(pkgdatadir)"\" \
+ -DGTKBUILDERDIR=\""$(pkgdatadir)"\" \
+ -DMATE_SETTINGS_LOCALEDIR=\""$(datadir)/locale"\" \
+ $(AM_CPPFLAGS)
+
+test_media_keys_CFLAGS = \
+ $(SETTINGS_PLUGIN_CFLAGS) \
+ $(AM_CFLAGS)
+
+test_media_keys_LDADD = \
+ $(top_builddir)/mate-settings-daemon/libgsd-profile.la \
+ $(top_builddir)/plugins/common/libcommon.la \
+ $(SETTINGS_DAEMON_LIBS) $(SETTINGS_PLUGIN_LIBS) \
+ $(XF86MISC_LIBS) $(GST_LIBS) -lm $(am__append_3)
+gtkbuilderdir = $(pkgdatadir)
+gtkbuilder_DATA = \
+ acme.ui \
+ $(NULL)
+
+DIST_SUBDIRS = cut-n-paste
+EXTRA_DIST = \
+ gsd-media-keys-manager.xml \
+ gsd-marshal.list \
+ $(plugin_in_files) \
+ $(gtkbuilder_DATA) \
+ $(pixmaps_DATA) \
+ touchpad-enabled-template.svg \
+ touchpad-disabled-template.svg \
+ $(ICON_FILES)
+
+CLEANFILES = \
+ $(BUILT_SOURCES) \
+ $(plugin_DATA)
+
+DISTCLEANFILES = \
+ $(plugin_DATA)
+
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu plugins/media-keys/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu plugins/media-keys/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libmedia-keys.la: $(libmedia_keys_la_OBJECTS) $(libmedia_keys_la_DEPENDENCIES)
+ $(libmedia_keys_la_LINK) $(am_libmedia_keys_la_rpath) $(libmedia_keys_la_OBJECTS) $(libmedia_keys_la_LIBADD) $(LIBS)
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+test-media-keys$(EXEEXT): $(test_media_keys_OBJECTS) $(test_media_keys_DEPENDENCIES)
+ @rm -f test-media-keys$(EXEEXT)
+ $(test_media_keys_LINK) $(test_media_keys_OBJECTS) $(test_media_keys_LDADD) $(LIBS)
+test-media-window$(EXEEXT): $(test_media_window_OBJECTS) $(test_media_window_DEPENDENCIES)
+ @rm -f test-media-window$(EXEEXT)
+ $(test_media_window_LINK) $(test_media_window_OBJECTS) $(test_media_window_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmedia_keys_la-gsd-marshal.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmedia_keys_la-gsd-media-keys-manager.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmedia_keys_la-gsd-media-keys-plugin.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmedia_keys_la-gsd-media-keys-window.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_media_keys-gsd-marshal.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_media_keys-gsd-media-keys-manager.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_media_keys-gsd-media-keys-window.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_media_keys-test-media-keys.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_media_window-gsd-media-keys-window.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_media_window-test-media-window.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+libmedia_keys_la-gsd-media-keys-plugin.lo: gsd-media-keys-plugin.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmedia_keys_la_CPPFLAGS) $(CPPFLAGS) $(libmedia_keys_la_CFLAGS) $(CFLAGS) -MT libmedia_keys_la-gsd-media-keys-plugin.lo -MD -MP -MF $(DEPDIR)/libmedia_keys_la-gsd-media-keys-plugin.Tpo -c -o libmedia_keys_la-gsd-media-keys-plugin.lo `test -f 'gsd-media-keys-plugin.c' || echo '$(srcdir)/'`gsd-media-keys-plugin.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libmedia_keys_la-gsd-media-keys-plugin.Tpo $(DEPDIR)/libmedia_keys_la-gsd-media-keys-plugin.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsd-media-keys-plugin.c' object='libmedia_keys_la-gsd-media-keys-plugin.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmedia_keys_la_CPPFLAGS) $(CPPFLAGS) $(libmedia_keys_la_CFLAGS) $(CFLAGS) -c -o libmedia_keys_la-gsd-media-keys-plugin.lo `test -f 'gsd-media-keys-plugin.c' || echo '$(srcdir)/'`gsd-media-keys-plugin.c
+
+libmedia_keys_la-gsd-media-keys-manager.lo: gsd-media-keys-manager.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmedia_keys_la_CPPFLAGS) $(CPPFLAGS) $(libmedia_keys_la_CFLAGS) $(CFLAGS) -MT libmedia_keys_la-gsd-media-keys-manager.lo -MD -MP -MF $(DEPDIR)/libmedia_keys_la-gsd-media-keys-manager.Tpo -c -o libmedia_keys_la-gsd-media-keys-manager.lo `test -f 'gsd-media-keys-manager.c' || echo '$(srcdir)/'`gsd-media-keys-manager.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libmedia_keys_la-gsd-media-keys-manager.Tpo $(DEPDIR)/libmedia_keys_la-gsd-media-keys-manager.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsd-media-keys-manager.c' object='libmedia_keys_la-gsd-media-keys-manager.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmedia_keys_la_CPPFLAGS) $(CPPFLAGS) $(libmedia_keys_la_CFLAGS) $(CFLAGS) -c -o libmedia_keys_la-gsd-media-keys-manager.lo `test -f 'gsd-media-keys-manager.c' || echo '$(srcdir)/'`gsd-media-keys-manager.c
+
+libmedia_keys_la-gsd-media-keys-window.lo: gsd-media-keys-window.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmedia_keys_la_CPPFLAGS) $(CPPFLAGS) $(libmedia_keys_la_CFLAGS) $(CFLAGS) -MT libmedia_keys_la-gsd-media-keys-window.lo -MD -MP -MF $(DEPDIR)/libmedia_keys_la-gsd-media-keys-window.Tpo -c -o libmedia_keys_la-gsd-media-keys-window.lo `test -f 'gsd-media-keys-window.c' || echo '$(srcdir)/'`gsd-media-keys-window.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libmedia_keys_la-gsd-media-keys-window.Tpo $(DEPDIR)/libmedia_keys_la-gsd-media-keys-window.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsd-media-keys-window.c' object='libmedia_keys_la-gsd-media-keys-window.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmedia_keys_la_CPPFLAGS) $(CPPFLAGS) $(libmedia_keys_la_CFLAGS) $(CFLAGS) -c -o libmedia_keys_la-gsd-media-keys-window.lo `test -f 'gsd-media-keys-window.c' || echo '$(srcdir)/'`gsd-media-keys-window.c
+
+libmedia_keys_la-gsd-marshal.lo: gsd-marshal.c
+@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmedia_keys_la_CPPFLAGS) $(CPPFLAGS) $(libmedia_keys_la_CFLAGS) $(CFLAGS) -MT libmedia_keys_la-gsd-marshal.lo -MD -MP -MF $(DEPDIR)/libmedia_keys_la-gsd-marshal.Tpo -c -o libmedia_keys_la-gsd-marshal.lo `test -f 'gsd-marshal.c' || echo '$(srcdir)/'`gsd-marshal.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/libmedia_keys_la-gsd-marshal.Tpo $(DEPDIR)/libmedia_keys_la-gsd-marshal.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsd-marshal.c' object='libmedia_keys_la-gsd-marshal.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmedia_keys_la_CPPFLAGS) $(CPPFLAGS) $(libmedia_keys_la_CFLAGS) $(CFLAGS) -c -o libmedia_keys_la-gsd-marshal.lo `test -f 'gsd-marshal.c' || echo '$(srcdir)/'`gsd-marshal.c
+
+test_media_keys-gsd-media-keys-manager.o: gsd-media-keys-manager.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_keys_CPPFLAGS) $(CPPFLAGS) $(test_media_keys_CFLAGS) $(CFLAGS) -MT test_media_keys-gsd-media-keys-manager.o -MD -MP -MF $(DEPDIR)/test_media_keys-gsd-media-keys-manager.Tpo -c -o test_media_keys-gsd-media-keys-manager.o `test -f 'gsd-media-keys-manager.c' || echo '$(srcdir)/'`gsd-media-keys-manager.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/test_media_keys-gsd-media-keys-manager.Tpo $(DEPDIR)/test_media_keys-gsd-media-keys-manager.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsd-media-keys-manager.c' object='test_media_keys-gsd-media-keys-manager.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_keys_CPPFLAGS) $(CPPFLAGS) $(test_media_keys_CFLAGS) $(CFLAGS) -c -o test_media_keys-gsd-media-keys-manager.o `test -f 'gsd-media-keys-manager.c' || echo '$(srcdir)/'`gsd-media-keys-manager.c
+
+test_media_keys-gsd-media-keys-manager.obj: gsd-media-keys-manager.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_keys_CPPFLAGS) $(CPPFLAGS) $(test_media_keys_CFLAGS) $(CFLAGS) -MT test_media_keys-gsd-media-keys-manager.obj -MD -MP -MF $(DEPDIR)/test_media_keys-gsd-media-keys-manager.Tpo -c -o test_media_keys-gsd-media-keys-manager.obj `if test -f 'gsd-media-keys-manager.c'; then $(CYGPATH_W) 'gsd-media-keys-manager.c'; else $(CYGPATH_W) '$(srcdir)/gsd-media-keys-manager.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/test_media_keys-gsd-media-keys-manager.Tpo $(DEPDIR)/test_media_keys-gsd-media-keys-manager.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsd-media-keys-manager.c' object='test_media_keys-gsd-media-keys-manager.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_keys_CPPFLAGS) $(CPPFLAGS) $(test_media_keys_CFLAGS) $(CFLAGS) -c -o test_media_keys-gsd-media-keys-manager.obj `if test -f 'gsd-media-keys-manager.c'; then $(CYGPATH_W) 'gsd-media-keys-manager.c'; else $(CYGPATH_W) '$(srcdir)/gsd-media-keys-manager.c'; fi`
+
+test_media_keys-gsd-media-keys-window.o: gsd-media-keys-window.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_keys_CPPFLAGS) $(CPPFLAGS) $(test_media_keys_CFLAGS) $(CFLAGS) -MT test_media_keys-gsd-media-keys-window.o -MD -MP -MF $(DEPDIR)/test_media_keys-gsd-media-keys-window.Tpo -c -o test_media_keys-gsd-media-keys-window.o `test -f 'gsd-media-keys-window.c' || echo '$(srcdir)/'`gsd-media-keys-window.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/test_media_keys-gsd-media-keys-window.Tpo $(DEPDIR)/test_media_keys-gsd-media-keys-window.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsd-media-keys-window.c' object='test_media_keys-gsd-media-keys-window.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_keys_CPPFLAGS) $(CPPFLAGS) $(test_media_keys_CFLAGS) $(CFLAGS) -c -o test_media_keys-gsd-media-keys-window.o `test -f 'gsd-media-keys-window.c' || echo '$(srcdir)/'`gsd-media-keys-window.c
+
+test_media_keys-gsd-media-keys-window.obj: gsd-media-keys-window.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_keys_CPPFLAGS) $(CPPFLAGS) $(test_media_keys_CFLAGS) $(CFLAGS) -MT test_media_keys-gsd-media-keys-window.obj -MD -MP -MF $(DEPDIR)/test_media_keys-gsd-media-keys-window.Tpo -c -o test_media_keys-gsd-media-keys-window.obj `if test -f 'gsd-media-keys-window.c'; then $(CYGPATH_W) 'gsd-media-keys-window.c'; else $(CYGPATH_W) '$(srcdir)/gsd-media-keys-window.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/test_media_keys-gsd-media-keys-window.Tpo $(DEPDIR)/test_media_keys-gsd-media-keys-window.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsd-media-keys-window.c' object='test_media_keys-gsd-media-keys-window.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_keys_CPPFLAGS) $(CPPFLAGS) $(test_media_keys_CFLAGS) $(CFLAGS) -c -o test_media_keys-gsd-media-keys-window.obj `if test -f 'gsd-media-keys-window.c'; then $(CYGPATH_W) 'gsd-media-keys-window.c'; else $(CYGPATH_W) '$(srcdir)/gsd-media-keys-window.c'; fi`
+
+test_media_keys-test-media-keys.o: test-media-keys.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_keys_CPPFLAGS) $(CPPFLAGS) $(test_media_keys_CFLAGS) $(CFLAGS) -MT test_media_keys-test-media-keys.o -MD -MP -MF $(DEPDIR)/test_media_keys-test-media-keys.Tpo -c -o test_media_keys-test-media-keys.o `test -f 'test-media-keys.c' || echo '$(srcdir)/'`test-media-keys.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/test_media_keys-test-media-keys.Tpo $(DEPDIR)/test_media_keys-test-media-keys.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-media-keys.c' object='test_media_keys-test-media-keys.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_keys_CPPFLAGS) $(CPPFLAGS) $(test_media_keys_CFLAGS) $(CFLAGS) -c -o test_media_keys-test-media-keys.o `test -f 'test-media-keys.c' || echo '$(srcdir)/'`test-media-keys.c
+
+test_media_keys-test-media-keys.obj: test-media-keys.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_keys_CPPFLAGS) $(CPPFLAGS) $(test_media_keys_CFLAGS) $(CFLAGS) -MT test_media_keys-test-media-keys.obj -MD -MP -MF $(DEPDIR)/test_media_keys-test-media-keys.Tpo -c -o test_media_keys-test-media-keys.obj `if test -f 'test-media-keys.c'; then $(CYGPATH_W) 'test-media-keys.c'; else $(CYGPATH_W) '$(srcdir)/test-media-keys.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/test_media_keys-test-media-keys.Tpo $(DEPDIR)/test_media_keys-test-media-keys.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-media-keys.c' object='test_media_keys-test-media-keys.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_keys_CPPFLAGS) $(CPPFLAGS) $(test_media_keys_CFLAGS) $(CFLAGS) -c -o test_media_keys-test-media-keys.obj `if test -f 'test-media-keys.c'; then $(CYGPATH_W) 'test-media-keys.c'; else $(CYGPATH_W) '$(srcdir)/test-media-keys.c'; fi`
+
+test_media_keys-gsd-marshal.o: gsd-marshal.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_keys_CPPFLAGS) $(CPPFLAGS) $(test_media_keys_CFLAGS) $(CFLAGS) -MT test_media_keys-gsd-marshal.o -MD -MP -MF $(DEPDIR)/test_media_keys-gsd-marshal.Tpo -c -o test_media_keys-gsd-marshal.o `test -f 'gsd-marshal.c' || echo '$(srcdir)/'`gsd-marshal.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/test_media_keys-gsd-marshal.Tpo $(DEPDIR)/test_media_keys-gsd-marshal.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsd-marshal.c' object='test_media_keys-gsd-marshal.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_keys_CPPFLAGS) $(CPPFLAGS) $(test_media_keys_CFLAGS) $(CFLAGS) -c -o test_media_keys-gsd-marshal.o `test -f 'gsd-marshal.c' || echo '$(srcdir)/'`gsd-marshal.c
+
+test_media_keys-gsd-marshal.obj: gsd-marshal.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_keys_CPPFLAGS) $(CPPFLAGS) $(test_media_keys_CFLAGS) $(CFLAGS) -MT test_media_keys-gsd-marshal.obj -MD -MP -MF $(DEPDIR)/test_media_keys-gsd-marshal.Tpo -c -o test_media_keys-gsd-marshal.obj `if test -f 'gsd-marshal.c'; then $(CYGPATH_W) 'gsd-marshal.c'; else $(CYGPATH_W) '$(srcdir)/gsd-marshal.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/test_media_keys-gsd-marshal.Tpo $(DEPDIR)/test_media_keys-gsd-marshal.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsd-marshal.c' object='test_media_keys-gsd-marshal.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_keys_CPPFLAGS) $(CPPFLAGS) $(test_media_keys_CFLAGS) $(CFLAGS) -c -o test_media_keys-gsd-marshal.obj `if test -f 'gsd-marshal.c'; then $(CYGPATH_W) 'gsd-marshal.c'; else $(CYGPATH_W) '$(srcdir)/gsd-marshal.c'; fi`
+
+test_media_window-gsd-media-keys-window.o: gsd-media-keys-window.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_window_CPPFLAGS) $(CPPFLAGS) $(test_media_window_CFLAGS) $(CFLAGS) -MT test_media_window-gsd-media-keys-window.o -MD -MP -MF $(DEPDIR)/test_media_window-gsd-media-keys-window.Tpo -c -o test_media_window-gsd-media-keys-window.o `test -f 'gsd-media-keys-window.c' || echo '$(srcdir)/'`gsd-media-keys-window.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/test_media_window-gsd-media-keys-window.Tpo $(DEPDIR)/test_media_window-gsd-media-keys-window.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsd-media-keys-window.c' object='test_media_window-gsd-media-keys-window.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_window_CPPFLAGS) $(CPPFLAGS) $(test_media_window_CFLAGS) $(CFLAGS) -c -o test_media_window-gsd-media-keys-window.o `test -f 'gsd-media-keys-window.c' || echo '$(srcdir)/'`gsd-media-keys-window.c
+
+test_media_window-gsd-media-keys-window.obj: gsd-media-keys-window.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_window_CPPFLAGS) $(CPPFLAGS) $(test_media_window_CFLAGS) $(CFLAGS) -MT test_media_window-gsd-media-keys-window.obj -MD -MP -MF $(DEPDIR)/test_media_window-gsd-media-keys-window.Tpo -c -o test_media_window-gsd-media-keys-window.obj `if test -f 'gsd-media-keys-window.c'; then $(CYGPATH_W) 'gsd-media-keys-window.c'; else $(CYGPATH_W) '$(srcdir)/gsd-media-keys-window.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/test_media_window-gsd-media-keys-window.Tpo $(DEPDIR)/test_media_window-gsd-media-keys-window.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='gsd-media-keys-window.c' object='test_media_window-gsd-media-keys-window.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_window_CPPFLAGS) $(CPPFLAGS) $(test_media_window_CFLAGS) $(CFLAGS) -c -o test_media_window-gsd-media-keys-window.obj `if test -f 'gsd-media-keys-window.c'; then $(CYGPATH_W) 'gsd-media-keys-window.c'; else $(CYGPATH_W) '$(srcdir)/gsd-media-keys-window.c'; fi`
+
+test_media_window-test-media-window.o: test-media-window.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_window_CPPFLAGS) $(CPPFLAGS) $(test_media_window_CFLAGS) $(CFLAGS) -MT test_media_window-test-media-window.o -MD -MP -MF $(DEPDIR)/test_media_window-test-media-window.Tpo -c -o test_media_window-test-media-window.o `test -f 'test-media-window.c' || echo '$(srcdir)/'`test-media-window.c
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/test_media_window-test-media-window.Tpo $(DEPDIR)/test_media_window-test-media-window.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-media-window.c' object='test_media_window-test-media-window.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_window_CPPFLAGS) $(CPPFLAGS) $(test_media_window_CFLAGS) $(CFLAGS) -c -o test_media_window-test-media-window.o `test -f 'test-media-window.c' || echo '$(srcdir)/'`test-media-window.c
+
+test_media_window-test-media-window.obj: test-media-window.c
+@am__fastdepCC_TRUE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_window_CPPFLAGS) $(CPPFLAGS) $(test_media_window_CFLAGS) $(CFLAGS) -MT test_media_window-test-media-window.obj -MD -MP -MF $(DEPDIR)/test_media_window-test-media-window.Tpo -c -o test_media_window-test-media-window.obj `if test -f 'test-media-window.c'; then $(CYGPATH_W) 'test-media-window.c'; else $(CYGPATH_W) '$(srcdir)/test-media-window.c'; fi`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/test_media_window-test-media-window.Tpo $(DEPDIR)/test_media_window-test-media-window.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test-media-window.c' object='test_media_window-test-media-window.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(test_media_window_CPPFLAGS) $(CPPFLAGS) $(test_media_window_CFLAGS) $(CFLAGS) -c -o test_media_window-test-media-window.obj `if test -f 'test-media-window.c'; then $(CYGPATH_W) 'test-media-window.c'; else $(CYGPATH_W) '$(srcdir)/test-media-window.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-gtkbuilderDATA: $(gtkbuilder_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(gtkbuilderdir)" || $(MKDIR_P) "$(DESTDIR)$(gtkbuilderdir)"
+ @list='$(gtkbuilder_DATA)'; test -n "$(gtkbuilderdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(gtkbuilderdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(gtkbuilderdir)" || exit $$?; \
+ done
+
+uninstall-gtkbuilderDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(gtkbuilder_DATA)'; test -n "$(gtkbuilderdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(gtkbuilderdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(gtkbuilderdir)" && rm -f $$files
+install-pluginDATA: $(plugin_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_DATA)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(plugindir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(plugindir)" || exit $$?; \
+ done
+
+uninstall-pluginDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_DATA)'; test -n "$(plugindir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(plugindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(plugindir)" && rm -f $$files
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-recursive
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(gtkbuilderdir)" "$(DESTDIR)$(plugindir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool clean-noinstPROGRAMS \
+ clean-pluginLTLIBRARIES mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-data-local install-gtkbuilderDATA \
+ install-pluginDATA install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-gtkbuilderDATA uninstall-local \
+ uninstall-pluginDATA uninstall-pluginLTLIBRARIES
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all check \
+ ctags-recursive install install-am install-strip \
+ tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am check check-am clean clean-generic clean-libtool \
+ clean-noinstPROGRAMS clean-pluginLTLIBRARIES ctags \
+ ctags-recursive distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-data-local install-dvi install-dvi-am \
+ install-exec install-exec-am install-gtkbuilderDATA \
+ install-html install-html-am install-info install-info-am \
+ install-man install-pdf install-pdf-am install-pluginDATA \
+ install-pluginLTLIBRARIES install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \
+ uninstall uninstall-am uninstall-gtkbuilderDATA \
+ uninstall-local uninstall-pluginDATA \
+ uninstall-pluginLTLIBRARIES
+
+
+install-data-local:
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/16x16/$(context)
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/22x22/$(context)
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/24x24/$(context)
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/32x32/$(context)
+ $(mkinstalldirs) $(DESTDIR)$(icondir)/scalable/$(context)
+ $(INSTALL_DATA) $(srcdir)/touchpad-enabled-16.png $(DESTDIR)$(icondir)/16x16/$(context)/touchpad-enabled.png
+ $(INSTALL_DATA) $(srcdir)/touchpad-enabled-22.png $(DESTDIR)$(icondir)/22x22/$(context)/touchpad-enabled.png
+ $(INSTALL_DATA) $(srcdir)/touchpad-enabled-24.png $(DESTDIR)$(icondir)/24x24/$(context)/touchpad-enabled.png
+ $(INSTALL_DATA) $(srcdir)/touchpad-enabled-32.png $(DESTDIR)$(icondir)/32x32/$(context)/touchpad-enabled.png
+ $(INSTALL_DATA) $(srcdir)/touchpad-enabled.svg $(DESTDIR)$(icondir)/scalable/$(context)/touchpad-enabled.svg
+ $(INSTALL_DATA) $(srcdir)/touchpad-disabled-16.png $(DESTDIR)$(icondir)/16x16/$(context)/touchpad-disabled.png
+ $(INSTALL_DATA) $(srcdir)/touchpad-disabled-22.png $(DESTDIR)$(icondir)/22x22/$(context)/touchpad-disabled.png
+ $(INSTALL_DATA) $(srcdir)/touchpad-disabled-24.png $(DESTDIR)$(icondir)/24x24/$(context)/touchpad-disabled.png
+ $(INSTALL_DATA) $(srcdir)/touchpad-disabled-32.png $(DESTDIR)$(icondir)/32x32/$(context)/touchpad-disabled.png
+ $(INSTALL_DATA) $(srcdir)/touchpad-disabled.svg $(DESTDIR)$(icondir)/scalable/$(context)/touchpad-disabled.svg
+
+uninstall-local:
+ rm -f $(DESTDIR)$(icondir)/16x16/$(context)/touchpad-enabled.png
+ rm -f $(DESTDIR)$(icondir)/22x22/$(context)/touchpad-enabled.png
+ rm -f $(DESTDIR)$(icondir)/24x24/$(context)/touchpad-enabled.png
+ rm -f $(DESTDIR)$(icondir)/32x32/$(context)/touchpad-enabled.png
+ rm -f $(DESTDIR)$(icondir)/scalable/$(context)/touchpad-enabled.svg
+ rm -f $(DESTDIR)$(icondir)/16x16/$(context)/touchpad-disabled.png
+ rm -f $(DESTDIR)$(icondir)/22x22/$(context)/touchpad-disabled.png
+ rm -f $(DESTDIR)$(icondir)/24x24/$(context)/touchpad-disabled.png
+ rm -f $(DESTDIR)$(icondir)/32x32/$(context)/touchpad-disabled.png
+ rm -f $(DESTDIR)$(icondir)/scalable/$(context)/touchpad-disabled.svg
+
+gsd-media-keys-manager-glue.h: gsd-media-keys-manager.xml Makefile
+ dbus-binding-tool --prefix=gsd_media_keys_manager --mode=glib-server $< > xgen-$(@F) \
+ && ( cmp -s xgen-$(@F) $@ || cp xgen-$(@F) $@ ) \
+ && rm -f xgen-$(@F)
+
+gsd-marshal.c: gsd-marshal.list
+ $(GLIB_GENMARSHAL) --prefix=gsd_marshal $< --header --body --internal > $@
+
+gsd-marshal.h: gsd-marshal.list
+ $(GLIB_GENMARSHAL) --prefix=gsd_marshal $< --header --internal > $@
+
+@GSD_INTLTOOL_PLUGIN_RULE@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/plugins/media-keys/acme.h b/plugins/media-keys/acme.h
new file mode 100644
index 0000000..66e13bc
--- /dev/null
+++ b/plugins/media-keys/acme.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2001 Bastien Nocera <[email protected]>
+ *
+ * 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.
+ */
+
+#ifndef __ACME_H__
+#define __ACME_H__
+
+#include "gsd-keygrab.h"
+
+#define MATECONF_BINDING_DIR "/apps/mate_settings_daemon/keybindings"
+#define MATECONF_MISC_DIR "/apps/mate_settings_daemon"
+
+enum {
+ TOUCHPAD_KEY,
+ MUTE_KEY,
+ VOLUME_DOWN_KEY,
+ VOLUME_UP_KEY,
+ POWER_KEY,
+ EJECT_KEY,
+ HOME_KEY,
+ MEDIA_KEY,
+ CALCULATOR_KEY,
+ SEARCH_KEY,
+ EMAIL_KEY,
+ SCREENSAVER_KEY,
+ HELP_KEY,
+ WWW_KEY,
+ PLAY_KEY,
+ PAUSE_KEY,
+ STOP_KEY,
+ PREVIOUS_KEY,
+ NEXT_KEY,
+ HANDLED_KEYS
+};
+
+static struct {
+ int key_type;
+ const char *mateconf_key;
+ Key *key;
+} keys[HANDLED_KEYS] = {
+ { TOUCHPAD_KEY, MATECONF_BINDING_DIR "/touchpad", NULL },
+ { MUTE_KEY, MATECONF_BINDING_DIR "/volume_mute",NULL },
+ { VOLUME_DOWN_KEY, MATECONF_BINDING_DIR "/volume_down", NULL },
+ { VOLUME_UP_KEY, MATECONF_BINDING_DIR "/volume_up", NULL },
+ { POWER_KEY, MATECONF_BINDING_DIR "/power", NULL },
+ { EJECT_KEY, MATECONF_BINDING_DIR "/eject", NULL },
+ { HOME_KEY, MATECONF_BINDING_DIR "/home", NULL },
+ { MEDIA_KEY, MATECONF_BINDING_DIR "/media", NULL },
+ { CALCULATOR_KEY, MATECONF_BINDING_DIR "/calculator", NULL },
+ { SEARCH_KEY, MATECONF_BINDING_DIR "/search", NULL },
+ { EMAIL_KEY, MATECONF_BINDING_DIR "/email", NULL },
+ { SCREENSAVER_KEY, MATECONF_BINDING_DIR "/screensaver", NULL },
+ { HELP_KEY, MATECONF_BINDING_DIR "/help", NULL },
+ { WWW_KEY, MATECONF_BINDING_DIR "/www", NULL },
+ { PLAY_KEY, MATECONF_BINDING_DIR "/play", NULL },
+ { PAUSE_KEY, MATECONF_BINDING_DIR "/pause", NULL },
+ { STOP_KEY, MATECONF_BINDING_DIR "/stop", NULL },
+ { PREVIOUS_KEY, MATECONF_BINDING_DIR "/previous", NULL },
+ { NEXT_KEY, MATECONF_BINDING_DIR "/next", NULL },
+};
+
+#endif /* __ACME_H__ */
diff --git a/plugins/media-keys/acme.ui b/plugins/media-keys/acme.ui
new file mode 100644
index 0000000..e0457ed
--- /dev/null
+++ b/plugins/media-keys/acme.ui
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<interface>
+ <!-- interface-requires gtk+ 2.6 -->
+ <!-- interface-naming-policy toplevel-contextual -->
+ <object class="GtkWindow" id="dialog">
+ <child>
+ <object class="GtkVBox" id="acme_box">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage" id="acme_image">
+ <property name="visible">True</property>
+ <property name="icon_name">audio-volume-high</property>
+ <property name="icon-size">6</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkProgressBar" id="acme_volume_progressbar">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/plugins/media-keys/cut-n-paste/Makefile.am b/plugins/media-keys/cut-n-paste/Makefile.am
new file mode 100644
index 0000000..bc59a10
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/Makefile.am
@@ -0,0 +1,39 @@
+NULL =
+
+noinst_LTLIBRARIES = libgvc.la
+
+INCLUDES = \
+ $(WARN_CFLAGS) \
+ $(VOLUME_CONTROL_CFLAGS) \
+ $(PULSE_CFLAGS) \
+ $(NULL)
+
+libgvc_la_LIBADD = \
+ $(VOLUME_CONTROL_LIBS) \
+ $(PULSE_LIBS) \
+ $(NULL)
+
+libgvc_la_SOURCES = \
+ gvc-mixer-stream.h \
+ gvc-mixer-stream.c \
+ gvc-channel-map.h \
+ gvc-channel-map.c \
+ gvc-mixer-card.c \
+ gvc-mixer-card.h \
+ gvc-mixer-sink.h \
+ gvc-mixer-sink.c \
+ gvc-mixer-source.h \
+ gvc-mixer-source.c \
+ gvc-mixer-sink-input.h \
+ gvc-mixer-sink-input.c \
+ gvc-mixer-source-output.h \
+ gvc-mixer-source-output.c \
+ gvc-mixer-event-role.h \
+ gvc-mixer-event-role.c \
+ gvc-mixer-control.h \
+ gvc-mixer-control.c \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ *~ \
+ Makefile.in
diff --git a/plugins/media-keys/cut-n-paste/Makefile.in b/plugins/media-keys/cut-n-paste/Makefile.in
new file mode 100644
index 0000000..9fbfa1c
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/Makefile.in
@@ -0,0 +1,586 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = plugins/media-keys/cut-n-paste
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgvc_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+am__objects_1 =
+am_libgvc_la_OBJECTS = gvc-mixer-stream.lo gvc-channel-map.lo \
+ gvc-mixer-card.lo gvc-mixer-sink.lo gvc-mixer-source.lo \
+ gvc-mixer-sink-input.lo gvc-mixer-source-output.lo \
+ gvc-mixer-event-role.lo gvc-mixer-control.lo $(am__objects_1)
+libgvc_la_OBJECTS = $(am_libgvc_la_OBJECTS)
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
+SOURCES = $(libgvc_la_SOURCES)
+DIST_SOURCES = $(libgvc_la_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DBUS_SYS_DIR = @DBUS_SYS_DIR@
+DEBUG_CFLAGS = @DEBUG_CFLAGS@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
+FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GIOUNIX_CFLAGS = @GIOUNIX_CFLAGS@
+GIOUNIX_LIBS = @GIOUNIX_LIBS@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GREP = @GREP@
+GSD_INTLTOOL_PLUGIN_RULE = @GSD_INTLTOOL_PLUGIN_RULE@
+GSD_PLUGIN_LDFLAGS = @GSD_PLUGIN_LDFLAGS@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBEXECDIR = @LIBEXECDIR@
+LIBMATEKBDUI_CFLAGS = @LIBMATEKBDUI_CFLAGS@
+LIBMATEKBDUI_LIBS = @LIBMATEKBDUI_LIBS@
+LIBMATENOTIFY_CFLAGS = @LIBMATENOTIFY_CFLAGS@
+LIBMATENOTIFY_LIBS = @LIBMATENOTIFY_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MATECONFTOOL = @MATECONFTOOL@
+MATECONF_SCHEMA_CONFIG_SOURCE = @MATECONF_SCHEMA_CONFIG_SOURCE@
+MATECONF_SCHEMA_FILE_DIR = @MATECONF_SCHEMA_FILE_DIR@
+MATE_KEYBINDINGS_KEYSDIR = @MATE_KEYBINDINGS_KEYSDIR@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NSS_CFLAGS = @NSS_CFLAGS@
+NSS_DATABASE = @NSS_DATABASE@
+NSS_LIBS = @NSS_LIBS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+POFILES = @POFILES@
+POLKIT_CFLAGS = @POLKIT_CFLAGS@
+POLKIT_LIBS = @POLKIT_LIBS@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+PULSE_CFLAGS = @PULSE_CFLAGS@
+PULSE_LIBS = @PULSE_LIBS@
+RANLIB = @RANLIB@
+SED = @SED@
+SETTINGS_DAEMON_CFLAGS = @SETTINGS_DAEMON_CFLAGS@
+SETTINGS_DAEMON_LIBS = @SETTINGS_DAEMON_LIBS@
+SETTINGS_PLUGIN_CFLAGS = @SETTINGS_PLUGIN_CFLAGS@
+SETTINGS_PLUGIN_LIBS = @SETTINGS_PLUGIN_LIBS@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+STRIP = @STRIP@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+X11_LIBS = @X11_LIBS@
+XF86MISC_LIBS = @XF86MISC_LIBS@
+XGETTEXT = @XGETTEXT@
+XINPUT_LIBS = @XINPUT_LIBS@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+plugindir = @plugindir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+NULL =
+noinst_LTLIBRARIES = libgvc.la
+INCLUDES = \
+ $(WARN_CFLAGS) \
+ $(VOLUME_CONTROL_CFLAGS) \
+ $(PULSE_CFLAGS) \
+ $(NULL)
+
+libgvc_la_LIBADD = \
+ $(VOLUME_CONTROL_LIBS) \
+ $(PULSE_LIBS) \
+ $(NULL)
+
+libgvc_la_SOURCES = \
+ gvc-mixer-stream.h \
+ gvc-mixer-stream.c \
+ gvc-channel-map.h \
+ gvc-channel-map.c \
+ gvc-mixer-card.c \
+ gvc-mixer-card.h \
+ gvc-mixer-sink.h \
+ gvc-mixer-sink.c \
+ gvc-mixer-source.h \
+ gvc-mixer-source.c \
+ gvc-mixer-sink-input.h \
+ gvc-mixer-sink-input.c \
+ gvc-mixer-source-output.h \
+ gvc-mixer-source-output.c \
+ gvc-mixer-event-role.h \
+ gvc-mixer-event-role.c \
+ gvc-mixer-control.h \
+ gvc-mixer-control.c \
+ $(NULL)
+
+MAINTAINERCLEANFILES = \
+ *~ \
+ Makefile.in
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu plugins/media-keys/cut-n-paste/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu plugins/media-keys/cut-n-paste/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgvc.la: $(libgvc_la_OBJECTS) $(libgvc_la_DEPENDENCIES)
+ $(LINK) $(libgvc_la_OBJECTS) $(libgvc_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gvc-channel-map.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gvc-mixer-card.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gvc-mixer-control.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gvc-mixer-event-role.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gvc-mixer-sink-input.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gvc-mixer-sink.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gvc-mixer-source-output.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gvc-mixer-source.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gvc-mixer-stream.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/plugins/media-keys/cut-n-paste/gvc-channel-map.c b/plugins/media-keys/cut-n-paste/gvc-channel-map.c
new file mode 100644
index 0000000..ea3e5af
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/gvc-channel-map.c
@@ -0,0 +1,292 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 William Jon McCann
+ *
+ * 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 "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "gvc-channel-map.h"
+
+#define GVC_CHANNEL_MAP_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_CHANNEL_MAP, GvcChannelMapPrivate))
+
+#ifndef PA_CHECK_VERSION
+#define PA_CHECK_VERSION(major,minor,micro) \
+ ((PA_MAJOR > (major)) || \
+ (PA_MAJOR == (major) && PA_MINOR > (minor)) || \
+ (PA_MAJOR == (major) && PA_MINOR == (minor) && PA_MICRO >= (micro)))
+#endif
+
+
+struct GvcChannelMapPrivate
+{
+ pa_channel_map pa_map;
+ gboolean pa_volume_is_set;
+ pa_cvolume pa_volume;
+ gdouble extern_volume[NUM_TYPES]; /* volume, balance, fade, lfe */
+ gboolean can_balance;
+ gboolean can_fade;
+ gboolean has_lfe;
+};
+
+enum {
+ VOLUME_CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static void gvc_channel_map_class_init (GvcChannelMapClass *klass);
+static void gvc_channel_map_init (GvcChannelMap *channel_map);
+static void gvc_channel_map_finalize (GObject *object);
+
+G_DEFINE_TYPE (GvcChannelMap, gvc_channel_map, G_TYPE_OBJECT)
+
+/* FIXME remove when we depend on a newer PA */
+static int
+gvc_pa_channel_map_has_position (const pa_channel_map *map, pa_channel_position_t p) {
+ unsigned c;
+
+ g_return_val_if_fail(pa_channel_map_valid(map), 0);
+ g_return_val_if_fail(p < PA_CHANNEL_POSITION_MAX, 0);
+
+ for (c = 0; c < map->channels; c++)
+ if (map->map[c] == p)
+ return 1;
+
+ return 0;
+}
+
+#if !PA_CHECK_VERSION(0,9,16)
+/* The PulseAudio master increase version only when tagged, so let's avoid clashing with pa_ namespace */
+#define pa_cvolume_get_position gvc_cvolume_get_position
+static pa_volume_t
+gvc_cvolume_get_position (pa_cvolume *cv, const pa_channel_map *map, pa_channel_position_t t) {
+ unsigned c;
+ pa_volume_t v = PA_VOLUME_MUTED;
+
+ g_assert(cv);
+ g_assert(map);
+
+ g_return_val_if_fail(pa_cvolume_compatible_with_channel_map(cv, map), PA_VOLUME_MUTED);
+ g_return_val_if_fail(t < PA_CHANNEL_POSITION_MAX, PA_VOLUME_MUTED);
+
+ for (c = 0; c < map->channels; c++)
+ if (map->map[c] == t)
+ if (cv->values[c] > v)
+ v = cv->values[c];
+
+ return v;
+}
+#endif
+
+guint
+gvc_channel_map_get_num_channels (GvcChannelMap *map)
+{
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), 0);
+
+ if (!pa_channel_map_valid(&map->priv->pa_map))
+ return 0;
+
+ return map->priv->pa_map.channels;
+}
+
+const gdouble *
+gvc_channel_map_get_volume (GvcChannelMap *map)
+{
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
+
+ if (!pa_channel_map_valid(&map->priv->pa_map))
+ return NULL;
+
+ map->priv->extern_volume[VOLUME] = (gdouble) pa_cvolume_max (&map->priv->pa_volume);
+ if (gvc_channel_map_can_balance (map))
+ map->priv->extern_volume[BALANCE] = (gdouble) pa_cvolume_get_balance (&map->priv->pa_volume, &map->priv->pa_map);
+ else
+ map->priv->extern_volume[BALANCE] = 0;
+ if (gvc_channel_map_can_fade (map))
+ map->priv->extern_volume[FADE] = (gdouble) pa_cvolume_get_fade (&map->priv->pa_volume, &map->priv->pa_map);
+ else
+ map->priv->extern_volume[FADE] = 0;
+ if (gvc_channel_map_has_lfe (map))
+ map->priv->extern_volume[LFE] = (gdouble) pa_cvolume_get_position (&map->priv->pa_volume, &map->priv->pa_map, PA_CHANNEL_POSITION_LFE);
+ else
+ map->priv->extern_volume[LFE] = 0;
+
+ return map->priv->extern_volume;
+}
+
+gboolean
+gvc_channel_map_can_balance (GvcChannelMap *map)
+{
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE);
+
+ return map->priv->can_balance;
+}
+
+gboolean
+gvc_channel_map_can_fade (GvcChannelMap *map)
+{
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE);
+
+ return map->priv->can_fade;
+}
+
+const char *
+gvc_channel_map_get_mapping (GvcChannelMap *map)
+{
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
+
+ if (!pa_channel_map_valid(&map->priv->pa_map))
+ return NULL;
+
+ return pa_channel_map_to_pretty_name (&map->priv->pa_map);
+}
+
+gboolean
+gvc_channel_map_has_lfe (GvcChannelMap *map)
+{
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), FALSE);
+
+ return map->priv->has_lfe;
+}
+
+const pa_channel_map *
+gvc_channel_map_get_pa_channel_map (GvcChannelMap *map)
+{
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
+
+ if (!pa_channel_map_valid(&map->priv->pa_map))
+ return NULL;
+
+ return &map->priv->pa_map;
+}
+
+const pa_cvolume *
+gvc_channel_map_get_cvolume (GvcChannelMap *map)
+{
+ g_return_val_if_fail (GVC_IS_CHANNEL_MAP (map), NULL);
+
+ if (!pa_channel_map_valid(&map->priv->pa_map))
+ return NULL;
+
+ return &map->priv->pa_volume;
+}
+
+static void
+gvc_channel_map_class_init (GvcChannelMapClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = gvc_channel_map_finalize;
+
+ signals [VOLUME_CHANGED] =
+ g_signal_new ("volume-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GvcChannelMapClass, volume_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
+
+ g_type_class_add_private (klass, sizeof (GvcChannelMapPrivate));
+}
+
+void
+gvc_channel_map_volume_changed (GvcChannelMap *map,
+ const pa_cvolume *cv,
+ gboolean set)
+{
+ g_return_if_fail (GVC_IS_CHANNEL_MAP (map));
+ g_return_if_fail (cv != NULL);
+ g_return_if_fail (pa_cvolume_compatible_with_channel_map(cv, &map->priv->pa_map));
+
+ if (pa_cvolume_equal(cv, &map->priv->pa_volume))
+ return;
+
+ map->priv->pa_volume = *cv;
+
+ if (map->priv->pa_volume_is_set == FALSE) {
+ map->priv->pa_volume_is_set = TRUE;
+ return;
+ }
+ g_signal_emit (map, signals[VOLUME_CHANGED], 0, set);
+}
+
+static void
+gvc_channel_map_init (GvcChannelMap *map)
+{
+ map->priv = GVC_CHANNEL_MAP_GET_PRIVATE (map);
+ map->priv->pa_volume_is_set = FALSE;
+}
+
+static void
+gvc_channel_map_finalize (GObject *object)
+{
+ GvcChannelMap *channel_map;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GVC_IS_CHANNEL_MAP (object));
+
+ channel_map = GVC_CHANNEL_MAP (object);
+
+ g_return_if_fail (channel_map->priv != NULL);
+
+ G_OBJECT_CLASS (gvc_channel_map_parent_class)->finalize (object);
+}
+
+GvcChannelMap *
+gvc_channel_map_new (void)
+{
+ GObject *map;
+ map = g_object_new (GVC_TYPE_CHANNEL_MAP, NULL);
+ return GVC_CHANNEL_MAP (map);
+}
+
+static void
+set_from_pa_map (GvcChannelMap *map,
+ const pa_channel_map *pa_map)
+{
+ g_assert (pa_channel_map_valid(pa_map));
+
+ map->priv->can_balance = pa_channel_map_can_balance (pa_map);
+ map->priv->can_fade = pa_channel_map_can_fade (pa_map);
+ map->priv->has_lfe = gvc_pa_channel_map_has_position (pa_map, PA_CHANNEL_POSITION_LFE);
+
+ map->priv->pa_map = *pa_map;
+ pa_cvolume_set(&map->priv->pa_volume, pa_map->channels, PA_VOLUME_NORM);
+}
+
+GvcChannelMap *
+gvc_channel_map_new_from_pa_channel_map (const pa_channel_map *pa_map)
+{
+ GObject *map;
+ map = g_object_new (GVC_TYPE_CHANNEL_MAP, NULL);
+
+ set_from_pa_map (GVC_CHANNEL_MAP (map), pa_map);
+
+ return GVC_CHANNEL_MAP (map);
+}
diff --git a/plugins/media-keys/cut-n-paste/gvc-channel-map.h b/plugins/media-keys/cut-n-paste/gvc-channel-map.h
new file mode 100644
index 0000000..8a9fa93
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/gvc-channel-map.h
@@ -0,0 +1,83 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __GVC_CHANNEL_MAP_H
+#define __GVC_CHANNEL_MAP_H
+
+#include <glib-object.h>
+#include <pulse/pulseaudio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GVC_TYPE_CHANNEL_MAP (gvc_channel_map_get_type ())
+#define GVC_CHANNEL_MAP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_CHANNEL_MAP, GvcChannelMap))
+#define GVC_CHANNEL_MAP_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_CHANNEL_MAP, GvcChannelMapClass))
+#define GVC_IS_CHANNEL_MAP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_CHANNEL_MAP))
+#define GVC_IS_CHANNEL_MAP_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_CHANNEL_MAP))
+#define GVC_CHANNEL_MAP_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_CHANNEL_MAP, GvcChannelMapClass))
+
+typedef struct GvcChannelMapPrivate GvcChannelMapPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GvcChannelMapPrivate *priv;
+} GvcChannelMap;
+
+typedef struct
+{
+ GObjectClass parent_class;
+ void (*volume_changed) (GvcChannelMap *channel_map, gboolean set);
+} GvcChannelMapClass;
+
+enum {
+ VOLUME,
+ BALANCE,
+ FADE,
+ LFE,
+};
+
+#define NUM_TYPES LFE + 1
+
+GType gvc_channel_map_get_type (void);
+
+GvcChannelMap * gvc_channel_map_new (void);
+GvcChannelMap * gvc_channel_map_new_from_pa_channel_map (const pa_channel_map *map);
+guint gvc_channel_map_get_num_channels (GvcChannelMap *map);
+const gdouble * gvc_channel_map_get_volume (GvcChannelMap *map);
+gboolean gvc_channel_map_can_balance (GvcChannelMap *map);
+gboolean gvc_channel_map_can_fade (GvcChannelMap *map);
+gboolean gvc_channel_map_has_lfe (GvcChannelMap *map);
+
+void gvc_channel_map_volume_changed (GvcChannelMap *map,
+ const pa_cvolume *cv,
+ gboolean set);
+const char * gvc_channel_map_get_mapping (GvcChannelMap *map);
+
+/* private */
+const pa_cvolume * gvc_channel_map_get_cvolume (GvcChannelMap *map);
+const pa_channel_map * gvc_channel_map_get_pa_channel_map (GvcChannelMap *map);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GVC_CHANNEL_MAP_H */
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-card.c b/plugins/media-keys/cut-n-paste/gvc-mixer-card.c
new file mode 100644
index 0000000..9037ff2
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-card.c
@@ -0,0 +1,493 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 William Jon McCann
+ * Copyright (C) 2009 Bastien Nocera
+ *
+ * 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 "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "gvc-mixer-card.h"
+
+#define GVC_MIXER_CARD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_CARD, GvcMixerCardPrivate))
+
+static guint32 card_serial = 1;
+
+struct GvcMixerCardPrivate
+{
+ pa_context *pa_context;
+ guint id;
+ guint index;
+ char *name;
+ char *icon_name;
+ char *profile;
+ char *target_profile;
+ char *human_profile;
+ GList *profiles;
+};
+
+enum
+{
+ PROP_0,
+ PROP_ID,
+ PROP_PA_CONTEXT,
+ PROP_INDEX,
+ PROP_NAME,
+ PROP_ICON_NAME,
+ PROP_PROFILE,
+ PROP_HUMAN_PROFILE,
+};
+
+static void gvc_mixer_card_class_init (GvcMixerCardClass *klass);
+static void gvc_mixer_card_init (GvcMixerCard *mixer_card);
+static void gvc_mixer_card_finalize (GObject *object);
+
+G_DEFINE_TYPE (GvcMixerCard, gvc_mixer_card, G_TYPE_OBJECT)
+
+static guint32
+get_next_card_serial (void)
+{
+ guint32 serial;
+
+ serial = card_serial++;
+
+ if ((gint32)card_serial < 0) {
+ card_serial = 1;
+ }
+
+ return serial;
+}
+
+pa_context *
+gvc_mixer_card_get_pa_context (GvcMixerCard *card)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0);
+ return card->priv->pa_context;
+}
+
+guint
+gvc_mixer_card_get_index (GvcMixerCard *card)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0);
+ return card->priv->index;
+}
+
+guint
+gvc_mixer_card_get_id (GvcMixerCard *card)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), 0);
+ return card->priv->id;
+}
+
+const char *
+gvc_mixer_card_get_name (GvcMixerCard *card)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
+ return card->priv->name;
+}
+
+gboolean
+gvc_mixer_card_set_name (GvcMixerCard *card,
+ const char *name)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
+
+ g_free (card->priv->name);
+ card->priv->name = g_strdup (name);
+ g_object_notify (G_OBJECT (card), "name");
+
+ return TRUE;
+}
+
+const char *
+gvc_mixer_card_get_icon_name (GvcMixerCard *card)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
+ return card->priv->icon_name;
+}
+
+gboolean
+gvc_mixer_card_set_icon_name (GvcMixerCard *card,
+ const char *icon_name)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
+
+ g_free (card->priv->icon_name);
+ card->priv->icon_name = g_strdup (icon_name);
+ g_object_notify (G_OBJECT (card), "icon-name");
+
+ return TRUE;
+}
+
+GvcMixerCardProfile *
+gvc_mixer_card_get_profile (GvcMixerCard *card)
+{
+ GList *l;
+
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), NULL);
+ g_return_val_if_fail (card->priv->profiles != NULL, FALSE);
+
+ for (l = card->priv->profiles; l != NULL; l = l->next) {
+ GvcMixerCardProfile *p = l->data;
+ if (g_str_equal (card->priv->profile, p->profile)) {
+ return p;
+ }
+ }
+
+ g_assert_not_reached ();
+
+ return NULL;
+}
+
+gboolean
+gvc_mixer_card_set_profile (GvcMixerCard *card,
+ const char *profile)
+{
+ GList *l;
+
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
+ g_return_val_if_fail (card->priv->profiles != NULL, FALSE);
+
+ g_free (card->priv->profile);
+ card->priv->profile = g_strdup (profile);
+
+ g_free (card->priv->human_profile);
+ card->priv->human_profile = NULL;
+
+ for (l = card->priv->profiles; l != NULL; l = l->next) {
+ GvcMixerCardProfile *p = l->data;
+ if (g_str_equal (card->priv->profile, p->profile)) {
+ card->priv->human_profile = g_strdup (p->human_profile);
+ break;
+ }
+ }
+
+ g_object_notify (G_OBJECT (card), "profile");
+
+ return TRUE;
+}
+
+static void
+_pa_context_set_card_profile_by_index_cb (pa_context *context,
+ int success,
+ void *userdata)
+{
+ GvcMixerCard *card = GVC_MIXER_CARD (userdata);
+
+ g_assert (card->priv->target_profile);
+
+ if (success > 0) {
+ gvc_mixer_card_set_profile (card, card->priv->target_profile);
+ } else {
+ g_debug ("Failed to switch profile on '%s' from '%s' to '%s'",
+ card->priv->name,
+ card->priv->profile,
+ card->priv->target_profile);
+ }
+ g_free (card->priv->target_profile);
+ card->priv->target_profile = NULL;
+}
+
+gboolean
+gvc_mixer_card_change_profile (GvcMixerCard *card,
+ const char *profile)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
+ g_return_val_if_fail (card->priv->profiles != NULL, FALSE);
+
+ /* Same profile, or already requested? */
+ if (g_strcmp0 (card->priv->profile, profile) == 0)
+ return TRUE;
+ if (g_strcmp0 (profile, card->priv->target_profile) == 0)
+ return TRUE;
+
+ if (card->priv->profile != NULL) {
+ pa_operation *o;
+
+ g_free (card->priv->target_profile);
+ card->priv->target_profile = g_strdup (profile);
+
+ o = pa_context_set_card_profile_by_index (card->priv->pa_context,
+ card->priv->index,
+ card->priv->target_profile,
+ _pa_context_set_card_profile_by_index_cb,
+ card);
+
+ if (o == NULL) {
+ g_warning ("pa_context_set_card_profile_by_index() failed");
+ return FALSE;
+ }
+
+ pa_operation_unref (o);
+ } else {
+ g_assert (card->priv->human_profile == NULL);
+ card->priv->profile = g_strdup (profile);
+ }
+
+ return TRUE;
+}
+
+const GList *
+gvc_mixer_card_get_profiles (GvcMixerCard *card)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
+ return card->priv->profiles;
+}
+
+static int
+sort_profiles (GvcMixerCardProfile *a,
+ GvcMixerCardProfile *b)
+{
+ if (a->priority == b->priority)
+ return 0;
+ if (a->priority > b->priority)
+ return 1;
+ return -1;
+}
+
+gboolean
+gvc_mixer_card_set_profiles (GvcMixerCard *card,
+ GList *profiles)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_CARD (card), FALSE);
+ g_return_val_if_fail (card->priv->profiles == NULL, FALSE);
+
+ card->priv->profiles = g_list_sort (profiles, (GCompareFunc) sort_profiles);
+
+ return TRUE;
+}
+
+static void
+gvc_mixer_card_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GvcMixerCard *self = GVC_MIXER_CARD (object);
+
+ switch (prop_id) {
+ case PROP_PA_CONTEXT:
+ self->priv->pa_context = g_value_get_pointer (value);
+ break;
+ case PROP_INDEX:
+ self->priv->index = g_value_get_ulong (value);
+ break;
+ case PROP_ID:
+ self->priv->id = g_value_get_ulong (value);
+ break;
+ case PROP_NAME:
+ gvc_mixer_card_set_name (self, g_value_get_string (value));
+ break;
+ case PROP_ICON_NAME:
+ gvc_mixer_card_set_icon_name (self, g_value_get_string (value));
+ break;
+ case PROP_PROFILE:
+ gvc_mixer_card_set_profile (self, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gvc_mixer_card_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GvcMixerCard *self = GVC_MIXER_CARD (object);
+
+ switch (prop_id) {
+ case PROP_PA_CONTEXT:
+ g_value_set_pointer (value, self->priv->pa_context);
+ break;
+ case PROP_INDEX:
+ g_value_set_ulong (value, self->priv->index);
+ break;
+ case PROP_ID:
+ g_value_set_ulong (value, self->priv->id);
+ break;
+ case PROP_NAME:
+ g_value_set_string (value, self->priv->name);
+ break;
+ case PROP_ICON_NAME:
+ g_value_set_string (value, self->priv->icon_name);
+ break;
+ case PROP_PROFILE:
+ g_value_set_string (value, self->priv->profile);
+ break;
+ case PROP_HUMAN_PROFILE:
+ g_value_set_string (value, self->priv->human_profile);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GObject *
+gvc_mixer_card_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+ GvcMixerCard *self;
+
+ object = G_OBJECT_CLASS (gvc_mixer_card_parent_class)->constructor (type, n_construct_properties, construct_params);
+
+ self = GVC_MIXER_CARD (object);
+
+ self->priv->id = get_next_card_serial ();
+
+ return object;
+}
+
+static void
+gvc_mixer_card_class_init (GvcMixerCardClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->constructor = gvc_mixer_card_constructor;
+ gobject_class->finalize = gvc_mixer_card_finalize;
+
+ gobject_class->set_property = gvc_mixer_card_set_property;
+ gobject_class->get_property = gvc_mixer_card_get_property;
+
+ g_object_class_install_property (gobject_class,
+ PROP_INDEX,
+ g_param_spec_ulong ("index",
+ "Index",
+ "The index for this card",
+ 0, G_MAXULONG, 0,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (gobject_class,
+ PROP_ID,
+ g_param_spec_ulong ("id",
+ "id",
+ "The id for this card",
+ 0, G_MAXULONG, 0,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (gobject_class,
+ PROP_PA_CONTEXT,
+ g_param_spec_pointer ("pa-context",
+ "PulseAudio context",
+ "The PulseAudio context for this card",
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (gobject_class,
+ PROP_NAME,
+ g_param_spec_string ("name",
+ "Name",
+ "Name to display for this card",
+ NULL,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property (gobject_class,
+ PROP_ICON_NAME,
+ g_param_spec_string ("icon-name",
+ "Icon Name",
+ "Name of icon to display for this card",
+ NULL,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property (gobject_class,
+ PROP_PROFILE,
+ g_param_spec_string ("profile",
+ "Profile",
+ "Name of current profile for this card",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class,
+ PROP_HUMAN_PROFILE,
+ g_param_spec_string ("human-profile",
+ "Profile (Human readable)",
+ "Name of current profile for this card in human readable form",
+ NULL,
+ G_PARAM_READABLE));
+
+ g_type_class_add_private (klass, sizeof (GvcMixerCardPrivate));
+}
+
+static void
+gvc_mixer_card_init (GvcMixerCard *card)
+{
+ card->priv = GVC_MIXER_CARD_GET_PRIVATE (card);
+}
+
+GvcMixerCard *
+gvc_mixer_card_new (pa_context *context,
+ guint index)
+{
+ GObject *object;
+
+ object = g_object_new (GVC_TYPE_MIXER_CARD,
+ "index", index,
+ "pa-context", context,
+ NULL);
+ return GVC_MIXER_CARD (object);
+}
+
+static void
+free_profile (GvcMixerCardProfile *p)
+{
+ g_free (p->profile);
+ g_free (p->human_profile);
+ g_free (p->status);
+ g_free (p);
+}
+
+static void
+gvc_mixer_card_finalize (GObject *object)
+{
+ GvcMixerCard *mixer_card;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GVC_IS_MIXER_CARD (object));
+
+ mixer_card = GVC_MIXER_CARD (object);
+
+ g_return_if_fail (mixer_card->priv != NULL);
+
+ g_free (mixer_card->priv->name);
+ mixer_card->priv->name = NULL;
+
+ g_free (mixer_card->priv->icon_name);
+ mixer_card->priv->icon_name = NULL;
+
+ g_free (mixer_card->priv->target_profile);
+ mixer_card->priv->target_profile = NULL;
+
+ g_free (mixer_card->priv->profile);
+ mixer_card->priv->profile = NULL;
+
+ g_free (mixer_card->priv->human_profile);
+ mixer_card->priv->human_profile = NULL;
+
+ g_list_foreach (mixer_card->priv->profiles, (GFunc) free_profile, NULL);
+ g_list_free (mixer_card->priv->profiles);
+ mixer_card->priv->profiles = NULL;
+
+ G_OBJECT_CLASS (gvc_mixer_card_parent_class)->finalize (object);
+}
+
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-card.h b/plugins/media-keys/cut-n-paste/gvc-mixer-card.h
new file mode 100644
index 0000000..eeaa29f
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-card.h
@@ -0,0 +1,90 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008-2009 Red Hat, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __GVC_MIXER_CARD_H
+#define __GVC_MIXER_CARD_H
+
+#include <glib-object.h>
+#include <pulse/pulseaudio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GVC_TYPE_MIXER_CARD (gvc_mixer_card_get_type ())
+#define GVC_MIXER_CARD(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_CARD, GvcMixerCard))
+#define GVC_MIXER_CARD_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_CARD, GvcMixerCardClass))
+#define GVC_IS_MIXER_CARD(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_CARD))
+#define GVC_IS_MIXER_CARD_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_CARD))
+#define GVC_MIXER_CARD_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_CARD, GvcMixerCardClass))
+
+typedef struct GvcMixerCardPrivate GvcMixerCardPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GvcMixerCardPrivate *priv;
+} GvcMixerCard;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+ /* vtable */
+} GvcMixerCardClass;
+
+typedef struct
+{
+ char *profile;
+ char *human_profile;
+ char *status;
+ guint priority;
+} GvcMixerCardProfile;
+
+GType gvc_mixer_card_get_type (void);
+GvcMixerCard * gvc_mixer_card_new (pa_context *context,
+ guint index);
+
+guint gvc_mixer_card_get_id (GvcMixerCard *card);
+guint gvc_mixer_card_get_index (GvcMixerCard *card);
+const char * gvc_mixer_card_get_name (GvcMixerCard *card);
+const char * gvc_mixer_card_get_icon_name (GvcMixerCard *card);
+GvcMixerCardProfile * gvc_mixer_card_get_profile (GvcMixerCard *card);
+const GList * gvc_mixer_card_get_profiles (GvcMixerCard *card);
+
+pa_context * gvc_mixer_card_get_pa_context (GvcMixerCard *card);
+gboolean gvc_mixer_card_change_profile (GvcMixerCard *card,
+ const char *profile);
+
+/* private */
+gboolean gvc_mixer_card_set_name (GvcMixerCard *card,
+ const char *name);
+gboolean gvc_mixer_card_set_icon_name (GvcMixerCard *card,
+ const char *name);
+gboolean gvc_mixer_card_set_profile (GvcMixerCard *card,
+ const char *profile);
+gboolean gvc_mixer_card_set_profiles (GvcMixerCard *card,
+ GList *profiles);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GVC_MIXER_CARD_H */
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-control.c b/plugins/media-keys/cut-n-paste/gvc-mixer-control.c
new file mode 100644
index 0000000..2c8d510
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-control.c
@@ -0,0 +1,2123 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2006-2008 Lennart Poettering
+ * Copyright (C) 2008 Sjoerd Simons <[email protected]>
+ * Copyright (C) 2008 William Jon McCann
+ *
+ * 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 "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <pulse/pulseaudio.h>
+#include <pulse/glib-mainloop.h>
+#include <pulse/ext-stream-restore.h>
+
+#include "gvc-mixer-control.h"
+#include "gvc-mixer-sink.h"
+#include "gvc-mixer-source.h"
+#include "gvc-mixer-sink-input.h"
+#include "gvc-mixer-source-output.h"
+#include "gvc-mixer-event-role.h"
+#include "gvc-mixer-card.h"
+
+#define GVC_MIXER_CONTROL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_CONTROL, GvcMixerControlPrivate))
+
+#define RECONNECT_DELAY 5
+
+enum {
+ PROP_0,
+ PROP_NAME
+};
+
+struct GvcMixerControlPrivate
+{
+ pa_glib_mainloop *pa_mainloop;
+ pa_mainloop_api *pa_api;
+ pa_context *pa_context;
+ int n_outstanding;
+ guint reconnect_id;
+ char *name;
+
+ gboolean default_sink_is_set;
+ guint default_sink_id;
+ char *default_sink_name;
+ gboolean default_source_is_set;
+ guint default_source_id;
+ char *default_source_name;
+
+ gboolean event_sink_input_is_set;
+ guint event_sink_input_id;
+
+ GHashTable *all_streams;
+ GHashTable *sinks; /* fixed outputs */
+ GHashTable *sources; /* fixed inputs */
+ GHashTable *sink_inputs; /* routable output streams */
+ GHashTable *source_outputs; /* routable input streams */
+ GHashTable *clients;
+ GHashTable *cards;
+
+ GvcMixerStream *new_default_stream; /* new default stream, used in gvc_mixer_control_set_default_sink () */
+};
+
+enum {
+ CONNECTING,
+ READY,
+ STREAM_ADDED,
+ STREAM_REMOVED,
+ CARD_ADDED,
+ CARD_REMOVED,
+ DEFAULT_SINK_CHANGED,
+ DEFAULT_SOURCE_CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static void gvc_mixer_control_class_init (GvcMixerControlClass *klass);
+static void gvc_mixer_control_init (GvcMixerControl *mixer_control);
+static void gvc_mixer_control_finalize (GObject *object);
+
+G_DEFINE_TYPE (GvcMixerControl, gvc_mixer_control, G_TYPE_OBJECT)
+
+pa_context *
+gvc_mixer_control_get_pa_context (GvcMixerControl *control)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
+ return control->priv->pa_context;
+}
+
+GvcMixerStream *
+gvc_mixer_control_get_event_sink_input (GvcMixerControl *control)
+{
+ GvcMixerStream *stream;
+
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
+
+ stream = g_hash_table_lookup (control->priv->all_streams,
+ GUINT_TO_POINTER (control->priv->event_sink_input_id));
+
+ return stream;
+}
+
+static void
+gvc_mixer_control_stream_restore_cb (pa_context *c,
+ const pa_ext_stream_restore_info *info,
+ int eol,
+ void *userdata)
+{
+ pa_operation *o;
+ GvcMixerControl *control = (GvcMixerControl *) userdata;
+ pa_ext_stream_restore_info new_info;
+
+ if (eol || control->priv->new_default_stream == NULL)
+ return;
+
+ new_info.name = info->name;
+ new_info.channel_map = info->channel_map;
+ new_info.volume = info->volume;
+ new_info.mute = info->mute;
+
+ new_info.device = gvc_mixer_stream_get_name (control->priv->new_default_stream);
+
+ o = pa_ext_stream_restore_write (control->priv->pa_context,
+ PA_UPDATE_REPLACE,
+ &new_info, 1,
+ TRUE, NULL, NULL);
+
+ if (o == NULL) {
+ g_warning ("pa_ext_stream_restore_write() failed: %s",
+ pa_strerror (pa_context_errno (control->priv->pa_context)));
+ return;
+ }
+
+ g_debug ("Changed default device for %s to %s", info->name, info->device);
+
+ pa_operation_unref (o);
+}
+
+gboolean
+gvc_mixer_control_set_default_sink (GvcMixerControl *control,
+ GvcMixerStream *stream)
+{
+ pa_operation *o;
+
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE);
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ o = pa_context_set_default_sink (control->priv->pa_context,
+ gvc_mixer_stream_get_name (stream),
+ NULL,
+ NULL);
+ if (o == NULL) {
+ g_warning ("pa_context_set_default_sink() failed: %s",
+ pa_strerror (pa_context_errno (control->priv->pa_context)));
+ return FALSE;
+ }
+
+ pa_operation_unref (o);
+
+ control->priv->new_default_stream = stream;
+ g_object_add_weak_pointer (G_OBJECT (stream), (gpointer *) &control->priv->new_default_stream);
+
+ o = pa_ext_stream_restore_read (control->priv->pa_context,
+ gvc_mixer_control_stream_restore_cb,
+ control);
+
+ if (o == NULL) {
+ g_warning ("pa_ext_stream_restore_read() failed: %s",
+ pa_strerror (pa_context_errno (control->priv->pa_context)));
+ return FALSE;
+ }
+
+ pa_operation_unref (o);
+
+ return TRUE;
+}
+
+gboolean
+gvc_mixer_control_set_default_source (GvcMixerControl *control,
+ GvcMixerStream *stream)
+{
+ pa_operation *o;
+
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE);
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ o = pa_context_set_default_source (control->priv->pa_context,
+ gvc_mixer_stream_get_name (stream),
+ NULL,
+ NULL);
+ if (o == NULL) {
+ g_warning ("pa_context_set_default_source() failed");
+ return FALSE;
+ }
+
+ pa_operation_unref (o);
+
+ return TRUE;
+}
+
+GvcMixerStream *
+gvc_mixer_control_get_default_sink (GvcMixerControl *control)
+{
+ GvcMixerStream *stream;
+
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
+
+ if (control->priv->default_sink_is_set) {
+ stream = g_hash_table_lookup (control->priv->all_streams,
+ GUINT_TO_POINTER (control->priv->default_sink_id));
+ } else {
+ stream = NULL;
+ }
+
+ return stream;
+}
+
+GvcMixerStream *
+gvc_mixer_control_get_default_source (GvcMixerControl *control)
+{
+ GvcMixerStream *stream;
+
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
+
+ if (control->priv->default_source_is_set) {
+ stream = g_hash_table_lookup (control->priv->all_streams,
+ GUINT_TO_POINTER (control->priv->default_source_id));
+ } else {
+ stream = NULL;
+ }
+
+ return stream;
+}
+
+static gpointer
+gvc_mixer_control_lookup_id (GHashTable *hash_table,
+ guint id)
+{
+ return g_hash_table_lookup (hash_table,
+ GUINT_TO_POINTER (id));
+}
+
+GvcMixerStream *
+gvc_mixer_control_lookup_stream_id (GvcMixerControl *control,
+ guint id)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
+
+ return gvc_mixer_control_lookup_id (control->priv->all_streams, id);
+}
+
+GvcMixerCard *
+gvc_mixer_control_lookup_card_id (GvcMixerControl *control,
+ guint id)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
+
+ return gvc_mixer_control_lookup_id (control->priv->cards, id);
+}
+
+static void
+listify_hash_values_hfunc (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ GSList **list = user_data;
+
+ *list = g_slist_prepend (*list, value);
+}
+
+static int
+gvc_name_collate (const char *namea,
+ const char *nameb)
+{
+ if (nameb == NULL && namea == NULL)
+ return 0;
+ if (nameb == NULL)
+ return 1;
+ if (namea == NULL)
+ return -1;
+
+ return g_utf8_collate (namea, nameb);
+}
+
+static int
+gvc_card_collate (GvcMixerCard *a,
+ GvcMixerCard *b)
+{
+ const char *namea;
+ const char *nameb;
+
+ g_return_val_if_fail (a == NULL || GVC_IS_MIXER_CARD (a), 0);
+ g_return_val_if_fail (b == NULL || GVC_IS_MIXER_CARD (b), 0);
+
+ namea = gvc_mixer_card_get_name (a);
+ nameb = gvc_mixer_card_get_name (b);
+
+ return gvc_name_collate (namea, nameb);
+}
+
+GSList *
+gvc_mixer_control_get_cards (GvcMixerControl *control)
+{
+ GSList *retval;
+
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
+
+ retval = NULL;
+ g_hash_table_foreach (control->priv->cards,
+ listify_hash_values_hfunc,
+ &retval);
+ return g_slist_sort (retval, (GCompareFunc) gvc_card_collate);
+}
+
+static int
+gvc_stream_collate (GvcMixerStream *a,
+ GvcMixerStream *b)
+{
+ const char *namea;
+ const char *nameb;
+
+ g_return_val_if_fail (a == NULL || GVC_IS_MIXER_STREAM (a), 0);
+ g_return_val_if_fail (b == NULL || GVC_IS_MIXER_STREAM (b), 0);
+
+ namea = gvc_mixer_stream_get_name (a);
+ nameb = gvc_mixer_stream_get_name (b);
+
+ return gvc_name_collate (namea, nameb);
+}
+
+GSList *
+gvc_mixer_control_get_streams (GvcMixerControl *control)
+{
+ GSList *retval;
+
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
+
+ retval = NULL;
+ g_hash_table_foreach (control->priv->all_streams,
+ listify_hash_values_hfunc,
+ &retval);
+ return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate);
+}
+
+GSList *
+gvc_mixer_control_get_sinks (GvcMixerControl *control)
+{
+ GSList *retval;
+
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
+
+ retval = NULL;
+ g_hash_table_foreach (control->priv->sinks,
+ listify_hash_values_hfunc,
+ &retval);
+ return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate);
+}
+
+GSList *
+gvc_mixer_control_get_sources (GvcMixerControl *control)
+{
+ GSList *retval;
+
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
+
+ retval = NULL;
+ g_hash_table_foreach (control->priv->sources,
+ listify_hash_values_hfunc,
+ &retval);
+ return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate);
+}
+
+GSList *
+gvc_mixer_control_get_sink_inputs (GvcMixerControl *control)
+{
+ GSList *retval;
+
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
+
+ retval = NULL;
+ g_hash_table_foreach (control->priv->sink_inputs,
+ listify_hash_values_hfunc,
+ &retval);
+ return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate);
+}
+
+GSList *
+gvc_mixer_control_get_source_outputs (GvcMixerControl *control)
+{
+ GSList *retval;
+
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), NULL);
+
+ retval = NULL;
+ g_hash_table_foreach (control->priv->source_outputs,
+ listify_hash_values_hfunc,
+ &retval);
+ return g_slist_sort (retval, (GCompareFunc) gvc_stream_collate);
+}
+
+static void
+dec_outstanding (GvcMixerControl *control)
+{
+ if (control->priv->n_outstanding <= 0) {
+ return;
+ }
+
+ if (--control->priv->n_outstanding <= 0) {
+ g_signal_emit (G_OBJECT (control), signals[READY], 0);
+ }
+}
+
+gboolean
+gvc_mixer_control_is_ready (GvcMixerControl *control)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE);
+
+ return (control->priv->n_outstanding == 0);
+}
+
+
+static void
+_set_default_source (GvcMixerControl *control,
+ GvcMixerStream *stream)
+{
+ guint new_id;
+
+ if (stream == NULL) {
+ control->priv->default_source_id = 0;
+ control->priv->default_source_is_set = FALSE;
+ return;
+ }
+
+ new_id = gvc_mixer_stream_get_id (stream);
+
+ if (control->priv->default_source_id != new_id) {
+ control->priv->default_source_id = new_id;
+ control->priv->default_source_is_set = TRUE;
+ g_signal_emit (control,
+ signals[DEFAULT_SOURCE_CHANGED],
+ 0,
+ new_id);
+ }
+}
+
+static void
+_set_default_sink (GvcMixerControl *control,
+ GvcMixerStream *stream)
+{
+ guint new_id;
+
+ if (stream == NULL) {
+ control->priv->default_sink_id = 0;
+ control->priv->default_sink_is_set = FALSE;
+ return;
+ }
+
+ new_id = gvc_mixer_stream_get_id (stream);
+
+ if (control->priv->default_sink_id != new_id) {
+ control->priv->default_sink_id = new_id;
+ control->priv->default_sink_is_set = TRUE;
+
+ g_signal_emit (control,
+ signals[DEFAULT_SINK_CHANGED],
+ 0,
+ new_id);
+ }
+}
+
+static gboolean
+_stream_has_name (gpointer key,
+ GvcMixerStream *stream,
+ const char *name)
+{
+ const char *t_name;
+
+ t_name = gvc_mixer_stream_get_name (stream);
+
+ if (t_name != NULL
+ && name != NULL
+ && strcmp (t_name, name) == 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static GvcMixerStream *
+find_stream_for_name (GvcMixerControl *control,
+ const char *name)
+{
+ GvcMixerStream *stream;
+
+ stream = g_hash_table_find (control->priv->all_streams,
+ (GHRFunc)_stream_has_name,
+ (char *)name);
+ return stream;
+}
+
+static void
+update_default_source_from_name (GvcMixerControl *control,
+ const char *name)
+{
+ gboolean changed;
+
+ if ((control->priv->default_source_name == NULL
+ && name != NULL)
+ || (control->priv->default_source_name != NULL
+ && name == NULL)
+ || strcmp (control->priv->default_source_name, name) != 0) {
+ changed = TRUE;
+ }
+
+ if (changed) {
+ GvcMixerStream *stream;
+
+ g_free (control->priv->default_source_name);
+ control->priv->default_source_name = g_strdup (name);
+
+ stream = find_stream_for_name (control, name);
+ _set_default_source (control, stream);
+ }
+}
+
+static void
+update_default_sink_from_name (GvcMixerControl *control,
+ const char *name)
+{
+ gboolean changed;
+
+ if ((control->priv->default_sink_name == NULL
+ && name != NULL)
+ || (control->priv->default_sink_name != NULL
+ && name == NULL)
+ || strcmp (control->priv->default_sink_name, name) != 0) {
+ changed = TRUE;
+ }
+
+ if (changed) {
+ GvcMixerStream *stream;
+ g_free (control->priv->default_sink_name);
+ control->priv->default_sink_name = g_strdup (name);
+
+ stream = find_stream_for_name (control, name);
+ _set_default_sink (control, stream);
+ }
+}
+
+static void
+update_server (GvcMixerControl *control,
+ const pa_server_info *info)
+{
+ if (info->default_source_name != NULL) {
+ update_default_source_from_name (control, info->default_source_name);
+ }
+ if (info->default_sink_name != NULL) {
+ update_default_sink_from_name (control, info->default_sink_name);
+ }
+}
+
+static void
+remove_stream (GvcMixerControl *control,
+ GvcMixerStream *stream)
+{
+ guint id;
+
+ g_object_ref (stream);
+
+ id = gvc_mixer_stream_get_id (stream);
+
+ if (id == control->priv->default_sink_id) {
+ _set_default_sink (control, NULL);
+ } else if (id == control->priv->default_source_id) {
+ _set_default_source (control, NULL);
+ }
+
+ g_hash_table_remove (control->priv->all_streams,
+ GUINT_TO_POINTER (id));
+ g_signal_emit (G_OBJECT (control),
+ signals[STREAM_REMOVED],
+ 0,
+ gvc_mixer_stream_get_id (stream));
+ g_object_unref (stream);
+}
+
+static void
+add_stream (GvcMixerControl *control,
+ GvcMixerStream *stream)
+{
+ g_hash_table_insert (control->priv->all_streams,
+ GUINT_TO_POINTER (gvc_mixer_stream_get_id (stream)),
+ stream);
+ g_signal_emit (G_OBJECT (control),
+ signals[STREAM_ADDED],
+ 0,
+ gvc_mixer_stream_get_id (stream));
+}
+
+static void
+update_sink (GvcMixerControl *control,
+ const pa_sink_info *info)
+{
+ GvcMixerStream *stream;
+ gboolean is_new;
+ pa_volume_t max_volume;
+ GvcChannelMap *map;
+ char map_buff[PA_CHANNEL_MAP_SNPRINT_MAX];
+
+ pa_channel_map_snprint (map_buff, PA_CHANNEL_MAP_SNPRINT_MAX, &info->channel_map);
+#if 1
+ g_debug ("Updating sink: index=%u name='%s' description='%s' map='%s'",
+ info->index,
+ info->name,
+ info->description,
+ map_buff);
+#endif
+
+ map = NULL;
+ is_new = FALSE;
+ stream = g_hash_table_lookup (control->priv->sinks,
+ GUINT_TO_POINTER (info->index));
+ if (stream == NULL) {
+#if PA_MICRO > 15
+ GList *list = NULL;
+ guint i;
+#endif /* PA_MICRO > 15 */
+
+ map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map);
+ stream = gvc_mixer_sink_new (control->priv->pa_context,
+ info->index,
+ map);
+#if PA_MICRO > 15
+ for (i = 0; i < info->n_ports; i++) {
+ GvcMixerStreamPort *port;
+
+ port = g_new0 (GvcMixerStreamPort, 1);
+ port->port = g_strdup (info->ports[i]->name);
+ port->human_port = g_strdup (info->ports[i]->description);
+ port->priority = info->ports[i]->priority;
+ list = g_list_prepend (list, port);
+ }
+ gvc_mixer_stream_set_ports (stream, list);
+#endif /* PA_MICRO > 15 */
+ g_object_unref (map);
+ is_new = TRUE;
+ } else if (gvc_mixer_stream_is_running (stream)) {
+ /* Ignore events if volume changes are outstanding */
+ g_debug ("Ignoring event, volume changes are outstanding");
+ return;
+ }
+
+ max_volume = pa_cvolume_max (&info->volume);
+ gvc_mixer_stream_set_name (stream, info->name);
+ gvc_mixer_stream_set_description (stream, info->description);
+ gvc_mixer_stream_set_icon_name (stream, "audio-card");
+ gvc_mixer_stream_set_volume (stream, (guint)max_volume);
+ gvc_mixer_stream_set_is_muted (stream, info->mute);
+ gvc_mixer_stream_set_can_decibel (stream, !!(info->flags & PA_SINK_DECIBEL_VOLUME));
+#if PA_MICRO > 15
+ if (info->active_port != NULL)
+ gvc_mixer_stream_set_port (stream, info->active_port->name);
+#endif /* PA_MICRO > 15 */
+
+ if (is_new) {
+ g_hash_table_insert (control->priv->sinks,
+ GUINT_TO_POINTER (info->index),
+ g_object_ref (stream));
+ add_stream (control, stream);
+ }
+
+ if (control->priv->default_sink_name != NULL
+ && info->name != NULL
+ && strcmp (control->priv->default_sink_name, info->name) == 0) {
+ _set_default_sink (control, stream);
+ }
+
+ if (map == NULL)
+ map = gvc_mixer_stream_get_channel_map (stream);
+ gvc_channel_map_volume_changed (map, &info->volume, FALSE);
+}
+
+static void
+update_source (GvcMixerControl *control,
+ const pa_source_info *info)
+{
+ GvcMixerStream *stream;
+ gboolean is_new;
+ pa_volume_t max_volume;
+
+#if 1
+ g_debug ("Updating source: index=%u name='%s' description='%s'",
+ info->index,
+ info->name,
+ info->description);
+#endif
+
+ /* completely ignore monitors, they're not real sources */
+ if (info->monitor_of_sink != PA_INVALID_INDEX) {
+ return;
+ }
+
+ is_new = FALSE;
+
+ stream = g_hash_table_lookup (control->priv->sources,
+ GUINT_TO_POINTER (info->index));
+ if (stream == NULL) {
+#if PA_MICRO > 15
+ GList *list = NULL;
+ guint i;
+#endif /* PA_MICRO > 15 */
+ GvcChannelMap *map;
+
+ map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map);
+ stream = gvc_mixer_source_new (control->priv->pa_context,
+ info->index,
+ map);
+#if PA_MICRO > 15
+ for (i = 0; i < info->n_ports; i++) {
+ GvcMixerStreamPort *port;
+
+ port = g_new0 (GvcMixerStreamPort, 1);
+ port->port = g_strdup (info->ports[i]->name);
+ port->human_port = g_strdup (info->ports[i]->description);
+ port->priority = info->ports[i]->priority;
+ list = g_list_prepend (list, port);
+ }
+ gvc_mixer_stream_set_ports (stream, list);
+#endif /* PA_MICRO > 15 */
+
+ g_object_unref (map);
+ is_new = TRUE;
+ } else if (gvc_mixer_stream_is_running (stream)) {
+ /* Ignore events if volume changes are outstanding */
+ g_debug ("Ignoring event, volume changes are outstanding");
+ return;
+ }
+
+ max_volume = pa_cvolume_max (&info->volume);
+
+ gvc_mixer_stream_set_name (stream, info->name);
+ gvc_mixer_stream_set_description (stream, info->description);
+ gvc_mixer_stream_set_icon_name (stream, "audio-input-microphone");
+ gvc_mixer_stream_set_volume (stream, (guint)max_volume);
+ gvc_mixer_stream_set_is_muted (stream, info->mute);
+ gvc_mixer_stream_set_can_decibel (stream, !!(info->flags & PA_SOURCE_DECIBEL_VOLUME));
+ gvc_mixer_stream_set_base_volume (stream, (guint32) info->base_volume);
+#if PA_MICRO > 15
+ if (info->active_port != NULL)
+ gvc_mixer_stream_set_port (stream, info->active_port->name);
+#endif /* PA_MICRO > 15 */
+
+ if (is_new) {
+ g_hash_table_insert (control->priv->sources,
+ GUINT_TO_POINTER (info->index),
+ g_object_ref (stream));
+ add_stream (control, stream);
+ }
+
+ if (control->priv->default_source_name != NULL
+ && info->name != NULL
+ && strcmp (control->priv->default_source_name, info->name) == 0) {
+ _set_default_source (control, stream);
+ }
+}
+
+static void
+set_icon_name_from_proplist (GvcMixerStream *stream,
+ pa_proplist *l,
+ const char *default_icon_name)
+{
+ const char *t;
+
+ if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ICON_NAME))) {
+ goto finish;
+ }
+
+ if ((t = pa_proplist_gets (l, PA_PROP_WINDOW_ICON_NAME))) {
+ goto finish;
+ }
+
+ if ((t = pa_proplist_gets (l, PA_PROP_APPLICATION_ICON_NAME))) {
+ goto finish;
+ }
+
+ if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ROLE))) {
+
+ if (strcmp (t, "video") == 0 ||
+ strcmp (t, "phone") == 0) {
+ goto finish;
+ }
+
+ if (strcmp (t, "music") == 0) {
+ t = "audio";
+ goto finish;
+ }
+
+ if (strcmp (t, "game") == 0) {
+ t = "applications-games";
+ goto finish;
+ }
+
+ if (strcmp (t, "event") == 0) {
+ t = "dialog-information";
+ goto finish;
+ }
+ }
+
+ t = default_icon_name;
+
+ finish:
+ gvc_mixer_stream_set_icon_name (stream, t);
+}
+
+static void
+set_is_event_stream_from_proplist (GvcMixerStream *stream,
+ pa_proplist *l)
+{
+ const char *t;
+ gboolean is_event_stream;
+
+ is_event_stream = FALSE;
+
+ if ((t = pa_proplist_gets (l, PA_PROP_MEDIA_ROLE))) {
+ if (g_str_equal (t, "event"))
+ is_event_stream = TRUE;
+ }
+
+ gvc_mixer_stream_set_is_event_stream (stream, is_event_stream);
+}
+
+static void
+set_application_id_from_proplist (GvcMixerStream *stream,
+ pa_proplist *l)
+{
+ const char *t;
+
+ if ((t = pa_proplist_gets (l, PA_PROP_APPLICATION_ID))) {
+ gvc_mixer_stream_set_application_id (stream, t);
+ }
+}
+
+static void
+update_sink_input (GvcMixerControl *control,
+ const pa_sink_input_info *info)
+{
+ GvcMixerStream *stream;
+ gboolean is_new;
+ pa_volume_t max_volume;
+ const char *name;
+
+#if 0
+ g_debug ("Updating sink input: index=%u name='%s' client=%u sink=%u",
+ info->index,
+ info->name,
+ info->client,
+ info->sink);
+#endif
+
+ is_new = FALSE;
+
+ stream = g_hash_table_lookup (control->priv->sink_inputs,
+ GUINT_TO_POINTER (info->index));
+ if (stream == NULL) {
+ GvcChannelMap *map;
+ map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map);
+ stream = gvc_mixer_sink_input_new (control->priv->pa_context,
+ info->index,
+ map);
+ g_object_unref (map);
+ is_new = TRUE;
+ } else if (gvc_mixer_stream_is_running (stream)) {
+ /* Ignore events if volume changes are outstanding */
+ g_debug ("Ignoring event, volume changes are outstanding");
+ return;
+ }
+
+ max_volume = pa_cvolume_max (&info->volume);
+
+ name = (const char *)g_hash_table_lookup (control->priv->clients,
+ GUINT_TO_POINTER (info->client));
+ gvc_mixer_stream_set_name (stream, name);
+ gvc_mixer_stream_set_description (stream, info->name);
+
+ set_application_id_from_proplist (stream, info->proplist);
+ set_is_event_stream_from_proplist (stream, info->proplist);
+ set_icon_name_from_proplist (stream, info->proplist, "applications-multimedia");
+ gvc_mixer_stream_set_volume (stream, (guint)max_volume);
+ gvc_mixer_stream_set_is_muted (stream, info->mute);
+ gvc_mixer_stream_set_is_virtual (stream, info->client == PA_INVALID_INDEX);
+
+ if (is_new) {
+ g_hash_table_insert (control->priv->sink_inputs,
+ GUINT_TO_POINTER (info->index),
+ g_object_ref (stream));
+ add_stream (control, stream);
+ }
+}
+
+static void
+update_source_output (GvcMixerControl *control,
+ const pa_source_output_info *info)
+{
+ GvcMixerStream *stream;
+ gboolean is_new;
+ const char *name;
+
+#if 1
+ g_debug ("Updating source output: index=%u name='%s' client=%u source=%u",
+ info->index,
+ info->name,
+ info->client,
+ info->source);
+#endif
+
+ is_new = FALSE;
+ stream = g_hash_table_lookup (control->priv->source_outputs,
+ GUINT_TO_POINTER (info->index));
+ if (stream == NULL) {
+ GvcChannelMap *map;
+ map = gvc_channel_map_new_from_pa_channel_map (&info->channel_map);
+ stream = gvc_mixer_source_output_new (control->priv->pa_context,
+ info->index,
+ map);
+ g_object_unref (map);
+ is_new = TRUE;
+ }
+
+ name = (const char *)g_hash_table_lookup (control->priv->clients,
+ GUINT_TO_POINTER (info->client));
+
+ gvc_mixer_stream_set_name (stream, name);
+ gvc_mixer_stream_set_description (stream, info->name);
+ set_application_id_from_proplist (stream, info->proplist);
+ set_is_event_stream_from_proplist (stream, info->proplist);
+ set_icon_name_from_proplist (stream, info->proplist, "audio-input-microphone");
+
+ if (is_new) {
+ g_hash_table_insert (control->priv->source_outputs,
+ GUINT_TO_POINTER (info->index),
+ g_object_ref (stream));
+ add_stream (control, stream);
+ }
+}
+
+static void
+update_client (GvcMixerControl *control,
+ const pa_client_info *info)
+{
+#if 1
+ g_debug ("Updating client: index=%u name='%s'",
+ info->index,
+ info->name);
+#endif
+ g_hash_table_insert (control->priv->clients,
+ GUINT_TO_POINTER (info->index),
+ g_strdup (info->name));
+}
+
+static char *
+card_num_streams_to_status (guint sinks,
+ guint sources)
+{
+ char *sinks_str;
+ char *sources_str;
+ char *ret;
+
+ if (sinks == 0 && sources == 0) {
+ /* translators:
+ * The device has been disabled */
+ return g_strdup (_("Disabled"));
+ }
+ if (sinks == 0) {
+ sinks_str = NULL;
+ } else {
+ /* translators:
+ * The number of sound outputs on a particular device */
+ sinks_str = g_strdup_printf (ngettext ("%u Output",
+ "%u Outputs",
+ sinks),
+ sinks);
+ }
+ if (sources == 0) {
+ sources_str = NULL;
+ } else {
+ /* translators:
+ * The number of sound inputs on a particular device */
+ sources_str = g_strdup_printf (ngettext ("%u Input",
+ "%u Inputs",
+ sources),
+ sources);
+ }
+ if (sources_str == NULL)
+ return sinks_str;
+ if (sinks_str == NULL)
+ return sources_str;
+ ret = g_strdup_printf ("%s / %s", sinks_str, sources_str);
+ g_free (sinks_str);
+ g_free (sources_str);
+ return ret;
+}
+
+static void
+update_card (GvcMixerControl *control,
+ const pa_card_info *info)
+{
+ GvcMixerCard *card;
+ gboolean is_new;
+#if 1
+ guint i;
+ const char *key;
+ void *state;
+
+ g_debug ("Udpating card %s (index: %u driver: %s):",
+ info->name, info->index, info->driver);
+
+ for (i = 0; i < info->n_profiles; i++) {
+ struct pa_card_profile_info pi = info->profiles[i];
+ gboolean is_default;
+
+ is_default = (g_strcmp0 (pi.name, info->active_profile->name) == 0);
+ g_debug ("\tProfile '%s': %d sources %d sinks%s",
+ pi.name, pi.n_sources, pi.n_sinks,
+ is_default ? " (Current)" : "");
+ }
+ state = NULL;
+ key = pa_proplist_iterate (info->proplist, &state);
+ while (key != NULL) {
+ g_debug ("\tProperty: '%s' = '%s'",
+ key, pa_proplist_gets (info->proplist, key));
+ key = pa_proplist_iterate (info->proplist, &state);
+ }
+#endif
+ card = g_hash_table_lookup (control->priv->cards,
+ GUINT_TO_POINTER (info->index));
+ if (card == NULL) {
+ GList *list = NULL;
+
+ for (i = 0; i < info->n_profiles; i++) {
+ struct pa_card_profile_info pi = info->profiles[i];
+ GvcMixerCardProfile *profile;
+
+ profile = g_new0 (GvcMixerCardProfile, 1);
+ profile->profile = g_strdup (pi.name);
+ profile->human_profile = g_strdup (pi.description);
+ profile->status = card_num_streams_to_status (pi.n_sinks, pi.n_sources);
+ profile->priority = pi.priority;
+ list = g_list_prepend (list, profile);
+ }
+ card = gvc_mixer_card_new (control->priv->pa_context,
+ info->index);
+ gvc_mixer_card_set_profiles (card, list);
+ is_new = TRUE;
+ }
+
+ gvc_mixer_card_set_name (card, pa_proplist_gets (info->proplist, "device.description"));
+ gvc_mixer_card_set_icon_name (card, pa_proplist_gets (info->proplist, "device.icon_name"));
+ gvc_mixer_card_set_profile (card, info->active_profile->name);
+
+ if (is_new) {
+ g_hash_table_insert (control->priv->cards,
+ GUINT_TO_POINTER (info->index),
+ g_object_ref (card));
+ }
+ g_signal_emit (G_OBJECT (control),
+ signals[CARD_ADDED],
+ 0,
+ info->index);
+}
+
+static void
+_pa_context_get_sink_info_cb (pa_context *context,
+ const pa_sink_info *i,
+ int eol,
+ void *userdata)
+{
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
+
+ if (eol < 0) {
+ if (pa_context_errno (context) == PA_ERR_NOENTITY) {
+ return;
+ }
+
+ g_warning ("Sink callback failure");
+ return;
+ }
+
+ if (eol > 0) {
+ dec_outstanding (control);
+ return;
+ }
+
+ update_sink (control, i);
+}
+
+static void
+_pa_context_get_source_info_cb (pa_context *context,
+ const pa_source_info *i,
+ int eol,
+ void *userdata)
+{
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
+
+ if (eol < 0) {
+ if (pa_context_errno (context) == PA_ERR_NOENTITY) {
+ return;
+ }
+
+ g_warning ("Source callback failure");
+ return;
+ }
+
+ if (eol > 0) {
+ dec_outstanding (control);
+ return;
+ }
+
+ update_source (control, i);
+}
+
+static void
+_pa_context_get_sink_input_info_cb (pa_context *context,
+ const pa_sink_input_info *i,
+ int eol,
+ void *userdata)
+{
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
+
+ if (eol < 0) {
+ if (pa_context_errno (context) == PA_ERR_NOENTITY) {
+ return;
+ }
+
+ g_warning ("Sink input callback failure");
+ return;
+ }
+
+ if (eol > 0) {
+ dec_outstanding (control);
+ return;
+ }
+
+ update_sink_input (control, i);
+}
+
+static void
+_pa_context_get_source_output_info_cb (pa_context *context,
+ const pa_source_output_info *i,
+ int eol,
+ void *userdata)
+{
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
+
+ if (eol < 0) {
+ if (pa_context_errno (context) == PA_ERR_NOENTITY) {
+ return;
+ }
+
+ g_warning ("Source output callback failure");
+ return;
+ }
+
+ if (eol > 0) {
+ dec_outstanding (control);
+ return;
+ }
+
+ update_source_output (control, i);
+}
+
+static void
+_pa_context_get_client_info_cb (pa_context *context,
+ const pa_client_info *i,
+ int eol,
+ void *userdata)
+{
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
+
+ if (eol < 0) {
+ if (pa_context_errno (context) == PA_ERR_NOENTITY) {
+ return;
+ }
+
+ g_warning ("Client callback failure");
+ return;
+ }
+
+ if (eol > 0) {
+ dec_outstanding (control);
+ return;
+ }
+
+ update_client (control, i);
+}
+
+static void
+_pa_context_get_card_info_by_index_cb (pa_context *context,
+ const pa_card_info *i,
+ int eol,
+ void *userdata)
+{
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
+
+ if (eol < 0) {
+ if (pa_context_errno (context) == PA_ERR_NOENTITY)
+ return;
+
+ g_warning ("Card callback failure");
+ return;
+ }
+
+ if (eol > 0) {
+ dec_outstanding (control);
+ return;
+ }
+
+ update_card (control, i);
+}
+
+static void
+_pa_context_get_server_info_cb (pa_context *context,
+ const pa_server_info *i,
+ void *userdata)
+{
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
+
+ if (i == NULL) {
+ g_warning ("Server info callback failure");
+ return;
+ }
+
+ update_server (control, i);
+ dec_outstanding (control);
+}
+
+static void
+remove_event_role_stream (GvcMixerControl *control)
+{
+ g_debug ("Removing event role");
+}
+
+static void
+update_event_role_stream (GvcMixerControl *control,
+ const pa_ext_stream_restore_info *info)
+{
+ GvcMixerStream *stream;
+ gboolean is_new;
+ pa_volume_t max_volume;
+
+ if (strcmp (info->name, "sink-input-by-media-role:event") != 0) {
+ return;
+ }
+
+#if 0
+ g_debug ("Updating event role: name='%s' device='%s'",
+ info->name,
+ info->device);
+#endif
+
+ is_new = FALSE;
+
+ if (!control->priv->event_sink_input_is_set) {
+ pa_channel_map pa_map;
+ GvcChannelMap *map;
+
+ pa_map.channels = 1;
+ pa_map.map[0] = PA_CHANNEL_POSITION_MONO;
+ map = gvc_channel_map_new_from_pa_channel_map (&pa_map);
+
+ stream = gvc_mixer_event_role_new (control->priv->pa_context,
+ info->device,
+ map);
+ control->priv->event_sink_input_id = gvc_mixer_stream_get_id (stream);
+ control->priv->event_sink_input_is_set = TRUE;
+
+ is_new = TRUE;
+ } else {
+ stream = g_hash_table_lookup (control->priv->all_streams,
+ GUINT_TO_POINTER (control->priv->event_sink_input_id));
+ }
+
+ max_volume = pa_cvolume_max (&info->volume);
+
+ gvc_mixer_stream_set_name (stream, _("System Sounds"));
+ gvc_mixer_stream_set_icon_name (stream, "multimedia-volume-control");
+ gvc_mixer_stream_set_volume (stream, (guint)max_volume);
+ gvc_mixer_stream_set_is_muted (stream, info->mute);
+
+ if (is_new) {
+ add_stream (control, stream);
+ }
+}
+
+static void
+_pa_ext_stream_restore_read_cb (pa_context *context,
+ const pa_ext_stream_restore_info *i,
+ int eol,
+ void *userdata)
+{
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
+
+ if (eol < 0) {
+ g_debug ("Failed to initialized stream_restore extension: %s",
+ pa_strerror (pa_context_errno (context)));
+ remove_event_role_stream (control);
+ return;
+ }
+
+ if (eol > 0) {
+ dec_outstanding (control);
+ return;
+ }
+
+ update_event_role_stream (control, i);
+}
+
+static void
+_pa_ext_stream_restore_subscribe_cb (pa_context *context,
+ void *userdata)
+{
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
+ pa_operation *o;
+
+ o = pa_ext_stream_restore_read (context,
+ _pa_ext_stream_restore_read_cb,
+ control);
+ if (o == NULL) {
+ g_warning ("pa_ext_stream_restore_read() failed");
+ return;
+ }
+
+ pa_operation_unref (o);
+}
+
+static void
+req_update_server_info (GvcMixerControl *control,
+ int index)
+{
+ pa_operation *o;
+
+ o = pa_context_get_server_info (control->priv->pa_context,
+ _pa_context_get_server_info_cb,
+ control);
+ if (o == NULL) {
+ g_warning ("pa_context_get_server_info() failed");
+ return;
+ }
+ pa_operation_unref (o);
+}
+
+static void
+req_update_client_info (GvcMixerControl *control,
+ int index)
+{
+ pa_operation *o;
+
+ if (index < 0) {
+ o = pa_context_get_client_info_list (control->priv->pa_context,
+ _pa_context_get_client_info_cb,
+ control);
+ } else {
+ o = pa_context_get_client_info (control->priv->pa_context,
+ index,
+ _pa_context_get_client_info_cb,
+ control);
+ }
+
+ if (o == NULL) {
+ g_warning ("pa_context_client_info_list() failed");
+ return;
+ }
+ pa_operation_unref (o);
+}
+
+static void
+req_update_card (GvcMixerControl *control,
+ int index)
+{
+ pa_operation *o;
+
+ if (index < 0) {
+ o = pa_context_get_card_info_list (control->priv->pa_context,
+ _pa_context_get_card_info_by_index_cb,
+ control);
+ } else {
+ o = pa_context_get_card_info_by_index (control->priv->pa_context,
+ index,
+ _pa_context_get_card_info_by_index_cb,
+ control);
+ }
+
+ if (o == NULL) {
+ g_warning ("pa_context_get_card_info_by_index() failed");
+ return;
+ }
+ pa_operation_unref (o);
+}
+
+static void
+req_update_sink_info (GvcMixerControl *control,
+ int index)
+{
+ pa_operation *o;
+
+ if (index < 0) {
+ o = pa_context_get_sink_info_list (control->priv->pa_context,
+ _pa_context_get_sink_info_cb,
+ control);
+ } else {
+ o = pa_context_get_sink_info_by_index (control->priv->pa_context,
+ index,
+ _pa_context_get_sink_info_cb,
+ control);
+ }
+
+ if (o == NULL) {
+ g_warning ("pa_context_get_sink_info_list() failed");
+ return;
+ }
+ pa_operation_unref (o);
+}
+
+static void
+req_update_source_info (GvcMixerControl *control,
+ int index)
+{
+ pa_operation *o;
+
+ if (index < 0) {
+ o = pa_context_get_source_info_list (control->priv->pa_context,
+ _pa_context_get_source_info_cb,
+ control);
+ } else {
+ o = pa_context_get_source_info_by_index(control->priv->pa_context,
+ index,
+ _pa_context_get_source_info_cb,
+ control);
+ }
+
+ if (o == NULL) {
+ g_warning ("pa_context_get_source_info_list() failed");
+ return;
+ }
+ pa_operation_unref (o);
+}
+
+static void
+req_update_sink_input_info (GvcMixerControl *control,
+ int index)
+{
+ pa_operation *o;
+
+ if (index < 0) {
+ o = pa_context_get_sink_input_info_list (control->priv->pa_context,
+ _pa_context_get_sink_input_info_cb,
+ control);
+ } else {
+ o = pa_context_get_sink_input_info (control->priv->pa_context,
+ index,
+ _pa_context_get_sink_input_info_cb,
+ control);
+ }
+
+ if (o == NULL) {
+ g_warning ("pa_context_get_sink_input_info_list() failed");
+ return;
+ }
+ pa_operation_unref (o);
+}
+
+static void
+req_update_source_output_info (GvcMixerControl *control,
+ int index)
+{
+ pa_operation *o;
+
+ if (index < 0) {
+ o = pa_context_get_source_output_info_list (control->priv->pa_context,
+ _pa_context_get_source_output_info_cb,
+ control);
+ } else {
+ o = pa_context_get_source_output_info (control->priv->pa_context,
+ index,
+ _pa_context_get_source_output_info_cb,
+ control);
+ }
+
+ if (o == NULL) {
+ g_warning ("pa_context_get_source_output_info_list() failed");
+ return;
+ }
+ pa_operation_unref (o);
+}
+
+static void
+remove_client (GvcMixerControl *control,
+ guint index)
+{
+ g_hash_table_remove (control->priv->clients,
+ GUINT_TO_POINTER (index));
+}
+
+static void
+remove_card (GvcMixerControl *control,
+ guint index)
+{
+ g_hash_table_remove (control->priv->cards,
+ GUINT_TO_POINTER (index));
+
+ g_signal_emit (G_OBJECT (control),
+ signals[CARD_REMOVED],
+ 0,
+ index);
+}
+
+static void
+remove_sink (GvcMixerControl *control,
+ guint index)
+{
+ GvcMixerStream *stream;
+
+#if 0
+ g_debug ("Removing sink: index=%u", index);
+#endif
+
+ stream = g_hash_table_lookup (control->priv->sinks,
+ GUINT_TO_POINTER (index));
+ if (stream == NULL) {
+ return;
+ }
+ g_hash_table_remove (control->priv->sinks,
+ GUINT_TO_POINTER (index));
+
+ remove_stream (control, stream);
+}
+
+static void
+remove_source (GvcMixerControl *control,
+ guint index)
+{
+ GvcMixerStream *stream;
+
+#if 0
+ g_debug ("Removing source: index=%u", index);
+#endif
+
+ stream = g_hash_table_lookup (control->priv->sources,
+ GUINT_TO_POINTER (index));
+ if (stream == NULL) {
+ return;
+ }
+ g_hash_table_remove (control->priv->sources,
+ GUINT_TO_POINTER (index));
+
+ remove_stream (control, stream);
+}
+
+static void
+remove_sink_input (GvcMixerControl *control,
+ guint index)
+{
+ GvcMixerStream *stream;
+
+#if 0
+ g_debug ("Removing sink input: index=%u", index);
+#endif
+ stream = g_hash_table_lookup (control->priv->sink_inputs,
+ GUINT_TO_POINTER (index));
+ if (stream == NULL) {
+ return;
+ }
+ g_hash_table_remove (control->priv->sink_inputs,
+ GUINT_TO_POINTER (index));
+
+ remove_stream (control, stream);
+}
+
+static void
+remove_source_output (GvcMixerControl *control,
+ guint index)
+{
+ GvcMixerStream *stream;
+
+#if 0
+ g_debug ("Removing source output: index=%u", index);
+#endif
+
+ stream = g_hash_table_lookup (control->priv->source_outputs,
+ GUINT_TO_POINTER (index));
+ if (stream == NULL) {
+ return;
+ }
+ g_hash_table_remove (control->priv->source_outputs,
+ GUINT_TO_POINTER (index));
+
+ remove_stream (control, stream);
+}
+
+static void
+_pa_context_subscribe_cb (pa_context *context,
+ pa_subscription_event_type_t t,
+ uint32_t index,
+ void *userdata)
+{
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
+
+ switch (t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) {
+ case PA_SUBSCRIPTION_EVENT_SINK:
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
+ remove_sink (control, index);
+ } else {
+ req_update_sink_info (control, index);
+ }
+ break;
+
+ case PA_SUBSCRIPTION_EVENT_SOURCE:
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
+ remove_source (control, index);
+ } else {
+ req_update_source_info (control, index);
+ }
+ break;
+
+ case PA_SUBSCRIPTION_EVENT_SINK_INPUT:
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
+ remove_sink_input (control, index);
+ } else {
+ req_update_sink_input_info (control, index);
+ }
+ break;
+
+ case PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT:
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
+ remove_source_output (control, index);
+ } else {
+ req_update_source_output_info (control, index);
+ }
+ break;
+
+ case PA_SUBSCRIPTION_EVENT_CLIENT:
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
+ remove_client (control, index);
+ } else {
+ req_update_client_info (control, index);
+ }
+ break;
+
+ case PA_SUBSCRIPTION_EVENT_SERVER:
+ req_update_server_info (control, index);
+ break;
+
+ case PA_SUBSCRIPTION_EVENT_CARD:
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_REMOVE) {
+ remove_card (control, index);
+ } else {
+ req_update_card (control, index);
+ }
+ break;
+ }
+}
+
+static void
+gvc_mixer_control_ready (GvcMixerControl *control)
+{
+ pa_operation *o;
+
+ pa_context_set_subscribe_callback (control->priv->pa_context,
+ _pa_context_subscribe_cb,
+ control);
+ o = pa_context_subscribe (control->priv->pa_context,
+ (pa_subscription_mask_t)
+ (PA_SUBSCRIPTION_MASK_SINK|
+ PA_SUBSCRIPTION_MASK_SOURCE|
+ PA_SUBSCRIPTION_MASK_SINK_INPUT|
+ PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT|
+ PA_SUBSCRIPTION_MASK_CLIENT|
+ PA_SUBSCRIPTION_MASK_SERVER|
+ PA_SUBSCRIPTION_MASK_CARD),
+ NULL,
+ NULL);
+
+ if (o == NULL) {
+ g_warning ("pa_context_subscribe() failed");
+ return;
+ }
+ pa_operation_unref (o);
+
+ req_update_server_info (control, -1);
+ req_update_client_info (control, -1);
+ req_update_sink_info (control, -1);
+ req_update_source_info (control, -1);
+ req_update_sink_input_info (control, -1);
+ req_update_source_output_info (control, -1);
+ req_update_card (control, -1);
+
+ control->priv->n_outstanding = 6;
+
+ /* This call is not always supported */
+ o = pa_ext_stream_restore_read (control->priv->pa_context,
+ _pa_ext_stream_restore_read_cb,
+ control);
+ if (o != NULL) {
+ pa_operation_unref (o);
+ control->priv->n_outstanding++;
+
+ pa_ext_stream_restore_set_subscribe_cb (control->priv->pa_context,
+ _pa_ext_stream_restore_subscribe_cb,
+ control);
+
+ o = pa_ext_stream_restore_subscribe (control->priv->pa_context,
+ 1,
+ NULL,
+ NULL);
+ if (o != NULL) {
+ pa_operation_unref (o);
+ }
+
+ } else {
+ g_debug ("Failed to initialized stream_restore extension: %s",
+ pa_strerror (pa_context_errno (control->priv->pa_context)));
+ }
+}
+
+static void
+gvc_mixer_new_pa_context (GvcMixerControl *self)
+{
+ pa_proplist *proplist;
+
+ g_return_if_fail (self);
+ g_return_if_fail (!self->priv->pa_context);
+
+ proplist = pa_proplist_new ();
+ pa_proplist_sets (proplist,
+ PA_PROP_APPLICATION_NAME,
+ self->priv->name);
+ pa_proplist_sets (proplist,
+ PA_PROP_APPLICATION_ID,
+ "org.mate.VolumeControl");
+ pa_proplist_sets (proplist,
+ PA_PROP_APPLICATION_ICON_NAME,
+ "multimedia-volume-control");
+ pa_proplist_sets (proplist,
+ PA_PROP_APPLICATION_VERSION,
+ PACKAGE_VERSION);
+
+ self->priv->pa_context = pa_context_new_with_proplist (self->priv->pa_api, NULL, proplist);
+
+ pa_proplist_free (proplist);
+ g_assert (self->priv->pa_context);
+}
+
+static void
+remove_all_streams (GvcMixerControl *control, GHashTable *hash_table)
+{
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init (&iter, hash_table);
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
+ remove_stream (control, value);
+ g_hash_table_iter_remove (&iter);
+ }
+}
+
+static gboolean
+idle_reconnect (gpointer data)
+{
+ GvcMixerControl *control = GVC_MIXER_CONTROL (data);
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_return_val_if_fail (control, FALSE);
+
+ if (control->priv->pa_context) {
+ pa_context_unref (control->priv->pa_context);
+ control->priv->pa_context = NULL;
+ gvc_mixer_new_pa_context (control);
+ }
+
+ remove_all_streams (control, control->priv->sinks);
+ remove_all_streams (control, control->priv->sources);
+ remove_all_streams (control, control->priv->sink_inputs);
+ remove_all_streams (control, control->priv->source_outputs);
+
+ g_hash_table_iter_init (&iter, control->priv->clients);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ g_hash_table_iter_remove (&iter);
+
+ gvc_mixer_control_open (control); /* cannot fail */
+
+ control->priv->reconnect_id = 0;
+ return FALSE;
+}
+
+static void
+_pa_context_state_cb (pa_context *context,
+ void *userdata)
+{
+ GvcMixerControl *control = GVC_MIXER_CONTROL (userdata);
+
+ switch (pa_context_get_state (context)) {
+ case PA_CONTEXT_UNCONNECTED:
+ case PA_CONTEXT_CONNECTING:
+ case PA_CONTEXT_AUTHORIZING:
+ case PA_CONTEXT_SETTING_NAME:
+ break;
+
+ case PA_CONTEXT_READY:
+ gvc_mixer_control_ready (control);
+ break;
+
+ case PA_CONTEXT_FAILED:
+ g_warning ("Connection failed, reconnecting...");
+ if (control->priv->reconnect_id == 0)
+ control->priv->reconnect_id = g_timeout_add_seconds (RECONNECT_DELAY, idle_reconnect, control);
+ break;
+
+ case PA_CONTEXT_TERMINATED:
+ default:
+ /* FIXME: */
+ break;
+ }
+}
+
+gboolean
+gvc_mixer_control_open (GvcMixerControl *control)
+{
+ int res;
+
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE);
+ g_return_val_if_fail (control->priv->pa_context != NULL, FALSE);
+ g_return_val_if_fail (pa_context_get_state (control->priv->pa_context) == PA_CONTEXT_UNCONNECTED, FALSE);
+
+ pa_context_set_state_callback (control->priv->pa_context,
+ _pa_context_state_cb,
+ control);
+
+ g_signal_emit (G_OBJECT (control), signals[CONNECTING], 0);
+ res = pa_context_connect (control->priv->pa_context, NULL, (pa_context_flags_t) PA_CONTEXT_NOFAIL, NULL);
+ if (res < 0) {
+ g_warning ("Failed to connect context: %s",
+ pa_strerror (pa_context_errno (control->priv->pa_context)));
+ }
+
+ return res;
+}
+
+gboolean
+gvc_mixer_control_close (GvcMixerControl *control)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_CONTROL (control), FALSE);
+ g_return_val_if_fail (control->priv->pa_context != NULL, FALSE);
+
+ pa_context_disconnect (control->priv->pa_context);
+ return TRUE;
+}
+
+static void
+gvc_mixer_control_dispose (GObject *object)
+{
+ GvcMixerControl *control = GVC_MIXER_CONTROL (object);
+
+ if (control->priv->pa_context != NULL) {
+ pa_context_unref (control->priv->pa_context);
+ control->priv->pa_context = NULL;
+ }
+
+ if (control->priv->default_source_name != NULL) {
+ g_free (control->priv->default_source_name);
+ control->priv->default_source_name = NULL;
+ }
+ if (control->priv->default_sink_name != NULL) {
+ g_free (control->priv->default_sink_name);
+ control->priv->default_sink_name = NULL;
+ }
+
+ if (control->priv->pa_mainloop != NULL) {
+ pa_glib_mainloop_free (control->priv->pa_mainloop);
+ control->priv->pa_mainloop = NULL;
+ }
+
+ if (control->priv->all_streams != NULL) {
+ g_hash_table_destroy (control->priv->all_streams);
+ control->priv->all_streams = NULL;
+ }
+
+ if (control->priv->sinks != NULL) {
+ g_hash_table_destroy (control->priv->sinks);
+ control->priv->sinks = NULL;
+ }
+ if (control->priv->sources != NULL) {
+ g_hash_table_destroy (control->priv->sources);
+ control->priv->sources = NULL;
+ }
+ if (control->priv->sink_inputs != NULL) {
+ g_hash_table_destroy (control->priv->sink_inputs);
+ control->priv->sink_inputs = NULL;
+ }
+ if (control->priv->source_outputs != NULL) {
+ g_hash_table_destroy (control->priv->source_outputs);
+ control->priv->source_outputs = NULL;
+ }
+ if (control->priv->clients != NULL) {
+ g_hash_table_destroy (control->priv->clients);
+ control->priv->clients = NULL;
+ }
+ if (control->priv->cards != NULL) {
+ g_hash_table_destroy (control->priv->cards);
+ control->priv->cards = NULL;
+ }
+
+ G_OBJECT_CLASS (gvc_mixer_control_parent_class)->dispose (object);
+}
+
+static void
+gvc_mixer_control_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GvcMixerControl *self = GVC_MIXER_CONTROL (object);
+
+ switch (prop_id) {
+ case PROP_NAME:
+ g_free (self->priv->name);
+ self->priv->name = g_value_dup_string (value);
+ g_object_notify (G_OBJECT (self), "name");
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gvc_mixer_control_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GvcMixerControl *self = GVC_MIXER_CONTROL (object);
+
+ switch (prop_id) {
+ case PROP_NAME:
+ g_value_set_string (value, self->priv->name);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+static GObject *
+gvc_mixer_control_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+ GvcMixerControl *self;
+
+ object = G_OBJECT_CLASS (gvc_mixer_control_parent_class)->constructor (type, n_construct_properties, construct_params);
+
+ self = GVC_MIXER_CONTROL (object);
+
+ gvc_mixer_new_pa_context (self);
+
+ return object;
+}
+
+static void
+gvc_mixer_control_class_init (GvcMixerControlClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->constructor = gvc_mixer_control_constructor;
+ object_class->dispose = gvc_mixer_control_dispose;
+ object_class->finalize = gvc_mixer_control_finalize;
+ object_class->set_property = gvc_mixer_control_set_property;
+ object_class->get_property = gvc_mixer_control_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_NAME,
+ g_param_spec_string ("name",
+ "Name",
+ "Name to display for this mixer control",
+ NULL,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+
+ signals [CONNECTING] =
+ g_signal_new ("connecting",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GvcMixerControlClass, connecting),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ signals [READY] =
+ g_signal_new ("ready",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GvcMixerControlClass, ready),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ signals [STREAM_ADDED] =
+ g_signal_new ("stream-added",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GvcMixerControlClass, stream_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE, 1, G_TYPE_UINT);
+ signals [STREAM_REMOVED] =
+ g_signal_new ("stream-removed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GvcMixerControlClass, stream_removed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE, 1, G_TYPE_UINT);
+ signals [CARD_ADDED] =
+ g_signal_new ("card-added",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GvcMixerControlClass, card_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE, 1, G_TYPE_UINT);
+ signals [CARD_REMOVED] =
+ g_signal_new ("card-removed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GvcMixerControlClass, card_removed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE, 1, G_TYPE_UINT);
+ signals [DEFAULT_SINK_CHANGED] =
+ g_signal_new ("default-sink-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GvcMixerControlClass, default_sink_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE, 1, G_TYPE_UINT);
+ signals [DEFAULT_SOURCE_CHANGED] =
+ g_signal_new ("default-source-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GvcMixerControlClass, default_source_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__UINT,
+ G_TYPE_NONE, 1, G_TYPE_UINT);
+
+ g_type_class_add_private (klass, sizeof (GvcMixerControlPrivate));
+}
+
+static void
+gvc_mixer_control_init (GvcMixerControl *control)
+{
+ control->priv = GVC_MIXER_CONTROL_GET_PRIVATE (control);
+
+ control->priv->pa_mainloop = pa_glib_mainloop_new (g_main_context_default ());
+ g_assert (control->priv->pa_mainloop);
+
+ control->priv->pa_api = pa_glib_mainloop_get_api (control->priv->pa_mainloop);
+ g_assert (control->priv->pa_api);
+
+ control->priv->all_streams = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref);
+ control->priv->sinks = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref);
+ control->priv->sources = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref);
+ control->priv->sink_inputs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref);
+ control->priv->source_outputs = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref);
+ control->priv->cards = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_object_unref);
+
+ control->priv->clients = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify)g_free);
+}
+
+static void
+gvc_mixer_control_finalize (GObject *object)
+{
+ GvcMixerControl *mixer_control;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GVC_IS_MIXER_CONTROL (object));
+
+ mixer_control = GVC_MIXER_CONTROL (object);
+ g_free (mixer_control->priv->name);
+ mixer_control->priv->name = NULL;
+
+ g_return_if_fail (mixer_control->priv != NULL);
+ G_OBJECT_CLASS (gvc_mixer_control_parent_class)->finalize (object);
+}
+
+GvcMixerControl *
+gvc_mixer_control_new (const char *name)
+{
+ GObject *control;
+ control = g_object_new (GVC_TYPE_MIXER_CONTROL,
+ "name", name,
+ NULL);
+ return GVC_MIXER_CONTROL (control);
+}
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-control.h b/plugins/media-keys/cut-n-paste/gvc-mixer-control.h
new file mode 100644
index 0000000..95dc756
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-control.h
@@ -0,0 +1,102 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __GVC_MIXER_CONTROL_H
+#define __GVC_MIXER_CONTROL_H
+
+#include <glib-object.h>
+#include <pulse/pulseaudio.h>
+#include "gvc-mixer-stream.h"
+#include "gvc-mixer-card.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GVC_TYPE_MIXER_CONTROL (gvc_mixer_control_get_type ())
+#define GVC_MIXER_CONTROL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_CONTROL, GvcMixerControl))
+#define GVC_MIXER_CONTROL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_CONTROL, GvcMixerControlClass))
+#define GVC_IS_MIXER_CONTROL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_CONTROL))
+#define GVC_IS_MIXER_CONTROL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_CONTROL))
+#define GVC_MIXER_CONTROL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_CONTROL, GvcMixerControlClass))
+
+typedef struct GvcMixerControlPrivate GvcMixerControlPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GvcMixerControlPrivate *priv;
+} GvcMixerControl;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+ void (*connecting) (GvcMixerControl *control);
+ void (*ready) (GvcMixerControl *control);
+ void (*stream_added) (GvcMixerControl *control,
+ guint id);
+ void (*stream_removed) (GvcMixerControl *control,
+ guint id);
+ void (*card_added) (GvcMixerControl *control,
+ guint id);
+ void (*card_removed) (GvcMixerControl *control,
+ guint id);
+ void (*default_sink_changed) (GvcMixerControl *control,
+ guint id);
+ void (*default_source_changed) (GvcMixerControl *control,
+ guint id);
+} GvcMixerControlClass;
+
+GType gvc_mixer_control_get_type (void);
+
+GvcMixerControl * gvc_mixer_control_new (const char *name);
+
+gboolean gvc_mixer_control_open (GvcMixerControl *control);
+gboolean gvc_mixer_control_close (GvcMixerControl *control);
+gboolean gvc_mixer_control_is_ready (GvcMixerControl *control);
+
+pa_context * gvc_mixer_control_get_pa_context (GvcMixerControl *control);
+GSList * gvc_mixer_control_get_cards (GvcMixerControl *control);
+GSList * gvc_mixer_control_get_streams (GvcMixerControl *control);
+GSList * gvc_mixer_control_get_sinks (GvcMixerControl *control);
+GSList * gvc_mixer_control_get_sources (GvcMixerControl *control);
+GSList * gvc_mixer_control_get_sink_inputs (GvcMixerControl *control);
+GSList * gvc_mixer_control_get_source_outputs (GvcMixerControl *control);
+
+GvcMixerStream * gvc_mixer_control_lookup_stream_id (GvcMixerControl *control,
+ guint id);
+GvcMixerCard * gvc_mixer_control_lookup_card_id (GvcMixerControl *control,
+ guint id);
+
+GvcMixerStream * gvc_mixer_control_get_default_sink (GvcMixerControl *control);
+GvcMixerStream * gvc_mixer_control_get_default_source (GvcMixerControl *control);
+GvcMixerStream * gvc_mixer_control_get_event_sink_input (GvcMixerControl *control);
+
+gboolean gvc_mixer_control_set_default_sink (GvcMixerControl *control,
+ GvcMixerStream *stream);
+gboolean gvc_mixer_control_set_default_source (GvcMixerControl *control,
+ GvcMixerStream *stream);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GVC_MIXER_CONTROL_H */
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-event-role.c b/plugins/media-keys/cut-n-paste/gvc-mixer-event-role.c
new file mode 100644
index 0000000..69e38ce
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-event-role.c
@@ -0,0 +1,239 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 William Jon McCann
+ *
+ * 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 "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <pulse/pulseaudio.h>
+#include <pulse/ext-stream-restore.h>
+
+#include "gvc-mixer-event-role.h"
+
+#define GVC_MIXER_EVENT_ROLE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRolePrivate))
+
+struct GvcMixerEventRolePrivate
+{
+ char *device;
+};
+
+enum
+{
+ PROP_0,
+ PROP_DEVICE
+};
+
+static void gvc_mixer_event_role_class_init (GvcMixerEventRoleClass *klass);
+static void gvc_mixer_event_role_init (GvcMixerEventRole *mixer_event_role);
+static void gvc_mixer_event_role_finalize (GObject *object);
+
+G_DEFINE_TYPE (GvcMixerEventRole, gvc_mixer_event_role, GVC_TYPE_MIXER_STREAM)
+
+static gboolean
+update_settings (GvcMixerEventRole *role,
+ gboolean is_muted,
+ gpointer *op)
+{
+ pa_operation *o;
+ guint index;
+ GvcChannelMap *map;
+ pa_context *context;
+ pa_ext_stream_restore_info info;
+
+ index = gvc_mixer_stream_get_index (GVC_MIXER_STREAM (role));
+
+ map = gvc_mixer_stream_get_channel_map (GVC_MIXER_STREAM(role));
+
+ info.volume = *gvc_channel_map_get_cvolume(map);
+ info.name = "sink-input-by-media-role:event";
+ info.channel_map = *gvc_channel_map_get_pa_channel_map(map);
+ info.device = role->priv->device;
+ info.mute = is_muted;
+
+ context = gvc_mixer_stream_get_pa_context (GVC_MIXER_STREAM (role));
+
+ o = pa_ext_stream_restore_write (context,
+ PA_UPDATE_REPLACE,
+ &info,
+ 1,
+ TRUE,
+ NULL,
+ NULL);
+
+ if (o == NULL) {
+ g_warning ("pa_ext_stream_restore_write() failed");
+ return FALSE;
+ }
+
+ if (op != NULL)
+ *op = o;
+
+ return TRUE;
+}
+
+static gboolean
+gvc_mixer_event_role_push_volume (GvcMixerStream *stream, gpointer *op)
+{
+ return update_settings (GVC_MIXER_EVENT_ROLE (stream),
+ gvc_mixer_stream_get_is_muted (stream), op);
+}
+
+static gboolean
+gvc_mixer_event_role_change_is_muted (GvcMixerStream *stream,
+ gboolean is_muted)
+{
+ return update_settings (GVC_MIXER_EVENT_ROLE (stream),
+ is_muted, NULL);
+}
+
+static gboolean
+gvc_mixer_event_role_set_device (GvcMixerEventRole *role,
+ const char *device)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_EVENT_ROLE (role), FALSE);
+
+ g_free (role->priv->device);
+ role->priv->device = g_strdup (device);
+ g_object_notify (G_OBJECT (role), "device");
+
+ return TRUE;
+}
+
+static void
+gvc_mixer_event_role_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GvcMixerEventRole *self = GVC_MIXER_EVENT_ROLE (object);
+
+ switch (prop_id) {
+ case PROP_DEVICE:
+ gvc_mixer_event_role_set_device (self, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gvc_mixer_event_role_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GvcMixerEventRole *self = GVC_MIXER_EVENT_ROLE (object);
+
+ switch (prop_id) {
+ case PROP_DEVICE:
+ g_value_set_string (value, self->priv->device);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GObject *
+gvc_mixer_event_role_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+ GvcMixerEventRole *self;
+
+ object = G_OBJECT_CLASS (gvc_mixer_event_role_parent_class)->constructor (type, n_construct_properties, construct_params);
+
+ self = GVC_MIXER_EVENT_ROLE (object);
+
+ return object;
+}
+
+static void
+gvc_mixer_event_role_class_init (GvcMixerEventRoleClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
+
+ object_class->constructor = gvc_mixer_event_role_constructor;
+ object_class->finalize = gvc_mixer_event_role_finalize;
+ object_class->set_property = gvc_mixer_event_role_set_property;
+ object_class->get_property = gvc_mixer_event_role_get_property;
+
+ stream_class->push_volume = gvc_mixer_event_role_push_volume;
+ stream_class->change_is_muted = gvc_mixer_event_role_change_is_muted;
+
+ g_object_class_install_property (object_class,
+ PROP_DEVICE,
+ g_param_spec_string ("device",
+ "Device",
+ "Device",
+ NULL,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+ g_type_class_add_private (klass, sizeof (GvcMixerEventRolePrivate));
+}
+
+static void
+gvc_mixer_event_role_init (GvcMixerEventRole *event_role)
+{
+ event_role->priv = GVC_MIXER_EVENT_ROLE_GET_PRIVATE (event_role);
+
+}
+
+static void
+gvc_mixer_event_role_finalize (GObject *object)
+{
+ GvcMixerEventRole *mixer_event_role;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GVC_IS_MIXER_EVENT_ROLE (object));
+
+ mixer_event_role = GVC_MIXER_EVENT_ROLE (object);
+
+ g_return_if_fail (mixer_event_role->priv != NULL);
+
+ g_free (mixer_event_role->priv->device);
+
+ G_OBJECT_CLASS (gvc_mixer_event_role_parent_class)->finalize (object);
+}
+
+GvcMixerStream *
+gvc_mixer_event_role_new (pa_context *context,
+ const char *device,
+ GvcChannelMap *channel_map)
+{
+ GObject *object;
+
+ object = g_object_new (GVC_TYPE_MIXER_EVENT_ROLE,
+ "pa-context", context,
+ "index", 0,
+ "device", device,
+ "channel-map", channel_map,
+ NULL);
+
+ return GVC_MIXER_STREAM (object);
+}
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-event-role.h b/plugins/media-keys/cut-n-paste/gvc-mixer-event-role.h
new file mode 100644
index 0000000..ee91fa8
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-event-role.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __GVC_MIXER_EVENT_ROLE_H
+#define __GVC_MIXER_EVENT_ROLE_H
+
+#include <glib-object.h>
+#include "gvc-mixer-stream.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GVC_TYPE_MIXER_EVENT_ROLE (gvc_mixer_event_role_get_type ())
+#define GVC_MIXER_EVENT_ROLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRole))
+#define GVC_MIXER_EVENT_ROLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRoleClass))
+#define GVC_IS_MIXER_EVENT_ROLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_EVENT_ROLE))
+#define GVC_IS_MIXER_EVENT_ROLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_EVENT_ROLE))
+#define GVC_MIXER_EVENT_ROLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_EVENT_ROLE, GvcMixerEventRoleClass))
+
+typedef struct GvcMixerEventRolePrivate GvcMixerEventRolePrivate;
+
+typedef struct
+{
+ GvcMixerStream parent;
+ GvcMixerEventRolePrivate *priv;
+} GvcMixerEventRole;
+
+typedef struct
+{
+ GvcMixerStreamClass parent_class;
+} GvcMixerEventRoleClass;
+
+GType gvc_mixer_event_role_get_type (void);
+
+GvcMixerStream * gvc_mixer_event_role_new (pa_context *context,
+ const char *device,
+ GvcChannelMap *channel_map);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GVC_MIXER_EVENT_ROLE_H */
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-sink-input.c b/plugins/media-keys/cut-n-paste/gvc-mixer-sink-input.c
new file mode 100644
index 0000000..35551bb
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-sink-input.c
@@ -0,0 +1,188 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 William Jon McCann
+ *
+ * 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 "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "gvc-mixer-sink-input.h"
+
+#define GVC_MIXER_SINK_INPUT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInputPrivate))
+
+struct GvcMixerSinkInputPrivate
+{
+ gpointer dummy;
+};
+
+static void gvc_mixer_sink_input_class_init (GvcMixerSinkInputClass *klass);
+static void gvc_mixer_sink_input_init (GvcMixerSinkInput *mixer_sink_input);
+static void gvc_mixer_sink_input_finalize (GObject *object);
+static void gvc_mixer_sink_input_dispose (GObject *object);
+
+G_DEFINE_TYPE (GvcMixerSinkInput, gvc_mixer_sink_input, GVC_TYPE_MIXER_STREAM)
+
+static gboolean
+gvc_mixer_sink_input_push_volume (GvcMixerStream *stream, gpointer *op)
+{
+ pa_operation *o;
+ guint index;
+ GvcChannelMap *map;
+ pa_context *context;
+ const pa_cvolume *cv;
+ guint num_channels;
+
+ index = gvc_mixer_stream_get_index (stream);
+
+ map = gvc_mixer_stream_get_channel_map (stream);
+ num_channels = gvc_channel_map_get_num_channels (map);
+
+ cv = gvc_channel_map_get_cvolume(map);
+
+ context = gvc_mixer_stream_get_pa_context (stream);
+
+ o = pa_context_set_sink_input_volume (context,
+ index,
+ cv,
+ NULL,
+ NULL);
+
+ if (o == NULL) {
+ g_warning ("pa_context_set_sink_input_volume() failed");
+ return FALSE;
+ }
+
+ *op = o;
+
+ return TRUE;
+}
+
+static gboolean
+gvc_mixer_sink_input_change_is_muted (GvcMixerStream *stream,
+ gboolean is_muted)
+{
+ pa_operation *o;
+ guint index;
+ pa_context *context;
+
+ index = gvc_mixer_stream_get_index (stream);
+ context = gvc_mixer_stream_get_pa_context (stream);
+
+ o = pa_context_set_sink_input_mute (context,
+ index,
+ is_muted,
+ NULL,
+ NULL);
+
+ if (o == NULL) {
+ g_warning ("pa_context_set_sink_input_mute_by_index() failed");
+ return FALSE;
+ }
+
+ pa_operation_unref(o);
+
+ return TRUE;
+}
+
+static GObject *
+gvc_mixer_sink_input_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+ GvcMixerSinkInput *self;
+
+ object = G_OBJECT_CLASS (gvc_mixer_sink_input_parent_class)->constructor (type, n_construct_properties, construct_params);
+
+ self = GVC_MIXER_SINK_INPUT (object);
+
+ return object;
+}
+
+static void
+gvc_mixer_sink_input_class_init (GvcMixerSinkInputClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
+
+ object_class->constructor = gvc_mixer_sink_input_constructor;
+ object_class->dispose = gvc_mixer_sink_input_dispose;
+ object_class->finalize = gvc_mixer_sink_input_finalize;
+
+ stream_class->push_volume = gvc_mixer_sink_input_push_volume;
+ stream_class->change_is_muted = gvc_mixer_sink_input_change_is_muted;
+
+ g_type_class_add_private (klass, sizeof (GvcMixerSinkInputPrivate));
+}
+
+static void
+gvc_mixer_sink_input_init (GvcMixerSinkInput *sink_input)
+{
+ sink_input->priv = GVC_MIXER_SINK_INPUT_GET_PRIVATE (sink_input);
+}
+
+static void
+gvc_mixer_sink_input_dispose (GObject *object)
+{
+ GvcMixerSinkInput *mixer_sink_input;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GVC_IS_MIXER_SINK_INPUT (object));
+
+ mixer_sink_input = GVC_MIXER_SINK_INPUT (object);
+
+ G_OBJECT_CLASS (gvc_mixer_sink_input_parent_class)->dispose (object);
+}
+
+static void
+gvc_mixer_sink_input_finalize (GObject *object)
+{
+ GvcMixerSinkInput *mixer_sink_input;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GVC_IS_MIXER_SINK_INPUT (object));
+
+ mixer_sink_input = GVC_MIXER_SINK_INPUT (object);
+
+ g_return_if_fail (mixer_sink_input->priv != NULL);
+ G_OBJECT_CLASS (gvc_mixer_sink_input_parent_class)->finalize (object);
+}
+
+GvcMixerStream *
+gvc_mixer_sink_input_new (pa_context *context,
+ guint index,
+ GvcChannelMap *channel_map)
+{
+ GObject *object;
+
+ object = g_object_new (GVC_TYPE_MIXER_SINK_INPUT,
+ "pa-context", context,
+ "index", index,
+ "channel-map", channel_map,
+ NULL);
+
+ return GVC_MIXER_STREAM (object);
+}
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-sink-input.h b/plugins/media-keys/cut-n-paste/gvc-mixer-sink-input.h
new file mode 100644
index 0000000..6e44811
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-sink-input.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __GVC_MIXER_SINK_INPUT_H
+#define __GVC_MIXER_SINK_INPUT_H
+
+#include <glib-object.h>
+#include "gvc-mixer-stream.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GVC_TYPE_MIXER_SINK_INPUT (gvc_mixer_sink_input_get_type ())
+#define GVC_MIXER_SINK_INPUT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInput))
+#define GVC_MIXER_SINK_INPUT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInputClass))
+#define GVC_IS_MIXER_SINK_INPUT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SINK_INPUT))
+#define GVC_IS_MIXER_SINK_INPUT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SINK_INPUT))
+#define GVC_MIXER_SINK_INPUT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SINK_INPUT, GvcMixerSinkInputClass))
+
+typedef struct GvcMixerSinkInputPrivate GvcMixerSinkInputPrivate;
+
+typedef struct
+{
+ GvcMixerStream parent;
+ GvcMixerSinkInputPrivate *priv;
+} GvcMixerSinkInput;
+
+typedef struct
+{
+ GvcMixerStreamClass parent_class;
+} GvcMixerSinkInputClass;
+
+GType gvc_mixer_sink_input_get_type (void);
+
+GvcMixerStream * gvc_mixer_sink_input_new (pa_context *context,
+ guint index,
+ GvcChannelMap *map);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GVC_MIXER_SINK_INPUT_H */
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-sink.c b/plugins/media-keys/cut-n-paste/gvc-mixer-sink.c
new file mode 100644
index 0000000..5e95f63
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-sink.c
@@ -0,0 +1,220 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 William Jon McCann
+ *
+ * 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 "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "gvc-mixer-sink.h"
+
+#define GVC_MIXER_SINK_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SINK, GvcMixerSinkPrivate))
+
+struct GvcMixerSinkPrivate
+{
+ gpointer dummy;
+};
+
+static void gvc_mixer_sink_class_init (GvcMixerSinkClass *klass);
+static void gvc_mixer_sink_init (GvcMixerSink *mixer_sink);
+static void gvc_mixer_sink_finalize (GObject *object);
+static void gvc_mixer_sink_dispose (GObject *object);
+
+G_DEFINE_TYPE (GvcMixerSink, gvc_mixer_sink, GVC_TYPE_MIXER_STREAM)
+
+static gboolean
+gvc_mixer_sink_push_volume (GvcMixerStream *stream, gpointer *op)
+{
+ pa_operation *o;
+ guint index;
+ GvcChannelMap *map;
+ pa_context *context;
+ const pa_cvolume *cv;
+
+ index = gvc_mixer_stream_get_index (stream);
+
+ map = gvc_mixer_stream_get_channel_map (stream);
+
+ /* set the volume */
+ cv = gvc_channel_map_get_cvolume(map);
+
+ context = gvc_mixer_stream_get_pa_context (stream);
+
+ o = pa_context_set_sink_volume_by_index (context,
+ index,
+ cv,
+ NULL,
+ NULL);
+
+ if (o == NULL) {
+ g_warning ("pa_context_set_sink_volume_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
+ return FALSE;
+ }
+
+ *op = o;
+
+ return TRUE;
+}
+
+static gboolean
+gvc_mixer_sink_change_is_muted (GvcMixerStream *stream,
+ gboolean is_muted)
+{
+ pa_operation *o;
+ guint index;
+ pa_context *context;
+
+ index = gvc_mixer_stream_get_index (stream);
+ context = gvc_mixer_stream_get_pa_context (stream);
+
+ o = pa_context_set_sink_mute_by_index (context,
+ index,
+ is_muted,
+ NULL,
+ NULL);
+
+ if (o == NULL) {
+ g_warning ("pa_context_set_sink_mute_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
+ return FALSE;
+ }
+
+ pa_operation_unref(o);
+
+ return TRUE;
+}
+
+static gboolean
+gvc_mixer_sink_change_port (GvcMixerStream *stream,
+ const char *port)
+{
+#if PA_MICRO > 15
+ pa_operation *o;
+ guint index;
+ pa_context *context;
+
+ index = gvc_mixer_stream_get_index (stream);
+ context = gvc_mixer_stream_get_pa_context (stream);
+
+ o = pa_context_set_sink_port_by_index (context,
+ index,
+ port,
+ NULL,
+ NULL);
+
+ if (o == NULL) {
+ g_warning ("pa_context_set_sink_port_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
+ return FALSE;
+ }
+
+ pa_operation_unref(o);
+
+ return TRUE;
+#else
+ return FALSE;
+#endif /* PA_MICRO > 15 */
+}
+
+static GObject *
+gvc_mixer_sink_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+ GvcMixerSink *self;
+
+ object = G_OBJECT_CLASS (gvc_mixer_sink_parent_class)->constructor (type, n_construct_properties, construct_params);
+
+ self = GVC_MIXER_SINK (object);
+
+ return object;
+}
+
+static void
+gvc_mixer_sink_class_init (GvcMixerSinkClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
+
+ object_class->constructor = gvc_mixer_sink_constructor;
+ object_class->dispose = gvc_mixer_sink_dispose;
+ object_class->finalize = gvc_mixer_sink_finalize;
+
+ stream_class->push_volume = gvc_mixer_sink_push_volume;
+ stream_class->change_port = gvc_mixer_sink_change_port;
+ stream_class->change_is_muted = gvc_mixer_sink_change_is_muted;
+
+ g_type_class_add_private (klass, sizeof (GvcMixerSinkPrivate));
+}
+
+static void
+gvc_mixer_sink_init (GvcMixerSink *sink)
+{
+ sink->priv = GVC_MIXER_SINK_GET_PRIVATE (sink);
+}
+
+static void
+gvc_mixer_sink_dispose (GObject *object)
+{
+ GvcMixerSink *mixer_sink;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GVC_IS_MIXER_SINK (object));
+
+ mixer_sink = GVC_MIXER_SINK (object);
+
+ G_OBJECT_CLASS (gvc_mixer_sink_parent_class)->dispose (object);
+}
+
+static void
+gvc_mixer_sink_finalize (GObject *object)
+{
+ GvcMixerSink *mixer_sink;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GVC_IS_MIXER_SINK (object));
+
+ mixer_sink = GVC_MIXER_SINK (object);
+
+ g_return_if_fail (mixer_sink->priv != NULL);
+ G_OBJECT_CLASS (gvc_mixer_sink_parent_class)->finalize (object);
+}
+
+GvcMixerStream *
+gvc_mixer_sink_new (pa_context *context,
+ guint index,
+ GvcChannelMap *channel_map)
+
+{
+ GObject *object;
+
+ object = g_object_new (GVC_TYPE_MIXER_SINK,
+ "pa-context", context,
+ "index", index,
+ "channel-map", channel_map,
+ NULL);
+
+ return GVC_MIXER_STREAM (object);
+}
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-sink.h b/plugins/media-keys/cut-n-paste/gvc-mixer-sink.h
new file mode 100644
index 0000000..1e457dc
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-sink.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __GVC_MIXER_SINK_H
+#define __GVC_MIXER_SINK_H
+
+#include <glib-object.h>
+#include "gvc-mixer-stream.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GVC_TYPE_MIXER_SINK (gvc_mixer_sink_get_type ())
+#define GVC_MIXER_SINK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SINK, GvcMixerSink))
+#define GVC_MIXER_SINK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SINK, GvcMixerSinkClass))
+#define GVC_IS_MIXER_SINK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SINK))
+#define GVC_IS_MIXER_SINK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SINK))
+#define GVC_MIXER_SINK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SINK, GvcMixerSinkClass))
+
+typedef struct GvcMixerSinkPrivate GvcMixerSinkPrivate;
+
+typedef struct
+{
+ GvcMixerStream parent;
+ GvcMixerSinkPrivate *priv;
+} GvcMixerSink;
+
+typedef struct
+{
+ GvcMixerStreamClass parent_class;
+} GvcMixerSinkClass;
+
+GType gvc_mixer_sink_get_type (void);
+
+GvcMixerStream * gvc_mixer_sink_new (pa_context *context,
+ guint index,
+ GvcChannelMap *map);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GVC_MIXER_SINK_H */
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-source-output.c b/plugins/media-keys/cut-n-paste/gvc-mixer-source-output.c
new file mode 100644
index 0000000..b4cc34d
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-source-output.c
@@ -0,0 +1,128 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 William Jon McCann
+ *
+ * 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 "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "gvc-mixer-source-output.h"
+
+#define GVC_MIXER_SOURCE_OUTPUT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutputPrivate))
+
+struct GvcMixerSourceOutputPrivate
+{
+ gpointer dummy;
+};
+
+static void gvc_mixer_source_output_class_init (GvcMixerSourceOutputClass *klass);
+static void gvc_mixer_source_output_init (GvcMixerSourceOutput *mixer_source_output);
+static void gvc_mixer_source_output_finalize (GObject *object);
+
+G_DEFINE_TYPE (GvcMixerSourceOutput, gvc_mixer_source_output, GVC_TYPE_MIXER_STREAM)
+
+static gboolean
+gvc_mixer_source_output_push_volume (GvcMixerStream *stream, gpointer *op)
+{
+ /* FIXME: */
+ *op = NULL;
+ return TRUE;
+}
+
+static gboolean
+gvc_mixer_source_output_change_is_muted (GvcMixerStream *stream,
+ gboolean is_muted)
+{
+ /* FIXME: */
+ return TRUE;
+}
+
+static GObject *
+gvc_mixer_source_output_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+ GvcMixerSourceOutput *self;
+
+ object = G_OBJECT_CLASS (gvc_mixer_source_output_parent_class)->constructor (type, n_construct_properties, construct_params);
+
+ self = GVC_MIXER_SOURCE_OUTPUT (object);
+
+ return object;
+}
+
+static void
+gvc_mixer_source_output_class_init (GvcMixerSourceOutputClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
+
+ object_class->constructor = gvc_mixer_source_output_constructor;
+ object_class->finalize = gvc_mixer_source_output_finalize;
+
+ stream_class->push_volume = gvc_mixer_source_output_push_volume;
+ stream_class->change_is_muted = gvc_mixer_source_output_change_is_muted;
+
+ g_type_class_add_private (klass, sizeof (GvcMixerSourceOutputPrivate));
+}
+
+static void
+gvc_mixer_source_output_init (GvcMixerSourceOutput *source_output)
+{
+ source_output->priv = GVC_MIXER_SOURCE_OUTPUT_GET_PRIVATE (source_output);
+
+}
+
+static void
+gvc_mixer_source_output_finalize (GObject *object)
+{
+ GvcMixerSourceOutput *mixer_source_output;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GVC_IS_MIXER_SOURCE_OUTPUT (object));
+
+ mixer_source_output = GVC_MIXER_SOURCE_OUTPUT (object);
+
+ g_return_if_fail (mixer_source_output->priv != NULL);
+ G_OBJECT_CLASS (gvc_mixer_source_output_parent_class)->finalize (object);
+}
+
+GvcMixerStream *
+gvc_mixer_source_output_new (pa_context *context,
+ guint index,
+ GvcChannelMap *channel_map)
+{
+ GObject *object;
+
+ object = g_object_new (GVC_TYPE_MIXER_SOURCE_OUTPUT,
+ "pa-context", context,
+ "index", index,
+ "channel-map", channel_map,
+ NULL);
+
+ return GVC_MIXER_STREAM (object);
+}
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-source-output.h b/plugins/media-keys/cut-n-paste/gvc-mixer-source-output.h
new file mode 100644
index 0000000..6ebaca9
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-source-output.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __GVC_MIXER_SOURCE_OUTPUT_H
+#define __GVC_MIXER_SOURCE_OUTPUT_H
+
+#include <glib-object.h>
+#include "gvc-mixer-stream.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GVC_TYPE_MIXER_SOURCE_OUTPUT (gvc_mixer_source_output_get_type ())
+#define GVC_MIXER_SOURCE_OUTPUT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutput))
+#define GVC_MIXER_SOURCE_OUTPUT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutputClass))
+#define GVC_IS_MIXER_SOURCE_OUTPUT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT))
+#define GVC_IS_MIXER_SOURCE_OUTPUT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SOURCE_OUTPUT))
+#define GVC_MIXER_SOURCE_OUTPUT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SOURCE_OUTPUT, GvcMixerSourceOutputClass))
+
+typedef struct GvcMixerSourceOutputPrivate GvcMixerSourceOutputPrivate;
+
+typedef struct
+{
+ GvcMixerStream parent;
+ GvcMixerSourceOutputPrivate *priv;
+} GvcMixerSourceOutput;
+
+typedef struct
+{
+ GvcMixerStreamClass parent_class;
+} GvcMixerSourceOutputClass;
+
+GType gvc_mixer_source_output_get_type (void);
+
+GvcMixerStream * gvc_mixer_source_output_new (pa_context *context,
+ guint index,
+ GvcChannelMap *map);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GVC_MIXER_SOURCE_OUTPUT_H */
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-source.c b/plugins/media-keys/cut-n-paste/gvc-mixer-source.c
new file mode 100644
index 0000000..d13be9d
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-source.c
@@ -0,0 +1,220 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 William Jon McCann
+ *
+ * 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 "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "gvc-mixer-source.h"
+
+#define GVC_MIXER_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_SOURCE, GvcMixerSourcePrivate))
+
+struct GvcMixerSourcePrivate
+{
+ gpointer dummy;
+};
+
+static void gvc_mixer_source_class_init (GvcMixerSourceClass *klass);
+static void gvc_mixer_source_init (GvcMixerSource *mixer_source);
+static void gvc_mixer_source_finalize (GObject *object);
+static void gvc_mixer_source_dispose (GObject *object);
+
+G_DEFINE_TYPE (GvcMixerSource, gvc_mixer_source, GVC_TYPE_MIXER_STREAM)
+
+static gboolean
+gvc_mixer_source_push_volume (GvcMixerStream *stream, gpointer *op)
+{
+ pa_operation *o;
+ guint index;
+ GvcChannelMap *map;
+ pa_context *context;
+ const pa_cvolume *cv;
+
+ index = gvc_mixer_stream_get_index (stream);
+
+ map = gvc_mixer_stream_get_channel_map (stream);
+
+ /* set the volume */
+ cv = gvc_channel_map_get_cvolume (map);
+
+ context = gvc_mixer_stream_get_pa_context (stream);
+
+ o = pa_context_set_source_volume_by_index (context,
+ index,
+ cv,
+ NULL,
+ NULL);
+
+ if (o == NULL) {
+ g_warning ("pa_context_set_source_volume_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
+ return FALSE;
+ }
+
+ *op = o;
+
+ return TRUE;
+}
+
+static gboolean
+gvc_mixer_source_change_is_muted (GvcMixerStream *stream,
+ gboolean is_muted)
+{
+ pa_operation *o;
+ guint index;
+ pa_context *context;
+
+ index = gvc_mixer_stream_get_index (stream);
+ context = gvc_mixer_stream_get_pa_context (stream);
+
+ o = pa_context_set_source_mute_by_index (context,
+ index,
+ is_muted,
+ NULL,
+ NULL);
+
+ if (o == NULL) {
+ g_warning ("pa_context_set_source_mute_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
+ return FALSE;
+ }
+
+ pa_operation_unref(o);
+
+ return TRUE;
+}
+
+static gboolean
+gvc_mixer_source_change_port (GvcMixerStream *stream,
+ const char *port)
+{
+#if PA_MICRO > 15
+ pa_operation *o;
+ guint index;
+ pa_context *context;
+
+ index = gvc_mixer_stream_get_index (stream);
+ context = gvc_mixer_stream_get_pa_context (stream);
+
+ o = pa_context_set_source_port_by_index (context,
+ index,
+ port,
+ NULL,
+ NULL);
+
+ if (o == NULL) {
+ g_warning ("pa_context_set_source_port_by_index() failed: %s", pa_strerror(pa_context_errno(context)));
+ return FALSE;
+ }
+
+ pa_operation_unref(o);
+
+ return TRUE;
+#else
+ return FALSE;
+#endif /* PA_MICRO > 15 */
+}
+
+static GObject *
+gvc_mixer_source_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+ GvcMixerSource *self;
+
+ object = G_OBJECT_CLASS (gvc_mixer_source_parent_class)->constructor (type, n_construct_properties, construct_params);
+
+ self = GVC_MIXER_SOURCE (object);
+
+ return object;
+}
+
+static void
+gvc_mixer_source_class_init (GvcMixerSourceClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GvcMixerStreamClass *stream_class = GVC_MIXER_STREAM_CLASS (klass);
+
+ object_class->constructor = gvc_mixer_source_constructor;
+ object_class->dispose = gvc_mixer_source_dispose;
+ object_class->finalize = gvc_mixer_source_finalize;
+
+ stream_class->push_volume = gvc_mixer_source_push_volume;
+ stream_class->change_is_muted = gvc_mixer_source_change_is_muted;
+ stream_class->change_port = gvc_mixer_source_change_port;
+
+ g_type_class_add_private (klass, sizeof (GvcMixerSourcePrivate));
+}
+
+static void
+gvc_mixer_source_init (GvcMixerSource *source)
+{
+ source->priv = GVC_MIXER_SOURCE_GET_PRIVATE (source);
+}
+
+static void
+gvc_mixer_source_dispose (GObject *object)
+{
+ GvcMixerSource *mixer_source;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GVC_IS_MIXER_SOURCE (object));
+
+ mixer_source = GVC_MIXER_SOURCE (object);
+
+ G_OBJECT_CLASS (gvc_mixer_source_parent_class)->dispose (object);
+}
+
+static void
+gvc_mixer_source_finalize (GObject *object)
+{
+ GvcMixerSource *mixer_source;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GVC_IS_MIXER_SOURCE (object));
+
+ mixer_source = GVC_MIXER_SOURCE (object);
+
+ g_return_if_fail (mixer_source->priv != NULL);
+ G_OBJECT_CLASS (gvc_mixer_source_parent_class)->finalize (object);
+}
+
+GvcMixerStream *
+gvc_mixer_source_new (pa_context *context,
+ guint index,
+ GvcChannelMap *channel_map)
+
+{
+ GObject *object;
+
+ object = g_object_new (GVC_TYPE_MIXER_SOURCE,
+ "pa-context", context,
+ "index", index,
+ "channel-map", channel_map,
+ NULL);
+
+ return GVC_MIXER_STREAM (object);
+}
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-source.h b/plugins/media-keys/cut-n-paste/gvc-mixer-source.h
new file mode 100644
index 0000000..502f31c
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-source.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __GVC_MIXER_SOURCE_H
+#define __GVC_MIXER_SOURCE_H
+
+#include <glib-object.h>
+#include "gvc-mixer-stream.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GVC_TYPE_MIXER_SOURCE (gvc_mixer_source_get_type ())
+#define GVC_MIXER_SOURCE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_SOURCE, GvcMixerSource))
+#define GVC_MIXER_SOURCE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_SOURCE, GvcMixerSourceClass))
+#define GVC_IS_MIXER_SOURCE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_SOURCE))
+#define GVC_IS_MIXER_SOURCE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_SOURCE))
+#define GVC_MIXER_SOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_SOURCE, GvcMixerSourceClass))
+
+typedef struct GvcMixerSourcePrivate GvcMixerSourcePrivate;
+
+typedef struct
+{
+ GvcMixerStream parent;
+ GvcMixerSourcePrivate *priv;
+} GvcMixerSource;
+
+typedef struct
+{
+ GvcMixerStreamClass parent_class;
+} GvcMixerSourceClass;
+
+GType gvc_mixer_source_get_type (void);
+
+GvcMixerStream * gvc_mixer_source_new (pa_context *context,
+ guint index,
+ GvcChannelMap *map);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GVC_MIXER_SOURCE_H */
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-stream.c b/plugins/media-keys/cut-n-paste/gvc-mixer-stream.c
new file mode 100644
index 0000000..4662d46
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-stream.c
@@ -0,0 +1,875 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 William Jon McCann
+ *
+ * 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 "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+
+#include <pulse/pulseaudio.h>
+
+#include "gvc-mixer-stream.h"
+
+#define GVC_MIXER_STREAM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GVC_TYPE_MIXER_STREAM, GvcMixerStreamPrivate))
+
+static guint32 stream_serial = 1;
+
+struct GvcMixerStreamPrivate
+{
+ pa_context *pa_context;
+ guint id;
+ guint index;
+ GvcChannelMap *channel_map;
+ char *name;
+ char *description;
+ char *application_id;
+ char *icon_name;
+ gboolean is_muted;
+ gboolean can_decibel;
+ gboolean is_event_stream;
+ gboolean is_virtual;
+ pa_volume_t base_volume;
+ pa_operation *change_volume_op;
+ char *port;
+ char *human_port;
+ GList *ports;
+};
+
+enum
+{
+ PROP_0,
+ PROP_ID,
+ PROP_PA_CONTEXT,
+ PROP_CHANNEL_MAP,
+ PROP_INDEX,
+ PROP_NAME,
+ PROP_DESCRIPTION,
+ PROP_APPLICATION_ID,
+ PROP_ICON_NAME,
+ PROP_VOLUME,
+ PROP_DECIBEL,
+ PROP_IS_MUTED,
+ PROP_CAN_DECIBEL,
+ PROP_IS_EVENT_STREAM,
+ PROP_IS_VIRTUAL,
+ PROP_PORT,
+};
+
+static void gvc_mixer_stream_class_init (GvcMixerStreamClass *klass);
+static void gvc_mixer_stream_init (GvcMixerStream *mixer_stream);
+static void gvc_mixer_stream_finalize (GObject *object);
+
+G_DEFINE_ABSTRACT_TYPE (GvcMixerStream, gvc_mixer_stream, G_TYPE_OBJECT)
+
+static guint32
+get_next_stream_serial (void)
+{
+ guint32 serial;
+
+ serial = stream_serial++;
+
+ if ((gint32)stream_serial < 0) {
+ stream_serial = 1;
+ }
+
+ return serial;
+}
+
+pa_context *
+gvc_mixer_stream_get_pa_context (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
+ return stream->priv->pa_context;
+}
+
+guint
+gvc_mixer_stream_get_index (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
+ return stream->priv->index;
+}
+
+guint
+gvc_mixer_stream_get_id (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
+ return stream->priv->id;
+}
+
+GvcChannelMap *
+gvc_mixer_stream_get_channel_map (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
+ return stream->priv->channel_map;
+}
+
+pa_volume_t
+gvc_mixer_stream_get_volume (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
+
+ return (pa_volume_t) gvc_channel_map_get_volume(stream->priv->channel_map)[VOLUME];
+}
+
+gdouble
+gvc_mixer_stream_get_decibel (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
+
+ return pa_sw_volume_to_dB(
+ (pa_volume_t) gvc_channel_map_get_volume(stream->priv->channel_map)[VOLUME]);
+}
+
+gboolean
+gvc_mixer_stream_set_volume (GvcMixerStream *stream,
+ pa_volume_t volume)
+{
+ pa_cvolume cv;
+
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ cv = *gvc_channel_map_get_cvolume(stream->priv->channel_map);
+ pa_cvolume_scale(&cv, volume);
+
+ if (!pa_cvolume_equal(gvc_channel_map_get_cvolume(stream->priv->channel_map), &cv)) {
+ gvc_channel_map_volume_changed(stream->priv->channel_map, &cv, FALSE);
+ g_object_notify (G_OBJECT (stream), "volume");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+gvc_mixer_stream_set_decibel (GvcMixerStream *stream,
+ gdouble db)
+{
+ pa_cvolume cv;
+
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ cv = *gvc_channel_map_get_cvolume(stream->priv->channel_map);
+ pa_cvolume_scale(&cv, pa_sw_volume_from_dB(db));
+
+ if (!pa_cvolume_equal(gvc_channel_map_get_cvolume(stream->priv->channel_map), &cv)) {
+ gvc_channel_map_volume_changed(stream->priv->channel_map, &cv, FALSE);
+ g_object_notify (G_OBJECT (stream), "volume");
+ }
+
+ return TRUE;
+}
+
+gboolean
+gvc_mixer_stream_get_is_muted (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+ return stream->priv->is_muted;
+}
+
+gboolean
+gvc_mixer_stream_get_can_decibel (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+ return stream->priv->can_decibel;
+}
+
+gboolean
+gvc_mixer_stream_set_is_muted (GvcMixerStream *stream,
+ gboolean is_muted)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ if (is_muted != stream->priv->is_muted) {
+ stream->priv->is_muted = is_muted;
+ g_object_notify (G_OBJECT (stream), "is-muted");
+ }
+
+ return TRUE;
+}
+
+gboolean
+gvc_mixer_stream_set_can_decibel (GvcMixerStream *stream,
+ gboolean can_decibel)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ if (can_decibel != stream->priv->can_decibel) {
+ stream->priv->can_decibel = can_decibel;
+ g_object_notify (G_OBJECT (stream), "can-decibel");
+ }
+
+ return TRUE;
+}
+
+const char *
+gvc_mixer_stream_get_name (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
+ return stream->priv->name;
+}
+
+const char *
+gvc_mixer_stream_get_description (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
+ return stream->priv->description;
+}
+
+gboolean
+gvc_mixer_stream_set_name (GvcMixerStream *stream,
+ const char *name)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ g_free (stream->priv->name);
+ stream->priv->name = g_strdup (name);
+ g_object_notify (G_OBJECT (stream), "name");
+
+ return TRUE;
+}
+
+gboolean
+gvc_mixer_stream_set_description (GvcMixerStream *stream,
+ const char *description)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ g_free (stream->priv->description);
+ stream->priv->description = g_strdup (description);
+ g_object_notify (G_OBJECT (stream), "description");
+
+ return TRUE;
+}
+
+gboolean
+gvc_mixer_stream_is_event_stream (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ return stream->priv->is_event_stream;
+}
+
+gboolean
+gvc_mixer_stream_set_is_event_stream (GvcMixerStream *stream,
+ gboolean is_event_stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ stream->priv->is_event_stream = is_event_stream;
+ g_object_notify (G_OBJECT (stream), "is-event-stream");
+
+ return TRUE;
+}
+
+gboolean
+gvc_mixer_stream_is_virtual (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ return stream->priv->is_virtual;
+}
+
+gboolean
+gvc_mixer_stream_set_is_virtual (GvcMixerStream *stream,
+ gboolean is_virtual)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ stream->priv->is_virtual = is_virtual;
+ g_object_notify (G_OBJECT (stream), "is-virtual");
+
+ return TRUE;
+}
+
+const char *
+gvc_mixer_stream_get_application_id (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
+ return stream->priv->application_id;
+}
+
+gboolean
+gvc_mixer_stream_set_application_id (GvcMixerStream *stream,
+ const char *application_id)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ g_free (stream->priv->application_id);
+ stream->priv->application_id = g_strdup (application_id);
+ g_object_notify (G_OBJECT (stream), "application-id");
+
+ return TRUE;
+}
+
+static void
+on_channel_map_volume_changed (GvcChannelMap *channel_map,
+ gboolean set,
+ GvcMixerStream *stream)
+{
+ if (set == TRUE)
+ gvc_mixer_stream_push_volume (stream);
+
+ g_object_notify (G_OBJECT (stream), "volume");
+}
+
+static gboolean
+gvc_mixer_stream_set_channel_map (GvcMixerStream *stream,
+ GvcChannelMap *channel_map)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ if (channel_map != NULL) {
+ g_object_ref (channel_map);
+ }
+
+ if (stream->priv->channel_map != NULL) {
+ g_signal_handlers_disconnect_by_func (stream->priv->channel_map,
+ on_channel_map_volume_changed,
+ stream);
+ g_object_unref (stream->priv->channel_map);
+ }
+
+ stream->priv->channel_map = channel_map;
+
+ if (stream->priv->channel_map != NULL) {
+ g_signal_connect (stream->priv->channel_map,
+ "volume-changed",
+ G_CALLBACK (on_channel_map_volume_changed),
+ stream);
+
+ g_object_notify (G_OBJECT (stream), "channel-map");
+ }
+
+ return TRUE;
+}
+
+const char *
+gvc_mixer_stream_get_icon_name (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
+ return stream->priv->icon_name;
+}
+
+gboolean
+gvc_mixer_stream_set_icon_name (GvcMixerStream *stream,
+ const char *icon_name)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ g_free (stream->priv->icon_name);
+ stream->priv->icon_name = g_strdup (icon_name);
+ g_object_notify (G_OBJECT (stream), "icon-name");
+
+ return TRUE;
+}
+
+pa_volume_t
+gvc_mixer_stream_get_base_volume (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), 0);
+
+ return stream->priv->base_volume;
+}
+
+gboolean
+gvc_mixer_stream_set_base_volume (GvcMixerStream *stream,
+ pa_volume_t base_volume)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ stream->priv->base_volume = base_volume;
+
+ return TRUE;
+}
+
+GvcMixerStreamPort *
+gvc_mixer_stream_get_port (GvcMixerStream *stream)
+{
+ GList *l;
+
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), NULL);
+ g_return_val_if_fail (stream->priv->ports != NULL, NULL);
+
+ for (l = stream->priv->ports; l != NULL; l = l->next) {
+ GvcMixerStreamPort *p = l->data;
+ if (g_strcmp0 (stream->priv->port, p->port) == 0) {
+ return p;
+ }
+ }
+
+ g_assert_not_reached ();
+
+ return NULL;
+}
+
+gboolean
+gvc_mixer_stream_set_port (GvcMixerStream *stream,
+ const char *port)
+{
+ GList *l;
+
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+ g_return_val_if_fail (stream->priv->ports != NULL, FALSE);
+
+ g_free (stream->priv->port);
+ stream->priv->port = g_strdup (port);
+
+ g_free (stream->priv->human_port);
+ stream->priv->human_port = NULL;
+
+ for (l = stream->priv->ports; l != NULL; l = l->next) {
+ GvcMixerStreamPort *p = l->data;
+ if (g_str_equal (stream->priv->port, p->port)) {
+ stream->priv->human_port = g_strdup (p->human_port);
+ break;
+ }
+ }
+
+ g_object_notify (G_OBJECT (stream), "port");
+
+ return TRUE;
+}
+
+gboolean
+gvc_mixer_stream_change_port (GvcMixerStream *stream,
+ const char *port)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+ return GVC_MIXER_STREAM_GET_CLASS (stream)->change_port (stream, port);
+}
+
+const GList *
+gvc_mixer_stream_get_ports (GvcMixerStream *stream)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+ return stream->priv->ports;
+}
+
+static int
+sort_ports (GvcMixerStreamPort *a,
+ GvcMixerStreamPort *b)
+{
+ if (a->priority == b->priority)
+ return 0;
+ if (a->priority > b->priority)
+ return 1;
+ return -1;
+}
+
+gboolean
+gvc_mixer_stream_set_ports (GvcMixerStream *stream,
+ GList *ports)
+{
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+ g_return_val_if_fail (stream->priv->ports == NULL, FALSE);
+
+ stream->priv->ports = g_list_sort (ports, (GCompareFunc) sort_ports);
+
+ return TRUE;
+}
+
+static void
+gvc_mixer_stream_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GvcMixerStream *self = GVC_MIXER_STREAM (object);
+
+ switch (prop_id) {
+ case PROP_PA_CONTEXT:
+ self->priv->pa_context = g_value_get_pointer (value);
+ break;
+ case PROP_INDEX:
+ self->priv->index = g_value_get_ulong (value);
+ break;
+ case PROP_ID:
+ self->priv->id = g_value_get_ulong (value);
+ break;
+ case PROP_CHANNEL_MAP:
+ gvc_mixer_stream_set_channel_map (self, g_value_get_object (value));
+ break;
+ case PROP_NAME:
+ gvc_mixer_stream_set_name (self, g_value_get_string (value));
+ break;
+ case PROP_DESCRIPTION:
+ gvc_mixer_stream_set_description (self, g_value_get_string (value));
+ break;
+ case PROP_APPLICATION_ID:
+ gvc_mixer_stream_set_application_id (self, g_value_get_string (value));
+ break;
+ case PROP_ICON_NAME:
+ gvc_mixer_stream_set_icon_name (self, g_value_get_string (value));
+ break;
+ case PROP_VOLUME:
+ gvc_mixer_stream_set_volume (self, g_value_get_ulong (value));
+ break;
+ case PROP_DECIBEL:
+ gvc_mixer_stream_set_decibel (self, g_value_get_double (value));
+ break;
+ case PROP_IS_MUTED:
+ gvc_mixer_stream_set_is_muted (self, g_value_get_boolean (value));
+ break;
+ case PROP_IS_EVENT_STREAM:
+ gvc_mixer_stream_set_is_event_stream (self, g_value_get_boolean (value));
+ break;
+ case PROP_IS_VIRTUAL:
+ gvc_mixer_stream_set_is_virtual (self, g_value_get_boolean (value));
+ break;
+ case PROP_CAN_DECIBEL:
+ gvc_mixer_stream_set_can_decibel (self, g_value_get_boolean (value));
+ break;
+ case PROP_PORT:
+ gvc_mixer_stream_set_port (self, g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gvc_mixer_stream_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GvcMixerStream *self = GVC_MIXER_STREAM (object);
+
+ switch (prop_id) {
+ case PROP_PA_CONTEXT:
+ g_value_set_pointer (value, self->priv->pa_context);
+ break;
+ case PROP_INDEX:
+ g_value_set_ulong (value, self->priv->index);
+ break;
+ case PROP_ID:
+ g_value_set_ulong (value, self->priv->id);
+ break;
+ case PROP_CHANNEL_MAP:
+ g_value_set_object (value, self->priv->channel_map);
+ break;
+ case PROP_NAME:
+ g_value_set_string (value, self->priv->name);
+ break;
+ case PROP_DESCRIPTION:
+ g_value_set_string (value, self->priv->description);
+ break;
+ case PROP_APPLICATION_ID:
+ g_value_set_string (value, self->priv->application_id);
+ break;
+ case PROP_ICON_NAME:
+ g_value_set_string (value, self->priv->icon_name);
+ break;
+ case PROP_VOLUME:
+ g_value_set_ulong (value,
+ pa_cvolume_max(gvc_channel_map_get_cvolume(self->priv->channel_map)));
+ break;
+ case PROP_DECIBEL:
+ g_value_set_double (value,
+ pa_sw_volume_to_dB(pa_cvolume_max(gvc_channel_map_get_cvolume(self->priv->channel_map))));
+ break;
+ case PROP_IS_MUTED:
+ g_value_set_boolean (value, self->priv->is_muted);
+ break;
+ case PROP_IS_EVENT_STREAM:
+ g_value_set_boolean (value, self->priv->is_event_stream);
+ break;
+ case PROP_IS_VIRTUAL:
+ g_value_set_boolean (value, self->priv->is_virtual);
+ break;
+ case PROP_CAN_DECIBEL:
+ g_value_set_boolean (value, self->priv->can_decibel);
+ break;
+ case PROP_PORT:
+ g_value_set_string (value, self->priv->port);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GObject *
+gvc_mixer_stream_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+ GvcMixerStream *self;
+
+ object = G_OBJECT_CLASS (gvc_mixer_stream_parent_class)->constructor (type, n_construct_properties, construct_params);
+
+ self = GVC_MIXER_STREAM (object);
+
+ self->priv->id = get_next_stream_serial ();
+
+ return object;
+}
+
+static gboolean
+gvc_mixer_stream_real_change_port (GvcMixerStream *stream,
+ const char *port)
+{
+ return FALSE;
+}
+
+static gboolean
+gvc_mixer_stream_real_push_volume (GvcMixerStream *stream, gpointer *op)
+{
+ return FALSE;
+}
+
+static gboolean
+gvc_mixer_stream_real_change_is_muted (GvcMixerStream *stream,
+ gboolean is_muted)
+{
+ return FALSE;
+}
+
+gboolean
+gvc_mixer_stream_push_volume (GvcMixerStream *stream)
+{
+ pa_operation *op;
+ gboolean ret;
+
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+
+ if (stream->priv->is_event_stream != FALSE)
+ return TRUE;
+
+ g_debug ("Pushing new volume to stream '%s' (%s)",
+ stream->priv->description, stream->priv->name);
+
+ ret = GVC_MIXER_STREAM_GET_CLASS (stream)->push_volume (stream, (gpointer *) &op);
+ if (ret) {
+ if (stream->priv->change_volume_op != NULL)
+ pa_operation_unref (stream->priv->change_volume_op);
+ stream->priv->change_volume_op = op;
+ }
+ return ret;
+}
+
+gboolean
+gvc_mixer_stream_change_is_muted (GvcMixerStream *stream,
+ gboolean is_muted)
+{
+ gboolean ret;
+ g_return_val_if_fail (GVC_IS_MIXER_STREAM (stream), FALSE);
+ ret = GVC_MIXER_STREAM_GET_CLASS (stream)->change_is_muted (stream, is_muted);
+ return ret;
+}
+
+gboolean
+gvc_mixer_stream_is_running (GvcMixerStream *stream)
+{
+ if (stream->priv->change_volume_op == NULL)
+ return FALSE;
+
+ if ((pa_operation_get_state(stream->priv->change_volume_op) == PA_OPERATION_RUNNING))
+ return TRUE;
+
+ pa_operation_unref(stream->priv->change_volume_op);
+ stream->priv->change_volume_op = NULL;
+
+ return FALSE;
+}
+
+static void
+gvc_mixer_stream_class_init (GvcMixerStreamClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->constructor = gvc_mixer_stream_constructor;
+ gobject_class->finalize = gvc_mixer_stream_finalize;
+ gobject_class->set_property = gvc_mixer_stream_set_property;
+ gobject_class->get_property = gvc_mixer_stream_get_property;
+
+ klass->push_volume = gvc_mixer_stream_real_push_volume;
+ klass->change_port = gvc_mixer_stream_real_change_port;
+ klass->change_is_muted = gvc_mixer_stream_real_change_is_muted;
+
+ g_object_class_install_property (gobject_class,
+ PROP_INDEX,
+ g_param_spec_ulong ("index",
+ "Index",
+ "The index for this stream",
+ 0, G_MAXULONG, 0,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (gobject_class,
+ PROP_ID,
+ g_param_spec_ulong ("id",
+ "id",
+ "The id for this stream",
+ 0, G_MAXULONG, 0,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (gobject_class,
+ PROP_CHANNEL_MAP,
+ g_param_spec_object ("channel-map",
+ "channel map",
+ "The channel map for this stream",
+ GVC_TYPE_CHANNEL_MAP,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property (gobject_class,
+ PROP_PA_CONTEXT,
+ g_param_spec_pointer ("pa-context",
+ "PulseAudio context",
+ "The PulseAudio context for this stream",
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (gobject_class,
+ PROP_VOLUME,
+ g_param_spec_ulong ("volume",
+ "Volume",
+ "The volume for this stream",
+ 0, G_MAXULONG, 0,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class,
+ PROP_DECIBEL,
+ g_param_spec_double ("decibel",
+ "Decibel",
+ "The decibel level for this stream",
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (gobject_class,
+ PROP_NAME,
+ g_param_spec_string ("name",
+ "Name",
+ "Name to display for this stream",
+ NULL,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property (gobject_class,
+ PROP_DESCRIPTION,
+ g_param_spec_string ("description",
+ "Description",
+ "Description to display for this stream",
+ NULL,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property (gobject_class,
+ PROP_APPLICATION_ID,
+ g_param_spec_string ("application-id",
+ "Application identifier",
+ "Application identifier for this stream",
+ NULL,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property (gobject_class,
+ PROP_ICON_NAME,
+ g_param_spec_string ("icon-name",
+ "Icon Name",
+ "Name of icon to display for this stream",
+ NULL,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property (gobject_class,
+ PROP_IS_MUTED,
+ g_param_spec_boolean ("is-muted",
+ "is muted",
+ "Whether stream is muted",
+ FALSE,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property (gobject_class,
+ PROP_CAN_DECIBEL,
+ g_param_spec_boolean ("can-decibel",
+ "can decibel",
+ "Whether stream volume can be converted to decibel units",
+ FALSE,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property (gobject_class,
+ PROP_IS_EVENT_STREAM,
+ g_param_spec_boolean ("is-event-stream",
+ "is event stream",
+ "Whether stream's role is to play an event",
+ FALSE,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property (gobject_class,
+ PROP_IS_VIRTUAL,
+ g_param_spec_boolean ("is-virtual",
+ "is virtual stream",
+ "Whether the stream is virtual",
+ FALSE,
+ G_PARAM_READWRITE|G_PARAM_CONSTRUCT));
+ g_object_class_install_property (gobject_class,
+ PROP_PORT,
+ g_param_spec_string ("port",
+ "Port",
+ "The name of the current port for this stream",
+ NULL,
+ G_PARAM_READWRITE));
+ g_type_class_add_private (klass, sizeof (GvcMixerStreamPrivate));
+}
+
+static void
+gvc_mixer_stream_init (GvcMixerStream *stream)
+{
+ stream->priv = GVC_MIXER_STREAM_GET_PRIVATE (stream);
+}
+
+static void
+free_port (GvcMixerStreamPort *p)
+{
+ g_free (p->port);
+ g_free (p->human_port);
+ g_free (p);
+}
+
+static void
+gvc_mixer_stream_finalize (GObject *object)
+{
+ GvcMixerStream *mixer_stream;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GVC_IS_MIXER_STREAM (object));
+
+ mixer_stream = GVC_MIXER_STREAM (object);
+
+ g_return_if_fail (mixer_stream->priv != NULL);
+
+ g_free (mixer_stream->priv->name);
+ mixer_stream->priv->name = NULL;
+
+ g_free (mixer_stream->priv->description);
+ mixer_stream->priv->description = NULL;
+
+ g_free (mixer_stream->priv->application_id);
+ mixer_stream->priv->application_id = NULL;
+
+ g_free (mixer_stream->priv->icon_name);
+ mixer_stream->priv->icon_name = NULL;
+
+ g_free (mixer_stream->priv->port);
+ mixer_stream->priv->port = NULL;
+
+ g_free (mixer_stream->priv->human_port);
+ mixer_stream->priv->human_port = NULL;
+
+ g_list_foreach (mixer_stream->priv->ports, (GFunc) free_port, NULL);
+ g_list_free (mixer_stream->priv->ports);
+ mixer_stream->priv->ports = NULL;
+
+ if (mixer_stream->priv->change_volume_op) {
+ pa_operation_unref(mixer_stream->priv->change_volume_op);
+ mixer_stream->priv->change_volume_op = NULL;
+ }
+
+ G_OBJECT_CLASS (gvc_mixer_stream_parent_class)->finalize (object);
+}
diff --git a/plugins/media-keys/cut-n-paste/gvc-mixer-stream.h b/plugins/media-keys/cut-n-paste/gvc-mixer-stream.h
new file mode 100644
index 0000000..16ab21e
--- /dev/null
+++ b/plugins/media-keys/cut-n-paste/gvc-mixer-stream.h
@@ -0,0 +1,128 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __GVC_MIXER_STREAM_H
+#define __GVC_MIXER_STREAM_H
+
+#include <glib-object.h>
+#include <pulse/pulseaudio.h>
+
+#include "gvc-channel-map.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GVC_TYPE_MIXER_STREAM (gvc_mixer_stream_get_type ())
+#define GVC_MIXER_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GVC_TYPE_MIXER_STREAM, GvcMixerStream))
+#define GVC_MIXER_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GVC_TYPE_MIXER_STREAM, GvcMixerStreamClass))
+#define GVC_IS_MIXER_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GVC_TYPE_MIXER_STREAM))
+#define GVC_IS_MIXER_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GVC_TYPE_MIXER_STREAM))
+#define GVC_MIXER_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GVC_TYPE_MIXER_STREAM, GvcMixerStreamClass))
+
+typedef struct GvcMixerStreamPrivate GvcMixerStreamPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GvcMixerStreamPrivate *priv;
+} GvcMixerStream;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+ /* vtable */
+ gboolean (*push_volume) (GvcMixerStream *stream,
+ gpointer *operation);
+ gboolean (*change_is_muted) (GvcMixerStream *stream,
+ gboolean is_muted);
+ gboolean (*change_port) (GvcMixerStream *stream,
+ const char *port);
+} GvcMixerStreamClass;
+
+typedef struct
+{
+ char *port;
+ char *human_port;
+ guint priority;
+} GvcMixerStreamPort;
+
+GType gvc_mixer_stream_get_type (void);
+
+pa_context * gvc_mixer_stream_get_pa_context (GvcMixerStream *stream);
+guint gvc_mixer_stream_get_index (GvcMixerStream *stream);
+guint gvc_mixer_stream_get_id (GvcMixerStream *stream);
+GvcChannelMap * gvc_mixer_stream_get_channel_map (GvcMixerStream *stream);
+GvcMixerStreamPort *gvc_mixer_stream_get_port (GvcMixerStream *stream);
+const GList * gvc_mixer_stream_get_ports (GvcMixerStream *stream);
+gboolean gvc_mixer_stream_change_port (GvcMixerStream *stream,
+ const char *port);
+
+pa_volume_t gvc_mixer_stream_get_volume (GvcMixerStream *stream);
+gdouble gvc_mixer_stream_get_decibel (GvcMixerStream *stream);
+gboolean gvc_mixer_stream_push_volume (GvcMixerStream *stream);
+pa_volume_t gvc_mixer_stream_get_base_volume (GvcMixerStream *stream);
+
+gboolean gvc_mixer_stream_get_is_muted (GvcMixerStream *stream);
+gboolean gvc_mixer_stream_get_can_decibel (GvcMixerStream *stream);
+gboolean gvc_mixer_stream_change_is_muted (GvcMixerStream *stream,
+ gboolean is_muted);
+gboolean gvc_mixer_stream_is_running (GvcMixerStream *stream);
+const char * gvc_mixer_stream_get_name (GvcMixerStream *stream);
+const char * gvc_mixer_stream_get_icon_name (GvcMixerStream *stream);
+const char * gvc_mixer_stream_get_description (GvcMixerStream *stream);
+const char * gvc_mixer_stream_get_application_id (GvcMixerStream *stream);
+gboolean gvc_mixer_stream_is_event_stream (GvcMixerStream *stream);
+gboolean gvc_mixer_stream_is_virtual (GvcMixerStream *stream);
+
+/* private */
+gboolean gvc_mixer_stream_set_volume (GvcMixerStream *stream,
+ pa_volume_t volume);
+gboolean gvc_mixer_stream_set_decibel (GvcMixerStream *stream,
+ gdouble db);
+gboolean gvc_mixer_stream_set_is_muted (GvcMixerStream *stream,
+ gboolean is_muted);
+gboolean gvc_mixer_stream_set_can_decibel (GvcMixerStream *stream,
+ gboolean can_decibel);
+gboolean gvc_mixer_stream_set_name (GvcMixerStream *stream,
+ const char *name);
+gboolean gvc_mixer_stream_set_description (GvcMixerStream *stream,
+ const char *description);
+gboolean gvc_mixer_stream_set_icon_name (GvcMixerStream *stream,
+ const char *name);
+gboolean gvc_mixer_stream_set_is_event_stream (GvcMixerStream *stream,
+ gboolean is_event_stream);
+gboolean gvc_mixer_stream_set_is_virtual (GvcMixerStream *stream,
+ gboolean is_event_stream);
+gboolean gvc_mixer_stream_set_application_id (GvcMixerStream *stream,
+ const char *application_id);
+gboolean gvc_mixer_stream_set_base_volume (GvcMixerStream *stream,
+ pa_volume_t base_volume);
+gboolean gvc_mixer_stream_set_port (GvcMixerStream *stream,
+ const char *port);
+gboolean gvc_mixer_stream_set_ports (GvcMixerStream *stream,
+ GList *ports);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GVC_MIXER_STREAM_H */
diff --git a/plugins/media-keys/gsd-marshal.list b/plugins/media-keys/gsd-marshal.list
new file mode 100644
index 0000000..72f9937
--- /dev/null
+++ b/plugins/media-keys/gsd-marshal.list
@@ -0,0 +1 @@
+VOID:STRING,STRING
diff --git a/plugins/media-keys/gsd-media-keys-manager.c b/plugins/media-keys/gsd-media-keys-manager.c
new file mode 100644
index 0000000..ae6383a
--- /dev/null
+++ b/plugins/media-keys/gsd-media-keys-manager.c
@@ -0,0 +1,1373 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2001-2003 Bastien Nocera <[email protected]>
+ * Copyright (C) 2006-2007 William Jon McCann <[email protected]>
+ *
+ * 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 "config.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <locale.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+#include <mateconf/mateconf-client.h>
+
+#include <dbus/dbus-glib.h>
+#include <dbus/dbus-glib-lowlevel.h>
+
+#include "mate-settings-profile.h"
+#include "gsd-marshal.h"
+#include "gsd-media-keys-manager.h"
+#include "gsd-media-keys-manager-glue.h"
+
+#include "eggaccelerators.h"
+#include "acme.h"
+#include "gsd-media-keys-window.h"
+
+#ifdef HAVE_PULSE
+#include <canberra-gtk.h>
+#include "gvc-mixer-control.h"
+#endif /* HAVE_PULSE */
+
+#define GSD_DBUS_PATH "/org/mate/SettingsDaemon"
+#define GSD_DBUS_NAME "org.mate.SettingsDaemon"
+#define GSD_MEDIA_KEYS_DBUS_PATH GSD_DBUS_PATH "/MediaKeys"
+#define GSD_MEDIA_KEYS_DBUS_NAME GSD_DBUS_NAME ".MediaKeys"
+
+#define TOUCHPAD_ENABLED_KEY "/desktop/mate/peripherals/touchpad/touchpad_enabled"
+
+#define VOLUME_STEP 6 /* percents for one volume button press */
+#define MAX_VOLUME 65536.0
+
+#define GSD_MEDIA_KEYS_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_MEDIA_KEYS_MANAGER, GsdMediaKeysManagerPrivate))
+
+typedef struct {
+ char *application;
+ guint32 time;
+} MediaPlayer;
+
+struct GsdMediaKeysManagerPrivate
+{
+#ifdef HAVE_PULSE
+ /* Volume bits */
+ GvcMixerControl *volume;
+ GvcMixerStream *stream;
+#endif /* HAVE_PULSE */
+ GtkWidget *dialog;
+ MateConfClient *conf_client;
+ GVolumeMonitor *volume_monitor;
+
+ /* Multihead stuff */
+ GdkScreen *current_screen;
+ GSList *screens;
+
+ GList *media_players;
+
+ DBusGConnection *connection;
+ guint notify[HANDLED_KEYS];
+};
+
+enum {
+ MEDIA_PLAYER_KEY_PRESSED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void gsd_media_keys_manager_class_init (GsdMediaKeysManagerClass *klass);
+static void gsd_media_keys_manager_init (GsdMediaKeysManager *media_keys_manager);
+static void gsd_media_keys_manager_finalize (GObject *object);
+
+G_DEFINE_TYPE (GsdMediaKeysManager, gsd_media_keys_manager, G_TYPE_OBJECT)
+
+static gpointer manager_object = NULL;
+
+
+static void
+init_screens (GsdMediaKeysManager *manager)
+{
+ GdkDisplay *display;
+ int i;
+
+ display = gdk_display_get_default ();
+ for (i = 0; i < gdk_display_get_n_screens (display); i++) {
+ GdkScreen *screen;
+
+ screen = gdk_display_get_screen (display, i);
+ if (screen == NULL) {
+ continue;
+ }
+ manager->priv->screens = g_slist_append (manager->priv->screens, screen);
+ }
+
+ manager->priv->current_screen = manager->priv->screens->data;
+}
+
+
+static void
+acme_error (char * msg)
+{
+ GtkWidget *error_dialog;
+
+ error_dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ msg, NULL);
+ gtk_dialog_set_default_response (GTK_DIALOG (error_dialog),
+ GTK_RESPONSE_OK);
+ gtk_widget_show (error_dialog);
+ g_signal_connect (error_dialog,
+ "response",
+ G_CALLBACK (gtk_widget_destroy),
+ NULL);
+}
+
+static char *
+get_term_command (GsdMediaKeysManager *manager)
+{
+ char *cmd_term;
+ char *cmd = NULL;
+
+ cmd_term = mateconf_client_get_string (manager->priv->conf_client,
+ "/desktop/mate/applications/terminal/exec", NULL);
+ if ((cmd_term != NULL) && (strcmp (cmd_term, "") != 0)) {
+ char *cmd_args;
+ cmd_args = mateconf_client_get_string (manager->priv->conf_client,
+ "/desktop/mate/applications/terminal/exec_arg", NULL);
+ if ((cmd_args != NULL) && (strcmp (cmd_term, "") != 0)) {
+ cmd = g_strdup_printf ("%s %s -e", cmd_term, cmd_args);
+ } else {
+ cmd = g_strdup_printf ("%s -e", cmd_term);
+ }
+
+ g_free (cmd_args);
+ }
+
+ g_free (cmd_term);
+
+ return cmd;
+}
+
+static void
+execute (GsdMediaKeysManager *manager,
+ char *cmd,
+ gboolean sync,
+ gboolean need_term)
+{
+ gboolean retval;
+ char **argv;
+ int argc;
+ char *exec;
+ char *term = NULL;
+
+ retval = FALSE;
+
+ if (need_term) {
+ term = get_term_command (manager);
+ if (term == NULL) {
+ acme_error (_("Could not get default terminal. Verify that your default "
+ "terminal command is set and points to a valid application."));
+ return;
+ }
+ }
+
+ if (term) {
+ exec = g_strdup_printf ("%s %s", term, cmd);
+ g_free (term);
+ } else {
+ exec = g_strdup (cmd);
+ }
+
+ if (g_shell_parse_argv (exec, &argc, &argv, NULL)) {
+ if (sync != FALSE) {
+ retval = g_spawn_sync (g_get_home_dir (),
+ argv,
+ NULL,
+ G_SPAWN_SEARCH_PATH,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ } else {
+ retval = g_spawn_async (g_get_home_dir (),
+ argv,
+ NULL,
+ G_SPAWN_SEARCH_PATH,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
+ }
+ g_strfreev (argv);
+ }
+
+ if (retval == FALSE) {
+ char *msg;
+ msg = g_strdup_printf (_("Couldn't execute command: %s\n"
+ "Verify that this is a valid command."),
+ exec);
+
+ acme_error (msg);
+ g_free (msg);
+ }
+ g_free (exec);
+}
+
+static void
+dialog_init (GsdMediaKeysManager *manager)
+{
+ if (manager->priv->dialog != NULL
+ && !gsd_osd_window_is_valid (GSD_OSD_WINDOW (manager->priv->dialog))) {
+ gtk_widget_destroy (manager->priv->dialog);
+ manager->priv->dialog = NULL;
+ }
+
+ if (manager->priv->dialog == NULL) {
+ manager->priv->dialog = gsd_media_keys_window_new ();
+ }
+}
+
+static gboolean
+is_valid_shortcut (const char *string)
+{
+ if (string == NULL || string[0] == '\0') {
+ return FALSE;
+ }
+ if (strcmp (string, "disabled") == 0) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+update_kbd_cb (MateConfClient *client,
+ guint id,
+ MateConfEntry *entry,
+ GsdMediaKeysManager *manager)
+{
+ int i;
+ gboolean need_flush = TRUE;
+
+ g_return_if_fail (entry->key != NULL);
+
+ gdk_error_trap_push ();
+
+ /* Find the key that was modified */
+ for (i = 0; i < HANDLED_KEYS; i++) {
+ if (strcmp (entry->key, keys[i].mateconf_key) == 0) {
+ char *tmp;
+ Key *key;
+
+ if (keys[i].key != NULL) {
+ need_flush = TRUE;
+ grab_key_unsafe (keys[i].key, FALSE, manager->priv->screens);
+ }
+
+ g_free (keys[i].key);
+ keys[i].key = NULL;
+
+ tmp = mateconf_client_get_string (manager->priv->conf_client,
+ keys[i].mateconf_key, NULL);
+
+ if (is_valid_shortcut (tmp) == FALSE) {
+ g_free (tmp);
+ break;
+ }
+
+ key = g_new0 (Key, 1);
+ if (!egg_accelerator_parse_virtual (tmp, &key->keysym, &key->keycodes, &key->state)) {
+ g_free (tmp);
+ g_free (key);
+ break;
+ }
+
+ need_flush = TRUE;
+ grab_key_unsafe (key, TRUE, manager->priv->screens);
+ keys[i].key = key;
+
+ g_free (tmp);
+
+ break;
+ }
+ }
+
+ if (need_flush)
+ gdk_flush ();
+ if (gdk_error_trap_pop ())
+ g_warning ("Grab failed for some keys, another application may already have access the them.");
+}
+
+static void
+init_kbd (GsdMediaKeysManager *manager)
+{
+ int i;
+ gboolean need_flush = FALSE;
+
+ mate_settings_profile_start (NULL);
+
+ gdk_error_trap_push ();
+
+ for (i = 0; i < HANDLED_KEYS; i++) {
+ char *tmp;
+ Key *key;
+
+ manager->priv->notify[i] =
+ mateconf_client_notify_add (manager->priv->conf_client,
+ keys[i].mateconf_key,
+ (MateConfClientNotifyFunc) update_kbd_cb,
+ manager,
+ NULL,
+ NULL);
+
+ tmp = mateconf_client_get_string (manager->priv->conf_client,
+ keys[i].mateconf_key,
+ NULL);
+
+ if (!is_valid_shortcut (tmp)) {
+ g_debug ("Not a valid shortcut: '%s'", tmp);
+ g_free (tmp);
+ continue;
+ }
+
+ key = g_new0 (Key, 1);
+ if (!egg_accelerator_parse_virtual (tmp, &key->keysym, &key->keycodes, &key->state)) {
+ g_debug ("Unable to parse: '%s'", tmp);
+ g_free (tmp);
+ g_free (key);
+ continue;
+ }
+
+ g_free (tmp);
+
+ keys[i].key = key;
+
+ need_flush = TRUE;
+ grab_key_unsafe (key, TRUE, manager->priv->screens);
+ }
+
+ if (need_flush)
+ gdk_flush ();
+ if (gdk_error_trap_pop ())
+ g_warning ("Grab failed for some keys, another application may already have access the them.");
+
+ mate_settings_profile_end (NULL);
+}
+
+static void
+dialog_show (GsdMediaKeysManager *manager)
+{
+ int orig_w;
+ int orig_h;
+ int screen_w;
+ int screen_h;
+ int x;
+ int y;
+ int pointer_x;
+ int pointer_y;
+ GtkRequisition win_req;
+ GdkScreen *pointer_screen;
+ GdkRectangle geometry;
+ int monitor;
+
+ gtk_window_set_screen (GTK_WINDOW (manager->priv->dialog),
+ manager->priv->current_screen);
+
+ /*
+ * get the window size
+ * if the window hasn't been mapped, it doesn't necessarily
+ * know its true size, yet, so we need to jump through hoops
+ */
+ gtk_window_get_default_size (GTK_WINDOW (manager->priv->dialog), &orig_w, &orig_h);
+ gtk_widget_size_request (manager->priv->dialog, &win_req);
+
+ if (win_req.width > orig_w) {
+ orig_w = win_req.width;
+ }
+ if (win_req.height > orig_h) {
+ orig_h = win_req.height;
+ }
+
+ pointer_screen = NULL;
+ gdk_display_get_pointer (gdk_screen_get_display (manager->priv->current_screen),
+ &pointer_screen,
+ &pointer_x,
+ &pointer_y,
+ NULL);
+ if (pointer_screen != manager->priv->current_screen) {
+ /* The pointer isn't on the current screen, so just
+ * assume the default monitor
+ */
+ monitor = 0;
+ } else {
+ monitor = gdk_screen_get_monitor_at_point (manager->priv->current_screen,
+ pointer_x,
+ pointer_y);
+ }
+
+ gdk_screen_get_monitor_geometry (manager->priv->current_screen,
+ monitor,
+ &geometry);
+
+ screen_w = geometry.width;
+ screen_h = geometry.height;
+
+ x = ((screen_w - orig_w) / 2) + geometry.x;
+ y = geometry.y + (screen_h / 2) + (screen_h / 2 - orig_h) / 2;
+
+ gtk_window_move (GTK_WINDOW (manager->priv->dialog), x, y);
+
+ gtk_widget_show (manager->priv->dialog);
+
+ gdk_display_sync (gdk_screen_get_display (manager->priv->current_screen));
+}
+
+static void
+do_unknown_action (GsdMediaKeysManager *manager,
+ const char *url)
+{
+ char *string;
+
+ g_return_if_fail (url != NULL);
+
+ string = mateconf_client_get_string (manager->priv->conf_client,
+ "/desktop/mate/url-handlers/unknown/command",
+ NULL);
+
+ if ((string != NULL) && (strcmp (string, "") != 0)) {
+ char *cmd;
+ cmd = g_strdup_printf (string, url);
+ execute (manager, cmd, FALSE, FALSE);
+ g_free (cmd);
+ }
+ g_free (string);
+}
+
+static void
+do_help_action (GsdMediaKeysManager *manager)
+{
+ char *string;
+
+ string = mateconf_client_get_string (manager->priv->conf_client,
+ "/desktop/mate/url-handlers/ghelp/command",
+ NULL);
+
+ if ((string != NULL) && (strcmp (string, "") != 0)) {
+ char *cmd;
+ cmd = g_strdup_printf (string, "");
+ execute (manager, cmd, FALSE, FALSE);
+ g_free (cmd);
+ } else {
+ do_unknown_action (manager, "ghelp:");
+ }
+
+ g_free (string);
+}
+
+static void
+do_mail_action (GsdMediaKeysManager *manager)
+{
+ char *string;
+
+ string = mateconf_client_get_string (manager->priv->conf_client,
+ "/desktop/mate/url-handlers/mailto/command",
+ NULL);
+
+ if ((string != NULL) && (strcmp (string, "") != 0)) {
+ char *cmd;
+ cmd = g_strdup_printf (string, "");
+ execute (manager,
+ cmd,
+ FALSE,
+ mateconf_client_get_bool (manager->priv->conf_client,
+ "/desktop/mate/url-handlers/mailto/needs_terminal", NULL));
+ g_free (cmd);
+ }
+ g_free (string);
+}
+
+static void
+do_media_action (GsdMediaKeysManager *manager)
+{
+ char *command;
+
+ command = mateconf_client_get_string (manager->priv->conf_client,
+ "/desktop/mate/applications/media/exec", NULL);
+ if ((command != NULL) && (strcmp (command, "") != 0)) {
+ execute (manager,
+ command,
+ FALSE,
+ mateconf_client_get_bool (manager->priv->conf_client,
+ "/desktop/mate/applications/media/needs_term", NULL));
+ }
+ g_free (command);
+}
+
+static void
+do_www_action (GsdMediaKeysManager *manager,
+ const char *url)
+{
+ char *string;
+
+ string = mateconf_client_get_string (manager->priv->conf_client,
+ "/desktop/mate/url-handlers/http/command",
+ NULL);
+
+ if ((string != NULL) && (strcmp (string, "") != 0)) {
+ gchar *cmd;
+
+ if (url == NULL) {
+ cmd = g_strdup_printf (string, "");
+ } else {
+ cmd = g_strdup_printf (string, url);
+ }
+
+ execute (manager,
+ cmd,
+ FALSE,
+ mateconf_client_get_bool (manager->priv->conf_client,
+ "/desktop/mate/url-handlers/http/needs_terminal", NULL));
+ g_free (cmd);
+ } else {
+ do_unknown_action (manager, url ? url : "");
+ }
+ g_free (string);
+}
+
+static void
+do_exit_action (GsdMediaKeysManager *manager)
+{
+ execute (manager, "mate-session-save --shutdown-dialog", FALSE, FALSE);
+}
+
+static void
+do_eject_action_cb (GDrive *drive,
+ GAsyncResult *res,
+ GsdMediaKeysManager *manager)
+{
+ g_drive_eject_with_operation_finish (drive, res, NULL);
+}
+
+#define NO_SCORE 0
+#define SCORE_CAN_EJECT 50
+#define SCORE_HAS_MEDIA 100
+static void
+do_eject_action (GsdMediaKeysManager *manager)
+{
+ GList *drives, *l;
+ GDrive *fav_drive;
+ guint score;
+
+ /* Find the best drive to eject */
+ fav_drive = NULL;
+ score = NO_SCORE;
+ drives = g_volume_monitor_get_connected_drives (manager->priv->volume_monitor);
+ for (l = drives; l != NULL; l = l->next) {
+ GDrive *drive = l->data;
+
+ if (g_drive_can_eject (drive) == FALSE)
+ continue;
+ if (g_drive_is_media_removable (drive) == FALSE)
+ continue;
+ if (score < SCORE_CAN_EJECT) {
+ fav_drive = drive;
+ score = SCORE_CAN_EJECT;
+ }
+ if (g_drive_has_media (drive) == FALSE)
+ continue;
+ if (score < SCORE_HAS_MEDIA) {
+ fav_drive = drive;
+ score = SCORE_HAS_MEDIA;
+ break;
+ }
+ }
+
+ /* Show the dialogue */
+ dialog_init (manager);
+ gsd_media_keys_window_set_action_custom (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
+ "media-eject",
+ FALSE);
+ dialog_show (manager);
+
+ /* Clean up the drive selection and exit if no suitable
+ * drives are found */
+ if (fav_drive != NULL)
+ fav_drive = g_object_ref (fav_drive);
+
+ g_list_foreach (drives, (GFunc) g_object_unref, NULL);
+ if (fav_drive == NULL)
+ return;
+
+ /* Eject! */
+ g_drive_eject_with_operation (fav_drive, G_MOUNT_UNMOUNT_FORCE,
+ NULL, NULL,
+ (GAsyncReadyCallback) do_eject_action_cb,
+ manager);
+ g_object_unref (fav_drive);
+}
+
+static void
+do_touchpad_action (GsdMediaKeysManager *manager)
+{
+ MateConfClient *client = manager->priv->conf_client;
+ gboolean state = mateconf_client_get_bool (client, TOUCHPAD_ENABLED_KEY, NULL);
+
+ dialog_init (manager);
+ gsd_media_keys_window_set_action_custom (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
+ (!state) ? "touchpad-enabled" : "touchpad-disabled",
+ FALSE);
+ dialog_show (manager);
+
+ mateconf_client_set_bool (client, TOUCHPAD_ENABLED_KEY, !state, NULL);
+}
+
+#ifdef HAVE_PULSE
+static void
+update_dialog (GsdMediaKeysManager *manager,
+ guint vol,
+ gboolean muted,
+ gboolean sound_changed)
+{
+ vol = (int) (100 * (double) vol / PA_VOLUME_NORM);
+ vol = CLAMP (vol, 0, 100);
+
+ dialog_init (manager);
+ gsd_media_keys_window_set_volume_muted (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
+ muted);
+ gsd_media_keys_window_set_volume_level (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog), vol);
+ gsd_media_keys_window_set_action (GSD_MEDIA_KEYS_WINDOW (manager->priv->dialog),
+ GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME);
+ dialog_show (manager);
+
+ if (sound_changed != FALSE && muted == FALSE)
+ ca_gtk_play_for_widget (manager->priv->dialog, 0,
+ CA_PROP_EVENT_ID, "audio-volume-change",
+ CA_PROP_EVENT_DESCRIPTION, "volume changed through key press",
+ CA_PROP_APPLICATION_ID, "org.mate.VolumeControl",
+ NULL);
+}
+
+static void
+do_sound_action (GsdMediaKeysManager *manager,
+ int type)
+{
+ gboolean muted;
+ guint vol, norm_vol_step;
+ int vol_step;
+ gboolean sound_changed;
+
+ if (manager->priv->stream == NULL)
+ return;
+
+ vol_step = mateconf_client_get_int (manager->priv->conf_client,
+ MATECONF_MISC_DIR "/volume_step",
+ NULL);
+
+ if (vol_step <= 0 || vol_step > 100)
+ vol_step = VOLUME_STEP;
+
+ norm_vol_step = PA_VOLUME_NORM * vol_step / 100;
+
+ /* FIXME: this is racy */
+ vol = gvc_mixer_stream_get_volume (manager->priv->stream);
+ muted = gvc_mixer_stream_get_is_muted (manager->priv->stream);
+ sound_changed = FALSE;
+
+ switch (type) {
+ case MUTE_KEY:
+ muted = !muted;
+ gvc_mixer_stream_change_is_muted (manager->priv->stream, muted);
+ sound_changed = TRUE;
+ break;
+ case VOLUME_DOWN_KEY:
+ if (!muted && (vol <= norm_vol_step)) {
+ muted = !muted;
+ vol = 0;
+ gvc_mixer_stream_change_is_muted (manager->priv->stream, muted);
+ if (gvc_mixer_stream_set_volume (manager->priv->stream, vol) != FALSE) {
+ gvc_mixer_stream_push_volume (manager->priv->stream);
+ sound_changed = TRUE;
+ }
+ } else if (!muted) {
+ vol = vol - norm_vol_step;
+ if (gvc_mixer_stream_set_volume (manager->priv->stream, vol) != FALSE) {
+ gvc_mixer_stream_push_volume (manager->priv->stream);
+ sound_changed = TRUE;
+ }
+ }
+ break;
+ case VOLUME_UP_KEY:
+ if (muted) {
+ muted = !muted;
+ if (vol == 0) {
+ vol = vol + norm_vol_step;
+ gvc_mixer_stream_change_is_muted (manager->priv->stream, muted);
+ if (gvc_mixer_stream_set_volume (manager->priv->stream, vol) != FALSE) {
+ gvc_mixer_stream_push_volume (manager->priv->stream);
+ sound_changed = TRUE;
+ }
+ } else {
+ gvc_mixer_stream_change_is_muted (manager->priv->stream, muted);
+ sound_changed = TRUE;
+ }
+ } else {
+ if (vol < MAX_VOLUME) {
+ if (vol + norm_vol_step >= MAX_VOLUME) {
+ vol = MAX_VOLUME;
+ } else {
+ vol = vol + norm_vol_step;
+ }
+ if (gvc_mixer_stream_set_volume (manager->priv->stream, vol) != FALSE) {
+ gvc_mixer_stream_push_volume (manager->priv->stream);
+ sound_changed = TRUE;
+ }
+ }
+ }
+ break;
+ }
+
+ update_dialog (manager, vol, muted, sound_changed);
+}
+
+static void
+update_default_sink (GsdMediaKeysManager *manager)
+{
+ GvcMixerStream *stream;
+
+ stream = gvc_mixer_control_get_default_sink (manager->priv->volume);
+ if (stream == manager->priv->stream)
+ return;
+
+ if (manager->priv->stream != NULL) {
+ g_object_unref (manager->priv->stream);
+ manager->priv->stream = NULL;
+ }
+
+ if (stream != NULL) {
+ manager->priv->stream = g_object_ref (stream);
+ } else {
+ g_warning ("Unable to get default sink");
+ }
+}
+
+static void
+on_control_ready (GvcMixerControl *control,
+ GsdMediaKeysManager *manager)
+{
+ update_default_sink (manager);
+}
+
+static void
+on_control_default_sink_changed (GvcMixerControl *control,
+ guint id,
+ GsdMediaKeysManager *manager)
+{
+ update_default_sink (manager);
+}
+
+#endif /* HAVE_PULSE */
+
+static gint
+find_by_application (gconstpointer a,
+ gconstpointer b)
+{
+ return strcmp (((MediaPlayer *)a)->application, b);
+}
+
+static gint
+find_by_time (gconstpointer a,
+ gconstpointer b)
+{
+ return ((MediaPlayer *)a)->time < ((MediaPlayer *)b)->time;
+}
+
+/*
+ * Register a new media player. Most applications will want to call
+ * this with time = GDK_CURRENT_TIME. This way, the last registered
+ * player will receive media events. In some cases, applications
+ * may want to register with a lower priority (usually 1), to grab
+ * events only nobody is interested.
+ */
+gboolean
+gsd_media_keys_manager_grab_media_player_keys (GsdMediaKeysManager *manager,
+ const char *application,
+ guint32 time,
+ GError **error)
+{
+ GList *iter;
+ MediaPlayer *media_player;
+
+ if (time == GDK_CURRENT_TIME) {
+ GTimeVal tv;
+
+ g_get_current_time (&tv);
+ time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+ }
+
+ iter = g_list_find_custom (manager->priv->media_players,
+ application,
+ find_by_application);
+
+ if (iter != NULL) {
+ if (((MediaPlayer *)iter->data)->time < time) {
+ g_free (((MediaPlayer *)iter->data)->application);
+ g_free (iter->data);
+ manager->priv->media_players = g_list_delete_link (manager->priv->media_players, iter);
+ } else {
+ return TRUE;
+ }
+ }
+
+ g_debug ("Registering %s at %u", application, time);
+ media_player = g_new0 (MediaPlayer, 1);
+ media_player->application = g_strdup (application);
+ media_player->time = time;
+
+ manager->priv->media_players = g_list_insert_sorted (manager->priv->media_players,
+ media_player,
+ find_by_time);
+
+ return TRUE;
+}
+
+gboolean
+gsd_media_keys_manager_release_media_player_keys (GsdMediaKeysManager *manager,
+ const char *application,
+ GError **error)
+{
+ GList *iter;
+
+ iter = g_list_find_custom (manager->priv->media_players,
+ application,
+ find_by_application);
+
+ if (iter != NULL) {
+ g_debug ("Deregistering %s", application);
+ g_free (((MediaPlayer *)iter->data)->application);
+ g_free (iter->data);
+ manager->priv->media_players = g_list_delete_link (manager->priv->media_players, iter);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gsd_media_player_key_pressed (GsdMediaKeysManager *manager,
+ const char *key)
+{
+ const char *application = NULL;
+ gboolean have_listeners;
+
+ have_listeners = (manager->priv->media_players != NULL);
+
+ if (have_listeners) {
+ application = ((MediaPlayer *)manager->priv->media_players->data)->application;
+ }
+
+ g_signal_emit (manager, signals[MEDIA_PLAYER_KEY_PRESSED], 0, application, key);
+
+ return !have_listeners;
+}
+
+static gboolean
+do_multimedia_player_action (GsdMediaKeysManager *manager,
+ const char *key)
+{
+ return gsd_media_player_key_pressed (manager, key);
+}
+
+static gboolean
+do_action (GsdMediaKeysManager *manager,
+ int type)
+{
+ char *cmd;
+ char *path;
+
+ switch (type) {
+ case TOUCHPAD_KEY:
+ do_touchpad_action (manager);
+ break;
+ case MUTE_KEY:
+ case VOLUME_DOWN_KEY:
+ case VOLUME_UP_KEY:
+#ifdef HAVE_PULSE
+ do_sound_action (manager, type);
+#endif /* HAVE_PULSE */
+ break;
+ case POWER_KEY:
+ do_exit_action (manager);
+ break;
+ case EJECT_KEY:
+ do_eject_action (manager);
+ break;
+ case HOME_KEY:
+ path = g_shell_quote (g_get_home_dir ());
+ cmd = g_strconcat ("caja --no-desktop ", path, NULL);
+ g_free (path);
+ execute (manager, cmd, FALSE, FALSE);
+ g_free (cmd);
+ break;
+ case SEARCH_KEY:
+ cmd = NULL;
+ if ((cmd = g_find_program_in_path ("beagle-search"))) {
+ execute (manager, "beagle-search", FALSE, FALSE);
+ } else if ((cmd = g_find_program_in_path ("tracker-search-tool"))) {
+ execute (manager, "tracker-search-tool", FALSE, FALSE);
+ } else {
+ execute (manager, "mate-search-tool", FALSE, FALSE);
+ }
+ g_free (cmd);
+ break;
+ case EMAIL_KEY:
+ do_mail_action (manager);
+ break;
+ case SCREENSAVER_KEY:
+ if ((cmd = g_find_program_in_path ("mate-screensaver-command"))) {
+ execute (manager, "mate-screensaver-command --lock", FALSE, FALSE);
+ } else {
+ execute (manager, "xscreensaver-command -lock", FALSE, FALSE);
+ }
+
+ g_free (cmd);
+ break;
+ case HELP_KEY:
+ do_help_action (manager);
+ break;
+ case WWW_KEY:
+ do_www_action (manager, NULL);
+ break;
+ case MEDIA_KEY:
+ do_media_action (manager);
+ break;
+ case CALCULATOR_KEY:
+ execute (manager, "gcalctool", FALSE, FALSE);
+ break;
+ case PLAY_KEY:
+ return do_multimedia_player_action (manager, "Play");
+ break;
+ case PAUSE_KEY:
+ return do_multimedia_player_action (manager, "Pause");
+ break;
+ case STOP_KEY:
+ return do_multimedia_player_action (manager, "Stop");
+ break;
+ case PREVIOUS_KEY:
+ return do_multimedia_player_action (manager, "Previous");
+ break;
+ case NEXT_KEY:
+ return do_multimedia_player_action (manager, "Next");
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ return FALSE;
+}
+
+static GdkScreen *
+acme_get_screen_from_event (GsdMediaKeysManager *manager,
+ XAnyEvent *xanyev)
+{
+ GdkWindow *window;
+ GdkScreen *screen;
+ GSList *l;
+
+ /* Look for which screen we're receiving events */
+ for (l = manager->priv->screens; l != NULL; l = l->next) {
+ screen = (GdkScreen *) l->data;
+ window = gdk_screen_get_root_window (screen);
+
+ if (GDK_WINDOW_XID (window) == xanyev->window) {
+ return screen;
+ }
+ }
+
+ return NULL;
+}
+
+static GdkFilterReturn
+acme_filter_events (GdkXEvent *xevent,
+ GdkEvent *event,
+ GsdMediaKeysManager *manager)
+{
+ XEvent *xev = (XEvent *) xevent;
+ XAnyEvent *xany = (XAnyEvent *) xevent;
+ int i;
+
+ /* verify we have a key event */
+ if (xev->type != KeyPress && xev->type != KeyRelease) {
+ return GDK_FILTER_CONTINUE;
+ }
+
+ for (i = 0; i < HANDLED_KEYS; i++) {
+ if (match_key (keys[i].key, xev)) {
+ switch (keys[i].key_type) {
+ case VOLUME_DOWN_KEY:
+ case VOLUME_UP_KEY:
+ /* auto-repeatable keys */
+ if (xev->type != KeyPress) {
+ return GDK_FILTER_CONTINUE;
+ }
+ break;
+ default:
+ if (xev->type != KeyRelease) {
+ return GDK_FILTER_CONTINUE;
+ }
+ }
+
+ manager->priv->current_screen = acme_get_screen_from_event (manager, xany);
+
+ if (do_action (manager, keys[i].key_type) == FALSE) {
+ return GDK_FILTER_REMOVE;
+ } else {
+ return GDK_FILTER_CONTINUE;
+ }
+ }
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static gboolean
+start_media_keys_idle_cb (GsdMediaKeysManager *manager)
+{
+ GSList *l;
+
+ g_debug ("Starting media_keys manager");
+ mate_settings_profile_start (NULL);
+ manager->priv->volume_monitor = g_volume_monitor_get ();
+ manager->priv->conf_client = mateconf_client_get_default ();
+
+ mateconf_client_add_dir (manager->priv->conf_client,
+ MATECONF_BINDING_DIR,
+ MATECONF_CLIENT_PRELOAD_ONELEVEL,
+ NULL);
+
+ init_screens (manager);
+ init_kbd (manager);
+
+ /* Start filtering the events */
+ for (l = manager->priv->screens; l != NULL; l = l->next) {
+ mate_settings_profile_start ("gdk_window_add_filter");
+
+ g_debug ("adding key filter for screen: %d",
+ gdk_screen_get_number (l->data));
+
+ gdk_window_add_filter (gdk_screen_get_root_window (l->data),
+ (GdkFilterFunc)acme_filter_events,
+ manager);
+ mate_settings_profile_end ("gdk_window_add_filter");
+ }
+
+ mate_settings_profile_end (NULL);
+
+ return FALSE;
+}
+
+gboolean
+gsd_media_keys_manager_start (GsdMediaKeysManager *manager,
+ GError **error)
+{
+ mate_settings_profile_start (NULL);
+
+#ifdef HAVE_PULSE
+ /* initialise Volume handler
+ *
+ * We do this one here to force checking gstreamer cache, etc.
+ * The rest (grabbing and setting the keys) can happen in an
+ * idle.
+ */
+ mate_settings_profile_start ("gvc_mixer_control_new");
+
+ manager->priv->volume = gvc_mixer_control_new ("MATE Volume Control Media Keys");
+
+ g_signal_connect (manager->priv->volume,
+ "ready",
+ G_CALLBACK (on_control_ready),
+ manager);
+ g_signal_connect (manager->priv->volume,
+ "default-sink-changed",
+ G_CALLBACK (on_control_default_sink_changed),
+ manager);
+
+ gvc_mixer_control_open (manager->priv->volume);
+
+ mate_settings_profile_end ("gvc_mixer_control_new");
+#endif /* HAVE_PULSE */
+ g_idle_add ((GSourceFunc) start_media_keys_idle_cb, manager);
+
+ mate_settings_profile_end (NULL);
+
+ return TRUE;
+}
+
+void
+gsd_media_keys_manager_stop (GsdMediaKeysManager *manager)
+{
+ GsdMediaKeysManagerPrivate *priv = manager->priv;
+ GSList *ls;
+ GList *l;
+ int i;
+ gboolean need_flush;
+
+ g_debug ("Stopping media_keys manager");
+
+ for (ls = priv->screens; ls != NULL; ls = ls->next) {
+ gdk_window_remove_filter (gdk_screen_get_root_window (ls->data),
+ (GdkFilterFunc) acme_filter_events,
+ manager);
+ }
+
+ if (priv->conf_client) {
+ mateconf_client_remove_dir (priv->conf_client,
+ MATECONF_BINDING_DIR,
+ NULL);
+
+ for (i = 0; i < HANDLED_KEYS; ++i) {
+ if (priv->notify[i] != 0) {
+ mateconf_client_notify_remove (priv->conf_client, priv->notify[i]);
+ priv->notify[i] = 0;
+ }
+ }
+
+ g_object_unref (priv->conf_client);
+ priv->conf_client = NULL;
+ }
+
+ if (priv->volume_monitor != NULL) {
+ g_object_unref (priv->volume_monitor);
+ priv->volume_monitor = NULL;
+ }
+
+ if (priv->connection != NULL) {
+ dbus_g_connection_unref (priv->connection);
+ priv->connection = NULL;
+ }
+
+ need_flush = FALSE;
+ gdk_error_trap_push ();
+
+ for (i = 0; i < HANDLED_KEYS; ++i) {
+ if (keys[i].key) {
+ need_flush = TRUE;
+ grab_key_unsafe (keys[i].key, FALSE, priv->screens);
+
+ g_free (keys[i].key->keycodes);
+ g_free (keys[i].key);
+ keys[i].key = NULL;
+ }
+ }
+
+ if (need_flush)
+ gdk_flush ();
+ gdk_error_trap_pop ();
+
+ g_slist_free (priv->screens);
+ priv->screens = NULL;
+
+#ifdef HAVE_PULSE
+ if (priv->stream) {
+ g_object_unref (priv->stream);
+ priv->stream = NULL;
+ }
+
+ if (priv->volume) {
+ g_object_unref (priv->volume);
+ priv->volume = NULL;
+ }
+#endif /* HAVE_PULSE */
+
+ if (priv->dialog != NULL) {
+ gtk_widget_destroy (priv->dialog);
+ priv->dialog = NULL;
+ }
+
+ for (l = priv->media_players; l; l = l->next) {
+ MediaPlayer *mp = l->data;
+ g_free (mp->application);
+ g_free (mp);
+ }
+ g_list_free (priv->media_players);
+ priv->media_players = NULL;
+}
+
+static void
+gsd_media_keys_manager_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GsdMediaKeysManager *self;
+
+ self = GSD_MEDIA_KEYS_MANAGER (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gsd_media_keys_manager_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GsdMediaKeysManager *self;
+
+ self = GSD_MEDIA_KEYS_MANAGER (object);
+
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GObject *
+gsd_media_keys_manager_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GsdMediaKeysManager *media_keys_manager;
+ GsdMediaKeysManagerClass *klass;
+
+ klass = GSD_MEDIA_KEYS_MANAGER_CLASS (g_type_class_peek (GSD_TYPE_MEDIA_KEYS_MANAGER));
+
+ media_keys_manager = GSD_MEDIA_KEYS_MANAGER (G_OBJECT_CLASS (gsd_media_keys_manager_parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties));
+
+ return G_OBJECT (media_keys_manager);
+}
+
+static void
+gsd_media_keys_manager_dispose (GObject *object)
+{
+ GsdMediaKeysManager *media_keys_manager;
+
+ media_keys_manager = GSD_MEDIA_KEYS_MANAGER (object);
+
+ G_OBJECT_CLASS (gsd_media_keys_manager_parent_class)->dispose (object);
+}
+
+static void
+gsd_media_keys_manager_class_init (GsdMediaKeysManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = gsd_media_keys_manager_get_property;
+ object_class->set_property = gsd_media_keys_manager_set_property;
+ object_class->constructor = gsd_media_keys_manager_constructor;
+ object_class->dispose = gsd_media_keys_manager_dispose;
+ object_class->finalize = gsd_media_keys_manager_finalize;
+
+ signals[MEDIA_PLAYER_KEY_PRESSED] =
+ g_signal_new ("media-player-key-pressed",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsdMediaKeysManagerClass, media_player_key_pressed),
+ NULL,
+ NULL,
+ gsd_marshal_VOID__STRING_STRING,
+ G_TYPE_NONE,
+ 2,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+
+ dbus_g_object_type_install_info (GSD_TYPE_MEDIA_KEYS_MANAGER, &dbus_glib_gsd_media_keys_manager_object_info);
+
+ g_type_class_add_private (klass, sizeof (GsdMediaKeysManagerPrivate));
+}
+
+static void
+gsd_media_keys_manager_init (GsdMediaKeysManager *manager)
+{
+ manager->priv = GSD_MEDIA_KEYS_MANAGER_GET_PRIVATE (manager);
+
+}
+
+static void
+gsd_media_keys_manager_finalize (GObject *object)
+{
+ GsdMediaKeysManager *media_keys_manager;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GSD_IS_MEDIA_KEYS_MANAGER (object));
+
+ media_keys_manager = GSD_MEDIA_KEYS_MANAGER (object);
+
+ g_return_if_fail (media_keys_manager->priv != NULL);
+
+ G_OBJECT_CLASS (gsd_media_keys_manager_parent_class)->finalize (object);
+}
+
+static gboolean
+register_manager (GsdMediaKeysManager *manager)
+{
+ GError *error = NULL;
+
+ manager->priv->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (manager->priv->connection == NULL) {
+ if (error != NULL) {
+ g_error ("Error getting session bus: %s", error->message);
+ g_error_free (error);
+ }
+ return FALSE;
+ }
+
+ dbus_g_connection_register_g_object (manager->priv->connection, GSD_MEDIA_KEYS_DBUS_PATH, G_OBJECT (manager));
+
+ return TRUE;
+}
+
+GsdMediaKeysManager *
+gsd_media_keys_manager_new (void)
+{
+ if (manager_object != NULL) {
+ g_object_ref (manager_object);
+ } else {
+ gboolean res;
+
+ manager_object = g_object_new (GSD_TYPE_MEDIA_KEYS_MANAGER, NULL);
+ g_object_add_weak_pointer (manager_object,
+ (gpointer *) &manager_object);
+ res = register_manager (manager_object);
+ if (! res) {
+ g_object_unref (manager_object);
+ return NULL;
+ }
+ }
+
+ return GSD_MEDIA_KEYS_MANAGER (manager_object);
+}
diff --git a/plugins/media-keys/gsd-media-keys-manager.h b/plugins/media-keys/gsd-media-keys-manager.h
new file mode 100644
index 0000000..19dafd5
--- /dev/null
+++ b/plugins/media-keys/gsd-media-keys-manager.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <[email protected]>
+ *
+ * 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.
+ *
+ */
+
+#ifndef __GSD_MEDIA_KEYS_MANAGER_H
+#define __GSD_MEDIA_KEYS_MANAGER_H
+
+#include <glib-object.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GSD_TYPE_MEDIA_KEYS_MANAGER (gsd_media_keys_manager_get_type ())
+#define GSD_MEDIA_KEYS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_MEDIA_KEYS_MANAGER, GsdMediaKeysManager))
+#define GSD_MEDIA_KEYS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_MEDIA_KEYS_MANAGER, GsdMediaKeysManagerClass))
+#define GSD_IS_MEDIA_KEYS_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_MEDIA_KEYS_MANAGER))
+#define GSD_IS_MEDIA_KEYS_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_MEDIA_KEYS_MANAGER))
+#define GSD_MEDIA_KEYS_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_MEDIA_KEYS_MANAGER, GsdMediaKeysManagerClass))
+
+typedef struct GsdMediaKeysManagerPrivate GsdMediaKeysManagerPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GsdMediaKeysManagerPrivate *priv;
+} GsdMediaKeysManager;
+
+typedef struct
+{
+ GObjectClass parent_class;
+ void (* media_player_key_pressed) (GsdMediaKeysManager *manager,
+ const char *application,
+ const char *key);
+} GsdMediaKeysManagerClass;
+
+GType gsd_media_keys_manager_get_type (void);
+
+GsdMediaKeysManager * gsd_media_keys_manager_new (void);
+gboolean gsd_media_keys_manager_start (GsdMediaKeysManager *manager,
+ GError **error);
+void gsd_media_keys_manager_stop (GsdMediaKeysManager *manager);
+
+gboolean gsd_media_keys_manager_grab_media_player_keys (GsdMediaKeysManager *manager,
+ const char *application,
+ guint32 time,
+ GError **error);
+gboolean gsd_media_keys_manager_release_media_player_keys (GsdMediaKeysManager *manager,
+ const char *application,
+ GError **error);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSD_MEDIA_KEYS_MANAGER_H */
diff --git a/plugins/media-keys/gsd-media-keys-manager.xml b/plugins/media-keys/gsd-media-keys-manager.xml
new file mode 100644
index 0000000..12cd03a
--- /dev/null
+++ b/plugins/media-keys/gsd-media-keys-manager.xml
@@ -0,0 +1,14 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.mate.SettingsDaemon.MediaKeys">
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="gsd_media_keys_manager"/>
+ <method name="GrabMediaPlayerKeys">
+ <arg name="application" direction="in" type="s"/>
+ <arg name="time" direction="in" type="u"/>
+ </method>
+ <method name="ReleaseMediaPlayerKeys">
+ <arg name="application" direction="in" type="s"/>
+ </method>
+ <signal name="MediaPlayerKeyPressed"/>
+ </interface>
+</node>
diff --git a/plugins/media-keys/gsd-media-keys-plugin.c b/plugins/media-keys/gsd-media-keys-plugin.c
new file mode 100644
index 0000000..319a42a
--- /dev/null
+++ b/plugins/media-keys/gsd-media-keys-plugin.c
@@ -0,0 +1,104 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <[email protected]>
+ *
+ * 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, 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 "config.h"
+
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+
+#include "mate-settings-plugin.h"
+#include "gsd-media-keys-plugin.h"
+#include "gsd-media-keys-manager.h"
+
+struct GsdMediaKeysPluginPrivate {
+ GsdMediaKeysManager *manager;
+};
+
+#define GSD_MEDIA_KEYS_PLUGIN_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), GSD_TYPE_MEDIA_KEYS_PLUGIN, GsdMediaKeysPluginPrivate))
+
+MATE_SETTINGS_PLUGIN_REGISTER (GsdMediaKeysPlugin, gsd_media_keys_plugin)
+
+static void
+gsd_media_keys_plugin_init (GsdMediaKeysPlugin *plugin)
+{
+ plugin->priv = GSD_MEDIA_KEYS_PLUGIN_GET_PRIVATE (plugin);
+
+ g_debug ("GsdMediaKeysPlugin initializing");
+
+ plugin->priv->manager = gsd_media_keys_manager_new ();
+}
+
+static void
+gsd_media_keys_plugin_finalize (GObject *object)
+{
+ GsdMediaKeysPlugin *plugin;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GSD_IS_MEDIA_KEYS_PLUGIN (object));
+
+ g_debug ("GsdMediaKeysPlugin finalizing");
+
+ plugin = GSD_MEDIA_KEYS_PLUGIN (object);
+
+ g_return_if_fail (plugin->priv != NULL);
+
+ if (plugin->priv->manager != NULL) {
+ g_object_unref (plugin->priv->manager);
+ }
+
+ G_OBJECT_CLASS (gsd_media_keys_plugin_parent_class)->finalize (object);
+}
+
+static void
+impl_activate (MateSettingsPlugin *plugin)
+{
+ gboolean res;
+ GError *error;
+
+ g_debug ("Activating media_keys plugin");
+
+ error = NULL;
+ res = gsd_media_keys_manager_start (GSD_MEDIA_KEYS_PLUGIN (plugin)->priv->manager, &error);
+ if (! res) {
+ g_warning ("Unable to start media_keys manager: %s", error->message);
+ g_error_free (error);
+ }
+}
+
+static void
+impl_deactivate (MateSettingsPlugin *plugin)
+{
+ g_debug ("Deactivating media_keys plugin");
+ gsd_media_keys_manager_stop (GSD_MEDIA_KEYS_PLUGIN (plugin)->priv->manager);
+}
+
+static void
+gsd_media_keys_plugin_class_init (GsdMediaKeysPluginClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ MateSettingsPluginClass *plugin_class = MATE_SETTINGS_PLUGIN_CLASS (klass);
+
+ object_class->finalize = gsd_media_keys_plugin_finalize;
+
+ plugin_class->activate = impl_activate;
+ plugin_class->deactivate = impl_deactivate;
+
+ g_type_class_add_private (klass, sizeof (GsdMediaKeysPluginPrivate));
+}
diff --git a/plugins/media-keys/gsd-media-keys-plugin.h b/plugins/media-keys/gsd-media-keys-plugin.h
new file mode 100644
index 0000000..fa092b5
--- /dev/null
+++ b/plugins/media-keys/gsd-media-keys-plugin.h
@@ -0,0 +1,63 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <[email protected]>
+ *
+ * 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, 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.
+ *
+ */
+
+#ifndef __GSD_MEDIA_KEYS_PLUGIN_H__
+#define __GSD_MEDIA_KEYS_PLUGIN_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gmodule.h>
+
+#include "mate-settings-plugin.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GSD_TYPE_MEDIA_KEYS_PLUGIN (gsd_media_keys_plugin_get_type ())
+#define GSD_MEDIA_KEYS_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GSD_TYPE_MEDIA_KEYS_PLUGIN, GsdMediaKeysPlugin))
+#define GSD_MEDIA_KEYS_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GSD_TYPE_MEDIA_KEYS_PLUGIN, GsdMediaKeysPluginClass))
+#define GSD_IS_MEDIA_KEYS_PLUGIN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GSD_TYPE_MEDIA_KEYS_PLUGIN))
+#define GSD_IS_MEDIA_KEYS_PLUGIN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GSD_TYPE_MEDIA_KEYS_PLUGIN))
+#define GSD_MEDIA_KEYS_PLUGIN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GSD_TYPE_MEDIA_KEYS_PLUGIN, GsdMediaKeysPluginClass))
+
+typedef struct GsdMediaKeysPluginPrivate GsdMediaKeysPluginPrivate;
+
+typedef struct
+{
+ MateSettingsPlugin parent;
+ GsdMediaKeysPluginPrivate *priv;
+} GsdMediaKeysPlugin;
+
+typedef struct
+{
+ MateSettingsPluginClass parent_class;
+} GsdMediaKeysPluginClass;
+
+GType gsd_media_keys_plugin_get_type (void) G_GNUC_CONST;
+
+/* All the plugins must implement this function */
+G_MODULE_EXPORT GType register_mate_settings_plugin (GTypeModule *module);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __GSD_MEDIA_KEYS_PLUGIN_H__ */
diff --git a/plugins/media-keys/gsd-media-keys-window.c b/plugins/media-keys/gsd-media-keys-window.c
new file mode 100644
index 0000000..2547068
--- /dev/null
+++ b/plugins/media-keys/gsd-media-keys-window.c
@@ -0,0 +1,714 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2006-2007 William Jon McCann <[email protected]>
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2, 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 Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser 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 "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "gsd-media-keys-window.h"
+
+#define GSD_MEDIA_KEYS_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GSD_TYPE_MEDIA_KEYS_WINDOW, GsdMediaKeysWindowPrivate))
+
+struct GsdMediaKeysWindowPrivate
+{
+ GsdMediaKeysWindowAction action;
+ char *icon_name;
+ gboolean show_level;
+
+ guint volume_muted : 1;
+ int volume_level;
+
+ GtkImage *image;
+ GtkWidget *progress;
+};
+
+G_DEFINE_TYPE (GsdMediaKeysWindow, gsd_media_keys_window, GSD_TYPE_OSD_WINDOW)
+
+static void
+volume_controls_set_visible (GsdMediaKeysWindow *window,
+ gboolean visible)
+{
+ if (window->priv->progress == NULL)
+ return;
+
+ if (visible) {
+ gtk_widget_show (window->priv->progress);
+ } else {
+ gtk_widget_hide (window->priv->progress);
+ }
+}
+
+static void
+window_set_icon_name (GsdMediaKeysWindow *window,
+ const char *name)
+{
+ if (window->priv->image == NULL)
+ return;
+
+ gtk_image_set_from_icon_name (window->priv->image,
+ name, GTK_ICON_SIZE_DIALOG);
+}
+
+static void
+action_changed (GsdMediaKeysWindow *window)
+{
+ if (!gsd_osd_window_is_composited (GSD_OSD_WINDOW (window))) {
+ switch (window->priv->action) {
+ case GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME:
+ volume_controls_set_visible (window, TRUE);
+
+ if (window->priv->volume_muted) {
+ window_set_icon_name (window, "audio-volume-muted");
+ } else {
+ window_set_icon_name (window, "audio-volume-high");
+ }
+
+ break;
+ case GSD_MEDIA_KEYS_WINDOW_ACTION_CUSTOM:
+ volume_controls_set_visible (window, window->priv->show_level);
+ window_set_icon_name (window, window->priv->icon_name);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+
+ gsd_osd_window_update_and_hide (GSD_OSD_WINDOW (window));
+}
+
+static void
+volume_level_changed (GsdMediaKeysWindow *window)
+{
+ gsd_osd_window_update_and_hide (GSD_OSD_WINDOW (window));
+
+ if (!gsd_osd_window_is_composited (GSD_OSD_WINDOW (window)) && window->priv->progress != NULL) {
+ double fraction;
+
+ fraction = (double) window->priv->volume_level / 100.0;
+
+ gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (window->priv->progress),
+ fraction);
+ }
+}
+
+static void
+volume_muted_changed (GsdMediaKeysWindow *window)
+{
+ gsd_osd_window_update_and_hide (GSD_OSD_WINDOW (window));
+
+ if (!gsd_osd_window_is_composited (GSD_OSD_WINDOW (window))) {
+ if (window->priv->volume_muted) {
+ window_set_icon_name (window, "audio-volume-muted");
+ } else {
+ window_set_icon_name (window, "audio-volume-high");
+ }
+ }
+}
+
+void
+gsd_media_keys_window_set_action (GsdMediaKeysWindow *window,
+ GsdMediaKeysWindowAction action)
+{
+ g_return_if_fail (GSD_IS_MEDIA_KEYS_WINDOW (window));
+ g_return_if_fail (action == GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME);
+
+ if (window->priv->action != action) {
+ window->priv->action = action;
+ action_changed (window);
+ } else {
+ gsd_osd_window_update_and_hide (GSD_OSD_WINDOW (window));
+ }
+}
+
+void
+gsd_media_keys_window_set_action_custom (GsdMediaKeysWindow *window,
+ const char *icon_name,
+ gboolean show_level)
+{
+ g_return_if_fail (GSD_IS_MEDIA_KEYS_WINDOW (window));
+ g_return_if_fail (icon_name != NULL);
+
+ if (window->priv->action != GSD_MEDIA_KEYS_WINDOW_ACTION_CUSTOM ||
+ g_strcmp0 (window->priv->icon_name, icon_name) != 0 ||
+ window->priv->show_level != show_level) {
+ window->priv->action = GSD_MEDIA_KEYS_WINDOW_ACTION_CUSTOM;
+ g_free (window->priv->icon_name);
+ window->priv->icon_name = g_strdup (icon_name);
+ window->priv->show_level = show_level;
+ action_changed (window);
+ } else {
+ gsd_osd_window_update_and_hide (GSD_OSD_WINDOW (window));
+ }
+}
+
+void
+gsd_media_keys_window_set_volume_muted (GsdMediaKeysWindow *window,
+ gboolean muted)
+{
+ g_return_if_fail (GSD_IS_MEDIA_KEYS_WINDOW (window));
+
+ if (window->priv->volume_muted != muted) {
+ window->priv->volume_muted = muted;
+ volume_muted_changed (window);
+ }
+}
+
+void
+gsd_media_keys_window_set_volume_level (GsdMediaKeysWindow *window,
+ int level)
+{
+ g_return_if_fail (GSD_IS_MEDIA_KEYS_WINDOW (window));
+
+ if (window->priv->volume_level != level) {
+ window->priv->volume_level = level;
+ volume_level_changed (window);
+ }
+}
+
+static GdkPixbuf *
+load_pixbuf (GsdMediaKeysWindow *window,
+ const char *name,
+ int icon_size)
+{
+ GtkIconTheme *theme;
+ GdkPixbuf *pixbuf;
+
+ if (window != NULL && gtk_widget_has_screen (GTK_WIDGET (window))) {
+ theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (window)));
+ } else {
+ theme = gtk_icon_theme_get_default ();
+ }
+
+ pixbuf = gtk_icon_theme_load_icon (theme,
+ name,
+ icon_size,
+ GTK_ICON_LOOKUP_FORCE_SIZE,
+ NULL);
+
+ return pixbuf;
+}
+
+static void
+draw_eject (cairo_t *cr,
+ double _x0,
+ double _y0,
+ double width,
+ double height)
+{
+ int box_height;
+ int tri_height;
+ int separation;
+
+ box_height = height * 0.2;
+ separation = box_height / 3;
+ tri_height = height - box_height - separation;
+
+ cairo_rectangle (cr, _x0, _y0 + height - box_height, width, box_height);
+
+ cairo_move_to (cr, _x0, _y0 + tri_height);
+ cairo_rel_line_to (cr, width, 0);
+ cairo_rel_line_to (cr, -width / 2, -tri_height);
+ cairo_rel_line_to (cr, -width / 2, tri_height);
+ cairo_close_path (cr);
+ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, GSD_OSD_WINDOW_FG_ALPHA);
+ cairo_fill_preserve (cr);
+
+ cairo_set_source_rgba (cr, 0.6, 0.6, 0.6, GSD_OSD_WINDOW_FG_ALPHA / 2);
+ cairo_set_line_width (cr, 2);
+ cairo_stroke (cr);
+}
+
+static void
+draw_waves (cairo_t *cr,
+ double cx,
+ double cy,
+ double max_radius,
+ int volume_level)
+{
+ const int n_waves = 3;
+ int last_wave;
+ int i;
+
+ last_wave = n_waves * volume_level / 100;
+
+ for (i = 0; i < n_waves; i++) {
+ double angle1;
+ double angle2;
+ double radius;
+ double alpha;
+
+ angle1 = -M_PI / 4;
+ angle2 = M_PI / 4;
+
+ if (i < last_wave)
+ alpha = 1.0;
+ else if (i > last_wave)
+ alpha = 0.1;
+ else alpha = 0.1 + 0.9 * (n_waves * volume_level % 100) / 100.0;
+
+ radius = (i + 1) * (max_radius / n_waves);
+ cairo_arc (cr, cx, cy, radius, angle1, angle2);
+ cairo_set_source_rgba (cr, 0.6, 0.6, 0.6, alpha / 2);
+ cairo_set_line_width (cr, 14);
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+ cairo_stroke_preserve (cr);
+
+ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, alpha);
+ cairo_set_line_width (cr, 10);
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+ cairo_stroke (cr);
+ }
+}
+
+static void
+draw_cross (cairo_t *cr,
+ double cx,
+ double cy,
+ double size)
+{
+ cairo_move_to (cr, cx, cy - size/2.0);
+ cairo_rel_line_to (cr, size, size);
+
+ cairo_move_to (cr, cx, cy + size/2.0);
+ cairo_rel_line_to (cr, size, -size);
+
+ cairo_set_source_rgba (cr, 0.6, 0.6, 0.6, GSD_OSD_WINDOW_FG_ALPHA / 2);
+ cairo_set_line_width (cr, 14);
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+ cairo_stroke_preserve (cr);
+
+ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, GSD_OSD_WINDOW_FG_ALPHA);
+ cairo_set_line_width (cr, 10);
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+ cairo_stroke (cr);
+}
+
+static void
+draw_speaker (cairo_t *cr,
+ double cx,
+ double cy,
+ double width,
+ double height)
+{
+ double box_width;
+ double box_height;
+ double _x0;
+ double _y0;
+
+ box_width = width / 3;
+ box_height = height / 3;
+
+ _x0 = cx - (width / 2) + box_width;
+ _y0 = cy - box_height / 2;
+
+ cairo_move_to (cr, _x0, _y0);
+ cairo_rel_line_to (cr, - box_width, 0);
+ cairo_rel_line_to (cr, 0, box_height);
+ cairo_rel_line_to (cr, box_width, 0);
+
+ cairo_line_to (cr, cx + box_width, cy + height / 2);
+ cairo_rel_line_to (cr, 0, -height);
+ cairo_line_to (cr, _x0, _y0);
+ cairo_close_path (cr);
+
+ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, GSD_OSD_WINDOW_FG_ALPHA);
+ cairo_fill_preserve (cr);
+
+ cairo_set_source_rgba (cr, 0.6, 0.6, 0.6, GSD_OSD_WINDOW_FG_ALPHA / 2);
+ cairo_set_line_width (cr, 2);
+ cairo_stroke (cr);
+}
+
+static gboolean
+render_speaker (GsdMediaKeysWindow *window,
+ cairo_t *cr,
+ double _x0,
+ double _y0,
+ double width,
+ double height)
+{
+ GdkPixbuf *pixbuf;
+ int icon_size;
+ int n;
+ static const char *icon_names[] = {
+ "audio-volume-muted",
+ "audio-volume-low",
+ "audio-volume-medium",
+ "audio-volume-high",
+ NULL
+ };
+
+ if (window->priv->volume_muted) {
+ n = 0;
+ } else {
+ /* select image */
+ n = 3 * window->priv->volume_level / 100 + 1;
+ if (n < 1) {
+ n = 1;
+ } else if (n > 3) {
+ n = 3;
+ }
+ }
+
+ icon_size = (int)width;
+
+ pixbuf = load_pixbuf (window, icon_names[n], icon_size);
+
+ if (pixbuf == NULL) {
+ return FALSE;
+ }
+
+ gdk_cairo_set_source_pixbuf (cr, pixbuf, _x0, _y0);
+ cairo_paint_with_alpha (cr, GSD_OSD_WINDOW_FG_ALPHA);
+
+ g_object_unref (pixbuf);
+
+ return TRUE;
+}
+
+static void
+draw_volume_boxes (GsdMediaKeysWindow *window,
+ cairo_t *cr,
+ double percentage,
+ double _x0,
+ double _y0,
+ double width,
+ double height)
+{
+ gdouble x1;
+ GdkColor color;
+ double r, g, b;
+ GtkStyle *style;
+
+ _x0 += 0.5;
+ _y0 += 0.5;
+ height = round (height) - 1;
+ width = round (width) - 1;
+ x1 = round ((width - 1) * percentage);
+ style = gtk_widget_get_style (GTK_WIDGET (window));
+
+ /* bar background */
+ gsd_osd_window_color_reverse (&style->dark[GTK_STATE_NORMAL], &color);
+ r = (float)color.red / 65535.0;
+ g = (float)color.green / 65535.0;
+ b = (float)color.blue / 65535.0;
+ gsd_osd_window_draw_rounded_rectangle (cr, 1.0, _x0, _y0, height / 6, width, height);
+ cairo_set_source_rgba (cr, r, g, b, GSD_OSD_WINDOW_FG_ALPHA / 2);
+ cairo_fill_preserve (cr);
+
+ /* bar border */
+ gsd_osd_window_color_reverse (&style->light[GTK_STATE_NORMAL], &color);
+ r = (float)color.red / 65535.0;
+ g = (float)color.green / 65535.0;
+ b = (float)color.blue / 65535.0;
+ cairo_set_source_rgba (cr, r, g, b, GSD_OSD_WINDOW_FG_ALPHA / 2);
+ cairo_set_line_width (cr, 1);
+ cairo_stroke (cr);
+
+ /* bar progress */
+ if (percentage < 0.01)
+ return;
+ color = style->bg[GTK_STATE_NORMAL];
+ r = (float)color.red / 65535.0;
+ g = (float)color.green / 65535.0;
+ b = (float)color.blue / 65535.0;
+ gsd_osd_window_draw_rounded_rectangle (cr, 1.0, _x0 + 0.5, _y0 + 0.5, height / 6 - 0.5, x1, height - 1);
+ cairo_set_source_rgba (cr, r, g, b, GSD_OSD_WINDOW_FG_ALPHA);
+ cairo_fill (cr);
+}
+
+static void
+draw_action_volume (GsdMediaKeysWindow *window,
+ cairo_t *cr)
+{
+ int window_width;
+ int window_height;
+ double icon_box_width;
+ double icon_box_height;
+ double icon_box_x0;
+ double icon_box_y0;
+ double volume_box_x0;
+ double volume_box_y0;
+ double volume_box_width;
+ double volume_box_height;
+ gboolean res;
+
+ gtk_window_get_size (GTK_WINDOW (window), &window_width, &window_height);
+
+ icon_box_width = round (window_width * 0.65);
+ icon_box_height = round (window_height * 0.65);
+ volume_box_width = icon_box_width;
+ volume_box_height = round (window_height * 0.05);
+
+ icon_box_x0 = (window_width - icon_box_width) / 2;
+ icon_box_y0 = (window_height - icon_box_height - volume_box_height) / 2;
+ volume_box_x0 = round (icon_box_x0);
+ volume_box_y0 = round (icon_box_height + icon_box_y0);
+
+#if 0
+ g_message ("icon box: w=%f h=%f _x0=%f _y0=%f",
+ icon_box_width,
+ icon_box_height,
+ icon_box_x0,
+ icon_box_y0);
+ g_message ("volume box: w=%f h=%f _x0=%f _y0=%f",
+ volume_box_width,
+ volume_box_height,
+ volume_box_x0,
+ volume_box_y0);
+#endif
+
+ res = render_speaker (window,
+ cr,
+ icon_box_x0, icon_box_y0,
+ icon_box_width, icon_box_height);
+ if (! res) {
+ double speaker_width;
+ double speaker_height;
+ double speaker_cx;
+ double speaker_cy;
+
+ speaker_width = icon_box_width * 0.5;
+ speaker_height = icon_box_height * 0.75;
+ speaker_cx = icon_box_x0 + speaker_width / 2;
+ speaker_cy = icon_box_y0 + speaker_height / 2;
+
+#if 0
+ g_message ("speaker box: w=%f h=%f cx=%f cy=%f",
+ speaker_width,
+ speaker_height,
+ speaker_cx,
+ speaker_cy);
+#endif
+
+ /* draw speaker symbol */
+ draw_speaker (cr, speaker_cx, speaker_cy, speaker_width, speaker_height);
+
+ if (! window->priv->volume_muted) {
+ /* draw sound waves */
+ double wave_x0;
+ double wave_y0;
+ double wave_radius;
+
+ wave_x0 = window_width / 2;
+ wave_y0 = speaker_cy;
+ wave_radius = icon_box_width / 2;
+
+ draw_waves (cr, wave_x0, wave_y0, wave_radius, window->priv->volume_level);
+ } else {
+ /* draw 'mute' cross */
+ double cross_x0;
+ double cross_y0;
+ double cross_size;
+
+ cross_size = speaker_width * 3 / 4;
+ cross_x0 = icon_box_x0 + icon_box_width - cross_size;
+ cross_y0 = speaker_cy;
+
+ draw_cross (cr, cross_x0, cross_y0, cross_size);
+ }
+ }
+
+ /* draw volume meter */
+ draw_volume_boxes (window,
+ cr,
+ (double)window->priv->volume_level / 100.0,
+ volume_box_x0,
+ volume_box_y0,
+ volume_box_width,
+ volume_box_height);
+}
+
+static gboolean
+render_custom (GsdMediaKeysWindow *window,
+ cairo_t *cr,
+ double _x0,
+ double _y0,
+ double width,
+ double height)
+{
+ GdkPixbuf *pixbuf;
+ int icon_size;
+
+ icon_size = (int)width;
+
+ pixbuf = load_pixbuf (window, window->priv->icon_name, icon_size);
+
+ if (pixbuf == NULL) {
+ char *name;
+ if (gtk_widget_get_direction (GTK_WIDGET (window)) == GTK_TEXT_DIR_RTL)
+ name = g_strdup_printf ("%s-rtl", window->priv->icon_name);
+ else
+ name = g_strdup_printf ("%s-ltr", window->priv->icon_name);
+ pixbuf = load_pixbuf (window, name, icon_size);
+ g_free (name);
+ if (pixbuf == NULL)
+ return FALSE;
+ }
+
+ gdk_cairo_set_source_pixbuf (cr, pixbuf, _x0, _y0);
+ cairo_paint_with_alpha (cr, GSD_OSD_WINDOW_FG_ALPHA);
+
+ g_object_unref (pixbuf);
+
+ return TRUE;
+}
+
+static void
+draw_action_custom (GsdMediaKeysWindow *window,
+ cairo_t *cr)
+{
+ int window_width;
+ int window_height;
+ double icon_box_width;
+ double icon_box_height;
+ double icon_box_x0;
+ double icon_box_y0;
+ double bright_box_x0;
+ double bright_box_y0;
+ double bright_box_width;
+ double bright_box_height;
+ gboolean res;
+
+ gtk_window_get_size (GTK_WINDOW (window), &window_width, &window_height);
+
+ icon_box_width = round (window_width * 0.65);
+ icon_box_height = round (window_height * 0.65);
+ bright_box_width = round (icon_box_width);
+ bright_box_height = round (window_height * 0.05);
+
+ icon_box_x0 = (window_width - icon_box_width) / 2;
+ icon_box_y0 = (window_height - icon_box_height - bright_box_height) / 2;
+ bright_box_x0 = round (icon_box_x0);
+ bright_box_y0 = round (icon_box_height + icon_box_y0);
+
+#if 0
+ g_message ("icon box: w=%f h=%f _x0=%f _y0=%f",
+ icon_box_width,
+ icon_box_height,
+ icon_box_x0,
+ icon_box_y0);
+ g_message ("brightness box: w=%f h=%f _x0=%f _y0=%f",
+ bright_box_width,
+ bright_box_height,
+ bright_box_x0,
+ bright_box_y0);
+#endif
+
+ res = render_custom (window,
+ cr,
+ icon_box_x0, icon_box_y0,
+ icon_box_width, icon_box_height);
+ if (! res && g_strcmp0 (window->priv->icon_name, "media-eject") == 0) {
+ /* draw eject symbol */
+ draw_eject (cr,
+ icon_box_x0, icon_box_y0,
+ icon_box_width, icon_box_height);
+ }
+
+ if (window->priv->show_level != FALSE) {
+ /* draw volume meter */
+ draw_volume_boxes (window,
+ cr,
+ (double)window->priv->volume_level / 100.0,
+ bright_box_x0,
+ bright_box_y0,
+ bright_box_width,
+ bright_box_height);
+ }
+}
+
+static void
+gsd_media_keys_window_expose_when_composited (GsdOsdWindow *osd_window,
+ cairo_t *cr)
+{
+ GsdMediaKeysWindow *window = GSD_MEDIA_KEYS_WINDOW (osd_window);
+
+ switch (window->priv->action) {
+ case GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME:
+ draw_action_volume (window, cr);
+ break;
+ case GSD_MEDIA_KEYS_WINDOW_ACTION_CUSTOM:
+ draw_action_custom (window, cr);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gsd_media_keys_window_class_init (GsdMediaKeysWindowClass *klass)
+{
+ GsdOsdWindowClass *osd_window_class = GSD_OSD_WINDOW_CLASS (klass);
+
+ osd_window_class->expose_when_composited = gsd_media_keys_window_expose_when_composited;
+
+ g_type_class_add_private (klass, sizeof (GsdMediaKeysWindowPrivate));
+}
+
+static void
+gsd_media_keys_window_init (GsdMediaKeysWindow *window)
+{
+ GdkScreen *screen;
+
+ window->priv = GSD_MEDIA_KEYS_WINDOW_GET_PRIVATE (window);
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (window));
+
+ if (!gsd_osd_window_is_composited (GSD_OSD_WINDOW (window))) {
+ GtkBuilder *builder;
+ const gchar *objects[] = {"acme_box", NULL};
+ GtkWidget *box;
+
+ builder = gtk_builder_new ();
+ gtk_builder_add_objects_from_file (builder,
+ GTKBUILDERDIR "/acme.ui",
+ (char **) objects,
+ NULL);
+
+ window->priv->image = GTK_IMAGE (gtk_builder_get_object (builder, "acme_image"));
+ window->priv->progress = GTK_WIDGET (gtk_builder_get_object (builder, "acme_volume_progressbar"));
+ box = GTK_WIDGET (gtk_builder_get_object (builder, "acme_box"));
+
+ if (box != NULL) {
+ gtk_container_add (GTK_CONTAINER (window), box);
+ gtk_widget_show_all (box);
+ }
+
+ /* The builder needs to stay alive until the window
+ takes ownership of the box (and its children) */
+ g_object_unref (builder);
+ }
+}
+
+GtkWidget *
+gsd_media_keys_window_new (void)
+{
+ return g_object_new (GSD_TYPE_MEDIA_KEYS_WINDOW, NULL);
+}
diff --git a/plugins/media-keys/gsd-media-keys-window.h b/plugins/media-keys/gsd-media-keys-window.h
new file mode 100644
index 0000000..236d011
--- /dev/null
+++ b/plugins/media-keys/gsd-media-keys-window.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 8; tab-width: 8 -*-
+ *
+ * Copyright (C) 2006 William Jon McCann <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2, 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 Lesser General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU Lesser 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.
+ *
+ */
+
+#ifndef GSD_MEDIA_KEYS_WINDOW_H
+#define GSD_MEDIA_KEYS_WINDOW_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gsd-osd-window.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define GSD_TYPE_MEDIA_KEYS_WINDOW (gsd_media_keys_window_get_type ())
+#define GSD_MEDIA_KEYS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSD_TYPE_MEDIA_KEYS_WINDOW, GsdMediaKeysWindow))
+#define GSD_MEDIA_KEYS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSD_TYPE_MEDIA_KEYS_WINDOW, GsdMediaKeysWindowClass))
+#define GSD_IS_MEDIA_KEYS_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSD_TYPE_MEDIA_KEYS_WINDOW))
+#define GSD_IS_MEDIA_KEYS_WINDOW_CLASS(klass) (G_TYPE_INSTANCE_GET_CLASS ((klass), GSD_TYPE_MEDIA_KEYS_WINDOW))
+
+typedef struct GsdMediaKeysWindow GsdMediaKeysWindow;
+typedef struct GsdMediaKeysWindowClass GsdMediaKeysWindowClass;
+typedef struct GsdMediaKeysWindowPrivate GsdMediaKeysWindowPrivate;
+
+struct GsdMediaKeysWindow {
+ GsdOsdWindow parent;
+
+ GsdMediaKeysWindowPrivate *priv;
+};
+
+struct GsdMediaKeysWindowClass {
+ GsdOsdWindowClass parent_class;
+};
+
+typedef enum {
+ GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME,
+ GSD_MEDIA_KEYS_WINDOW_ACTION_CUSTOM
+} GsdMediaKeysWindowAction;
+
+GType gsd_media_keys_window_get_type (void);
+
+GtkWidget * gsd_media_keys_window_new (void);
+void gsd_media_keys_window_set_action (GsdMediaKeysWindow *window,
+ GsdMediaKeysWindowAction action);
+void gsd_media_keys_window_set_action_custom (GsdMediaKeysWindow *window,
+ const char *icon_name,
+ gboolean show_level);
+void gsd_media_keys_window_set_volume_muted (GsdMediaKeysWindow *window,
+ gboolean muted);
+void gsd_media_keys_window_set_volume_level (GsdMediaKeysWindow *window,
+ int level);
+gboolean gsd_media_keys_window_is_valid (GsdMediaKeysWindow *window);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/plugins/media-keys/libmedia-keys.la b/plugins/media-keys/libmedia-keys.la
new file mode 100644
index 0000000..26117f7
--- /dev/null
+++ b/plugins/media-keys/libmedia-keys.la
@@ -0,0 +1,41 @@
+# libmedia-keys.la - a libtool library file
+# Generated by libtool (GNU libtool) 2.4
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='libmedia-keys.so'
+
+# Names of this library.
+library_names='libmedia-keys.so libmedia-keys.so libmedia-keys.so'
+
+# The name of the static archive.
+old_library='libmedia-keys.a'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags=' -pthread'
+
+# Libraries that this one depends upon.
+dependency_libs=' -lXext -lpulse-mainloop-glib -lpulse /usr/lib/libcanberra-gtk.la -lgobject-2.0 -lgthread-2.0 -lglib-2.0 -lfontconfig /usr/lib/libcanberra.la -lvorbisfile -lvorbis -logg -ltdb -lltdl /usr/lib/libmate-desktop-2.la /usr/lib/libmateconf-2.la /usr/lib/libMateCORBA-2.la -lXrandr /usr/lib/libgtk-x11-2.0.la /usr/lib/libstartup-notification-1.la -lSM -lICE /usr/lib/libgdk-x11-2.0.la /usr/lib/libatk-1.0.la /usr/lib/libpangocairo-1.0.la /usr/lib/libpangoft2-1.0.la /usr/lib/libgdk_pixbuf-2.0.la /usr/lib/libcairo.la -lpixman-1 -lpng14 -lXrender -lX11 /usr/lib/libpango-1.0.la /usr/lib/libfontconfig.la -lfreetype -lexpat /usr/lib/libgio-2.0.la -lresolv -lz /usr/lib/libgmodule-2.0.la -ldl /usr/lib/libdbus-glib-1.la /usr/lib/libdbus-1.la /usr/lib/libgobject-2.0.la /usr/lib/libgthread-2.0.la -lpthread -lrt /usr/lib/libglib-2.0.la -lm'
+
+# Names of additional weak libraries provided by this library
+weak_library_names=''
+
+# Version information for libmedia-keys.
+current=0
+age=0
+revision=0
+
+# Is this an already installed library?
+installed=no
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=yes
+
+# Files to dlopen/dlpreopen
+dlopen=''
+dlpreopen=''
+
+# Directory that this library needs to be installed in:
+libdir='/usr/lib/mate-settings-daemon-2.0'
diff --git a/plugins/media-keys/media-keys.mate-settings-plugin b/plugins/media-keys/media-keys.mate-settings-plugin
new file mode 100644
index 0000000..48b62bc
--- /dev/null
+++ b/plugins/media-keys/media-keys.mate-settings-plugin
@@ -0,0 +1,136 @@
+[MATE Settings Plugin]
+Module=media-keys
+IAge=0
+Name=Media keys
+Name[af]=Mediasleutels
+Name[ar]=مفاتيح الوسائط
+Name[as]=মিডিয়া কি
+Name[ast]=Tecles multimedia
+Name[be@latin]=Medyja-klavišy
+Name[bg]=Мултимедийни клавиши
+Name[bn]=মিডিয়া কী
+Name[bn_IN]=মিডিয়া কি
+Name[br]=Alc'hwezioù ar media
+Name[ca]=Tecles multimèdia
+Name[ca@valencia]=Tecles multimèdia
+Name[crh]=Ortam tuşları
+Name[cs]=Multimediální klávesy
+Name[da]=Medietaster
+Name[de]=Medientasten
+Name[el]=Πλήκτρα πολυμέσων
+Name[en@shaw]=𐑥𐑰𐑛𐑦𐑩 𐑒𐑰𐑟
+Name[en_GB]=Media keys
+Name[es]=Teclas multimedia
+Name[et]=Meediaklahvid
+Name[eu]=Multimedia-teklak
+Name[fi]=Medianäppäimet
+Name[fr]=Touches multimédias
+Name[ga]=Eochracha meán
+Name[gl]=Teclas multimedia
+Name[gu]=મીડિયા કીઓ
+Name[he]=מקשי מדיה
+Name[hi]=मीडिया कुंजी
+Name[hu]=Médiabillentyűk
+Name[id]=Kunci media
+Name[it]=Tasti multimediali
+Name[ja]=メディア・キー
+Name[kn]=ಮೀಡಿಯಾ ಕೀಲಿಗಳು
+Name[ko]=미디어 키
+Name[lt]=Multimedijos klavišai
+Name[lv]=Mediju taustiņi
+Name[mk]=Музички копчиња
+Name[ml]=മാധ്യമ സംയോജകം
+Name[mr]=मिडीया कि
+Name[nb]=Medietaster
+Name[nds]=Medienknöppe
+Name[nl]=Mediatoetsen
+Name[nn]=Mediatastar
+Name[or]=ମେଡିଆ କିଗୁଡ଼ିକ
+Name[pa]=ਮੀਡਿਆ ਸਵਿੱਚਾਂ
+Name[pl]=Klawisze multimedialne
+Name[pt]=Teclas de Media
+Name[pt_BR]=Teclas de mídia
+Name[ro]=Taste media
+Name[ru]=Мультимедийные клавиши
+Name[sk]=Multimediálne klávesy
+Name[sl]=Večpredstavnostne tipke
+Name[sr]=Мултимедијални тастери
+Name[sr@latin]=Multimedijalni tasteri
+Name[sv]=Mediatangenter
+Name[ta]=ஊடக விசைகள்
+Name[te]=మాద్యమం కీలు
+Name[th]=ปุ่มสั่งการสื่อ
+Name[tr]=Ortam tuşları
+Name[uk]=Мультимедійний клавіші
+Name[vi]=Phím nhạc/phim
+Name[zh_CN]=媒体键
+Name[zh_HK]=多媒體按鍵
+Name[zh_TW]=多媒體按鍵
+Description=Media keys plugin
+Description[af]=Inprop vir mediasleutels
+Description[ar]=ملحق مفاتيح الوسائط
+Description[as]=মিডিয়া-কি প্লাগ-ইন
+Description[ast]=Complementu de tecles multimedia
+Description[be@latin]=Plugin medyja-klavišaŭ
+Description[bg]=Приставка за мултимедийни клавиши
+Description[bn]=মিডিয়া-কি প্লাগ-ইন
+Description[bn_IN]=মিডিয়া-কি প্লাগ-ইন
+Description[br]=Enlugellad alc'hwezioù ar media
+Description[ca]=Connector de les tecles multimèdia
+Description[ca@valencia]=Connector de les tecles multimèdia
+Description[crh]=Ortam tuşları eklentisi
+Description[cs]=Zásuvný modul multimediálních kláves
+Description[da]=Medietastmodul
+Description[de]=Medientastenmodul
+Description[el]=Πρόσθετη λειτουργία πλήκτρων πολυμέσων
+Description[en@shaw]=𐑥𐑰𐑛𐑦𐑩 𐑒𐑰𐑟 𐑐𐑤𐑳𐑜𐑦𐑯
+Description[en_GB]=Media keys plugin
+Description[es]=Complemento de teclas multimedia
+Description[et]=Meediaklahvide plugin
+Description[eu]=Multimedia-teklen plugina
+Description[fi]=Medianäppäinten liitännäinen
+Description[fr]=Greffon des touches multimédias
+Description[ga]=Breiseán eochracha meán
+Description[gl]=Engadido das teclas multimedia
+Description[gu]=મીડિયા કી પલ્ગઇન
+Description[he]=תוסף מקשי מדיה
+Description[hi]=मीडिया कुंजी प्लगिन
+Description[hu]=Médiabillentyűk bővítmény
+Description[id]=Plugin kunci media
+Description[it]=Plugin per i tasti multimediali
+Description[ja]=メディア・キーのプラグイン
+Description[kn]=ಮೀಡಿಯಾ ಕೀಲಿಗಳು ಪ್ಲಗ್ಇನ್
+Description[ko]=미디어 키 플러그인
+Description[lt]=Multimedijos klavišų įskiepis
+Description[lv]=Mediju taustiņu spraudnis
+Description[mk]=Додаток за копчињата за музика
+Description[ml]= സംയോജകം
+Description[mr]=मिडीया कि पल्गइन
+Description[nb]=Tillegg for medietaster
+Description[nds]=Medienknöppeplugin
+Description[nl]=Mediatoetsen-plugin
+Description[nn]=Tillegg for medietastar
+Description[or]=ମେଡ଼ିଆ କିଗୁଡ଼ିକର ପ୍ଲଗଇନ
+Description[pa]=ਮੀਡਿਆ ਸਵਿੱਚ ਪਲੱਗਇਨ
+Description[pl]=Wtyczka klawiszy multimedialnych
+Description[pt]=Plugin de teclas de media
+Description[pt_BR]=Plug-in de teclas de mídia
+Description[ro]=Modul taste media
+Description[ru]=Модуль мультимедийных клавиш
+Description[sk]=Modul multimediálnych kláves
+Description[sl]=Vstavek večpredstavnostnih tipk
+Description[sr]=Додатак за мултимедијалне тастере
+Description[sr@latin]=Dodatak za multimedijalne tastere
+Description[sv]=Insticksmodul för mediatangenter
+Description[ta]=ஊடக விசைகள் சொருகி
+Description[te]=మాద్యమం కీల ప్లగ్ఇన్
+Description[th]=ปลั๊กอินจัดการปุ่มสั่งการสื่อ
+Description[tr]=Ortam tuşları eklentisi
+Description[uk]=Модуль мультимедійних клавіш
+Description[vi]=Phần mở rộng phím nhạc/phim
+Description[zh_CN]=媒体键插件
+Description[zh_HK]=多媒體按鍵外掛程式
+Description[zh_TW]=多媒體按鍵外掛程式
+Authors=
+Copyright=Copyright © 2007
+Website=
diff --git a/plugins/media-keys/media-keys.mate-settings-plugin.in b/plugins/media-keys/media-keys.mate-settings-plugin.in
new file mode 100644
index 0000000..fdaf931
--- /dev/null
+++ b/plugins/media-keys/media-keys.mate-settings-plugin.in
@@ -0,0 +1,8 @@
+[MATE Settings Plugin]
+Module=media-keys
+IAge=0
+_Name=Media keys
+_Description=Media keys plugin
+Authors=
+Copyright=Copyright © 2007
+Website=
diff --git a/plugins/media-keys/test-media-keys.c b/plugins/media-keys/test-media-keys.c
new file mode 100644
index 0000000..e3345f9
--- /dev/null
+++ b/plugins/media-keys/test-media-keys.c
@@ -0,0 +1,64 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <[email protected]>
+ *
+ * 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 "config.h"
+
+#include <stdlib.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "gsd-media-keys-manager.h"
+
+static GsdMediaKeysManager *manager = NULL;
+
+int
+main (int argc,
+ char **argv)
+{
+ GError *error;
+ gboolean res;
+
+#ifdef ENABLE_NLS
+ bindtextdomain (GETTEXT_PACKAGE, MATE_SETTINGS_LOCALEDIR);
+# ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+# endif
+ textdomain (GETTEXT_PACKAGE);
+#endif
+
+ error = NULL;
+ if (! gtk_init_with_args (&argc, &argv, NULL, NULL, NULL, &error)) {
+ fprintf (stderr, "%s", error->message);
+ g_error_free (error);
+ exit (1);
+ }
+
+ manager = gsd_media_keys_manager_new ();
+
+ error = NULL;
+ res = gsd_media_keys_manager_start (manager, &error);
+
+ gtk_main ();
+
+ return 0;
+}
diff --git a/plugins/media-keys/test-media-window.c b/plugins/media-keys/test-media-window.c
new file mode 100644
index 0000000..c97f3d9
--- /dev/null
+++ b/plugins/media-keys/test-media-window.c
@@ -0,0 +1,152 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2007 William Jon McCann <[email protected]>
+ *
+ * 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 "config.h"
+
+#include <stdlib.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "gsd-media-keys-window.h"
+
+static gboolean
+update_state (GtkWidget *window)
+{
+ static int count = 0;
+
+ count++;
+
+ switch (count) {
+ case 1:
+ gsd_media_keys_window_set_volume_level (GSD_MEDIA_KEYS_WINDOW (window),
+ 50);
+ gsd_media_keys_window_set_action (GSD_MEDIA_KEYS_WINDOW (window),
+ GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME);
+
+ gtk_widget_show (window);
+ break;
+ case 2:
+ gsd_media_keys_window_set_volume_level (GSD_MEDIA_KEYS_WINDOW (window),
+ 100);
+ gsd_media_keys_window_set_action (GSD_MEDIA_KEYS_WINDOW (window),
+ GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME);
+
+ gtk_widget_show (window);
+ break;
+ case 3:
+ gsd_media_keys_window_set_volume_muted (GSD_MEDIA_KEYS_WINDOW (window),
+ TRUE);
+ gsd_media_keys_window_set_action (GSD_MEDIA_KEYS_WINDOW (window),
+ GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME);
+
+ gtk_widget_show (window);
+ break;
+ case 4:
+ gsd_media_keys_window_set_action_custom (GSD_MEDIA_KEYS_WINDOW (window),
+ "media-eject",
+ FALSE);
+
+ gtk_widget_show (window);
+ break;
+ case 5:
+ gsd_media_keys_window_set_volume_level (GSD_MEDIA_KEYS_WINDOW (window),
+ 0);
+ gsd_media_keys_window_set_action_custom (GSD_MEDIA_KEYS_WINDOW (window),
+ "gpm-brightness-lcd",
+ TRUE);
+
+ gtk_widget_show (window);
+ break;
+ case 6:
+ gsd_media_keys_window_set_volume_level (GSD_MEDIA_KEYS_WINDOW (window),
+ 50);
+ gsd_media_keys_window_set_action_custom (GSD_MEDIA_KEYS_WINDOW (window),
+ "gpm-brightness-lcd",
+ TRUE);
+
+ gtk_widget_show (window);
+ break;
+ case 7:
+ gsd_media_keys_window_set_volume_level (GSD_MEDIA_KEYS_WINDOW (window),
+ 100);
+ gsd_media_keys_window_set_action_custom (GSD_MEDIA_KEYS_WINDOW (window),
+ "gpm-brightness-lcd",
+ TRUE);
+
+ gtk_widget_show (window);
+ break;
+ default:
+ gtk_main_quit ();
+ break;
+ }
+
+ return TRUE;
+}
+
+static void
+test_window (void)
+{
+ GtkWidget *window;
+
+ window = gsd_media_keys_window_new ();
+ gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_CENTER_ALWAYS);
+
+ gsd_media_keys_window_set_volume_level (GSD_MEDIA_KEYS_WINDOW (window),
+ 0);
+ gsd_media_keys_window_set_action (GSD_MEDIA_KEYS_WINDOW (window),
+ GSD_MEDIA_KEYS_WINDOW_ACTION_VOLUME);
+
+ gtk_widget_show (window);
+
+ g_timeout_add (3000, (GSourceFunc) update_state, window);
+}
+
+int
+main (int argc,
+ char **argv)
+{
+ GError *error = NULL;
+
+#ifdef ENABLE_NLS
+ bindtextdomain (GETTEXT_PACKAGE, MATE_SETTINGS_LOCALEDIR);
+# ifdef HAVE_BIND_TEXTDOMAIN_CODESET
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+# endif
+ textdomain (GETTEXT_PACKAGE);
+#endif
+
+ if (! gtk_init_with_args (&argc, &argv, NULL, NULL, NULL, &error)) {
+ fprintf (stderr, "%s", error->message);
+ g_error_free (error);
+ exit (1);
+ }
+
+ gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
+ DATADIR G_DIR_SEPARATOR_S "mate-power-manager" G_DIR_SEPARATOR_S "icons");
+
+ test_window ();
+
+ gtk_main ();
+
+ return 0;
+}
diff --git a/plugins/media-keys/touchpad-disabled-16.png b/plugins/media-keys/touchpad-disabled-16.png
new file mode 100644
index 0000000..c8355de
--- /dev/null
+++ b/plugins/media-keys/touchpad-disabled-16.png
Binary files differ
diff --git a/plugins/media-keys/touchpad-disabled-22.png b/plugins/media-keys/touchpad-disabled-22.png
new file mode 100644
index 0000000..706fbc7
--- /dev/null
+++ b/plugins/media-keys/touchpad-disabled-22.png
Binary files differ
diff --git a/plugins/media-keys/touchpad-disabled-24.png b/plugins/media-keys/touchpad-disabled-24.png
new file mode 100644
index 0000000..fc0bac7
--- /dev/null
+++ b/plugins/media-keys/touchpad-disabled-24.png
Binary files differ
diff --git a/plugins/media-keys/touchpad-disabled-32.png b/plugins/media-keys/touchpad-disabled-32.png
new file mode 100644
index 0000000..1311c60
--- /dev/null
+++ b/plugins/media-keys/touchpad-disabled-32.png
Binary files differ
diff --git a/plugins/media-keys/touchpad-disabled-48.png b/plugins/media-keys/touchpad-disabled-48.png
new file mode 100644
index 0000000..8f6ee03
--- /dev/null
+++ b/plugins/media-keys/touchpad-disabled-48.png
Binary files differ
diff --git a/plugins/media-keys/touchpad-disabled-template.svg b/plugins/media-keys/touchpad-disabled-template.svg
new file mode 100644
index 0000000..4d08198
--- /dev/null
+++ b/plugins/media-keys/touchpad-disabled-template.svg
@@ -0,0 +1,1172 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ height="300"
+ id="svg11300"
+ inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png"
+ inkscape:export-xdpi="90.000000"
+ inkscape:export-ydpi="90.000000"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:version="0.46+devel"
+ sodipodi:docname="hicolor_status_scalable_touchpad-disabled.svg"
+ sodipodi:version="0.32"
+ style="display:inline;enable-background:new"
+ version="1.0"
+ width="400">
+ <title
+ id="title3835">Touchpad</title>
+ <metadata
+ id="metadata154">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Touchpad</dc:title>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Lapo Calamandrei</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:contributor>
+ <dc:source />
+ <cc:license
+ rdf:resource="" />
+ <dc:subject>
+ <rdf:Bag />
+ </dc:subject>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ bordercolor="#666666"
+ borderopacity="0.25490196"
+ fill="#f57900"
+ gridtolerance="12"
+ guidetolerance="13"
+ height="300px"
+ id="base"
+ inkscape:current-layer="layer2"
+ inkscape:cx="433.90068"
+ inkscape:cy="165.06237"
+ inkscape:document-units="px"
+ inkscape:grid-bbox="true"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:showpageshadow="false"
+ inkscape:snap-bbox="true"
+ inkscape:snap-nodes="true"
+ inkscape:window-height="1177"
+ inkscape:window-width="1920"
+ inkscape:window-x="1440"
+ inkscape:window-y="0"
+ inkscape:zoom="1.4142136"
+ objecttolerance="7"
+ pagecolor="#ffffff"
+ showgrid="false"
+ stroke="#ef2929"
+ width="400px"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ showborder="true"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ enabled="true"
+ id="grid5883"
+ spacingx="0.5px"
+ spacingy="0.5px"
+ type="xygrid"
+ visible="true"
+ empspacing="2"
+ snapvisiblegridlinesonly="true" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="313.98438,106.53125"
+ id="guide4872" />
+ <sodipodi:guide
+ orientation="0,1"
+ position="312.32813,105.01563"
+ id="guide4874" />
+ <sodipodi:guide
+ orientation="0,1"
+ position="312.90625,147"
+ id="guide4876" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="313,161.6875"
+ id="guide4878" />
+ <sodipodi:guide
+ orientation="0,1"
+ position="341.64306,213.01592"
+ id="guide4880" />
+ </sodipodi:namedview>
+ <defs
+ id="defs3">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 150 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="400 : 150 : 1"
+ inkscape:persp3d-origin="200 : 100 : 1"
+ id="perspective147" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2972">
+ <stop
+ style="stop-color:#babdb6;stop-opacity:1"
+ offset="0"
+ id="stop2974" />
+ <stop
+ style="stop-color:#555753;stop-opacity:1"
+ offset="1"
+ id="stop2976" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3100">
+ <stop
+ id="stop3102"
+ offset="0"
+ style="stop-color:#babdb6;stop-opacity:1" />
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0.25"
+ id="stop3104" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="0.5"
+ id="stop3106" />
+ <stop
+ id="stop3108"
+ offset="0.75"
+ style="stop-color:#ffffff;stop-opacity:1" />
+ <stop
+ id="stop3110"
+ offset="1"
+ style="stop-color:#babdb6;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3743">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.2"
+ offset="0"
+ id="stop3745" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop3747" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3760-7"
+ id="radialGradient3766-2"
+ cx="311"
+ cy="225.23932"
+ fx="311"
+ fy="225.23932"
+ r="8"
+ gradientTransform="matrix(1.4590081,0,0,1.0942561,-142.75153,-21.969492)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3760-7">
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0"
+ id="stop3762-0" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="1"
+ id="stop3764-5" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3752-2">
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="0"
+ id="stop3754-2" />
+ <stop
+ style="stop-color:#babdb6;stop-opacity:1"
+ offset="1"
+ id="stop3756-8" />
+ </linearGradient>
+ <linearGradient
+ y2="238.1875"
+ x2="324.875"
+ y1="231.5"
+ x1="304.8125"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3794"
+ xlink:href="#linearGradient3752-2"
+ inkscape:collect="always"
+ gradientTransform="translate(0,-1)" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3760-7-6"
+ id="radialGradient3766-2-5"
+ cx="312.09396"
+ cy="224.27068"
+ fx="312.09396"
+ fy="224.27068"
+ r="8"
+ gradientTransform="matrix(2.0157047,0,0,1.5117786,-315.08929,-153.04762)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3760-7-6">
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0"
+ id="stop3762-0-6" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="1"
+ id="stop3764-5-1" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3752-2-3">
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="0"
+ id="stop3754-2-2" />
+ <stop
+ style="stop-color:#babdb6;stop-opacity:1"
+ offset="1"
+ id="stop3756-8-6" />
+ </linearGradient>
+ <linearGradient
+ y2="238.1875"
+ x2="324.875"
+ y1="231.5"
+ x1="304.8125"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2894"
+ xlink:href="#linearGradient3752-2-3"
+ inkscape:collect="always"
+ gradientTransform="translate(1,-38)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3743"
+ id="linearGradient3749"
+ x1="304"
+ y1="177"
+ x2="304"
+ y2="195"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3760-7-6-4"
+ id="radialGradient3766-2-5-1"
+ cx="312.09396"
+ cy="224.27068"
+ fx="312.09396"
+ fy="224.27068"
+ r="8"
+ gradientTransform="matrix(3.7131449,0,0,3.563472,-838.85008,-725.00376)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3760-7-6-4">
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0"
+ id="stop3762-0-6-6" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="1"
+ id="stop3764-5-1-4" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3743-4">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.2"
+ offset="0"
+ id="stop3745-6" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop3747-2" />
+ </linearGradient>
+ <linearGradient
+ y2="195"
+ x2="304"
+ y1="177"
+ x1="304"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2910"
+ xlink:href="#linearGradient3743-4"
+ inkscape:collect="always"
+ gradientTransform="matrix(1.9473685,0,0,1.9444446,-291.47369,-291.58337)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3100"
+ id="linearGradient3092"
+ x1="302"
+ y1="82.375"
+ x2="338"
+ y2="92.75"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3100-5"
+ id="linearGradient3092-9"
+ x1="305.89941"
+ y1="83.784264"
+ x2="334.10059"
+ y2="91.340736"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-2,66)" />
+ <linearGradient
+ id="linearGradient3100-5">
+ <stop
+ id="stop3102-6"
+ offset="0"
+ style="stop-color:#babdb6;stop-opacity:1" />
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0.25"
+ id="stop3104-13" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="0.5"
+ id="stop3106-5" />
+ <stop
+ id="stop3108-50"
+ offset="0.75"
+ style="stop-color:#ffffff;stop-opacity:1" />
+ <stop
+ id="stop3110-4"
+ offset="1"
+ style="stop-color:#babdb6;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3743-4-4">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.2"
+ offset="0"
+ id="stop3745-6-8" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop3747-2-3" />
+ </linearGradient>
+ <linearGradient
+ y2="195"
+ x2="304"
+ y1="180.95102"
+ x1="304"
+ gradientTransform="matrix(1.8448754,0,0,1.8333335,-257.26455,-204.75003)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4350"
+ xlink:href="#linearGradient3743-4-4"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3760-7-6-4-66-6">
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0"
+ id="stop3762-0-6-6-61-7" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="1"
+ id="stop3764-5-1-4-0-6" />
+ </linearGradient>
+ <radialGradient
+ r="8"
+ fy="222.91086"
+ fx="312.22864"
+ cy="222.91086"
+ cx="312.22864"
+ gradientTransform="matrix(2.8880002,0,0,2.9155676,-583.21633,-511.91208)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient4444"
+ xlink:href="#linearGradient3760-7-6-4-66-6"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2972"
+ id="linearGradient2978"
+ x1="315.81155"
+ y1="82.20932"
+ x2="315.81155"
+ y2="89.25135"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2972"
+ id="linearGradient3756"
+ x1="318.5"
+ y1="147.03621"
+ x2="318.5"
+ y2="155.96379"
+ gradientUnits="userSpaceOnUse" />
+ <inkscape:perspective
+ id="perspective3111"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective3912"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective4331"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective4799"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ </defs>
+ <g
+ id="layer1"
+ inkscape:groupmode="layer"
+ inkscape:label="artwork"
+ style="display:inline">
+ <g
+ inkscape:groupmode="layer"
+ id="layer5"
+ inkscape:label="disabled"
+ style="display:none"
+ sodipodi:insensitive="true">
+ <rect
+ height="256"
+ id="rect6282"
+ inkscape:label="256x256"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="256"
+ x="16"
+ y="28" />
+ </g>
+ <g
+ id="layer6"
+ inkscape:groupmode="layer"
+ inkscape:label="baseplate"
+ style="display:none">
+ <rect
+ height="48"
+ id="rect6284"
+ inkscape:label="48x48"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="48"
+ x="296"
+ y="50" />
+ <rect
+ height="32"
+ id="rect6592"
+ inkscape:label="32x32"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="32"
+ x="303"
+ y="126" />
+ <rect
+ height="22"
+ id="rect6749"
+ inkscape:label="22x22"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="22"
+ x="303"
+ y="177" />
+ <rect
+ height="16"
+ id="rect6833"
+ inkscape:label="16x16"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="16"
+ x="303"
+ y="219" />
+ <rect
+ height="24"
+ id="rect8104"
+ inkscape:label="24x24"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="24"
+ x="302"
+ y="176" />
+ <text
+ id="context"
+ inkscape:label="context"
+ style="font-size:18.30070686px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;enable-background:new;font-family:Bitstream Vera Sans"
+ x="20.970737"
+ xml:space="preserve"
+ y="21.513618"><tspan
+ id="tspan2716"
+ sodipodi:role="line"
+ x="20.970737"
+ y="21.513618">devices</tspan></text>
+ <text
+ id="icon-name"
+ inkscape:label="icon-name"
+ sodipodi:linespacing="125%"
+ style="font-size:18.30070686px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;enable-background:new;font-family:Droid Sans;-inkscape-font-specification:Droid Sans Bold"
+ x="141.97073"
+ xml:space="preserve"
+ y="21.513618"><tspan
+ id="tspan3023"
+ sodipodi:role="line"
+ x="141.97073"
+ y="21.513618">input-touchpad</tspan></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="small sizes"
+ style="display:inline">
+ <path
+ style="color:#000000;fill:url(#linearGradient3794);fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 303.5,227.5 0,4 c 0,1.108 0.892,2 2,2 l 11,0 c 1.108,0 2,-0.892 2,-2 l 0,-4 c 0,1.108 -0.892,2 -2,2 l -11,0 c -1.108,0 -2,-0.892 -2,-2 z"
+ id="rect2846-2-3"
+ sodipodi:nodetypes="ccccccccc" />
+ <rect
+ style="color:#000000;fill:url(#radialGradient3766-2);fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2846"
+ width="15"
+ height="10"
+ x="303.5"
+ y="219.5"
+ rx="2"
+ ry="2" />
+ <rect
+ style="opacity:0.3;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect3694"
+ width="13"
+ height="12"
+ x="304.5"
+ y="220.5"
+ rx="1"
+ ry="1" />
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ d="m 304,229.5 0,1 c 0,0.0541 0.002,0.1029 0,0.15625 0.45244,0.21377 0.96717,0.34375 1.5,0.34375 l 11,0 c 0.53283,0 1.04756,-0.12998 1.5,-0.34375 L 318,229.5 c -0.41577,0.30853 -0.93558,0.5 -1.5,0.5 l -11,0 c -0.56442,0 -1.08423,-0.19147 -1.5,-0.5 z"
+ id="rect2846-2"
+ sodipodi:nodetypes="cccccccccc" />
+ <rect
+ style="color:#000000;fill:#d3d7cf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect3728"
+ width="1"
+ height="3"
+ x="310"
+ y="230"
+ rx="0"
+ ry="0" />
+ <rect
+ style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect3728-4"
+ width="1"
+ height="3"
+ x="311"
+ y="230"
+ rx="0"
+ ry="0" />
+ <rect
+ style="opacity:0.3;color:#000000;fill:none;stroke:url(#linearGradient3749);stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2846-28-6"
+ width="19"
+ height="18"
+ x="304.5"
+ y="178.5"
+ rx="2"
+ ry="2" />
+ <path
+ style="color:#000000;fill:url(#linearGradient2894);fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 304.5,190.5 0,4 c 0,1.108 0.892,2 2,2 l 15,0 c 1.108,0 2,-0.892 2,-2 l 0,-4 c 0,1.108 -0.892,2 -2,2 l -15,0 c -1.108,0 -2,-0.892 -2,-2 z"
+ id="rect2846-2-3-0"
+ sodipodi:nodetypes="ccccccccc" />
+ <rect
+ style="color:#000000;fill:url(#radialGradient3766-2-5);fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2846-28"
+ width="18.999943"
+ height="14.000024"
+ x="304.5"
+ y="178.5"
+ rx="2"
+ ry="2" />
+ <rect
+ style="opacity:0.3;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect3694-0"
+ width="17.000095"
+ height="16.000011"
+ x="305.5"
+ y="179.5"
+ rx="1"
+ ry="1" />
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ d="m 305,192.5 0,1 c 0,0.0541 0.002,0.1029 0,0.15625 0.45244,0.21377 0.96717,0.34375 1.5,0.34375 l 15,0 c 0.53283,0 1.04756,-0.12998 1.5,-0.34375 L 323,192.5 c -0.41577,0.30853 -0.93558,0.5 -1.5,0.5 l -15,0 c -0.56442,0 -1.08423,-0.19147 -1.5,-0.5 z"
+ id="rect2846-2-1"
+ sodipodi:nodetypes="cccccccccc" />
+ <rect
+ style="color:#000000;fill:#d3d7cf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect3728-5"
+ width="1"
+ height="3"
+ x="313"
+ y="193"
+ rx="0"
+ ry="0" />
+ <rect
+ style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect3728-4-5"
+ width="1"
+ height="3"
+ x="314"
+ y="193"
+ rx="0"
+ ry="0" />
+ <rect
+ style="opacity:0.3;color:#000000;fill:none;stroke:url(#linearGradient2910);stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2846-28-6-4"
+ width="38"
+ height="35"
+ x="301.5"
+ y="55.5"
+ rx="4"
+ ry="4" />
+ <rect
+ style="color:#000000;fill:url(#radialGradient3766-2-5-1);fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2846-28-66"
+ width="35.999939"
+ height="33.000004"
+ x="302.50006"
+ y="56.499996"
+ rx="3.0000038"
+ ry="3.0000038" />
+ <rect
+ ry="2"
+ rx="2"
+ y="57.5"
+ x="303.5"
+ height="25"
+ width="34"
+ id="rect3694-0-0"
+ style="opacity:0.3;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <g
+ id="g4205">
+ <path
+ id="rect3694-0-0-9"
+ d="m 303,84.5 0,2 c 0,1.367703 1.1323,2.5 2.5,2.5 l 14.5,0 0,-2 -14.5,0 c -0.0657,0 -0.1232,-0.02642 -0.1875,-0.03125 C 304.01204,86.871142 303,85.827989 303,84.5 z"
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.1;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane" />
+ <path
+ id="rect3694-0-0-9-8"
+ d="m 338,84.5 0,2 c 0,1.367703 -1.1323,2.5 -2.5,2.5 l -14.5,0 0,-2 14.5,0 c 0.0657,0 0.1232,-0.02642 0.1875,-0.03125 C 336.98796,86.871142 338,85.827989 338,84.5 z"
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.1;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane" />
+ </g>
+ <g
+ id="g2958"
+ style="fill-opacity:1;stroke:url(#linearGradient2978)">
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ id="rect2846-28-66-1"
+ d="m 302.5,80.5 0,6 c 0,1.662002 1.338,3 3,3 l 30,0 c 1.662,0 3,-1.337998 3,-3 l 0,-6 c 0,1.662002 -1.338,3 -3,3 l -30,0 c -1.662,0 -3,-1.337998 -3,-3 z"
+ style="color:#000000;fill:url(#linearGradient3092);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2978);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <path
+ id="path3112"
+ d="m 320.5,83.5 0,6"
+ style="fill:none;stroke:url(#linearGradient2978);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" />
+ </g>
+ <path
+ style="opacity:0.5;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 303.5,83.875 0,2.625 c 0,1.12494 0.87506,2 2,2 l 14,0 0,-4 -14,0 c -0.74347,0 -1.40165,-0.267405 -2,-0.625 z"
+ id="path3161-2"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="opacity:0.5;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 337.5,83.875 0,2.625 c 0,1.12494 -0.87506,2 -2,2 l -14,0 0,-4 14,0 c 0.74347,0 1.40165,-0.267405 2,-0.625 z"
+ id="path3161-2-0"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.4;color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ d="m 303,82.65625 0,1.3125 C 303.8401,84.608417 304.86264,85 306,85 l 14,0 0,-1 -14,0 c -1.20201,0 -2.2695,-0.516326 -3,-1.34375 z"
+ id="rect2846-28-66-0" />
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.4;color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ d="m 338,82.65625 0,1.3125 C 337.1599,84.608417 336.13736,85 335,85 l -14,0 0,-1 14,0 c 1.20201,0 2.2695,-0.516326 3,-1.34375 z"
+ id="rect2846-28-66-0-6" />
+ <path
+ style="opacity:0.1;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 309.49911,81.5 22.00265,0"
+ id="path4233" />
+ <path
+ style="opacity:0.1;fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 336.5,76.504425 0,-13.00885"
+ id="path4235" />
+ <rect
+ style="opacity:1;color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237"
+ width="0.99953973"
+ height="0.99999803"
+ x="307.00046"
+ y="81" />
+ <rect
+ style="opacity:1;color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-6"
+ width="0.99953973"
+ height="0.99999803"
+ x="333.00046"
+ y="81" />
+ <rect
+ style="opacity:1;color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-6-8"
+ width="0.99953973"
+ height="0.99999803"
+ x="336.00046"
+ y="78" />
+ <rect
+ style="opacity:1;color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-6-8-5"
+ width="0.99953973"
+ height="0.99999803"
+ x="336.00046"
+ y="61" />
+ <rect
+ style="opacity:0.3;color:#000000;fill:none;stroke:url(#linearGradient4350);stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2846-28-6-4-0"
+ width="28"
+ height="27"
+ x="304.5"
+ y="128.5"
+ rx="3"
+ ry="3" />
+ <rect
+ style="color:#000000;fill:url(#radialGradient4444);fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:0.99999994000000003;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2846-28-66-3-9"
+ width="28"
+ height="26"
+ x="304.5"
+ y="128.5"
+ rx="3"
+ ry="3" />
+ <rect
+ ry="2"
+ rx="2"
+ y="129.5"
+ x="305.5"
+ height="20"
+ width="26"
+ id="rect3694-0-0-2"
+ style="opacity:0.3;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <g
+ id="g3752"
+ style="stroke:url(#linearGradient3756)">
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ id="rect2846-28-66-1-2"
+ d="m 304.5,147.5 0,5 c 0,1.662 1.338,3 3,3 l 22,0 c 1.662,0 3,-1.338 3,-3 l 0,-5 c 0,1.662 -1.338,3 -3,3 l -22,0 c -1.662,0 -3,-1.338 -3,-3 z"
+ style="color:#000000;fill:url(#linearGradient3092-9);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3756);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path3112-3"
+ d="m 318.5,150.5 0,5"
+ style="fill:none;stroke:url(#linearGradient3756);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;enable-background:new" />
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g4205-5"
+ transform="translate(-2,66)">
+ <path
+ id="rect3694-0-0-9-83"
+ d="m 307,84.5 0,2 c 0,1.367703 1.1323,2.5 2.5,2.5 l 10.5,0 0,-2 -10.5,0 c -0.0657,0 -0.1232,-0.02642 -0.1875,-0.03125 C 308.01204,86.871142 307,85.827989 307,84.5 z"
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.1;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ sodipodi:nodetypes="ccccccsc" />
+ <path
+ id="rect3694-0-0-9-8-9"
+ d="m 334,84.5 0,2 c 0,1.367703 -1.1323,2.5 -2.5,2.5 l -10.5,0 0,-2 10.5,0 c 0.0657,0 0.1232,-0.02642 0.1875,-0.03125 C 332.98796,86.871142 334,85.827989 334,84.5 z"
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.1;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ sodipodi:nodetypes="ccccccsc" />
+ </g>
+ <path
+ style="opacity:0.6;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 305.5,150.875 0,1.625 c 0,1.12494 0.87506,2 2,2 l 10,0 0,-3 -10,0 c -0.74347,0 -1.40165,-0.2674 -2,-0.625 z"
+ id="path3161-2-4"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="opacity:0.6;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 331.5,150.875 0,1.625 c 0,1.12494 -0.87506,2 -2,2 l -10,0 0,-3 10,0 c 0.74347,0 1.40165,-0.2674 2,-0.625 z"
+ id="path3161-2-0-7"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.4;color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ d="m 305,149.65625 0,1.3125 c 0.8401,0.63967 1.86264,1.03125 3,1.03125 l 10,0 0,-1 -10,0 c -1.20201,0 -2.2695,-0.51633 -3,-1.34375 z"
+ id="rect2846-28-66-0-7"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.4;color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ d="m 332,149.65625 0,1.3125 C 331.1599,151.60842 330.13736,152 329,152 l -10,0 0,-1 10,0 c 1.20201,0 2.2695,-0.51633 3,-1.34375 z"
+ id="rect2846-28-66-0-6-4"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="opacity:0.1;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline;enable-background:new"
+ d="m 310.49911,148.5 15.00265,0"
+ id="path4233-4"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="opacity:0.1;fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline;enable-background:new"
+ d="m 330.5,143.50442 0,-9.00884"
+ id="path4235-3"
+ sodipodi:nodetypes="cc" />
+ <rect
+ style="opacity:1;color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-5"
+ width="0.99953973"
+ height="0.99999803"
+ x="308.00046"
+ y="148" />
+ <rect
+ style="opacity:1;color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-6-80"
+ width="0.99953973"
+ height="0.99999803"
+ x="327.00046"
+ y="148" />
+ <rect
+ style="opacity:1;color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-6-8-3"
+ width="0.99953973"
+ height="0.99999803"
+ x="330.00046"
+ y="145" />
+ <rect
+ style="opacity:1;color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-6-8-5-0"
+ width="0.99953973"
+ height="0.99999803"
+ x="330.00046"
+ y="132" />
+ <g
+ id="g6998"
+ transform="translate(297.68228,160.06933)">
+ <rect
+ style="fill:#ef2929;fill-opacity:1;stroke:#a40000;stroke-width:1.00000012;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0"
+ id="rect5861"
+ width="7.9959006"
+ height="7.9958639"
+ x="12.802565"
+ y="26.419176"
+ rx="1.5753298"
+ ry="1.5876297" />
+ <g
+ id="g6991">
+ <rect
+ y="27.918909"
+ x="14.302099"
+ height="2"
+ width="2"
+ id="rect6981"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ <rect
+ y="30.918909"
+ x="14.302099"
+ height="2"
+ width="2"
+ id="rect6983"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ <rect
+ y="28.918909"
+ x="15.302099"
+ height="3.0000005"
+ width="2.9999998"
+ id="rect6985"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ <rect
+ y="30.918909"
+ x="17.302099"
+ height="2"
+ width="2"
+ id="rect6987"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ <rect
+ y="27.918909"
+ x="17.302099"
+ height="2"
+ width="2"
+ id="rect6989"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ </g>
+ </g>
+ <g
+ id="g7188"
+ transform="translate(300.694,231.07228)">
+ <rect
+ ry="1.1537831"
+ rx="1.0881115"
+ y="-6.0811005"
+ x="7.3020992"
+ height="7"
+ width="7"
+ id="rect7176"
+ style="fill:#ef2929;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ <rect
+ ry="0"
+ rx="0"
+ y="-5.0811005"
+ x="8.3020992"
+ height="2"
+ width="2"
+ id="rect7178"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ <rect
+ ry="0"
+ rx="0"
+ y="-5.0811005"
+ x="11.302099"
+ height="2"
+ width="2"
+ id="rect7180"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ <rect
+ ry="0"
+ rx="0"
+ y="-2.0811005"
+ x="11.302099"
+ height="2"
+ width="2"
+ id="rect7182"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ <rect
+ ry="0"
+ rx="0"
+ y="-2.0811005"
+ x="8.3020992"
+ height="2"
+ width="2"
+ id="rect7184"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ <rect
+ ry="0"
+ rx="0"
+ y="-4.0811005"
+ x="9.3020992"
+ height="3.0000005"
+ width="3.0000002"
+ id="rect7186"
+ style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none" />
+ </g>
+ <g
+ transform="matrix(0.9980467,0,0,0.9980473,271.08457,122.06151)"
+ id="g7081">
+ <rect
+ style="fill:#ef2929;fill-opacity:0.98473283;fill-rule:evenodd;stroke:#a40000;stroke-width:1.0019567;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:10.43299961;stroke-opacity:1;stroke-dasharray:none"
+ id="rect7069"
+ width="10.000005"
+ height="10"
+ x="42.5"
+ y="21.5"
+ rx="1.7585585"
+ ry="1.7585585" />
+ <g
+ id="g7075"
+ transform="matrix(0.7692308,0,0,0.7692308,2.5,6.1153846)">
+ <path
+ id="path7071"
+ d="m 56,24 5,5"
+ style="fill:none;stroke:#ffffff;stroke-width:1.69330692;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ <path
+ id="path7073"
+ d="m 56,29 5,-5"
+ style="fill:none;stroke:#ffffff;stroke-width:1.69330692;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ </g>
+ <rect
+ style="opacity:0.3;fill:none;stroke:#ffffff;stroke-width:1.00195682;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:10.43299961;stroke-opacity:1;stroke-dasharray:none"
+ id="rect7079"
+ width="8.0156603"
+ height="8.0156527"
+ x="43.492176"
+ y="22.492174"
+ rx="0.78614295"
+ ry="0.78614295" />
+ </g>
+ <g
+ id="layer4-3"
+ inkscape:label="Muted"
+ style="display:inline"
+ transform="translate(284.98438,57.984079)">
+ <g
+ id="g4694"
+ transform="translate(-2,0)">
+ <rect
+ ry="1.4868355"
+ rx="1.4868355"
+ y="16.498245"
+ x="31.498245"
+ height="12.00351"
+ width="12.00351"
+ id="rect2021"
+ style="fill:#ef2929;fill-opacity:1;stroke:#cc0000;stroke-width:0.9964897;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.20000057;display:inline" />
+ <rect
+ ry="0.4861359"
+ rx="0.4861359"
+ y="17.500002"
+ x="32.5"
+ height="9.9999962"
+ width="9.9999962"
+ id="rect3795"
+ style="opacity:0.3;fill:none;stroke:#ffffff;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.20000057;display:inline" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4682"
+ d="m 35,20 5,5"
+ style="fill:none;stroke:#ffffff;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4684"
+ d="m 40,20 -5,5"
+ style="fill:none;stroke:#ffffff;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
+ </g>
+ </g>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="hires"
+ style="display:inline" />
+ <g
+ id="g256"
+ style="display:inline;enable-background:new"
+ transform="translate(20,30)" />
+ <g
+ id="g4021"
+ style="display:inline;enable-background:new"
+ transform="translate(-577.97771,370.7754)" />
+ <g
+ transform="translate(-457.73144,-1.374928)"
+ id="g10306"
+ style="enable-background:new">
+ <g
+ id="layer3"
+ inkscape:label="plate"
+ style="display:none">
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect6282-8"
+ width="256"
+ height="256"
+ x="20"
+ y="20"
+ inkscape:label="256x256" />
+ <rect
+ inkscape:label="48x48"
+ y="39.99633"
+ x="296.0625"
+ height="48"
+ width="48"
+ id="rect6284-8"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect6592-5"
+ width="32"
+ height="32"
+ x="303"
+ y="115.99633"
+ inkscape:label="32x32" />
+ <rect
+ inkscape:label="22x22"
+ y="167.05884"
+ x="303"
+ height="22"
+ width="22"
+ id="rect6749-0"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect6833-9"
+ width="16"
+ height="16"
+ x="303"
+ y="209"
+ inkscape:label="16x16" />
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect5028"
+ width="24"
+ height="24"
+ x="301.95709"
+ y="165.95343"
+ inkscape:label="24x24" />
+ </g>
+ <g
+ id="layer1-6"
+ inkscape:label="artwork"
+ style="display:inline">
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate"
+ id="256x256"
+ width="256"
+ height="256"
+ x="23.5"
+ y="171.59863"
+ inkscape:label="256x256" />
+ <rect
+ y="171.59863"
+ x="-38.5"
+ height="48"
+ width="48"
+ id="48x48"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate"
+ inkscape:label="48x48" />
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate"
+ id="24x24"
+ width="24"
+ height="24"
+ x="-123.5"
+ y="171.59863"
+ inkscape:label="24x24" />
+ <rect
+ y="171.59863"
+ x="-155.5"
+ height="16"
+ width="16"
+ id="16x16"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate"
+ inkscape:label="16x16" />
+ <rect
+ inkscape:label="32x32"
+ y="171.59863"
+ x="-87.5"
+ height="32"
+ width="32"
+ id="32x32"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate" />
+ </g>
+ </g>
+ <g
+ id="g4445"
+ style="display:inline;enable-background:new"
+ transform="translate(-393,-62.246031)" />
+ <g
+ id="g5542"
+ style="display:inline;enable-background:new"
+ transform="translate(-364.39697,166.26869)" />
+ </g>
+</svg>
diff --git a/plugins/media-keys/touchpad-disabled.svg b/plugins/media-keys/touchpad-disabled.svg
new file mode 100644
index 0000000..4f1b37f
--- /dev/null
+++ b/plugins/media-keys/touchpad-disabled.svg
@@ -0,0 +1,833 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ height="38"
+ id="svg11300"
+ inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png"
+ inkscape:export-xdpi="90.000000"
+ inkscape:export-ydpi="90.000000"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="touchpad-disabled.svg"
+ sodipodi:version="0.32"
+ style="display:inline;enable-background:new"
+ version="1.0"
+ width="41">
+ <title
+ id="title3835">Touchpad</title>
+ <metadata
+ id="metadata154">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Touchpad</dc:title>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Lapo Calamandrei</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:contributor>
+ <dc:source />
+ <cc:license
+ rdf:resource="" />
+ <dc:subject>
+ <rdf:Bag />
+ </dc:subject>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ bordercolor="#666666"
+ borderopacity="0.25490196"
+ fill="#f57900"
+ gridtolerance="12"
+ guidetolerance="13"
+ height="300px"
+ id="base"
+ inkscape:current-layer="layer2"
+ inkscape:cx="133.90068"
+ inkscape:cy="-44.351844"
+ inkscape:document-units="px"
+ inkscape:grid-bbox="true"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:showpageshadow="false"
+ inkscape:snap-bbox="true"
+ inkscape:snap-nodes="true"
+ inkscape:window-height="975"
+ inkscape:window-width="1680"
+ inkscape:window-x="0"
+ inkscape:window-y="25"
+ inkscape:zoom="1.4142136"
+ objecttolerance="7"
+ pagecolor="#ffffff"
+ showgrid="false"
+ stroke="#ef2929"
+ width="400px"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ showborder="true"
+ inkscape:window-maximized="1">
+ <inkscape:grid
+ enabled="true"
+ id="grid5883"
+ spacingx="0.5px"
+ spacingy="0.5px"
+ type="xygrid"
+ visible="true"
+ empspacing="2"
+ snapvisiblegridlinesonly="true" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="13.98438,-101.46875"
+ id="guide4872" />
+ <sodipodi:guide
+ orientation="0,1"
+ position="12.32813,-102.98437"
+ id="guide4874" />
+ <sodipodi:guide
+ orientation="0,1"
+ position="12.90625,-61"
+ id="guide4876" />
+ <sodipodi:guide
+ orientation="1,0"
+ position="13,-46.3125"
+ id="guide4878" />
+ <sodipodi:guide
+ orientation="0,1"
+ position="41.64306,5.01592"
+ id="guide4880" />
+ </sodipodi:namedview>
+ <defs
+ id="defs3">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 150 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="400 : 150 : 1"
+ inkscape:persp3d-origin="200 : 100 : 1"
+ id="perspective147" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2972">
+ <stop
+ style="stop-color:#babdb6;stop-opacity:1"
+ offset="0"
+ id="stop2974" />
+ <stop
+ style="stop-color:#555753;stop-opacity:1"
+ offset="1"
+ id="stop2976" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3100">
+ <stop
+ id="stop3102"
+ offset="0"
+ style="stop-color:#babdb6;stop-opacity:1" />
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0.25"
+ id="stop3104" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="0.5"
+ id="stop3106" />
+ <stop
+ id="stop3108"
+ offset="0.75"
+ style="stop-color:#ffffff;stop-opacity:1" />
+ <stop
+ id="stop3110"
+ offset="1"
+ style="stop-color:#babdb6;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3743">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.2"
+ offset="0"
+ id="stop3745" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop3747" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3760-7"
+ id="radialGradient3766-2"
+ cx="311"
+ cy="225.23932"
+ fx="311"
+ fy="225.23932"
+ r="8"
+ gradientTransform="matrix(1.4590081,0,0,1.0942561,-142.75153,-21.969492)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3760-7">
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0"
+ id="stop3762-0" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="1"
+ id="stop3764-5" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3752-2">
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="0"
+ id="stop3754-2" />
+ <stop
+ style="stop-color:#babdb6;stop-opacity:1"
+ offset="1"
+ id="stop3756-8" />
+ </linearGradient>
+ <linearGradient
+ y2="238.1875"
+ x2="324.875"
+ y1="231.5"
+ x1="304.8125"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3794"
+ xlink:href="#linearGradient3752-2"
+ inkscape:collect="always"
+ gradientTransform="translate(0,-1)" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3760-7-6"
+ id="radialGradient3766-2-5"
+ cx="312.09396"
+ cy="224.27068"
+ fx="312.09396"
+ fy="224.27068"
+ r="8"
+ gradientTransform="matrix(2.0157047,0,0,1.5117786,-315.08929,-153.04762)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3760-7-6">
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0"
+ id="stop3762-0-6" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="1"
+ id="stop3764-5-1" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3752-2-3">
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="0"
+ id="stop3754-2-2" />
+ <stop
+ style="stop-color:#babdb6;stop-opacity:1"
+ offset="1"
+ id="stop3756-8-6" />
+ </linearGradient>
+ <linearGradient
+ y2="238.1875"
+ x2="324.875"
+ y1="231.5"
+ x1="304.8125"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2894"
+ xlink:href="#linearGradient3752-2-3"
+ inkscape:collect="always"
+ gradientTransform="translate(1,-38)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3743"
+ id="linearGradient3749"
+ x1="304"
+ y1="177"
+ x2="304"
+ y2="195"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3760-7-6-4"
+ id="radialGradient3766-2-5-1"
+ cx="312.09396"
+ cy="224.27068"
+ fx="312.09396"
+ fy="224.27068"
+ r="8"
+ gradientTransform="matrix(3.7131449,0,0,3.563472,-838.85008,-725.00376)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3760-7-6-4">
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0"
+ id="stop3762-0-6-6" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="1"
+ id="stop3764-5-1-4" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3743-4">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.2"
+ offset="0"
+ id="stop3745-6" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop3747-2" />
+ </linearGradient>
+ <linearGradient
+ y2="195"
+ x2="304"
+ y1="177"
+ x1="304"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2910"
+ xlink:href="#linearGradient3743-4"
+ inkscape:collect="always"
+ gradientTransform="matrix(1.9473685,0,0,1.9444446,-291.47369,-291.58337)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3100"
+ id="linearGradient3092"
+ x1="302"
+ y1="82.375"
+ x2="338"
+ y2="92.75"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3100-5"
+ id="linearGradient3092-9"
+ x1="305.89941"
+ y1="83.784264"
+ x2="334.10059"
+ y2="91.340736"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-2,66)" />
+ <linearGradient
+ id="linearGradient3100-5">
+ <stop
+ id="stop3102-6"
+ offset="0"
+ style="stop-color:#babdb6;stop-opacity:1" />
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0.25"
+ id="stop3104-13" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="0.5"
+ id="stop3106-5" />
+ <stop
+ id="stop3108-50"
+ offset="0.75"
+ style="stop-color:#ffffff;stop-opacity:1" />
+ <stop
+ id="stop3110-4"
+ offset="1"
+ style="stop-color:#babdb6;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3743-4-4">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.2"
+ offset="0"
+ id="stop3745-6-8" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop3747-2-3" />
+ </linearGradient>
+ <linearGradient
+ y2="195"
+ x2="304"
+ y1="180.95102"
+ x1="304"
+ gradientTransform="matrix(1.8448754,0,0,1.8333335,-257.26455,-204.75003)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4350"
+ xlink:href="#linearGradient3743-4-4"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3760-7-6-4-66-6">
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0"
+ id="stop3762-0-6-6-61-7" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="1"
+ id="stop3764-5-1-4-0-6" />
+ </linearGradient>
+ <radialGradient
+ r="8"
+ fy="222.91086"
+ fx="312.22864"
+ cy="222.91086"
+ cx="312.22864"
+ gradientTransform="matrix(2.8880002,0,0,2.9155676,-583.21633,-511.91208)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient4444"
+ xlink:href="#linearGradient3760-7-6-4-66-6"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2972"
+ id="linearGradient2978"
+ x1="315.81155"
+ y1="82.20932"
+ x2="315.81155"
+ y2="89.25135"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2972"
+ id="linearGradient3756"
+ x1="318.5"
+ y1="147.03621"
+ x2="318.5"
+ y2="155.96379"
+ gradientUnits="userSpaceOnUse" />
+ <inkscape:perspective
+ id="perspective3111"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective3912"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective4331"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <inkscape:perspective
+ id="perspective4799"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2972"
+ id="linearGradient2988"
+ gradientUnits="userSpaceOnUse"
+ x1="315.81155"
+ y1="82.20932"
+ x2="315.81155"
+ y2="89.25135" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2972"
+ id="linearGradient2990"
+ gradientUnits="userSpaceOnUse"
+ x1="315.81155"
+ y1="82.20932"
+ x2="315.81155"
+ y2="89.25135" />
+ </defs>
+ <g
+ id="layer1"
+ inkscape:groupmode="layer"
+ inkscape:label="artwork"
+ style="display:inline"
+ transform="translate(-300,-54)">
+ <g
+ inkscape:groupmode="layer"
+ id="layer5"
+ inkscape:label="disabled"
+ style="display:none"
+ sodipodi:insensitive="true">
+ <rect
+ height="256"
+ id="rect6282"
+ inkscape:label="256x256"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="256"
+ x="16"
+ y="28" />
+ </g>
+ <g
+ id="layer6"
+ inkscape:groupmode="layer"
+ inkscape:label="baseplate"
+ style="display:none">
+ <rect
+ height="48"
+ id="rect6284"
+ inkscape:label="48x48"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="48"
+ x="296"
+ y="50" />
+ <rect
+ height="32"
+ id="rect6592"
+ inkscape:label="32x32"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="32"
+ x="303"
+ y="126" />
+ <rect
+ height="22"
+ id="rect6749"
+ inkscape:label="22x22"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="22"
+ x="303"
+ y="177" />
+ <rect
+ height="16"
+ id="rect6833"
+ inkscape:label="16x16"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="16"
+ x="303"
+ y="219" />
+ <rect
+ height="24"
+ id="rect8104"
+ inkscape:label="24x24"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="24"
+ x="302"
+ y="176" />
+ <text
+ id="context"
+ inkscape:label="context"
+ style="font-size:18.30070686px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;enable-background:new;font-family:Bitstream Vera Sans"
+ x="20.970737"
+ xml:space="preserve"
+ y="21.513618"><tspan
+ id="tspan2716"
+ sodipodi:role="line"
+ x="20.970737"
+ y="21.513618">devices</tspan></text>
+ <text
+ id="icon-name"
+ inkscape:label="icon-name"
+ sodipodi:linespacing="125%"
+ style="font-size:18.30070686px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;enable-background:new;font-family:Droid Sans;-inkscape-font-specification:Droid Sans Bold"
+ x="141.97073"
+ xml:space="preserve"
+ y="21.513618"><tspan
+ id="tspan3023"
+ sodipodi:role="line"
+ x="141.97073"
+ y="21.513618">input-touchpad</tspan></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="small sizes"
+ style="display:inline">
+ <rect
+ style="opacity:0.3;color:#000000;fill:none;stroke:url(#linearGradient2910);stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2846-28-6-4"
+ width="38"
+ height="35"
+ x="301.5"
+ y="55.5"
+ rx="4"
+ ry="4" />
+ <rect
+ style="color:#000000;fill:url(#radialGradient3766-2-5-1);fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2846-28-66"
+ width="35.999939"
+ height="33.000004"
+ x="302.50006"
+ y="56.499996"
+ rx="3.0000038"
+ ry="3.0000038" />
+ <rect
+ ry="2"
+ rx="2"
+ y="57.5"
+ x="303.5"
+ height="25"
+ width="34"
+ id="rect3694-0-0"
+ style="opacity:0.3;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <g
+ id="g4205">
+ <path
+ id="rect3694-0-0-9"
+ d="m 303,84.5 0,2 c 0,1.367703 1.1323,2.5 2.5,2.5 l 14.5,0 0,-2 -14.5,0 c -0.0657,0 -0.1232,-0.02642 -0.1875,-0.03125 C 304.01204,86.871142 303,85.827989 303,84.5 z"
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.1;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane" />
+ <path
+ id="rect3694-0-0-9-8"
+ d="m 338,84.5 0,2 c 0,1.367703 -1.1323,2.5 -2.5,2.5 l -14.5,0 0,-2 14.5,0 c 0.0657,0 0.1232,-0.02642 0.1875,-0.03125 C 336.98796,86.871142 338,85.827989 338,84.5 z"
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.1;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane" />
+ </g>
+ <g
+ id="g2958"
+ style="fill-opacity:1;stroke:url(#linearGradient2978)">
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ id="rect2846-28-66-1"
+ d="m 302.5,80.5 0,6 c 0,1.662002 1.338,3 3,3 l 30,0 c 1.662,0 3,-1.337998 3,-3 l 0,-6 c 0,1.662002 -1.338,3 -3,3 l -30,0 c -1.662,0 -3,-1.337998 -3,-3 z"
+ style="color:#000000;fill:url(#linearGradient3092);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2988);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <path
+ id="path3112"
+ d="m 320.5,83.5 0,6"
+ style="fill:none;stroke:url(#linearGradient2990);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ </g>
+ <path
+ style="opacity:0.5;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 303.5,83.875 0,2.625 c 0,1.12494 0.87506,2 2,2 l 14,0 0,-4 -14,0 c -0.74347,0 -1.40165,-0.267405 -2,-0.625 z"
+ id="path3161-2"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="opacity:0.5;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 337.5,83.875 0,2.625 c 0,1.12494 -0.87506,2 -2,2 l -14,0 0,-4 14,0 c 0.74347,0 1.40165,-0.267405 2,-0.625 z"
+ id="path3161-2-0"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.4;color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ d="m 303,82.65625 0,1.3125 C 303.8401,84.608417 304.86264,85 306,85 l 14,0 0,-1 -14,0 c -1.20201,0 -2.2695,-0.516326 -3,-1.34375 z"
+ id="rect2846-28-66-0" />
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.4;color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ d="m 338,82.65625 0,1.3125 C 337.1599,84.608417 336.13736,85 335,85 l -14,0 0,-1 14,0 c 1.20201,0 2.2695,-0.516326 3,-1.34375 z"
+ id="rect2846-28-66-0-6" />
+ <path
+ style="opacity:0.1;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 309.49911,81.5 22.00265,0"
+ id="path4233" />
+ <path
+ style="opacity:0.1;fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 336.5,76.504425 0,-13.00885"
+ id="path4235" />
+ <rect
+ style="color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237"
+ width="0.99953973"
+ height="0.99999803"
+ x="307.00046"
+ y="81" />
+ <rect
+ style="color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-6"
+ width="0.99953973"
+ height="0.99999803"
+ x="333.00046"
+ y="81" />
+ <rect
+ style="color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-6-8"
+ width="0.99953973"
+ height="0.99999803"
+ x="336.00046"
+ y="78" />
+ <rect
+ style="color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-6-8-5"
+ width="0.99953973"
+ height="0.99999803"
+ x="336.00046"
+ y="61" />
+ <g
+ id="layer4-3"
+ inkscape:label="Muted"
+ style="display:inline"
+ transform="translate(284.98438,57.984079)">
+ <g
+ id="g4694"
+ transform="translate(-2,0)">
+ <rect
+ ry="1.4868355"
+ rx="1.4868355"
+ y="16.498245"
+ x="31.498245"
+ height="12.00351"
+ width="12.00351"
+ id="rect2021"
+ style="fill:#ef2929;fill-opacity:1;stroke:#cc0000;stroke-width:0.9964897;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.20000057;display:inline" />
+ <rect
+ ry="0.4861359"
+ rx="0.4861359"
+ y="17.500002"
+ x="32.5"
+ height="9.9999962"
+ width="9.9999962"
+ id="rect3795"
+ style="opacity:0.3;fill:none;stroke:#ffffff;stroke-width:0.99999988;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:1.20000057;display:inline" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4682"
+ d="m 35,20 5,5"
+ style="fill:none;stroke:#ffffff;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4684"
+ d="m 40,20 -5,5"
+ style="fill:none;stroke:#ffffff;stroke-width:1.5;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
+ </g>
+ </g>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="hires"
+ style="display:inline" />
+ <g
+ id="g256"
+ style="display:inline;enable-background:new"
+ transform="translate(20,30)" />
+ <g
+ id="g4021"
+ style="display:inline;enable-background:new"
+ transform="translate(-577.97771,370.7754)" />
+ <g
+ transform="translate(-457.73144,-1.374928)"
+ id="g10306"
+ style="enable-background:new">
+ <g
+ id="layer3"
+ inkscape:label="plate"
+ style="display:none">
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect6282-8"
+ width="256"
+ height="256"
+ x="20"
+ y="20"
+ inkscape:label="256x256" />
+ <rect
+ inkscape:label="48x48"
+ y="39.99633"
+ x="296.0625"
+ height="48"
+ width="48"
+ id="rect6284-8"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect6592-5"
+ width="32"
+ height="32"
+ x="303"
+ y="115.99633"
+ inkscape:label="32x32" />
+ <rect
+ inkscape:label="22x22"
+ y="167.05884"
+ x="303"
+ height="22"
+ width="22"
+ id="rect6749-0"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect6833-9"
+ width="16"
+ height="16"
+ x="303"
+ y="209"
+ inkscape:label="16x16" />
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect5028"
+ width="24"
+ height="24"
+ x="301.95709"
+ y="165.95343"
+ inkscape:label="24x24" />
+ </g>
+ <g
+ id="layer1-6"
+ inkscape:label="artwork"
+ style="display:inline">
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate"
+ id="256x256"
+ width="256"
+ height="256"
+ x="23.5"
+ y="171.59863"
+ inkscape:label="256x256" />
+ <rect
+ y="171.59863"
+ x="-38.5"
+ height="48"
+ width="48"
+ id="48x48"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate"
+ inkscape:label="48x48" />
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate"
+ id="24x24"
+ width="24"
+ height="24"
+ x="-123.5"
+ y="171.59863"
+ inkscape:label="24x24" />
+ <rect
+ y="171.59863"
+ x="-155.5"
+ height="16"
+ width="16"
+ id="16x16"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate"
+ inkscape:label="16x16" />
+ <rect
+ inkscape:label="32x32"
+ y="171.59863"
+ x="-87.5"
+ height="32"
+ width="32"
+ id="32x32"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate" />
+ </g>
+ </g>
+ <g
+ id="g4445"
+ style="display:inline;enable-background:new"
+ transform="translate(-393,-62.246031)" />
+ <g
+ id="g5542"
+ style="display:inline;enable-background:new"
+ transform="translate(-364.39697,166.26869)" />
+ </g>
+</svg>
diff --git a/plugins/media-keys/touchpad-enabled-16.png b/plugins/media-keys/touchpad-enabled-16.png
new file mode 100644
index 0000000..58fc1d4
--- /dev/null
+++ b/plugins/media-keys/touchpad-enabled-16.png
Binary files differ
diff --git a/plugins/media-keys/touchpad-enabled-22.png b/plugins/media-keys/touchpad-enabled-22.png
new file mode 100644
index 0000000..ae23118
--- /dev/null
+++ b/plugins/media-keys/touchpad-enabled-22.png
Binary files differ
diff --git a/plugins/media-keys/touchpad-enabled-24.png b/plugins/media-keys/touchpad-enabled-24.png
new file mode 100644
index 0000000..b8617e9
--- /dev/null
+++ b/plugins/media-keys/touchpad-enabled-24.png
Binary files differ
diff --git a/plugins/media-keys/touchpad-enabled-32.png b/plugins/media-keys/touchpad-enabled-32.png
new file mode 100644
index 0000000..7bbfa48
--- /dev/null
+++ b/plugins/media-keys/touchpad-enabled-32.png
Binary files differ
diff --git a/plugins/media-keys/touchpad-enabled-48.png b/plugins/media-keys/touchpad-enabled-48.png
new file mode 100644
index 0000000..ebad680
--- /dev/null
+++ b/plugins/media-keys/touchpad-enabled-48.png
Binary files differ
diff --git a/plugins/media-keys/touchpad-enabled-template.svg b/plugins/media-keys/touchpad-enabled-template.svg
new file mode 100644
index 0000000..fe07b68
--- /dev/null
+++ b/plugins/media-keys/touchpad-enabled-template.svg
@@ -0,0 +1,936 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ height="300"
+ id="svg11300"
+ inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png"
+ inkscape:export-xdpi="90.000000"
+ inkscape:export-ydpi="90.000000"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:version="0.47pre4 r22446"
+ sodipodi:docname="input-touchpad.svg"
+ sodipodi:version="0.32"
+ style="display:inline;enable-background:new"
+ version="1.0"
+ width="400">
+ <title
+ id="title3835">Touchpad</title>
+ <metadata
+ id="metadata154">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Touchpad</dc:title>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Lapo Calamandrei</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:contributor>
+ <dc:source />
+ <cc:license
+ rdf:resource="" />
+ <dc:subject>
+ <rdf:Bag />
+ </dc:subject>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ bordercolor="#666666"
+ borderopacity="0.25490196"
+ fill="#f57900"
+ gridtolerance="12"
+ guidetolerance="13"
+ height="300px"
+ id="base"
+ inkscape:current-layer="layer2"
+ inkscape:cx="329.26576"
+ inkscape:cy="97.934968"
+ inkscape:document-units="px"
+ inkscape:grid-bbox="true"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:showpageshadow="false"
+ inkscape:snap-bbox="true"
+ inkscape:snap-nodes="true"
+ inkscape:window-height="935"
+ inkscape:window-width="968"
+ inkscape:window-x="213"
+ inkscape:window-y="37"
+ inkscape:zoom="1"
+ objecttolerance="7"
+ pagecolor="#ffffff"
+ showgrid="false"
+ stroke="#ef2929"
+ width="400px"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ showborder="true"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ enabled="true"
+ id="grid5883"
+ spacingx="0.5px"
+ spacingy="0.5px"
+ type="xygrid"
+ visible="true"
+ empspacing="2"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <defs
+ id="defs3">
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2972">
+ <stop
+ style="stop-color:#babdb6;stop-opacity:1"
+ offset="0"
+ id="stop2974" />
+ <stop
+ style="stop-color:#555753;stop-opacity:1"
+ offset="1"
+ id="stop2976" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3100">
+ <stop
+ id="stop3102"
+ offset="0"
+ style="stop-color:#babdb6;stop-opacity:1" />
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0.25"
+ id="stop3104" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="0.5"
+ id="stop3106" />
+ <stop
+ id="stop3108"
+ offset="0.75"
+ style="stop-color:#ffffff;stop-opacity:1" />
+ <stop
+ id="stop3110"
+ offset="1"
+ style="stop-color:#babdb6;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3743">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.2"
+ offset="0"
+ id="stop3745" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop3747" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3760-7"
+ id="radialGradient3766-2"
+ cx="311"
+ cy="225.23932"
+ fx="311"
+ fy="225.23932"
+ r="8"
+ gradientTransform="matrix(1.4590081,0,0,1.0942561,-142.75153,-21.969492)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3760-7">
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0"
+ id="stop3762-0" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="1"
+ id="stop3764-5" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3752-2">
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="0"
+ id="stop3754-2" />
+ <stop
+ style="stop-color:#babdb6;stop-opacity:1"
+ offset="1"
+ id="stop3756-8" />
+ </linearGradient>
+ <linearGradient
+ y2="238.1875"
+ x2="324.875"
+ y1="231.5"
+ x1="304.8125"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient3794"
+ xlink:href="#linearGradient3752-2"
+ inkscape:collect="always"
+ gradientTransform="translate(0,-1)" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3760-7-6"
+ id="radialGradient3766-2-5"
+ cx="312.09396"
+ cy="224.27068"
+ fx="312.09396"
+ fy="224.27068"
+ r="8"
+ gradientTransform="matrix(2.0157047,0,0,1.5117786,-315.08929,-153.04762)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3760-7-6">
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0"
+ id="stop3762-0-6" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="1"
+ id="stop3764-5-1" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3752-2-3">
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="0"
+ id="stop3754-2-2" />
+ <stop
+ style="stop-color:#babdb6;stop-opacity:1"
+ offset="1"
+ id="stop3756-8-6" />
+ </linearGradient>
+ <linearGradient
+ y2="238.1875"
+ x2="324.875"
+ y1="231.5"
+ x1="304.8125"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2894"
+ xlink:href="#linearGradient3752-2-3"
+ inkscape:collect="always"
+ gradientTransform="translate(1,-38)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3743"
+ id="linearGradient3749"
+ x1="304"
+ y1="177"
+ x2="304"
+ y2="195"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3760-7-6-4"
+ id="radialGradient3766-2-5-1"
+ cx="312.09396"
+ cy="224.27068"
+ fx="312.09396"
+ fy="224.27068"
+ r="8"
+ gradientTransform="matrix(3.7131449,0,0,3.563472,-838.85008,-725.00376)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3760-7-6-4">
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0"
+ id="stop3762-0-6-6" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="1"
+ id="stop3764-5-1-4" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3743-4">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.2"
+ offset="0"
+ id="stop3745-6" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop3747-2" />
+ </linearGradient>
+ <linearGradient
+ y2="195"
+ x2="304"
+ y1="177"
+ x1="304"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2910"
+ xlink:href="#linearGradient3743-4"
+ inkscape:collect="always"
+ gradientTransform="matrix(1.9473685,0,0,1.9444446,-291.47369,-291.58337)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3100"
+ id="linearGradient3092"
+ x1="302"
+ y1="82.375"
+ x2="338"
+ y2="92.75"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3100-5"
+ id="linearGradient3092-9"
+ x1="305.89941"
+ y1="83.784264"
+ x2="334.10059"
+ y2="91.340736"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="translate(-2,66)" />
+ <linearGradient
+ id="linearGradient3100-5">
+ <stop
+ id="stop3102-6"
+ offset="0"
+ style="stop-color:#babdb6;stop-opacity:1" />
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0.25"
+ id="stop3104-13" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="0.5"
+ id="stop3106-5" />
+ <stop
+ id="stop3108-50"
+ offset="0.75"
+ style="stop-color:#ffffff;stop-opacity:1" />
+ <stop
+ id="stop3110-4"
+ offset="1"
+ style="stop-color:#babdb6;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3743-4-4">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.2"
+ offset="0"
+ id="stop3745-6-8" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop3747-2-3" />
+ </linearGradient>
+ <linearGradient
+ y2="195"
+ x2="304"
+ y1="180.95102"
+ x1="304"
+ gradientTransform="matrix(1.8448754,0,0,1.8333335,-257.26455,-204.75003)"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient4350"
+ xlink:href="#linearGradient3743-4-4"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3760-7-6-4-66-6">
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0"
+ id="stop3762-0-6-6-61-7" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="1"
+ id="stop3764-5-1-4-0-6" />
+ </linearGradient>
+ <radialGradient
+ r="8"
+ fy="222.91086"
+ fx="312.22864"
+ cy="222.91086"
+ cx="312.22864"
+ gradientTransform="matrix(2.8880002,0,0,2.9155676,-583.21633,-511.91208)"
+ gradientUnits="userSpaceOnUse"
+ id="radialGradient4444"
+ xlink:href="#linearGradient3760-7-6-4-66-6"
+ inkscape:collect="always" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2972"
+ id="linearGradient2978"
+ x1="315.81155"
+ y1="82.20932"
+ x2="315.81155"
+ y2="89.25135"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2972"
+ id="linearGradient3756"
+ x1="318.5"
+ y1="147.03621"
+ x2="318.5"
+ y2="155.96379"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <g
+ id="layer1"
+ inkscape:groupmode="layer"
+ inkscape:label="artwork"
+ style="display:inline">
+ <g
+ inkscape:groupmode="layer"
+ id="layer5"
+ inkscape:label="disabled"
+ style="display:none"
+ sodipodi:insensitive="true">
+ <rect
+ height="256"
+ id="rect6282"
+ inkscape:label="256x256"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="256"
+ x="16"
+ y="28" />
+ </g>
+ <g
+ id="layer6"
+ inkscape:groupmode="layer"
+ inkscape:label="baseplate"
+ style="display:none">
+ <rect
+ height="48"
+ id="rect6284"
+ inkscape:label="48x48"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="48"
+ x="296"
+ y="50" />
+ <rect
+ height="32"
+ id="rect6592"
+ inkscape:label="32x32"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="32"
+ x="303"
+ y="126" />
+ <rect
+ height="22"
+ id="rect6749"
+ inkscape:label="22x22"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="22"
+ x="303"
+ y="177" />
+ <rect
+ height="16"
+ id="rect6833"
+ inkscape:label="16x16"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="16"
+ x="303"
+ y="219" />
+ <rect
+ height="24"
+ id="rect8104"
+ inkscape:label="24x24"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="24"
+ x="302"
+ y="176" />
+ <text
+ id="context"
+ inkscape:label="context"
+ style="font-size:18.30070686px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;enable-background:new;font-family:Bitstream Vera Sans"
+ x="20.970737"
+ xml:space="preserve"
+ y="21.513618"><tspan
+ id="tspan2716"
+ sodipodi:role="line"
+ x="20.970737"
+ y="21.513618">devices</tspan></text>
+ <text
+ id="icon-name"
+ inkscape:label="icon-name"
+ sodipodi:linespacing="125%"
+ style="font-size:18.30070686px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;enable-background:new;font-family:Droid Sans;-inkscape-font-specification:Droid Sans Bold"
+ x="141.97073"
+ xml:space="preserve"
+ y="21.513618"><tspan
+ id="tspan3023"
+ sodipodi:role="line"
+ x="141.97073"
+ y="21.513618">input-touchpad</tspan></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="small sizes"
+ style="display:inline">
+ <path
+ style="color:#000000;fill:url(#linearGradient3794);fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 303.5,227.5 0,4 c 0,1.108 0.892,2 2,2 l 11,0 c 1.108,0 2,-0.892 2,-2 l 0,-4 c 0,1.108 -0.892,2 -2,2 l -11,0 c -1.108,0 -2,-0.892 -2,-2 z"
+ id="rect2846-2-3"
+ sodipodi:nodetypes="ccccccccc" />
+ <rect
+ style="color:#000000;fill:url(#radialGradient3766-2);fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2846"
+ width="15"
+ height="10"
+ x="303.5"
+ y="219.5"
+ rx="2"
+ ry="2" />
+ <rect
+ style="opacity:0.3;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect3694"
+ width="13"
+ height="12"
+ x="304.5"
+ y="220.5"
+ rx="1"
+ ry="1" />
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ d="m 304,229.5 0,1 c 0,0.0541 0.002,0.1029 0,0.15625 0.45244,0.21377 0.96717,0.34375 1.5,0.34375 l 11,0 c 0.53283,0 1.04756,-0.12998 1.5,-0.34375 L 318,229.5 c -0.41577,0.30853 -0.93558,0.5 -1.5,0.5 l -11,0 c -0.56442,0 -1.08423,-0.19147 -1.5,-0.5 z"
+ id="rect2846-2"
+ sodipodi:nodetypes="cccccccccc" />
+ <rect
+ style="color:#000000;fill:#d3d7cf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect3728"
+ width="1"
+ height="3"
+ x="310"
+ y="230"
+ rx="0"
+ ry="0" />
+ <rect
+ style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect3728-4"
+ width="1"
+ height="3"
+ x="311"
+ y="230"
+ rx="0"
+ ry="0" />
+ <rect
+ style="opacity:0.3;color:#000000;fill:none;stroke:url(#linearGradient3749);stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2846-28-6"
+ width="19"
+ height="18"
+ x="304.5"
+ y="178.5"
+ rx="2"
+ ry="2" />
+ <path
+ style="color:#000000;fill:url(#linearGradient2894);fill-opacity:1;fill-rule:nonzero;stroke:#888a85;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 304.5,190.5 0,4 c 0,1.108 0.892,2 2,2 l 15,0 c 1.108,0 2,-0.892 2,-2 l 0,-4 c 0,1.108 -0.892,2 -2,2 l -15,0 c -1.108,0 -2,-0.892 -2,-2 z"
+ id="rect2846-2-3-0"
+ sodipodi:nodetypes="ccccccccc" />
+ <rect
+ style="color:#000000;fill:url(#radialGradient3766-2-5);fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2846-28"
+ width="18.999943"
+ height="14.000024"
+ x="304.5"
+ y="178.5"
+ rx="2"
+ ry="2" />
+ <rect
+ style="opacity:0.3;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect3694-0"
+ width="17.000095"
+ height="16.000011"
+ x="305.5"
+ y="179.5"
+ rx="1"
+ ry="1" />
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ d="m 305,192.5 0,1 c 0,0.0541 0.002,0.1029 0,0.15625 0.45244,0.21377 0.96717,0.34375 1.5,0.34375 l 15,0 c 0.53283,0 1.04756,-0.12998 1.5,-0.34375 L 323,192.5 c -0.41577,0.30853 -0.93558,0.5 -1.5,0.5 l -15,0 c -0.56442,0 -1.08423,-0.19147 -1.5,-0.5 z"
+ id="rect2846-2-1"
+ sodipodi:nodetypes="cccccccccc" />
+ <rect
+ style="color:#000000;fill:#d3d7cf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect3728-5"
+ width="1"
+ height="3"
+ x="313"
+ y="193"
+ rx="0"
+ ry="0" />
+ <rect
+ style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect3728-4-5"
+ width="1"
+ height="3"
+ x="314"
+ y="193"
+ rx="0"
+ ry="0" />
+ <rect
+ style="opacity:0.3;color:#000000;fill:none;stroke:url(#linearGradient2910);stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2846-28-6-4"
+ width="38"
+ height="35"
+ x="301.5"
+ y="55.5"
+ rx="4"
+ ry="4" />
+ <rect
+ style="color:#000000;fill:url(#radialGradient3766-2-5-1);fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2846-28-66"
+ width="35.999939"
+ height="33.000004"
+ x="302.50006"
+ y="56.499996"
+ rx="3.0000038"
+ ry="3.0000038" />
+ <rect
+ ry="2"
+ rx="2"
+ y="57.5"
+ x="303.5"
+ height="25"
+ width="34"
+ id="rect3694-0-0"
+ style="opacity:0.3;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <g
+ id="g4205">
+ <path
+ id="rect3694-0-0-9"
+ d="m 303,84.5 0,2 c 0,1.367703 1.1323,2.5 2.5,2.5 l 14.5,0 0,-2 -14.5,0 c -0.0657,0 -0.1232,-0.02642 -0.1875,-0.03125 C 304.01204,86.871142 303,85.827989 303,84.5 z"
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.1;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane" />
+ <path
+ id="rect3694-0-0-9-8"
+ d="m 338,84.5 0,2 c 0,1.367703 -1.1323,2.5 -2.5,2.5 l -14.5,0 0,-2 14.5,0 c 0.0657,0 0.1232,-0.02642 0.1875,-0.03125 C 336.98796,86.871142 338,85.827989 338,84.5 z"
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.1;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane" />
+ </g>
+ <g
+ id="g2958"
+ style="fill-opacity:1;stroke:url(#linearGradient2978)">
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ id="rect2846-28-66-1"
+ d="m 302.5,80.5 0,6 c 0,1.662002 1.338,3 3,3 l 30,0 c 1.662,0 3,-1.337998 3,-3 l 0,-6 c 0,1.662002 -1.338,3 -3,3 l -30,0 c -1.662,0 -3,-1.337998 -3,-3 z"
+ style="color:#000000;fill:url(#linearGradient3092);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2978);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <path
+ id="path3112"
+ d="m 320.5,83.5 0,6"
+ style="fill:none;stroke:url(#linearGradient2978);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;fill-opacity:1" />
+ </g>
+ <path
+ style="opacity:0.5;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 303.5,83.875 0,2.625 c 0,1.12494 0.87506,2 2,2 l 14,0 0,-4 -14,0 c -0.74347,0 -1.40165,-0.267405 -2,-0.625 z"
+ id="path3161-2"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="opacity:0.5;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 337.5,83.875 0,2.625 c 0,1.12494 -0.87506,2 -2,2 l -14,0 0,-4 14,0 c 0.74347,0 1.40165,-0.267405 2,-0.625 z"
+ id="path3161-2-0"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.4;color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ d="m 303,82.65625 0,1.3125 C 303.8401,84.608417 304.86264,85 306,85 l 14,0 0,-1 -14,0 c -1.20201,0 -2.2695,-0.516326 -3,-1.34375 z"
+ id="rect2846-28-66-0" />
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.4;color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ d="m 338,82.65625 0,1.3125 C 337.1599,84.608417 336.13736,85 335,85 l -14,0 0,-1 14,0 c 1.20201,0 2.2695,-0.516326 3,-1.34375 z"
+ id="rect2846-28-66-0-6" />
+ <path
+ style="opacity:0.1;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 309.49911,81.5 22.00265,0"
+ id="path4233" />
+ <path
+ style="opacity:0.1;fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 336.5,76.504425 0,-13.00885"
+ id="path4235" />
+ <rect
+ style="opacity:1;color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237"
+ width="0.99953973"
+ height="0.99999803"
+ x="307.00046"
+ y="81" />
+ <rect
+ style="opacity:1;color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-6"
+ width="0.99953973"
+ height="0.99999803"
+ x="333.00046"
+ y="81" />
+ <rect
+ style="opacity:1;color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-6-8"
+ width="0.99953973"
+ height="0.99999803"
+ x="336.00046"
+ y="78" />
+ <rect
+ style="opacity:1;color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-6-8-5"
+ width="0.99953973"
+ height="0.99999803"
+ x="336.00046"
+ y="61" />
+ <rect
+ style="opacity:0.3;color:#000000;fill:none;stroke:url(#linearGradient4350);stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2846-28-6-4-0"
+ width="28"
+ height="27"
+ x="304.5"
+ y="128.5"
+ rx="3"
+ ry="3" />
+ <rect
+ style="color:#000000;fill:url(#radialGradient4444);fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:0.99999994000000003;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2846-28-66-3-9"
+ width="28"
+ height="26"
+ x="304.5"
+ y="128.5"
+ rx="3"
+ ry="3" />
+ <rect
+ ry="2"
+ rx="2"
+ y="129.5"
+ x="305.5"
+ height="20"
+ width="26"
+ id="rect3694-0-0-2"
+ style="opacity:0.3;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <g
+ id="g3752"
+ style="stroke:url(#linearGradient3756)">
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ id="rect2846-28-66-1-2"
+ d="m 304.5,147.5 0,5 c 0,1.662 1.338,3 3,3 l 22,0 c 1.662,0 3,-1.338 3,-3 l 0,-5 c 0,1.662 -1.338,3 -3,3 l -22,0 c -1.662,0 -3,-1.338 -3,-3 z"
+ style="color:#000000;fill:url(#linearGradient3092-9);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient3756);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path3112-3"
+ d="m 318.5,150.5 0,5"
+ style="fill:none;stroke:url(#linearGradient3756);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;display:inline;enable-background:new" />
+ </g>
+ <g
+ style="display:inline;enable-background:new"
+ id="g4205-5"
+ transform="translate(-2,66)">
+ <path
+ id="rect3694-0-0-9-83"
+ d="m 307,84.5 0,2 c 0,1.367703 1.1323,2.5 2.5,2.5 l 10.5,0 0,-2 -10.5,0 c -0.0657,0 -0.1232,-0.02642 -0.1875,-0.03125 C 308.01204,86.871142 307,85.827989 307,84.5 z"
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.1;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ sodipodi:nodetypes="ccccccsc" />
+ <path
+ id="rect3694-0-0-9-8-9"
+ d="m 334,84.5 0,2 c 0,1.367703 -1.1323,2.5 -2.5,2.5 l -10.5,0 0,-2 10.5,0 c 0.0657,0 0.1232,-0.02642 0.1875,-0.03125 C 332.98796,86.871142 334,85.827989 334,84.5 z"
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.1;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ sodipodi:nodetypes="ccccccsc" />
+ </g>
+ <path
+ style="opacity:0.6;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 305.5,150.875 0,1.625 c 0,1.12494 0.87506,2 2,2 l 10,0 0,-3 -10,0 c -0.74347,0 -1.40165,-0.2674 -2,-0.625 z"
+ id="path3161-2-4"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="opacity:0.6;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 331.5,150.875 0,1.625 c 0,1.12494 -0.87506,2 -2,2 l -10,0 0,-3 10,0 c 0.74347,0 1.40165,-0.2674 2,-0.625 z"
+ id="path3161-2-0-7"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.4;color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ d="m 305,149.65625 0,1.3125 c 0.8401,0.63967 1.86264,1.03125 3,1.03125 l 10,0 0,-1 -10,0 c -1.20201,0 -2.2695,-0.51633 -3,-1.34375 z"
+ id="rect2846-28-66-0-7"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.4;color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ d="m 332,149.65625 0,1.3125 C 331.1599,151.60842 330.13736,152 329,152 l -10,0 0,-1 10,0 c 1.20201,0 2.2695,-0.51633 3,-1.34375 z"
+ id="rect2846-28-66-0-6-4"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="opacity:0.1;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline;enable-background:new"
+ d="m 310.49911,148.5 15.00265,0"
+ id="path4233-4"
+ sodipodi:nodetypes="cc" />
+ <path
+ style="opacity:0.1;fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1;display:inline;enable-background:new"
+ d="m 330.5,143.50442 0,-9.00884"
+ id="path4235-3"
+ sodipodi:nodetypes="cc" />
+ <rect
+ style="opacity:1;color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-5"
+ width="0.99953973"
+ height="0.99999803"
+ x="308.00046"
+ y="148" />
+ <rect
+ style="opacity:1;color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-6-80"
+ width="0.99953973"
+ height="0.99999803"
+ x="327.00046"
+ y="148" />
+ <rect
+ style="opacity:1;color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-6-8-3"
+ width="0.99953973"
+ height="0.99999803"
+ x="330.00046"
+ y="145" />
+ <rect
+ style="opacity:1;color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-6-8-5-0"
+ width="0.99953973"
+ height="0.99999803"
+ x="330.00046"
+ y="132" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="hires"
+ style="display:inline" />
+ <g
+ id="g256"
+ style="display:inline;enable-background:new"
+ transform="translate(20,30)" />
+ <g
+ id="g4021"
+ style="display:inline;enable-background:new"
+ transform="translate(-577.97771,370.7754)" />
+ <g
+ transform="translate(-457.73144,-1.374928)"
+ id="g10306"
+ style="enable-background:new">
+ <g
+ id="layer3"
+ inkscape:label="plate"
+ style="display:none">
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect6282-8"
+ width="256"
+ height="256"
+ x="20"
+ y="20"
+ inkscape:label="256x256" />
+ <rect
+ inkscape:label="48x48"
+ y="39.99633"
+ x="296.0625"
+ height="48"
+ width="48"
+ id="rect6284-8"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect6592-5"
+ width="32"
+ height="32"
+ x="303"
+ y="115.99633"
+ inkscape:label="32x32" />
+ <rect
+ inkscape:label="22x22"
+ y="167.05884"
+ x="303"
+ height="22"
+ width="22"
+ id="rect6749-0"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect6833-9"
+ width="16"
+ height="16"
+ x="303"
+ y="209"
+ inkscape:label="16x16" />
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect5028"
+ width="24"
+ height="24"
+ x="301.95709"
+ y="165.95343"
+ inkscape:label="24x24" />
+ </g>
+ <g
+ id="layer1-6"
+ inkscape:label="artwork"
+ style="display:inline">
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate"
+ id="256x256"
+ width="256"
+ height="256"
+ x="23.5"
+ y="171.59863"
+ inkscape:label="256x256" />
+ <rect
+ y="171.59863"
+ x="-38.5"
+ height="48"
+ width="48"
+ id="48x48"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate"
+ inkscape:label="48x48" />
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate"
+ id="24x24"
+ width="24"
+ height="24"
+ x="-123.5"
+ y="171.59863"
+ inkscape:label="24x24" />
+ <rect
+ y="171.59863"
+ x="-155.5"
+ height="16"
+ width="16"
+ id="16x16"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate"
+ inkscape:label="16x16" />
+ <rect
+ inkscape:label="32x32"
+ y="171.59863"
+ x="-87.5"
+ height="32"
+ width="32"
+ id="32x32"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate" />
+ </g>
+ </g>
+ <g
+ id="g4445"
+ style="display:inline;enable-background:new"
+ transform="translate(-393,-62.246031)" />
+ <g
+ id="g5542"
+ style="display:inline;enable-background:new"
+ transform="translate(-364.39697,166.26869)" />
+ </g>
+</svg>
diff --git a/plugins/media-keys/touchpad-enabled.svg b/plugins/media-keys/touchpad-enabled.svg
new file mode 100644
index 0000000..98fa258
--- /dev/null
+++ b/plugins/media-keys/touchpad-enabled.svg
@@ -0,0 +1,581 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ height="38"
+ id="svg11300"
+ inkscape:export-filename="/home/jimmac/Desktop/wi-fi.png"
+ inkscape:export-xdpi="90.000000"
+ inkscape:export-ydpi="90.000000"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="touchpad-enabled.svg"
+ sodipodi:version="0.32"
+ style="display:inline;enable-background:new"
+ version="1.0"
+ width="41">
+ <title
+ id="title3835">Touchpad</title>
+ <metadata
+ id="metadata154">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title>Touchpad</dc:title>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>Lapo Calamandrei</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:contributor>
+ <dc:source />
+ <cc:license
+ rdf:resource="" />
+ <dc:subject>
+ <rdf:Bag />
+ </dc:subject>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ bordercolor="#666666"
+ borderopacity="0.25490196"
+ fill="#f57900"
+ gridtolerance="12"
+ guidetolerance="13"
+ height="300px"
+ id="base"
+ inkscape:current-layer="layer2"
+ inkscape:cx="29.26576"
+ inkscape:cy="-112.06503"
+ inkscape:document-units="px"
+ inkscape:grid-bbox="true"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:showpageshadow="false"
+ inkscape:snap-bbox="true"
+ inkscape:snap-nodes="true"
+ inkscape:window-height="935"
+ inkscape:window-width="968"
+ inkscape:window-x="213"
+ inkscape:window-y="37"
+ inkscape:zoom="1"
+ objecttolerance="7"
+ pagecolor="#ffffff"
+ showgrid="false"
+ stroke="#ef2929"
+ width="400px"
+ showguides="true"
+ inkscape:guide-bbox="true"
+ showborder="true"
+ inkscape:window-maximized="0">
+ <inkscape:grid
+ enabled="true"
+ id="grid5883"
+ spacingx="0.5px"
+ spacingy="0.5px"
+ type="xygrid"
+ visible="true"
+ empspacing="2"
+ snapvisiblegridlinesonly="true" />
+ </sodipodi:namedview>
+ <defs
+ id="defs3">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 150 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="400 : 150 : 1"
+ inkscape:persp3d-origin="200 : 100 : 1"
+ id="perspective147" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2972">
+ <stop
+ style="stop-color:#babdb6;stop-opacity:1"
+ offset="0"
+ id="stop2974" />
+ <stop
+ style="stop-color:#555753;stop-opacity:1"
+ offset="1"
+ id="stop2976" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient3100">
+ <stop
+ id="stop3102"
+ offset="0"
+ style="stop-color:#babdb6;stop-opacity:1" />
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0.25"
+ id="stop3104" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="0.5"
+ id="stop3106" />
+ <stop
+ id="stop3108"
+ offset="0.75"
+ style="stop-color:#ffffff;stop-opacity:1" />
+ <stop
+ id="stop3110"
+ offset="1"
+ style="stop-color:#babdb6;stop-opacity:1" />
+ </linearGradient>
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3760-7-6-4"
+ id="radialGradient3766-2-5-1"
+ cx="312.09396"
+ cy="224.27068"
+ fx="312.09396"
+ fy="224.27068"
+ r="8"
+ gradientTransform="matrix(3.7131449,0,0,3.563472,-838.85008,-725.00376)"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3760-7-6-4">
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0"
+ id="stop3762-0-6-6" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="1"
+ id="stop3764-5-1-4" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient3743-4">
+ <stop
+ style="stop-color:#000000;stop-opacity:0.2"
+ offset="0"
+ id="stop3745-6" />
+ <stop
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="1"
+ id="stop3747-2" />
+ </linearGradient>
+ <linearGradient
+ y2="195"
+ x2="304"
+ y1="177"
+ x1="304"
+ gradientUnits="userSpaceOnUse"
+ id="linearGradient2910"
+ xlink:href="#linearGradient3743-4"
+ inkscape:collect="always"
+ gradientTransform="matrix(1.9473685,0,0,1.9444446,-291.47369,-291.58337)" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient3100"
+ id="linearGradient3092"
+ x1="302"
+ y1="82.375"
+ x2="338"
+ y2="92.75"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ id="linearGradient3100-5">
+ <stop
+ id="stop3102-6"
+ offset="0"
+ style="stop-color:#babdb6;stop-opacity:1" />
+ <stop
+ style="stop-color:#eeeeec;stop-opacity:1"
+ offset="0.25"
+ id="stop3104-13" />
+ <stop
+ style="stop-color:#d3d7cf;stop-opacity:1"
+ offset="0.5"
+ id="stop3106-5" />
+ <stop
+ id="stop3108-50"
+ offset="0.75"
+ style="stop-color:#ffffff;stop-opacity:1" />
+ <stop
+ id="stop3110-4"
+ offset="1"
+ style="stop-color:#babdb6;stop-opacity:1" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2972"
+ id="linearGradient2978"
+ x1="315.81155"
+ y1="82.20932"
+ x2="315.81155"
+ y2="89.25135"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2972"
+ id="linearGradient3756"
+ x1="318.5"
+ y1="147.03621"
+ x2="318.5"
+ y2="155.96379"
+ gradientUnits="userSpaceOnUse" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2972"
+ id="linearGradient2953"
+ gradientUnits="userSpaceOnUse"
+ x1="315.81155"
+ y1="82.20932"
+ x2="315.81155"
+ y2="89.25135" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2972"
+ id="linearGradient2955"
+ gradientUnits="userSpaceOnUse"
+ x1="315.81155"
+ y1="82.20932"
+ x2="315.81155"
+ y2="89.25135" />
+ </defs>
+ <g
+ id="layer1"
+ inkscape:groupmode="layer"
+ inkscape:label="artwork"
+ style="display:inline"
+ transform="translate(-300,-54)">
+ <g
+ inkscape:groupmode="layer"
+ id="layer5"
+ inkscape:label="disabled"
+ style="display:none"
+ sodipodi:insensitive="true">
+ <rect
+ height="256"
+ id="rect6282"
+ inkscape:label="256x256"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="256"
+ x="16"
+ y="28" />
+ </g>
+ <g
+ id="layer6"
+ inkscape:groupmode="layer"
+ inkscape:label="baseplate"
+ style="display:none">
+ <rect
+ height="48"
+ id="rect6284"
+ inkscape:label="48x48"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="48"
+ x="296"
+ y="50" />
+ <rect
+ height="32"
+ id="rect6592"
+ inkscape:label="32x32"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="32"
+ x="303"
+ y="126" />
+ <rect
+ height="22"
+ id="rect6749"
+ inkscape:label="22x22"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="22"
+ x="303"
+ y="177" />
+ <rect
+ height="16"
+ id="rect6833"
+ inkscape:label="16x16"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="16"
+ x="303"
+ y="219" />
+ <rect
+ height="24"
+ id="rect8104"
+ inkscape:label="24x24"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ width="24"
+ x="302"
+ y="176" />
+ <text
+ id="context"
+ inkscape:label="context"
+ style="font-size:18.30070686px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;display:inline;enable-background:new;font-family:Bitstream Vera Sans"
+ x="20.970737"
+ xml:space="preserve"
+ y="21.513618"><tspan
+ id="tspan2716"
+ sodipodi:role="line"
+ x="20.970737"
+ y="21.513618">devices</tspan></text>
+ <text
+ id="icon-name"
+ inkscape:label="icon-name"
+ sodipodi:linespacing="125%"
+ style="font-size:18.30070686px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;display:inline;enable-background:new;font-family:Droid Sans;-inkscape-font-specification:Droid Sans Bold"
+ x="141.97073"
+ xml:space="preserve"
+ y="21.513618"><tspan
+ id="tspan3023"
+ sodipodi:role="line"
+ x="141.97073"
+ y="21.513618">input-touchpad</tspan></text>
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="small sizes"
+ style="display:inline">
+ <rect
+ style="opacity:0.3;color:#000000;fill:none;stroke:url(#linearGradient2910);stroke-width:3;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2846-28-6-4"
+ width="38"
+ height="35"
+ x="301.5"
+ y="55.5"
+ rx="4"
+ ry="4" />
+ <rect
+ style="color:#000000;fill:url(#radialGradient3766-2-5-1);fill-opacity:1;fill-rule:nonzero;stroke:#babdb6;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect2846-28-66"
+ width="35.999939"
+ height="33.000004"
+ x="302.50006"
+ y="56.499996"
+ rx="3.0000038"
+ ry="3.0000038" />
+ <rect
+ ry="2"
+ rx="2"
+ y="57.5"
+ x="303.5"
+ height="25"
+ width="34"
+ id="rect3694-0-0"
+ style="opacity:0.3;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <g
+ id="g4205">
+ <path
+ id="rect3694-0-0-9"
+ d="m 303,84.5 0,2 c 0,1.367703 1.1323,2.5 2.5,2.5 l 14.5,0 0,-2 -14.5,0 c -0.0657,0 -0.1232,-0.02642 -0.1875,-0.03125 C 304.01204,86.871142 303,85.827989 303,84.5 z"
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.1;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane" />
+ <path
+ id="rect3694-0-0-9-8"
+ d="m 338,84.5 0,2 c 0,1.367703 -1.1323,2.5 -2.5,2.5 l -14.5,0 0,-2 14.5,0 c 0.0657,0 0.1232,-0.02642 0.1875,-0.03125 C 336.98796,86.871142 338,85.827989 338,84.5 z"
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.1;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane" />
+ </g>
+ <g
+ id="g2958"
+ style="fill-opacity:1;stroke:url(#linearGradient2978)">
+ <path
+ sodipodi:nodetypes="ccccccccc"
+ id="rect2846-28-66-1"
+ d="m 302.5,80.5 0,6 c 0,1.662002 1.338,3 3,3 l 30,0 c 1.662,0 3,-1.337998 3,-3 l 0,-6 c 0,1.662002 -1.338,3 -3,3 l -30,0 c -1.662,0 -3,-1.337998 -3,-3 z"
+ style="color:#000000;fill:url(#linearGradient3092);fill-opacity:1;fill-rule:nonzero;stroke:url(#linearGradient2953);stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <path
+ id="path3112"
+ d="m 320.5,83.5 0,6"
+ style="fill:none;stroke:url(#linearGradient2955);stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
+ </g>
+ <path
+ style="opacity:0.5;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 303.5,83.875 0,2.625 c 0,1.12494 0.87506,2 2,2 l 14,0 0,-4 -14,0 c -0.74347,0 -1.40165,-0.267405 -2,-0.625 z"
+ id="path3161-2"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="opacity:0.5;color:#000000;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ d="m 337.5,83.875 0,2.625 c 0,1.12494 -0.87506,2 -2,2 l -14,0 0,-4 14,0 c 0.74347,0 1.40165,-0.267405 2,-0.625 z"
+ id="path3161-2-0"
+ sodipodi:nodetypes="ccccccc" />
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.4;color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ d="m 303,82.65625 0,1.3125 C 303.8401,84.608417 304.86264,85 306,85 l 14,0 0,-1 -14,0 c -1.20201,0 -2.2695,-0.516326 -3,-1.34375 z"
+ id="rect2846-28-66-0" />
+ <path
+ style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;opacity:0.4;color:#000000;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Abandoned Bitplane;-inkscape-font-specification:Abandoned Bitplane"
+ d="m 338,82.65625 0,1.3125 C 337.1599,84.608417 336.13736,85 335,85 l -14,0 0,-1 14,0 c 1.20201,0 2.2695,-0.516326 3,-1.34375 z"
+ id="rect2846-28-66-0-6" />
+ <path
+ style="opacity:0.1;fill:none;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 309.49911,81.5 22.00265,0"
+ id="path4233" />
+ <path
+ style="opacity:0.1;fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1"
+ d="m 336.5,76.504425 0,-13.00885"
+ id="path4235" />
+ <rect
+ style="color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237"
+ width="0.99953973"
+ height="0.99999803"
+ x="307.00046"
+ y="81" />
+ <rect
+ style="color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-6"
+ width="0.99953973"
+ height="0.99999803"
+ x="333.00046"
+ y="81" />
+ <rect
+ style="color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-6-8"
+ width="0.99953973"
+ height="0.99999803"
+ x="336.00046"
+ y="78" />
+ <rect
+ style="color:#000000;fill:#729fcf;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect4237-6-8-5"
+ width="0.99953973"
+ height="0.99999803"
+ x="336.00046"
+ y="61" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer4"
+ inkscape:label="hires"
+ style="display:inline" />
+ <g
+ id="g256"
+ style="display:inline;enable-background:new"
+ transform="translate(20,30)" />
+ <g
+ id="g4021"
+ style="display:inline;enable-background:new"
+ transform="translate(-577.97771,370.7754)" />
+ <g
+ transform="translate(-457.73144,-1.374928)"
+ id="g10306"
+ style="enable-background:new">
+ <g
+ id="layer3"
+ inkscape:label="plate"
+ style="display:none">
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect6282-8"
+ width="256"
+ height="256"
+ x="20"
+ y="20"
+ inkscape:label="256x256" />
+ <rect
+ inkscape:label="48x48"
+ y="39.99633"
+ x="296.0625"
+ height="48"
+ width="48"
+ id="rect6284-8"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect6592-5"
+ width="32"
+ height="32"
+ x="303"
+ y="115.99633"
+ inkscape:label="32x32" />
+ <rect
+ inkscape:label="22x22"
+ y="167.05884"
+ x="303"
+ height="22"
+ width="22"
+ id="rect6749-0"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect6833-9"
+ width="16"
+ height="16"
+ x="303"
+ y="209"
+ inkscape:label="16x16" />
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="rect5028"
+ width="24"
+ height="24"
+ x="301.95709"
+ y="165.95343"
+ inkscape:label="24x24" />
+ </g>
+ <g
+ id="layer1-6"
+ inkscape:label="artwork"
+ style="display:inline">
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate"
+ id="256x256"
+ width="256"
+ height="256"
+ x="23.5"
+ y="171.59863"
+ inkscape:label="256x256" />
+ <rect
+ y="171.59863"
+ x="-38.5"
+ height="48"
+ width="48"
+ id="48x48"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate"
+ inkscape:label="48x48" />
+ <rect
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate"
+ id="24x24"
+ width="24"
+ height="24"
+ x="-123.5"
+ y="171.59863"
+ inkscape:label="24x24" />
+ <rect
+ y="171.59863"
+ x="-155.5"
+ height="16"
+ width="16"
+ id="16x16"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate"
+ inkscape:label="16x16" />
+ <rect
+ inkscape:label="32x32"
+ y="171.59863"
+ x="-87.5"
+ height="32"
+ width="32"
+ id="32x32"
+ style="fill:#eeeeec;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:5;marker:none;visibility:visible;display:none;overflow:visible;enable-background:accumulate" />
+ </g>
+ </g>
+ <g
+ id="g4445"
+ style="display:inline;enable-background:new"
+ transform="translate(-393,-62.246031)" />
+ <g
+ id="g5542"
+ style="display:inline;enable-background:new"
+ transform="translate(-364.39697,166.26869)" />
+ </g>
+</svg>