[epiphany] Add basic support for Web Applications



commit ebac66a05be1e71bd978f070fb842fd8b457e7e8
Author: Xan Lopez <xlopez igalia com>
Date:   Thu Jul 14 00:47:33 2011 +0200

    Add basic support for Web Applications
    
    Allow to save any page as a "Web Application". A new .desktop file
    will be created, and added to the Shell as a new application. It will
    launch epiphany in application mode, with its own private profile
    (inheriting some data from the main profile, like the relevant domain
    cookies) and in a new process.

 data/ui/epiphany-ui.xml   |    1 +
 embed/ephy-web-view.c     |  203 +++++++++++++++++++++++++++++++++++++++++++++
 embed/ephy-web-view.h     |    8 ++
 src/ephy-main.c           |   33 +++++---
 src/ephy-toolbars-model.c |   12 ++-
 src/ephy-window.c         |   28 ++++--
 src/window-commands.c     |  191 ++++++++++++++++++++++++++++++++++++++++++
 src/window-commands.h     |    3 +
 8 files changed, 453 insertions(+), 26 deletions(-)
---
diff --git a/data/ui/epiphany-ui.xml b/data/ui/epiphany-ui.xml
index 1c2fff3..2091def 100644
--- a/data/ui/epiphany-ui.xml
+++ b/data/ui/epiphany-ui.xml
@@ -6,6 +6,7 @@
 			<menuitem name="FileOpenMenu" action="FileOpen"/>
 			<separator name="FileSep1"/>	
 			<menuitem name="FileSaveAsMenu" action="FileSaveAs"/>
+			<menuitem name="FileSaveAsApplicationMenu" action="FileSaveAsApplication"/>
 			<separator name="FileSep2"/>
 			<menuitem name="FilePrintSetupMenu" action="FilePrintSetup"/>
 			<menuitem name="FilePrintPreviewMenu" action="FilePrintPreview"/>
diff --git a/embed/ephy-web-view.c b/embed/ephy-web-view.c
index fd45772..6a52f06 100644
--- a/embed/ephy-web-view.c
+++ b/embed/ephy-web-view.c
@@ -24,10 +24,12 @@
 
 #include <gio/gio.h>
 #include <glib/gi18n.h>
+#include <glib/gstdio.h>
 #include <gtk/gtk.h>
 #include <string.h>
 #include <webkit/webkit.h>
 #include <gnome-keyring.h>
+#include <libsoup/soup-gnome.h>
 
 #include "ephy-debug.h"
 #include "ephy-embed.h"
@@ -3684,3 +3686,204 @@ ephy_web_view_load_homepage (EphyWebView *view)
   return is_empty;
 }
 
+#define EPHY_WEB_APP_TOOLBAR "<?xml version=\"1.0\"?>" \
+                             "<toolbars version=\"1.1\">" \
+                             "  <toolbar name=\"DefaultToolbar\" hidden=\"true\" editable=\"false\">" \
+                             "    <toolitem name=\"NavigationBack\"/>" \
+                             "    <toolitem name=\"NavigationForward\"/>" \
+                             "    <toolitem name=\"ViewReload\"/>" \
+                             "    <toolitem name=\"ViewCancel\"/>" \
+                             "  </toolbar>" \
+                             "</toolbars>"
+
+#define EPHY_TOOLBARS_XML_FILE "epiphany-toolbars-3.xml"
+
+static char *
+create_desktop_file (EphyWebView *view,
+                     const char *profile_dir,
+                     const char *title,
+                     GdkPixbuf *icon)
+{
+  GKeyFile *file;
+  char *exec_string;
+  char *data;
+  char *filename, *desktop_file_path;
+  char *link_path;
+  GFile *link;
+
+  g_return_val_if_fail (profile_dir, NULL);
+
+  file = g_key_file_new ();
+  g_key_file_set_value (file, "Desktop Entry", "Name", title);
+  exec_string = g_strdup_printf ("jhbuild run epiphany --application-mode --profile=\"%s\" %s",
+                                 profile_dir,
+                                 webkit_web_view_get_uri (WEBKIT_WEB_VIEW (view)));
+  g_key_file_set_value (file, "Desktop Entry", "Exec", exec_string);
+  g_free (exec_string);
+  g_key_file_set_value (file, "Desktop Entry", "StartupNotification", "true");
+  g_key_file_set_value (file, "Desktop Entry", "Terminal", "false");
+  g_key_file_set_value (file, "Desktop Entry", "Type", "Application");
+
+  if (icon) {
+    GOutputStream *stream;
+    char *path;
+    GFile *image;
+
+    path = g_build_filename (profile_dir, "app-icon.png", NULL);
+    image = g_file_new_for_path (path);
+
+    stream = (GOutputStream*)g_file_create (image, 0, NULL, NULL);
+    gdk_pixbuf_save_to_stream (icon, stream, "png", NULL, NULL, NULL);
+    g_key_file_set_value (file, "Desktop Entry", "Icon", path);
+
+    g_object_unref (stream);
+    g_object_unref (image);
+    g_free (path);
+  }
+
+  g_key_file_set_value (file, "Desktop Entry", "StartupWMClass", title);
+
+  data = g_key_file_to_data (file, NULL, NULL);
+  filename = g_strconcat (title, ".desktop", NULL);
+  desktop_file_path = g_build_filename (profile_dir, filename, NULL);
+  g_key_file_free (file);
+
+  if (!g_file_set_contents (desktop_file_path, data, -1, NULL)) {
+    g_free (desktop_file_path);
+    desktop_file_path = NULL;
+  }
+
+  g_free (data);
+
+  /* Create a symlink in XDG_DATA_DIR/applications for the Shell to
+   * pick up this application. */
+  link_path = g_build_filename (g_get_user_data_dir (), "applications", filename, NULL);
+  link = g_file_new_for_path (link_path);
+  g_free (link_path);
+  g_file_make_symbolic_link (link, desktop_file_path, NULL, NULL);
+  g_object_unref (link);
+  g_free (filename);
+
+  return desktop_file_path;
+}
+
+static void
+create_cookie_jar_for_domain (EphyWebView *view, const char *directory)
+{
+  SoupSession *session;
+  GSList *cookies, *p;
+  SoupCookieJar *current_jar, *new_jar;
+  char *domain, *filename;
+  SoupURI *uri;
+
+  /* Create the new cookie jar */
+  filename = g_build_filename (directory, "cookies.sqlite", NULL);
+  new_jar = (SoupCookieJar*)soup_cookie_jar_sqlite_new (filename, FALSE);
+  g_free (filename);
+
+  /* The app domain for the current view */
+  uri = soup_uri_new (webkit_web_view_get_uri (WEBKIT_WEB_VIEW (view)));
+  domain = uri->host;
+
+  /* The current cookies */
+  session = webkit_get_default_session ();
+  current_jar = (SoupCookieJar*)soup_session_get_feature (session, SOUP_TYPE_COOKIE_JAR);
+  cookies = soup_cookie_jar_all_cookies (current_jar);
+
+  for (p = cookies; p; p = p->next) {
+    SoupCookie *cookie = (SoupCookie*)p->data;
+
+    if (g_str_has_suffix (cookie->domain, domain))
+      soup_cookie_jar_add_cookie (new_jar, cookie);
+    else
+      soup_cookie_free (cookie);
+  }
+
+  soup_uri_free (uri);
+  g_slist_free (cookies);
+}
+
+char *
+ephy_web_view_create_web_application (EphyWebView *view, const char *title, GdkPixbuf *icon)
+{
+  char *app_dir;
+  char *profile_dir = NULL;
+  char *toolbar_path = NULL;
+  char *desktop_file_path = NULL;
+
+  g_return_val_if_fail (EPHY_IS_WEB_VIEW (view), NULL);
+
+  /* If there's already a WebApp profile for the contents of this
+   * view, do nothing. TODO: create a method to check this and use it
+   * to ask the user if she wants to overwrite the existing WebApp. */
+  app_dir = g_strconcat (EPHY_WEB_APP_PREFIX, title, NULL);
+  profile_dir = g_build_filename (ephy_dot_dir (), app_dir, NULL);
+  g_free (app_dir);
+  if (g_file_test (profile_dir, G_FILE_TEST_IS_DIR))
+    goto out;
+
+  /* Create the profile directory, populate it. */
+  if (g_mkdir (profile_dir, 488) == -1) {
+    LOG ("Failed to create directory %s", profile_dir);
+    goto out;
+  }
+
+  /* Things we need in a WebApp's profile:
+     - Toolbar layout
+     - Our own cookies file, copying the relevant cookies for the
+       app's domain.
+  */
+  toolbar_path = g_build_filename (profile_dir, EPHY_TOOLBARS_XML_FILE, NULL);
+  if (!g_file_set_contents (toolbar_path, EPHY_WEB_APP_TOOLBAR, -1, NULL))
+    goto out;
+
+  create_cookie_jar_for_domain (view, profile_dir);
+
+  /* Create the deskop file. */
+  desktop_file_path = create_desktop_file (view, profile_dir, title, icon);
+
+out:
+  if (toolbar_path)
+    g_free (toolbar_path);
+
+  if (profile_dir)
+    g_free (profile_dir);
+
+  return desktop_file_path;
+}
+
+/**
+ * ephy_web_view_get_snapshot: takes a snapshot of the requested region of a #EphyWebView
+ * @view: the #EphyWebView
+ * @x: the x coordinate of the snapshot
+ * @y: the y coordinate of the snapshot
+ * @width: the width of the snapshot
+ * @height: the height of the snapshot
+ * 
+ * Returns: (transfer full): a #GdkPixbuf with a snapshot of the requested area.
+ **/
+GdkPixbuf *
+ephy_web_view_get_snapshot (EphyWebView *view, int x, int y, int width, int height)
+{
+  cairo_surface_t *surface;
+  cairo_t *cr;
+  GdkPixbuf *snapshot;
+  GtkAllocation allocation;
+
+  g_return_val_if_fail (EPHY_IS_WEB_VIEW (view), NULL);
+
+  gtk_widget_get_allocation (GTK_WIDGET (view), &allocation);
+  surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24,
+                                        allocation.width,
+                                        allocation.height);
+  cr = cairo_create (surface);
+  cairo_rectangle (cr, x, y, width, height);
+  cairo_clip (cr);
+  gtk_widget_draw (GTK_WIDGET (view), cr);
+
+  snapshot = gdk_pixbuf_get_from_surface (surface, x, y, width, height);
+  cairo_destroy (cr);
+  cairo_surface_destroy (surface);
+
+  return snapshot;
+}
diff --git a/embed/ephy-web-view.h b/embed/ephy-web-view.h
index 508ed2c..bf865d3 100644
--- a/embed/ephy-web-view.h
+++ b/embed/ephy-web-view.h
@@ -88,6 +88,8 @@ typedef enum {
   EPHY_WEB_VIEW_ERROR_PAGE_CRASH
 } EphyWebViewErrorPage;
 
+#define EPHY_WEB_APP_PREFIX "app-"
+
 struct _EphyWebView
 {
   WebKitWebView parent;
@@ -194,6 +196,12 @@ void                       ephy_web_view_save                     (EphyWebView
                                                                    const char                *uri);
 gboolean                   ephy_web_view_load_homepage            (EphyWebView               *view);
 
+char *
+ephy_web_view_create_web_application (EphyWebView *view, const char *title, GdkPixbuf *icon);
+
+GdkPixbuf *
+ephy_web_view_get_snapshot (EphyWebView *view, int x, int y, int width, int height);
+
 G_END_DECLS
 
 #endif
diff --git a/src/ephy-main.c b/src/ephy-main.c
index b85fa75..a87b4b4 100644
--- a/src/ephy-main.c
+++ b/src/ephy-main.c
@@ -261,9 +261,6 @@ main (int argc,
    */
   LIBXML_TEST_VERSION;
 
-  /* sets name to help matching with the .desktop file */
-  g_set_prgname ("epiphany");
-
   /* If we're given -remote arguments, translate them */
   if (argc >= 2 && strcmp (argv[1], "-remote") == 0) {
     const char *opening, *closing;
@@ -400,12 +397,6 @@ main (int argc,
   if (user_time == 0)
       user_time = slowly_and_stupidly_obtain_timestamp (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
 
-  /* sets the name to appear in the window list applet when grouping windows */
-  g_set_application_name (_("Web Browser"));
-
-  /* Set default window icon */
-  gtk_window_set_default_icon_name (EPHY_STOCK_EPHY);
-
   startup_error_quark = g_quark_from_static_string ("epiphany-startup-error");
 
   /* Start our services */
@@ -426,11 +417,31 @@ main (int argc,
   /* Now create the shell */
   if (private_instance)
     mode = EPHY_EMBED_SHELL_MODE_PRIVATE;
-  else if (application_mode)
+  else if (application_mode) {
+    char *app_name;
+
     mode = EPHY_EMBED_SHELL_MODE_APPLICATION;
-  else
+
+    app_name = g_strrstr (profile_directory, EPHY_WEB_APP_PREFIX);
+    if (app_name) {
+      /* Skip the 'app-' part */
+      app_name += strlen (EPHY_WEB_APP_PREFIX);
+
+      g_set_prgname (app_name);
+      g_set_application_name (app_name);
+
+      /* We need to re-set this because we have already parsed the
+       * options, which inits GTK+ and sets this as a side effect. */
+      gdk_set_program_class (app_name);
+    }
+  } else {
     mode = EPHY_EMBED_SHELL_MODE_BROWSER;
 
+    g_set_prgname ("epiphany");
+    g_set_application_name (_("Web Browser"));
+    gtk_window_set_default_icon_name (EPHY_STOCK_EPHY);
+  }
+
   _ephy_shell_create_instance (mode);
 
   startup_flags = get_startup_flags ();
diff --git a/src/ephy-toolbars-model.c b/src/ephy-toolbars-model.c
index 5dc6cf4..346aa02 100644
--- a/src/ephy-toolbars-model.c
+++ b/src/ephy-toolbars-model.c
@@ -19,13 +19,14 @@
  */
 
 #include "config.h"
-
 #include "ephy-toolbars-model.h"
+
+#include "eggtypebuiltins.h"
+#include "ephy-debug.h"
+#include "ephy-embed-shell.h"
 #include "ephy-file-helpers.h"
 #include "ephy-prefs.h"
 #include "ephy-settings.h"
-#include "eggtypebuiltins.h"
-#include "ephy-debug.h"
 
 #include <string.h>
 
@@ -213,8 +214,9 @@ ephy_toolbars_model_load (EphyToolbarsModel *model)
 		}
 	}
 	
-	/* Ensure we have at least 1 toolbar */
-	if (egg_toolbars_model_n_toolbars (eggmodel) < 1)
+	/* Ensure we have at least 1 toolbar unless we are in WebApp mode. */
+	if (ephy_embed_shell_get_mode (embed_shell) != EPHY_EMBED_SHELL_MODE_APPLICATION &&
+            egg_toolbars_model_n_toolbars (eggmodel) < 1)
 	{
 		egg_toolbars_model_add_toolbar (eggmodel, 0, "DefaultToolbar");
 	}
diff --git a/src/ephy-window.c b/src/ephy-window.c
index f8cedf9..a54ee25 100644
--- a/src/ephy-window.c
+++ b/src/ephy-window.c
@@ -131,6 +131,9 @@ static const GtkActionEntry ephy_menu_entries [] = {
 	{ "FileSaveAs", GTK_STOCK_SAVE_AS, N_("Save _Asâ"), "<shift><control>S",
 	  N_("Save the current page"),
 	  G_CALLBACK (window_cmd_file_save_as) },
+	{ "FileSaveAsApplication", GTK_STOCK_SAVE_AS, N_("Save As _Web Applicationâ"), "<shift><control>A",
+	  N_("Save the current page as a Web Application"),
+	  G_CALLBACK (window_cmd_file_save_as_application) },
 	{ "FilePrintSetup", STOCK_PRINT_SETUP, N_("Page Set_up"), NULL,
 	  N_("Setup the page settings for printing"),
 	  G_CALLBACK (window_cmd_file_print_setup) },
@@ -380,19 +383,19 @@ static const struct
 	const gchar *action;
 	gboolean fromToolbar;
 } extra_keybindings [] = {
-	{ GDK_KEY_s,		GDK_CONTROL_MASK,	"FileSaveAs",		FALSE },
+	{ GDK_KEY_s,		GDK_CONTROL_MASK,	"FileSaveAs",		 FALSE },
 	{ GDK_KEY_R,		GDK_CONTROL_MASK |
-				GDK_SHIFT_MASK,		"ViewReload",		FALSE },
+				GDK_SHIFT_MASK,		"ViewReload",		 FALSE },
 	/* Support all the MSIE tricks as well ;) */
-	{ GDK_KEY_F5,		0,			"ViewReload",		FALSE },
-	{ GDK_KEY_F5,		GDK_CONTROL_MASK,	"ViewReload",		FALSE },
-	{ GDK_KEY_F5,		GDK_SHIFT_MASK,		"ViewReload",		FALSE },
+	{ GDK_KEY_F5,		0,			"ViewReload",		 FALSE },
+	{ GDK_KEY_F5,		GDK_CONTROL_MASK,	"ViewReload",		 FALSE },
+	{ GDK_KEY_F5,		GDK_SHIFT_MASK,		"ViewReload",		 FALSE },
 	{ GDK_KEY_F5,		GDK_CONTROL_MASK |
-				GDK_SHIFT_MASK,		"ViewReload",		FALSE },
-	{ GDK_KEY_KP_Add,	GDK_CONTROL_MASK,	"ViewZoomIn",		FALSE },
-	{ GDK_KEY_KP_Subtract,	GDK_CONTROL_MASK,	"ViewZoomOut",		FALSE },
-	{ GDK_KEY_equal,	GDK_CONTROL_MASK,	"ViewZoomIn",		FALSE },
-	{ GDK_KEY_KP_0,		GDK_CONTROL_MASK,	"ViewZoomNormal",	FALSE },
+				GDK_SHIFT_MASK,		"ViewReload",		 FALSE },
+	{ GDK_KEY_KP_Add,	GDK_CONTROL_MASK,	"ViewZoomIn",		 FALSE },
+	{ GDK_KEY_KP_Subtract,	GDK_CONTROL_MASK,	"ViewZoomOut",		 FALSE },
+	{ GDK_KEY_equal,	GDK_CONTROL_MASK,	"ViewZoomIn",		 FALSE },
+	{ GDK_KEY_KP_0,		GDK_CONTROL_MASK,	"ViewZoomNormal",	 FALSE },
 	/* These keys are a bit strange: when pressed with no modifiers, they emit
 	 * KP_PageUp/Down Control; when pressed with Control+Shift they are KP_9/3,
 	 * when NumLock is on they are KP_9/3 and with NumLock and Control+Shift
@@ -804,6 +807,9 @@ get_chromes_visibility (EphyWindow *window,
 		*show_toolbar = (flags & EPHY_WEB_VIEW_CHROME_TOOLBAR) != 0;
 		*show_tabsbar = !priv->is_popup;
 	}
+
+	if (ephy_embed_shell_get_mode (embed_shell) == EPHY_EMBED_SHELL_MODE_APPLICATION)
+		*show_menubar = FALSE;
 }
 
 static void
@@ -1586,6 +1592,8 @@ setup_ui_manager (EphyWindow *window)
 	g_object_set (action, "short_label", _("Open"), NULL);
 	action = gtk_action_group_get_action (action_group, "FileSaveAs");
 	g_object_set (action, "short_label", _("Save As"), NULL);
+	action = gtk_action_group_get_action (action_group, "FileSaveAsApplication");
+	g_object_set (action, "short_label", _("Save As Application"), NULL);
 	action = gtk_action_group_get_action (action_group, "FilePrint");
 	g_object_set (action, "short_label", _("Print"), NULL);
 	action = gtk_action_group_get_action (action_group, "FileBookmarkPage");
diff --git a/src/window-commands.c b/src/window-commands.c
index 32043c9..341ea40 100644
--- a/src/window-commands.c
+++ b/src/window-commands.c
@@ -2,6 +2,7 @@
 /*
  *  Copyright  2000-2004 Marco Pesenti Gritti
  *  Copyright  2009 Collabora Ltd.
+ *  Copyright  2011 Igalia S.L.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -382,6 +383,196 @@ window_cmd_file_save_as (GtkAction *action,
 	gtk_widget_show (GTK_WIDGET (dialog));
 }
 
+typedef struct {
+	EphyWebView *view;
+	GtkWidget *image;
+	GtkWidget *entry;
+	GtkWidget *spinner;
+	GtkWidget *box;
+	char *icon_href;
+} EphyApplicationDialogData;
+
+static void
+ephy_application_dialog_data_free (EphyApplicationDialogData *data)
+{
+	g_free (data->icon_href);
+	g_slice_free (EphyApplicationDialogData, data);
+}
+
+static void
+take_page_snapshot_and_set_image (EphyApplicationDialogData *data)
+{
+	GdkPixbuf *snapshot;
+	int x, y, w, h;
+
+	x = y = 0;
+	w = h = 128; /* GNOME hi-res icon size. */
+
+	snapshot = ephy_web_view_get_snapshot (data->view, x, y, w, h);
+
+	gtk_image_set_from_pixbuf (GTK_IMAGE (data->image), snapshot);
+	g_object_unref (snapshot);
+}
+
+static void
+download_status_changed_cb (WebKitDownload *download,
+			    GParamSpec *spec,
+			    EphyApplicationDialogData *data)
+{
+	WebKitDownloadStatus status = webkit_download_get_status (download);
+	const char *destination;
+
+	switch (status)
+	{
+	case WEBKIT_DOWNLOAD_STATUS_FINISHED:
+		destination = g_filename_from_uri (webkit_download_get_destination_uri (download),
+						   NULL, NULL);
+		gtk_image_set_from_file (GTK_IMAGE (data->image), destination);
+		break;
+	case WEBKIT_DOWNLOAD_STATUS_ERROR:
+	case WEBKIT_DOWNLOAD_STATUS_CANCELLED:
+		/* Something happened, default to a page snapshot. */
+		take_page_snapshot_and_set_image (data);
+		break;
+	default:
+		break;
+	}
+}
+
+static void
+download_icon_and_set_image (EphyApplicationDialogData *data)
+{
+	WebKitNetworkRequest *request;
+	WebKitDownload *download;
+	char *destination, *destination_uri, *tmp_filename;
+
+	request = webkit_network_request_new (data->icon_href);
+	download = webkit_download_new (request);
+	g_object_unref (request);
+
+	tmp_filename = ephy_file_tmp_filename ("ephy-download-XXXXXX", NULL);
+	destination = g_build_filename (ephy_file_tmp_dir (), tmp_filename, NULL);
+	destination_uri = g_filename_to_uri (destination, NULL, NULL);
+	webkit_download_set_destination_uri (download, destination_uri);
+	g_free (destination);
+	g_free (destination_uri);
+	g_free (tmp_filename);
+
+	g_signal_connect (download, "notify::status",
+			  G_CALLBACK (download_status_changed_cb), data);
+
+	webkit_download_start (download);	
+}
+
+static void
+fill_default_application_image (EphyApplicationDialogData *data)
+{
+	WebKitDOMDocument *document;
+	WebKitDOMNodeList *links;
+	gulong length, i;
+
+	document = webkit_web_view_get_dom_document (WEBKIT_WEB_VIEW (data->view));
+	links = webkit_dom_document_get_elements_by_tag_name (document, "link");
+	length = webkit_dom_node_list_get_length (links);
+
+	for (i = 0; i < length; i++)
+	{
+		char *rel;
+		WebKitDOMNode *node = webkit_dom_node_list_item (links, i);
+		rel = webkit_dom_html_link_element_get_rel (WEBKIT_DOM_HTML_LINK_ELEMENT (node));
+		/* TODO: support more than one possible icon. */
+		if (g_strcmp0 (rel, "apple-touch-icon") == 0 ||
+		    g_strcmp0 (rel, "apple-touch-icon-precomposed") == 0)
+		{
+			data->icon_href = webkit_dom_html_link_element_get_href (WEBKIT_DOM_HTML_LINK_ELEMENT (node));
+			download_icon_and_set_image (data);
+			g_free (rel);
+			return;
+		}
+	}
+
+	/* If we make it here, no "apple-touch-icon" link was
+	 * found. Take a snapshot of the page. */
+	take_page_snapshot_and_set_image (data);
+}
+
+static void
+fill_default_application_title (EphyApplicationDialogData *data)
+{
+	const char *title = ephy_web_view_get_title (data->view);
+	gtk_entry_set_text (GTK_ENTRY (data->entry), title);
+}
+
+void
+window_cmd_file_save_as_application (GtkAction *action,
+				     EphyWindow *window)
+{
+	EphyEmbed *embed;
+	GtkWidget *dialog, *box, *image, *entry, *content_area;
+	EphyWebView *view;
+	gboolean response;
+	EphyApplicationDialogData *data;
+
+	embed = ephy_embed_container_get_active_child (EPHY_EMBED_CONTAINER (window));
+	g_return_if_fail (embed != NULL);
+
+	view = EPHY_WEB_VIEW (EPHY_GET_WEBKIT_WEB_VIEW_FROM_EMBED (embed));
+
+	/* Show dialog with icon, title. */
+	dialog = gtk_dialog_new_with_buttons (_("Create Web Application"),
+					      GTK_WINDOW (window),
+					      0,
+					      GTK_STOCK_CANCEL,
+					      GTK_RESPONSE_CANCEL,
+					      _("Create"),
+					      GTK_RESPONSE_OK,
+					      NULL);
+
+	content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+	gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+	gtk_box_set_spacing (GTK_BOX (content_area), 14); /* 14 + 2 * 5 = 24 */
+
+	box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 5);
+	gtk_container_add (GTK_CONTAINER (content_area), box);
+
+	image = gtk_image_new ();
+	gtk_widget_set_size_request (image, 128, 128);
+	gtk_container_add (GTK_CONTAINER (box), image);
+
+	entry = gtk_entry_new ();
+	gtk_box_pack_end (GTK_BOX (box), entry, FALSE, FALSE, 0);
+
+	data = g_slice_new0 (EphyApplicationDialogData);
+	data->view = view;
+	data->image = image;
+	data->entry = entry;
+
+	fill_default_application_image (data);
+	fill_default_application_title (data);
+
+	gtk_widget_show_all (dialog);
+
+	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+	response = gtk_dialog_run (GTK_DIALOG (dialog));
+
+	if (response == GTK_RESPONSE_OK)
+	{
+		char *desktop_file;
+
+		/* Create Web Application, including a new profile and .desktop file. */
+		desktop_file = ephy_web_view_create_web_application (view,
+								     gtk_entry_get_text (GTK_ENTRY (data->entry)),
+								     gtk_image_get_pixbuf (GTK_IMAGE (data->image)));
+
+		/* TODO: show a notification when the app is totally
+		 * created and ready to be launched */
+		g_free (desktop_file);
+	}
+
+	ephy_application_dialog_data_free (data);
+	gtk_widget_destroy (dialog);
+}
+
 void
 window_cmd_file_work_offline (GtkAction *action,
 		              EphyWindow *window)
diff --git a/src/window-commands.h b/src/window-commands.h
index 5b37585..e20ca1a 100644
--- a/src/window-commands.h
+++ b/src/window-commands.h
@@ -54,6 +54,9 @@ void window_cmd_file_open	(GtkAction *action,
 void window_cmd_file_save_as    (GtkAction *action,
 				 EphyWindow *window);
 
+void window_cmd_file_save_as_application (GtkAction *action,
+                                          EphyWindow *window);
+
 void window_cmd_file_print_setup (GtkAction *action,
 				  EphyWindow *window);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]