On Fri, 2007-08-17 at 14:11 -0400, Matthias Clasen wrote: > > Yeah, doing a "lauch preferred browser/mail client/terminal" applet should > take ~20 lines of non-boilerplate code... > Turns out it took a bit more than 20 lines, but I ended up taking a different approach to implementing this anyway. The attached panel patch does 3 things: - let the launcher properties dialog handle selected desktop files sensibly - make the panel optionally use file monitoring for desktop files backing launchers - add some code that maintains preferred-web-browser.desktop and preferred-mail-reader.desktop and keeps them in sync with the corresponding gconf keys. The first two parts make sense independently of preferred apps; the third one should maybe live somewhere else, e.g. gnome-settings-daemon. Using this patch, we can have nicely updating launchers with correct icons for the preferred web and mail apps. Matthias
diff -up gnome-panel-2.19.6/gnome-panel/panel-ditem-editor.c.launcher-desktop-file-improvements gnome-panel-2.19.6/gnome-panel/panel-ditem-editor.c --- gnome-panel-2.19.6/gnome-panel/panel-ditem-editor.c.launcher-desktop-file-improvements 2007-08-13 19:36:51.000000000 -0400 +++ gnome-panel-2.19.6/gnome-panel/panel-ditem-editor.c 2007-08-26 00:44:56.000000000 -0400 @@ -80,6 +80,8 @@ struct _PanelDItemEditorPrivate /* the directory of the theme for the icon, see bug #119208 */ char *icon_theme_dir; + + char *orig_desktop_file; }; /* Time in seconds after which we save the file on the disk */ @@ -367,6 +369,11 @@ panel_ditem_editor_destroy (GtkObject *o g_free (dialog->priv->icon_theme_dir); dialog->priv->icon_theme_dir = NULL; + + if (dialog->priv->orig_desktop_file != NULL) + g_free (dialog->priv->orig_desktop_file); + dialog->priv->orig_desktop_file = NULL; + GTK_OBJECT_CLASS (panel_ditem_editor_parent_class)->destroy (object); } @@ -833,6 +840,13 @@ panel_ditem_editor_changed (PanelDItemEd TRUE); } + /* When the user changes any fields, unset the orig_desktop_file + * field since the editor contents are not entirely from a desktop + * file anymore. + */ + g_free (dialog->priv->orig_desktop_file); + dialog->priv->orig_desktop_file = NULL; + dialog->priv->dirty = TRUE; g_signal_emit (G_OBJECT (dialog), ditem_edit_signals[CHANGED], 0); } @@ -973,6 +987,49 @@ panel_ditem_editor_icon_changed (PanelDI g_free (file); } +static gboolean +update_editor_from_desktop_file (PanelDItemEditor *dialog, + const gchar *uri) +{ + GKeyFile *key_file; + char *name; + char *comment; + char *exec; + char *icon; + + key_file = g_key_file_new (); + if (g_key_file_load_from_file (key_file, uri, 0, NULL)) { + if (panel_util_key_file_get_boolean (key_file, "Terminal", FALSE)) + gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->type_combo), 1); + else + gtk_combo_box_set_active (GTK_COMBO_BOX (dialog->priv->type_combo), 0); + + name = panel_util_key_file_get_locale_string (key_file, "Name"); + comment = panel_util_key_file_get_locale_string (key_file, "Comment"); + icon = panel_util_key_file_get_locale_string (key_file, "Icon"); + exec = panel_util_key_file_get_string (key_file, "Exec"); + + gtk_entry_set_text (GTK_ENTRY (dialog->priv->name_entry), name ? name : ""); + gtk_entry_set_text (GTK_ENTRY (dialog->priv->comment_entry), comment ? comment : ""); + gtk_entry_set_text (GTK_ENTRY (dialog->priv->command_entry), exec ? exec : ""); + /* Note: we need to set the icon last, since the editor + * tries to guess the icon when the command is modified + */ + setup_icon_entry (dialog, icon); + + /* We set the orig_desktop_file field to let the + * launcher know that the editor contents are coming + * directly from a desktop file. + */ + g_free (dialog->priv->orig_desktop_file); + dialog->priv->orig_desktop_file = g_strdup (uri); + + return TRUE; + } + + return FALSE; +} + static void command_browse_chooser_response (GtkFileChooser *chooser, gint response_id, @@ -986,7 +1043,11 @@ command_browse_chooser_response (GtkFile case PANEL_DITEM_EDITOR_TYPE_APPLICATION: case PANEL_DITEM_EDITOR_TYPE_TERMINAL_APPLICATION: text = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (chooser)); - uri = panel_util_make_exec_uri_for_desktop (text); + if (g_str_has_suffix (text, ".desktop") && + update_editor_from_desktop_file (dialog, text)) + uri = NULL; + else + uri = panel_util_make_exec_uri_for_desktop (text); g_free (text); break; case PANEL_DITEM_EDITOR_TYPE_LINK: @@ -996,8 +1057,9 @@ command_browse_chooser_response (GtkFile g_assert_not_reached (); } - gtk_entry_set_text (GTK_ENTRY (dialog->priv->command_entry), - uri); + if (uri) + gtk_entry_set_text (GTK_ENTRY (dialog->priv->command_entry), + uri); g_free (uri); } @@ -1785,3 +1847,12 @@ panel_ditem_register_save_uri_func (Pane dialog->priv->save_uri = save_uri; dialog->priv->save_uri_data = data; } + +G_CONST_RETURN char * +panel_ditem_editor_get_orig_desktop_file (PanelDItemEditor *dialog) +{ + g_return_val_if_fail (PANEL_IS_DITEM_EDITOR (dialog), NULL); + + return dialog->priv->orig_desktop_file; +} + diff -up gnome-panel-2.19.6/gnome-panel/launcher.h.launcher-desktop-file-improvements gnome-panel-2.19.6/gnome-panel/launcher.h --- gnome-panel-2.19.6/gnome-panel/launcher.h.launcher-desktop-file-improvements 2007-08-13 19:36:51.000000000 -0400 +++ gnome-panel-2.19.6/gnome-panel/launcher.h 2007-08-25 22:28:39.000000000 -0400 @@ -13,6 +13,7 @@ #include "applet.h" #include "panel-widget.h" +#include <libgnomevfs/gnome-vfs.h> G_BEGIN_DECLS @@ -29,6 +30,8 @@ typedef struct { GSList *error_dialogs; gulong destroy_handler; + + GnomeVFSMonitorHandle *monitor; } Launcher; void panel_launcher_create (PanelToplevel *toplevel, @@ -73,6 +76,8 @@ void panel_launcher_set_dnd_e gboolean dnd_enabled); +void panel_preferred_apps_init (void); + G_END_DECLS #endif diff -up gnome-panel-2.19.6/gnome-panel/panel-run-dialog.c.launcher-desktop-file-improvements gnome-panel-2.19.6/gnome-panel/panel-run-dialog.c --- gnome-panel-2.19.6/gnome-panel/panel-run-dialog.c.launcher-desktop-file-improvements 2007-08-13 19:36:51.000000000 -0400 +++ gnome-panel-2.19.6/gnome-panel/panel-run-dialog.c 2007-08-25 22:28:39.000000000 -0400 @@ -813,7 +813,7 @@ get_all_applications_from_dir (GMenuTree return list; } -static GSList * +GSList * get_all_applications (void) { GMenuTree *tree; diff -up gnome-panel-2.19.6/gnome-panel/launcher.c.launcher-desktop-file-improvements gnome-panel-2.19.6/gnome-panel/launcher.c --- gnome-panel-2.19.6/gnome-panel/launcher.c.launcher-desktop-file-improvements 2007-08-13 19:36:51.000000000 -0400 +++ gnome-panel-2.19.6/gnome-panel/launcher.c 2007-08-26 00:44:48.000000000 -0400 @@ -22,6 +22,7 @@ #include <libgnomeui/gnome-url.h> #include <libgnomevfs/gnome-vfs.h> #include <gdk/gdkx.h> +#include <gmenu-tree.h> #include "launcher.h" @@ -39,6 +40,7 @@ #include "panel-compatibility.h" #include "panel-ditem-editor.h" #include "panel-icon-names.h" +#include "panel-run-dialog.h" static GdkScreen * launcher_get_screen (Launcher *launcher) @@ -285,6 +287,8 @@ static void destroy_launcher (GtkWidget *widget, Launcher *launcher) { + if (launcher->monitor) + gnome_vfs_monitor_cancel (launcher->monitor); launcher_properties_destroy (launcher); launcher_widget_destroy_open_dialogs (launcher); } @@ -458,6 +462,37 @@ drag_data_get_cb (GtkWidget *widg } +static void setup_button (Launcher *launcher); + +static void +desktop_file_changed (GnomeVFSMonitorHandle *handle, + const gchar *monitor_uri, + const gchar *info_uri, + GnomeVFSMonitorEventType event_type, + gpointer user_data) +{ + Launcher *launcher = user_data; + GKeyFile *key_file; + + if (event_type == GNOME_VFS_MONITOR_EVENT_CHANGED || + event_type == GNOME_VFS_MONITOR_EVENT_CREATED) { + gchar *path; + + path = gnome_vfs_get_local_path_from_uri (monitor_uri); + + key_file = g_key_file_new (); + if (g_key_file_load_from_file (key_file, path, + G_KEY_FILE_KEEP_COMMENTS|G_KEY_FILE_KEEP_TRANSLATIONS, + NULL)) { + g_key_file_free (launcher->key_file); + launcher->key_file = key_file; + setup_button (launcher); + } + + g_free (path); + } +} + static Launcher * create_launcher (const char *location) { @@ -523,17 +558,34 @@ create_launcher (const char *location) return NULL; /*button is null*/ } - if (!new_location) + if (!new_location) new_location = g_strdup (location); launcher = g_new0 (Launcher, 1); launcher->info = NULL; launcher->button = NULL; - launcher->location = new_location; launcher->key_file = key_file; launcher->prop_dialog = NULL; launcher->destroy_handler = 0; + launcher->monitor = NULL; + launcher->location = new_location; + + /* Watch for changes to the desktop file. Since we don't want + * to do this for every launcher, we only do it if the desktop + * file contains a X-Panel-Monitor entry. + */ + if (g_key_file_get_boolean (key_file, "Desktop Entry", "X-Panel-Monitor", NULL)) { + gchar *uri; + + uri = g_strdup_printf ("file:%s", new_location); + gnome_vfs_monitor_add (&launcher->monitor, + uri, + GNOME_VFS_MONITOR_FILE, + desktop_file_changed, + launcher); + g_free (uri); + } /* Icon will be setup later */ launcher->button = button_widget_new (NULL /* icon */, @@ -662,6 +714,15 @@ static void launcher_changed (PanelDItemEditor *dialog, Launcher *launcher) { + /* If the user manually changes launcher properties, + * we stop monitoring the desktop file to not overwrite + * user changes. + */ + if (launcher->monitor) { + gnome_vfs_monitor_cancel (launcher->monitor); + launcher->monitor = NULL; + } + /* Setup the button look */ setup_button (launcher); } @@ -737,14 +798,44 @@ static void launcher_saved (GtkWidget *dialog, Launcher *launcher) { - const char *uri; + const char *uri, *path; GConfClient *client; const char *key; + const char *entry; + GKeyFile *key_file; uri = panel_ditem_editor_get_uri (PANEL_DITEM_EDITOR (dialog)); if (panel_launcher_get_filename (uri) != NULL) - uri = panel_launcher_get_filename (uri); + path = panel_launcher_get_filename (uri); + else + path = uri; + /* When the user selects a desktop file in the ditem editor, + * start monitoring the desktop file for changes. + */ + entry = panel_ditem_editor_get_orig_desktop_file (PANEL_DITEM_EDITOR (dialog)); + if (entry) { + key_file = g_key_file_new (); + if (g_key_file_load_from_file (key_file, entry, 0, NULL) && + panel_util_key_file_get_boolean (key_file, "X-Panel-Monitor", FALSE)) { + gchar *s; + + s = g_strdup_printf ("file:%s", entry); + if (launcher->monitor) + gnome_vfs_monitor_cancel (launcher->monitor); + gnome_vfs_monitor_add (&launcher->monitor, + s, + GNOME_VFS_MONITOR_FILE, + desktop_file_changed, + launcher); + g_free (s); + } + g_key_file_free (key_file); + uri = entry; + } + else + uri = path; + if (uri && launcher->location && strcmp (uri, launcher->location)) { client = panel_gconf_get_client (); @@ -1174,3 +1265,170 @@ panel_launcher_set_dnd_enabled (Launcher } else gtk_drag_source_unset (launcher->button); } + + +static gchar * +find_desktop_file_from_exec (const gchar *exec) +{ + GSList *all_applications, *l; + gchar *path = NULL; + gchar **tokens, **tokens2; + gint i, match = 0; + + /* FIXME no need to construct a humongous list here */ + all_applications = get_all_applications (); + + for (l = all_applications; l; l = l->next) { + GMenuTreeEntry *entry = l->data; + const char *entry_exec; + + entry_exec = gmenu_tree_entry_get_exec (entry); + + if (strcmp (exec, entry_exec) == 0) { + path = gmenu_tree_entry_get_desktop_file_path (entry); + break; + } + + tokens = g_strsplit (exec, " ", -1); + tokens2 = g_strsplit (entry_exec, " ", -1); + + for (i = 0; tokens[i] && tokens2[i]; i++) { + if (strcmp (tokens[i], tokens2[i]) != 0) + break; + } + if (i > match) { + match = i; + path = gmenu_tree_entry_get_desktop_file_path (entry); + } + + g_strfreev (tokens); + g_strfreev (tokens2); + } + + path = g_strdup (path); + + g_slist_foreach (all_applications, (GFunc) gmenu_tree_item_unref, NULL); + g_slist_free (all_applications); + + return path; +} + + +static void +update_preferred_app (const gchar *filename, + const gchar *key, + const gchar *exec) +{ + gchar *location; + GKeyFile *key_file; + GError *error = NULL; + gchar *data; + gsize len; + gboolean needs_terminal; + + location = find_desktop_file_from_exec (exec); + key_file = g_key_file_new (); + if (!panel_util_key_file_load_from_uri (key_file, location, + G_KEY_FILE_KEEP_COMMENTS|G_KEY_FILE_KEEP_TRANSLATIONS, + NULL)) { + /* FIXME would be much better if preferred apps were backed by desktop files */ + g_key_file_set_string (key_file, "Desktop Entry", "Version", "1.0"); + g_key_file_set_string (key_file, "Desktop Entry", "Encoding", "UTF-8"); + g_key_file_set_string (key_file, "Desktop Entry", "Type", "Application"); + g_key_file_set_string (key_file, "Desktop Entry", "Exec", exec); + if (strstr (key, "http")) { + g_key_file_set_string (key_file, "Desktop Entry", "Name", "Preferred Web Browser"); + g_key_file_set_string (key_file, "Desktop Entry", "GenericName", "Web Browser"); + g_key_file_set_string (key_file, "Desktop Entry", "Comment", "Browse the Web"); + g_key_file_set_string (key_file, "Desktop Entry", "Icon", "redhat-web-browser.png"); + } + else if (strstr (key, "mailto")) { + g_key_file_set_string (key_file, "Desktop Entry", "Name", "Preferred Mail Reader"); + g_key_file_set_string (key_file, "Desktop Entry", "GenericName", "Mail Reader"); + g_key_file_set_string (key_file, "Desktop Entry", "Comment", "Send email"); + g_key_file_set_string (key_file, "Desktop Entry", "Icon", "redhat-email.png"); + } + if (g_str_has_suffix (key, "command")) { + int len; + char *key2; + + len = strlen (key); + key2 = g_new (char, len - strlen ("command") + strlen ("needs_terminal") + 1); + strncpy (key2, key, len - strlen ("command")); + strcpy (key2 + len - strlen ("command"), "needs_terminal"); + needs_terminal = gconf_client_get_bool (panel_gconf_get_client (), + key2, + NULL); + g_free (key2); + } + else + needs_terminal = FALSE; + g_key_file_set_boolean (key_file, "Desktop Entry", "Terminal", needs_terminal); + } + + g_free (location); + + g_key_file_set_boolean (key_file, "Desktop Entry", "X-Panel-Monitor", TRUE); + g_key_file_set_boolean (key_file, "Desktop Entry", "NoDisplay", TRUE); + + data = g_key_file_to_data (key_file, &len, &error); + if (error) { + g_printerr (_("Failed to convert data for '%s': %s"), + filename, error->message); + g_error_free (error); + g_key_file_free (key_file); + + return; + } + if (!g_file_set_contents (filename, data, len, &error)) { + g_printerr (_("Failed to save '%s': %s"), + filename, error->message); + g_error_free (error); + } + + g_key_file_free (key_file); + g_free (data); +} + +static void +preferred_app_changed (GConfClient *client, + gint notify_id, + GConfEntry *entry, + const gchar *filename) +{ + update_preferred_app (filename, + gconf_entry_get_key (entry), + gconf_value_get_string (entry->value)); +} + +void +panel_preferred_apps_init (void) +{ + GConfClient *client; + gchar *filename, *exec; + gint i; + + const gchar *keys[] = { + "/desktop/gnome/url-handlers/http/command", + "/desktop/gnome/url-handlers/mailto/command", + NULL }; + const gchar *files[] = { + "preferred-web-browser.desktop", + "preferred-mail-reader.desktop", + NULL }; + + client = panel_gconf_get_client (); + + for (i = 0; keys[i]; i++) { + filename = g_build_filename (g_get_user_data_dir (), + "applications", files[i], NULL); + if (!g_file_test (filename, G_FILE_TEST_EXISTS)) { + exec = gconf_client_get_string (client, keys[i], NULL); + update_preferred_app (filename, keys[i], exec); + g_free (exec); + } + gconf_client_notify_add (client, keys[i], + (GConfClientNotifyFunc) preferred_app_changed, + filename, g_free, NULL); + } +} diff -up gnome-panel-2.19.6/gnome-panel/main.c.launcher-desktop-file-improvements gnome-panel-2.19.6/gnome-panel/main.c --- gnome-panel-2.19.6/gnome-panel/main.c.launcher-desktop-file-improvements 2007-08-13 19:36:51.000000000 -0400 +++ gnome-panel-2.19.6/gnome-panel/main.c 2007-08-25 22:28:39.000000000 -0400 @@ -26,6 +26,7 @@ #include "panel-action-protocol.h" #include "panel-lockdown.h" #include "panel-icon-names.h" +#include "launcher.h" #include "xstuff.h" #include "nothing.cP" @@ -81,6 +82,8 @@ main (int argc, char **argv) GCONF_CLIENT_PRELOAD_NONE, NULL); + panel_preferred_apps_init (); + panel_global_config_load (); panel_lockdown_init (); panel_profile_load (); diff -up gnome-panel-2.19.6/gnome-panel/panel-run-dialog.h.launcher-desktop-file-improvements gnome-panel-2.19.6/gnome-panel/panel-run-dialog.h --- gnome-panel-2.19.6/gnome-panel/panel-run-dialog.h.launcher-desktop-file-improvements 2007-08-13 19:36:51.000000000 -0400 +++ gnome-panel-2.19.6/gnome-panel/panel-run-dialog.h 2007-08-25 22:28:39.000000000 -0400 @@ -32,6 +32,8 @@ G_BEGIN_DECLS void panel_run_dialog_present (GdkScreen *screen, guint32 activate_time); +GSList *get_all_applications (void); + G_END_DECLS #endif /* __PANEL_RUN_DIALOG_H__ */ diff -up gnome-panel-2.19.6/gnome-panel/panel-ditem-editor.h.launcher-desktop-file-improvements gnome-panel-2.19.6/gnome-panel/panel-ditem-editor.h --- gnome-panel-2.19.6/gnome-panel/panel-ditem-editor.h.launcher-desktop-file-improvements 2007-08-13 19:36:51.000000000 -0400 +++ gnome-panel-2.19.6/gnome-panel/panel-ditem-editor.h 2007-08-25 22:28:39.000000000 -0400 @@ -101,6 +101,7 @@ void panel_ditem_editor_set_uri (PanelDI const char *uri); G_CONST_RETURN char *panel_ditem_editor_get_uri (PanelDItemEditor *dialog); +G_CONST_RETURN char *panel_ditem_editor_get_orig_desktop_file (PanelDItemEditor *dialog); void panel_ditem_register_save_uri_func (PanelDItemEditor *dialog, PanelDitemSaveUri save_uri,
-- Fedora-desktop-list mailing list Fedora-desktop-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/fedora-desktop-list