diff options
-rw-r--r-- | .bzrignore | 4 | ||||
-rw-r--r-- | configure.ac | 6 | ||||
-rw-r--r-- | debian/changelog | 13 | ||||
-rw-r--r-- | debian/control | 1 | ||||
-rwxr-xr-x | debian/rules | 2 | ||||
-rw-r--r-- | libindicator/Makefile.am | 2 | ||||
-rw-r--r-- | libindicator/indicator-desktop-shortcuts.c | 523 | ||||
-rw-r--r-- | libindicator/indicator-desktop-shortcuts.h | 74 | ||||
-rw-r--r-- | tests/Makefile.am | 36 | ||||
-rw-r--r-- | tests/test-desktop-shortcuts.c | 137 | ||||
-rw-r--r-- | tests/test-well-formed.desktop | 24 |
11 files changed, 820 insertions, 2 deletions
@@ -147,3 +147,7 @@ libindicator/indicator-object-marshal.c libindicator/indicator-object-marshal.h libindicator/libindicator_la-indicator-object-marshal.lo libindicator/stamp-marshal +libindicator/libindicator_la-indicator-desktop-shortcuts.lo +tests/test-desktop-shortcuts +tests/test-desktop-shortcuts-tester +tests/test-desktop-shortcuts-touch-test diff --git a/configure.ac b/configure.ac index a816206..24293c5 100644 --- a/configure.ac +++ b/configure.ac @@ -1,10 +1,10 @@ -AC_INIT(libindicator, 0.3.2, ted@canonical.com) +AC_INIT(libindicator, 0.3.3, ted@canonical.com) AC_PREREQ(2.53) AM_CONFIG_HEADER(config.h) -AM_INIT_AUTOMAKE(libindicator, 0.3.2) +AM_INIT_AUTOMAKE(libindicator, 0.3.3) AM_MAINTAINER_MODE m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES]) @@ -28,8 +28,10 @@ m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) GTK_REQUIRED_VERSION=2.18 DBUS_REQUIRED_VERSION=0.76 +GIO_UNIX_REQUIRED_VERSION=2.23 PKG_CHECK_MODULES(LIBINDICATOR, gtk+-2.0 >= $GTK_REQUIRED_VERSION + gio-unix-2.0 >= $GIO_UNIX_REQUIRED_VERSION dbus-glib-1 >= $DBUS_REQUIRED_VERSION) AC_SUBST(LIBINDICATOR_CFLAGS) diff --git a/debian/changelog b/debian/changelog index fd1e0eb..12f819d 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,16 @@ +libindicator (0.3.3-0ubuntu1) lucid; urgency=low + + * debian/control: + - build-depends on libglib2.0-dev + * debian/rules: + - updated shlibs version + + [ Ted Gould ] + * Upstream release 0.3.3 + * Adding new object for parsing desktop files for Shortcuts + + -- Sebastien Bacher <seb128@ubuntu.com> Thu, 18 Feb 2010 17:32:08 +0100 + libindicator (0.3.2-0ubuntu1) lucid; urgency=low * Upstream release 0.3.2 diff --git a/debian/control b/debian/control index aa6d787..52a36ed 100644 --- a/debian/control +++ b/debian/control @@ -4,6 +4,7 @@ Priority: optional Maintainer: Ubuntu Core Developers <ubuntu-devel-discuss@lists.ubuntu.com> Build-Depends: debhelper (>= 5.0), cdbs (>= 0.4.41), + libglib2.0-dev (>= 2.23), libgtk2.0-dev (>= 2.12.0), libdbus-glib-1-dev, libtool, diff --git a/debian/rules b/debian/rules index 744b984..5ee8f88 100755 --- a/debian/rules +++ b/debian/rules @@ -4,3 +4,5 @@ include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/class/gnome.mk LDFLAGS += -Wl,-z,defs -Wl,--as-needed + +DEB_DH_MAKESHLIBS_ARGS_libindicator0 += -V 'libindicator0 (>= 0.3.3)' diff --git a/libindicator/Makefile.am b/libindicator/Makefile.am index 19247ce..467e09a 100644 --- a/libindicator/Makefile.am +++ b/libindicator/Makefile.am @@ -10,6 +10,7 @@ libindicatorincludedir=$(includedir)/libindicator-0.3/libindicator indicator_headers = \ indicator.h \ + indicator-desktop-shortcuts.h \ indicator-object.h \ indicator-service.h \ indicator-service-manager.h @@ -24,6 +25,7 @@ libindicator_la_SOURCES = \ $(indicator_headers) \ dbus-shared.h \ indicator-object.c \ + indicator-desktop-shortcuts.c \ indicator-object-marshal.h \ indicator-object-marshal.c \ indicator-service.c \ diff --git a/libindicator/indicator-desktop-shortcuts.c b/libindicator/indicator-desktop-shortcuts.c new file mode 100644 index 0000000..e86a6ab --- /dev/null +++ b/libindicator/indicator-desktop-shortcuts.c @@ -0,0 +1,523 @@ +/* +A small file to parse through the actions that are available +in the desktop file and making those easily usable. + +Copyright 2010 Canonical Ltd. + +Authors: + Ted Gould <ted@canonical.com> + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 3.0 as published by the Free Software Foundation. + +This library 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 version 3.0 for more details. + +You should have received a copy of the GNU General Public +License along with this library. If not, see +<http://www.gnu.org/licenses/>. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gio/gdesktopappinfo.h> +#include "indicator-desktop-shortcuts.h" + +#define GROUP_SUFFIX "Shortcut Group" +#define SHORTCUTS_KEY "X-Ayatana-Desktop-Shortcuts" + +#define PROP_DESKTOP_FILE_S "desktop-file" +#define PROP_IDENTITY_S "identity" + +typedef struct _IndicatorDesktopShortcutsPrivate IndicatorDesktopShortcutsPrivate; +struct _IndicatorDesktopShortcutsPrivate { + GKeyFile * keyfile; + gchar * identity; + GArray * nicks; +}; + +enum { + PROP_0, + PROP_DESKTOP_FILE, + PROP_IDENTITY +}; + +#define INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), INDICATOR_TYPE_DESKTOP_SHORTCUTS, IndicatorDesktopShortcutsPrivate)) + +static void indicator_desktop_shortcuts_class_init (IndicatorDesktopShortcutsClass *klass); +static void indicator_desktop_shortcuts_init (IndicatorDesktopShortcuts *self); +static void indicator_desktop_shortcuts_dispose (GObject *object); +static void indicator_desktop_shortcuts_finalize (GObject *object); +static void set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); +static void get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); +static void parse_keyfile (IndicatorDesktopShortcuts * ids); +static gboolean should_show (GKeyFile * keyfile, const gchar * group, const gchar * identity); + +G_DEFINE_TYPE (IndicatorDesktopShortcuts, indicator_desktop_shortcuts, G_TYPE_OBJECT); + +/* Build up the class */ +static void +indicator_desktop_shortcuts_class_init (IndicatorDesktopShortcutsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (IndicatorDesktopShortcutsPrivate)); + + object_class->dispose = indicator_desktop_shortcuts_dispose; + object_class->finalize = indicator_desktop_shortcuts_finalize; + + /* Property funcs */ + object_class->set_property = set_property; + object_class->get_property = get_property; + + g_object_class_install_property(object_class, PROP_DESKTOP_FILE, + g_param_spec_string(PROP_DESKTOP_FILE_S, + "The path of the desktop file to read", + "A path to a desktop file that we'll look for shortcuts in.", + NULL, + G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property(object_class, PROP_IDENTITY, + g_param_spec_string(PROP_IDENTITY_S, + "The string that represents the identity that we're acting as.", + "Used to process ShowIn and NotShownIn fields of the desktop shortcust to get the proper list.", + NULL, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY)); + + return; +} + +/* Initialize instance data */ +static void +indicator_desktop_shortcuts_init (IndicatorDesktopShortcuts *self) +{ + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(self); + + priv->keyfile = NULL; + priv->identity = NULL; + priv->nicks = g_array_new(TRUE, TRUE, sizeof(gchar *)); + + return; +} + +/* Clear object references */ +static void +indicator_desktop_shortcuts_dispose (GObject *object) +{ + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(object); + + if (priv->keyfile) { + g_key_file_free(priv->keyfile); + priv->keyfile = NULL; + } + + G_OBJECT_CLASS (indicator_desktop_shortcuts_parent_class)->dispose (object); + return; +} + +/* Free all memory */ +static void +indicator_desktop_shortcuts_finalize (GObject *object) +{ + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(object); + + if (priv->identity != NULL) { + g_free(priv->identity); + priv->identity = NULL; + } + + if (priv->nicks != NULL) { + gint i; + for (i = 0; i < priv->nicks->len; i++) { + gchar * nick = g_array_index(priv->nicks, gchar *, i); + g_free(nick); + } + g_array_free(priv->nicks, TRUE); + priv->nicks = NULL; + } + + G_OBJECT_CLASS (indicator_desktop_shortcuts_parent_class)->finalize (object); + return; +} + +/* Sets one of the two properties we have, only at construction though */ +static void +set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) +{ + g_return_if_fail(INDICATOR_IS_DESKTOP_SHORTCUTS(object)); + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(object); + + switch(prop_id) { + case PROP_DESKTOP_FILE: { + GError * error = NULL; + GKeyFile * keyfile = g_key_file_new(); + g_key_file_load_from_file(keyfile, g_value_get_string(value), G_KEY_FILE_NONE, &error); + + if (error != NULL) { + g_warning("Unable to load keyfile from file '%s': %s", g_value_get_string(value), error->message); + g_error_free(error); + g_key_file_free(keyfile); + break; + } + + if (!g_key_file_has_key(keyfile, G_KEY_FILE_DESKTOP_GROUP, SHORTCUTS_KEY, NULL)) { + g_warning("Keyfile from file '%s' does not have '" SHORTCUTS_KEY "' key", g_value_get_string(value)); + g_key_file_free(keyfile); + break; + } + + priv->keyfile = keyfile; + parse_keyfile(INDICATOR_DESKTOP_SHORTCUTS(object)); + break; + } + case PROP_IDENTITY: + if (priv->identity != NULL) { + g_warning("Identity already set to '%s' and trying to set it to '%s'.", priv->identity, g_value_get_string(value)); + return; + } + priv->identity = g_value_dup_string(value); + parse_keyfile(INDICATOR_DESKTOP_SHORTCUTS(object)); + break; + /* *********************** */ + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + + return; +} + +/* Gets either the desktop file our the identity. */ +static void +get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) +{ + g_return_if_fail(INDICATOR_IS_DESKTOP_SHORTCUTS(object)); + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(object); + + switch(prop_id) { + case PROP_IDENTITY: + g_value_set_string(value, priv->identity); + break; + /* *********************** */ + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } + + return; +} + +/* Checks to see if we can, and if we can it goes through + and parses the keyfile entries. */ +static void +parse_keyfile (IndicatorDesktopShortcuts * ids) +{ + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(ids); + + if (priv->keyfile == NULL) { + return; + } + + if (priv->identity == NULL) { + return; + } + + /* Okay, we've got everything we need. Let's get it on! */ + gint i; + gsize num_nicks = 0; + gchar ** nicks = g_key_file_get_string_list(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, SHORTCUTS_KEY, &num_nicks, NULL); + + /* If there is an error from get_string_list num_nicks should still + be zero, so this loop will drop out. */ + for (i = 0; i < num_nicks; i++) { + /* g_debug("Looking at group nick %s", nicks[i]); */ + gchar * groupname = g_strdup_printf("%s " GROUP_SUFFIX, nicks[i]); + if (!g_key_file_has_group(priv->keyfile, groupname)) { + g_warning("Unable to find group '%s'", groupname); + g_free(groupname); + continue; + } + + if (!should_show(priv->keyfile, G_KEY_FILE_DESKTOP_GROUP, priv->identity)) { + g_free(groupname); + continue; + } + + if (!should_show(priv->keyfile, groupname, priv->identity)) { + g_free(groupname); + continue; + } + + gchar * nickalloc = g_strdup(nicks[i]); + g_array_append_val(priv->nicks, nickalloc); + } + + if (nicks != NULL) { + g_strfreev(nicks); + } + + return; +} + +/* Checks the ONLY_SHOW_IN and NOT_SHOW_IN keys for a group to + see if we should be showing ourselves. */ +static gboolean +should_show (GKeyFile * keyfile, const gchar * group, const gchar * identity) +{ + /* If there is a list of OnlyShowIn entries we need to check + to see if we're in that list. If not, we drop this nick */ + if (g_key_file_has_key(keyfile, group, G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN, NULL)) { + gint j; + gsize num_only = 0; + gchar ** onlies = g_key_file_get_string_list(keyfile, group, G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN, &num_only, NULL); + + for (j = 0; j < num_only; j++) { + if (g_strcmp0(onlies[j], identity) == 0) { + break; + } + } + + if (onlies != NULL) { + g_strfreev(onlies); + } + + if (j == num_only) { + return FALSE; + } + } + + /* If there is a NotShowIn entry we need to make sure that we're + not in that list. If we are, we need to drop out. */ + if (g_key_file_has_key(keyfile, group, G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN, NULL)) { + gint j; + gsize num_not = 0; + gchar ** nots = g_key_file_get_string_list(keyfile, group, G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN, &num_not, NULL); + + for (j = 0; j < num_not; j++) { + if (g_strcmp0(nots[j], identity) == 0) { + break; + } + } + + if (nots != NULL) { + g_strfreev(nots); + } + + if (j != num_not) { + return FALSE; + } + } + + return TRUE; +} + +/* Looks through the nicks ot see if this one is in the list, + and thus valid to use. */ +static gboolean +is_valid_nick (gchar ** list, const gchar * nick) +{ + if (*list == NULL) + return FALSE; + /* g_debug("Checking Nick: %s", list[0]); */ + if (g_strcmp0(list[0], nick) == 0) + return TRUE; + return is_valid_nick(&list[1], nick); +} + +/* API */ + +/** + indicator_desktop_shortcuts_new: + @file: The desktop file that would be opened to + find the actions. + @identity: This is a string that represents the identity + that should be used in searching those actions. It + relates to the ShowIn and NotShownIn properties. + + This function creates the basic object. It involves opening + the file and parsing it. It could potentially block on IO. At + the end of the day you'll have a fully functional object. + + Return value: A new #IndicatorDesktopShortcuts object. +*/ +IndicatorDesktopShortcuts * +indicator_desktop_shortcuts_new (const gchar * file, const gchar * identity) +{ + GObject * obj = g_object_new(INDICATOR_TYPE_DESKTOP_SHORTCUTS, + PROP_DESKTOP_FILE_S, file, + PROP_IDENTITY_S, identity, + NULL); + return INDICATOR_DESKTOP_SHORTCUTS(obj); +} + +/** + indicator_desktop_shortcuts_get_nicks: + @ids: The #IndicatorDesktopShortcuts object to look in + + Give you the list of commands that are available for this desktop + file given the identity that was passed in at creation. This will + filter out the various items in the desktop file. These nicks can + then be used as keys for working with the desktop file. + + Return value: A #NULL terminated list of strings. This memory + is managed by the @ids object. +*/ +const gchar ** +indicator_desktop_shortcuts_get_nicks (IndicatorDesktopShortcuts * ids) +{ + g_return_val_if_fail(INDICATOR_IS_DESKTOP_SHORTCUTS(ids), NULL); + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(ids); + return (const gchar **)priv->nicks->data; +} + +/** + indicator_desktop_shortcuts_nick_get_name: + @ids: The #IndicatorDesktopShortcuts object to look in + @nick: Which command that we're referencing. + + This function looks in a desktop file for a nick to find the + user visible name for that shortcut. The @nick parameter + should be gotten from #indicator_desktop_shortcuts_get_nicks + though it's not required that the exact memory location + be the same. + + Return value: A user visible string for the shortcut or + #NULL on error. +*/ +gchar * +indicator_desktop_shortcuts_nick_get_name (IndicatorDesktopShortcuts * ids, const gchar * nick) +{ + g_return_val_if_fail(INDICATOR_IS_DESKTOP_SHORTCUTS(ids), NULL); + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(ids); + + g_return_val_if_fail(priv->keyfile != NULL, NULL); + g_return_val_if_fail(is_valid_nick((gchar **)priv->nicks->data, nick), NULL); + + gchar * groupheader = g_strdup_printf("%s " GROUP_SUFFIX, nick); + if (!g_key_file_has_group(priv->keyfile, groupheader)) { + g_warning("The group for nick '%s' doesn't exist anymore.", nick); + g_free(groupheader); + return NULL; + } + + if (!g_key_file_has_key(priv->keyfile, groupheader, G_KEY_FILE_DESKTOP_KEY_NAME, NULL)) { + g_warning("No name available for nick '%s'", nick); + g_free(groupheader); + return NULL; + } + + gchar * name = g_key_file_get_locale_string(priv->keyfile, + groupheader, + G_KEY_FILE_DESKTOP_KEY_NAME, + NULL, + NULL); + + g_free(groupheader); + + return name; +} + +/** + indicator_desktop_shortcuts_nick_exec: + @ids: The #IndicatorDesktopShortcuts object to look in + @nick: Which command that we're referencing. + + Here we take a @nick and try and execute the action that is + associated with it. The @nick parameter should be gotten + from #indicator_desktop_shortcuts_get_nicks though it's not + required that the exact memory location be the same. + + Return value: #TRUE on success or #FALSE on error. +*/ +gboolean +indicator_desktop_shortcuts_nick_exec (IndicatorDesktopShortcuts * ids, const gchar * nick) +{ + GError * error = NULL; + + g_return_val_if_fail(INDICATOR_IS_DESKTOP_SHORTCUTS(ids), FALSE); + IndicatorDesktopShortcutsPrivate * priv = INDICATOR_DESKTOP_SHORTCUTS_GET_PRIVATE(ids); + + g_return_val_if_fail(priv->keyfile != NULL, FALSE); + g_return_val_if_fail(is_valid_nick((gchar **)priv->nicks->data, nick), FALSE); + + gchar * groupheader = g_strdup_printf("%s " GROUP_SUFFIX, nick); + if (!g_key_file_has_group(priv->keyfile, groupheader)) { + g_warning("The group for nick '%s' doesn't exist anymore.", nick); + g_free(groupheader); + return FALSE; + } + + if (!g_key_file_has_key(priv->keyfile, groupheader, G_KEY_FILE_DESKTOP_KEY_NAME, NULL)) { + g_warning("No name available for nick '%s'", nick); + g_free(groupheader); + return FALSE; + } + + if (!g_key_file_has_key(priv->keyfile, groupheader, G_KEY_FILE_DESKTOP_KEY_EXEC, NULL)) { + g_warning("No exec available for nick '%s'", nick); + g_free(groupheader); + return FALSE; + } + + /* Grab the name and the exec entries out of our current group */ + gchar * name = g_key_file_get_locale_string(priv->keyfile, + groupheader, + G_KEY_FILE_DESKTOP_KEY_NAME, + NULL, + NULL); + + gchar * exec = g_key_file_get_locale_string(priv->keyfile, + groupheader, + G_KEY_FILE_DESKTOP_KEY_EXEC, + NULL, + NULL); + + /* Build a new desktop file with the name and exec in the desktop + group. We have to do this with data as apparently there isn't + and add_group function in g_key_file. Go figure. */ + gchar * desktopdata = g_strdup_printf("[" G_KEY_FILE_DESKTOP_GROUP "]\n" + G_KEY_FILE_DESKTOP_KEY_TYPE "=" G_KEY_FILE_DESKTOP_TYPE_APPLICATION "\n" + G_KEY_FILE_DESKTOP_KEY_NAME "=%s\n" + G_KEY_FILE_DESKTOP_KEY_EXEC "=%s\n", + name, exec); + + + g_free(name); g_free(exec); + /* g_debug("Desktop file: \n%s", desktopdata); */ + + GKeyFile * launcher = g_key_file_new(); + g_key_file_load_from_data(launcher, desktopdata, -1, G_KEY_FILE_NONE, &error); + g_free(desktopdata); + + if (error != NULL) { + g_warning("Unable to build desktop keyfile for executing shortcut '%s': %s", nick, error->message); + g_error_free(error); + return FALSE; + } + + GDesktopAppInfo * appinfo = g_desktop_app_info_new_from_keyfile(launcher); + if (appinfo == NULL) { + g_warning("Unable to build Desktop App info (unknown)"); + g_key_file_free(launcher); + return FALSE; + } + + gboolean launched = g_app_info_launch(G_APP_INFO(appinfo), NULL, NULL, &error); + + if (error != NULL) { + g_warning("Unable to launch file from nick '%s': %s", nick, error->message); + g_error_free(error); + g_key_file_free(launcher); + return FALSE; + } + + g_object_unref(appinfo); + g_key_file_free(launcher); + + return launched; +} diff --git a/libindicator/indicator-desktop-shortcuts.h b/libindicator/indicator-desktop-shortcuts.h new file mode 100644 index 0000000..5ed490e --- /dev/null +++ b/libindicator/indicator-desktop-shortcuts.h @@ -0,0 +1,74 @@ +/* +A small file to parse through the actions that are available +in the desktop file and making those easily usable. + +Copyright 2010 Canonical Ltd. + +Authors: + Ted Gould <ted@canonical.com> + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 3.0 as published by the Free Software Foundation. + +This library 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 version 3.0 for more details. + +You should have received a copy of the GNU General Public +License along with this library. If not, see +<http://www.gnu.org/licenses/>. +*/ + +#ifndef __INDICATOR_DESKTOP_SHORTCUTS_H__ +#define __INDICATOR_DESKTOP_SHORTCUTS_H__ + +#include <glib.h> +#include <glib-object.h> + +G_BEGIN_DECLS + +#define INDICATOR_TYPE_DESKTOP_SHORTCUTS (indicator_desktop_shortcuts_get_type ()) +#define INDICATOR_DESKTOP_SHORTCUTS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), INDICATOR_TYPE_DESKTOP_SHORTCUTS, IndicatorDesktopShortcuts)) +#define INDICATOR_DESKTOP_SHORTCUTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), INDICATOR_TYPE_DESKTOP_SHORTCUTS, IndicatorDesktopShortcutsClass)) +#define INDICATOR_IS_DESKTOP_SHORTCUTS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), INDICATOR_TYPE_DESKTOP_SHORTCUTS)) +#define INDICATOR_IS_DESKTOP_SHORTCUTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), INDICATOR_TYPE_DESKTOP_SHORTCUTS)) +#define INDICATOR_DESKTOP_SHORTCUTS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), INDICATOR_TYPE_DESKTOP_SHORTCUTS, IndicatorDesktopShortcutsClass)) + +typedef struct _IndicatorDesktopShortcuts IndicatorDesktopShortcuts; +typedef struct _IndicatorDesktopShortcutsClass IndicatorDesktopShortcutsClass; + +/** + IndicatorDesktopShortcutsClass: + @parent_class: Space for #GObjectClass + + The vtable for our precious #IndicatorDesktopShortcutsClass. +*/ +struct _IndicatorDesktopShortcutsClass { + GObjectClass parent_class; +}; + +/** + IndicatorDesktopShortcuts: + @parent: The parent data from #GObject + + The public data for an instance of the class + #IndicatorDesktopShortcuts. +*/ +struct _IndicatorDesktopShortcuts { + GObject parent; +}; + +GType indicator_desktop_shortcuts_get_type (void); +IndicatorDesktopShortcuts * indicator_desktop_shortcuts_new (const gchar * file, + const gchar * identity); +const gchar ** indicator_desktop_shortcuts_get_nicks (IndicatorDesktopShortcuts * ids); +gchar * indicator_desktop_shortcuts_nick_get_name (IndicatorDesktopShortcuts * ids, + const gchar * nick); +gboolean indicator_desktop_shortcuts_nick_exec (IndicatorDesktopShortcuts * ids, + const gchar * nick); + +G_END_DECLS + +#endif diff --git a/tests/Makefile.am b/tests/Makefile.am index b111655..cd1a958 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -34,6 +34,42 @@ test_loader_LDADD = \ -lindicator ############################# +# Test Desktop Shortcuts +############################# + +check_PROGRAMS += test-desktop-shortcuts + +test_desktop_shortcuts_SOURCES = \ + test-desktop-shortcuts.c + +test_desktop_shortcuts_CFLAGS = \ + -Wall -Werror \ + -DSRCDIR="\"$(srcdir)\"" \ + $(LIBINDICATOR_CFLAGS) -I$(top_srcdir) \ + -DBUILD_DIR="\"$(builddir)\"" + +test_desktop_shortcuts_LDADD = \ + $(LIBINDICATOR_LIBS) \ + -L$(top_builddir)/libindicator/.libs \ + -lindicator + +DS_XML_REPORT = desktop-shortcuts-check-results.xml +DS_HTML_REPORT = desktop-shortcuts-check-results.html + +test-desktop-shortcuts-tester: test-desktop-shortcuts Makefile.am + @echo "#!/bin/bash" > $@ + @echo $(XVFB_RUN) >> $@ + @echo gtester -k --verbose -o=$(XML_REPORT) ./test-desktop-shortcuts >> $@ + @chmod +x $@ + +TESTS += test-desktop-shortcuts-tester +DISTCLEANFILES += test-desktop-shortcuts-tester \ + test-desktop-shortcuts-touch-test \ + $(DS_XML_REPORT) \ + $(DS_HTML_REPORT) +EXTRA_DIST += test-well-formed.desktop + +############################# # Dummy Indicator Blank ############################# diff --git a/tests/test-desktop-shortcuts.c b/tests/test-desktop-shortcuts.c new file mode 100644 index 0000000..1a655f7 --- /dev/null +++ b/tests/test-desktop-shortcuts.c @@ -0,0 +1,137 @@ +#include <gtk/gtk.h> +#include "libindicator/indicator-desktop-shortcuts.h" + +/* Basic object creation and destruction. Stop big + f*** ups here. */ +void +test_desktop_shortcuts_creation (void) +{ + + IndicatorDesktopShortcuts * ids = indicator_desktop_shortcuts_new(SRCDIR "/test-well-formed.desktop", "France"); + g_assert(ids != NULL); + + g_object_add_weak_pointer(G_OBJECT(ids), (gpointer *)&ids); + g_object_unref(G_OBJECT(ids)); + + g_assert(ids == NULL); + return; +} + +/* Tests that the NotShowIn the desktop group is watched + for */ +void +test_desktop_shortcuts_globalnoshow (void) +{ + + IndicatorDesktopShortcuts * ids = indicator_desktop_shortcuts_new(SRCDIR "/test-well-formed.desktop", "Germany"); + g_assert(ids != NULL); + + const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(ids); + g_assert(nicks[0] == NULL); + + g_object_unref(ids); + + return; +} + +gboolean +nicks_contains (const gchar ** nicks, const gchar * search) +{ + if (nicks[0] == NULL) + return FALSE; + if (g_strcmp0(nicks[0], search) == 0) + return TRUE; + return nicks_contains(&nicks[1], search); +} + +/* Checking that the local show OnlyIn works. */ +void +test_desktop_shortcuts_localfilter (void) +{ + IndicatorDesktopShortcuts * ids = indicator_desktop_shortcuts_new(SRCDIR "/test-well-formed.desktop", "France"); + g_assert(ids != NULL); + + const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(ids); + + g_assert(nicks_contains(nicks, "bob")); + g_assert(nicks_contains(nicks, "alvin")); + g_assert(!nicks_contains(nicks, "jim")); + + g_object_unref(ids); + + return; +} + +/* Nick names -- checks to see they all have names */ +void +test_desktop_shortcuts_nicknames (void) +{ + IndicatorDesktopShortcuts * ids = indicator_desktop_shortcuts_new(SRCDIR "/test-well-formed.desktop", "France"); + g_assert(ids != NULL); + + const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(ids); + gint i = 0; + while (nicks[i] != NULL) { + gchar * expectedstr = g_strdup_printf("%s's shortcut", nicks[i]); + gchar * name = indicator_desktop_shortcuts_nick_get_name(ids, nicks[i]); + g_assert(name != NULL); + + gboolean same = (g_strcmp0(expectedstr, name) == 0); + + g_free(name); + g_free(expectedstr); + + g_assert(same); + + i++; + } + + + g_object_unref(ids); + + return; +} + +/* Try executing a shortcut which will touch a file */ +void +test_desktop_shortcuts_launch (void) +{ + IndicatorDesktopShortcuts * ids = indicator_desktop_shortcuts_new(SRCDIR "/test-well-formed.desktop", "TouchTest"); + g_assert(ids != NULL); + + const gchar ** nicks = indicator_desktop_shortcuts_get_nicks(ids); + g_assert(nicks_contains(nicks, "touch")); + + g_assert(indicator_desktop_shortcuts_nick_exec(ids, "touch")); + g_assert(g_file_test(BUILD_DIR "/test-desktop-shortcuts-touch-test", G_FILE_TEST_EXISTS)); + + g_object_unref(ids); + + return; +} + +/* Build our test suite */ +void +test_desktop_shortcuts_suite (void) +{ + g_test_add_func ("/libindicator/desktopshortcuts/creation", test_desktop_shortcuts_creation); + g_test_add_func ("/libindicator/desktopshortcuts/globalnosho", test_desktop_shortcuts_globalnoshow); + g_test_add_func ("/libindicator/desktopshortcuts/nicknames", test_desktop_shortcuts_nicknames); + g_test_add_func ("/libindicator/desktopshortcuts/launch", test_desktop_shortcuts_launch); + + return; +} + +int +main (int argc, char ** argv) +{ + g_type_init (); + g_test_init (&argc, &argv, NULL); + gtk_init(&argc, &argv); + + test_desktop_shortcuts_suite(); + + g_log_set_always_fatal(G_LOG_LEVEL_CRITICAL); + + return g_test_run(); +} diff --git a/tests/test-well-formed.desktop b/tests/test-well-formed.desktop new file mode 100644 index 0000000..84e2e02 --- /dev/null +++ b/tests/test-well-formed.desktop @@ -0,0 +1,24 @@ +[Desktop Entry] +Name=My Application +Exec=ls +NotShowIn=Germany +X-Ayatana-Desktop-Shortcuts=bob;alvin;jim;touch + +[bob Shortcut Group] +Name=bob's shortcut +Exec=ls bob + +[alvin Shortcut Group] +Name=alvin's shortcut +Exec=ls alvin +OnlyShowIn=France + +[jim Shortcut Group] +Name=Jim's shortcut +Exec=ls jim +NotShowIn=France + +[touch Shortcut Group] +Name=Touch Test +Exec=touch test-desktop-shortcuts-touch-test +OnlyShowIn=TouchTest |