aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLars Uebernickel <lars.uebernickel@canonical.com>2012-09-05 15:21:16 +0200
committerLars Uebernickel <lars.uebernickel@canonical.com>2012-09-05 15:21:16 +0200
commitaf9183664c534c39d12e34b5c8e7c14ea189ce8b (patch)
tree25e285ec316f410e3a0749796f3bfd56045e56be /src
parent824daba1155620df5be05baec1829247dd9788c0 (diff)
downloadayatana-indicator-messages-af9183664c534c39d12e34b5c8e7c14ea189ce8b.tar.gz
ayatana-indicator-messages-af9183664c534c39d12e34b5c8e7c14ea189ce8b.tar.bz2
ayatana-indicator-messages-af9183664c534c39d12e34b5c8e7c14ea189ce8b.zip
Watch desktop files for changes
This introduces a slightly clumsy "destroy" signal for AppSection to notify outsiders that the desktop file was deleted. This will do for now, but a larger refactoring which pulls all the desktop-file-reading code out of appsection is in order.
Diffstat (limited to 'src')
-rw-r--r--src/app-section.c121
-rw-r--r--src/messages-service.c34
2 files changed, 129 insertions, 26 deletions
diff --git a/src/app-section.c b/src/app-section.c
index bed1302..58f1612 100644
--- a/src/app-section.c
+++ b/src/app-section.c
@@ -37,6 +37,7 @@ with this program. If not, see <http://www.gnu.org/licenses/>.
struct _AppSectionPrivate
{
GDesktopAppInfo * appinfo;
+ GFileMonitor *desktop_file_monitor;
guint unreadcount;
IndicatorDesktopShortcuts * ids;
@@ -64,6 +65,7 @@ enum {
};
static GParamSpec *properties[NUM_PROPERTIES];
+guint destroy_signal;
/* Prototypes */
static void app_section_class_init (AppSectionClass *klass);
@@ -98,6 +100,11 @@ static void action_removed (GActionGroup *group,
const gchar *action_name,
gpointer user_data);
static gboolean action_draws_attention (GVariant *state);
+static void desktop_file_changed_cb (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event,
+ gpointer user_data);
/* GObject Boilerplate */
G_DEFINE_TYPE (AppSection, app_section, G_TYPE_OBJECT);
@@ -138,6 +145,14 @@ app_section_class_init (AppSectionClass *klass)
G_PARAM_READABLE);
g_object_class_install_properties (object_class, NUM_PROPERTIES, properties);
+
+ destroy_signal = g_signal_new ("destroy",
+ APP_SECTION_TYPE,
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
}
static void
@@ -209,12 +224,18 @@ app_section_set_property (GObject *object,
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
}
+
static void
app_section_dispose (GObject *object)
{
AppSection * self = APP_SECTION(object);
AppSectionPrivate * priv = self->priv;
+ if (priv->desktop_file_monitor) {
+ g_signal_handlers_disconnect_by_func (priv->desktop_file_monitor, desktop_file_changed_cb, self);
+ g_clear_object (&priv->desktop_file_monitor);
+ }
+
g_clear_object (&priv->menu);
g_clear_object (&priv->static_shortcuts);
@@ -289,6 +310,9 @@ keyfile_loaded (GObject *source_object,
G_KEY_FILE_DESKTOP_GROUP,
"X-MessagingMenu-UsesChatSection",
&error);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USES_CHAT_STATUS]);
+
if (error) {
if (error->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) {
g_warning ("could not read X-MessagingMenu-UsesChatSection: %s",
@@ -298,34 +322,48 @@ keyfile_loaded (GObject *source_object,
goto out;
}
- if (self->priv->uses_chat_status)
- g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_USES_CHAT_STATUS]);
-
out:
g_key_file_free (keyfile);
g_free (contents);
}
static void
-app_section_set_app_info (AppSection *self,
- GDesktopAppInfo *appinfo)
+g_menu_clear (GMenu *menu)
+{
+ gint n_items = g_menu_model_get_n_items (G_MENU_MODEL (menu));
+
+ while (n_items--)
+ g_menu_remove (menu, 0);
+}
+
+static void
+g_simple_action_group_clear (GSimpleActionGroup *group)
+{
+ gchar **actions;
+ gchar **it;
+
+ actions = g_action_group_list_actions (G_ACTION_GROUP (group));
+ for (it = actions; *it; it++)
+ g_simple_action_group_remove (group, *it);
+
+ g_strfreev (actions);
+}
+
+static void
+app_section_update_menu (AppSection *self)
{
AppSectionPrivate *priv = self->priv;
GSimpleAction *launch;
GFile *keyfile;
GMenuItem *item;
gchar *iconstr;
+ gboolean is_running;
- g_return_if_fail (priv->appinfo == NULL);
+ g_menu_clear (priv->menu);
+ g_simple_action_group_clear (priv->static_shortcuts);
- if (appinfo == NULL) {
- g_warning ("appinfo must not be NULL");
- return;
- }
-
- priv->appinfo = g_object_ref (appinfo);
-
- launch = g_simple_action_new_stateful ("launch", NULL, g_variant_new_boolean (FALSE));
+ is_running = priv->name_watch_id > 0;
+ launch = g_simple_action_new_stateful ("launch", NULL, g_variant_new_boolean (is_running));
g_signal_connect (launch, "activate", G_CALLBACK (activate_cb), self);
g_signal_connect (launch, "change-state", G_CALLBACK (launch_action_change_state), self);
g_simple_action_group_insert (priv->static_shortcuts, G_ACTION (launch));
@@ -366,14 +404,65 @@ app_section_set_app_info (AppSection *self,
keyfile = g_file_new_for_path (g_desktop_app_info_get_filename (priv->appinfo));
g_file_load_contents_async (keyfile, NULL, keyfile_loaded, self);
- g_object_unref (keyfile);
- g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_APPINFO]);
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ACTIONS]);
+ g_object_unref (keyfile);
g_object_unref (launch);
}
+static void
+desktop_file_changed_cb (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event,
+ gpointer user_data)
+{
+ AppSection *self = user_data;
+
+ if (event == G_FILE_MONITOR_EVENT_CHANGED) {
+ app_section_update_menu (self);
+ }
+ else if (event == G_FILE_MONITOR_EVENT_DELETED ||
+ event == G_FILE_MONITOR_EVENT_UNMOUNTED) {
+ g_signal_emit (self, destroy_signal, 0);
+ }
+}
+
+static void
+app_section_set_app_info (AppSection *self,
+ GDesktopAppInfo *appinfo)
+{
+ AppSectionPrivate *priv = self->priv;
+ GFile *desktop_file;
+ GError *error = NULL;
+
+ g_return_if_fail (priv->appinfo == NULL);
+ g_return_if_fail (priv->desktop_file_monitor == NULL);
+
+ if (appinfo == NULL) {
+ g_warning ("appinfo must not be NULL");
+ return;
+ }
+
+ priv->appinfo = g_object_ref (appinfo);
+
+ desktop_file = g_file_new_for_path (g_desktop_app_info_get_filename (appinfo));
+ priv->desktop_file_monitor = g_file_monitor (desktop_file, G_FILE_MONITOR_SEND_MOVED, NULL, &error);
+ if (priv->desktop_file_monitor == NULL) {
+ g_warning ("unable to watch desktop file: %s", error->message);
+ g_error_free (error);
+ }
+ g_signal_connect (priv->desktop_file_monitor, "changed",
+ G_CALLBACK (desktop_file_changed_cb), self);
+
+ g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_APPINFO]);
+
+ app_section_update_menu (self);
+
+ g_object_unref (desktop_file);
+}
+
AppSection *
app_section_new (GDesktopAppInfo *appinfo)
{
diff --git a/src/messages-service.c b/src/messages-service.c
index 15c5123..ed9bfe4 100644
--- a/src/messages-service.c
+++ b/src/messages-service.c
@@ -45,7 +45,6 @@ static GMenu *menu;
static GMenuModel *chat_section;
static GSettings *settings;
-
static gchar *
g_app_info_get_simple_id (GAppInfo *appinfo)
{
@@ -138,6 +137,23 @@ uses_chat_status_changed (GObject *object,
g_object_unref (first_section);
}
+static void
+remove_section (AppSection *section,
+ const gchar *id)
+{
+ int pos = g_menu_find_section (menu, app_section_get_menu (section));
+ if (pos >= 0)
+ g_menu_remove (menu, pos);
+ g_action_muxer_remove (action_muxer, id);
+
+ g_signal_handlers_disconnect_by_func (section, actions_changed, NULL);
+ g_signal_handlers_disconnect_by_func (section, draws_attention_changed, NULL);
+ g_signal_handlers_disconnect_by_func (section, uses_chat_status_changed, NULL);
+ g_signal_handlers_disconnect_by_func (section, remove_section, NULL);
+
+ g_hash_table_remove (applications, id);
+}
+
static AppSection *
add_application (const gchar *desktop_id)
{
@@ -167,6 +183,11 @@ add_application (const gchar *desktop_id)
G_CALLBACK (draws_attention_changed), NULL);
g_signal_connect (section, "notify::uses-chat-status",
G_CALLBACK (uses_chat_status_changed), NULL);
+ g_signal_connect_data (section, "destroy",
+ G_CALLBACK (remove_section),
+ g_strdup (id),
+ (GClosureNotify) g_free,
+ 0);
/* TODO insert it at the right position (alphabetically by application name) */
menuitem = g_menu_item_new_section (NULL, app_section_get_menu (section));
@@ -197,20 +218,13 @@ remove_application (const char *desktop_id)
section = g_hash_table_lookup (applications, id);
if (section) {
- int pos = g_menu_find_section (menu, app_section_get_menu (section));
- if (pos >= 0)
- g_menu_remove (menu, pos);
- g_action_muxer_remove (action_muxer, id);
-
- g_signal_handlers_disconnect_by_func (section, actions_changed, NULL);
- g_signal_handlers_disconnect_by_func (section, draws_attention_changed, NULL);
- g_signal_handlers_disconnect_by_func (section, uses_chat_status_changed, NULL);
+ remove_section (section, id);
}
else {
+ g_hash_table_remove (applications, id);
g_warning ("could not remove '%s', it's not registered", desktop_id);
}
- g_hash_table_remove (applications, id);
g_free (id);
g_object_unref (appinfo);
}