[Xfce4-commits] <midori:master> Supersede AddDesktopShortcut by Web App Manager
Christian Dywan
noreply at xfce.org
Fri Apr 12 00:02:01 CEST 2013
Updating branch refs/heads/master
to 67add99e7432e8199362056ecd065a3463be7c93 (commit)
from a18d036cba8e2601c5d0e7bc1a3b88fb2939b030 (commit)
commit 67add99e7432e8199362056ecd065a3463be7c93
Author: Christian Dywan <christian at twotoasts.de>
Date: Thu Apr 11 23:57:51 2013 +0200
Supersede AddDesktopShortcut by Web App Manager
Launchers can be created from websites, apps appear in a panel.
extensions/apps.vala | 279 +++++++++++++++++++++++++++++++++++++++++++++++
katze/katze.vapi | 3 +-
midori/midori-app.c | 2 +-
midori/midori-browser.c | 60 +----------
midori/midori-stock.h | 2 +-
midori/midori-view.c | 3 -
midori/midori.vapi | 11 ++-
po/POTFILES.in | 1 +
tests/app.vala | 2 -
9 files changed, 297 insertions(+), 66 deletions(-)
diff --git a/extensions/apps.vala b/extensions/apps.vala
new file mode 100644
index 0000000..6015d20
--- /dev/null
+++ b/extensions/apps.vala
@@ -0,0 +1,279 @@
+/*
+ Copyright (C) 2013 Christian Dywan <christian at twotoasts.de>
+
+ This library 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.1 of the License, or (at your option) any later version.
+
+ See the file COPYING for the full license text.
+*/
+
+namespace Apps {
+ const string EXEC_PREFIX = PACKAGE_NAME + " -a ";
+
+ private class Launcher : GLib.Object, GLib.Initable {
+ internal GLib.File file;
+ internal string name;
+ internal string icon_name;
+ internal string exec;
+ internal string uri;
+
+ internal static async void create (GLib.File folder, string uri, string title) {
+ /* Strip LRE leading character and / */
+ string filename = title.delimit ("/", ' ') + ".desktop";
+ string exec = EXEC_PREFIX + uri;
+ string name = title;
+ // TODO: Midori.Paths.get_icon save to png
+ string icon_name = Midori.Stock.WEB_BROWSER;
+ string contents = """
+ [Desktop Entry]
+ Version=1.0
+ Type=Application
+ Name=%s
+ Exec=%s
+ TryExec=%s
+ Icon=%s
+ Categories=Network;
+ """.printf (name, exec, PACKAGE_NAME, icon_name);
+ var file = folder.get_child (filename);
+ try {
+ yield file.replace_contents_async (contents.data, null, false, GLib.FileCreateFlags.NONE, null, null);
+ }
+ catch (Error error) {
+ // TODO GUI infobar
+ warning ("Failed to create new launcher: %s", error.message);
+ }
+ }
+
+ internal Launcher (GLib.File file) {
+ this.file = file;
+ }
+
+ bool init (GLib.Cancellable? cancellable) throws GLib.Error {
+ if (!file.get_basename ().has_suffix (".desktop"))
+ return false;
+
+ var keyfile = new GLib.KeyFile ();
+ keyfile.load_from_file (file.get_path (), GLib.KeyFileFlags.NONE);
+ exec = keyfile.get_string ("Desktop Entry", "Exec");
+ if (!exec.has_prefix (EXEC_PREFIX))
+ return false;
+
+ name = keyfile.get_string ("Desktop Entry", "Name");
+ icon_name = keyfile.get_string ("Desktop Entry", "Icon");
+ uri = exec.replace (EXEC_PREFIX, "");
+ return true;
+ }
+ }
+
+ private class Sidebar : Gtk.VBox, Midori.Viewable {
+ Gtk.Toolbar? toolbar = null;
+ Gtk.ListStore store = new Gtk.ListStore (1, typeof (Launcher));
+ Gtk.TreeView treeview;
+ Katze.Array array;
+
+ public unowned string get_stock_id () {
+ return Midori.Stock.WEB_BROWSER;
+ }
+
+ public unowned string get_label () {
+ return _("Applications");
+ }
+
+ public Gtk.Widget get_toolbar () {
+ if (toolbar == null) {
+ toolbar = new Gtk.Toolbar ();
+ toolbar.set_icon_size (Gtk.IconSize.BUTTON);
+ }
+ return toolbar;
+ }
+
+ public Sidebar (Katze.Array array) {
+ Gtk.TreeViewColumn column;
+
+ treeview = new Gtk.TreeView.with_model (store);
+ treeview.headers_visible = false;
+
+ store.set_sort_column_id (0, Gtk.SortType.ASCENDING);
+ store.set_sort_func (0, tree_sort_func);
+
+ column = new Gtk.TreeViewColumn ();
+ Gtk.CellRendererPixbuf renderer_icon = new Gtk.CellRendererPixbuf ();
+ column.pack_start (renderer_icon, false);
+ column.set_cell_data_func (renderer_icon, on_render_icon);
+ treeview.append_column (column);
+
+ column = new Gtk.TreeViewColumn ();
+ column.set_sizing (Gtk.TreeViewColumnSizing.AUTOSIZE);
+ Gtk.CellRendererText renderer_text = new Gtk.CellRendererText ();
+ column.pack_start (renderer_text, true);
+ column.set_expand (true);
+ column.set_cell_data_func (renderer_text, on_render_text);
+ treeview.append_column (column);
+
+ treeview.show ();
+ pack_start (treeview, true, true, 0);
+ assert (treeview.get_n_columns () > 0);;
+
+ this.array = array;
+ array.add_item.connect (launcher_added);
+ array.remove_item.connect (launcher_removed);
+ foreach (GLib.Object item in array.get_items ())
+ launcher_added (item);
+ }
+
+ private int tree_sort_func (Gtk.TreeModel model, Gtk.TreeIter a, Gtk.TreeIter b) {
+ Launcher launcher1, launcher2;
+ model.get (a, 0, out launcher1);
+ model.get (b, 0, out launcher2);
+ return strcmp (launcher1.name, launcher2.name);
+ }
+ void launcher_added (GLib.Object item) {
+ var launcher = item as Launcher;
+ Gtk.TreeIter iter;
+ store.append (out iter);
+ store.set (iter, 0, launcher);
+ }
+
+ void launcher_removed (GLib.Object item) {
+ // TODO remove iter
+ }
+
+ private void on_render_icon (Gtk.CellLayout column, Gtk.CellRenderer renderer,
+ Gtk.TreeModel model, Gtk.TreeIter iter) {
+
+ Launcher launcher;
+ model.get (iter, 0, out launcher);
+ if (launcher.icon_name != null)
+ renderer.set ("icon-name", launcher.icon_name);
+ else
+ renderer.set ("stock-id", Gtk.STOCK_FILE);
+ renderer.set ("stock-size", Gtk.IconSize.BUTTON,
+ "xpad", 4);
+ }
+
+ private void on_render_text (Gtk.CellLayout column, Gtk.CellRenderer renderer,
+ Gtk.TreeModel model, Gtk.TreeIter iter) {
+
+ Launcher launcher;
+ model.get (iter, 0, out launcher);
+ renderer.set ("markup",
+ Markup.printf_escaped ("<b>%s</b>\n%s",
+ launcher.name, launcher.uri),
+ "ellipsize", Pango.EllipsizeMode.END);
+ }
+ }
+
+ private class Manager : Midori.Extension {
+ internal Katze.Array array;
+ internal GLib.File app_folder;
+ internal GLib.FileMonitor? monitor;
+ internal GLib.List<Gtk.Widget> widgets;
+
+ void app_changed (GLib.File file, GLib.File? other, GLib.FileMonitorEvent event) {
+ try {
+ switch (event) {
+ case GLib.FileMonitorEvent.DELETED:
+ // TODO array.remove_item ();
+ break;
+ case GLib.FileMonitorEvent.CREATED:
+ var launcher = new Launcher (file);
+ if (launcher.init ())
+ array.add_item (launcher);
+ break;
+ case GLib.FileMonitorEvent.CHANGED:
+ // TODO
+ break;
+ }
+ }
+ catch (Error error) {
+ warning ("Application changed: %s", error.message);
+ }
+ }
+
+ async void populate_apps () {
+ var data_dir = File.new_for_path (Midori.Paths.get_user_data_dir ());
+ app_folder = data_dir.get_child ("applications");
+ try {
+ monitor = app_folder.monitor_directory (0, null);
+ monitor.changed.connect (app_changed);
+
+ var enumerator = yield app_folder.enumerate_children_async (FileAttribute.STANDARD_NAME, 0);
+ while (true) {
+ var files = yield enumerator.next_files_async (10);
+ if (files == null)
+ break;
+ foreach (var info in files) {
+ var desktop_file = app_folder.get_child (info.get_name ());
+ try {
+ var launcher = new Launcher (desktop_file);
+ if (launcher.init ())
+ array.add_item (launcher);
+ }
+ catch (Error error) {
+ warning ("Failed to parse launcher: %s", error.message);
+ }
+ }
+ }
+ }
+ catch (Error io_error) {
+ monitor = null;
+ warning ("Failed to list .desktop files: %s", io_error.message);
+ }
+ }
+
+ void tool_menu_populated (Midori.Browser browser, Gtk.Menu menu) {
+ var menuitem = new Gtk.MenuItem.with_mnemonic (_("Create _Launcher"));
+ menuitem.show ();
+ menu.append (menuitem);
+ menuitem.activate.connect (() => {
+ var view = browser.tab as Midori.View;
+ Launcher.create.begin (app_folder,
+ view.get_display_uri (), view.get_display_title ());
+ });
+ }
+
+ void browser_added (Midori.Browser browser) {
+ var viewable = new Sidebar (array);
+ viewable.show ();
+ browser.panel.append_page (viewable);
+ browser.populate_tool_menu.connect (tool_menu_populated);
+ // TODO website context menu
+ widgets.append (viewable);
+ }
+
+ void activated (Midori.App app) {
+ array = new Katze.Array (typeof (Launcher));
+ populate_apps.begin ();
+ widgets = new GLib.List<Gtk.Widget> ();
+ foreach (var browser in app.get_browsers ())
+ browser_added (browser);
+ app.add_browser.connect (browser_added);
+ }
+
+ void deactivated () {
+ var app = get_app ();
+ if (monitor != null)
+ monitor.changed.disconnect (app_changed);
+ app.add_browser.disconnect (browser_added);
+ foreach (var widget in widgets)
+ widget.destroy ();
+ }
+
+ internal Manager () {
+ GLib.Object (name: _("Web App Manager"),
+ description: _("Manage websites installed as applications"),
+ version: "0.1" + Midori.VERSION_SUFFIX,
+ authors: "Christian Dywan <christian at twotoasts.de>");
+
+ this.activate.connect (activated);
+ this.deactivate.connect (deactivated);
+ }
+ }
+}
+
+public Midori.Extension extension_init () {
+ return new Apps.Manager ();
+}
+
diff --git a/katze/katze.vapi b/katze/katze.vapi
index c5cf318..776b06f 100644
--- a/katze/katze.vapi
+++ b/katze/katze.vapi
@@ -9,7 +9,8 @@ namespace Katze {
[CCode (cheader_filename = "katze/katze.h")]
public class Array : Katze.Item {
public Array (GLib.Type type);
- public void add_item (GLib.Object item);
+ public signal void add_item (GLib.Object item);
+ public signal void remove_item (GLib.Object item);
public uint get_length ();
public GLib.List<unowned Item> get_items ();
}
diff --git a/midori/midori-app.c b/midori/midori-app.c
index 435f11b..cf59605 100644
--- a/midori/midori-app.c
+++ b/midori/midori-app.c
@@ -1353,7 +1353,7 @@ midori_app_setup (gint *argc,
static GtkStockItem items[] =
{
{ STOCK_IMAGE },
- { STOCK_WEB_BROWSER },
+ { MIDORI_STOCK_WEB_BROWSER },
{ STOCK_NEWS_FEED },
{ STOCK_STYLE },
diff --git a/midori/midori-browser.c b/midori/midori-browser.c
index 2e9dbba..c0d5563 100644
--- a/midori/midori-browser.c
+++ b/midori/midori-browser.c
@@ -2546,48 +2546,6 @@ _action_add_speed_dial_activate (GtkAction* action,
}
static void
-_action_add_desktop_shortcut_activate (GtkAction* action,
- MidoriBrowser* browser)
-{
- #if defined (GDK_WINDOWING_X11)
- GtkWidget* tab = midori_browser_get_current_tab (browser);
- KatzeItem* item = midori_view_get_proxy_item (MIDORI_VIEW (tab));
- const gchar* app_name = katze_item_get_name (item);
- gchar* app_exec = g_strconcat ("midori -a ", katze_item_get_uri (item), NULL);
- GKeyFile* keyfile = g_key_file_new ();
- /* Strip LRE leading character and / */
- gchar* filename = g_strdelimit (g_strconcat (app_name, ".desktop", NULL), "/", ' ');
- gchar* app_dir = g_build_filename (g_get_user_data_dir (), "applications", filename, NULL);
- #if WEBKIT_CHECK_VERSION (1, 3, 13)
- /* FIXME: midori_paths_get_icon */
- gchar* app_icon = g_strdup (STOCK_WEB_BROWSER);
- #else
- const gchar* icon_uri = midori_view_get_icon_uri (MIDORI_VIEW (tab));
- gchar* app_icon = katze_net_get_cached_path (NULL, icon_uri, "icons");
- if (!g_file_test (app_icon, G_FILE_TEST_EXISTS))
- katze_assign (app_icon, g_strdup (STOCK_WEB_BROWSER));
- #endif
- g_key_file_set_string (keyfile, "Desktop Entry", "Version", "1.0");
- g_key_file_set_string (keyfile, "Desktop Entry", "Type", "Application");
- g_key_file_set_string (keyfile, "Desktop Entry", "Name", app_name);
- g_key_file_set_string (keyfile, "Desktop Entry", "Exec", app_exec);
- g_key_file_set_string (keyfile, "Desktop Entry", "TryExec", PACKAGE_NAME);
- g_key_file_set_string (keyfile, "Desktop Entry", "Icon", app_icon);
- g_key_file_set_string (keyfile, "Desktop Entry", "Categories", "Network;");
- sokoke_key_file_save_to_file (keyfile, app_dir, NULL);
- g_free (app_dir);
- g_free (filename);
- g_free (app_exec);
- g_free (app_icon);
- g_key_file_free (keyfile);
- #elif defined(GDK_WINDOWING_QUARTZ)
- /* TODO: Implement */
- #elif defined (GDK_WINDOWING_WIN32)
- /* TODO: Implement */
- #endif
-}
-
-static void
midori_browser_subscribe_to_news_feed (MidoriBrowser* browser,
const gchar* uri)
{
@@ -2646,8 +2604,7 @@ _action_compact_add_activate (GtkAction* action,
{
GtkWidget* dialog;
GtkBox* box;
- const gchar* actions[] = { "BookmarkAdd", "AddSpeedDial",
- "AddDesktopShortcut", "AddNewsFeed" };
+ const gchar* actions[] = { "BookmarkAdd", "AddSpeedDial", "AddNewsFeed" };
guint i;
dialog = g_object_new (GTK_TYPE_DIALOG,
@@ -3249,9 +3206,6 @@ _action_compact_menu_populate_popup (GtkAction* action,
{ "BookmarksImport" },
{ "BookmarksExport" },
{ "ClearPrivateData" },
- #if defined (GDK_WINDOWING_X11)
- { "AddDesktopShortcut" },
- #endif
{ "-" },
{ NULL },
#ifndef HAVE_GRANITE
@@ -5339,10 +5293,6 @@ static const GtkActionEntry entries[] =
{ "AddSpeedDial", NULL,
N_("Add to Speed _dial"), "<Ctrl>h",
NULL, G_CALLBACK (_action_add_speed_dial_activate) },
- { "AddDesktopShortcut", NULL,
- /* N_("Add Shortcut to the _desktop"), "", */
- N_("Create _Launcher"), "",
- NULL, G_CALLBACK (_action_add_desktop_shortcut_activate) },
{ "AddNewsFeed", NULL,
N_("Subscribe to News _feed"), NULL,
NULL, G_CALLBACK (_action_add_news_feed_activate) },
@@ -5769,7 +5719,6 @@ static const gchar* ui_markup =
"<separator/>"
"<menuitem action='SaveAs'/>"
"<menuitem action='AddSpeedDial'/>"
- "<menuitem action='AddDesktopShortcut'/>"
"<separator/>"
"<menuitem action='TabClose'/>"
"<menuitem action='WindowClose'/>"
@@ -5896,7 +5845,7 @@ midori_browser_realize_cb (GtkStyle* style,
if (gtk_icon_theme_has_icon (icon_theme, "midori"))
gtk_window_set_icon_name (GTK_WINDOW (browser), "midori");
else
- gtk_window_set_icon_name (GTK_WINDOW (browser), STOCK_WEB_BROWSER);
+ gtk_window_set_icon_name (GTK_WINDOW (browser), MIDORI_STOCK_WEB_BROWSER);
}
}
@@ -6067,7 +6016,7 @@ midori_browser_init (MidoriBrowser* browser)
g_signal_connect (browser, "destroy",
G_CALLBACK (midori_browser_destroy_cb), NULL);
gtk_window_set_role (GTK_WINDOW (browser), "browser");
- gtk_window_set_icon_name (GTK_WINDOW (browser), STOCK_WEB_BROWSER);
+ gtk_window_set_icon_name (GTK_WINDOW (browser), MIDORI_STOCK_WEB_BROWSER);
#if GTK_CHECK_VERSION (3, 4, 0)
gtk_window_set_hide_titlebar_when_maximized (GTK_WINDOW (browser), TRUE);
#endif
@@ -6292,9 +6241,6 @@ midori_browser_init (MidoriBrowser* browser)
_action_set_sensitive (browser, "EncodingCustom", FALSE);
_action_set_visible (browser, "LastSession", FALSE);
- #if !defined (GDK_WINDOWING_X11)
- _action_set_visible (browser, "AddDesktopShortcut", FALSE);
- #endif
_action_set_visible (browser, "Bookmarks", browser->bookmarks != NULL);
_action_set_visible (browser, "BookmarkAdd", browser->bookmarks != NULL);
diff --git a/midori/midori-stock.h b/midori/midori-stock.h
index fc8ce5c..e674c37 100644
--- a/midori/midori-stock.h
+++ b/midori/midori-stock.h
@@ -17,7 +17,7 @@
#define STOCK_BOOKMARKS "user-bookmarks"
#define STOCK_EXTENSION "extension"
#define STOCK_HISTORY "document-open-recent"
-#define STOCK_WEB_BROWSER "web-browser"
+#define MIDORI_STOCK_WEB_BROWSER "web-browser"
#define STOCK_NEWS_FEED "internet-news-reader"
#define STOCK_STYLE "preferences-desktop-theme"
#define STOCK_TRANSFER "package"
diff --git a/midori/midori-view.c b/midori/midori-view.c
index 1d300c3..1a44ed3 100644
--- a/midori/midori-view.c
+++ b/midori/midori-view.c
@@ -2981,9 +2981,6 @@ midori_view_populate_popup (MidoriView* view,
gtk_action_group_get_action (actions, "AddSpeedDial"));
gtk_menu_shell_append (menu_shell, menuitem);
}
- menuitem = sokoke_action_create_popup_menu_item (
- gtk_action_group_get_action (actions, "AddDesktopShortcut"));
- gtk_menu_shell_append (menu_shell, menuitem);
menuitem = sokoke_action_create_popup_menu_item (
gtk_action_group_get_action (actions, "SaveAs"));
diff --git a/midori/midori.vapi b/midori/midori.vapi
index 83871f5..71bfcdc 100644
--- a/midori/midori.vapi
+++ b/midori/midori.vapi
@@ -1,10 +1,13 @@
/* Copyright (C) 2010 Christian Dywan <christian at twotoasts.de>
This file is licensed under the terms of the expat license, see the file EXPAT. */
+public const string PACKAGE_NAME;
+
[CCode (cprefix = "Midori", lower_case_cprefix = "midori_")]
namespace Midori {
public const string VERSION_SUFFIX;
namespace Stock {
+ public const string WEB_BROWSER;
public const string PLUGINS;
}
@@ -71,7 +74,7 @@ namespace Midori {
[NoAccessorMethod]
public Gtk.Notebook notebook { owned get; }
[NoAccessorMethod]
- public Gtk.Widget panel { owned get; }
+ public Midori.Panel panel { owned get; }
[NoAccessorMethod]
public string uri { owned get; set; }
public Gtk.Widget? tab { get; set; }
@@ -109,6 +112,12 @@ namespace Midori {
}
[CCode (cheader_filename = "midori/midori.h")]
+ public class Panel : Gtk.HBox {
+ public Panel ();
+ public int append_page (Midori.Viewable viewable);
+ }
+
+ [CCode (cheader_filename = "midori/midori.h")]
public class Extension : GLib.Object {
[CCode (has_construct_function = false)]
public Extension ();
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 2d79251..c0b1680 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -85,3 +85,4 @@ extensions/cookie-permissions/cookie-permission-manager-preferences-window.h
extensions/cookie-permissions/cookie-permission-manager.c
extensions/cookie-permissions/cookie-permission-manager.h
extensions/cookie-permissions/main.c
+extensions/apps.vala
diff --git a/tests/app.vala b/tests/app.vala
index eaa8603..b44726e 100644
--- a/tests/app.vala
+++ b/tests/app.vala
@@ -9,8 +9,6 @@
See the file COPYING for the full license text.
*/
-extern const string PACKAGE_NAME;
-
bool check_sensible_window_size (Gtk.Window window, Midori.WebSettings settings) {
Gdk.Rectangle monitor;
window.screen.get_monitor_geometry (0, out monitor);
More information about the Xfce4-commits
mailing list