Commit 1da8768a authored by Carlos Garcia Campos's avatar Carlos Garcia Campos

Use always a different process for every document

parent 3a748f44
......@@ -17,6 +17,7 @@ INCLUDES= \
-I$(top_srcdir)/properties \
-DGNOMELOCALEDIR=\"$(datadir)/locale\" \
-DGNOMEICONDIR=\""$(datadir)/pixmaps"\" \
-DBINDIR=\""$(bindir)"\" \
-DLIBEXECDIR=\""$(libexecdir)"\" \
-DEVINCE_COMPILATION \
$(SHELL_CFLAGS) \
......
......@@ -20,8 +20,8 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*/
#include <config.h>
#include <config.h>
#include <stdlib.h>
#include <string.h>
......@@ -63,6 +63,9 @@ static void ev_application_save_print_settings (EvApplication *application);
struct _EvApplication {
GObject base_instance;
EvWindow *window;
gchar *uri;
gchar *dot_dir;
gchar *data_dir;
gchar *accel_map_file;
......@@ -70,8 +73,7 @@ struct _EvApplication {
#ifdef ENABLE_DBUS
DBusGConnection *connection;
GHashTable *windows;
guint doc_counter;
EvMediaPlayerKeys *keys;
#endif
EggToolbarsModel *toolbars_model;
......@@ -85,10 +87,6 @@ struct _EvApplication {
gchar *filechooser_open_uri;
gchar *filechooser_save_uri;
#ifdef ENABLE_DBUS
EvMediaPlayerKeys *keys;
#endif /* ENABLE_DBUS */
GtkPrintSettings *print_settings;
GtkPageSetup *page_setup;
GKeyFile *print_settings_file;
......@@ -128,43 +126,12 @@ ev_application_get_instance (void)
return instance;
}
#if defined (WITH_SMCLIENT)
/* Session */
static void
save_session (EvApplication *application,
GList *windows_list,
GKeyFile *state_file)
{
GList *l;
gint i;
const gchar **uri_list;
const gchar *empty = "empty-window";
uri_list = g_new (const gchar *, g_list_length (windows_list));
for (l = windows_list, i = 0; l != NULL; l = g_list_next (l), i++) {
EvWindow *window = EV_WINDOW (l->data);
if (ev_window_is_empty (window))
uri_list[i] = empty;
else
uri_list[i] = ev_window_get_uri (window);
}
g_key_file_set_string_list (state_file,
"Evince",
"documents",
(const char **)uri_list,
i);
g_free (uri_list);
}
#endif /* WITH_SMCLIENT */
gboolean
ev_application_load_session (EvApplication *application,
const gchar **files)
ev_application_load_session (EvApplication *application)
{
GKeyFile *state_file;
gchar **uri_list;
gchar *uri;
#ifdef WITH_SMCLIENT
if (egg_sm_client_is_resumed (application->smclient)) {
......@@ -175,23 +142,15 @@ ev_application_load_session (EvApplication *application,
#endif /* WITH_SMCLIENT */
return FALSE;
uri_list = g_key_file_get_string_list (state_file,
"Evince",
"documents",
NULL, NULL);
if (uri_list) {
gint i;
GdkScreen *screen = gdk_screen_get_default ();
for (i = 0; uri_list[i]; i++) {
if (g_ascii_strcasecmp (uri_list[i], "empty-window") == 0)
ev_application_open_window (application, screen, GDK_CURRENT_TIME);
else
ev_application_open_uri_at_dest (application, uri_list[i], screen,
NULL, 0, NULL, GDK_CURRENT_TIME);
}
g_strfreev (uri_list);
}
uri = g_key_file_get_string (state_file, "Evince", "uri", NULL);
if (!uri)
return FALSE;
ev_application_open_uri_at_dest (application, uri,
gdk_screen_get_default (),
NULL, 0, NULL,
GDK_CURRENT_TIME);
g_free (uri);
g_key_file_free (state_file);
return TRUE;
......@@ -204,13 +163,10 @@ smclient_save_state_cb (EggSMClient *client,
GKeyFile *state_file,
EvApplication *application)
{
GList *windows;
if (!application->uri)
return;
windows = ev_application_get_windows (application);
if (windows) {
save_session (application, windows, state_file);
g_list_free (windows);
}
g_key_file_set_string (state_file, "Evince", "uri", application->uri);
}
static void
......@@ -219,7 +175,6 @@ smclient_quit_cb (EggSMClient *client,
{
ev_application_shutdown (application);
}
#endif /* WITH_SMCLIENT */
static void
......@@ -443,108 +398,63 @@ build_args (GdkScreen *screen,
return args;
}
/**
* ev_application_open_window:
* @application: The instance of the application.
* @timestamp: Current time value.
*
* Creates a new window
*/
void
ev_application_open_window (EvApplication *application,
GdkScreen *screen,
guint32 timestamp)
static void
ev_spawn (const char *uri,
GdkScreen *screen,
EvLinkDest *dest,
EvWindowRunMode mode,
const gchar *search_string)
{
GtkWidget *new_window = ev_window_new ();
gchar *argv[6];
guint arg = 0;
gint i;
gboolean res;
GError *error = NULL;
if (screen) {
ev_stock_icons_set_screen (screen);
gtk_window_set_screen (GTK_WINDOW (new_window), screen);
}
if (!GTK_WIDGET_REALIZED (new_window))
gtk_widget_realize (new_window);
#ifdef GDK_WINDOWING_X11
if (timestamp <= 0)
timestamp = gdk_x11_get_server_time (GTK_WIDGET (new_window)->window);
gdk_x11_window_set_user_time (GTK_WIDGET (new_window)->window, timestamp);
argv[arg++] = g_build_filename (BINDIR, "evince", NULL);
gtk_window_present (GTK_WINDOW (new_window));
#else
gtk_window_present_with_time (GTK_WINDOW (new_window), timestamp);
#endif /* GDK_WINDOWING_X11 */
}
/**
* ev_application_get_empty_window:
* @application: The instance of the application.
* @screen: The screen where the empty window will be search.
*
* It does look if there is any empty window in the indicated screen.
*
* Returns: The first empty #EvWindow in the passed #GdkScreen or NULL in other
* case.
*/
static EvWindow *
ev_application_get_empty_window (EvApplication *application,
GdkScreen *screen)
{
EvWindow *empty_window = NULL;
GList *windows = ev_application_get_windows (application);
GList *l;
for (l = windows; l != NULL; l = l->next) {
EvWindow *window = EV_WINDOW (l->data);
/* Page label */
if (dest) {
const gchar *page_label;
if (ev_window_is_empty (window) &&
gtk_window_get_screen (GTK_WINDOW (window)) == screen) {
empty_window = window;
break;
}
page_label = ev_link_dest_get_page_label (dest);
if (page_label)
argv[arg++] = g_strdup_printf ("--page-label=%s", page_label);
else
argv[arg++] = g_strdup_printf ("--page-label=%d",
ev_link_dest_get_page (dest));
}
g_list_free (windows);
return empty_window;
}
/**
* ev_application_get_uri_window:
* @application: The instance of the application.
* @uri: The uri to be opened.
*
* It looks in the list of the windows for the one with the document represented
* by the passed uri on it. If the window is empty or the document isn't present
* on any window, it will return NULL.
*
* Returns: The #EvWindow where the document represented by the passed uri is
* shown, NULL in other case.
*/
static EvWindow *
ev_application_get_uri_window (EvApplication *application, const char *uri)
{
EvWindow *uri_window = NULL;
GList *windows = gtk_window_list_toplevels ();
GList *l;
/* Find string */
if (search_string) {
argv[arg++] = g_strdup_printf ("--find=%s", search_string);
}
g_return_val_if_fail (uri != NULL, NULL);
/* Mode */
switch (mode) {
case EV_WINDOW_MODE_FULLSCREEN:
argv[arg++] = g_strdup ("-f");
break;
case EV_WINDOW_MODE_PRESENTATION:
argv[arg++] = g_strdup ("-s");
break;
default:
break;
}
for (l = windows; l != NULL; l = l->next) {
if (EV_IS_WINDOW (l->data)) {
EvWindow *window = EV_WINDOW (l->data);
const char *window_uri = ev_window_get_uri (window);
argv[arg++] = (gchar *)uri;
argv[arg] = NULL;
if (window_uri && strcmp (window_uri, uri) == 0 && !ev_window_is_empty (window)) {
uri_window = window;
break;
}
}
res = gdk_spawn_on_screen (screen, NULL /* wd */, argv, NULL /* env */,
0, NULL, NULL, NULL, &error);
if (!res) {
g_warning ("Error launching evince %s: %s\n", uri, error->message);
g_error_free (error);
}
g_list_free (windows);
return uri_window;
for (i = 0; i < arg - 1; i++) {
g_free (argv[i]);
}
}
#ifdef ENABLE_DBUS
......@@ -635,28 +545,19 @@ ev_application_unregister_uri (EvApplication *application,
g_object_unref (proxy);
}
static void
ev_application_window_destroyed (EvApplication *application,
EvWindow *ev_window)
{
gchar *uri = g_hash_table_lookup (application->windows, ev_window);
ev_application_unregister_uri (application, uri);
g_hash_table_remove (application->windows, ev_window);
}
#endif /* ENABLE_DBUS */
static void
ev_application_open_uri_in_window (EvApplication *application,
const char *uri,
EvWindow *ev_window,
GdkScreen *screen,
EvLinkDest *dest,
EvWindowRunMode mode,
const gchar *search_string,
guint timestamp)
{
EvWindow *ev_window = application->window;
if (screen) {
ev_stock_icons_set_screen (screen);
gtk_window_set_screen (GTK_WINDOW (ev_window), screen);
......@@ -666,16 +567,6 @@ ev_application_open_uri_in_window (EvApplication *application,
we can restore window size without flickering */
ev_window_open_uri (ev_window, uri, dest, mode, search_string);
#ifdef ENABLE_DBUS
if (application->windows != NULL &&
!g_hash_table_lookup (application->windows, ev_window)) {
g_hash_table_insert (application->windows, ev_window, g_strdup (uri));
g_signal_connect_swapped (ev_window, "destroy",
G_CALLBACK (ev_application_window_destroyed),
application);
}
#endif
if (!GTK_WIDGET_REALIZED (GTK_WIDGET (ev_window)))
gtk_widget_realize (GTK_WIDGET (ev_window));
......@@ -712,13 +603,16 @@ ev_application_open_uri_at_dest (EvApplication *application,
const gchar *search_string,
guint timestamp)
{
EvWindow *ev_window;
g_return_if_fail (uri != NULL);
ev_window = ev_application_get_uri_window (application, uri);
if (application->window && !ev_window_is_empty (application->window)) {
if (application->uri && strcmp (application->uri, uri) != 0) {
/* spawn a new evince process */
ev_spawn (uri, screen, dest, mode, search_string);
return;
}
} else {
#ifdef ENABLE_DBUS
if (!ev_window) {
GHashTable *args = build_args (screen, dest, mode, search_string);
gboolean ret;
......@@ -729,22 +623,55 @@ ev_application_open_uri_at_dest (EvApplication *application,
g_hash_table_destroy (args);
if (!ret)
return;
}
#endif /* ENABLE_DBUS */
if (ev_window == NULL) {
ev_window = ev_application_get_empty_window (application, screen);
if (!application->window)
application->window = EV_WINDOW (ev_window_new ());
}
if (ev_window == NULL) {
ev_window = EV_WINDOW (ev_window_new ());
}
application->uri = g_strdup (uri);
ev_application_open_uri_in_window (application, uri, ev_window,
screen, dest, mode, search_string,
ev_application_open_uri_in_window (application, uri,
screen, dest, mode,
search_string,
timestamp);
}
/**
* ev_application_open_window:
* @application: The instance of the application.
* @timestamp: Current time value.
*
* Creates a new window
*/
void
ev_application_open_window (EvApplication *application,
GdkScreen *screen,
guint32 timestamp)
{
GtkWidget *new_window = ev_window_new ();
application->window = EV_WINDOW (new_window);
if (screen) {
ev_stock_icons_set_screen (screen);
gtk_window_set_screen (GTK_WINDOW (new_window), screen);
}
if (!GTK_WIDGET_REALIZED (new_window))
gtk_widget_realize (new_window);
#ifdef GDK_WINDOWING_X11
if (timestamp <= 0)
timestamp = gdk_x11_get_server_time (new_window->window);
gdk_x11_window_set_user_time (new_window->window, timestamp);
gtk_window_present (GTK_WINDOW (new_window));
#else
gtk_window_present_with_time (GTK_WINDOW (new_window), timestamp);
#endif /* GDK_WINDOWING_X11 */
}
/**
* ev_application_open_uri:
* @application: The instance of the application.
......@@ -760,14 +687,22 @@ ev_application_open_uri (EvApplication *application,
guint timestamp,
GError **error)
{
EvWindow *ev_window;
EvLinkDest *dest = NULL;
EvWindowRunMode mode = EV_WINDOW_MODE_NORMAL;
const gchar *search_string = NULL;
GdkScreen *screen = NULL;
ev_window = ev_application_get_uri_window (application, uri);
g_assert (ev_window != NULL);
g_assert (application->window != NULL);
/* FIXME: we don't need uri anymore,
* maybe this method should be renamed
* as reload, refresh or something like that
*/
if (!application->uri || strcmp (application->uri, uri)) {
g_warning ("Invalid uri: %s, expected %s\n",
uri, application->uri);
return TRUE;
}
if (args) {
screen = get_screen_from_args (args);
......@@ -776,8 +711,9 @@ ev_application_open_uri (EvApplication *application,
search_string = get_find_string_from_args (args);
}
ev_application_open_uri_in_window (application, uri, ev_window,
screen, dest, mode, search_string,
ev_application_open_uri_in_window (application, uri,
screen, dest, mode,
search_string,
timestamp);
if (dest)
......@@ -804,12 +740,14 @@ ev_application_open_uri_list (EvApplication *application,
void
ev_application_shutdown (EvApplication *application)
{
if (application->uri) {
#ifdef ENABLE_DBUS
if (application->windows) {
g_hash_table_destroy (application->windows);
application->windows = NULL;
}
ev_application_unregister_uri (application,
application->uri);
#endif
g_free (application->uri);
application->uri = NULL;
}
if (application->accel_map_file) {
gtk_accel_map_save (application->accel_map_file);
......@@ -955,10 +893,6 @@ ev_application_init (EvApplication *ev_application)
dbus_g_connection_register_g_object (ev_application->connection,
APPLICATION_DBUS_OBJECT_PATH,
G_OBJECT (ev_application));
ev_application->windows = g_hash_table_new_full (g_direct_hash,
g_direct_equal,
NULL,
(GDestroyNotify)g_free);
ev_application->scr_saver = totem_scrsaver_new (ev_application->connection);
} else {
g_warning ("Error connection to DBus: %s\n", error->message);
......@@ -968,31 +902,16 @@ ev_application_init (EvApplication *ev_application)
#endif /* ENABLE_DBUS */
}
/**
* ev_application_get_windows:
* @application: The instance of the application.
*
* It creates a list of the top level windows.
*
* Returns: A #GList of the top level windows.
*/
GList *
ev_application_get_windows (EvApplication *application)
gboolean
ev_application_has_window (EvApplication *application)
{
GList *l, *toplevels;
GList *windows = NULL;
toplevels = gtk_window_list_toplevels ();
for (l = toplevels; l != NULL; l = l->next) {
if (EV_IS_WINDOW (l->data)) {
windows = g_list_append (windows, l->data);
}
}
g_list_free (toplevels);
return application->window != NULL;
}
return windows;
const gchar *
ev_application_get_uri (EvApplication *application)
{
return application->uri;
}
/**
......
......@@ -50,11 +50,9 @@ typedef struct _EvApplicationClass EvApplicationClass;
GType ev_application_get_type (void) G_GNUC_CONST;
EvApplication *ev_application_get_instance (void);
gboolean ev_application_register_service (EvApplication *application);
void ev_application_shutdown (EvApplication *application);
gboolean ev_application_load_session (EvApplication *application,
const gchar **files);
void ev_application_shutdown (EvApplication *application);
gboolean ev_application_load_session (EvApplication *application);
void ev_application_open_window (EvApplication *application,
GdkScreen *screen,
guint32 timestamp);
......@@ -69,7 +67,8 @@ void ev_application_open_uri_list (EvApplication *application,
GSList *uri_list,
GdkScreen *screen,
guint32 timestamp);
GList *ev_application_get_windows (EvApplication *application);
gboolean ev_application_has_window (EvApplication *application);
const gchar * ev_application_get_uri (EvApplication *application);
GObject *ev_application_get_media_keys (EvApplication *application);
EggToolbarsModel *ev_application_get_toolbars_model (EvApplication *application);
......
......@@ -310,6 +310,8 @@ static void ev_window_media_player_key_pressed (EvWindow *windo
gpointer user_data);
static void ev_window_save_print_page_setup (EvWindow *window);
static guint ev_window_n_copies = 0;
G_DEFINE_TYPE (EvWindow, ev_window, GTK_TYPE_WINDOW)
static void
......@@ -2129,6 +2131,8 @@ ev_window_open_copy_at_dest (EvWindow *window,
{
EvWindow *new_window = EV_WINDOW (ev_window_new ());
ev_window_n_copies++;
if (window->priv->metadata)
new_window->priv->metadata = g_object_ref (window->priv->metadata);
ev_window_open_document (new_window,
......@@ -4549,14 +4553,12 @@ ev_window_drag_data_received (GtkWidget *widget,
static void
ev_window_finalize (GObject *object)
{
GList *windows = ev_application_get_windows (EV_APP);
if (windows == NULL) {
if (ev_window_n_copies == 0) {
ev_application_shutdown (EV_APP);
} else {
g_list_free (windows);
ev_window_n_copies--;
}
G_OBJECT_CLASS (ev_window_parent_class)->finalize (object);
}
......
......@@ -141,29 +141,17 @@ launch_previewer (void)
return retval;
}
static gint
find_window_list (EvWindow *window,
const gchar *uri)
{
return g_ascii_strcasecmp (uri, ev_window_get_uri (window));
}
static void
load_files (const char **files)
{
GdkScreen *screen = gdk_screen_get_default ();
EvWindowRunMode mode = EV_WINDOW_MODE_NORMAL;
GList *windows;
gint i;
EvLinkDest *global_dest = NULL;
windows = ev_application_get_windows (EV_APP);
if (!files) {
if (!windows)
if (!ev_application_has_window (EV_APP))
ev_application_open_window (EV_APP, screen, GDK_CURRENT_TIME);
else
g_list_free (windows);
return;
}
......@@ -176,16 +164,18 @@ load_files (const char **files)
mode = EV_WINDOW_MODE_PRESENTATION;
for (i = 0; files[i]; i++) {
gchar *uri;
gchar *label;
GFile *file;
EvLinkDest *dest = NULL;
gchar *uri;
gchar *label;
GFile *file;
EvLinkDest *dest = NULL;
const gchar *app_uri;
file = g_file_new_for_commandline_arg (files[i]);
uri = g_file_get_uri (file);
g_object_unref (file);
if (g_list_find_custom (windows, uri, (GCompareFunc) find_window_list)) {
app_uri = ev_application_get_uri (EV_APP);
if (app_uri && strcmp (app_uri, uri) == 0) {
g_free (uri);
continue;
}
......@@ -207,16 +197,13 @@ load_files (const char **files)
g_object_unref (dest);
g_free (uri);
}
g_list_free (windows);
}
int
main (int argc, char *argv[])
{
GOptionContext *context;
GList *toplevels;
GError *error = NULL;
GError *error = NULL;
#ifdef G_OS_WIN32
......@@ -265,10 +252,10 @@ main (int argc, char *argv[])
g_option_context_add_group (context, gtk_get_option_group (TRUE));
if (!g_option_context_parse (context, &argc, &argv, &error)) {
g_printerr ("Cannot parse arguments: %s", error->message);
g_printerr ("Cannot parse arguments: %s\n", error->message);
g_error_free (error);
g_option_context_free (context);
return 1;
}
g_option_context_free (context);
......@@ -294,11 +281,9 @@ main (int argc, char *argv[])
gtk_window_set_default_icon_name ("evince");
#endif /* WITH_SMCLIENT && GDK_WINDOWING_X11 */
ev_application_load_session (EV_APP, file_arguments);
ev_application_load_session (EV_APP);
load_files (file_arguments);
toplevels = gtk_window_list_toplevels ();
if (toplevels) {
g_list_free (toplevels);
if (ev_application_has_window (EV_APP)) {
/* Change directory so we don't prevent unmounting in case the initial cwd
* is on an external device (see bug #575436)
*/
......