You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2747 lines
91 KiB

/*
* Copyright (C) 2008-2010 Nick Schermer <nick@xfce.org>
*
* This library 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.
12 years ago
*
* 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 for
* more details.
12 years ago
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
12 years ago
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <gio/gio.h>
#include <exo/exo.h>
12 years ago
#include <libxfce4util/libxfce4util.h>
#include <libxfce4ui/libxfce4ui.h>
#include <garcon/garcon.h>
#include <xfconf/xfconf.h>
#include <libxfce4panel/libxfce4panel.h>
#include <common/panel-private.h>
#include <common/panel-xfconf.h>
#include <common/panel-utils.h>
12 years ago
#include "launcher.h"
#include "launcher-dialog.h"
12 years ago
#define ARROW_BUTTON_SIZE (12)
#define TOOLTIP_ICON_SIZE (32)
#define MENU_ICON_SIZE (32)
#define MENU_POPUP_DELAY (225)
#define NO_ARROW_INSIDE_BUTTON(plugin) ((plugin)->arrow_position != LAUNCHER_ARROW_INTERNAL \
|| LIST_HAS_ONE_OR_NO_ENTRIES ((plugin)->items))
#define ARROW_INSIDE_BUTTON(plugin) (!NO_ARROW_INSIDE_BUTTON (plugin))
#define RELATIVE_CONFIG_PATH PANEL_PLUGIN_RELATIVE_PATH G_DIR_SEPARATOR_S "%s-%d"
12 years ago
static void launcher_plugin_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static void launcher_plugin_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void launcher_plugin_construct (XfcePanelPlugin *panel_plugin);
static void launcher_plugin_free_data (XfcePanelPlugin *panel_plugin);
static void launcher_plugin_removed (XfcePanelPlugin *panel_plugin);
static gboolean launcher_plugin_remote_event (XfcePanelPlugin *panel_plugin,
const gchar *name,
const GValue *value);
static gboolean launcher_plugin_save_delayed_timeout (gpointer user_data);
static void launcher_plugin_save_delayed (LauncherPlugin *plugin);
static void launcher_plugin_mode_changed (XfcePanelPlugin *panel_plugin,
XfcePanelPluginMode mode);
static gboolean launcher_plugin_size_changed (XfcePanelPlugin *panel_plugin,
gint size);
static void launcher_plugin_configure_plugin (XfcePanelPlugin *panel_plugin);
static void launcher_plugin_screen_position_changed (XfcePanelPlugin *panel_plugin,
XfceScreenPosition position);
static void launcher_plugin_icon_theme_changed (GtkIconTheme *icon_theme,
LauncherPlugin *plugin);
static LauncherArrowType launcher_plugin_default_arrow_type (LauncherPlugin *plugin);
static void launcher_plugin_pack_widgets (LauncherPlugin *plugin);
static GdkPixbuf *launcher_plugin_tooltip_pixbuf (GdkScreen *screen,
const gchar *icon_name);
static void launcher_plugin_menu_deactivate (GtkWidget *menu,
LauncherPlugin *plugin);
static void launcher_plugin_menu_item_activate (GtkMenuItem *widget,
GarconMenuItem *item);
static void launcher_plugin_menu_item_drag_data_received (GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
GtkSelectionData *data,
guint info,
guint drag_time,
GarconMenuItem *item);
static void launcher_plugin_menu_construct (LauncherPlugin *plugin);
static void launcher_plugin_menu_popup_destroyed (gpointer user_data);
static gboolean launcher_plugin_menu_popup (gpointer user_data);
static void launcher_plugin_menu_destroy (LauncherPlugin *plugin);
static void launcher_plugin_button_update (LauncherPlugin *plugin);
static void launcher_plugin_button_state_changed (GtkWidget *button_a,
GtkStateType state,
GtkWidget *button_b);
static gboolean launcher_plugin_button_press_event (GtkWidget *button,
GdkEventButton *event,
LauncherPlugin *plugin);
static gboolean launcher_plugin_button_release_event (GtkWidget *button,
GdkEventButton *event,
LauncherPlugin *plugin);
static gboolean launcher_plugin_button_query_tooltip (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_mode,
GtkTooltip *tooltip,
LauncherPlugin *plugin);
static void launcher_plugin_button_drag_data_received (GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
GtkSelectionData *selection_data,
guint info,
guint drag_time,
LauncherPlugin *plugin);
static gboolean launcher_plugin_button_drag_motion (GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
guint drag_time,
LauncherPlugin *plugin);
static gboolean launcher_plugin_button_drag_drop (GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
guint drag_time,
LauncherPlugin *plugin);
static void launcher_plugin_button_drag_leave (GtkWidget *widget,
GdkDragContext *context,
guint drag_time,
LauncherPlugin *plugin);
static gboolean launcher_plugin_button_expose_event (GtkWidget *widget,
GdkEventExpose *event,
LauncherPlugin *launcher);
static void launcher_plugin_arrow_visibility (LauncherPlugin *plugin);
static gboolean launcher_plugin_arrow_press_event (GtkWidget *button,
GdkEventButton *event,
LauncherPlugin *plugin);
static gboolean launcher_plugin_arrow_drag_motion (GtkWidget *widget,
GdkDragContext *context,
gint x,
gint y,
guint drag_time,
LauncherPlugin *plugin);
static void launcher_plugin_arrow_drag_leave (GtkWidget *widget,
GdkDragContext *context,
guint drag_time,
LauncherPlugin *plugin);
static gboolean launcher_plugin_item_query_tooltip (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_mode,
GtkTooltip *tooltip,
GarconMenuItem *item);
static gboolean launcher_plugin_item_exec_on_screen (GarconMenuItem *item,
guint32 event_time,
GdkScreen *screen,
GSList *uri_list);
static void launcher_plugin_item_exec (GarconMenuItem *item,
guint32 event_time,
GdkScreen *screen,
GSList *uri_list);
static void launcher_plugin_item_exec_from_clipboard (GarconMenuItem *item,
guint32 event_time,
GdkScreen *screen);
static void launcher_plugin_exec_append_quoted (GString *string,
const gchar *unquoted);
static gboolean launcher_plugin_exec_parse (GarconMenuItem *item,
GSList *uri_list,
gchar ***argv,
GError **error);
static GSList *launcher_plugin_uri_list_extract (GtkSelectionData *data);
static void launcher_plugin_uri_list_free (GSList *uri_list);
12 years ago
struct _LauncherPluginClass
{
XfcePanelPluginClass __parent__;
};
struct _LauncherPlugin
{
XfcePanelPlugin __parent__;
GtkWidget *box;
GtkWidget *button;
GtkWidget *arrow;
GtkWidget *child;
GtkWidget *menu;
GSList *items;
GdkPixbuf *tooltip_cache;
gulong theme_change_id;
guint menu_timeout_id;
guint disable_tooltips : 1;
guint move_first : 1;
guint show_label : 1;
LauncherArrowType arrow_position;
GFile *config_directory;
GFileMonitor *config_monitor;
guint save_timeout_id;
};
enum
{
PROP_0,
PROP_ITEMS,
PROP_DISABLE_TOOLTIPS,
PROP_MOVE_FIRST,
PROP_SHOW_LABEL,
PROP_ARROW_POSITION
};
enum
{
ITEMS_CHANGED,
LAST_SIGNAL
};
12 years ago
/* define the plugin */
XFCE_PANEL_DEFINE_PLUGIN_RESIDENT (LauncherPlugin, launcher_plugin)
12 years ago
/* quark to attach the plugin to menu items */
static GQuark launcher_plugin_quark = 0;
static guint launcher_signals[LAST_SIGNAL];
static GtkIconSize launcher_menu_icon_size = GTK_ICON_SIZE_INVALID;
static GtkIconSize launcher_tooltip_icon_size = GTK_ICON_SIZE_INVALID;
/* target types for dropping in the launcher plugin */
static const GtkTargetEntry drop_targets[] =
{
{ "text/uri-list", 0, 0, },
{ "STRING", 0, 0 },
{ "UTF8_STRING", 0, 0 },
{ "text/plain", 0, 0 },
};
static void
launcher_plugin_class_init (LauncherPluginClass *klass)
{
GObjectClass *gobject_class;
XfcePanelPluginClass *plugin_class;
gobject_class = G_OBJECT_CLASS (klass);
gobject_class->get_property = launcher_plugin_get_property;
gobject_class->set_property = launcher_plugin_set_property;
plugin_class = XFCE_PANEL_PLUGIN_CLASS (klass);
plugin_class->construct = launcher_plugin_construct;
plugin_class->free_data = launcher_plugin_free_data;
plugin_class->mode_changed = launcher_plugin_mode_changed;
plugin_class->size_changed = launcher_plugin_size_changed;
plugin_class->configure_plugin = launcher_plugin_configure_plugin;
plugin_class->screen_position_changed = launcher_plugin_screen_position_changed;
plugin_class->removed = launcher_plugin_removed;
plugin_class->remote_event = launcher_plugin_remote_event;
g_object_class_install_property (gobject_class,
PROP_ITEMS,
g_param_spec_boxed ("items",
NULL, NULL,
PANEL_PROPERTIES_TYPE_VALUE_ARRAY,
EXO_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_DISABLE_TOOLTIPS,
g_param_spec_boolean ("disable-tooltips",
NULL, NULL,
FALSE,
EXO_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_MOVE_FIRST,
g_param_spec_boolean ("move-first",
NULL, NULL,
FALSE,
EXO_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_SHOW_LABEL,
g_param_spec_boolean ("show-label",
NULL, NULL,
FALSE,
EXO_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_ARROW_POSITION,
g_param_spec_uint ("arrow-position",
NULL, NULL,
LAUNCHER_ARROW_DEFAULT,
LAUNCHER_ARROW_INTERNAL,
LAUNCHER_ARROW_DEFAULT,
EXO_PARAM_READWRITE));
launcher_signals[ITEMS_CHANGED] =
g_signal_new (g_intern_static_string ("items-changed"),
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
0, NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
/* initialize the quark */
launcher_plugin_quark = g_quark_from_static_string ("xfce-launcher-plugin");
launcher_menu_icon_size = gtk_icon_size_from_name ("panel-launcher-menu");
if (launcher_menu_icon_size == GTK_ICON_SIZE_INVALID)
launcher_menu_icon_size = gtk_icon_size_register ("panel-launcher-menu",
MENU_ICON_SIZE,
MENU_ICON_SIZE);
launcher_tooltip_icon_size = gtk_icon_size_from_name ("panel-launcher-tooltip");
if (launcher_tooltip_icon_size == GTK_ICON_SIZE_INVALID)
launcher_tooltip_icon_size = gtk_icon_size_register ("panel-launcher-tooltip",
TOOLTIP_ICON_SIZE,
TOOLTIP_ICON_SIZE);
}
12 years ago
static void
launcher_plugin_init (LauncherPlugin *plugin)
{
GtkIconTheme *icon_theme;
plugin->disable_tooltips = FALSE;
plugin->move_first = FALSE;
plugin->show_label = FALSE;
plugin->arrow_position = LAUNCHER_ARROW_DEFAULT;
plugin->menu = NULL;
plugin->items = NULL;
plugin->child = NULL;
plugin->tooltip_cache = NULL;
plugin->menu_timeout_id = 0;
plugin->save_timeout_id = 0;
/* monitor the default icon theme for changes */
icon_theme = gtk_icon_theme_get_default ();
plugin->theme_change_id = g_signal_connect (G_OBJECT (icon_theme), "changed",
G_CALLBACK (launcher_plugin_icon_theme_changed), plugin);
/* create the panel widgets */
plugin->box = xfce_hvbox_new (GTK_ORIENTATION_HORIZONTAL, FALSE, 0);
gtk_container_add (GTK_CONTAINER (plugin), plugin->box);
plugin->button = xfce_panel_create_button ();
gtk_box_pack_start (GTK_BOX (plugin->box), plugin->button, TRUE, TRUE, 0);
xfce_panel_plugin_add_action_widget (XFCE_PANEL_PLUGIN (plugin), plugin->button);
gtk_widget_set_has_tooltip (plugin->button, TRUE);
gtk_widget_set_name (plugin->button, "launcher-button");
g_signal_connect (G_OBJECT (plugin->button), "button-press-event",
G_CALLBACK (launcher_plugin_button_press_event), plugin);
g_signal_connect (G_OBJECT (plugin->button), "button-release-event",
G_CALLBACK (launcher_plugin_button_release_event), plugin);
g_signal_connect (G_OBJECT (plugin->button), "query-tooltip",
G_CALLBACK (launcher_plugin_button_query_tooltip), plugin);
g_signal_connect (G_OBJECT (plugin->button), "drag-data-received",
G_CALLBACK (launcher_plugin_button_drag_data_received), plugin);
g_signal_connect (G_OBJECT (plugin->button), "drag-motion",
G_CALLBACK (launcher_plugin_button_drag_motion), plugin);
g_signal_connect (G_OBJECT (plugin->button), "drag-drop",
G_CALLBACK (launcher_plugin_button_drag_drop), plugin);
g_signal_connect (G_OBJECT (plugin->button), "drag-leave",
G_CALLBACK (launcher_plugin_button_drag_leave), plugin);
g_signal_connect_after (G_OBJECT (plugin->button), "expose-event",
G_CALLBACK (launcher_plugin_button_expose_event), plugin);
plugin->child = xfce_panel_image_new ();
gtk_container_add (GTK_CONTAINER (plugin->button), plugin->child);
plugin->arrow = xfce_arrow_button_new (GTK_ARROW_UP);
gtk_box_pack_start (GTK_BOX (plugin->box), plugin->arrow, FALSE, FALSE, 0);
xfce_panel_plugin_add_action_widget (XFCE_PANEL_PLUGIN (plugin), plugin->arrow);
gtk_button_set_relief (GTK_BUTTON (plugin->arrow), GTK_RELIEF_NONE);
gtk_widget_set_name (plugin->button, "launcher-arrow");
g_signal_connect (G_OBJECT (plugin->arrow), "button-press-event",
G_CALLBACK (launcher_plugin_arrow_press_event), plugin);
g_signal_connect (G_OBJECT (plugin->arrow), "drag-motion",
G_CALLBACK (launcher_plugin_arrow_drag_motion), plugin);
g_signal_connect (G_OBJECT (plugin->button), "drag-drop",
G_CALLBACK (launcher_plugin_button_drag_drop), plugin);
g_signal_connect (G_OBJECT (plugin->arrow), "drag-leave",
G_CALLBACK (launcher_plugin_arrow_drag_leave), plugin);
panel_utils_set_atk_info (plugin->arrow, _("Open launcher menu"), NULL);
/* accept all sorts of drag data, but filter in drag-drop, so we can
* send other sorts of drops to parent widgets */
gtk_drag_dest_set (plugin->button, 0, NULL, 0, 0);
gtk_drag_dest_set (plugin->arrow, 0, NULL, 0, 0);
/* sync button states */
g_signal_connect (G_OBJECT (plugin->button), "state-changed",
G_CALLBACK (launcher_plugin_button_state_changed), plugin->arrow);
g_signal_connect (G_OBJECT (plugin->arrow), "state-changed",
G_CALLBACK (launcher_plugin_button_state_changed), plugin->button);
12 years ago
}
static void
launcher_plugin_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
LauncherPlugin *plugin = XFCE_LAUNCHER_PLUGIN (object);
GPtrArray *array;
GValue *tmp;
GSList *li;
GFile *item_file;
switch (prop_id)
{
case PROP_ITEMS:
array = g_ptr_array_new ();
for (li = plugin->items; li != NULL; li = li->next)
{
tmp = g_new0 (GValue, 1);
g_value_init (tmp, G_TYPE_STRING);
panel_return_if_fail (GARCON_IS_MENU_ITEM (li->data));
item_file = garcon_menu_item_get_file (li->data);
if (g_file_has_prefix (item_file, plugin->config_directory))
g_value_take_string (tmp, g_file_get_basename (item_file));
else
g_value_take_string (tmp, g_file_get_uri (item_file));
g_object_unref (G_OBJECT (item_file));
g_ptr_array_add (array, tmp);
}
g_value_set_boxed (value, array);
xfconf_array_free (array);
break;
case PROP_DISABLE_TOOLTIPS:
g_value_set_boolean (value, plugin->disable_tooltips);
break;
case PROP_MOVE_FIRST:
g_value_set_boolean (value, plugin->move_first);
break;
case PROP_SHOW_LABEL:
g_value_set_boolean (value, plugin->show_label);
break;
case PROP_ARROW_POSITION:
g_value_set_uint (value, plugin->arrow_position);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
launcher_plugin_item_changed (GarconMenuItem *item,
LauncherPlugin *plugin)
{
GSList *li;
panel_return_if_fail (GARCON_IS_MENU_ITEM (item));
panel_return_if_fail (XFCE_IS_LAUNCHER_PLUGIN (plugin));
/* find the item */
li = g_slist_find (plugin->items, item);
if (G_LIKELY (li != NULL))
{
/* update the button or destroy the menu */
if (plugin->items == li)
launcher_plugin_button_update (plugin);
else
launcher_plugin_menu_destroy (plugin);
}
else
{
panel_assert_not_reached ();
}
}
static gboolean
launcher_plugin_item_duplicate (GFile *src_file,
GFile *dst_file,
GError **error)
{
GKeyFile *key_file;
gchar *contents = NULL;
gsize length;
gboolean result = FALSE;
gchar *uri;
panel_return_val_if_fail (G_IS_FILE (src_file), FALSE);
panel_return_val_if_fail (G_IS_FILE (dst_file), FALSE);
panel_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (!g_file_load_contents (src_file, NULL, &contents, &length, NULL, error))
return FALSE;
/* note that we don't load the key file with preserving the translations
* and comments, this way we save a small desktop file in the user's language */
key_file = g_key_file_new ();
if (!g_key_file_load_from_data (key_file, contents, length, 0, error))
goto err1;
/* store the source uri in the desktop file for restore purposes */
uri = g_file_get_uri (src_file);
g_key_file_set_string (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-XFCE-Source", uri);
g_free (uri);
contents = g_key_file_to_data (key_file, &length, error);
if (contents == NULL)
goto err1;
result = g_file_replace_contents (dst_file, contents, length, NULL, FALSE,
#if GLIB_CHECK_VERSION (2, 20, 0)
G_FILE_CREATE_REPLACE_DESTINATION,
#else
G_FILE_CREATE_NONE,
#endif
NULL, NULL, error);
err1:
g_free (contents);
g_key_file_free (key_file);
return result;
}
static GarconMenuItem *
launcher_plugin_item_load (LauncherPlugin *plugin,
const gchar *str,
gboolean *desktop_id_return,
gboolean *location_changed)
{
GFile *src_file, *dst_file;
gchar *src_path, *dst_path;
GSList *li, *lnext;
GarconMenuItem *item = NULL;
GError *error = NULL;
panel_return_val_if_fail (XFCE_IS_LAUNCHER_PLUGIN (plugin), NULL);
panel_return_val_if_fail (str != NULL, NULL);
panel_return_val_if_fail (G_IS_FILE (plugin->config_directory), NULL);
if (G_UNLIKELY (g_path_is_absolute (str) || exo_str_looks_like_an_uri (str)))
{
src_file = g_file_new_for_commandline_arg (str);
if (g_file_has_prefix (src_file, plugin->config_directory))
{
/* nothing, we use the file below */
}
else if (g_file_query_exists (src_file, NULL))
{
/* create a unique file in the config directory */
dst_path = launcher_plugin_unique_filename (plugin);
dst_file = g_file_new_for_path (dst_path);
/* create a duplicate in the config directory */
if (launcher_plugin_item_duplicate (src_file, dst_file, &error))
{
/* use the new file */
g_object_unref (G_OBJECT (src_file));
src_file = dst_file;
if (G_LIKELY (location_changed != NULL))
*location_changed = TRUE;
}
else
{
src_path = g_file_get_parse_name (src_file);
g_warning ("Failed to create duplicate of desktop file \"%s\" "
"to \"%s\": %s", src_path, dst_path, error->message);
g_error_free (error);
g_free (src_path);
/* continue using the source file, the user won't be able to
* edit the item, but atleast we have something that works in
* the panel */
g_object_unref (G_OBJECT (dst_file));
}
g_free (dst_path);
}
else
{
/* nothing we can do with this file */
src_path = g_file_get_parse_name (src_file);
g_warning ("Failed to load desktop file \"%s\". It will be removed "
"from the configuration", src_path);
g_free (src_path);
g_object_unref (G_OBJECT (src_file));
return NULL;
}
}
else
{
/* assume the file is a child in the config directory */
src_file = g_file_get_child (plugin->config_directory, str);
/* str might also be a global desktop id */
if (G_LIKELY (desktop_id_return != NULL))
*desktop_id_return = TRUE;
}
panel_assert (G_IS_FILE (src_file));
/* maybe we have this file in the launcher configuration, then we don't
* have to load it again from the harddisk */
for (li = plugin->items; item == NULL && li != NULL; li = lnext)
{
lnext = li->next;
dst_file = garcon_menu_item_get_file (GARCON_MENU_ITEM (li->data));
if (g_file_equal (src_file, dst_file))
{
item = GARCON_MENU_ITEM (li->data);
plugin->items = g_slist_delete_link (plugin->items, li);
}
g_object_unref (G_OBJECT (dst_file));
}
/* load the file from the disk */
if (item == NULL)
item = garcon_menu_item_new (src_file);
g_object_unref (G_OBJECT (src_file));
return item;
}
static void
launcher_plugin_items_delete_configs (LauncherPlugin *plugin)
{
GSList *li;
GFile *file;
gboolean succeed = TRUE;
GError *error = NULL;
panel_return_if_fail (G_IS_FILE (plugin->config_directory));
/* cleanup desktop files in the config dir */
for (li = plugin->items; succeed && li != NULL; li = li->next)
{
file = garcon_menu_item_get_file (li->data);
if (g_file_has_prefix (file, plugin->config_directory))
succeed = g_file_delete (file, NULL, &error);
g_object_unref (G_OBJECT (file));
}
if (!succeed)
{
g_message ("launcher-%d: Failed to cleanup the configuration: %s",
xfce_panel_plugin_get_unique_id (XFCE_PANEL_PLUGIN (plugin)),
error->message);
g_error_free (error);
}
}
static void
launcher_plugin_items_free (LauncherPlugin *plugin)
{
if (G_LIKELY (plugin->items != NULL))
{
g_slist_foreach (plugin->items, (GFunc) g_object_unref, NULL);
g_slist_free (plugin->items);
plugin->items = NULL;
}
}
static void
launcher_plugin_items_load (LauncherPlugin *plugin,
GPtrArray *array)
{
guint i;
const GValue *value;
const gchar *str;
GarconMenuItem *item;
GarconMenuItem *pool_item;
GSList *items = NULL;
GHashTable *pool = NULL;
gboolean desktop_id;
gchar *uri;
gboolean items_modified = FALSE;
gboolean location_changed;
panel_return_if_fail (XFCE_IS_LAUNCHER_PLUGIN (plugin));
panel_return_if_fail (array != NULL);
for (i = 0; i < array->len; i++)
{
value = g_ptr_array_index (array, i);
panel_assert (G_VALUE_HOLDS_STRING (value));
str = g_value_get_string (value);
/* only accept desktop files */
if (str == NULL || !g_str_has_suffix (str, ".desktop"))
continue;
/* try to load the item */
desktop_id = FALSE;
location_changed = FALSE;
item = launcher_plugin_item_load (plugin, str, &desktop_id, &location_changed);
if (G_LIKELY (item == NULL))
{
/* str did not look like a desktop-id, so no need to look
* for it in the application pool */
if (!desktop_id)
continue;
/* we are going to load an desktop_id from the item pool,
* even if this failes, save the new item list, so we don't
* try this again in the future */
items_modified = TRUE;
/* load the pool with desktop items */
if (pool == NULL)
pool = launcher_plugin_garcon_menu_pool ();
/* lookup the item in the item pool */
pool_item = g_hash_table_lookup (pool, str);
if (pool_item != NULL)
{
/* we want an editable file, so try to make a copy */
uri = garcon_menu_item_get_uri (pool_item);
item = launcher_plugin_item_load (plugin, uri, NULL, NULL);
g_free (uri);
/* if something failed, use the pool item, but this one
* won't be editable in the dialog */
if (G_UNLIKELY (item == NULL))
item = g_object_ref (G_OBJECT (pool_item));
}
/* skip this item if still not found */
if (item == NULL)
continue;
}
else if (location_changed)
{
items_modified = TRUE;
}
/* add the item to the list */
panel_assert (GARCON_IS_MENU_ITEM (item));
items = g_slist_append (items, item);
g_signal_connect (G_OBJECT (item), "changed",
G_CALLBACK (launcher_plugin_item_changed), plugin);
}
if (G_UNLIKELY (pool != NULL))
g_hash_table_destroy (pool);
/* remove config files of items not in the new config */
launcher_plugin_items_delete_configs (plugin);
/* release the old menu items and set new one */
launcher_plugin_items_free (plugin);
plugin->items = items;
/* store the new item list */
if (items_modified)
launcher_plugin_save_delayed (plugin);
}
static void
launcher_plugin_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
LauncherPlugin *plugin = XFCE_LAUNCHER_PLUGIN (object);
GPtrArray *array;
panel_return_if_fail (G_IS_FILE (plugin->config_directory));
/* destroy the menu, all the setting changes need this */
launcher_plugin_menu_destroy (plugin);
switch (prop_id)
{
case PROP_ITEMS:
/* load new items from the array */
array = g_value_get_boxed (value);
if (G_LIKELY (array != NULL))
{
launcher_plugin_items_load (plugin, array);
}
else
{
launcher_plugin_items_delete_configs (plugin);
launcher_plugin_items_free (plugin);
}
/* emit signal */
g_signal_emit (G_OBJECT (plugin), launcher_signals[ITEMS_CHANGED], 0);
/* update the button */
launcher_plugin_button_update (plugin);
/* update the widget packing */
goto update_arrow;
break;