diff --git a/configure.ac b/configure.ac index 3475f20..f6591ee 100644 --- a/configure.ac +++ b/configure.ac @@ -49,12 +49,6 @@ dnl toolbar style for GSettings schemas TOOLBAR_STYLE="XED_TOOLBAR_SYSTEM" AC_SUBST(TOOLBAR_STYLE) -# GLib min/max required versions -AC_DEFINE([GLIB_VERSION_MAX_ALLOWED], [GLIB_VERSION_2_36], - [Warn on use of APIs added after GLib 2.36]) -AC_DEFINE([GLIB_VERSION_MIN_REQUIRED], [GLIB_VERSION_2_36], - [Warn on use of APIs deprecated before GLib 2.36]) - dnl =============================================================== dnl Expanded dirs dnl =============================================================== @@ -151,12 +145,12 @@ dnl ================================================================ PKG_CHECK_MODULES(GMODULE,gmodule-2.0,[GMODULE_ADD="gmodule-2.0"],[GMODULE_ADD=""]) PKG_CHECK_MODULES(XED, [ libxml-2.0 >= 2.5.0 - glib-2.0 >= 2.36.0 + glib-2.0 >= 2.40.0 $GMODULE_ADD gthread-2.0 >= 2.13.0 - gio-2.0 >= 2.26.0 - gtk+-3.0 >= 3.10.0 - gtksourceview-3.0 >= 2.9.7 + gio-2.0 >= 2.40.0 + gtk+-3.0 >= 3.14.0 + gtksourceview-3.0 >= 3.14.3 libpeas-1.0 >= 1.12.0 libpeas-gtk-1.0 >= 1.12.0 ]) @@ -169,19 +163,14 @@ XED_LIBS="$XED_LIBS $X11_LIBS" AC_SUBST(XED_CFLAGS) AC_SUBST(XED_LIBS) -PKG_CHECK_MODULES(EGG_SMCLIENT, [sm >= 1.0.0]) - -AC_SUBST(EGG_SMCLIENT_CFLAGS) -AC_SUBST(EGG_SMCLIENT_LIBS) - # Introspection GOBJECT_INTROSPECTION_CHECK([0.9.3]) if test "$found_introspection" = "yes"; then - have_introspection=yes - AC_DEFINE([HAVE_INTROSPECTION], [1], [Define to enable GObject Introspection]) + enable_introspection=yes + AC_DEFINE([ENABLE_INTROSPECTION], [1], [Define to enable GObject Introspection]) else - have_introspection=no + enable_introspection=no fi dnl ================================================================ @@ -235,7 +224,6 @@ data/Makefile docs/Makefile docs/reference/Makefile xed/dialogs/Makefile -xed/smclient/Makefile xed/Makefile help/Makefile pixmaps/Makefile @@ -264,5 +252,5 @@ Configuration: Compiler: ${CC} Spell Plugin enabled: $enable_enchant Gvfs metadata enabled: $enable_gvfs_metadata - GObject Introspection: ${have_introspection} + GObject Introspection: ${enable_introspection} " diff --git a/data/Makefile.am b/data/Makefile.am index 8591f2b..c234c15 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -13,6 +13,13 @@ gsettings_SCHEMAS = org.x.editor.gschema.xml @GSETTINGS_RULES@ +servicedir = $(datadir)/dbus-1/services +service_in_files = org.x.editor.service.in +service_DATA = $(service_in_files:.service.in=.service) + +$(service_DATA): $(service_in_files) Makefile + @sed -e "s|\@bindir\@|$(bindir)|" $<> $@ + man_MANS = xed.1 pkgconfigdir = $(libdir)/pkgconfig @@ -24,12 +31,14 @@ bugreport_SCRIPTS = xed-bugreport.sh EXTRA_DIST = \ $(appdata_in_files) \ $(desktop_in_files) \ + $(service_in_files) \ $(man_MANS) \ xed.pc.in \ xed-bugreport.sh.in CLEANFILES = \ $(desktop_DATA) \ + $(service_DATA) \ $(gsettings_SCHEMAS) \ $(pkgconfig_DATA) \ $(appdata_DATA) diff --git a/debian/xed.install b/debian/xed.install index 85dfd41..755fad6 100644 --- a/debian/xed.install +++ b/debian/xed.install @@ -4,4 +4,5 @@ usr/lib/xed/xed-bugreport.sh usr/lib/*/xed/plugins/*.plugin usr/lib/*/xed/plugins/*.so usr/share/applications/xed.desktop +usr/share/dbus-1/ usr/share/man/ diff --git a/docs/reference/xed.types b/docs/reference/xed.types index 5625c13..8c34ddd 100644 --- a/docs/reference/xed.types +++ b/docs/reference/xed.types @@ -1,5 +1,3 @@ -egg_sm_client_get_type -egg_sm_client_xsmp_get_type xed_app_activatable_get_type xed_app_get_type xed_close_button_get_type diff --git a/plugins/filebrowser/xed-file-browser-plugin.c b/plugins/filebrowser/xed-file-browser-plugin.c index a970978..2556ed4 100644 --- a/plugins/filebrowser/xed-file-browser-plugin.c +++ b/plugins/filebrowser/xed-file-browser-plugin.c @@ -761,13 +761,11 @@ on_rename_cb (XedFileBrowserStore *store, GFile *newfile, XedWindow *window) { - XedApp *app; GList *documents; GList *item; /* Find all documents and set its uri to newuri where it matches olduri */ - app = xed_app_get_default (); - documents = xed_app_get_documents (app); + documents = xed_app_get_documents (XED_APP (g_application_get_default ())); for (item = documents; item; item = item->next) { diff --git a/plugins/sort/xed-sort-plugin.c b/plugins/sort/xed-sort-plugin.c index 5104188..80f33b0 100644 --- a/plugins/sort/xed-sort-plugin.c +++ b/plugins/sort/xed-sort-plugin.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #define XED_SORT_PLUGIN_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), XED_TYPE_SORT_PLUGIN, XedSortPluginPrivate)) @@ -110,7 +110,7 @@ sort_dialog_response_handler (GtkDialog *dlg, break; case GTK_RESPONSE_HELP: - xed_help_display (GTK_WINDOW (dlg), NULL, "xed-sort-plugin"); + xed_app_show_help (XED_APP (g_application_get_default ()), GTK_WINDOW (dlg), NULL, "xed-sort-plugin"); break; case GTK_RESPONSE_CANCEL: diff --git a/plugins/spell/xed-spell-language-dialog.c b/plugins/spell/xed-spell-language-dialog.c index ee1efab..452447a 100644 --- a/plugins/spell/xed-spell-language-dialog.c +++ b/plugins/spell/xed-spell-language-dialog.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include "xed-spell-language-dialog.h" #include "xed-spell-checker-language.h" @@ -70,7 +70,7 @@ dialog_response_handler (GtkDialog *dlg, { if (res_id == GTK_RESPONSE_HELP) { - xed_help_display (GTK_WINDOW (dlg), NULL, "xed-spell-checker-plugin"); + xed_app_show_help (XED_APP (g_application_get_default ()), GTK_WINDOW (dlg), NULL, "xed-spell-checker-plugin"); g_signal_stop_emission_by_name (dlg, "response"); } diff --git a/plugins/time/xed-time-plugin.c b/plugins/time/xed-time-plugin.c index eb840a6..3fd3840 100644 --- a/plugins/time/xed-time-plugin.c +++ b/plugins/time/xed-time-plugin.c @@ -32,7 +32,7 @@ #include #include "xed-time-plugin.h" -#include +#include #include #include @@ -916,7 +916,7 @@ choose_format_dialog_response_cb (GtkWidget *widget, case GTK_RESPONSE_HELP: { xed_debug_message (DEBUG_PLUGINS, "GTK_RESPONSE_HELP"); - xed_help_display (GTK_WINDOW (widget), NULL, "xed-insert-date-time-plugin"); + xed_app_show_help (XED_APP (g_application_get_default ()), GTK_WINDOW (widget), NULL, "xed-insert-date-time-plugin"); break; } case GTK_RESPONSE_OK: diff --git a/po/POTFILES.in b/po/POTFILES.in index eae2181..9497faa 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -17,7 +17,6 @@ xed/xed-commands-search.c xed/xed-debug.c xed/xed-document.c xed/xed-documents-panel.c -xed/xed-encodings.c xed/xed-encodings-combo-box.c xed/xed-file-chooser-dialog.c xed/xed-gio-document-loader.c diff --git a/xed/Makefile.am b/xed/Makefile.am index ba25581..9283fd9 100644 --- a/xed/Makefile.am +++ b/xed/Makefile.am @@ -1,5 +1,5 @@ ## Process this file with automake to produce Makefile.in -SUBDIRS = dialogs smclient +SUBDIRS = dialogs bin_PROGRAMS = xed @@ -8,7 +8,6 @@ noinst_LTLIBRARIES = libxed.la AM_CPPFLAGS = \ -I$(top_srcdir) \ -I$(srcdir) \ - -I$(srcdir)/smclient \ $(XED_CFLAGS) \ $(WARN_CFLAGS) \ $(INTROSPECTION_CFLAGS) \ @@ -22,7 +21,6 @@ xed_SOURCES = \ xed_LDADD = \ libxed.la \ $(XED_LIBS) \ - $(EGG_SMCLIENT_LIBS) \ $(INTROSPECTION_LIBS) xed_LDFLAGS = -export-dynamic -no-undefined -export-symbols-regex "^[[^_]].*" @@ -30,8 +28,7 @@ xed_LDFLAGS = -export-dynamic -no-undefined -export-symbols-regex "^[[^_]].*" libxed_la_LDFLAGS = -export-dynamic -no-undefined -export-symbols-regex "^[[^_]].*" libxed_la_LIBADD = \ - dialogs/libdialogs.la \ - smclient/libeggsmclient.la + dialogs/libdialogs.la # XED_LIBS must be the last to ensure correct order on some platforms libxed_la_LIBADD += $(XED_LIBS) -lICE @@ -52,7 +49,6 @@ NOINST_H_FILES = \ xed-plugins-engine.h \ xed-print-job.h \ xed-print-preview.h \ - xed-session.h \ xed-settings.h \ xed-status-combo-box.h \ xed-tab-label.h \ @@ -69,7 +65,6 @@ INST_H_FILES = \ xed-document.h \ xed-encodings-combo-box.h \ xed-file-chooser-dialog.h \ - xed-help.h \ xed-message-bus.h \ xed-message-type.h \ xed-message.h \ @@ -111,7 +106,6 @@ libxed_c_files = \ xed-documents-panel.c \ xed-encodings-combo-box.c \ xed-file-chooser-dialog.c \ - xed-help.c \ xed-history-entry.c \ xed-io-error-message-area.c \ xed-message-bus.c \ @@ -123,7 +117,6 @@ libxed_c_files = \ xed-print-job.c \ xed-print-preview.c \ xed-progress-message-area.c \ - xed-session.c \ xed-settings.c \ xed-searchbar.c \ xed-statusbar.c \ @@ -140,7 +133,6 @@ libxed_c_files = \ libxed_la_SOURCES = \ $(BUILT_SOURCES) \ $(libxed_c_files) \ - $(BACON_FILES) \ $(POSIXIO_FILES) \ $(NOINST_H_FILES) \ $(INST_H_FILES) @@ -205,10 +197,4 @@ endif dist-hook: cd $(distdir); rm -f $(BUILT_SOURCES) -BACON_DIR=$(srcdir)/../../libbacon/src/ -BACON_FILES=bacon-message-connection.h bacon-message-connection.c - -regenerate-built-sources: - BACONFILES="$(BACON_FILES)" BACONDIR="$(BACON_DIR)" $(top_srcdir)/xed/update-from-bacon.sh - -include $(top_srcdir)/git.mk diff --git a/xed/bacon-message-connection.c b/xed/bacon-message-connection.c deleted file mode 100644 index 7b35342..0000000 --- a/xed/bacon-message-connection.c +++ /dev/null @@ -1,396 +0,0 @@ -/* - * Copyright (C) 2003 Bastien Nocera - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "bacon-message-connection.h" - -#ifndef UNIX_PATH_MAX -#define UNIX_PATH_MAX 108 -#endif - -struct BaconMessageConnection { - /* A server accepts connections */ - gboolean is_server; - - /* The socket path itself */ - char *path; - - /* File descriptor of the socket */ - int fd; - /* Channel to watch */ - GIOChannel *chan; - /* Event id returned by g_io_add_watch() */ - int conn_id; - - /* Connections accepted by this connection */ - GSList *accepted_connections; - - /* callback */ - void (*func) (const char *message, gpointer user_data); - gpointer data; -}; - -static gboolean -test_is_socket (const char *path) -{ - struct stat s; - - if (stat (path, &s) == -1) - return FALSE; - - if (S_ISSOCK (s.st_mode)) - return TRUE; - - return FALSE; -} - -static gboolean -is_owned_by_user_and_socket (const char *path) -{ - struct stat s; - - if (stat (path, &s) == -1) - return FALSE; - - if (s.st_uid != geteuid ()) - return FALSE; - - if ((s.st_mode & S_IFSOCK) != S_IFSOCK) - return FALSE; - - return TRUE; -} - -static gboolean server_cb (GIOChannel *source, - GIOCondition condition, gpointer data); - -static gboolean -setup_connection (BaconMessageConnection *conn) -{ - g_return_val_if_fail (conn->chan == NULL, FALSE); - - conn->chan = g_io_channel_unix_new (conn->fd); - if (!conn->chan) { - return FALSE; - } - g_io_channel_set_line_term (conn->chan, "\n", 1); - conn->conn_id = g_io_add_watch (conn->chan, G_IO_IN, server_cb, conn); - - return TRUE; -} - -static void -accept_new_connection (BaconMessageConnection *server_conn) -{ - BaconMessageConnection *conn; - int alen; - - g_return_if_fail (server_conn->is_server); - - conn = g_new0 (BaconMessageConnection, 1); - conn->is_server = FALSE; - conn->func = server_conn->func; - conn->data = server_conn->data; - - conn->fd = accept (server_conn->fd, NULL, (guint *)&alen); - - server_conn->accepted_connections = - g_slist_prepend (server_conn->accepted_connections, conn); - - setup_connection (conn); -} - -static gboolean -server_cb (GIOChannel *source, GIOCondition condition, gpointer data) -{ - BaconMessageConnection *conn = (BaconMessageConnection *)data; - char *message, *subs, buf; - int cd, rc, offset; - gboolean finished; - - offset = 0; - if (conn->is_server && conn->fd == g_io_channel_unix_get_fd (source)) { - accept_new_connection (conn); - return TRUE; - } - message = g_malloc (1); - cd = conn->fd; - rc = read (cd, &buf, 1); - while (rc > 0 && buf != '\n') - { - message = g_realloc (message, rc + offset + 1); - message[offset] = buf; - offset = offset + rc; - rc = read (cd, &buf, 1); - } - if (rc <= 0) { - g_io_channel_shutdown (conn->chan, FALSE, NULL); - g_io_channel_unref (conn->chan); - conn->chan = NULL; - close (conn->fd); - conn->fd = -1; - g_free (message); - conn->conn_id = 0; - - return FALSE; - } - message[offset] = '\0'; - - subs = message; - finished = FALSE; - - while (finished == FALSE && *subs != '\0') - { - if (conn->func != NULL) - (*conn->func) (subs, conn->data); - - subs += strlen (subs) + 1; - if (subs - message >= offset) - finished = TRUE; - } - - g_free (message); - - return TRUE; -} - -static char * -find_file_with_pattern (const char *dir, const char *pattern) -{ - GDir *filedir; - char *found_filename; - const char *filename; - GPatternSpec *pat; - - filedir = g_dir_open (dir, 0, NULL); - if (filedir == NULL) - return NULL; - - pat = g_pattern_spec_new (pattern); - if (pat == NULL) - { - g_dir_close (filedir); - return NULL; - } - - found_filename = NULL; - - while ((filename = g_dir_read_name (filedir))) - { - if (g_pattern_match_string (pat, filename)) - { - char *tmp = g_build_filename (dir, filename, NULL); - if (is_owned_by_user_and_socket (tmp)) - found_filename = g_strdup (filename); - g_free (tmp); - } - - if (found_filename != NULL) - break; - } - - g_pattern_spec_free (pat); - g_dir_close (filedir); - - return found_filename; -} - -static char * -socket_filename (const char *prefix) -{ - char *pattern, *newfile, *path, *filename; - const char *tmpdir; - - pattern = g_strdup_printf ("%s.%s.*", prefix, g_get_user_name ()); - tmpdir = g_get_tmp_dir (); - filename = find_file_with_pattern (tmpdir, pattern); - if (filename == NULL) - { - newfile = g_strdup_printf ("%s.%s.%u", prefix, - g_get_user_name (), g_random_int ()); - path = g_build_filename (tmpdir, newfile, NULL); - g_free (newfile); - } else { - path = g_build_filename (tmpdir, filename, NULL); - g_free (filename); - } - - g_free (pattern); - return path; -} - -static gboolean -try_server (BaconMessageConnection *conn) -{ - struct sockaddr_un uaddr; - - uaddr.sun_family = AF_UNIX; - strncpy (uaddr.sun_path, conn->path, - MIN (strlen(conn->path)+1, UNIX_PATH_MAX)); - conn->fd = socket (PF_UNIX, SOCK_STREAM, 0); - if (bind (conn->fd, (struct sockaddr *) &uaddr, sizeof (uaddr)) == -1) - { - conn->fd = -1; - return FALSE; - } - listen (conn->fd, 5); - - if (!setup_connection (conn)) - return FALSE; - return TRUE; -} - -static gboolean -try_client (BaconMessageConnection *conn) -{ - struct sockaddr_un uaddr; - - uaddr.sun_family = AF_UNIX; - strncpy (uaddr.sun_path, conn->path, - MIN(strlen(conn->path)+1, UNIX_PATH_MAX)); - conn->fd = socket (PF_UNIX, SOCK_STREAM, 0); - if (connect (conn->fd, (struct sockaddr *) &uaddr, - sizeof (uaddr)) == -1) - { - conn->fd = -1; - return FALSE; - } - - return setup_connection (conn); -} - -BaconMessageConnection * -bacon_message_connection_new (const char *prefix) -{ - BaconMessageConnection *conn; - - g_return_val_if_fail (prefix != NULL, NULL); - - conn = g_new0 (BaconMessageConnection, 1); - conn->path = socket_filename (prefix); - - if (test_is_socket (conn->path) == FALSE) - { - if (!try_server (conn)) - { - bacon_message_connection_free (conn); - return NULL; - } - - conn->is_server = TRUE; - return conn; - } - - if (try_client (conn) == FALSE) - { - unlink (conn->path); - try_server (conn); - if (conn->fd == -1) - { - bacon_message_connection_free (conn); - return NULL; - } - - conn->is_server = TRUE; - return conn; - } - - conn->is_server = FALSE; - return conn; -} - -void -bacon_message_connection_free (BaconMessageConnection *conn) -{ - GSList *child_conn; - - g_return_if_fail (conn != NULL); - /* Only servers can accept other connections */ - g_return_if_fail (conn->is_server != FALSE || - conn->accepted_connections == NULL); - - child_conn = conn->accepted_connections; - while (child_conn != NULL) { - bacon_message_connection_free (child_conn->data); - child_conn = g_slist_next (child_conn); - } - g_slist_free (conn->accepted_connections); - - if (conn->conn_id) { - g_source_remove (conn->conn_id); - conn->conn_id = 0; - } - if (conn->chan) { - g_io_channel_shutdown (conn->chan, FALSE, NULL); - g_io_channel_unref (conn->chan); - } - - if (conn->is_server != FALSE) { - unlink (conn->path); - } - if (conn->fd != -1) { - close (conn->fd); - } - - g_free (conn->path); - g_free (conn); -} - -void -bacon_message_connection_set_callback (BaconMessageConnection *conn, - BaconMessageReceivedFunc func, - gpointer user_data) -{ - g_return_if_fail (conn != NULL); - - conn->func = func; - conn->data = user_data; -} - -void -bacon_message_connection_send (BaconMessageConnection *conn, - const char *message) -{ - g_return_if_fail (conn != NULL); - g_return_if_fail (message != NULL); - - g_io_channel_write_chars (conn->chan, message, strlen (message), - NULL, NULL); - g_io_channel_write_chars (conn->chan, "\n", 1, NULL, NULL); - g_io_channel_flush (conn->chan, NULL); -} - -gboolean -bacon_message_connection_get_is_server (BaconMessageConnection *conn) -{ - g_return_val_if_fail (conn != NULL, FALSE); - - return conn->is_server; -} - diff --git a/xed/bacon-message-connection.h b/xed/bacon-message-connection.h deleted file mode 100644 index adefa62..0000000 --- a/xed/bacon-message-connection.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2003 Bastien Nocera - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#ifndef BACON_MESSAGE_CONNECTION_H -#define BACON_MESSAGE_CONNECTION_H - -#include - -G_BEGIN_DECLS - -typedef void (*BaconMessageReceivedFunc) (const char *message, - gpointer user_data); - -typedef struct BaconMessageConnection BaconMessageConnection; - -BaconMessageConnection *bacon_message_connection_new (const char *prefix); -void bacon_message_connection_free (BaconMessageConnection *conn); -void bacon_message_connection_set_callback (BaconMessageConnection *conn, - BaconMessageReceivedFunc func, - gpointer user_data); -void bacon_message_connection_send (BaconMessageConnection *conn, - const char *message); -gboolean bacon_message_connection_get_is_server (BaconMessageConnection *conn); - -G_END_DECLS - -#endif /* BACON_MESSAGE_CONNECTION_H */ diff --git a/xed/dialogs/xed-encodings-dialog.c b/xed/dialogs/xed-encodings-dialog.c index 3938817..1be461c 100755 --- a/xed/dialogs/xed-encodings-dialog.c +++ b/xed/dialogs/xed-encodings-dialog.c @@ -40,7 +40,6 @@ #include "xed-encodings-dialog.h" #include "xed-utils.h" #include "xed-debug.h" -#include "xed-help.h" #include "xed-dirs.h" #include "xed-settings.h" @@ -271,7 +270,7 @@ response_handler (GtkDialog *dialog, { if (response_id == GTK_RESPONSE_HELP) { - xed_help_display (GTK_WINDOW (dialog), "xed", NULL); + xed_app_show_help (XED_APP (g_application_get_default ()), GTK_WINDOW (dialog), "xed", NULL); g_signal_stop_emission_by_name (dialog, "response"); return; } diff --git a/xed/dialogs/xed-preferences-dialog.c b/xed/dialogs/xed-preferences-dialog.c index 00023db..1038d8c 100755 --- a/xed/dialogs/xed-preferences-dialog.c +++ b/xed/dialogs/xed-preferences-dialog.c @@ -47,7 +47,6 @@ #include "xed-utils.h" #include "xed-debug.h" #include "xed-document.h" -#include "xed-help.h" #include "xed-dirs.h" #include "xed-settings.h" #include "xed-utils.h" @@ -172,11 +171,11 @@ dialog_response_handler (GtkDialog *dlg, switch (res_id) { case GTK_RESPONSE_HELP: - xed_help_display (GTK_WINDOW (dlg), NULL, "xed-prefs"); + xed_app_show_help (XED_APP (g_application_get_default ()), GTK_WINDOW (dlg), NULL, "xed-prefs"); g_signal_stop_emission_by_name (dlg, "response"); break; default: - gtk_widget_destroy (GTK_WIDGET(dlg)); + gtk_widget_destroy (GTK_WIDGET (dlg)); } } @@ -308,13 +307,11 @@ setup_view_page (XedPreferencesDialog *dlg) { GtkWrapMode wrap_mode; gboolean display_right_margin; - guint right_margin_position; xed_debug (DEBUG_PREFS); /* Get values */ display_right_margin = g_settings_get_boolean (dlg->priv->editor, XED_SETTINGS_DISPLAY_RIGHT_MARGIN); - right_margin_position = g_settings_get_uint (dlg->priv->editor, XED_SETTINGS_RIGHT_MARGIN_POSITION); /* Set initial state */ wrap_mode = g_settings_get_enum (dlg->priv->editor, XED_SETTINGS_WRAP_MODE); @@ -400,7 +397,7 @@ setup_font_colors_page_font_section (XedPreferencesDialog *dlg) ATK_RELATION_CONTROLLER_FOR); /* Get values */ - settings = _xed_app_get_settings (xed_app_get_default ()); + settings = _xed_app_get_settings (XED_APP (g_application_get_default ())); system_font = xed_settings_get_system_font (XED_SETTINGS (settings)); use_default_font = g_settings_get_boolean (dlg->priv->editor, XED_SETTINGS_USE_DEFAULT_FONT); diff --git a/xed/smclient/Makefile.am b/xed/smclient/Makefile.am deleted file mode 100644 index d7dbbb5..0000000 --- a/xed/smclient/Makefile.am +++ /dev/null @@ -1,39 +0,0 @@ -platform_defines = -DEGG_SM_CLIENT_BACKEND_XSMP -platform_libs = libeggdesktopfile.la -platform_ltlibraries = libeggdesktopfile.la -platform_sources = eggsmclient-xsmp.c - -AM_CPPFLAGS = \ - -DG_LOG_DOMAIN=\""EggSMClient"\" \ - $(XED_CFLAGS) \ - $(platform_defines) \ - $(EGG_SMCLIENT_CFLAGS) - -noinst_LTLIBRARIES = \ - libeggsmclient.la \ - $(platform_ltlibraries) - -libeggsmclient_la_LIBADD = \ - $(EGG_SMCLIENT_LIBS) \ - $(platform_libs) - -libeggsmclient_la_LDFLAGS = \ - $(platform_ldflags) - -libeggsmclient_la_SOURCES = \ - eggsmclient.c \ - eggsmclient.h \ - eggsmclient-private.h \ - $(platform_sources) - -libeggdesktopfile_la_LIBADD = \ - $(EGG_LIBS) - -libeggdesktopfile_la_SOURCES = \ - eggdesktopfile.c \ - eggdesktopfile.h - -EXTRA_DIST = \ - eggsmclient-xsmp.c - --include $(top_srcdir)/git.mk diff --git a/xed/smclient/eggdesktopfile.c b/xed/smclient/eggdesktopfile.c deleted file mode 100644 index 384fd47..0000000 --- a/xed/smclient/eggdesktopfile.c +++ /dev/null @@ -1,1502 +0,0 @@ -/* eggdesktopfile.c - Freedesktop.Org Desktop Files - * Copyright (C) 2007 Novell, Inc. - * - * Based on mate-desktop-item.c - * Copyright (C) 1999, 2000 Red Hat Inc. - * Copyright (C) 2001 George Lebl - * - * 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 of - * the License, or (at your option) any later version. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; see the file COPYING.LIB. If not, - * write to the Free Software Foundation, Inc., 151 Franklin Street, - * Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "eggdesktopfile.h" - -#include -#include - -#include -#include -#include - -struct EggDesktopFile { - GKeyFile *key_file; - char *source; - - char *name, *icon; - EggDesktopFileType type; - char document_code; -}; - -/** - * egg_desktop_file_new: - * @desktop_file_path: path to a Freedesktop-style Desktop file - * @error: error pointer - * - * Creates a new #EggDesktopFile for @desktop_file. - * - * Return value: the new #EggDesktopFile, or %NULL on error. - **/ -EggDesktopFile * -egg_desktop_file_new (const char *desktop_file_path, GError **error) -{ - GKeyFile *key_file; - - key_file = g_key_file_new (); - if (!g_key_file_load_from_file (key_file, desktop_file_path, 0, error)) - { - g_key_file_free (key_file); - return NULL; - } - - return egg_desktop_file_new_from_key_file (key_file, desktop_file_path, - error); -} - -/** - * egg_desktop_file_new_from_data_dirs: - * @desktop_file_path: relative path to a Freedesktop-style Desktop file - * @error: error pointer - * - * Looks for @desktop_file_path in the paths returned from - * g_get_user_data_dir() and g_get_system_data_dirs(), and creates - * a new #EggDesktopFile from it. - * - * Return value: the new #EggDesktopFile, or %NULL on error. - **/ -EggDesktopFile * -egg_desktop_file_new_from_data_dirs (const char *desktop_file_path, - GError **error) -{ - EggDesktopFile *desktop_file; - GKeyFile *key_file; - char *full_path; - - key_file = g_key_file_new (); - if (!g_key_file_load_from_data_dirs (key_file, desktop_file_path, - &full_path, 0, error)) - { - g_key_file_free (key_file); - return NULL; - } - - desktop_file = egg_desktop_file_new_from_key_file (key_file, - full_path, - error); - g_free (full_path); - return desktop_file; -} - -/** - * egg_desktop_file_new_from_dirs: - * @desktop_file_path: relative path to a Freedesktop-style Desktop file - * @search_dirs: NULL-terminated array of directories to search - * @error: error pointer - * - * Looks for @desktop_file_path in the paths returned from - * g_get_user_data_dir() and g_get_system_data_dirs(), and creates - * a new #EggDesktopFile from it. - * - * Return value: the new #EggDesktopFile, or %NULL on error. - **/ -EggDesktopFile * -egg_desktop_file_new_from_dirs (const char *desktop_file_path, - const char **search_dirs, - GError **error) -{ - EggDesktopFile *desktop_file; - GKeyFile *key_file; - char *full_path; - - key_file = g_key_file_new (); - if (!g_key_file_load_from_dirs (key_file, desktop_file_path, search_dirs, - &full_path, 0, error)) - { - g_key_file_free (key_file); - return NULL; - } - - desktop_file = egg_desktop_file_new_from_key_file (key_file, - full_path, - error); - g_free (full_path); - return desktop_file; -} - -/** - * egg_desktop_file_new_from_key_file: - * @key_file: a #GKeyFile representing a desktop file - * @source: the path or URI that @key_file was loaded from, or %NULL - * @error: error pointer - * - * Creates a new #EggDesktopFile for @key_file. Assumes ownership of - * @key_file (on success or failure); you should consider @key_file to - * be freed after calling this function. - * - * Return value: the new #EggDesktopFile, or %NULL on error. - **/ -EggDesktopFile * -egg_desktop_file_new_from_key_file (GKeyFile *key_file, - const char *source, - GError **error) -{ - EggDesktopFile *desktop_file; - char *version, *type; - - if (!g_key_file_has_group (key_file, EGG_DESKTOP_FILE_GROUP)) - { - g_set_error (error, EGG_DESKTOP_FILE_ERROR, - EGG_DESKTOP_FILE_ERROR_INVALID, - _("File is not a valid .desktop file")); - g_key_file_free (key_file); - return NULL; - } - - version = g_key_file_get_value (key_file, EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_VERSION, - NULL); - if (version) - { - double version_num; - char *end; - - version_num = g_ascii_strtod (version, &end); - if (*end) - { - g_warning ("Invalid Version string '%s' in %s", - version, source ? source : "(unknown)"); - } - else if (version_num > 1.0) - { - g_set_error (error, EGG_DESKTOP_FILE_ERROR, - EGG_DESKTOP_FILE_ERROR_INVALID, - _("Unrecognized desktop file Version '%s'"), version); - g_free (version); - g_key_file_free (key_file); - return NULL; - } - g_free (version); - } - - desktop_file = g_new0 (EggDesktopFile, 1); - desktop_file->key_file = key_file; - - if (g_path_is_absolute (source)) - desktop_file->source = g_filename_to_uri (source, NULL, NULL); - else - desktop_file->source = g_strdup (source); - - desktop_file->name = g_key_file_get_string (key_file, EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_NAME, error); - if (!desktop_file->name) - { - egg_desktop_file_free (desktop_file); - return NULL; - } - - type = g_key_file_get_string (key_file, EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_TYPE, error); - if (!type) - { - egg_desktop_file_free (desktop_file); - return NULL; - } - - if (!strcmp (type, "Application")) - { - char *exec, *p; - - desktop_file->type = EGG_DESKTOP_FILE_TYPE_APPLICATION; - - exec = g_key_file_get_string (key_file, - EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_EXEC, - error); - if (!exec) - { - egg_desktop_file_free (desktop_file); - g_free (type); - return NULL; - } - - /* See if it takes paths or URIs or neither */ - for (p = exec; *p; p++) - { - if (*p == '%') - { - if (p[1] == '\0' || strchr ("FfUu", p[1])) - { - desktop_file->document_code = p[1]; - break; - } - p++; - } - } - - g_free (exec); - } - else if (!strcmp (type, "Link")) - { - char *url; - - desktop_file->type = EGG_DESKTOP_FILE_TYPE_LINK; - - url = g_key_file_get_string (key_file, - EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_URL, - error); - if (!url) - { - egg_desktop_file_free (desktop_file); - g_free (type); - return NULL; - } - g_free (url); - } - else if (!strcmp (type, "Directory")) - desktop_file->type = EGG_DESKTOP_FILE_TYPE_DIRECTORY; - else - desktop_file->type = EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED; - - g_free (type); - - /* Check the Icon key */ - desktop_file->icon = g_key_file_get_string (key_file, - EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_ICON, - NULL); - if (desktop_file->icon && !g_path_is_absolute (desktop_file->icon)) - { - char *ext; - - /* Lots of .desktop files still get this wrong */ - ext = strrchr (desktop_file->icon, '.'); - if (ext && (!strcmp (ext, ".png") || - !strcmp (ext, ".xpm") || - !strcmp (ext, ".svg"))) - { - g_warning ("Desktop file '%s' has malformed Icon key '%s'" - "(should not include extension)", - source ? source : "(unknown)", - desktop_file->icon); - *ext = '\0'; - } - } - - return desktop_file; -} - -/** - * egg_desktop_file_free: - * @desktop_file: an #EggDesktopFile - * - * Frees @desktop_file. - **/ -void -egg_desktop_file_free (EggDesktopFile *desktop_file) -{ - g_key_file_free (desktop_file->key_file); - g_free (desktop_file->source); - g_free (desktop_file->name); - g_free (desktop_file->icon); - g_free (desktop_file); -} - -/** - * egg_desktop_file_get_source: - * @desktop_file: an #EggDesktopFile - * - * Gets the URI that @desktop_file was loaded from. - * - * Return value: @desktop_file's source URI - **/ -const char * -egg_desktop_file_get_source (EggDesktopFile *desktop_file) -{ - return desktop_file->source; -} - -/** - * egg_desktop_file_get_desktop_file_type: - * @desktop_file: an #EggDesktopFile - * - * Gets the desktop file type of @desktop_file. - * - * Return value: @desktop_file's type - **/ -EggDesktopFileType -egg_desktop_file_get_desktop_file_type (EggDesktopFile *desktop_file) -{ - return desktop_file->type; -} - -/** - * egg_desktop_file_get_name: - * @desktop_file: an #EggDesktopFile - * - * Gets the (localized) value of @desktop_file's "Name" key. - * - * Return value: the application/link name - **/ -const char * -egg_desktop_file_get_name (EggDesktopFile *desktop_file) -{ - return desktop_file->name; -} - -/** - * egg_desktop_file_get_icon: - * @desktop_file: an #EggDesktopFile - * - * Gets the value of @desktop_file's "Icon" key. - * - * If the icon string is a full path (that is, if g_path_is_absolute() - * returns %TRUE when called on it), it points to a file containing an - * unthemed icon. If the icon string is not a full path, it is the - * name of a themed icon, which can be looked up with %GtkIconTheme, - * or passed directly to a theme-aware widget like %GtkImage or - * %GtkCellRendererPixbuf. - * - * Return value: the icon path or name - **/ -const char * -egg_desktop_file_get_icon (EggDesktopFile *desktop_file) -{ - return desktop_file->icon; -} - -gboolean -egg_desktop_file_has_key (EggDesktopFile *desktop_file, - const char *key, - GError **error) -{ - return g_key_file_has_key (desktop_file->key_file, - EGG_DESKTOP_FILE_GROUP, key, - error); -} - -char * -egg_desktop_file_get_string (EggDesktopFile *desktop_file, - const char *key, - GError **error) -{ - return g_key_file_get_string (desktop_file->key_file, - EGG_DESKTOP_FILE_GROUP, key, - error); -} - -char * -egg_desktop_file_get_locale_string (EggDesktopFile *desktop_file, - const char *key, - const char *locale, - GError **error) -{ - return g_key_file_get_locale_string (desktop_file->key_file, - EGG_DESKTOP_FILE_GROUP, key, locale, - error); -} - -gboolean -egg_desktop_file_get_boolean (EggDesktopFile *desktop_file, - const char *key, - GError **error) -{ - return g_key_file_get_boolean (desktop_file->key_file, - EGG_DESKTOP_FILE_GROUP, key, - error); -} - -double -egg_desktop_file_get_numeric (EggDesktopFile *desktop_file, - const char *key, - GError **error) -{ - return g_key_file_get_double (desktop_file->key_file, - EGG_DESKTOP_FILE_GROUP, key, - error); -} - -char ** -egg_desktop_file_get_string_list (EggDesktopFile *desktop_file, - const char *key, - gsize *length, - GError **error) -{ - return g_key_file_get_string_list (desktop_file->key_file, - EGG_DESKTOP_FILE_GROUP, key, length, - error); -} - -char ** -egg_desktop_file_get_locale_string_list (EggDesktopFile *desktop_file, - const char *key, - const char *locale, - gsize *length, - GError **error) -{ - return g_key_file_get_locale_string_list (desktop_file->key_file, - EGG_DESKTOP_FILE_GROUP, key, - locale, length, - error); -} - -/** - * egg_desktop_file_can_launch: - * @desktop_file: an #EggDesktopFile - * @desktop_environment: the name of the running desktop environment, - * or %NULL - * - * Tests if @desktop_file can/should be launched in the current - * environment. If @desktop_environment is non-%NULL, @desktop_file's - * "OnlyShowIn" and "NotShowIn" keys are checked to make sure that - * this desktop_file is appropriate for the named environment. - * - * Furthermore, if @desktop_file has type - * %EGG_DESKTOP_FILE_TYPE_APPLICATION, its "TryExec" key (if any) is - * also checked, to make sure the binary it points to exists. - * - * egg_desktop_file_can_launch() does NOT check the value of the - * "Hidden" key. - * - * Return value: %TRUE if @desktop_file can be launched - **/ -gboolean -egg_desktop_file_can_launch (EggDesktopFile *desktop_file, - const char *desktop_environment) -{ - char *try_exec, *found_program; - char **only_show_in, **not_show_in; - gboolean found; - int i; - - if (desktop_file->type != EGG_DESKTOP_FILE_TYPE_APPLICATION && - desktop_file->type != EGG_DESKTOP_FILE_TYPE_LINK) - return FALSE; - - if (desktop_environment) - { - only_show_in = g_key_file_get_string_list (desktop_file->key_file, - EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_ONLY_SHOW_IN, - NULL, NULL); - if (only_show_in) - { - for (i = 0, found = FALSE; only_show_in[i] && !found; i++) - { - if (!strcmp (only_show_in[i], desktop_environment)) - found = TRUE; - } - - g_strfreev (only_show_in); - - if (!found) - return FALSE; - } - - not_show_in = g_key_file_get_string_list (desktop_file->key_file, - EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_NOT_SHOW_IN, - NULL, NULL); - if (not_show_in) - { - for (i = 0, found = FALSE; not_show_in[i] && !found; i++) - { - if (!strcmp (not_show_in[i], desktop_environment)) - found = TRUE; - } - - g_strfreev (not_show_in); - - if (found) - return FALSE; - } - } - - if (desktop_file->type == EGG_DESKTOP_FILE_TYPE_APPLICATION) - { - try_exec = g_key_file_get_string (desktop_file->key_file, - EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_TRY_EXEC, - NULL); - if (try_exec) - { - found_program = g_find_program_in_path (try_exec); - g_free (try_exec); - - if (!found_program) - return FALSE; - g_free (found_program); - } - } - - return TRUE; -} - -/** - * egg_desktop_file_accepts_documents: - * @desktop_file: an #EggDesktopFile - * - * Tests if @desktop_file represents an application that can accept - * documents on the command line. - * - * Return value: %TRUE or %FALSE - **/ -gboolean -egg_desktop_file_accepts_documents (EggDesktopFile *desktop_file) -{ - return desktop_file->document_code != 0; -} - -/** - * egg_desktop_file_accepts_multiple: - * @desktop_file: an #EggDesktopFile - * - * Tests if @desktop_file can accept multiple documents at once. - * - * If this returns %FALSE, you can still pass multiple documents to - * egg_desktop_file_launch(), but that will result in multiple copies - * of the application being launched. See egg_desktop_file_launch() - * for more details. - * - * Return value: %TRUE or %FALSE - **/ -gboolean -egg_desktop_file_accepts_multiple (EggDesktopFile *desktop_file) -{ - return (desktop_file->document_code == 'F' || - desktop_file->document_code == 'U'); -} - -/** - * egg_desktop_file_accepts_uris: - * @desktop_file: an #EggDesktopFile - * - * Tests if @desktop_file can accept (non-"file:") URIs as documents to - * open. - * - * Return value: %TRUE or %FALSE - **/ -gboolean -egg_desktop_file_accepts_uris (EggDesktopFile *desktop_file) -{ - return (desktop_file->document_code == 'U' || - desktop_file->document_code == 'u'); -} - -static void -append_quoted_word (GString *str, - const char *s, - gboolean in_single_quotes, - gboolean in_double_quotes) -{ - const char *p; - - if (!in_single_quotes && !in_double_quotes) - g_string_append_c (str, '\''); - else if (!in_single_quotes && in_double_quotes) - g_string_append (str, "\"'"); - - if (!strchr (s, '\'')) - g_string_append (str, s); - else - { - for (p = s; *p != '\0'; p++) - { - if (*p == '\'') - g_string_append (str, "'\\''"); - else - g_string_append_c (str, *p); - } - } - - if (!in_single_quotes && !in_double_quotes) - g_string_append_c (str, '\''); - else if (!in_single_quotes && in_double_quotes) - g_string_append (str, "'\""); -} - -static void -do_percent_subst (EggDesktopFile *desktop_file, - char code, - GString *str, - GSList **documents, - gboolean in_single_quotes, - gboolean in_double_quotes) -{ - GSList *d; - char *doc; - - switch (code) - { - case '%': - g_string_append_c (str, '%'); - break; - - case 'F': - case 'U': - for (d = *documents; d; d = d->next) - { - doc = d->data; - g_string_append (str, " "); - append_quoted_word (str, doc, in_single_quotes, in_double_quotes); - } - *documents = NULL; - break; - - case 'f': - case 'u': - if (*documents) - { - doc = (*documents)->data; - g_string_append (str, " "); - append_quoted_word (str, doc, in_single_quotes, in_double_quotes); - *documents = (*documents)->next; - } - break; - - case 'i': - if (desktop_file->icon) - { - g_string_append (str, "--icon "); - append_quoted_word (str, desktop_file->icon, - in_single_quotes, in_double_quotes); - } - break; - - case 'c': - if (desktop_file->name) - { - append_quoted_word (str, desktop_file->name, - in_single_quotes, in_double_quotes); - } - break; - - case 'k': - if (desktop_file->source) - { - append_quoted_word (str, desktop_file->source, - in_single_quotes, in_double_quotes); - } - break; - - case 'D': - case 'N': - case 'd': - case 'n': - case 'v': - case 'm': - /* Deprecated; skip */ - break; - - default: - g_warning ("Unrecognized %%-code '%%%c' in Exec", code); - break; - } -} - -static char * -parse_exec (EggDesktopFile *desktop_file, - GSList **documents, - GError **error) -{ - char *exec, *p, *command; - gboolean escape, single_quot, double_quot; - GString *gs; - - exec = g_key_file_get_string (desktop_file->key_file, - EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_EXEC, - error); - if (!exec) - return NULL; - - /* Build the command */ - gs = g_string_new (NULL); - escape = single_quot = double_quot = FALSE; - - for (p = exec; *p != '\0'; p++) - { - if (escape) - { - escape = FALSE; - g_string_append_c (gs, *p); - } - else if (*p == '\\') - { - if (!single_quot) - escape = TRUE; - g_string_append_c (gs, *p); - } - else if (*p == '\'') - { - g_string_append_c (gs, *p); - if (!single_quot && !double_quot) - single_quot = TRUE; - else if (single_quot) - single_quot = FALSE; - } - else if (*p == '"') - { - g_string_append_c (gs, *p); - if (!single_quot && !double_quot) - double_quot = TRUE; - else if (double_quot) - double_quot = FALSE; - } - else if (*p == '%' && p[1]) - { - do_percent_subst (desktop_file, p[1], gs, documents, - single_quot, double_quot); - p++; - } - else - g_string_append_c (gs, *p); - } - - g_free (exec); - command = g_string_free (gs, FALSE); - - /* Prepend "xdg-terminal " if needed (FIXME: use gvfs) */ - if (g_key_file_has_key (desktop_file->key_file, - EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_TERMINAL, - NULL)) - { - GError *terminal_error = NULL; - gboolean use_terminal = - g_key_file_get_boolean (desktop_file->key_file, - EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_TERMINAL, - &terminal_error); - if (terminal_error) - { - g_free (command); - g_propagate_error (error, terminal_error); - return NULL; - } - - if (use_terminal) - { - gs = g_string_new ("xdg-terminal "); - append_quoted_word (gs, command, FALSE, FALSE); - g_free (command); - command = g_string_free (gs, FALSE); - } - } - - return command; -} - -static GSList * -translate_document_list (EggDesktopFile *desktop_file, GSList *documents) -{ - gboolean accepts_uris = egg_desktop_file_accepts_uris (desktop_file); - GSList *ret, *d; - - for (d = documents, ret = NULL; d; d = d->next) - { - const char *document = d->data; - gboolean is_uri = !g_path_is_absolute (document); - char *translated; - - if (accepts_uris) - { - if (is_uri) - translated = g_strdup (document); - else - translated = g_filename_to_uri (document, NULL, NULL); - } - else - { - if (is_uri) - translated = g_filename_from_uri (document, NULL, NULL); - else - translated = g_strdup (document); - } - - if (translated) - ret = g_slist_prepend (ret, translated); - } - - return g_slist_reverse (ret); -} - -static void -free_document_list (GSList *documents) -{ - GSList *d; - - for (d = documents; d; d = d->next) - g_free (d->data); - g_slist_free (documents); -} - -/** - * egg_desktop_file_parse_exec: - * @desktop_file: a #EggDesktopFile - * @documents: a list of document paths or URIs - * @error: error pointer - * - * Parses @desktop_file's Exec key, inserting @documents into it, and - * returns the result. - * - * If @documents contains non-file: URIs and @desktop_file does not - * accept URIs, those URIs will be ignored. Likewise, if @documents - * contains more elements than @desktop_file accepts, the extra - * documents will be ignored. - * - * Return value: the parsed Exec string - **/ -char * -egg_desktop_file_parse_exec (EggDesktopFile *desktop_file, - GSList *documents, - GError **error) -{ - GSList *translated, *docs; - char *command; - - docs = translated = translate_document_list (desktop_file, documents); - command = parse_exec (desktop_file, &docs, error); - free_document_list (translated); - - return command; -} - -static gboolean -parse_link (EggDesktopFile *desktop_file, - EggDesktopFile **app_desktop_file, - GSList **documents, - GError **error) -{ - char *url; - GKeyFile *key_file; - - url = g_key_file_get_string (desktop_file->key_file, - EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_URL, - error); - if (!url) - return FALSE; - *documents = g_slist_prepend (NULL, url); - - /* FIXME: use gvfs */ - key_file = g_key_file_new (); - g_key_file_set_string (key_file, EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_NAME, - "xdg-open"); - g_key_file_set_string (key_file, EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_TYPE, - "Application"); - g_key_file_set_string (key_file, EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_EXEC, - "xdg-open %u"); - *app_desktop_file = egg_desktop_file_new_from_key_file (key_file, NULL, NULL); - return TRUE; -} - -static char * -start_startup_notification (GdkDisplay *display, - EggDesktopFile *desktop_file, - const char *argv0, - int screen, - int workspace, - guint32 launch_time) -{ - static int sequence = 0; - char *startup_id; - char *description, *wmclass; - char *screen_str, *workspace_str; - - if (g_key_file_has_key (desktop_file->key_file, - EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY, - NULL)) - { - if (!g_key_file_get_boolean (desktop_file->key_file, - EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY, - NULL)) - return NULL; - wmclass = NULL; - } - else - { - wmclass = g_key_file_get_string (desktop_file->key_file, - EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_STARTUP_WM_CLASS, - NULL); - if (!wmclass) - return NULL; - } - - if (launch_time == (guint32)-1) - launch_time = gdk_x11_display_get_user_time (display); - startup_id = g_strdup_printf ("%s-%lu-%s-%s-%d_TIME%lu", - g_get_prgname (), - (unsigned long)getpid (), - g_get_host_name (), - argv0, - sequence++, - (unsigned long)launch_time); - - description = g_strdup_printf (_("Starting %s"), desktop_file->name); - screen_str = g_strdup_printf ("%d", screen); - workspace_str = workspace == -1 ? NULL : g_strdup_printf ("%d", workspace); - - gdk_x11_display_broadcast_startup_message (display, "new", - "ID", startup_id, - "NAME", desktop_file->name, - "SCREEN", screen_str, - "BIN", argv0, - "ICON", desktop_file->icon, - "DESKTOP", workspace_str, - "DESCRIPTION", description, - "WMCLASS", wmclass, - NULL); - - g_free (description); - g_free (wmclass); - g_free (screen_str); - g_free (workspace_str); - - return startup_id; -} - -static void -end_startup_notification (GdkDisplay *display, - const char *startup_id) -{ - gdk_x11_display_broadcast_startup_message (display, "remove", - "ID", startup_id, - NULL); -} - -#define EGG_DESKTOP_FILE_SN_TIMEOUT_LENGTH (30 /* seconds */) - -typedef struct { - GdkDisplay *display; - char *startup_id; -} StartupNotificationData; - -static gboolean -startup_notification_timeout (gpointer data) -{ - StartupNotificationData *sn_data = data; - - end_startup_notification (sn_data->display, sn_data->startup_id); - g_object_unref (sn_data->display); - g_free (sn_data->startup_id); - g_free (sn_data); - - return FALSE; -} - -static void -set_startup_notification_timeout (GdkDisplay *display, - const char *startup_id) -{ - StartupNotificationData *sn_data; - - sn_data = g_new (StartupNotificationData, 1); - sn_data->display = g_object_ref (display); - sn_data->startup_id = g_strdup (startup_id); - - g_timeout_add_seconds (EGG_DESKTOP_FILE_SN_TIMEOUT_LENGTH, - startup_notification_timeout, sn_data); -} - -static GPtrArray * -array_putenv (GPtrArray *env, char *variable) -{ - guint i, keylen; - - if (!env) - { - char **envp; - - env = g_ptr_array_new (); - - envp = g_listenv (); - for (i = 0; envp[i]; i++) - { - const char *value; - - value = g_getenv (envp[i]); - g_ptr_array_add (env, g_strdup_printf ("%s=%s", envp[i], - value ? value : "")); - } - g_strfreev (envp); - } - - keylen = strcspn (variable, "="); - - /* Remove old value of key */ - for (i = 0; i < env->len; i++) - { - char *envvar = env->pdata[i]; - - if (!strncmp (envvar, variable, keylen) && envvar[keylen] == '=') - { - g_free (envvar); - g_ptr_array_remove_index_fast (env, i); - break; - } - } - - /* Add new value */ - g_ptr_array_add (env, g_strdup (variable)); - - return env; -} - -static gboolean -egg_desktop_file_launchv (EggDesktopFile *desktop_file, - GSList *documents, va_list args, - GError **error) -{ - EggDesktopFileLaunchOption option; - GSList *translated_documents = NULL, *docs = NULL; - char *command, **argv; - int argc, i, screen_num; - gboolean success, current_success; - GdkDisplay *display; - char *startup_id; - - GPtrArray *env = NULL; - char **variables = NULL; - GdkScreen *screen = NULL; - int workspace = -1; - const char *directory = NULL; - guint32 launch_time = (guint32)-1; - GSpawnFlags flags = G_SPAWN_SEARCH_PATH; - GSpawnChildSetupFunc setup_func = NULL; - gpointer setup_data = NULL; - - GPid *ret_pid = NULL; - int *ret_stdin = NULL, *ret_stdout = NULL, *ret_stderr = NULL; - char **ret_startup_id = NULL; - - if (documents && desktop_file->document_code == 0) - { - g_set_error (error, EGG_DESKTOP_FILE_ERROR, - EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE, - _("Application does not accept documents on command line")); - return FALSE; - } - - /* Read the options: technically it's incorrect for the caller to - * NULL-terminate the list of options (rather than 0-terminating - * it), but NULL-terminating lets us use G_GNUC_NULL_TERMINATED, - * it's more consistent with other glib/gtk methods, and it will - * work as long as sizeof (int) <= sizeof (NULL), and NULL is - * represented as 0. (Which is true everywhere we care about.) - */ - while ((option = va_arg (args, EggDesktopFileLaunchOption))) - { - switch (option) - { - case EGG_DESKTOP_FILE_LAUNCH_CLEARENV: - if (env) - g_ptr_array_free (env, TRUE); - env = g_ptr_array_new (); - break; - case EGG_DESKTOP_FILE_LAUNCH_PUTENV: - variables = va_arg (args, char **); - for (i = 0; variables[i]; i++) - env = array_putenv (env, variables[i]); - break; - - case EGG_DESKTOP_FILE_LAUNCH_SCREEN: - screen = va_arg (args, GdkScreen *); - break; - case EGG_DESKTOP_FILE_LAUNCH_WORKSPACE: - workspace = va_arg (args, int); - break; - - case EGG_DESKTOP_FILE_LAUNCH_DIRECTORY: - directory = va_arg (args, const char *); - break; - case EGG_DESKTOP_FILE_LAUNCH_TIME: - launch_time = va_arg (args, guint32); - break; - case EGG_DESKTOP_FILE_LAUNCH_FLAGS: - flags |= va_arg (args, GSpawnFlags); - /* Make sure they didn't set any flags that don't make sense. */ - flags &= ~G_SPAWN_FILE_AND_ARGV_ZERO; - break; - case EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC: - setup_func = va_arg (args, GSpawnChildSetupFunc); - setup_data = va_arg (args, gpointer); - break; - - case EGG_DESKTOP_FILE_LAUNCH_RETURN_PID: - ret_pid = va_arg (args, GPid *); - break; - case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE: - ret_stdin = va_arg (args, int *); - break; - case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE: - ret_stdout = va_arg (args, int *); - break; - case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE: - ret_stderr = va_arg (args, int *); - break; - case EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID: - ret_startup_id = va_arg (args, char **); - break; - - default: - g_set_error (error, EGG_DESKTOP_FILE_ERROR, - EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION, - _("Unrecognized launch option: %d"), - GPOINTER_TO_INT (option)); - success = FALSE; - goto out; - } - } - - if (screen) - { - char *display_name = gdk_screen_make_display_name (screen); - char *display_env = g_strdup_printf ("DISPLAY=%s", display_name); - env = array_putenv (env, display_env); - g_free (display_name); - g_free (display_env); - - display = gdk_screen_get_display (screen); - } - else - { - display = gdk_display_get_default (); - screen = gdk_display_get_default_screen (display); - } - screen_num = gdk_screen_get_number (screen); - - translated_documents = translate_document_list (desktop_file, documents); - docs = translated_documents; - - success = FALSE; - - do - { - command = parse_exec (desktop_file, &docs, error); - if (!command) - goto out; - - if (!g_shell_parse_argv (command, &argc, &argv, error)) - { - g_free (command); - goto out; - } - g_free (command); - - startup_id = start_startup_notification (display, desktop_file, - argv[0], screen_num, - workspace, launch_time); - if (startup_id) - { - char *startup_id_env = g_strdup_printf ("DESKTOP_STARTUP_ID=%s", - startup_id); - env = array_putenv (env, startup_id_env); - g_free (startup_id_env); - } - - if (env != NULL) - g_ptr_array_add (env, NULL); - - current_success = - g_spawn_async_with_pipes (directory, - argv, - env ? (char **)(env->pdata) : NULL, - flags, - setup_func, setup_data, - ret_pid, - ret_stdin, ret_stdout, ret_stderr, - error); - g_strfreev (argv); - - if (startup_id) - { - if (current_success) - { - set_startup_notification_timeout (display, startup_id); - - if (ret_startup_id) - *ret_startup_id = startup_id; - else - g_free (startup_id); - } - else - g_free (startup_id); - } - else if (ret_startup_id) - *ret_startup_id = NULL; - - if (current_success) - { - /* If we successfully launch any instances of the app, make - * sure we return TRUE and don't set @error. - */ - success = TRUE; - error = NULL; - - /* Also, only set the output params on the first one */ - ret_pid = NULL; - ret_stdin = ret_stdout = ret_stderr = NULL; - ret_startup_id = NULL; - } - } - while (docs && current_success); - - out: - if (env) - { - g_ptr_array_foreach (env, (GFunc)g_free, NULL); - g_ptr_array_free (env, TRUE); - } - free_document_list (translated_documents); - - return success; -} - -/** - * egg_desktop_file_launch: - * @desktop_file: an #EggDesktopFile - * @documents: a list of URIs or paths to documents to open - * @error: error pointer - * @...: additional options - * - * Launches @desktop_file with the given arguments. Additional options - * can be specified as follows: - * - * %EGG_DESKTOP_FILE_LAUNCH_CLEARENV: (no arguments) - * clears the environment in the child process - * %EGG_DESKTOP_FILE_LAUNCH_PUTENV: (char **variables) - * adds the NAME=VALUE strings in the given %NULL-terminated - * array to the child process's environment - * %EGG_DESKTOP_FILE_LAUNCH_SCREEN: (GdkScreen *screen) - * causes the application to be launched on the given screen - * %EGG_DESKTOP_FILE_LAUNCH_WORKSPACE: (int workspace) - * causes the application to be launched on the given workspace - * %EGG_DESKTOP_FILE_LAUNCH_DIRECTORY: (char *dir) - * causes the application to be launched in the given directory - * %EGG_DESKTOP_FILE_LAUNCH_TIME: (guint32 launch_time) - * sets the "launch time" for the application. If the user - * interacts with another window after @launch_time but before - * the launched application creates its first window, the window - * manager may choose to not give focus to the new application. - * Passing 0 for @launch_time will explicitly request that the - * application not receive focus. - * %EGG_DESKTOP_FILE_LAUNCH_FLAGS (GSpawnFlags flags) - * Sets additional #GSpawnFlags to use. See g_spawn_async() for - * more details. - * %EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC (GSpawnChildSetupFunc, gpointer) - * Sets the child setup callback and the data to pass to it. - * (See g_spawn_async() for more details.) - * - * %EGG_DESKTOP_FILE_LAUNCH_RETURN_PID (GPid **pid) - * On a successful launch, sets *@pid to the PID of the launched - * application. - * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID (char **startup_id) - * On a successful launch, sets *@startup_id to the Startup - * Notification "startup id" of the launched application. - * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE (int *fd) - * On a successful launch, sets *@fd to the file descriptor of - * a pipe connected to the application's stdin. - * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE (int *fd) - * On a successful launch, sets *@fd to the file descriptor of - * a pipe connected to the application's stdout. - * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE (int *fd) - * On a successful launch, sets *@fd to the file descriptor of - * a pipe connected to the application's stderr. - * - * The options should be terminated with a single %NULL. - * - * If @documents contains multiple documents, but - * egg_desktop_file_accepts_multiple() returns %FALSE for - * @desktop_file, then egg_desktop_file_launch() will actually launch - * multiple instances of the application. In that case, the return - * value (as well as any values passed via - * %EGG_DESKTOP_FILE_LAUNCH_RETURN_PID, etc) will only reflect the - * first instance of the application that was launched (but the - * %EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC will be called for each - * instance). - * - * Return value: %TRUE if the application was successfully launched. - **/ -gboolean -egg_desktop_file_launch (EggDesktopFile *desktop_file, - GSList *documents, GError **error, - ...) -{ - va_list args; - gboolean success; - EggDesktopFile *app_desktop_file; - - switch (desktop_file->type) - { - case EGG_DESKTOP_FILE_TYPE_APPLICATION: - va_start (args, error); - success = egg_desktop_file_launchv (desktop_file, documents, - args, error); - va_end (args); - break; - - case EGG_DESKTOP_FILE_TYPE_LINK: - if (documents) - { - g_set_error (error, EGG_DESKTOP_FILE_ERROR, - EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE, - _("Can't pass document URIs to a 'Type=Link' desktop entry")); - return FALSE; - } - - if (!parse_link (desktop_file, &app_desktop_file, &documents, error)) - return FALSE; - - va_start (args, error); - success = egg_desktop_file_launchv (app_desktop_file, documents, - args, error); - va_end (args); - - egg_desktop_file_free (app_desktop_file); - free_document_list (documents); - break; - - case EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED: - case EGG_DESKTOP_FILE_TYPE_DIRECTORY: - default: - g_set_error (error, EGG_DESKTOP_FILE_ERROR, - EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE, - _("Not a launchable item")); - success = FALSE; - break; - } - - return success; -} - - -GQuark -egg_desktop_file_error_quark (void) -{ - return g_quark_from_static_string ("egg-desktop_file-error-quark"); -} - - -G_LOCK_DEFINE_STATIC (egg_desktop_file); -static EggDesktopFile *egg_desktop_file; - -static void -egg_set_desktop_file_internal (const char *desktop_file_path, - gboolean set_defaults) -{ - GError *error = NULL; - - G_LOCK (egg_desktop_file); - if (egg_desktop_file) - egg_desktop_file_free (egg_desktop_file); - - egg_desktop_file = egg_desktop_file_new (desktop_file_path, &error); - if (error) - { - g_warning ("Could not load desktop file '%s': %s", - desktop_file_path, error->message); - g_error_free (error); - } - - if (set_defaults && egg_desktop_file != NULL) { - /* Set localized application name and default window icon */ - if (egg_desktop_file->name) - g_set_application_name (egg_desktop_file->name); - if (egg_desktop_file->icon) - { - if (g_path_is_absolute (egg_desktop_file->icon)) - gtk_window_set_default_icon_from_file (egg_desktop_file->icon, NULL); - else - gtk_window_set_default_icon_name (egg_desktop_file->icon); - } - } - - G_UNLOCK (egg_desktop_file); -} - -/** - * egg_set_desktop_file: - * @desktop_file_path: path to the application's desktop file - * - * Creates an #EggDesktopFile for the application from the data at - * @desktop_file_path. This will also call g_set_application_name() - * with the localized application name from the desktop file, and - * gtk_window_set_default_icon_name() or - * gtk_window_set_default_icon_from_file() with the application's - * icon. Other code may use additional information from the desktop - * file. - * See egg_set_desktop_file_without_defaults() for a variant of this - * function that does not set the application name and default window - * icon. - * - * Note that for thread safety reasons, this function can only - * be called once, and is mutually exclusive with calling - * egg_set_desktop_file_without_defaults(). - **/ -void -egg_set_desktop_file (const char *desktop_file_path) -{ - egg_set_desktop_file_internal (desktop_file_path, TRUE); -} - -/** - * egg_set_desktop_file_without_defaults: - * @desktop_file_path: path to the application's desktop file - * - * Creates an #EggDesktopFile for the application from the data at - * @desktop_file_path. - * See egg_set_desktop_file() for a variant of this function that - * sets the application name and default window icon from the information - * in the desktop file. - * - * Note that for thread safety reasons, this function can only - * be called once, and is mutually exclusive with calling - * egg_set_desktop_file(). - **/ -void -egg_set_desktop_file_without_defaults (const char *desktop_file_path) -{ - egg_set_desktop_file_internal (desktop_file_path, FALSE); -} - -/** - * egg_get_desktop_file: - * - * Gets the application's #EggDesktopFile, as set by - * egg_set_desktop_file(). - * - * Return value: the #EggDesktopFile, or %NULL if it hasn't been set. - **/ -EggDesktopFile * -egg_get_desktop_file (void) -{ - EggDesktopFile *retval; - - G_LOCK (egg_desktop_file); - retval = egg_desktop_file; - G_UNLOCK (egg_desktop_file); - - return retval; -} diff --git a/xed/smclient/eggdesktopfile.h b/xed/smclient/eggdesktopfile.h deleted file mode 100644 index d9e69ec..0000000 --- a/xed/smclient/eggdesktopfile.h +++ /dev/null @@ -1,160 +0,0 @@ -/* eggdesktopfile.h - Freedesktop.Org Desktop Files - * Copyright (C) 2007 Novell, Inc. - * - * 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 of - * the License, or (at your option) any later version. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; see the file COPYING.LIB. If not, - * write to the Free Software Foundation, Inc., 151 Franklin Street, - * Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __EGG_DESKTOP_FILE_H__ -#define __EGG_DESKTOP_FILE_H__ - -#include - -G_BEGIN_DECLS - -typedef struct EggDesktopFile EggDesktopFile; - -typedef enum { - EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED, - - EGG_DESKTOP_FILE_TYPE_APPLICATION, - EGG_DESKTOP_FILE_TYPE_LINK, - EGG_DESKTOP_FILE_TYPE_DIRECTORY -} EggDesktopFileType; - -EggDesktopFile *egg_desktop_file_new (const char *desktop_file_path, - GError **error); - -EggDesktopFile *egg_desktop_file_new_from_data_dirs (const char *desktop_file_path, - GError **error); -EggDesktopFile *egg_desktop_file_new_from_dirs (const char *desktop_file_path, - const char **search_dirs, - GError **error); -EggDesktopFile *egg_desktop_file_new_from_key_file (GKeyFile *key_file, - const char *source, - GError **error); - -void egg_desktop_file_free (EggDesktopFile *desktop_file); - -const char *egg_desktop_file_get_source (EggDesktopFile *desktop_file); - -EggDesktopFileType egg_desktop_file_get_desktop_file_type (EggDesktopFile *desktop_file); - -const char *egg_desktop_file_get_name (EggDesktopFile *desktop_file); -const char *egg_desktop_file_get_icon (EggDesktopFile *desktop_file); - -gboolean egg_desktop_file_can_launch (EggDesktopFile *desktop_file, - const char *desktop_environment); - -gboolean egg_desktop_file_accepts_documents (EggDesktopFile *desktop_file); -gboolean egg_desktop_file_accepts_multiple (EggDesktopFile *desktop_file); -gboolean egg_desktop_file_accepts_uris (EggDesktopFile *desktop_file); - -char *egg_desktop_file_parse_exec (EggDesktopFile *desktop_file, - GSList *documents, - GError **error); - -gboolean egg_desktop_file_launch (EggDesktopFile *desktop_file, - GSList *documents, - GError **error, - ...) G_GNUC_NULL_TERMINATED; - -typedef enum { - EGG_DESKTOP_FILE_LAUNCH_CLEARENV = 1, - EGG_DESKTOP_FILE_LAUNCH_PUTENV, - EGG_DESKTOP_FILE_LAUNCH_SCREEN, - EGG_DESKTOP_FILE_LAUNCH_WORKSPACE, - EGG_DESKTOP_FILE_LAUNCH_DIRECTORY, - EGG_DESKTOP_FILE_LAUNCH_TIME, - EGG_DESKTOP_FILE_LAUNCH_FLAGS, - EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC, - EGG_DESKTOP_FILE_LAUNCH_RETURN_PID, - EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE, - EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE, - EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE, - EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID -} EggDesktopFileLaunchOption; - -/* Standard Keys */ -#define EGG_DESKTOP_FILE_GROUP "Desktop Entry" - -#define EGG_DESKTOP_FILE_KEY_TYPE "Type" -#define EGG_DESKTOP_FILE_KEY_VERSION "Version" -#define EGG_DESKTOP_FILE_KEY_NAME "Name" -#define EGG_DESKTOP_FILE_KEY_GENERIC_NAME "GenericName" -#define EGG_DESKTOP_FILE_KEY_NO_DISPLAY "NoDisplay" -#define EGG_DESKTOP_FILE_KEY_COMMENT "Comment" -#define EGG_DESKTOP_FILE_KEY_ICON "Icon" -#define EGG_DESKTOP_FILE_KEY_HIDDEN "Hidden" -#define EGG_DESKTOP_FILE_KEY_ONLY_SHOW_IN "OnlyShowIn" -#define EGG_DESKTOP_FILE_KEY_NOT_SHOW_IN "NotShowIn" -#define EGG_DESKTOP_FILE_KEY_TRY_EXEC "TryExec" -#define EGG_DESKTOP_FILE_KEY_EXEC "Exec" -#define EGG_DESKTOP_FILE_KEY_PATH "Path" -#define EGG_DESKTOP_FILE_KEY_TERMINAL "Terminal" -#define EGG_DESKTOP_FILE_KEY_MIME_TYPE "MimeType" -#define EGG_DESKTOP_FILE_KEY_CATEGORIES "Categories" -#define EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY "StartupNotify" -#define EGG_DESKTOP_FILE_KEY_STARTUP_WM_CLASS "StartupWMClass" -#define EGG_DESKTOP_FILE_KEY_URL "URL" - -/* Accessors */ -gboolean egg_desktop_file_has_key (EggDesktopFile *desktop_file, - const char *key, - GError **error); -char *egg_desktop_file_get_string (EggDesktopFile *desktop_file, - const char *key, - GError **error) G_GNUC_MALLOC; -char *egg_desktop_file_get_locale_string (EggDesktopFile *desktop_file, - const char *key, - const char *locale, - GError **error) G_GNUC_MALLOC; -gboolean egg_desktop_file_get_boolean (EggDesktopFile *desktop_file, - const char *key, - GError **error); -double egg_desktop_file_get_numeric (EggDesktopFile *desktop_file, - const char *key, - GError **error); -char **egg_desktop_file_get_string_list (EggDesktopFile *desktop_file, - const char *key, - gsize *length, - GError **error) G_GNUC_MALLOC; -char **egg_desktop_file_get_locale_string_list (EggDesktopFile *desktop_file, - const char *key, - const char *locale, - gsize *length, - GError **error) G_GNUC_MALLOC; - - -/* Errors */ -#define EGG_DESKTOP_FILE_ERROR egg_desktop_file_error_quark() - -GQuark egg_desktop_file_error_quark (void); - -typedef enum { - EGG_DESKTOP_FILE_ERROR_INVALID, - EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE, - EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION -} EggDesktopFileError; - -/* Global application desktop file */ -void egg_set_desktop_file (const char *desktop_file_path); -void egg_set_desktop_file_without_defaults (const char *desktop_file_path); -EggDesktopFile *egg_get_desktop_file (void); - - -G_END_DECLS - -#endif /* __EGG_DESKTOP_FILE_H__ */ diff --git a/xed/smclient/eggsmclient-private.h b/xed/smclient/eggsmclient-private.h deleted file mode 100644 index 9a63555..0000000 --- a/xed/smclient/eggsmclient-private.h +++ /dev/null @@ -1,39 +0,0 @@ -/* eggsmclient-private.h - * Copyright (C) 2007 Novell, Inc. - * - * 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 of the License, or (at your option) any later version. - * - * 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 - * Lesser General Public License for more details. - * - * 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 St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef __EGG_SM_CLIENT_PRIVATE_H__ -#define __EGG_SM_CLIENT_PRIVATE_H__ - -#include -#include "eggsmclient.h" - -G_BEGIN_DECLS - -GKeyFile *egg_sm_client_save_state (EggSMClient *client); -void egg_sm_client_quit_requested (EggSMClient *client); -void egg_sm_client_quit_cancelled (EggSMClient *client); -void egg_sm_client_quit (EggSMClient *client); - -GType egg_sm_client_xsmp_get_type (void); -EggSMClient *egg_sm_client_xsmp_new (void); - -G_END_DECLS - - -#endif /* __EGG_SM_CLIENT_PRIVATE_H__ */ diff --git a/xed/smclient/eggsmclient-xsmp.c b/xed/smclient/eggsmclient-xsmp.c deleted file mode 100644 index 15bcf74..0000000 --- a/xed/smclient/eggsmclient-xsmp.c +++ /dev/null @@ -1,1365 +0,0 @@ -/* - * Copyright (C) 2007 Novell, Inc. - * - * Inspired by various other pieces of code including GsmClient (C) - * 2001 Havoc Pennington, MateClient (C) 1998 Carsten Schaar, and twm - * session code (C) 1998 The Open Group. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "config.h" - -#include "eggsmclient.h" -#include "eggsmclient-private.h" - -#include "eggdesktopfile.h" - -#include -#include -#include -#include -#include -#include - -#include -#include - -#define EGG_TYPE_SM_CLIENT_XSMP (egg_sm_client_xsmp_get_type ()) -#define EGG_SM_CLIENT_XSMP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMP)) -#define EGG_SM_CLIENT_XSMP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMPClass)) -#define EGG_IS_SM_CLIENT_XSMP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT_XSMP)) -#define EGG_IS_SM_CLIENT_XSMP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT_XSMP)) -#define EGG_SM_CLIENT_XSMP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMPClass)) - -typedef struct _EggSMClientXSMP EggSMClientXSMP; -typedef struct _EggSMClientXSMPClass EggSMClientXSMPClass; - -/* These mostly correspond to the similarly-named states in section - * 9.1 of the XSMP spec. Some of the states there aren't represented - * here, because we don't need them. SHUTDOWN_CANCELLED is slightly - * different from the spec; we use it when the client is IDLE after a - * ShutdownCancelled message, but the application is still interacting - * and doesn't know the shutdown has been cancelled yet. - */ -typedef enum -{ - XSMP_STATE_IDLE, - XSMP_STATE_SAVE_YOURSELF, - XSMP_STATE_INTERACT_REQUEST, - XSMP_STATE_INTERACT, - XSMP_STATE_SAVE_YOURSELF_DONE, - XSMP_STATE_SHUTDOWN_CANCELLED, - XSMP_STATE_CONNECTION_CLOSED -} EggSMClientXSMPState; - -static const char *state_names[] = { - "idle", - "save-yourself", - "interact-request", - "interact", - "save-yourself-done", - "shutdown-cancelled", - "connection-closed" -}; - -#define EGG_SM_CLIENT_XSMP_STATE(xsmp) (state_names[(xsmp)->state]) - -struct _EggSMClientXSMP -{ - EggSMClient parent; - - SmcConn connection; - char *client_id; - - EggSMClientXSMPState state; - char **restart_command; - gboolean set_restart_command; - int restart_style; - - guint idle; - - /* Current SaveYourself state */ - guint expecting_initial_save_yourself : 1; - guint need_save_state : 1; - guint need_quit_requested : 1; - guint interact_errors : 1; - guint shutting_down : 1; - - /* Todo list */ - guint waiting_to_set_initial_properties : 1; - guint waiting_to_emit_quit : 1; - guint waiting_to_emit_quit_cancelled : 1; - guint waiting_to_save_myself : 1; - -}; - -struct _EggSMClientXSMPClass -{ - EggSMClientClass parent_class; - -}; - -static void sm_client_xsmp_startup (EggSMClient *client, - const char *client_id); -static void sm_client_xsmp_set_restart_command (EggSMClient *client, - int argc, - const char **argv); -static void sm_client_xsmp_will_quit (EggSMClient *client, - gboolean will_quit); -static gboolean sm_client_xsmp_end_session (EggSMClient *client, - EggSMClientEndStyle style, - gboolean request_confirmation); - -static void xsmp_save_yourself (SmcConn smc_conn, - SmPointer client_data, - int save_style, - Bool shutdown, - int interact_style, - Bool fast); -static void xsmp_die (SmcConn smc_conn, - SmPointer client_data); -static void xsmp_save_complete (SmcConn smc_conn, - SmPointer client_data); -static void xsmp_shutdown_cancelled (SmcConn smc_conn, - SmPointer client_data); -static void xsmp_interact (SmcConn smc_conn, - SmPointer client_data); - -static SmProp *array_prop (const char *name, - ...); -static SmProp *ptrarray_prop (const char *name, - GPtrArray *values); -static SmProp *string_prop (const char *name, - const char *value); -static SmProp *card8_prop (const char *name, - unsigned char value); - -static void set_properties (EggSMClientXSMP *xsmp, ...); -static void delete_properties (EggSMClientXSMP *xsmp, ...); - -static GPtrArray *generate_command (char **restart_command, - const char *client_id, - const char *state_file); - -static void save_state (EggSMClientXSMP *xsmp); -static void do_save_yourself (EggSMClientXSMP *xsmp); -static void update_pending_events (EggSMClientXSMP *xsmp); - -static void ice_init (void); -static gboolean process_ice_messages (IceConn ice_conn); -static void smc_error_handler (SmcConn smc_conn, - Bool swap, - int offending_minor_opcode, - unsigned long offending_sequence, - int error_class, - int severity, - SmPointer values); - -G_DEFINE_TYPE (EggSMClientXSMP, egg_sm_client_xsmp, EGG_TYPE_SM_CLIENT) - -static void -egg_sm_client_xsmp_init (EggSMClientXSMP *xsmp) -{ - xsmp->state = XSMP_STATE_CONNECTION_CLOSED; - xsmp->connection = NULL; - xsmp->restart_style = SmRestartIfRunning; -} - -static void -egg_sm_client_xsmp_class_init (EggSMClientXSMPClass *klass) -{ - EggSMClientClass *sm_client_class = EGG_SM_CLIENT_CLASS (klass); - - sm_client_class->startup = sm_client_xsmp_startup; - sm_client_class->set_restart_command = sm_client_xsmp_set_restart_command; - sm_client_class->will_quit = sm_client_xsmp_will_quit; - sm_client_class->end_session = sm_client_xsmp_end_session; -} - -EggSMClient * -egg_sm_client_xsmp_new (void) -{ - if (!g_getenv ("SESSION_MANAGER")) - return NULL; - - return g_object_new (EGG_TYPE_SM_CLIENT_XSMP, NULL); -} - -static gboolean -sm_client_xsmp_set_initial_properties (gpointer user_data) -{ - EggSMClientXSMP *xsmp = user_data; - EggDesktopFile *desktop_file; - GPtrArray *clone, *restart; - char pid_str[64]; - - if (xsmp->idle) - { - g_source_remove (xsmp->idle); - xsmp->idle = 0; - } - xsmp->waiting_to_set_initial_properties = FALSE; - - if (egg_sm_client_get_mode () == EGG_SM_CLIENT_MODE_NO_RESTART) - xsmp->restart_style = SmRestartNever; - - /* Parse info out of desktop file */ - desktop_file = egg_get_desktop_file (); - if (desktop_file) - { - GError *err = NULL; - char *cmdline, **argv; - int argc; - - if (xsmp->restart_style == SmRestartIfRunning) - { - if (egg_desktop_file_get_boolean (desktop_file, - "X-MATE-AutoRestart", NULL)) - xsmp->restart_style = SmRestartImmediately; - } - - if (!xsmp->set_restart_command) - { - cmdline = egg_desktop_file_parse_exec (desktop_file, NULL, &err); - if (cmdline && g_shell_parse_argv (cmdline, &argc, &argv, &err)) - { - egg_sm_client_set_restart_command (EGG_SM_CLIENT (xsmp), - argc, (const char **)argv); - g_strfreev (argv); - } - else - { - g_warning ("Could not parse Exec line in desktop file: %s", - err->message); - g_error_free (err); - } - g_free (cmdline); - } - } - - if (!xsmp->set_restart_command) - xsmp->restart_command = g_strsplit (g_get_prgname (), " ", -1); - - clone = generate_command (xsmp->restart_command, NULL, NULL); - restart = generate_command (xsmp->restart_command, xsmp->client_id, NULL); - - g_debug ("Setting initial properties"); - - /* Program, CloneCommand, RestartCommand, and UserID are required. - * ProcessID isn't required, but the SM may be able to do something - * useful with it. - */ - g_snprintf (pid_str, sizeof (pid_str), "%lu", (gulong) getpid ()); - set_properties (xsmp, - string_prop (SmProgram, g_get_prgname ()), - ptrarray_prop (SmCloneCommand, clone), - ptrarray_prop (SmRestartCommand, restart), - string_prop (SmUserID, g_get_user_name ()), - string_prop (SmProcessID, pid_str), - card8_prop (SmRestartStyleHint, xsmp->restart_style), - NULL); - g_ptr_array_free (clone, TRUE); - g_ptr_array_free (restart, TRUE); - - if (desktop_file) - { - set_properties (xsmp, - string_prop ("_GSM_DesktopFile", egg_desktop_file_get_source (desktop_file)), - NULL); - } - - update_pending_events (xsmp); - return FALSE; -} - -/* This gets called from two different places: xsmp_die() (when the - * server asks us to disconnect) and process_ice_messages() (when the - * server disconnects unexpectedly). - */ -static void -sm_client_xsmp_disconnect (EggSMClientXSMP *xsmp) -{ - SmcConn connection; - - if (!xsmp->connection) - return; - - g_debug ("Disconnecting"); - - connection = xsmp->connection; - xsmp->connection = NULL; - SmcCloseConnection (connection, 0, NULL); - xsmp->state = XSMP_STATE_CONNECTION_CLOSED; - - xsmp->waiting_to_save_myself = FALSE; - update_pending_events (xsmp); -} - -static void -sm_client_xsmp_startup (EggSMClient *client, - const char *client_id) -{ - EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client; - SmcCallbacks callbacks; - char *ret_client_id; - char error_string_ret[256]; - - xsmp->client_id = g_strdup (client_id); - - ice_init (); - SmcSetErrorHandler (smc_error_handler); - - callbacks.save_yourself.callback = xsmp_save_yourself; - callbacks.die.callback = xsmp_die; - callbacks.save_complete.callback = xsmp_save_complete; - callbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled; - - callbacks.save_yourself.client_data = xsmp; - callbacks.die.client_data = xsmp; - callbacks.save_complete.client_data = xsmp; - callbacks.shutdown_cancelled.client_data = xsmp; - - client_id = NULL; - error_string_ret[0] = '\0'; - xsmp->connection = - SmcOpenConnection (NULL, xsmp, SmProtoMajor, SmProtoMinor, - SmcSaveYourselfProcMask | SmcDieProcMask | - SmcSaveCompleteProcMask | - SmcShutdownCancelledProcMask, - &callbacks, - xsmp->client_id, &ret_client_id, - sizeof (error_string_ret), error_string_ret); - - if (!xsmp->connection) - { - g_warning ("Failed to connect to the session manager: %s\n", - error_string_ret[0] ? - error_string_ret : "no error message given"); - xsmp->state = XSMP_STATE_CONNECTION_CLOSED; - return; - } - - /* We expect a pointless initial SaveYourself if either (a) we - * didn't have an initial client ID, or (b) we DID have an initial - * client ID, but the server rejected it and gave us a new one. - */ - if (!xsmp->client_id || - (ret_client_id && strcmp (xsmp->client_id, ret_client_id) != 0)) - xsmp->expecting_initial_save_yourself = TRUE; - - if (ret_client_id) - { - g_free (xsmp->client_id); - xsmp->client_id = g_strdup (ret_client_id); - free (ret_client_id); - - gdk_x11_set_sm_client_id (xsmp->client_id); - - g_debug ("Got client ID \"%s\"", xsmp->client_id); - } - - xsmp->state = XSMP_STATE_IDLE; - - /* Do not set the initial properties until we reach the main loop, - * so that the application has a chance to call - * egg_set_desktop_file(). (This may also help the session manager - * have a better idea of when the application is fully up and - * running.) - */ - xsmp->waiting_to_set_initial_properties = TRUE; - xsmp->idle = g_idle_add (sm_client_xsmp_set_initial_properties, client); -} - -static void -sm_client_xsmp_set_restart_command (EggSMClient *client, - int argc, - const char **argv) -{ - EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client; - int i; - - g_strfreev (xsmp->restart_command); - - xsmp->restart_command = g_new (char *, argc + 1); - for (i = 0; i < argc; i++) - xsmp->restart_command[i] = g_strdup (argv[i]); - xsmp->restart_command[i] = NULL; - - xsmp->set_restart_command = TRUE; -} - -static void -sm_client_xsmp_will_quit (EggSMClient *client, - gboolean will_quit) -{ - EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client; - - if (xsmp->state == XSMP_STATE_CONNECTION_CLOSED) - { - /* The session manager has already exited! Schedule a quit - * signal. - */ - xsmp->waiting_to_emit_quit = TRUE; - update_pending_events (xsmp); - return; - } - else if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED) - { - /* We received a ShutdownCancelled message while the application - * was interacting; Schedule a quit_cancelled signal. - */ - xsmp->waiting_to_emit_quit_cancelled = TRUE; - update_pending_events (xsmp); - return; - } - - g_return_if_fail (xsmp->state == XSMP_STATE_INTERACT); - - g_debug ("Sending InteractDone(%s)", will_quit ? "False" : "True"); - SmcInteractDone (xsmp->connection, !will_quit); - - if (will_quit && xsmp->need_save_state) - save_state (xsmp); - - g_debug ("Sending SaveYourselfDone(%s)", will_quit ? "True" : "False"); - SmcSaveYourselfDone (xsmp->connection, will_quit); - xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE; -} - -static gboolean -sm_client_xsmp_end_session (EggSMClient *client, - EggSMClientEndStyle style, - gboolean request_confirmation) -{ - EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client; - int save_type; - - /* To end the session via XSMP, we have to send a - * SaveYourselfRequest. We aren't allowed to do that if anything - * else is going on, but we don't want to expose this fact to the - * application. So we do our best to patch things up here... - * - * In the worst case, this method might block for some length of - * time in process_ice_messages, but the only time that code path is - * honestly likely to get hit is if the application tries to end the - * session as the very first thing it does, in which case it - * probably won't actually block anyway. It's not worth gunking up - * the API to try to deal nicely with the other 0.01% of cases where - * this happens. - */ - - while (xsmp->state != XSMP_STATE_IDLE || - xsmp->expecting_initial_save_yourself) - { - /* If we're already shutting down, we don't need to do anything. */ - if (xsmp->shutting_down) - return TRUE; - - switch (xsmp->state) - { - case XSMP_STATE_CONNECTION_CLOSED: - return FALSE; - - case XSMP_STATE_SAVE_YOURSELF: - /* Trying to log out from the save_state callback? Whatever. - * Abort the save_state. - */ - SmcSaveYourselfDone (xsmp->connection, FALSE); - xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE; - break; - - case XSMP_STATE_INTERACT_REQUEST: - case XSMP_STATE_INTERACT: - case XSMP_STATE_SHUTDOWN_CANCELLED: - /* Already in a shutdown-related state, just ignore - * the new shutdown request... - */ - return TRUE; - - case XSMP_STATE_IDLE: - if (xsmp->waiting_to_set_initial_properties) - sm_client_xsmp_set_initial_properties (xsmp); - - if (!xsmp->expecting_initial_save_yourself) - break; - /* else fall through */ - - case XSMP_STATE_SAVE_YOURSELF_DONE: - /* We need to wait for some response from the server.*/ - process_ice_messages (SmcGetIceConnection (xsmp->connection)); - break; - - default: - /* Hm... shouldn't happen */ - return FALSE; - } - } - - /* xfce4-session will do the wrong thing if we pass SmSaveGlobal and - * the user chooses to save the session. But mate-session will do - * the wrong thing if we pass SmSaveBoth and the user chooses NOT to - * save the session... Sigh. - */ - if (!strcmp (SmcVendor (xsmp->connection), "xfce4-session")) - save_type = SmSaveBoth; - else - save_type = SmSaveGlobal; - - g_debug ("Sending SaveYourselfRequest(SmSaveGlobal, Shutdown, SmInteractStyleAny, %sFast)", request_confirmation ? "!" : ""); - SmcRequestSaveYourself (xsmp->connection, - save_type, - True, /* shutdown */ - SmInteractStyleAny, - !request_confirmation, /* fast */ - True /* global */); - return TRUE; -} - -static gboolean -idle_do_pending_events (gpointer data) -{ - EggSMClientXSMP *xsmp = data; - EggSMClient *client = data; - - xsmp->idle = 0; - - if (xsmp->waiting_to_emit_quit) - { - xsmp->waiting_to_emit_quit = FALSE; - egg_sm_client_quit (client); - goto out; - } - - if (xsmp->waiting_to_emit_quit_cancelled) - { - xsmp->waiting_to_emit_quit_cancelled = FALSE; - egg_sm_client_quit_cancelled (client); - xsmp->state = XSMP_STATE_IDLE; - } - - if (xsmp->waiting_to_save_myself) - { - xsmp->waiting_to_save_myself = FALSE; - do_save_yourself (xsmp); - } - - out: - return FALSE; -} - -static void -update_pending_events (EggSMClientXSMP *xsmp) -{ - gboolean want_idle = - xsmp->waiting_to_emit_quit || - xsmp->waiting_to_emit_quit_cancelled || - xsmp->waiting_to_save_myself; - - if (want_idle) - { - if (xsmp->idle == 0) - xsmp->idle = g_idle_add (idle_do_pending_events, xsmp); - } - else - { - if (xsmp->idle != 0) - g_source_remove (xsmp->idle); - xsmp->idle = 0; - } -} - -static void -fix_broken_state (EggSMClientXSMP *xsmp, const char *message, - gboolean send_interact_done, - gboolean send_save_yourself_done) -{ - g_warning ("Received XSMP %s message in state %s: client or server error", - message, EGG_SM_CLIENT_XSMP_STATE (xsmp)); - - /* Forget any pending SaveYourself plans we had */ - xsmp->waiting_to_save_myself = FALSE; - update_pending_events (xsmp); - - if (send_interact_done) - SmcInteractDone (xsmp->connection, False); - if (send_save_yourself_done) - SmcSaveYourselfDone (xsmp->connection, True); - - xsmp->state = send_save_yourself_done ? XSMP_STATE_SAVE_YOURSELF_DONE : XSMP_STATE_IDLE; -} - -/* SM callbacks */ - -static void -xsmp_save_yourself (SmcConn smc_conn, - SmPointer client_data, - int save_type, - Bool shutdown, - int interact_style, - Bool fast) -{ - EggSMClientXSMP *xsmp = client_data; - gboolean wants_quit_requested; - - g_debug ("Received SaveYourself(%s, %s, %s, %s) in state %s", - save_type == SmSaveLocal ? "SmSaveLocal" : - save_type == SmSaveGlobal ? "SmSaveGlobal" : "SmSaveBoth", - shutdown ? "Shutdown" : "!Shutdown", - interact_style == SmInteractStyleAny ? "SmInteractStyleAny" : - interact_style == SmInteractStyleErrors ? "SmInteractStyleErrors" : - "SmInteractStyleNone", fast ? "Fast" : "!Fast", - EGG_SM_CLIENT_XSMP_STATE (xsmp)); - - if (xsmp->state != XSMP_STATE_IDLE && - xsmp->state != XSMP_STATE_SHUTDOWN_CANCELLED) - { - fix_broken_state (xsmp, "SaveYourself", FALSE, TRUE); - return; - } - - if (xsmp->waiting_to_set_initial_properties) - sm_client_xsmp_set_initial_properties (xsmp); - - /* If this is the initial SaveYourself, ignore it; we've already set - * properties and there's no reason to actually save state too. - */ - if (xsmp->expecting_initial_save_yourself) - { - xsmp->expecting_initial_save_yourself = FALSE; - - if (save_type == SmSaveLocal && - interact_style == SmInteractStyleNone && - !shutdown && !fast) - { - g_debug ("Sending SaveYourselfDone(True) for initial SaveYourself"); - SmcSaveYourselfDone (xsmp->connection, True); - /* As explained in the comment at the end of - * do_save_yourself(), SAVE_YOURSELF_DONE is the correct - * state here, not IDLE. - */ - xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE; - return; - } - else - g_warning ("First SaveYourself was not the expected one!"); - } - - /* Even ignoring the "fast" flag completely, there are still 18 - * different combinations of save_type, shutdown and interact_style. - * We interpret them as follows: - * - * Type Shutdown Interact Interpretation - * G F A/E/N do nothing (1) - * G T N do nothing (1)* - * G T A/E quit_requested (2) - * L/B F A/E/N save_state (3) - * L/B T N save_state (3)* - * L/B T A/E quit_requested, then save_state (4) - * - * 1. Do nothing, because the SM asked us to do something - * uninteresting (save open files, but then don't quit - * afterward) or rude (save open files without asking the user - * for confirmation). - * - * 2. Request interaction and then emit ::quit_requested. This - * perhaps isn't quite correct for the SmInteractStyleErrors - * case, but we don't care. - * - * 3. Emit ::save_state. The SmSaveBoth SaveYourselfs in these - * rows essentially get demoted to SmSaveLocal, because their - * Global halves correspond to "do nothing". - * - * 4. Request interaction, emit ::quit_requested, and then emit - * ::save_state after interacting. This is the SmSaveBoth - * equivalent of #2, but we also promote SmSaveLocal shutdown - * SaveYourselfs to SmSaveBoth here, because we want to give - * the user a chance to save open files before quitting. - * - * (* It would be nice if we could do something useful when the - * session manager sends a SaveYourself with shutdown True and - * SmInteractStyleNone. But we can't, so we just pretend it didn't - * even tell us it was shutting down. The docs for ::quit mention - * that it might not always be preceded by ::quit_requested.) - */ - - /* As an optimization, we don't actually request interaction and - * emit ::quit_requested if the application isn't listening to the - * signal. - */ - wants_quit_requested = g_signal_has_handler_pending (xsmp, g_signal_lookup ("quit_requested", EGG_TYPE_SM_CLIENT), 0, FALSE); - - xsmp->need_save_state = (save_type != SmSaveGlobal); - xsmp->need_quit_requested = (shutdown && wants_quit_requested && - interact_style != SmInteractStyleNone); - xsmp->interact_errors = (interact_style == SmInteractStyleErrors); - - xsmp->shutting_down = shutdown; - - do_save_yourself (xsmp); -} - -static void -do_save_yourself (EggSMClientXSMP *xsmp) -{ - if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED) - { - /* The SM cancelled a previous SaveYourself, but we haven't yet - * had a chance to tell the application, so we can't start - * processing this SaveYourself yet. - */ - xsmp->waiting_to_save_myself = TRUE; - update_pending_events (xsmp); - return; - } - - if (xsmp->need_quit_requested) - { - xsmp->state = XSMP_STATE_INTERACT_REQUEST; - - g_debug ("Sending InteractRequest(%s)", - xsmp->interact_errors ? "Error" : "Normal"); - SmcInteractRequest (xsmp->connection, - xsmp->interact_errors ? SmDialogError : SmDialogNormal, - xsmp_interact, - xsmp); - return; - } - - if (xsmp->need_save_state) - { - save_state (xsmp); - - /* Though unlikely, the client could have been disconnected - * while the application was saving its state. - */ - if (!xsmp->connection) - return; - } - - g_debug ("Sending SaveYourselfDone(True)"); - SmcSaveYourselfDone (xsmp->connection, True); - - /* The client state diagram in the XSMP spec says that after a - * non-shutdown SaveYourself, we go directly back to "idle". But - * everything else in both the XSMP spec and the libSM docs - * disagrees. - */ - xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE; -} - -static void -save_state (EggSMClientXSMP *xsmp) -{ - GKeyFile *state_file; - char *state_file_path, *data; - EggDesktopFile *desktop_file; - GPtrArray *restart; - int offset, fd; - - /* We set xsmp->state before emitting save_state, but our caller is - * responsible for setting it back afterward. - */ - xsmp->state = XSMP_STATE_SAVE_YOURSELF; - - state_file = egg_sm_client_save_state ((EggSMClient *)xsmp); - if (!state_file) - { - restart = generate_command (xsmp->restart_command, xsmp->client_id, NULL); - set_properties (xsmp, - ptrarray_prop (SmRestartCommand, restart), - NULL); - g_ptr_array_free (restart, TRUE); - delete_properties (xsmp, SmDiscardCommand, NULL); - return; - } - - desktop_file = egg_get_desktop_file (); - if (desktop_file) - { - GKeyFile *merged_file; - char *desktop_file_path; - - merged_file = g_key_file_new (); - desktop_file_path = - g_filename_from_uri (egg_desktop_file_get_source (desktop_file), - NULL, NULL); - if (desktop_file_path && - g_key_file_load_from_file (merged_file, desktop_file_path, - G_KEY_FILE_KEEP_COMMENTS | - G_KEY_FILE_KEEP_TRANSLATIONS, NULL)) - { - guint g, k, i; - char **groups, **keys, *value, *exec; - - groups = g_key_file_get_groups (state_file, NULL); - for (g = 0; groups[g]; g++) - { - keys = g_key_file_get_keys (state_file, groups[g], NULL, NULL); - for (k = 0; keys[k]; k++) - { - value = g_key_file_get_value (state_file, groups[g], - keys[k], NULL); - if (value) - { - g_key_file_set_value (merged_file, groups[g], - keys[k], value); - g_free (value); - } - } - g_strfreev (keys); - } - g_strfreev (groups); - - g_key_file_free (state_file); - state_file = merged_file; - - /* Update Exec key using "--sm-client-state-file %k" */ - restart = generate_command (xsmp->restart_command, - NULL, "%k"); - for (i = 0; i < restart->len; i++) - restart->pdata[i] = g_shell_quote (restart->pdata[i]); - g_ptr_array_add (restart, NULL); - exec = g_strjoinv (" ", (char **)restart->pdata); - g_strfreev ((char **)restart->pdata); - g_ptr_array_free (restart, FALSE); - - g_key_file_set_string (state_file, EGG_DESKTOP_FILE_GROUP, - EGG_DESKTOP_FILE_KEY_EXEC, - exec); - g_free (exec); - } - else - desktop_file = NULL; - - g_free (desktop_file_path); - } - - /* Now write state_file to disk. (We can't use mktemp(), because - * that requires the filename to end with "XXXXXX", and we want - * it to end with ".desktop".) - */ - - data = g_key_file_to_data (state_file, NULL, NULL); - g_key_file_free (state_file); - - offset = 0; - while (1) - { - state_file_path = g_strdup_printf ("%s%csession-state%c%s-%ld.%s", - g_get_user_config_dir (), - G_DIR_SEPARATOR, G_DIR_SEPARATOR, - g_get_prgname (), - (long)time (NULL) + offset, - desktop_file ? "desktop" : "state"); - - fd = open (state_file_path, O_WRONLY | O_CREAT | O_EXCL, 0644); - if (fd == -1) - { - if (errno == EEXIST) - { - offset++; - g_free (state_file_path); - continue; - } - else if (errno == ENOTDIR || errno == ENOENT) - { - char *sep = strrchr (state_file_path, G_DIR_SEPARATOR); - - *sep = '\0'; - if (g_mkdir_with_parents (state_file_path, 0755) != 0) - { - g_warning ("Could not create directory '%s'", - state_file_path); - g_free (state_file_path); - state_file_path = NULL; - break; - } - - continue; - } - - g_warning ("Could not create file '%s': %s", - state_file_path, g_strerror (errno)); - g_free (state_file_path); - state_file_path = NULL; - break; - } - - close (fd); - g_file_set_contents (state_file_path, data, -1, NULL); - break; - } - g_free (data); - - restart = generate_command (xsmp->restart_command, xsmp->client_id, - state_file_path); - set_properties (xsmp, - ptrarray_prop (SmRestartCommand, restart), - NULL); - g_ptr_array_free (restart, TRUE); - - if (state_file_path) - { - set_properties (xsmp, - array_prop (SmDiscardCommand, - "/bin/rm", "-rf", state_file_path, - NULL), - NULL); - g_free (state_file_path); - } -} - -static void -xsmp_interact (SmcConn smc_conn, - SmPointer client_data) -{ - EggSMClientXSMP *xsmp = client_data; - EggSMClient *client = client_data; - - g_debug ("Received Interact message in state %s", - EGG_SM_CLIENT_XSMP_STATE (xsmp)); - - if (xsmp->state != XSMP_STATE_INTERACT_REQUEST) - { - fix_broken_state (xsmp, "Interact", TRUE, TRUE); - return; - } - - xsmp->state = XSMP_STATE_INTERACT; - egg_sm_client_quit_requested (client); -} - -static void -xsmp_die (SmcConn smc_conn, - SmPointer client_data) -{ - EggSMClientXSMP *xsmp = client_data; - EggSMClient *client = client_data; - - g_debug ("Received Die message in state %s", - EGG_SM_CLIENT_XSMP_STATE (xsmp)); - - sm_client_xsmp_disconnect (xsmp); - egg_sm_client_quit (client); -} - -static void -xsmp_save_complete (SmcConn smc_conn, - SmPointer client_data) -{ - EggSMClientXSMP *xsmp = client_data; - - g_debug ("Received SaveComplete message in state %s", - EGG_SM_CLIENT_XSMP_STATE (xsmp)); - - if (xsmp->state == XSMP_STATE_SAVE_YOURSELF_DONE) - xsmp->state = XSMP_STATE_IDLE; - else - fix_broken_state (xsmp, "SaveComplete", FALSE, FALSE); -} - -static void -xsmp_shutdown_cancelled (SmcConn smc_conn, - SmPointer client_data) -{ - EggSMClientXSMP *xsmp = client_data; - EggSMClient *client = client_data; - - g_debug ("Received ShutdownCancelled message in state %s", - EGG_SM_CLIENT_XSMP_STATE (xsmp)); - - xsmp->shutting_down = FALSE; - - if (xsmp->state == XSMP_STATE_SAVE_YOURSELF_DONE) - { - /* We've finished interacting and now the SM has agreed to - * cancel the shutdown. - */ - xsmp->state = XSMP_STATE_IDLE; - egg_sm_client_quit_cancelled (client); - } - else if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED) - { - /* Hm... ok, so we got a shutdown SaveYourself, which got - * cancelled, but the application was still interacting, so we - * didn't tell it yet, and then *another* SaveYourself arrived, - * which we must still be waiting to tell the app about, except - * that now that SaveYourself has been cancelled too! Dizzy yet? - */ - xsmp->waiting_to_save_myself = FALSE; - update_pending_events (xsmp); - } - else - { - g_debug ("Sending SaveYourselfDone(False)"); - SmcSaveYourselfDone (xsmp->connection, False); - - if (xsmp->state == XSMP_STATE_INTERACT) - { - /* The application is currently interacting, so we can't - * tell it about the cancellation yet; we will wait until - * after it calls egg_sm_client_will_quit(). - */ - xsmp->state = XSMP_STATE_SHUTDOWN_CANCELLED; - } - else - { - /* The shutdown was cancelled before the application got a - * chance to interact. - */ - xsmp->state = XSMP_STATE_IDLE; - } - } -} - -/* Utilities */ - -/* Create a restart/clone/Exec command based on @restart_command. - * If @client_id is non-%NULL, add "--sm-client-id @client_id". - * If @state_file is non-%NULL, add "--sm-client-state-file @state_file". - * - * None of the input strings are g_strdup()ed; the caller must keep - * them around until it is done with the returned GPtrArray, and must - * then free the array, but not its contents. - */ -static GPtrArray * -generate_command (char **restart_command, const char *client_id, - const char *state_file) -{ - GPtrArray *cmd; - int i; - - cmd = g_ptr_array_new (); - g_ptr_array_add (cmd, restart_command[0]); - - if (client_id) - { - g_ptr_array_add (cmd, (char *)"--sm-client-id"); - g_ptr_array_add (cmd, (char *)client_id); - } - - if (state_file) - { - g_ptr_array_add (cmd, (char *)"--sm-client-state-file"); - g_ptr_array_add (cmd, (char *)state_file); - } - - for (i = 1; restart_command[i]; i++) - g_ptr_array_add (cmd, restart_command[i]); - - return cmd; -} - -/* Takes a NULL-terminated list of SmProp * values, created by - * array_prop, ptrarray_prop, string_prop, card8_prop, sets them, and - * frees them. - */ -static void -set_properties (EggSMClientXSMP *xsmp, ...) -{ - GPtrArray *props; - SmProp *prop; - va_list ap; - guint i; - - props = g_ptr_array_new (); - - va_start (ap, xsmp); - while ((prop = va_arg (ap, SmProp *))) - g_ptr_array_add (props, prop); - va_end (ap); - - if (xsmp->connection) - { - SmcSetProperties (xsmp->connection, props->len, - (SmProp **)props->pdata); - } - - for (i = 0; i < props->len; i++) - { - prop = props->pdata[i]; - g_free (prop->vals); - g_free (prop); - } - g_ptr_array_free (props, TRUE); -} - -/* Takes a NULL-terminated list of property names and deletes them. */ -static void -delete_properties (EggSMClientXSMP *xsmp, ...) -{ - GPtrArray *props; - char *prop; - va_list ap; - - if (!xsmp->connection) - return; - - props = g_ptr_array_new (); - - va_start (ap, xsmp); - while ((prop = va_arg (ap, char *))) - g_ptr_array_add (props, prop); - va_end (ap); - - SmcDeleteProperties (xsmp->connection, props->len, - (char **)props->pdata); - - g_ptr_array_free (props, TRUE); -} - -/* Takes an array of strings and creates a LISTofARRAY8 property. The - * strings are neither dupped nor freed; they need to remain valid - * until you're done with the SmProp. - */ -static SmProp * -array_prop (const char *name, ...) -{ - SmProp *prop; - SmPropValue pv; - GArray *vals; - char *value; - va_list ap; - - prop = g_new (SmProp, 1); - prop->name = (char *)name; - prop->type = (char *)SmLISTofARRAY8; - - vals = g_array_new (FALSE, FALSE, sizeof (SmPropValue)); - - va_start (ap, name); - while ((value = va_arg (ap, char *))) - { - pv.length = strlen (value); - pv.value = value; - g_array_append_val (vals, pv); - } - va_end (ap); - - prop->num_vals = vals->len; - prop->vals = (SmPropValue *)vals->data; - - g_array_free (vals, FALSE); - - return prop; -} - -/* Takes a GPtrArray of strings and creates a LISTofARRAY8 property. - * The array contents are neither dupped nor freed; they need to - * remain valid until you're done with the SmProp. - */ -static SmProp * -ptrarray_prop (const char *name, GPtrArray *values) -{ - SmProp *prop; - SmPropValue pv; - GArray *vals; - guint i; - - prop = g_new (SmProp, 1); - prop->name = (char *)name; - prop->type = (char *)SmLISTofARRAY8; - - vals = g_array_new (FALSE, FALSE, sizeof (SmPropValue)); - - for (i = 0; i < values->len; i++) - { - pv.length = strlen (values->pdata[i]); - pv.value = values->pdata[i]; - g_array_append_val (vals, pv); - } - - prop->num_vals = vals->len; - prop->vals = (SmPropValue *)vals->data; - - g_array_free (vals, FALSE); - - return prop; -} - -/* Takes a string and creates an ARRAY8 property. The string is - * neither dupped nor freed; it needs to remain valid until you're - * done with the SmProp. - */ -static SmProp * -string_prop (const char *name, const char *value) -{ - SmProp *prop; - - prop = g_new (SmProp, 1); - prop->name = (char *)name; - prop->type = (char *)SmARRAY8; - - prop->num_vals = 1; - prop->vals = g_new (SmPropValue, 1); - - prop->vals[0].length = strlen (value); - prop->vals[0].value = (char *)value; - - return prop; -} - -/* Takes a char and creates a CARD8 property. */ -static SmProp * -card8_prop (const char *name, unsigned char value) -{ - SmProp *prop; - char *card8val; - - /* To avoid having to allocate and free prop->vals[0], we cheat and - * make vals a 2-element-long array and then use the second element - * to store value. - */ - - prop = g_new (SmProp, 1); - prop->name = (char *)name; - prop->type = (char *)SmCARD8; - - prop->num_vals = 1; - prop->vals = g_new (SmPropValue, 2); - card8val = (char *)(&prop->vals[1]); - card8val[0] = value; - - prop->vals[0].length = 1; - prop->vals[0].value = card8val; - - return prop; -} - -/* ICE code. This makes no effort to play nice with anyone else trying - * to use libICE. Fortunately, no one uses libICE for anything other - * than SM. (DCOP uses ICE, but it has its own private copy of - * libICE.) - * - * When this moves to gtk, it will need to be cleverer, to avoid - * tripping over old apps that use MateClient or that use libSM - * directly. - */ - -#include -#include - -static void ice_error_handler (IceConn ice_conn, - Bool swap, - int offending_minor_opcode, - unsigned long offending_sequence, - int error_class, - int severity, - IcePointer values); -static void ice_io_error_handler (IceConn ice_conn); -static void ice_connection_watch (IceConn ice_conn, - IcePointer client_data, - Bool opening, - IcePointer *watch_data); - -static void -ice_init (void) -{ - IceSetIOErrorHandler (ice_io_error_handler); - IceSetErrorHandler (ice_error_handler); - IceAddConnectionWatch (ice_connection_watch, NULL); -} - -static gboolean -process_ice_messages (IceConn ice_conn) -{ - IceProcessMessagesStatus status; - - status = IceProcessMessages (ice_conn, NULL, NULL); - - switch (status) - { - case IceProcessMessagesSuccess: - return TRUE; - - case IceProcessMessagesIOError: - sm_client_xsmp_disconnect (IceGetConnectionContext (ice_conn)); - return FALSE; - - case IceProcessMessagesConnectionClosed: - return FALSE; - - default: - g_assert_not_reached (); - } -} - -static gboolean -ice_iochannel_watch (GIOChannel *channel, - GIOCondition condition, - gpointer client_data) -{ - return process_ice_messages (client_data); -} - -static void -ice_connection_watch (IceConn ice_conn, - IcePointer client_data, - Bool opening, - IcePointer *watch_data) -{ - guint watch_id; - - if (opening) - { - GIOChannel *channel; - int fd = IceConnectionNumber (ice_conn); - - fcntl (fd, F_SETFD, fcntl (fd, F_GETFD, 0) | FD_CLOEXEC); - channel = g_io_channel_unix_new (fd); - watch_id = g_io_add_watch (channel, G_IO_IN | G_IO_ERR, - ice_iochannel_watch, ice_conn); - g_io_channel_unref (channel); - - *watch_data = GUINT_TO_POINTER (watch_id); - } - else - { - watch_id = GPOINTER_TO_UINT (*watch_data); - g_source_remove (watch_id); - } -} - -static void -ice_error_handler (IceConn ice_conn, - Bool swap, - int offending_minor_opcode, - unsigned long offending_sequence, - int error_class, - int severity, - IcePointer values) -{ - /* Do nothing */ -} - -static void -ice_io_error_handler (IceConn ice_conn) -{ - /* Do nothing */ -} - -static void -smc_error_handler (SmcConn smc_conn, - Bool swap, - int offending_minor_opcode, - unsigned long offending_sequence, - int error_class, - int severity, - SmPointer values) -{ - /* Do nothing */ -} diff --git a/xed/smclient/eggsmclient.c b/xed/smclient/eggsmclient.c deleted file mode 100644 index 4fc64da..0000000 --- a/xed/smclient/eggsmclient.c +++ /dev/null @@ -1,573 +0,0 @@ -/* - * Copyright (C) 2007 Novell, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * 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 - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "config.h" - -#include -#include - -#include "eggsmclient.h" -#include "eggsmclient-private.h" - -static void egg_sm_client_debug_handler (const char *log_domain, - GLogLevelFlags log_level, - const char *message, - gpointer user_data); - -enum { - SAVE_STATE, - QUIT_REQUESTED, - QUIT_CANCELLED, - QUIT, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -struct _EggSMClientPrivate { - GKeyFile *state_file; -}; - -#define EGG_SM_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), EGG_TYPE_SM_CLIENT, EggSMClientPrivate)) - -G_DEFINE_TYPE (EggSMClient, egg_sm_client, G_TYPE_OBJECT) - -static EggSMClient *global_client; -static EggSMClientMode global_client_mode = EGG_SM_CLIENT_MODE_NORMAL; - -static void -egg_sm_client_init (EggSMClient *client) -{ - ; -} - -static void -egg_sm_client_class_init (EggSMClientClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (EggSMClientPrivate)); - - /** - * EggSMClient::save_state: - * @client: the client - * @state_file: a #GKeyFile to save state information into - * - * Emitted when the session manager has requested that the - * application save information about its current state. The - * application should save its state into @state_file, and then the - * session manager may then restart the application in a future - * session and tell it to initialize itself from that state. - * - * You should not save any data into @state_file's "start group" - * (ie, the %NULL group). Instead, applications should save their - * data into groups with names that start with the application name, - * and libraries that connect to this signal should save their data - * into groups with names that start with the library name. - * - * Alternatively, rather than (or in addition to) using @state_file, - * the application can save its state by calling - * egg_sm_client_set_restart_command() during the processing of this - * signal (eg, to include a list of files to open). - **/ - signals[SAVE_STATE] = - g_signal_new ("save_state", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EggSMClientClass, save_state), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, - 1, G_TYPE_POINTER); - - /** - * EggSMClient::quit_requested: - * @client: the client - * - * Emitted when the session manager requests that the application - * exit (generally because the user is logging out). The application - * should decide whether or not it is willing to quit (perhaps after - * asking the user what to do with documents that have unsaved - * changes) and then call egg_sm_client_will_quit(), passing %TRUE - * or %FALSE to give its answer to the session manager. (It does not - * need to give an answer before returning from the signal handler; - * it can interact with the user asynchronously and then give its - * answer later on.) If the application does not connect to this - * signal, then #EggSMClient will automatically return %TRUE on its - * behalf. - * - * The application should not save its session state as part of - * handling this signal; if the user has requested that the session - * be saved when logging out, then ::save_state will be emitted - * separately. - * - * If the application agrees to quit, it should then wait for either - * the ::quit_cancelled or ::quit signals to be emitted. - **/ - signals[QUIT_REQUESTED] = - g_signal_new ("quit_requested", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EggSMClientClass, quit_requested), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - /** - * EggSMClient::quit_cancelled: - * @client: the client - * - * Emitted when the session manager decides to cancel a logout after - * the application has already agreed to quit. After receiving this - * signal, the application can go back to what it was doing before - * receiving the ::quit_requested signal. - **/ - signals[QUIT_CANCELLED] = - g_signal_new ("quit_cancelled", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EggSMClientClass, quit_cancelled), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - /** - * EggSMClient::quit: - * @client: the client - * - * Emitted when the session manager wants the application to quit - * (generally because the user is logging out). The application - * should exit as soon as possible after receiving this signal; if - * it does not, the session manager may choose to forcibly kill it. - * - * Normally a GUI application would only be sent a ::quit if it - * agreed to quit in response to a ::quit_requested signal. However, - * this is not guaranteed; in some situations the session manager - * may decide to end the session without giving applications a - * chance to object. - **/ - signals[QUIT] = - g_signal_new ("quit", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EggSMClientClass, quit), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); -} - -static gboolean sm_client_disable = FALSE; -static char *sm_client_state_file = NULL; -static char *sm_client_id = NULL; -static char *sm_config_prefix = NULL; - -static gboolean -sm_client_post_parse_func (GOptionContext *context, - GOptionGroup *group, - gpointer data, - GError **error) -{ - EggSMClient *client = egg_sm_client_get (); - - if (sm_client_id == NULL) - { - const gchar *desktop_autostart_id; - - desktop_autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID"); - - if (desktop_autostart_id != NULL) - sm_client_id = g_strdup (desktop_autostart_id); - } - - /* Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to - * use the same client id. */ - g_unsetenv ("DESKTOP_AUTOSTART_ID"); - - if (EGG_SM_CLIENT_GET_CLASS (client)->startup) - EGG_SM_CLIENT_GET_CLASS (client)->startup (client, sm_client_id); - return TRUE; -} - -/** - * egg_sm_client_get_option_group: - * - * Creates a %GOptionGroup containing the session-management-related - * options. You should add this group to the application's - * %GOptionContext if you want to use #EggSMClient. - * - * Return value: the %GOptionGroup - **/ -GOptionGroup * -egg_sm_client_get_option_group (void) -{ - const GOptionEntry entries[] = { - { "sm-client-disable", 0, 0, - G_OPTION_ARG_NONE, &sm_client_disable, - N_("Disable connection to session manager"), NULL }, - { "sm-client-state-file", 0, 0, - G_OPTION_ARG_FILENAME, &sm_client_state_file, - N_("Specify file containing saved configuration"), N_("FILE") }, - { "sm-client-id", 0, 0, - G_OPTION_ARG_STRING, &sm_client_id, - N_("Specify session management ID"), N_("ID") }, - /* MateClient compatibility option */ - { "sm-disable", 0, G_OPTION_FLAG_HIDDEN, - G_OPTION_ARG_NONE, &sm_client_disable, - NULL, NULL }, - /* MateClient compatibility option. This is a dummy option that only - * exists so that sessions saved by apps with MateClient can be restored - * later when they've switched to EggSMClient. See bug #575308. - */ - { "sm-config-prefix", 0, G_OPTION_FLAG_HIDDEN, - G_OPTION_ARG_STRING, &sm_config_prefix, - NULL, NULL }, - { NULL } - }; - GOptionGroup *group; - - /* Use our own debug handler for the "EggSMClient" domain. */ - g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, - egg_sm_client_debug_handler, NULL); - - group = g_option_group_new ("sm-client", - _("Session management options:"), - _("Show session management options"), - NULL, NULL); - g_option_group_add_entries (group, entries); - g_option_group_set_parse_hooks (group, NULL, sm_client_post_parse_func); - - return group; -} - -/** - * egg_sm_client_set_mode: - * @mode: an #EggSMClient mode - * - * Sets the "mode" of #EggSMClient as follows: - * - * %EGG_SM_CLIENT_MODE_DISABLED: Session management is completely - * disabled. The application will not even connect to the session - * manager. (egg_sm_client_get() will still return an #EggSMClient, - * but it will just be a dummy object.) - * - * %EGG_SM_CLIENT_MODE_NO_RESTART: The application will connect to - * the session manager (and thus will receive notification when the - * user is logging out, etc), but will request to not be - * automatically restarted with saved state in future sessions. - * - * %EGG_SM_CLIENT_MODE_NORMAL: The default. #EggSMCLient will - * function normally. - * - * This must be called before the application's main loop begins. - **/ -void -egg_sm_client_set_mode (EggSMClientMode mode) -{ - global_client_mode = mode; -} - -/** - * egg_sm_client_get_mode: - * - * Gets the global #EggSMClientMode. See egg_sm_client_set_mode() - * for details. - * - * Return value: the global #EggSMClientMode - **/ -EggSMClientMode -egg_sm_client_get_mode (void) -{ - return global_client_mode; -} - -/** - * egg_sm_client_get: - * - * Returns the master #EggSMClient for the application. - * - * On platforms that support saved sessions (ie, POSIX/X11), the - * application will only request to be restarted by the session - * manager if you call egg_set_desktop_file() to set an application - * desktop file. In particular, if the desktop file contains the key - * "X - * - * Return value: the master #EggSMClient. - **/ -EggSMClient * -egg_sm_client_get (void) -{ - if (!global_client) - { - if (global_client_mode != EGG_SM_CLIENT_MODE_DISABLED && - !sm_client_disable) - { - global_client = egg_sm_client_xsmp_new (); - } - - /* Fallback: create a dummy client, so that callers don't have - * to worry about a %NULL return value. - */ - if (!global_client) - global_client = g_object_new (EGG_TYPE_SM_CLIENT, NULL); - } - - return global_client; -} - -/** - * egg_sm_client_is_resumed: - * @client: the client - * - * Checks whether or not the current session has been resumed from - * a previous saved session. If so, the application should call - * egg_sm_client_get_state_file() and restore its state from the - * returned #GKeyFile. - * - * Return value: %TRUE if the session has been resumed - **/ -gboolean -egg_sm_client_is_resumed (EggSMClient *client) -{ - g_return_val_if_fail (client == global_client, FALSE); - - return sm_client_state_file != NULL; -} - -/** - * egg_sm_client_get_state_file: - * @client: the client - * - * If the application was resumed by the session manager, this will - * return the #GKeyFile containing its state from the previous - * session. - * - * Note that other libraries and #EggSMClient itself may also store - * state in the key file, so if you call egg_sm_client_get_groups(), - * on it, the return value will likely include groups that you did not - * put there yourself. (It is also not guaranteed that the first - * group created by the application will still be the "start group" - * when it is resumed.) - * - * Return value: the #GKeyFile containing the application's earlier - * state, or %NULL on error. You should not free this key file; it - * is owned by @client. - **/ -GKeyFile * -egg_sm_client_get_state_file (EggSMClient *client) -{ - EggSMClientPrivate *priv = EGG_SM_CLIENT_GET_PRIVATE (client); - char *state_file_path; - GError *err = NULL; - - g_return_val_if_fail (client == global_client, NULL); - - if (!sm_client_state_file) - return NULL; - if (priv->state_file) - return priv->state_file; - - if (!strncmp (sm_client_state_file, "file://", 7)) - state_file_path = g_filename_from_uri (sm_client_state_file, NULL, NULL); - else - state_file_path = g_strdup (sm_client_state_file); - - priv->state_file = g_key_file_new (); - if (!g_key_file_load_from_file (priv->state_file, state_file_path, 0, &err)) - { - g_warning ("Could not load SM state file '%s': %s", - sm_client_state_file, err->message); - g_clear_error (&err); - g_key_file_free (priv->state_file); - priv->state_file = NULL; - } - - g_free (state_file_path); - return priv->state_file; -} - -/** - * egg_sm_client_set_restart_command: - * @client: the client - * @argc: the length of @argv - * @argv: argument vector - * - * Sets the command used to restart @client if it does not have a - * .desktop file that can be used to find its restart command. - * - * This can also be used when handling the ::save_state signal, to - * save the current state via an updated command line. (Eg, providing - * a list of filenames to open when the application is resumed.) - **/ -void -egg_sm_client_set_restart_command (EggSMClient *client, - int argc, - const char **argv) -{ - g_return_if_fail (EGG_IS_SM_CLIENT (client)); - - if (EGG_SM_CLIENT_GET_CLASS (client)->set_restart_command) - EGG_SM_CLIENT_GET_CLASS (client)->set_restart_command (client, argc, argv); -} - -/** - * egg_sm_client_will_quit: - * @client: the client - * @will_quit: whether or not the application is willing to quit - * - * This MUST be called in response to the ::quit_requested signal, to - * indicate whether or not the application is willing to quit. The - * application may call it either directly from the signal handler, or - * at some later point (eg, after asynchronously interacting with the - * user). - * - * If the application does not connect to ::quit_requested, - * #EggSMClient will call this method on its behalf (passing %TRUE - * for @will_quit). - * - * After calling this method, the application should wait to receive - * either ::quit_cancelled or ::quit. - **/ -void -egg_sm_client_will_quit (EggSMClient *client, - gboolean will_quit) -{ - g_return_if_fail (EGG_IS_SM_CLIENT (client)); - - if (EGG_SM_CLIENT_GET_CLASS (client)->will_quit) - EGG_SM_CLIENT_GET_CLASS (client)->will_quit (client, will_quit); -} - -/** - * egg_sm_client_end_session: - * @style: a hint at how to end the session - * @request_confirmation: whether or not the user should get a chance - * to confirm the action - * - * Requests that the session manager end the current session. @style - * indicates how the session should be ended, and - * @request_confirmation indicates whether or not the user should be - * given a chance to confirm the logout/reboot/shutdown. Both of these - * flags are merely hints though; the session manager may choose to - * ignore them. - * - * Return value: %TRUE if the request was sent; %FALSE if it could not - * be (eg, because it could not connect to the session manager). - **/ -gboolean -egg_sm_client_end_session (EggSMClientEndStyle style, - gboolean request_confirmation) -{ - EggSMClient *client = egg_sm_client_get (); - - g_return_val_if_fail (EGG_IS_SM_CLIENT (client), FALSE); - - if (EGG_SM_CLIENT_GET_CLASS (client)->end_session) - { - return EGG_SM_CLIENT_GET_CLASS (client)->end_session (client, style, - request_confirmation); - } - else - return FALSE; -} - -/* Signal-emitting callbacks from platform-specific code */ - -GKeyFile * -egg_sm_client_save_state (EggSMClient *client) -{ - GKeyFile *state_file; - char *group; - - g_return_val_if_fail (client == global_client, NULL); - - state_file = g_key_file_new (); - - g_debug ("Emitting save_state"); - g_signal_emit (client, signals[SAVE_STATE], 0, state_file); - g_debug ("Done emitting save_state"); - - group = g_key_file_get_start_group (state_file); - if (group) - { - g_free (group); - return state_file; - } - else - { - g_key_file_free (state_file); - return NULL; - } -} - -void -egg_sm_client_quit_requested (EggSMClient *client) -{ - g_return_if_fail (client == global_client); - - if (!g_signal_has_handler_pending (client, signals[QUIT_REQUESTED], 0, FALSE)) - { - g_debug ("Not emitting quit_requested because no one is listening"); - egg_sm_client_will_quit (client, TRUE); - return; - } - - g_debug ("Emitting quit_requested"); - g_signal_emit (client, signals[QUIT_REQUESTED], 0); - g_debug ("Done emitting quit_requested"); -} - -void -egg_sm_client_quit_cancelled (EggSMClient *client) -{ - g_return_if_fail (client == global_client); - - g_debug ("Emitting quit_cancelled"); - g_signal_emit (client, signals[QUIT_CANCELLED], 0); - g_debug ("Done emitting quit_cancelled"); -} - -void -egg_sm_client_quit (EggSMClient *client) -{ - g_return_if_fail (client == global_client); - - g_debug ("Emitting quit"); - g_signal_emit (client, signals[QUIT], 0); - g_debug ("Done emitting quit"); - - /* FIXME: should we just call gtk_main_quit() here? */ -} - -static void -egg_sm_client_debug_handler (const char *log_domain, - GLogLevelFlags log_level, - const char *message, - gpointer user_data) -{ - static int debug = -1; - - if (debug < 0) - debug = (g_getenv ("EGG_SM_CLIENT_DEBUG") != NULL); - - if (debug) - g_log_default_handler (log_domain, log_level, message, NULL); -} diff --git a/xed/smclient/eggsmclient.h b/xed/smclient/eggsmclient.h deleted file mode 100644 index d87f670..0000000 --- a/xed/smclient/eggsmclient.h +++ /dev/null @@ -1,117 +0,0 @@ -/* eggsmclient.h - * Copyright (C) 2007 Novell, Inc. - * - * 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 of the License, or (at your option) any later version. - * - * 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 - * Lesser General Public License for more details. - * - * 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 St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef __EGG_SM_CLIENT_H__ -#define __EGG_SM_CLIENT_H__ - -#include - -G_BEGIN_DECLS - -#define EGG_TYPE_SM_CLIENT (egg_sm_client_get_type ()) -#define EGG_SM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT, EggSMClient)) -#define EGG_SM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT, EggSMClientClass)) -#define EGG_IS_SM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT)) -#define EGG_IS_SM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT)) -#define EGG_SM_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT, EggSMClientClass)) - -typedef struct _EggSMClient EggSMClient; -typedef struct _EggSMClientClass EggSMClientClass; -typedef struct _EggSMClientPrivate EggSMClientPrivate; - -typedef enum { - EGG_SM_CLIENT_END_SESSION_DEFAULT, - EGG_SM_CLIENT_LOGOUT, - EGG_SM_CLIENT_REBOOT, - EGG_SM_CLIENT_SHUTDOWN -} EggSMClientEndStyle; - -typedef enum { - EGG_SM_CLIENT_MODE_DISABLED, - EGG_SM_CLIENT_MODE_NO_RESTART, - EGG_SM_CLIENT_MODE_NORMAL -} EggSMClientMode; - -struct _EggSMClient -{ - GObject parent; - -}; - -struct _EggSMClientClass -{ - GObjectClass parent_class; - - /* signals */ - void (*save_state) (EggSMClient *client, - GKeyFile *state_file); - - void (*quit_requested) (EggSMClient *client); - void (*quit_cancelled) (EggSMClient *client); - void (*quit) (EggSMClient *client); - - /* virtual methods */ - void (*startup) (EggSMClient *client, - const char *client_id); - void (*set_restart_command) (EggSMClient *client, - int argc, - const char **argv); - void (*will_quit) (EggSMClient *client, - gboolean will_quit); - gboolean (*end_session) (EggSMClient *client, - EggSMClientEndStyle style, - gboolean request_confirmation); - - /* Padding for future expansion */ - void (*_egg_reserved1) (void); - void (*_egg_reserved2) (void); - void (*_egg_reserved3) (void); - void (*_egg_reserved4) (void); -}; - -GType egg_sm_client_get_type (void) G_GNUC_CONST; - -GOptionGroup *egg_sm_client_get_option_group (void); - -/* Initialization */ -void egg_sm_client_set_mode (EggSMClientMode mode); -EggSMClientMode egg_sm_client_get_mode (void); -EggSMClient *egg_sm_client_get (void); - -/* Resuming a saved session */ -gboolean egg_sm_client_is_resumed (EggSMClient *client); -GKeyFile *egg_sm_client_get_state_file (EggSMClient *client); - -/* Alternate means of saving state */ -void egg_sm_client_set_restart_command (EggSMClient *client, - int argc, - const char **argv); - -/* Handling "quit_requested" signal */ -void egg_sm_client_will_quit (EggSMClient *client, - gboolean will_quit); - -/* Initiate a logout/reboot/shutdown */ -gboolean egg_sm_client_end_session (EggSMClientEndStyle style, - gboolean request_confirmation); - -G_END_DECLS - - -#endif /* __EGG_SM_CLIENT_H__ */ diff --git a/xed/xed-app.c b/xed/xed-app.c index 460fc39..f5a513d 100644 --- a/xed/xed-app.c +++ b/xed/xed-app.c @@ -34,11 +34,17 @@ #include #include +#include +#include #include #include #include +#ifdef ENABLE_INTROSPECTION +#include +#endif + #include "xed-app.h" #include "xed-commands.h" #include "xed-notebook.h" @@ -50,6 +56,11 @@ #include "xed-plugins-engine.h" #include "xed-settings.h" +#ifndef ENABLE_GVFS_METADATA +#include "xed-metadata-manager.h" +#define METADATA_FILE "xed-metadata.xml" +#endif + #define XED_PAGE_SETUP_FILE "xed-page-setup" #define XED_PRINT_SETTINGS_FILE "xed-print-settings" @@ -63,8 +74,7 @@ enum struct _XedAppPrivate { - GList *windows; - XedWindow *active_window; + XedPluginsEngine *engine; GtkPageSetup *page_setup; GtkPrintSettings *print_settings; @@ -75,27 +85,82 @@ struct _XedAppPrivate PeasExtensionSet *extensions; }; -G_DEFINE_TYPE(XedApp, xed_app, G_TYPE_OBJECT) +G_DEFINE_TYPE (XedApp, xed_app, GTK_TYPE_APPLICATION) -static void -xed_app_finalize (GObject *object) +static gboolean new_window = FALSE; +static gboolean new_document = FALSE; +static gchar *geometry = NULL; +static const GtkSourceEncoding *encoding = NULL; +static GInputStream *stdin_stream = NULL; +static GSList *file_list = NULL; +static gint line_position = 0; +static GApplicationCommandLine *command_line = NULL; + +static const GOptionEntry options[] = { - XedApp *app = XED_APP (object); - - g_list_free (app->priv->windows); - - if (app->priv->page_setup) + /* Version */ { - g_object_unref (app->priv->page_setup); - } + "version", 'V', 0, G_OPTION_ARG_NONE, NULL, + N_("Show the application's version"), NULL + }, - if (app->priv->print_settings) + /* List available encodings */ { - g_object_unref (app->priv->print_settings); - } + "list-encodings", '\0', 0, G_OPTION_ARG_NONE, NULL, + N_("Display list of possible values for the encoding option"), + NULL + }, - G_OBJECT_CLASS (xed_app_parent_class)->finalize (object); -} + /* Encoding */ + { + "encoding", '\0', 0, G_OPTION_ARG_STRING, NULL, + N_("Set the character encoding to be used to open the files listed on the command line"), + N_("ENCODING") + }, + + /* Open a new window */ + { + "new-window", '\0', 0, G_OPTION_ARG_NONE, NULL, + N_("Create a new top-level window in an existing instance of xed"), + NULL + }, + + /* Create a new empty document */ + { + "new-document", '\0', 0, G_OPTION_ARG_NONE, NULL, + N_("Create a new document in an existing instance of xed"), + NULL + }, + + /* Window geometry */ + { + "geometry", 'g', 0, G_OPTION_ARG_STRING, NULL, + N_("Set the size and position of the window (WIDTHxHEIGHT+X+Y)"), + N_("GEOMETRY") + }, + + /* Wait for closing documents */ + { + "wait", 'w', 0, G_OPTION_ARG_NONE, NULL, + N_("Open files and block process until files are closed"), + NULL + }, + + /* New instance */ + { + "standalone", 's', 0, G_OPTION_ARG_NONE, NULL, + N_("Run xed in standalone mode"), + NULL + }, + + /* collects file arguments */ + { + G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, NULL, NULL, + N_("[FILE...] [+LINE") + }, + + {NULL} +}; static void xed_app_dispose (GObject *object) @@ -104,7 +169,10 @@ xed_app_dispose (GObject *object) g_clear_object (&app->priv->window_settings); g_clear_object (&app->priv->settings); + g_clear_object (&app->priv->page_setup); + g_clear_object (&app->priv->print_settings); g_clear_object (&app->priv->extensions); + g_clear_object (&app->priv->engine); G_OBJECT_CLASS (xed_app_parent_class)->dispose (object); } @@ -124,21 +192,421 @@ xed_app_get_property (GObject *object, } static void -xed_app_class_init (XedAppClass *klass) +extension_added (PeasExtensionSet *extensions, + PeasPluginInfo *info, + PeasExtension *exten, + XedApp *app) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); + peas_extension_call (exten, "activate"); +} - object_class->finalize = xed_app_finalize; - object_class->dispose = xed_app_dispose; - object_class->get_property = xed_app_get_property; +static void +extension_removed (PeasExtensionSet *extensions, + PeasPluginInfo *info, + PeasExtension *exten, + XedApp *app) +{ + peas_extension_call (exten, "deactivate"); +} - g_type_class_add_private (object_class, sizeof (XedAppPrivate)); +static void +xed_app_startup (GApplication *application) +{ + XedApp *app = XED_APP (application); + GtkSourceStyleSchemeManager *manager; + const gchar *dir; + gchar *icon_dir; +#ifndef ENABLE_GVFS_METADATA + const gchar *cache_dir; + gchar *metadata_filename; +#endif + + G_APPLICATION_CLASS (xed_app_parent_class)->startup (application); + + /* Setup debugging */ + xed_debug_init (); + xed_debug_message (DEBUG_APP, "Startup"); + + xed_dirs_init (); + + /* Setup locale/gettext */ + setlocale (LC_ALL, ""); + + dir = xed_dirs_get_xed_locale_dir (); + bindtextdomain (GETTEXT_PACKAGE, dir); + + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + xed_debug_message (DEBUG_APP, "Set icon"); + + dir = xed_dirs_get_xed_data_dir (); + icon_dir = g_build_filename (dir, "icons", NULL); + + gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), icon_dir); + g_free (icon_dir); + +#ifndef ENABLE_GVFS_METADATA + /* Setup metadata-manager */ + cache_dir = xed_dirs_get_user_cache_dir (); + + metadata_filename = g_build_filename (cache_dir, METADATA_FILE, NULL); + + xed_metadata_manager_init (metadata_filename); + + g_free (metadata_filename); +#endif + + /* Load settings */ + app->priv->settings = xed_settings_new (); + app->priv->window_settings = g_settings_new ("org.x.editor.state.window"); + + /* + * We use the default gtksourceview style scheme manager so that plugins + * can obtain it easily without a xed specific api, but we need to + * add our search path at startup before the manager is actually used. + */ + manager = gtk_source_style_scheme_manager_get_default (); + gtk_source_style_scheme_manager_append_search_path (manager, xed_dirs_get_user_styles_dir ()); + + app->priv->engine = xed_plugins_engine_get_default (); + app->priv->extensions = peas_extension_set_new (PEAS_ENGINE (app->priv->engine), + XED_TYPE_APP_ACTIVATABLE, + "app", app, + NULL); + + g_signal_connect (app->priv->extensions, "extension-added", + G_CALLBACK (extension_added), app); + + g_signal_connect (app->priv->extensions, "extension-removed", + G_CALLBACK (extension_removed), app); + + peas_extension_set_foreach (app->priv->extensions, + (PeasExtensionSetForeachFunc) extension_added, + app); +} + +static gboolean +is_in_viewport (GtkWindow *window, + GdkScreen *screen, + gint workspace, + gint viewport_x, + gint viewport_y) +{ + GdkScreen *s; + GdkDisplay *display; + GdkWindow *gdkwindow; + const gchar *cur_name; + const gchar *name; + gint cur_n; + gint n; + gint ws; + gint sc_width, sc_height; + gint x, y, width, height; + gint vp_x, vp_y; + + /* Check for screen and display match */ + display = gdk_screen_get_display (screen); + cur_name = gdk_display_get_name (display); + cur_n = gdk_screen_get_number (screen); + + s = gtk_window_get_screen (window); + display = gdk_screen_get_display (s); + name = gdk_display_get_name (display); + n = gdk_screen_get_number (s); + + if (strcmp (cur_name, name) != 0 || cur_n != n) + { + return FALSE; + } + + /* Check for workspace match */ + ws = xed_utils_get_window_workspace (window); + if (ws != workspace && ws != XED_ALL_WORKSPACES) + { + return FALSE; + } + + /* Check for viewport match */ + gdkwindow = gtk_widget_get_window (GTK_WIDGET (window)); + gdk_window_get_position (gdkwindow, &x, &y); + width = gdk_window_get_width (gdkwindow); + height = gdk_window_get_height (gdkwindow); + xed_utils_get_current_viewport (screen, &vp_x, &vp_y); + x += vp_x; + y += vp_y; + + sc_width = gdk_screen_get_width (screen); + sc_height = gdk_screen_get_height (screen); + + return x + width * .25 >= viewport_x && + x + width * .75 <= viewport_x + sc_width && + y >= viewport_y && + y + height <= viewport_y + sc_height; +} + +static XedWindow * +get_active_window (GtkApplication *app) +{ + GdkScreen *screen; + guint workspace; + gint viewport_x, viewport_y; + GList *windows, *l; + + screen = gdk_screen_get_default (); + + workspace = xed_utils_get_current_workspace (screen); + xed_utils_get_current_viewport (screen, &viewport_x, &viewport_y); + + /* Gtk documentation says the window list is always in MRU order */ + windows = gtk_application_get_windows (app); + for (l = windows; l != NULL; l = l->next) + { + GtkWindow *window = l->data; + + if (is_in_viewport (window, screen, workspace, viewport_x, viewport_y)) + { + return XED_WINDOW (window); + } + } + + return NULL; +} + +static void +set_command_line_wait (XedTab *tab) +{ + g_object_set_data_full (G_OBJECT (tab), + "XedTabCommandLineWait", + g_object_ref (command_line), + (GDestroyNotify)g_object_unref); +} + +static void +xed_app_activate (GApplication *application) +{ + XedWindow *window = NULL; + XedTab *tab; + gboolean doc_created = FALSE; + + if (!new_window) + { + window = get_active_window (GTK_APPLICATION (application)); + } + + if (window == NULL) + { + xed_debug_message (DEBUG_APP, "Create main window"); + window = xed_app_create_window (XED_APP (application), NULL); + + xed_debug_message (DEBUG_APP, "Show window"); + gtk_widget_show (GTK_WIDGET (window)); + } + + if (geometry) + { + gtk_window_parse_geometry (GTK_WINDOW (window), geometry); + } + + if (stdin_stream) + { + xed_debug_message (DEBUG_APP, "Load stdin"); + + tab = xed_window_create_tab_from_stream (window, + stdin_stream, + encoding, + line_position, + TRUE); + doc_created = tab != NULL; + + if (doc_created && command_line) + { + set_command_line_wait (tab); + } + g_input_stream_close (stdin_stream, NULL, NULL); + } + + if (file_list != NULL) + { + GSList *loaded; + + xed_debug_message (DEBUG_APP, "Load files"); + loaded = _xed_cmd_load_files_from_prompt (window, file_list, encoding, line_position); + + doc_created = doc_created || loaded != NULL; + + if (command_line) + { + g_slist_foreach (loaded, (GFunc)set_command_line_wait, NULL); + } + g_slist_free (loaded); + } + + if (!doc_created || new_document) + { + xed_debug_message (DEBUG_APP, "Create tab"); + tab = xed_window_create_tab (window, TRUE); + + if (command_line) + { + set_command_line_wait (tab); + } + } + + gtk_window_present (GTK_WINDOW (window)); +} + +static void +clear_options (void) +{ + g_free (geometry); + g_clear_object (&stdin_stream); + g_slist_free_full (file_list, g_object_unref); + + new_window = FALSE; + new_document = FALSE; + geometry = NULL; + encoding = NULL; + file_list = NULL; + line_position = 0; + command_line = NULL; +} + +static void +get_line_position (const gchar *arg, + gint *line) +{ + *line = atoi (arg); +} + +static gint +xed_app_command_line (GApplication *application, + GApplicationCommandLine *cl) +{ + GVariantDict *options; + const gchar *encoding_charset; + const gchar **remaining_args; + + options = g_application_command_line_get_options_dict (cl); + + g_variant_dict_lookup (options, "new-window", "b", &new_window); + g_variant_dict_lookup (options, "new-document", "b", &new_document); + g_variant_dict_lookup (options, "geometry", "s", &geometry); + + if (g_variant_dict_contains (options, "wait")) + { + command_line = cl; + } + + if (g_variant_dict_lookup (options, "encoding", "&s", &encoding_charset)) + { + encoding = gtk_source_encoding_get_from_charset (encoding_charset); + + if (encoding == NULL) + { + g_application_command_line_printerr (cl, _("%s: invalid encoding."), encoding_charset); + } + } + + /* Parse filenames */ + if (g_variant_dict_lookup (options, G_OPTION_REMAINING, "^a&ay", &remaining_args)) + { + gint i; + + for (i = 0; remaining_args[i]; i++) + { + if (*remaining_args[i] == '+') + { + if (*(remaining_args[i] + 1) == '\0') + { + /* goto the last line of the document */ + line_position = G_MAXINT; + } + else + { + get_line_position (remaining_args[i] + 1, &line_position); + } + } + + else if (*remaining_args[i] == '-' && *(remaining_args[i] + 1) == '\0') + { + stdin_stream = g_application_command_line_get_stdin (cl); + } + else + { + GFile *file; + + file = g_application_command_line_create_file_for_arg (cl, remaining_args[i]); + file_list = g_slist_prepend (file_list, file); + } + } + + file_list = g_slist_reverse (file_list); + g_free (remaining_args); + } + + g_application_activate (application); + clear_options (); + + return 0; +} + +static void +print_all_encodings (void) +{ + GSList *all_encodings; + GSList *l; + + all_encodings = gtk_source_encoding_get_all (); + + for (l = all_encodings; l != NULL; l = l->next) + { + const GtkSourceEncoding *encoding = l->data; + g_print ("%s\n", gtk_source_encoding_get_charset (encoding)); + } + + g_slist_free (all_encodings); +} + +static gint +xed_app_handle_local_options (GApplication *application, + GVariantDict *options) +{ + if (g_variant_dict_contains (options, "version")) + { + g_print ("%s - Version %s\n", g_get_application_name (), VERSION); + return 0; + } + + if (g_variant_dict_contains (options, "list-encodings")) + { + print_all_encodings (); + return 0; + } + + if (g_variant_dict_contains (options, "standalone")) + { + GApplicationFlags old_flags; + + old_flags = g_application_get_flags (application); + g_application_set_flags (application, old_flags | G_APPLICATION_NON_UNIQUE); + } + + if (g_variant_dict_contains (options, "wait")) + { + GApplicationFlags old_flags; + + old_flags = g_application_get_flags (application); + g_application_set_flags (application, old_flags | G_APPLICATION_IS_LAUNCHER); + } + + return -1; } static gboolean ensure_user_config_dir (void) { - gchar *config_dir; + const gchar *config_dir; gboolean ret = TRUE; gint res; @@ -156,31 +624,15 @@ ensure_user_config_dir (void) ret = FALSE; } - g_free (config_dir); - return ret; } -static void -load_accels (void) -{ - gchar *filename; - - filename = xed_dirs_get_user_accels_file (); - if (filename != NULL) - { - xed_debug_message (DEBUG_APP, "Loading keybindings from %s\n", filename); - gtk_accel_map_load (filename); - g_free (filename); - } -} - static void save_accels (void) { gchar *filename; - filename = xed_dirs_get_user_accels_file (); + filename = g_build_filename (xed_dirs_get_user_config_dir (), "accels", NULL); if (filename != NULL) { xed_debug_message (DEBUG_APP, "Saving keybindings in %s\n", filename); @@ -192,7 +644,7 @@ save_accels (void) static gchar * get_page_setup_file (void) { - gchar *config_dir; + const gchar *config_dir; gchar *setup = NULL; config_dir = xed_dirs_get_user_config_dir (); @@ -200,12 +652,126 @@ get_page_setup_file (void) if (config_dir != NULL) { setup = g_build_filename (config_dir, XED_PAGE_SETUP_FILE, NULL); - g_free (config_dir); } return setup; } +static void +save_page_setup (XedApp *app) +{ + gchar *filename; + GError *error = NULL; + + if (app->priv->page_setup == NULL) + { + return; + } + + filename = get_page_setup_file (); + + gtk_page_setup_to_file (app->priv->page_setup, filename, &error); + if (error) + { + g_warning ("%s", error->message); + g_error_free (error); + } + + g_free (filename); +} + +static gchar * +get_print_settings_file (void) +{ + const gchar *config_dir; + gchar *settings = NULL; + + config_dir = xed_dirs_get_user_config_dir (); + + if (config_dir != NULL) + { + settings = g_build_filename (config_dir, XED_PRINT_SETTINGS_FILE, NULL); + } + + return settings; +} + +static void +save_print_settings (XedApp *app) +{ + gchar *filename; + GError *error = NULL; + + if (app->priv->print_settings == NULL) + { + return; + } + + filename = get_print_settings_file (); + + gtk_print_settings_to_file (app->priv->print_settings, filename, &error); + if (error) + { + g_warning ("%s", error->message); + g_error_free (error); + } + + g_free (filename); +} + +static void +xed_app_shutdown (GApplication *app) +{ + xed_debug_message (DEBUG_APP, "Quitting\n"); + + /* Last window is gone... save some settings and exit */ + ensure_user_config_dir (); + + save_accels (); + save_page_setup (XED_APP (app)); + save_print_settings (XED_APP (app)); + +#ifndef ENABLE_GVFS_METADATA + xed_metadata_manager_shutdown (); +#endif + + xed_dirs_shutdown (); + + G_APPLICATION_CLASS (xed_app_parent_class)->shutdown (app); +} + +static void +xed_app_class_init (XedAppClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GApplicationClass *app_class = G_APPLICATION_CLASS (klass); + + object_class->dispose = xed_app_dispose; + object_class->get_property = xed_app_get_property; + + app_class->startup = xed_app_startup; + app_class->activate = xed_app_activate; + app_class->command_line = xed_app_command_line; + app_class->handle_local_options = xed_app_handle_local_options; + app_class->shutdown = xed_app_shutdown; + + g_type_class_add_private (object_class, sizeof (XedAppPrivate)); +} + +static void +load_accels (void) +{ + gchar *filename; + + filename = g_build_filename (xed_dirs_get_user_config_dir (), "accels", NULL); + if (filename != NULL) + { + xed_debug_message (DEBUG_APP, "Loading keybindings from %s\n", filename); + gtk_accel_map_load (filename); + g_free (filename); + } +} + static void load_page_setup (XedApp *app) { @@ -237,46 +803,6 @@ load_page_setup (XedApp *app) } } -static void -save_page_setup (XedApp *app) -{ - gchar *filename; - GError *error = NULL; - - if (app->priv->page_setup == NULL) - { - return; - } - - filename = get_page_setup_file (); - - gtk_page_setup_to_file (app->priv->page_setup, filename, &error); - if (error) - { - g_warning ("%s", error->message); - g_error_free (error); - } - - g_free (filename); -} - -static gchar * -get_print_settings_file (void) -{ - gchar *config_dir; - gchar *settings = NULL; - - config_dir = xed_dirs_get_user_config_dir (); - - if (config_dir != NULL) - { - settings = g_build_filename (config_dir, XED_PRINT_SETTINGS_FILE, NULL); - g_free (config_dir); - } - - return settings; -} - static void load_print_settings (XedApp *app) { @@ -308,119 +834,21 @@ load_print_settings (XedApp *app) } } -static void -save_print_settings (XedApp *app) -{ - gchar *filename; - GError *error = NULL; - - if (app->priv->print_settings == NULL) - { - return; - } - - filename = get_print_settings_file (); - - gtk_print_settings_to_file (app->priv->print_settings, filename, &error); - if (error) - { - g_warning ("%s", error->message); - g_error_free (error); - } - - g_free (filename); -} - -static void -extension_added (PeasExtensionSet *extensions, - PeasPluginInfo *info, - PeasExtension *exten, - XedApp *app) -{ - peas_extension_call (exten, "activate"); -} - -static void -extension_removed (PeasExtensionSet *extensions, - PeasPluginInfo *info, - PeasExtension *exten, - XedApp *app) -{ - peas_extension_call (exten, "deactivate"); -} - static void xed_app_init (XedApp *app) { - GtkSourceStyleSchemeManager *manager; - app->priv = XED_APP_GET_PRIVATE (app); + g_set_application_name ("xed"); + gtk_window_set_default_icon_name ("accessories-text-editor"); + + g_application_add_main_option_entries (G_APPLICATION (app), options); + +#ifdef ENABLE_INTROSPECTION + g_application_add_option_group (G_APPLICATION (app), g_irepository_get_option_group ()); +#endif + load_accels (); - - app->priv->settings = xed_settings_new (); - app->priv->window_settings = g_settings_new ("org.x.editor.state.window"); - - /* - * We use the default gtksourceview style scheme manager so that plugins - * can obtain it easily without a xed specific api, but we need to - * add our search path at startup before the manager is actually used. - */ - manager = gtk_source_style_scheme_manager_get_default (); - gtk_source_style_scheme_manager_append_search_path (manager, xed_dirs_get_user_styles_dir ()); - - app->priv->extensions = peas_extension_set_new (PEAS_ENGINE (xed_plugins_engine_get_default ()), - XED_TYPE_APP_ACTIVATABLE, "app", app, NULL); - - g_signal_connect (app->priv->extensions, "extension-added", - G_CALLBACK (extension_added), app); - g_signal_connect (app->priv->extensions, "extension-removed", - G_CALLBACK (extension_removed), app); - - peas_extension_set_call (app->priv->extensions, "activate"); -} - -/** - * xed_app_get_default: - * - * Returns the #XedApp object. This object is a singleton and - * represents the running xed instance. - * - * Return value: (transfer none): the #XedApp pointer - */ -XedApp * -xed_app_get_default (void) -{ - static XedApp *app = NULL; - - if (app != NULL) - return app; - - app = XED_APP (g_object_new (XED_TYPE_APP, NULL)); - - g_object_add_weak_pointer (G_OBJECT (app), (gpointer) &app); - - return app; -} - -static void -set_active_window (XedApp *app, - XedWindow *window) -{ - app->priv->active_window = window; -} - -static gboolean -window_focus_in_event (XedWindow *window, - GdkEventFocus *event, - XedApp *app) -{ - /* updates active_view and active_child when a new toplevel receives focus */ - g_return_val_if_fail (XED_IS_WINDOW (window), FALSE); - - set_active_window (app, window); - - return FALSE; } static gboolean @@ -446,41 +874,6 @@ window_delete_event (XedWindow *window, return TRUE; } -static void -window_destroy (XedWindow *window, - XedApp *app) -{ - app->priv->windows = g_list_remove (app->priv->windows, - window); - - if (window == app->priv->active_window) - { - set_active_window (app, app->priv->windows != NULL ? app->priv->windows->data : NULL); - } - -/* CHECK: I don't think we have to disconnect this function, since windows - is being destroyed */ -/* - g_signal_handlers_disconnect_by_func (window, - G_CALLBACK (window_focus_in_event), - app); - g_signal_handlers_disconnect_by_func (window, - G_CALLBACK (window_destroy), - app); -*/ - if (app->priv->windows == NULL) - { - /* Last window is gone... save some settings and exit */ - ensure_user_config_dir (); - - save_accels (); - save_page_setup (app); - save_print_settings (app); - - gtk_main_quit (); - } -} - /* Generates a unique string for a window role */ static gchar * gen_role (void) @@ -504,25 +897,7 @@ xed_app_create_window_real (XedApp *app, { XedWindow *window; - xed_debug (DEBUG_APP); - - /* - * We need to be careful here, there is a race condition: - * when another xed is launched it checks active_window, - * so we must do our best to ensure that active_window - * is never NULL when at least a window exists. - */ - if (app->priv->windows == NULL) - { - window = g_object_new (XED_TYPE_WINDOW, NULL); - set_active_window (app, window); - } - else - { - window = g_object_new (XED_TYPE_WINDOW, NULL); - } - - app->priv->windows = g_list_prepend (app->priv->windows, window); + window = g_object_new (XED_TYPE_WINDOW, "application", app, NULL); xed_debug_message (DEBUG_APP, "Window created"); @@ -545,17 +920,15 @@ xed_app_create_window_real (XedApp *app, gint w, h; state = g_settings_get_int (app->priv->window_settings, XED_SETTINGS_WINDOW_STATE); + g_settings_get (app->priv->window_settings, XED_SETTINGS_WINDOW_SIZE, "(ii)", &w, &h); + gtk_window_set_default_size (GTK_WINDOW (window), w, h); if ((state & GDK_WINDOW_STATE_MAXIMIZED) != 0) { - _xed_window_get_default_size (&w, &h); - gtk_window_set_default_size (GTK_WINDOW (window), w, h); gtk_window_maximize (GTK_WINDOW (window)); } else { - g_settings_get (app->priv->window_settings, XED_SETTINGS_WINDOW_SIZE, "(ii)", &w, &h); - gtk_window_set_default_size (GTK_WINDOW (window), w, h); gtk_window_unmaximize (GTK_WINDOW (window)); } @@ -569,9 +942,7 @@ xed_app_create_window_real (XedApp *app, } } - g_signal_connect (window, "focus_in_event", G_CALLBACK (window_focus_in_event), app); g_signal_connect (window, "delete_event", G_CALLBACK (window_delete_event), app); - g_signal_connect (window, "destroy", G_CALLBACK (window_destroy), app); return window; } @@ -617,159 +988,34 @@ _xed_app_restore_window (XedApp *app, } /** - * xed_app_get_windows: - * @app: the #XedApp + * xed_app_get_main_windows: + * @app: the #GeditApp * - * Returns all the windows currently present in #XedApp. + * Returns all #XedWindows currently open in #XedApp. + * This differs from gtk_application_get_windows() since it does not + * include the preferences dialog and other auxiliary windows. * - * Return value: (element-type Xed.Window) (transfer none): the list of #XedWindows objects. - * The list should not be freed + * Return value: (element-type Xed.Window) (transfer container): + * a newly allocated list of #XedWindow objects */ -const GList * -xed_app_get_windows (XedApp *app) +GList * +xed_app_get_main_windows (XedApp *app) { - g_return_val_if_fail (XED_IS_APP (app), NULL); - - return app->priv->windows; -} - -/** - * xed_app_get_active_window: - * @app: the #XedApp - * - * Retrives the #XedWindow currently active. - * - * Return value: (transfer none): the active #XedWindow - */ -XedWindow * -xed_app_get_active_window (XedApp *app) -{ - g_return_val_if_fail (XED_IS_APP (app), NULL); - - /* make sure our active window is always realized: - * this is needed on startup if we launch two xed fast - * enough that the second instance comes up before the - * first one shows its window. - */ - if (!gtk_widget_get_realized (GTK_WIDGET (app->priv->active_window))) - { - gtk_widget_realize (GTK_WIDGET (app->priv->active_window)); - } - - return app->priv->active_window; -} - -static gboolean -is_in_viewport (XedWindow *window, - GdkScreen *screen, - gint workspace, - gint viewport_x, - gint viewport_y) -{ - GdkScreen *s; - GdkDisplay *display; - GdkWindow *gdkwindow; - const gchar *cur_name; - const gchar *name; - gint cur_n; - gint n; - gint ws; - gint sc_width, sc_height; - gint x, y, width, height; - gint vp_x, vp_y; - - /* Check for screen and display match */ - display = gdk_screen_get_display (screen); - cur_name = gdk_display_get_name (display); - cur_n = gdk_screen_get_number (screen); - - s = gtk_window_get_screen (GTK_WINDOW (window)); - display = gdk_screen_get_display (s); - name = gdk_display_get_name (display); - n = gdk_screen_get_number (s); - - if (strcmp (cur_name, name) != 0 || cur_n != n) - { - return FALSE; - } - - /* Check for workspace match */ - ws = xed_utils_get_window_workspace (GTK_WINDOW (window)); - if (ws != workspace && ws != XED_ALL_WORKSPACES) - { - return FALSE; - } - - /* Check for viewport match */ - gdkwindow = gtk_widget_get_window (GTK_WIDGET (window)); - gdk_window_get_position (gdkwindow, &x, &y); - - width = gdk_window_get_width (gdkwindow); - height = gdk_window_get_height (gdkwindow); - - xed_utils_get_current_viewport (screen, &vp_x, &vp_y); - x += vp_x; - y += vp_y; - - sc_width = gdk_screen_get_width (screen); - sc_height = gdk_screen_get_height (screen); - - return x + width * .25 >= viewport_x && - x + width * .75 <= viewport_x + sc_width && - y >= viewport_y && - y + height <= viewport_y + sc_height; -} - -/** - * _xed_app_get_window_in_viewport - * @app: the #XedApp - * @screen: the #GdkScreen - * @workspace: the workspace number - * @viewport_x: the viewport horizontal origin - * @viewport_y: the viewport vertical origin - * - * Since a workspace can be larger than the screen, it is divided into several - * equal parts called viewports. This function retrives the #XedWindow in - * the given viewport of the given workspace. - * - * Return value: the #XedWindow in the given viewport of the given workspace. - */ -XedWindow * -_xed_app_get_window_in_viewport (XedApp *app, - GdkScreen *screen, - gint workspace, - gint viewport_x, - gint viewport_y) -{ - XedWindow *window; - - GList *l; + GList *res = NULL; + GList *windows, *l; g_return_val_if_fail (XED_IS_APP (app), NULL); - /* first try if the active window */ - window = app->priv->active_window; - - g_return_val_if_fail (XED_IS_WINDOW (window), NULL); - - if (is_in_viewport (window, screen, workspace, viewport_x, viewport_y)) + windows = gtk_application_get_windows (GTK_APPLICATION (app)); + for (l = windows; l != NULL; l = g_list_next (l)) { - return window; - } - - /* otherwise try to see if there is a window on this workspace */ - for (l = app->priv->windows; l != NULL; l = l->next) - { - window = l->data; - - if (is_in_viewport (window, screen, workspace, viewport_x, viewport_y)) + if (XED_IS_WINDOW (l->data)) { - return window; + res = g_list_prepend (res, l->data); } } - /* no window on this workspace... create a new one */ - return xed_app_create_window (app, screen); + return g_list_reverse (res); } /** @@ -785,16 +1031,14 @@ GList * xed_app_get_documents (XedApp *app) { GList *res = NULL; - GList *windows; + GList *windows, *l; g_return_val_if_fail (XED_IS_APP (app), NULL); - windows = app->priv->windows; - - while (windows != NULL) + windows = gtk_application_get_windows (GTK_APPLICATION (app)); + for (l = windows; l != NULL; l = g_list_next (l)) { - res = g_list_concat (res, xed_window_get_documents (XED_WINDOW (windows->data))); - windows = g_list_next (windows); + res = g_list_concat (res, xed_window_get_documents (XED_WINDOW (l->data))); } return res; @@ -813,21 +1057,88 @@ GList * xed_app_get_views (XedApp *app) { GList *res = NULL; - GList *windows; + GList *windows, *l; g_return_val_if_fail (XED_IS_APP (app), NULL); - windows = app->priv->windows; - - while (windows != NULL) + windows = gtk_application_get_windows (GTK_APPLICATION (app)); + for (l = windows; l != NULL; l = g_list_next (l)) { - res = g_list_concat (res, xed_window_get_views (XED_WINDOW (windows->data))); - windows = g_list_next (windows); + res = g_list_concat (res, xed_window_get_views (XED_WINDOW (l->data))); } return res; } +gboolean +xed_app_show_help (XedApp *app, + GtkWindow *parent, + const gchar *name, + const gchar *link_id) +{ + g_return_val_if_fail (XED_IS_APP (app), FALSE); + g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), FALSE); + + GError *error = NULL; + gboolean ret; + gchar *link; + + if (name == NULL) + { + name = "xed"; + } + else if (strcmp (name, "xed.xml") == 0) + { + g_warning ("%s: Using \"xed.xml\" for the help name is deprecated, use \"xed\" or simply NULL instead", G_STRFUNC); + name = "xed"; + } + + if (link_id) + { + link = g_strdup_printf ("help:%s/%s", name, link_id); + } + else + { + link = g_strdup_printf ("help:%s", name); + } + + ret = gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (parent)), link, GDK_CURRENT_TIME, &error); + + g_free (link); + + if (error != NULL) + { + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (parent, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_CLOSE, + _("There was an error displaying the help.")); + + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", error->message); + + g_signal_connect (G_OBJECT (dialog), "response", + G_CALLBACK (gtk_widget_destroy), NULL); + + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + + gtk_widget_show (dialog); + + g_error_free (error); + } + + return ret; +} + +void +xed_app_set_window_title (XedApp *app, + XedWindow *window, + const gchar *title) +{ + gtk_window_set_title (GTK_WINDOW (window), title); +} + /* Returns a copy */ GtkPageSetup * _xed_app_get_default_page_setup (XedApp *app) diff --git a/xed/xed-app.h b/xed/xed-app.h index 5266d88..b9919d4 100644 --- a/xed/xed-app.h +++ b/xed/xed-app.h @@ -50,7 +50,7 @@ typedef struct _XedAppClass XedAppClass; struct _XedApp { - GObject object; + GtkApplication parent; /*< private > */ XedAppPrivate *priv; @@ -58,38 +58,49 @@ struct _XedApp struct _XedAppClass { - GObjectClass parent_class; + GtkApplicationClass parent_class; + + // gboolean (*last_window_destroyed) (XedApp *app); + + gboolean (*show_help) (XedApp *app, + GtkWindow *parent, + const gchar *name, + const gchar *link_id); + + gchar *(*help_link_id) (XedApp *app, + const gchar *name, + const gchar *link_id); + + void (*set_window_title) (XedApp *app, + XedWindow *window, + const gchar *title); }; -/* - * Public methods - */ +/* Public methods */ GType xed_app_get_type (void) G_GNUC_CONST; -XedApp *xed_app_get_default (void); - XedWindow *xed_app_create_window (XedApp *app, GdkScreen *screen); -const GList *xed_app_get_windows (XedApp *app); -XedWindow *xed_app_get_active_window (XedApp *app); +GList *xed_app_get_main_windows (XedApp *app); -/* Returns a newly allocated list with all the documents */ GList *xed_app_get_documents (XedApp *app); /* Returns a newly allocated list with all the views */ GList *xed_app_get_views (XedApp *app); -/* - * Non exported functions - */ +gboolean xed_app_show_help (XedApp *app, + GtkWindow *parent, + const gchar *name, + const gchar *link_id); + +void xed_app_set_window_title (XedApp *app, + XedWindow *window, + const gchar *title); + +/* Non exported functions */ XedWindow *_xed_app_restore_window (XedApp *app, const gchar *role); -XedWindow *_xed_app_get_window_in_viewport (XedApp *app, - GdkScreen *screen, - gint workspace, - gint viewport_x, - gint viewport_y); /* global print config */ GtkPageSetup *_xed_app_get_default_page_setup (XedApp *app); diff --git a/xed/xed-commands-file.c b/xed/xed-commands-file.c index 4256f78..9ec11de 100644 --- a/xed/xed-commands-file.c +++ b/xed/xed-commands-file.c @@ -61,6 +61,9 @@ static void tab_state_changed_while_saving (XedTab *tab, GParamSpec *pspec, XedWindow *window); +static void save_as_tab (XedTab *tab, + XedWindow *window); + void _xed_cmd_file_new (GtkAction *action, XedWindow *window) @@ -116,7 +119,7 @@ is_duplicated_file (GSList *files, } /* File loading */ -static gint +static GSList * load_file_list (XedWindow *window, const GSList *files, const GtkSourceEncoding *encoding, @@ -124,11 +127,12 @@ load_file_list (XedWindow *window, gboolean create) { XedTab *tab; - gint loaded_files = 0; /* Number of files to load */ + GSList *loaded_files = NULL; /* Number of files to load */ gboolean jump_to = TRUE; /* Whether to jump to the new tab */ GList *win_docs; GSList *files_to_load = NULL; const GSList *l; + gint num_loaded_files = 0; xed_debug (DEBUG_COMMANDS); @@ -145,29 +149,25 @@ load_file_list (XedWindow *window, { if (l == files) { + XedDocument *doc; + xed_window_set_active_tab (window, tab); jump_to = FALSE; + doc = xed_tab_get_document (tab); if (line_pos > 0) { - XedDocument *doc; - XedView *view; - - doc = xed_tab_get_document (tab); - view = xed_tab_get_view (tab); - - /* document counts lines starting from 0 */ xed_document_goto_line (doc, line_pos - 1); - xed_view_scroll_to_cursor (view); + xed_view_scroll_to_cursor (xed_tab_get_view (tab)); } } - ++loaded_files; + ++num_loaded_files; + loaded_files = g_slist_prepend (loaded_files, xed_tab_get_document (tab)); } else { - files_to_load = g_slist_prepend (files_to_load, - l->data); + files_to_load = g_slist_prepend (files_to_load, l->data); } } } @@ -176,7 +176,7 @@ load_file_list (XedWindow *window, if (files_to_load == NULL) { - return loaded_files; + return g_slist_reverse (loaded_files); } files_to_load = g_slist_reverse (files_to_load); @@ -196,7 +196,8 @@ load_file_list (XedWindow *window, l = g_slist_next (l); jump_to = FALSE; - ++loaded_files; + ++num_loaded_files; + loaded_files = g_slist_prepend (loaded_files, xed_tab_get_document (tab)); } } @@ -209,13 +210,16 @@ load_file_list (XedWindow *window, if (tab != NULL) { jump_to = FALSE; - ++loaded_files; + ++num_loaded_files; + loaded_files = g_slist_prepend (loaded_files, xed_tab_get_document (tab)); } l = g_slist_next (l); } - if (loaded_files == 1) + loaded_files = g_slist_reverse (loaded_files); + + if (num_loaded_files == 1) { XedDocument *doc; gchar *uri_for_display; @@ -238,8 +242,8 @@ load_file_list (XedWindow *window, window->priv->generic_message_cid, ngettext("Loading %d file\342\200\246", "Loading %d files\342\200\246", - loaded_files), - loaded_files); + num_loaded_files), + num_loaded_files); } /* Free uris_to_load. Note that l points to the first element of uris_to_load */ @@ -265,6 +269,7 @@ xed_commands_load_location (XedWindow *window, { GSList *locations = NULL; gchar *uri; + GSList *ret; g_return_if_fail (XED_IS_WINDOW (window)); g_return_if_fail (G_IS_FILE (location)); @@ -276,7 +281,8 @@ xed_commands_load_location (XedWindow *window, locations = g_slist_prepend (locations, location); - load_file_list (window, locations, encoding, line_pos, FALSE); + ret = load_file_list (window, locations, encoding, line_pos, FALSE); + g_slist_free (ret); g_slist_free (locations); } @@ -292,7 +298,7 @@ xed_commands_load_location (XedWindow *window, * * Returns: */ -gint +GSList * xed_commands_load_locations (XedWindow *window, const GSList *locations, const GtkSourceEncoding *encoding, @@ -311,7 +317,7 @@ xed_commands_load_locations (XedWindow *window, * first doc. Beside specifying a not existing uri creates a * titled document. */ -gint +GSList * _xed_cmd_load_files_from_prompt (XedWindow *window, GSList *files, const GtkSourceEncoding *encoding, @@ -338,6 +344,7 @@ open_dialog_response_cb (XedFileChooserDialog *dialog, { GSList *files; const GtkSourceEncoding *encoding; + GSList *loaded; xed_debug (DEBUG_COMMANDS); @@ -358,7 +365,9 @@ open_dialog_response_cb (XedFileChooserDialog *dialog, /* Remember the folder we navigated to */ _xed_window_set_default_location (window, files->data); - xed_commands_load_locations (window, files, encoding, 0); + loaded = xed_commands_load_locations (window, files, encoding, 0); + + g_slist_free (loaded); g_slist_foreach (files, (GFunc) g_object_unref, NULL); g_slist_free (files); @@ -433,9 +442,6 @@ _xed_cmd_file_open (GtkAction *action, gtk_widget_show (open_dialog); } -/* File saving */ -static void file_save_as (XedTab *tab, XedWindow *window); - static gboolean is_read_only (GFile *location) { @@ -511,6 +517,14 @@ replace_read_only_file (GtkWindow *parent, return (ret == GTK_RESPONSE_YES); } +static void +save_finish_cb (XedTab *tab, + GAsyncResult *result, + gpointer user_data) +{ + _xed_tab_save_finish (tab, result); +} + static void save_dialog_response_cb (XedFileChooserDialog *dialog, gint response_id, @@ -535,13 +549,11 @@ save_dialog_response_cb (XedFileChooserDialog *dialog, { GFile *location; XedDocument *doc; - GtkSourceFile *file; gchar *parse_name; GtkSourceNewlineType newline_type; const GtkSourceEncoding *encoding; doc = xed_tab_get_document (tab); - file = xed_document_get_file (doc); location = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog)); g_return_if_fail (location != NULL); @@ -567,7 +579,13 @@ save_dialog_response_cb (XedFileChooserDialog *dialog, * even if the saving fails... */ _xed_window_set_default_location (window, location); - _xed_tab_save_as (tab, location, encoding, newline_type); + _xed_tab_save_as_async (tab, + location, + encoding, + newline_type, + NULL, + (GAsyncReadyCallback) save_finish_cb, + NULL); g_object_unref (location); } @@ -602,7 +620,7 @@ save_next_tab: } xed_window_set_active_tab (window, tab); - file_save_as (tab, window); + save_as_tab (tab, window); } } @@ -643,8 +661,8 @@ confirm_overwrite_callback (GtkFileChooser *dialog, } static void -file_save_as (XedTab *tab, - XedWindow *window) +save_as_tab (XedTab *tab, + XedWindow *window) { GtkWidget *save_dialog; GtkWindowGroup *wg; @@ -715,7 +733,11 @@ file_save_as (XedTab *tab, /* Set suggested encoding */ encoding = gtk_source_file_get_encoding (file); - g_return_if_fail (encoding != NULL); + + if (encoding == NULL) + { + encoding = gtk_source_encoding_get_utf8 (); + } newline_type = gtk_source_file_get_newline_type (file); @@ -731,8 +753,8 @@ file_save_as (XedTab *tab, } static void -file_save (XedTab *tab, - XedWindow *window) +save_tab (XedTab *tab, + XedWindow *window) { XedDocument *doc; gchar *uri_for_display; @@ -750,7 +772,7 @@ file_save (XedTab *tab, { xed_debug_message (DEBUG_COMMANDS, "Untitled or Readonly"); - file_save_as (tab, window); + save_as_tab (tab, window); return; } @@ -763,7 +785,10 @@ file_save (XedTab *tab, g_free (uri_for_display); - _xed_tab_save (tab); + _xed_tab_save_async (tab, + NULL, + (GAsyncReadyCallback) save_finish_cb, + NULL); } void @@ -780,7 +805,7 @@ _xed_cmd_file_save (GtkAction *action, return; } - file_save (tab, window); + save_tab (tab, window); } void @@ -797,15 +822,15 @@ _xed_cmd_file_save_as (GtkAction *action, return; } - file_save_as (tab, window); + save_as_tab (tab, window); } /* * The docs in the list must belong to the same XedWindow. */ -void -_xed_cmd_file_save_documents_list (XedWindow *window, - GList *docs) +static void +save_documents_list (XedWindow *window, + GList *docs) { GList *l; GSList *tabs_to_save_as = NULL; @@ -846,7 +871,7 @@ _xed_cmd_file_save_documents_list (XedWindow *window, } else { - file_save (t, window); + save_tab (t, window); } } else @@ -898,7 +923,7 @@ _xed_cmd_file_save_documents_list (XedWindow *window, tab = XED_TAB (tabs_to_save_as->data); xed_window_set_active_tab (window, tab); - file_save_as (tab, window); + save_as_tab (tab, window); } } @@ -913,7 +938,7 @@ xed_commands_save_all_documents (XedWindow *window) docs = xed_window_get_documents (window); - _xed_cmd_file_save_documents_list (window, docs); + save_documents_list (window, docs); g_list_free (docs); } @@ -937,7 +962,7 @@ xed_commands_save_document (XedWindow *window, xed_debug (DEBUG_COMMANDS); tab = xed_tab_get_from_document (document); - file_save (tab, window); + save_tab (tab, window); } /* File revert */ @@ -1213,7 +1238,7 @@ save_and_close (XedTab *tab, /* Trace tab state changes */ g_signal_connect (tab, "notify::state", G_CALLBACK (tab_state_changed_while_saving), window); - file_save (tab, window); + save_tab (tab, window); } static void @@ -1228,7 +1253,7 @@ save_as_and_close (XedTab *tab, g_signal_connect (tab, "notify::state", G_CALLBACK (tab_state_changed_while_saving), window); xed_window_set_active_tab (window, tab); - file_save_as (tab, window); + save_as_tab (tab, window); } static void diff --git a/xed/xed-commands-help.c b/xed/xed-commands-help.c index 23e0155..b031339 100644 --- a/xed/xed-commands-help.c +++ b/xed/xed-commands-help.c @@ -32,7 +32,7 @@ */ #ifdef HAVE_CONFIG_H - #include +#include #endif #include @@ -40,28 +40,30 @@ #include "xed-commands.h" #include "xed-debug.h" -#include "xed-help.h" +#include "xed-app.h" #include "xed-dirs.h" -void _xed_cmd_help_contents(GtkAction* action, XedWindow* window) +void _xed_cmd_help_contents (GtkAction *action, + XedWindow *window) { - xed_debug(DEBUG_COMMANDS); + xed_debug(DEBUG_COMMANDS); - xed_help_display(GTK_WINDOW(window), NULL, NULL); + xed_app_show_help (XED_APP (g_application_get_default ()), GTK_WINDOW (window), NULL, NULL); } -void _xed_cmd_help_about(GtkAction* action, XedWindow* window) +void _xed_cmd_help_about (GtkAction *action, + XedWindow *window) { - static const gchar comments[] = \ - N_("A small and lightweight text editor"); + static const gchar comments[] = \ + N_("A small and lightweight text editor"); - xed_debug (DEBUG_COMMANDS); + xed_debug (DEBUG_COMMANDS); - gtk_show_about_dialog(GTK_WINDOW(window), - "program-name", "xed", - "comments", _(comments), - "logo_icon_name", "accessories-text-editor", - "version", VERSION, - "website", "http://github.com/linuxmint/xed", - NULL); + gtk_show_about_dialog (GTK_WINDOW (window), + "program-name", "xed", + "comments", _(comments), + "logo_icon_name", "accessories-text-editor", + "version", VERSION, + "website", "http://github.com/linuxmint/xed", + NULL); } diff --git a/xed/xed-commands-search.c b/xed/xed-commands-search.c index 64f91b2..7d32444 100644 --- a/xed/xed-commands-search.c +++ b/xed/xed-commands-search.c @@ -25,14 +25,14 @@ void _xed_cmd_search_find (GtkAction *action, XedWindow *window) { - xed_searchbar_show (XED_SEARCHBAR (xed_window_get_searchbar (window)), SEARCH_MODE_SEARCH); + xed_searchbar_show (XED_SEARCHBAR (xed_window_get_searchbar (window)), XED_SEARCH_MODE_SEARCH); } void _xed_cmd_search_replace (GtkAction *action, XedWindow *window) { - xed_searchbar_show (XED_SEARCHBAR (xed_window_get_searchbar (window)), SEARCH_MODE_REPLACE); + xed_searchbar_show (XED_SEARCHBAR (xed_window_get_searchbar (window)), XED_SEARCH_MODE_REPLACE); } void diff --git a/xed/xed-commands.h b/xed/xed-commands.h index e25a5da..1977ddc 100644 --- a/xed/xed-commands.h +++ b/xed/xed-commands.h @@ -10,7 +10,7 @@ G_BEGIN_DECLS void xed_commands_load_location (XedWindow *window, GFile *location, const GtkSourceEncoding *encoding, gint line_pos); /* Ignore non-existing URIs */ -gint xed_commands_load_locations (XedWindow *window, const GSList *locations, const GtkSourceEncoding *encoding, gint line_pos); +GSList *xed_commands_load_locations (XedWindow *window, const GSList *locations, const GtkSourceEncoding *encoding, gint line_pos); void xed_commands_save_document (XedWindow *window, XedDocument *document); void xed_commands_save_all_documents (XedWindow *window); @@ -19,14 +19,13 @@ void xed_commands_save_all_documents (XedWindow *window); */ /* Create titled documens for non-existing URIs */ -gint _xed_cmd_load_files_from_prompt (XedWindow *window, GSList *files, const GtkSourceEncoding *encoding, gint line_pos); +GSList *_xed_cmd_load_files_from_prompt (XedWindow *window, GSList *files, const GtkSourceEncoding *encoding, gint line_pos); void _xed_cmd_file_new (GtkAction *action, XedWindow *window); void _xed_cmd_file_open (GtkAction *action, XedWindow *window); void _xed_cmd_file_save (GtkAction *action, XedWindow *window); void _xed_cmd_file_save_as (GtkAction *action, XedWindow *window); void _xed_cmd_file_save_all (GtkAction *action, XedWindow *window); void _xed_cmd_file_revert (GtkAction *action, XedWindow *window); -void _xed_cmd_file_open_uri (GtkAction *action, XedWindow *window); void _xed_cmd_file_print_preview (GtkAction *action, XedWindow *window); void _xed_cmd_file_print (GtkAction *action, XedWindow *window); void _xed_cmd_file_close (GtkAction *action, XedWindow *window); @@ -67,8 +66,6 @@ void _xed_cmd_help_about (GtkAction *action, XedWindow *window); void _xed_cmd_file_close_tab (XedTab *tab, XedWindow *window); -void _xed_cmd_file_save_documents_list (XedWindow *window, GList *docs); - G_END_DECLS #endif /* __XED_COMMANDS_H__ */ diff --git a/xed/xed-dirs.c b/xed/xed-dirs.c index 271a6cf..e2548a3 100644 --- a/xed/xed-dirs.c +++ b/xed/xed-dirs.c @@ -27,115 +27,115 @@ #include "xed-dirs.h" -gchar * +static gchar *user_config_dir = NULL; +static gchar *user_cache_dir = NULL; +static gchar *user_styles_dir = NULL; +static gchar *user_plugins_dir = NULL; +static gchar *xed_data_dir = NULL; +static gchar *xed_locale_dir = NULL; +static gchar *xed_lib_dir = NULL; +static gchar *xed_plugins_dir = NULL; +static gchar *xed_plugins_data_dir = NULL; + +void +xed_dirs_init () +{ + if (xed_data_dir == NULL) + { + xed_data_dir = g_build_filename (DATADIR, "xed", NULL); + xed_locale_dir = g_build_filename (DATADIR, "locale", NULL); + xed_lib_dir = g_build_filename (LIBDIR, "xed", NULL); + } + + user_cache_dir = g_build_filename (g_get_user_cache_dir (), "xed", NULL); + user_config_dir = g_build_filename (g_get_user_config_dir (), "xed", NULL); + user_styles_dir = g_build_filename (g_get_user_data_dir (), "xed", "styles", NULL); + user_plugins_dir = g_build_filename (g_get_user_data_dir (), "xed", "plugins", NULL); + xed_plugins_dir = g_build_filename (xed_lib_dir, "plugins", NULL); + xed_plugins_data_dir = g_build_filename (xed_data_dir, "plugins", NULL); +} + +void +xed_dirs_shutdown () +{ + g_free (user_config_dir); + g_free (user_cache_dir); + g_free (user_plugins_dir); + g_free (xed_data_dir); + g_free (xed_locale_dir); + g_free (xed_lib_dir); + g_free (xed_plugins_dir); + g_free (xed_plugins_data_dir); +} + +const gchar * xed_dirs_get_user_config_dir (void) { - gchar* config_dir = NULL; - - config_dir = g_build_filename(g_get_user_config_dir(), "xed", NULL); - - return config_dir; + return user_config_dir; } -gchar * +const gchar * xed_dirs_get_user_cache_dir (void) { - const gchar* cache_dir; - - cache_dir = g_get_user_cache_dir(); - - return g_build_filename(cache_dir, "xed", NULL); + return user_cache_dir; } -gchar * +const gchar * xed_dirs_get_user_styles_dir (void) { - gchar *user_style_dir; - - user_style_dir = g_build_filename (g_get_user_data_dir (), "xed", "styles", NULL); + return user_styles_dir; } -gchar * +const gchar * xed_dirs_get_user_plugins_dir (void) { - gchar* plugin_dir; - - plugin_dir = g_build_filename(g_get_user_data_dir(), "xed", "plugins", NULL); - - return plugin_dir; + return user_plugins_dir; } -gchar * -xed_dirs_get_user_accels_file (void) -{ - gchar* accels = NULL; - gchar *config_dir = NULL; - - config_dir = xed_dirs_get_user_config_dir(); - accels = g_build_filename(config_dir, "accels", NULL); - - g_free(config_dir); - - return accels; -} - -gchar * +const gchar * xed_dirs_get_xed_data_dir (void) { - return g_build_filename(DATADIR, "xed", NULL); + return xed_data_dir; } -gchar * +const gchar * xed_dirs_get_xed_locale_dir (void) { - return g_build_filename(DATADIR, "locale", NULL); + return xed_locale_dir; } -gchar * +const gchar * xed_dirs_get_xed_lib_dir (void) { - return g_build_filename(LIBDIR, "xed", NULL); + return xed_lib_dir; } -gchar * +const gchar * xed_dirs_get_xed_plugins_dir (void) { - gchar* lib_dir; - gchar* plugin_dir; - - lib_dir = xed_dirs_get_xed_lib_dir(); - - plugin_dir = g_build_filename(lib_dir, "plugins", NULL); - g_free(lib_dir); - - return plugin_dir; + return xed_plugins_dir; } -gchar * +const gchar * xed_dirs_get_xed_plugins_data_dir (void) { - gchar* data_dir; - gchar* plugin_data_dir; + return xed_plugins_data_dir; +} - data_dir = xed_dirs_get_xed_data_dir (); - - plugin_data_dir = g_build_filename (data_dir, "plugins", NULL); - g_free (data_dir); - - return plugin_data_dir; +const gchar * +xed_dirs_get_binding_modules_dir (void) +{ + return xed_lib_dir; } gchar * -xed_dirs_get_ui_file (const gchar* file) +xed_dirs_get_ui_file (const gchar *file) { - gchar* datadir; - gchar* ui_file; + gchar *ui_file; - g_return_val_if_fail(file != NULL, NULL); + g_return_val_if_fail (file != NULL, NULL); - datadir = xed_dirs_get_xed_data_dir(); - ui_file = g_build_filename(datadir, "ui", file, NULL); - g_free(datadir); + ui_file = g_build_filename (xed_dirs_get_xed_data_dir (), "ui", file, NULL); return ui_file; } diff --git a/xed/xed-dirs.h b/xed/xed-dirs.h index 97bcc6d..fed863a 100644 --- a/xed/xed-dirs.h +++ b/xed/xed-dirs.h @@ -28,25 +28,30 @@ G_BEGIN_DECLS -gchar *xed_dirs_get_user_config_dir (void); +/* This function must be called before starting xed */ +void xed_dirs_init (void); +/* This function must be called before exiting xed */ +void xed_dirs_shutdown (void); -gchar *xed_dirs_get_user_cache_dir (void); +const gchar *xed_dirs_get_user_config_dir (void); -gchar *xed_dirs_get_user_styles_dir (void); +const gchar *xed_dirs_get_user_cache_dir (void); -gchar *xed_dirs_get_user_plugins_dir (void); +const gchar *xed_dirs_get_user_styles_dir (void); -gchar *xed_dirs_get_user_accels_file (void); +const gchar *xed_dirs_get_user_plugins_dir (void); -gchar *xed_dirs_get_xed_data_dir (void); +const gchar *xed_dirs_get_xed_data_dir (void); -gchar *xed_dirs_get_xed_locale_dir (void); +const gchar *xed_dirs_get_xed_locale_dir (void); -gchar *xed_dirs_get_xed_lib_dir (void); +const gchar *xed_dirs_get_xed_lib_dir (void); -gchar *xed_dirs_get_xed_plugins_dir (void); +const gchar *xed_dirs_get_xed_plugins_dir (void); -gchar *xed_dirs_get_xed_plugins_data_dir (void); +const gchar *xed_dirs_get_xed_plugins_data_dir (void); + +const gchar *xed_dirs_get_binding_modules_dir (void); gchar *xed_dirs_get_ui_file (const gchar *file); diff --git a/xed/xed-document.c b/xed/xed-document.c index 41522bb..30a5fa9 100644 --- a/xed/xed-document.c +++ b/xed/xed-document.c @@ -510,6 +510,12 @@ save_encoding_metadata (XedDocument *doc) xed_debug (DEBUG_DOCUMENT); encoding = gtk_source_file_get_encoding (doc->priv->file); + + if (encoding == NULL) + { + encoding = gtk_source_encoding_get_utf8 (); + } + charset = gtk_source_encoding_get_charset (encoding); xed_document_set_metadata (doc, XED_METADATA_ATTRIBUTE_ENCODING, charset, NULL); @@ -954,8 +960,6 @@ loaded_query_info_cb (GFile *location, XedDocument *doc) { GFileInfo *info; - const gchar *content_type = NULL; - gboolean read_only = FALSE; GError *error = NULL; info = g_file_query_info_finish (location, result, &error); @@ -974,18 +978,22 @@ loaded_query_info_cb (GFile *location, error = NULL; } - doc->priv->mtime_set = FALSE; - if (info != NULL) { if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE)) { + const gchar *content_type; + content_type = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE); + xed_document_set_content_type (doc, content_type); } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE)) { + gboolean read_only; + read_only = !g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE); + set_readonly (doc, read_only); } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_TIME_MODIFIED)) @@ -993,22 +1001,19 @@ loaded_query_info_cb (GFile *location, g_file_info_get_modification_time (info, &doc->priv->mtime); doc->priv->mtime_set = TRUE; } - } - set_readonly (doc, read_only); - - g_get_current_time (&doc->priv->time_of_last_save_or_load); - - doc->priv->externally_modified = FALSE; - doc->priv->deleted = FALSE; - - xed_document_set_content_type (doc, content_type); - - if (info != NULL) - { g_object_unref (info); } + /* Async operation finished. */ + g_object_unref (doc); +} + +static void +xed_document_loaded_real (XedDocument *doc) +{ + GFile *location; + if (!doc->priv->language_set_by_user) { GtkSourceLanguage *language = guess_language (doc); @@ -1019,27 +1024,33 @@ loaded_query_info_cb (GFile *location, set_language (doc, language, FALSE); } - /* Async operation finished. */ - g_object_unref (doc); -} + doc->priv->mtime_set = FALSE; + doc->priv->externally_modified = FALSE; + doc->priv->deleted = FALSE; -static void -xed_document_loaded_real (XedDocument *doc) -{ - GFile *location = gtk_source_file_get_location (doc->priv->file); + g_get_current_time (&doc->priv->time_of_last_save_or_load); - /* Keep the doc alive during the async operation. */ - g_object_ref (doc); + set_readonly (doc, FALSE); - g_file_query_info_async (location, - G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," - G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE "," - G_FILE_ATTRIBUTE_TIME_MODIFIED, - G_FILE_QUERY_INFO_NONE, - G_PRIORITY_DEFAULT, - NULL, - (GAsyncReadyCallback) loaded_query_info_cb, - doc); + xed_document_set_content_type (doc, NULL); + + location = gtk_source_file_get_location (doc->priv->file); + + if (location != NULL) + { + /* Keep the doc alive during the async operation. */ + g_object_ref (doc); + + g_file_query_info_async (location, + G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," + G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE "," + G_FILE_ATTRIBUTE_TIME_MODIFIED, + G_FILE_QUERY_INFO_NONE, + G_PRIORITY_DEFAULT, + NULL, + (GAsyncReadyCallback) loaded_query_info_cb, + doc); + } } static void @@ -1191,9 +1202,11 @@ check_file_on_disk (XedDocument *doc) g_file_info_get_modification_time (info, &timeval); - if (timeval.tv_sec > doc->priv->mtime.tv_sec || - (timeval.tv_sec == doc->priv->mtime.tv_sec && - timeval.tv_usec > doc->priv->mtime.tv_usec)) + /* Note that mtime can even go backwards if the + * user is copying over a file with an old mtime + */ + if (timeval.tv_sec != doc->priv->mtime.tv_sec || + timeval.tv_usec != doc->priv->mtime.tv_usec) { doc->priv->externally_modified = TRUE; } diff --git a/xed/xed-help.c b/xed/xed-help.c deleted file mode 100644 index a904910..0000000 --- a/xed/xed-help.c +++ /dev/null @@ -1,99 +0,0 @@ -/* - * xed-help.c - * This file is part of xed - * - * Copyright (C) 2005 - Paolo Maggi - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -/* - * Modified by the xed Team, 2005. See the AUTHORS file for a - * list of people on the xed Team. - * See the ChangeLog files for a list of changes. - * - * $Id$ - */ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "xed-help.h" - -#include -#include -#include - -gboolean -xed_help_display (GtkWindow *parent, - const gchar *name, /* "xed" if NULL */ - const gchar *link_id) -{ - GError *error = NULL; - gboolean ret; - gchar *link; - - g_return_val_if_fail ((parent == NULL) || GTK_IS_WINDOW (parent), FALSE); - - if (name == NULL) - name = "xed"; - else if (strcmp (name, "xed.xml") == 0) - { - g_warning ("%s: Using \"xed.xml\" for the help name is deprecated, use \"xed\" or simply NULL instead", G_STRFUNC); - - name = "xed"; - } - - if (link_id) - link = g_strdup_printf ("help:%s/%s", name, link_id); - else - link = g_strdup_printf ("help:%s", name); - - ret = gtk_show_uri (gtk_widget_get_screen (GTK_WIDGET (parent)), - link, - GDK_CURRENT_TIME, - &error); - - g_free (link); - - if (error != NULL) - { - GtkWidget *dialog; - - dialog = gtk_message_dialog_new (parent, - GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_MESSAGE_ERROR, - GTK_BUTTONS_CLOSE, - _("There was an error displaying the help.")); - - gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), - "%s", error->message); - - g_signal_connect (G_OBJECT (dialog), - "response", - G_CALLBACK (gtk_widget_destroy), - NULL); - - gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); - - gtk_widget_show (dialog); - - g_error_free (error); - } - - return ret; -} diff --git a/xed/xed-help.h b/xed/xed-help.h deleted file mode 100644 index 2325589..0000000 --- a/xed/xed-help.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * xed-help.h - * This file is part of xed - * - * Copyright (C) 2005 - Paolo Maggi - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -/* - * Modified by the xed Team, 2005. See the AUTHORS file for a - * list of people on the xed Team. - * See the ChangeLog files for a list of changes. - * - * $Id$ - */ - -#ifndef __XED_HELP_H__ -#define __XED_HELP_H__ - -#include - -G_BEGIN_DECLS - -gboolean xed_help_display (GtkWindow *parent, - const gchar *name, /* "xed" if NULL */ - const gchar *link_id); - -G_END_DECLS - -#endif /* __XED_HELP_H__ */ diff --git a/xed/xed-metadata-manager.c b/xed/xed-metadata-manager.c index 16192e0..01d491e 100644 --- a/xed/xed-metadata-manager.c +++ b/xed/xed-metadata-manager.c @@ -27,23 +27,16 @@ * See the ChangeLog files for a list of changes. */ -#ifdef HAVE_CONFIG_H -#include -#endif - #include #include #include #include "xed-metadata-manager.h" #include "xed-debug.h" -#include "xed-dirs.h" /* #define XED_METADATA_VERBOSE_DEBUG 1 */ -#define METADATA_FILE "xed-metadata.xml" - #define MAX_ITEMS 50 typedef struct _XedMetadataManager XedMetadataManager; @@ -65,6 +58,8 @@ struct _XedMetadataManager guint timeout_id; GHashTable *items; + + gchar *metadata_filename; }; static gboolean xed_metadata_manager_save (gpointer data); @@ -105,13 +100,20 @@ xed_metadata_manager_arm_timeout (void) } } -static gboolean -xed_metadata_manager_init (void) +/** + * xed_metadata_manager_init: + * @metadata_filename: the filename where the metadata is. + * + * This function initializes the metadata manager. + * See also xed_metadata_manager_shutdown(). + */ +void +xed_metadata_manager_init (const gchar *metadata_filename) { xed_debug (DEBUG_METADATA); if (xed_metadata_manager != NULL) - return TRUE; + return; xed_metadata_manager = g_new0 (XedMetadataManager, 1); @@ -123,10 +125,17 @@ xed_metadata_manager_init (void) g_free, item_free); - return TRUE; + xed_metadata_manager->metadata_filename = g_strdup (metadata_filename); + + return; } -/* This function must be called before exiting xed */ +/** + * xed_metadata_manager_shutdown: + * + * This function frees the internal data of the metadata manager. + * See also xed_metadata_manager_init(). + */ void xed_metadata_manager_shutdown (void) { @@ -145,6 +154,7 @@ xed_metadata_manager_shutdown (void) if (xed_metadata_manager->items != NULL) g_hash_table_destroy (xed_metadata_manager->items); + g_free (gedit_metadata_manager->metadata_filename); g_free (xed_metadata_manager); xed_metadata_manager = NULL; } @@ -218,29 +228,11 @@ parseItem (xmlDocPtr doc, xmlNodePtr cur) xmlFree (atime); } -static gchar * -get_metadata_filename (void) -{ - gchar *cache_dir; - gchar *metadata; - - cache_dir = xed_dirs_get_user_cache_dir (); - - metadata = g_build_filename (cache_dir, - METADATA_FILE, - NULL); - - g_free (cache_dir); - - return metadata; -} - static gboolean load_values (void) { xmlDocPtr doc; xmlNodePtr cur; - gchar *file_name; xed_debug (DEBUG_METADATA); @@ -252,16 +244,13 @@ load_values (void) xmlKeepBlanksDefault (0); /* FIXME: file locking - Paolo */ - file_name = get_metadata_filename (); - if ((file_name == NULL) || - (!g_file_test (file_name, G_FILE_TEST_EXISTS))) + if ((xed_metadata_manager->metadata_filename == NULL) || + (!g_file_test (xed_metadata_manager->metadata_filename, G_FILE_TEST_EXISTS))) { - g_free (file_name); return FALSE; } - doc = xmlParseFile (file_name); - g_free (file_name); + doc = xmlParseFile (xed_metadata_manager->metadata_filename); if (doc == NULL) { @@ -271,7 +260,7 @@ load_values (void) cur = xmlDocGetRootElement (doc); if (cur == NULL) { - g_message ("The metadata file '%s' is empty", METADATA_FILE); + g_message ("The metadata file '%s' is empty", g_path_get_basename (xed_metadata_manager->metadata_filename)); xmlFreeDoc (doc); return FALSE; @@ -279,7 +268,7 @@ load_values (void) if (xmlStrcmp (cur->name, (const xmlChar *) "metadata")) { - g_message ("File '%s' is of the wrong type", METADATA_FILE); + g_message ("File '%s' is of the wrong type", g_path_get_basename (xed_metadata_manager->metadata_filename)); xmlFreeDoc (doc); return FALSE; @@ -300,6 +289,13 @@ load_values (void) return TRUE; } +/** + * xed_metadata_manager_get: + * @location: a #GFile. + * @key: a key. + * + * Gets the value associated with the specified @key for the file @location. + */ gchar * xed_metadata_manager_get (GFile *location, const gchar *key) @@ -315,8 +311,6 @@ xed_metadata_manager_get (GFile *location, xed_debug_message (DEBUG_METADATA, "URI: %s --- key: %s", uri, key ); - xed_metadata_manager_init (); - if (!xed_metadata_manager->values_loaded) { gboolean res; @@ -348,6 +342,14 @@ xed_metadata_manager_get (GFile *location, return g_strdup (value); } +/** + * xed_metadata_manager_set: + * @location: a #GFile. + * @key: a key. + * @value: the value associated with the @key. + * + * Sets the @key to contain the given @value for the file @location. + */ void xed_metadata_manager_set (GFile *location, const gchar *key, @@ -363,8 +365,6 @@ xed_metadata_manager_set (GFile *location, xed_debug_message (DEBUG_METADATA, "URI: %s --- key: %s --- value: %s", uri, key, value); - xed_metadata_manager_init (); - if (!xed_metadata_manager->values_loaded) { gboolean res; @@ -523,7 +523,6 @@ xed_metadata_manager_save (gpointer data) { xmlDocPtr doc; xmlNodePtr root; - gchar *file_name; xed_debug (DEBUG_METADATA); @@ -546,22 +545,20 @@ xed_metadata_manager_save (gpointer data) root); /* FIXME: lock file - Paolo */ - file_name = get_metadata_filename (); - if (file_name != NULL) + if (xed_metadata_manager->metadata_filename != NULL) { gchar *cache_dir; int res; /* make sure the cache dir exists */ - cache_dir = xed_dirs_get_user_cache_dir (); + cache_dir = g_path_get_dirname (xed_metadata_manager->metadata_filename); res = g_mkdir_with_parents (cache_dir, 0755); if (res != -1) { - xmlSaveFormatFile (file_name, doc, 1); + xmlSaveFormatFile (xed_metadata_manager->metadata_filename, doc, 1); } g_free (cache_dir); - g_free (file_name); } xmlFreeDoc (doc); diff --git a/xed/xed-metadata-manager.h b/xed/xed-metadata-manager.h index eef8f1f..dd682f7 100644 --- a/xed/xed-metadata-manager.h +++ b/xed/xed-metadata-manager.h @@ -34,16 +34,17 @@ G_BEGIN_DECLS +void xed_metadata_manager_init (const gchar *metadata_filename); /* This function must be called before exiting xed */ -void xed_metadata_manager_shutdown (void); +void xed_metadata_manager_shutdown (void); +gchar *xed_metadata_manager_get (GFile *location, + const gchar *key); -gchar *xed_metadata_manager_get (GFile *location, - const gchar *key); -void xed_metadata_manager_set (GFile *location, - const gchar *key, - const gchar *value); +void xed_metadata_manager_set (GFile *location, + const gchar *key, + const gchar *value); G_END_DECLS diff --git a/xed/xed-searchbar.c b/xed/xed-searchbar.c index 97ac60a..474c0e2 100755 --- a/xed/xed-searchbar.c +++ b/xed/xed-searchbar.c @@ -54,7 +54,7 @@ struct _XedSearchbarPrivate GtkWidget *close_button; GtkSourceSearchSettings *search_settings; - SearchMode search_mode; + XedSearchMode search_mode; guint update_occurrence_count_id; }; @@ -280,7 +280,7 @@ update_occurrence_count (XedSearchbar *searchbar) gint count; gint pos; - if (searchbar->priv->search_mode == SEARCH_MODE_REPLACE) + if (searchbar->priv->search_mode == XED_SEARCH_MODE_REPLACE) { return; } @@ -376,7 +376,7 @@ do_find (XedSearchbar *searchbar, search_settings = xed_searchbar_get_search_settings (searchbar); doc = xed_window_get_active_document (searchbar->window); search_context = xed_document_get_search_context (doc); - searchbar->priv->search_mode = SEARCH_MODE_SEARCH; + searchbar->priv->search_mode = XED_SEARCH_MODE_SEARCH; if (search_context == NULL || search_settings != gtk_source_search_context_get_settings (search_context)) { @@ -487,7 +487,7 @@ do_replace (XedSearchbar *searchbar) unescaped_replace_text = gtk_source_utils_unescape_search_text (replace_entry_text); gtk_text_buffer_get_selection_bounds (GTK_TEXT_BUFFER (doc), &start, &end); - searchbar->priv->search_mode = SEARCH_MODE_REPLACE; + searchbar->priv->search_mode = XED_SEARCH_MODE_REPLACE; gtk_source_search_context_replace (search_context, &start, @@ -530,7 +530,7 @@ do_replace_all (XedSearchbar *searchbar) unescaped_replace_text = gtk_source_utils_unescape_search_text (replace_entry_text); count = gtk_source_search_context_replace_all (search_context, unescaped_replace_text, -1, NULL); - searchbar->priv->search_mode = SEARCH_MODE_REPLACE; + searchbar->priv->search_mode = XED_SEARCH_MODE_REPLACE; g_free (unescaped_replace_text); @@ -799,8 +799,8 @@ xed_searchbar_new (GtkWindow *parent) } void -xed_searchbar_show (XedSearchbar *searchbar, - SearchMode search_mode) +xed_searchbar_show (XedSearchbar *searchbar, + XedSearchMode search_mode) { XedDocument *doc; gboolean selection_exists; @@ -835,7 +835,7 @@ xed_searchbar_show (XedSearchbar *searchbar, gtk_revealer_set_transition_type (GTK_REVEALER (searchbar->priv->revealer), GTK_REVEALER_TRANSITION_TYPE_SLIDE_UP); gtk_revealer_set_reveal_child (GTK_REVEALER (searchbar->priv->revealer), TRUE); - if (search_mode == SEARCH_MODE_REPLACE) + if (search_mode == XED_SEARCH_MODE_REPLACE) { gtk_widget_show (searchbar->priv->replace_label); gtk_widget_show (searchbar->priv->replace_entry); diff --git a/xed/xed-searchbar.h b/xed/xed-searchbar.h index a4d92e6..fd0e755 100755 --- a/xed/xed-searchbar.h +++ b/xed/xed-searchbar.h @@ -39,16 +39,16 @@ struct _XedSearchbarClass typedef enum { - SEARCH_MODE_SEARCH, - SEARCH_MODE_REPLACE -} SearchMode; + XED_SEARCH_MODE_SEARCH, + XED_SEARCH_MODE_REPLACE +} XedSearchMode; GType xed_searchbar_get_type (void) G_GNUC_CONST; GtkWidget *xed_searchbar_new (GtkWindow *parent); void xed_searchbar_hide (XedSearchbar *searchbar); -void xed_searchbar_show (XedSearchbar *searchbar, SearchMode search_mode); +void xed_searchbar_show (XedSearchbar *searchbar, XedSearchMode search_mode); void xed_searchbar_find_again (XedSearchbar *searchbar, gboolean backward); const gchar *xed_searchbar_get_replace_text (XedSearchbar *searchbar); diff --git a/xed/xed-session.c b/xed/xed-session.c deleted file mode 100644 index 3f57e27..0000000 --- a/xed/xed-session.c +++ /dev/null @@ -1,618 +0,0 @@ -/* - * xed-session.c - Basic session management for xed - * This file is part of xed - * - * Copyright (C) 2002 Ximian, Inc. - * Copyright (C) 2005 - Paolo Maggi - * - * Author: Federico Mena-Quintero - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -/* - * Modified by the xed Team, 2002-2005. See the AUTHORS file for a - * list of people on the xed Team. - * See the ChangeLog files for a list of changes. - * - * $Id$ - */ - - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include -#include - -#include "xed-session.h" - -#include "xed-debug.h" -#include "xed-plugins-engine.h" -#include "xed-metadata-manager.h" -#include "xed-window.h" -#include "xed-app.h" -#include "xed-commands.h" -#include "dialogs/xed-close-confirmation-dialog.h" -#include "smclient/eggsmclient.h" - -/* The master client we use for SM */ -static EggSMClient *master_client = NULL; - -/* global var used during quit_requested */ -static GSList *window_dirty_list; - -static void ask_next_confirmation (void); - -#define XED_SESSION_LIST_OF_DOCS_TO_SAVE "xed-session-list-of-docs-to-save-key" - -static void -save_window_session (GKeyFile *state_file, - const gchar *group_name, - XedWindow *window) -{ - const gchar *role; - int width, height; - XedPanel *panel; - GList *docs, *l; - GPtrArray *doc_array; - XedDocument *active_document; - gchar *uri = NULL; - - xed_debug (DEBUG_SESSION); - - role = gtk_window_get_role (GTK_WINDOW (window)); - g_key_file_set_string (state_file, group_name, "role", role); - gtk_window_get_size (GTK_WINDOW (window), &width, &height); - g_key_file_set_integer (state_file, group_name, "width", width); - g_key_file_set_integer (state_file, group_name, "height", height); - - panel = xed_window_get_side_panel (window); - g_key_file_set_boolean (state_file, group_name, "side-panel-visible", - gtk_widget_get_visible (GTK_WIDGET (panel))); - - panel = xed_window_get_bottom_panel (window); - g_key_file_set_boolean (state_file, group_name, "bottom-panel-visible", - gtk_widget_get_visible (GTK_WIDGET (panel))); - - active_document = xed_window_get_active_document (window); - if (active_document) - { - GFile *location; - - location = xed_document_get_location (active_document); - if (location) - { - uri = g_file_get_uri (location); - g_object_unref (location); - } - - g_key_file_set_string (state_file, group_name, "active-document", uri); - g_free (uri); - } - - docs = xed_window_get_documents (window); - - doc_array = g_ptr_array_new (); - for (l = docs; l != NULL; l = g_list_next (l)) - { - GFile *location; - - location = xed_document_get_location (XED_DOCUMENT (l->data)); - if (location) - { - uri = g_file_get_uri (location); - g_object_unref (location); - } - - if (uri != NULL) - { - g_ptr_array_add (doc_array, uri); - } - - } - g_list_free (docs); - - if (doc_array->len) - { - g_key_file_set_string_list (state_file, group_name, - "documents", - (const char **)doc_array->pdata, - doc_array->len); - g_ptr_array_foreach (doc_array, (GFunc) g_free, NULL); - } - g_ptr_array_free (doc_array, TRUE); -} - -static void -client_save_state_cb (EggSMClient *client, - GKeyFile *state_file, - gpointer user_data) -{ - const GList *windows; - gchar *group_name; - int n; - - windows = xed_app_get_windows (xed_app_get_default ()); - n = 1; - - while (windows != NULL) - { - group_name = g_strdup_printf ("xed window %d", n); - save_window_session (state_file, - group_name, - XED_WINDOW (windows->data)); - g_free (group_name); - - windows = g_list_next (windows); - n++; - } -} - -static void -window_handled (XedWindow *window) -{ - window_dirty_list = g_slist_remove (window_dirty_list, window); - - /* whee... we made it! */ - if (window_dirty_list == NULL) - egg_sm_client_will_quit (master_client, TRUE); - else - ask_next_confirmation (); -} - -static void -window_state_change (XedWindow *window, - GParamSpec *pspec, - gpointer data) -{ - XedWindowState state; - GList *unsaved_docs; - GList *docs_to_save; - GList *l; - gboolean done = TRUE; - - state = xed_window_get_state (window); - - /* we are still saving */ - if (state & XED_WINDOW_STATE_SAVING) - return; - - unsaved_docs = xed_window_get_unsaved_documents (window); - - docs_to_save = g_object_get_data (G_OBJECT (window), - XED_SESSION_LIST_OF_DOCS_TO_SAVE); - - - for (l = docs_to_save; l != NULL; l = l->next) - { - if (g_list_find (unsaved_docs, l->data)) - { - done = FALSE; - break; - } - } - - if (done) - { - g_signal_handlers_disconnect_by_func (window, window_state_change, data); - g_list_free (docs_to_save); - g_object_set_data (G_OBJECT (window), - XED_SESSION_LIST_OF_DOCS_TO_SAVE, - NULL); - - window_handled (window); - } - - g_list_free (unsaved_docs); -} - -static void -close_confirmation_dialog_response_handler (XedCloseConfirmationDialog *dlg, - gint response_id, - XedWindow *window) -{ - GList *selected_documents; - GSList *l; - - xed_debug (DEBUG_COMMANDS); - - switch (response_id) - { - case GTK_RESPONSE_YES: - /* save selected docs */ - - g_signal_connect (window, - "notify::state", - G_CALLBACK (window_state_change), - NULL); - - selected_documents = xed_close_confirmation_dialog_get_selected_documents (dlg); - - g_return_if_fail (g_object_get_data (G_OBJECT (window), - XED_SESSION_LIST_OF_DOCS_TO_SAVE) == NULL); - - g_object_set_data (G_OBJECT (window), - XED_SESSION_LIST_OF_DOCS_TO_SAVE, - selected_documents); - - _xed_cmd_file_save_documents_list (window, selected_documents); - - /* FIXME: also need to lock the window to prevent further changes... */ - - break; - - case GTK_RESPONSE_NO: - /* dont save */ - window_handled (window); - break; - - default: - /* disconnect window_state_changed where needed */ - for (l = window_dirty_list; l != NULL; l = l->next) - g_signal_handlers_disconnect_by_func (window, - window_state_change, NULL); - g_slist_free (window_dirty_list); - window_dirty_list = NULL; - - /* cancel shutdown */ - egg_sm_client_will_quit (master_client, FALSE); - - break; - } - - gtk_widget_destroy (GTK_WIDGET (dlg)); -} - -static void -show_confirmation_dialog (XedWindow *window) -{ - GList *unsaved_docs; - GtkWidget *dlg; - - xed_debug (DEBUG_SESSION); - - unsaved_docs = xed_window_get_unsaved_documents (window); - - g_return_if_fail (unsaved_docs != NULL); - - if (unsaved_docs->next == NULL) - { - /* There is only one unsaved document */ - XedTab *tab; - XedDocument *doc; - - doc = XED_DOCUMENT (unsaved_docs->data); - - tab = xed_tab_get_from_document (doc); - g_return_if_fail (tab != NULL); - - xed_window_set_active_tab (window, tab); - - dlg = xed_close_confirmation_dialog_new_single ( - GTK_WINDOW (window), - doc, - TRUE); - } - else - { - dlg = xed_close_confirmation_dialog_new (GTK_WINDOW (window), - unsaved_docs, - TRUE); - } - - g_list_free (unsaved_docs); - - g_signal_connect (dlg, - "response", - G_CALLBACK (close_confirmation_dialog_response_handler), - window); - - gtk_widget_show (dlg); -} - -static void -ask_next_confirmation (void) -{ - g_return_if_fail (window_dirty_list != NULL); - - /* pop up the confirmation dialog for the first window - * in the dirty list. The next confirmation is asked once - * this one has been handled. - */ - show_confirmation_dialog (XED_WINDOW (window_dirty_list->data)); -} - -/* quit_requested handler for the master client */ -static void -client_quit_requested_cb (EggSMClient *client, gpointer data) -{ - XedApp *app; - const GList *l; - - xed_debug (DEBUG_SESSION); - - app = xed_app_get_default (); - - if (window_dirty_list != NULL) - { - g_critical ("global variable window_dirty_list not NULL"); - window_dirty_list = NULL; - } - - for (l = xed_app_get_windows (app); l != NULL; l = l->next) - { - if (xed_window_get_unsaved_documents (XED_WINDOW (l->data)) != NULL) - { - window_dirty_list = g_slist_prepend (window_dirty_list, l->data); - } - } - - /* no modified docs */ - if (window_dirty_list == NULL) - { - egg_sm_client_will_quit (client, TRUE); - - return; - } - - ask_next_confirmation (); - - xed_debug_message (DEBUG_SESSION, "END"); -} - -/* quit handler for the master client */ -static void -client_quit_cb (EggSMClient *client, gpointer data) -{ -#if 0 - xed_debug (DEBUG_SESSION); - - if (!client->save_yourself_emitted) - xed_file_close_all (); - - xed_debug_message (DEBUG_FILE, "All files closed."); - - matecomponent_mdi_destroy (MATECOMPONENT_MDI (xed_mdi)); - - xed_debug_message (DEBUG_FILE, "Unref xed_mdi."); - - g_object_unref (G_OBJECT (xed_mdi)); - - xed_debug_message (DEBUG_FILE, "Unref xed_mdi: DONE"); - - xed_debug_message (DEBUG_FILE, "Unref xed_app_server."); - - matecomponent_object_unref (xed_app_server); - - xed_debug_message (DEBUG_FILE, "Unref xed_app_server: DONE"); -#endif - - gtk_main_quit (); -} - -/** - * xed_session_init: - * - * Initializes session management support. This function should be called near - * the beginning of the program. - **/ -void -xed_session_init (void) -{ - xed_debug (DEBUG_SESSION); - - if (master_client) - return; - - master_client = egg_sm_client_get (); - g_signal_connect (master_client, - "save_state", - G_CALLBACK (client_save_state_cb), - NULL); - g_signal_connect (master_client, - "quit_requested", - G_CALLBACK (client_quit_requested_cb), - NULL); - g_signal_connect (master_client, - "quit", - G_CALLBACK (client_quit_cb), - NULL); -} - -/** - * xed_session_is_restored: - * - * Returns whether this xed is running from a restarted session. - * - * Return value: TRUE if the session manager restarted us, FALSE otherwise. - * This should be used to determine whether to pay attention to command line - * arguments in case the session was not restored. - **/ -gboolean -xed_session_is_restored (void) -{ - gboolean restored; - - xed_debug (DEBUG_SESSION); - - if (!master_client) - return FALSE; - - restored = egg_sm_client_is_resumed (master_client); - - xed_debug_message (DEBUG_SESSION, restored ? "RESTORED" : "NOT RESTORED"); - - return restored; -} - -static void -parse_window (GKeyFile *state_file, const char *group_name) -{ - XedWindow *window; - gchar *role, *active_document, **documents; - int width, height; - gboolean visible; - XedPanel *panel; - GError *error = NULL; - - role = g_key_file_get_string (state_file, group_name, "role", NULL); - - xed_debug_message (DEBUG_SESSION, "Window role: %s", role); - - window = _xed_app_restore_window (xed_app_get_default (), (gchar *) role); - g_free (role); - - if (window == NULL) - { - g_warning ("Couldn't restore window"); - return; - } - - width = g_key_file_get_integer (state_file, group_name, - "width", &error); - if (error) - { - g_clear_error (&error); - width = -1; - } - height = g_key_file_get_integer (state_file, group_name, - "height", &error); - if (error) - { - g_clear_error (&error); - height = -1; - } - gtk_window_set_default_size (GTK_WINDOW (window), width, height); - - - visible = g_key_file_get_boolean (state_file, group_name, - "side-panel-visible", &error); - if (error) - { - g_clear_error (&error); - visible = FALSE; - } - - panel = xed_window_get_side_panel (window); - - if (visible) - { - xed_debug_message (DEBUG_SESSION, "Side panel visible"); - gtk_widget_show (GTK_WIDGET (panel)); - } - else - { - xed_debug_message (DEBUG_SESSION, "Side panel _NOT_ visible"); - gtk_widget_hide (GTK_WIDGET (panel)); - } - - visible = g_key_file_get_boolean (state_file, group_name, - "bottom-panel-visible", &error); - if (error) - { - g_clear_error (&error); - visible = FALSE; - } - - panel = xed_window_get_bottom_panel (window); - if (visible) - { - xed_debug_message (DEBUG_SESSION, "Bottom panel visible"); - gtk_widget_show (GTK_WIDGET (panel)); - } - else - { - xed_debug_message (DEBUG_SESSION, "Bottom panel _NOT_ visible"); - gtk_widget_hide (GTK_WIDGET (panel)); - } - - active_document = g_key_file_get_string (state_file, group_name, - "active-document", NULL); - documents = g_key_file_get_string_list (state_file, group_name, - "documents", NULL, NULL); - if (documents) - { - gint i; - gboolean jump_to = FALSE; - - for (i = 0; documents[i]; i++) - { - GFile *location; - - if (active_document != NULL) - { - jump_to = strcmp (active_document, documents[i]) == 0; - } - - xed_debug_message (DEBUG_SESSION, - "URI: %s (%s)", - documents[i], - jump_to ? "active" : "not active"); - - location = g_file_new_for_uri (documents[i]); - xed_window_create_tab_from_location (window, location, NULL, 0, FALSE, jump_to); - if (location) - { - g_object_unref (location); - } - } - g_strfreev (documents); - } - - g_free (active_document); - - gtk_widget_show (GTK_WIDGET (window)); -} - -/** - * xed_session_load: - * - * Loads the session by fetching the necessary information from the session - * manager and opening files. - * - * Return value: TRUE if the session was loaded successfully, FALSE otherwise. - **/ -gboolean -xed_session_load (void) -{ - GKeyFile *state_file; - gchar **groups; - int i; - - xed_debug (DEBUG_SESSION); - - state_file = egg_sm_client_get_state_file (master_client); - if (state_file == NULL) - return FALSE; - - groups = g_key_file_get_groups (state_file, NULL); - - for (i = 0; groups[i] != NULL; i++) - { - if (g_str_has_prefix (groups[i], "xed window ")) - parse_window (state_file, groups[i]); - } - - g_strfreev (groups); - g_key_file_free (state_file); - - return TRUE; -} diff --git a/xed/xed-session.h b/xed/xed-session.h deleted file mode 100644 index e8f5822..0000000 --- a/xed/xed-session.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * xed-session.h - Basic session management for xed - * This file is part of xed - * - * Copyright (C) 2002 Ximian, Inc. - * Copyright (C) 2005 - Paolo Maggi - * - * Author: Federico Mena-Quintero - * - * 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 - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -/* - * Modified by the xed Team, 2002-2005. See the AUTHORS file for a - * list of people on the xed Team. - * See the ChangeLog files for a list of changes. - * - * $Id - */ - -#ifndef __XED_SESSION_H__ -#define __XED_SESSION_H__ - -#include - -G_BEGIN_DECLS - -void xed_session_init (void); -gboolean xed_session_is_restored (void); -gboolean xed_session_load (void); - -G_END_DECLS - -#endif /* __XED_SESSION_H__ */ diff --git a/xed/xed-settings.c b/xed/xed-settings.c index c3eac5a..b484aeb 100644 --- a/xed/xed-settings.c +++ b/xed/xed-settings.c @@ -96,7 +96,7 @@ set_font (XedSettings *xs, ts = g_settings_get_uint (xs->priv->editor, XED_SETTINGS_TABS_SIZE); - views = xed_app_get_views (xed_app_get_default ()); + views = xed_app_get_views (XED_APP (g_application_get_default ())); for (l = views; l != NULL; l = g_list_next (l)) { @@ -213,7 +213,7 @@ on_scheme_changed (GSettings *settings, } } - docs = xed_app_get_documents (xed_app_get_default ()); + docs = xed_app_get_documents (XED_APP (g_application_get_default ())); for (l = docs; l != NULL; l = g_list_next (l)) { g_return_if_fail (GTK_SOURCE_IS_BUFFER (l->data)); @@ -234,7 +234,7 @@ on_auto_save_changed (GSettings *settings, auto_save = g_settings_get_boolean (settings, key); - docs = xed_app_get_documents (xed_app_get_default ()); + docs = xed_app_get_documents (XED_APP (g_application_get_default ())); for (l = docs; l != NULL; l = g_list_next (l)) { @@ -256,7 +256,7 @@ on_auto_save_interval_changed (GSettings *settings, g_settings_get (settings, key, "u", &auto_save_interval); - docs = xed_app_get_documents (xed_app_get_default ()); + docs = xed_app_get_documents (XED_APP (g_application_get_default ())); for (l = docs; l != NULL; l = g_list_next (l)) { @@ -278,7 +278,7 @@ on_wrap_mode_changed (GSettings *settings, wrap_mode = g_settings_get_enum (settings, key); - views = xed_app_get_views (xed_app_get_default ()); + views = xed_app_get_views (XED_APP (g_application_get_default ())); for (l = views; l != NULL; l = g_list_next (l)) { @@ -293,13 +293,12 @@ on_syntax_highlighting_changed (GSettings *settings, const gchar *key, XedSettings *xs) { - const GList *windows; - GList *docs, *l; + GList *docs, *windows, *l; gboolean enable; enable = g_settings_get_boolean (settings, key); - docs = xed_app_get_documents (xed_app_get_default ()); + docs = xed_app_get_documents (XED_APP (g_application_get_default ())); for (l = docs; l != NULL; l = g_list_next (l)) { @@ -309,20 +308,20 @@ on_syntax_highlighting_changed (GSettings *settings, g_list_free (docs); /* update the sensitivity of the Higlight Mode menu item */ - windows = xed_app_get_windows (xed_app_get_default ()); - while (windows != NULL) + windows = xed_app_get_main_windows (XED_APP (g_application_get_default ())); + for (l = windows; l != NULL; l = g_list_next (l)) { GtkUIManager *ui; GtkAction *a; - ui = xed_window_get_ui_manager (XED_WINDOW (windows->data)); + ui = xed_window_get_ui_manager (XED_WINDOW (l->data)); a = gtk_ui_manager_get_action (ui, "/MenuBar/ViewMenu/ViewHighlightModeMenu"); gtk_action_set_sensitive (a, enable); - - windows = g_list_next (windows); } + + g_list_free (windows); } static void @@ -335,7 +334,7 @@ on_enable_tab_scrolling_changed (GSettings *settings, enable = g_settings_get_boolean (settings, key); - windows = xed_app_get_windows (xed_app_get_default ()); + windows = xed_app_get_main_windows (XED_APP (g_application_get_default ())); while (windows != NULL) { XedNotebook *notebook; diff --git a/xed/xed-tab.c b/xed/xed-tab.c index 32c59ee..ee146a6 100644 --- a/xed/xed-tab.c +++ b/xed/xed-tab.c @@ -64,7 +64,7 @@ struct _XedTabPrivate XedPrintJob *print_job; - GtkSourceFileSaver *saver; + GTask *task_saver; GtkSourceFileSaverFlags save_flags; /* tmp data for loading */ @@ -74,9 +74,9 @@ struct _XedTabPrivate guint idle_scroll; GTimer *timer; - guint times_called; + guint times_called; - guint auto_save_interval; + guint auto_save_interval; guint auto_save_timeout; gint editable : 1; @@ -84,10 +84,20 @@ struct _XedTabPrivate gint ask_if_externally_modified : 1; + /*tmp data for loading */ + guint user_requested_encoding : 1; +}; + +typedef struct _SaverData SaverData; + +struct _SaverData +{ + GtkSourceFileSaver *saver; + /* Notes about the create_backup saver flag: - * - At the beginning of a new file saving, force_no_backup is reset to - * FALSE. The create_backup flag is set to the saver if it is enabled - * in GSettings and if it isn't an auto-save. + * - At the beginning of a new file saving, force_no_backup is FALSE. + * The create_backup flag is set to the saver if it is enabled in + * GSettings and if it isn't an auto-save. * - If creating the backup gives an error, and if the user wants to * save the file without the backup, force_no_backup is set to TRUE * and the create_backup flag is removed from the saver. @@ -103,9 +113,6 @@ struct _XedTabPrivate * button in the info bar to retry the file saving. */ guint force_no_backup : 1; - - /*tmp data for loading */ - guint user_requested_encoding : 1; }; G_DEFINE_TYPE(XedTab, xed_tab, GTK_TYPE_BOX) @@ -127,6 +134,26 @@ static void load (XedTab *tab, static void save (XedTab *tab); +static SaverData * +saver_data_new (void) +{ + return g_slice_new0 (SaverData); +} + +static void +saver_data_free (SaverData *data) +{ + if (data != NULL) + { + if (data->saver != NULL) + { + g_object_unref (data->saver); + } + + g_slice_free (SaverData, data); + } +} + static void install_auto_save_timeout (XedTab *tab) { @@ -235,22 +262,15 @@ clear_loading (XedTab *tab) g_clear_object (&tab->priv->cancellable); } -static void -clear_saving (XedTab *tab) -{ - g_clear_object (&tab->priv->saver); - tab->priv->force_no_backup = FALSE; -} - static void xed_tab_dispose (GObject *object) { XedTab *tab = XED_TAB (object); g_clear_object (&tab->priv->editor); + g_clear_object (&tab->priv->task_saver); clear_loading (tab); - clear_saving (tab); G_OBJECT_CLASS (xed_tab_parent_class)->dispose (object); } @@ -734,7 +754,7 @@ show_saving_message_area (XedTab *tab) gchar *msg = NULL; gint len; - g_return_if_fail (tab->priv->saver != NULL); + g_return_if_fail (tab->priv->task_saver != NULL); if (tab->priv->message_area != NULL) { @@ -761,7 +781,11 @@ show_saving_message_area (XedTab *tab) else { gchar *str; - GFile *location = gtk_source_file_saver_get_location (tab->priv->saver); + SaverData *data; + GFile *location; + + data = g_task_get_task_data (tab->priv->task_saver); + location = gtk_source_file_saver_get_location (data->saver); from = short_name; to = g_file_get_parse_name (location); @@ -858,10 +882,11 @@ unrecoverable_saving_error_message_area_response (GtkWidget *message_area, xed_tab_set_state (tab, XED_TAB_STATE_NORMAL); } - clear_saving (tab); - set_message_area (tab, NULL); + g_return_if_fail (tab->priv->task_saver != NULL); + g_task_return_boolean (tab->priv->task_saver, FALSE); + view = xed_tab_get_view (tab); gtk_widget_grab_focus (GTK_WIDGET (view)); @@ -872,8 +897,11 @@ static void response_set_save_flags (XedTab *tab, GtkSourceFileSaverFlags save_flags) { + SaverData *data; gboolean create_backup; + data = g_task_get_task_data (tab->priv->task_saver); + create_backup = g_settings_get_boolean (tab->priv->editor, XED_SETTINGS_CREATE_BACKUP_COPY); /* If we are here, it means that the user expressed his or her willing @@ -881,7 +909,7 @@ response_set_save_flags (XedTab *tab, * the file saving was initially an auto-save, we set the create_backup * flag (if the conditions are met). */ - if (create_backup && !tab->priv->force_no_backup) + if (create_backup && !data->force_no_backup) { save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_CREATE_BACKUP; } @@ -890,7 +918,7 @@ response_set_save_flags (XedTab *tab, save_flags &= ~GTK_SOURCE_FILE_SAVER_FLAGS_CREATE_BACKUP; } - gtk_source_file_saver_set_flags (tab->priv->saver, save_flags); + gtk_source_file_saver_set_flags (data->saver, save_flags); } static void @@ -900,16 +928,18 @@ invalid_character_message_area_response (GtkWidget *info_bar, { if (response_id == GTK_RESPONSE_YES) { + SaverData *data; GtkSourceFileSaverFlags save_flags; set_message_area (tab, NULL); - g_return_if_fail (tab->priv->saver != NULL); + g_return_if_fail (tab->priv->task_saver != NULL); + data = g_task_get_task_data (tab->priv->task_saver); /* Don't bug the user again with this... */ tab->priv->save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_INVALID_CHARS; - save_flags = gtk_source_file_saver_get_flags (tab->priv->saver); + save_flags = gtk_source_file_saver_get_flags (data->saver); save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_INVALID_CHARS; response_set_save_flags (tab, save_flags); @@ -929,14 +959,16 @@ no_backup_error_message_area_response (GtkWidget *message_area, { if (response_id == GTK_RESPONSE_YES) { + SaverData *data; GtkSourceFileSaverFlags save_flags; set_message_area (tab, NULL); - g_return_if_fail (tab->priv->saver != NULL); + g_return_if_fail (tab->priv->task_saver != NULL); + data = g_task_get_task_data (tab->priv->task_saver); - tab->priv->force_no_backup = TRUE; - save_flags = gtk_source_file_saver_get_flags (tab->priv->saver); + data->force_no_backup = TRUE; + save_flags = gtk_source_file_saver_get_flags (data->saver); response_set_save_flags (tab, save_flags); /* Force saving */ @@ -955,17 +987,19 @@ externally_modified_error_message_area_response (GtkWidget *message_area, { if (response_id == GTK_RESPONSE_YES) { + SaverData *data; GtkSourceFileSaverFlags save_flags; set_message_area (tab, NULL); - g_return_if_fail (tab->priv->saver != NULL); + g_return_if_fail (tab->priv->task_saver != NULL); + data = g_task_get_task_data (tab->priv->task_saver); /* ignore_modification_time should not be persisted in save * flags across saves (i.e. priv->save_flags is not modified). */ - save_flags = gtk_source_file_saver_get_flags (tab->priv->saver); + save_flags = gtk_source_file_saver_get_flags (data->saver); save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_MODIFICATION_TIME; response_set_save_flags (tab, save_flags); @@ -985,16 +1019,18 @@ recoverable_saving_error_message_area_response (GtkWidget *message_area, { if (response_id == GTK_RESPONSE_OK) { + SaverData *data; const GtkSourceEncoding *encoding; set_message_area (tab, NULL); - g_return_if_fail (tab->priv->saver != NULL); + g_return_if_fail (tab->priv->task_saver != NULL); + data = g_task_get_task_data (tab->priv->task_saver); encoding = xed_conversion_error_message_area_get_encoding (GTK_WIDGET (message_area)); g_return_if_fail (encoding != NULL); - gtk_source_file_saver_set_encoding (tab->priv->saver, encoding); + gtk_source_file_saver_set_encoding (data->saver, encoding); save (tab); } else @@ -1175,6 +1211,22 @@ _xed_tab_new_from_location (GFile *location, return GTK_WIDGET (tab); } +GtkWidget * +_xed_tab_new_from_stream (GInputStream *stream, + const GtkSourceEncoding *encoding, + gint line_pos) +{ + GtkWidget *tab; + + g_return_val_if_fail (G_IS_INPUT_STREAM (stream), NULL); + + tab = _xed_tab_new (); + + _xed_tab_load_stream (XED_TAB (tab), stream, encoding, line_pos); + + return tab; +} + /** * xed_tab_get_view: * @tab: a #XedTab @@ -1317,13 +1369,11 @@ _xed_tab_get_tooltips (XedTab *tab) if (enc == NULL) { - encoding = g_strdup (_("Unicode (UTF-8)")); - } - else - { - encoding = gtk_source_encoding_to_string (enc); + enc = gtk_source_encoding_get_utf8 (); } + encoding = gtk_source_encoding_to_string (enc); + tip = g_markup_printf_escaped ("%s %s\n\n" "%s %s\n" "%s %s", @@ -1574,6 +1624,7 @@ load_cb (GtkSourceFileLoader *loader, { XedDocument *doc = xed_tab_get_document (tab); GFile *location = gtk_source_file_loader_get_location (loader); + gboolean create_named_new_doc; GError *error = NULL; g_return_if_fail (tab->priv->state == XED_TAB_STATE_LOADING || @@ -1611,10 +1662,13 @@ load_cb (GtkSourceFileLoader *loader, } /* Special case creating a named new doc. */ - else if (_xed_document_get_create (doc) && - error->domain == G_IO_ERROR && - error->code == G_IO_ERROR_NOT_FOUND && - g_file_has_uri_scheme (location, "file")) + create_named_new_doc = (_xed_document_get_create (doc) && + error != NULL && + error->domain == G_IO_ERROR && + error->code == G_IO_ERROR_NOT_FOUND && + g_file_has_uri_scheme (location, "file")); + + if (create_named_new_doc) { g_error_free (error); error = NULL; @@ -1676,7 +1730,7 @@ load_cb (GtkSourceFileLoader *loader, goto end; } - if (location != NULL) + if (location != NULL && !create_named_new_doc) { gchar *mime = xed_document_get_mime_type (doc); @@ -1725,7 +1779,7 @@ load_cb (GtkSourceFileLoader *loader, GList *all_documents; GList *l; - all_documents = xed_app_get_documents (xed_app_get_default ()); + all_documents = xed_app_get_documents (XED_APP (g_application_get_default ())); for (l = all_documents; l != NULL; l = g_list_next (l)) { @@ -1793,6 +1847,8 @@ get_candidate_encodings (XedTab *tab) GSettings *enc_settings; gchar **enc_strv; gchar *metadata_charset; + GtkSourceFile *file; + const GtkSourceEncoding *file_encoding; GSList *encodings; enc_settings = g_settings_new ("org.x.editor.preferences.encodings"); @@ -1806,20 +1862,27 @@ get_candidate_encodings (XedTab *tab) if (metadata_charset != NULL) { - const GtkSourceEncoding *metadata_enc; + const GtkSourceEncoding *metadata_enc; - metadata_enc = gtk_source_encoding_get_from_charset (metadata_charset); + metadata_enc = gtk_source_encoding_get_from_charset (metadata_charset); - if (metadata_enc != NULL) - { - encodings = g_slist_prepend (encodings, (gpointer)metadata_enc); - } - - g_free (metadata_charset); + if (metadata_enc != NULL) + { + encodings = g_slist_prepend (encodings, (gpointer)metadata_enc); + } + } + + file = xed_document_get_file (doc); + file_encoding = gtk_source_file_get_encoding (file); + + if (file_encoding != NULL) + { + encodings = g_slist_prepend (encodings, (gpointer)file_encoding); } - g_strfreev (enc_strv); g_object_unref (enc_settings); + g_strfreev (enc_strv); + g_free (metadata_charset); return encodings; } @@ -1902,6 +1965,39 @@ _xed_tab_load (XedTab *tab, load (tab, encoding, line_pos); } +void +_xed_tab_load_stream (XedTab *tab, + GInputStream *stream, + const GtkSourceEncoding *encoding, + gint line_pos) +{ + XedDocument *doc; + GtkSourceFile *file; + + g_return_if_fail (XED_IS_TAB (tab)); + g_return_if_fail (G_IS_INPUT_STREAM (stream)); + g_return_if_fail (tab->priv->state == XED_TAB_STATE_NORMAL); + + xed_tab_set_state (tab, XED_TAB_STATE_LOADING); + + doc = xed_tab_get_document (tab); + file = xed_document_get_file (doc); + + if (tab->priv->loader != NULL) + { + g_warning ("XedTab: file loader already exists."); + g_object_unref (tab->priv->loader); + } + + gtk_source_file_set_location (file, NULL); + + tab->priv->loader = gtk_source_file_loader_new_from_stream (GTK_SOURCE_BUFFER (doc), file, stream); + + _xed_document_set_create (doc, FALSE); + + load (tab, encoding, line_pos); +} + void _xed_tab_revert (XedTab *tab) { @@ -1977,7 +2073,7 @@ save_cb (GtkSourceFileSaver *saver, GFile *location = gtk_source_file_saver_get_location (saver); GError *error = NULL; - g_return_if_fail (tab->priv->state == XED_TAB_STATE_SAVING); + g_return_if_fail (tab->priv->task_saver != NULL); gtk_source_file_saver_save_finish (saver, result, &error); @@ -2001,7 +2097,7 @@ save_cb (GtkSourceFileSaver *saver, xed_tab_set_state (tab, XED_TAB_STATE_SAVING_ERROR); if (error->domain == GTK_SOURCE_FILE_SAVER_ERROR && - error->code == GTK_SOURCE_FILE_SAVER_ERROR_EXTERNALLY_MODIFIED) + error->code == GTK_SOURCE_FILE_SAVER_ERROR_EXTERNALLY_MODIFIED) { /* This error is recoverable */ message_area = xed_externally_modified_saving_error_message_area_new (location, error); @@ -2084,14 +2180,10 @@ save_cb (GtkSourceFileSaver *saver, tab->priv->ask_if_externally_modified = TRUE; - clear_saving (tab); - g_signal_emit_by_name (doc, "saved"); + g_task_return_boolean (tab->priv->task_saver, TRUE); } - /* Async operation finished. */ - g_object_unref (tab); - if (error != NULL) { g_error_free (error); @@ -2102,20 +2194,20 @@ static void save (XedTab *tab) { XedDocument *doc; + SaverData *data; - g_return_if_fail (GTK_SOURCE_IS_FILE_SAVER (tab->priv->saver)); + g_return_if_fail (G_IS_TASK (tab->priv->task_saver)); xed_tab_set_state (tab, XED_TAB_STATE_SAVING); doc = xed_tab_get_document (tab); g_signal_emit_by_name (doc, "save"); - /* Keep the tab alive during the async operation. */ - g_object_ref (tab); + data = g_task_get_task_data (tab->priv->task_saver); - gtk_source_file_saver_save_async (tab->priv->saver, + gtk_source_file_saver_save_async (data->saver, G_PRIORITY_DEFAULT, - NULL, /* TODO add a cancellable */ + g_task_get_cancellable (tab->priv->task_saver), (GFileProgressCallback) saver_progress_cb, tab, NULL, @@ -2133,9 +2225,6 @@ get_initial_save_flags (XedTab *tab, save_flags = tab->priv->save_flags; - /* force_no_backup must have been reset to FALSE for a new file saving. */ - g_return_val_if_fail (!tab->priv->force_no_backup, save_flags); - create_backup = g_settings_get_boolean (tab->priv->editor, XED_SETTINGS_CREATE_BACKUP_COPY); /* In case of autosaving, we need to preserve the backup that was produced @@ -2151,8 +2240,12 @@ get_initial_save_flags (XedTab *tab, } void -_xed_tab_save (XedTab *tab) +_xed_tab_save_async (XedTab *tab, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { + SaverData *data; XedDocument *doc; GtkSourceFile *file; GtkSourceFileSaverFlags save_flags; @@ -2162,19 +2255,23 @@ _xed_tab_save (XedTab *tab) (tab->priv->state == XED_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) || (tab->priv->state == XED_TAB_STATE_SHOWING_PRINT_PREVIEW)); - if (tab->priv->saver != NULL) + if (tab->priv->task_saver != NULL) { g_warning ("XedTab: file saver already exists."); - g_object_unref (tab->priv->saver); - tab->priv->saver = NULL; + return; } - clear_saving (tab); - doc = xed_tab_get_document (tab); - g_return_if_fail (XED_IS_DOCUMENT (doc)); + // g_return_if_fail (XED_IS_DOCUMENT (doc)); g_return_if_fail (!xed_document_is_untitled (doc)); + tab->priv->task_saver = g_task_new (tab, cancellable, callback, user_data); + + data = saver_data_new (); + g_task_set_task_data (tab->priv->task_saver, + data, + (GDestroyNotify) saver_data_free); + save_flags = get_initial_save_flags (tab, FALSE); if (tab->priv->state == XED_TAB_STATE_EXTERNALLY_MODIFIED_NOTIFICATION) @@ -2189,15 +2286,39 @@ _xed_tab_save (XedTab *tab) file = xed_document_get_file (doc); - tab->priv->saver = gtk_source_file_saver_new (GTK_SOURCE_BUFFER (doc), file); - gtk_source_file_saver_set_flags (tab->priv->saver, save_flags); + data->saver = gtk_source_file_saver_new (GTK_SOURCE_BUFFER (doc), file); + gtk_source_file_saver_set_flags (data->saver, save_flags); save (tab); } +gboolean +_xed_tab_save_finish (XedTab *tab, + GAsyncResult *result) +{ + gboolean success; + + g_return_val_if_fail (g_task_is_valid (result, tab), FALSE); + g_return_val_if_fail (tab->priv->task_saver == G_TASK (result), FALSE); + + success = g_task_propagate_boolean (tab->priv->task_saver, NULL); + g_clear_object (&tab->priv->task_saver); + + return success; +} + +static void +auto_save_finished_cb (XedTab *tab, + GAsyncResult *result, + gpointer user_data) +{ + _xed_tab_save_finish (tab, result); +} + static gboolean xed_tab_auto_save (XedTab *tab) { + SaverData *data; XedDocument *doc; GtkSourceFile *file; GtkSourceFileSaverFlags save_flags; @@ -2205,11 +2326,10 @@ xed_tab_auto_save (XedTab *tab) xed_debug (DEBUG_TAB); doc = xed_tab_get_document (tab); + g_return_val_if_fail (!xed_document_is_untitled (doc), G_SOURCE_REMOVE); + g_return_val_if_fail (!xed_document_get_readonly (doc), G_SOURCE_REMOVE); - g_return_val_if_fail (!xed_document_is_untitled (doc), FALSE); - g_return_val_if_fail (!xed_document_get_readonly (doc), FALSE); - - if (!gtk_text_buffer_get_modified (GTK_TEXT_BUFFER(doc))) + if (!gtk_text_buffer_get_modified (GTK_TEXT_BUFFER (doc))) { xed_debug_message (DEBUG_TAB, "Document not modified"); @@ -2229,37 +2349,50 @@ xed_tab_auto_save (XedTab *tab) /* Set auto_save_timeout to 0 since the timeout is going to be destroyed */ tab->priv->auto_save_timeout = 0; - if (tab->priv->saver != NULL) + if (tab->priv->task_saver != NULL) { g_warning ("XedTab: file saver already exists."); - g_object_unref (tab->priv->saver); - tab->priv->saver = NULL; + return G_SOURCE_REMOVE; } - clear_saving (tab); + tab->priv->task_saver = g_task_new (tab, + NULL, + (GAsyncReadyCallback) auto_save_finished_cb, + NULL); + + data = saver_data_new (); + g_task_set_task_data (tab->priv->task_saver, + data, + (GDestroyNotify) saver_data_free); file = xed_document_get_file (doc); - tab->priv->saver = gtk_source_file_saver_new (GTK_SOURCE_BUFFER (doc), file); + data->saver = gtk_source_file_saver_new (GTK_SOURCE_BUFFER (doc), file); save_flags = get_initial_save_flags (tab, TRUE); - gtk_source_file_saver_set_flags (tab->priv->saver, save_flags); + gtk_source_file_saver_set_flags (data->saver, save_flags); save (tab); return G_SOURCE_REMOVE; } +/* Call _xed_tab_save_finish() in @callback, there is no + * _xed_tab_save_as_finish(). + */ void -_xed_tab_save_as (XedTab *tab, - GFile *location, - const GtkSourceEncoding *encoding, - GtkSourceNewlineType newline_type) +_xed_tab_save_as_async (XedTab *tab, + GFile *location, + const GtkSourceEncoding *encoding, + GtkSourceNewlineType newline_type, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { + SaverData *data; XedDocument *doc; GtkSourceFile *file; GtkSourceFileSaverFlags save_flags; - GFile *prev_location; g_return_if_fail (XED_IS_TAB (tab)); g_return_if_fail ((tab->priv->state == XED_TAB_STATE_NORMAL) || @@ -2268,14 +2401,18 @@ _xed_tab_save_as (XedTab *tab, g_return_if_fail (G_IS_FILE (location)); g_return_if_fail (encoding != NULL); - if (tab->priv->saver != NULL) + if (tab->priv->task_saver != NULL) { g_warning ("XedTab: file saver already exists."); - g_object_unref (tab->priv->saver); - tab->priv->saver = NULL; + return; } - clear_saving (tab); + tab->priv->task_saver = g_task_new (tab, cancellable, callback, user_data); + + data = saver_data_new (); + g_task_set_task_data (tab->priv->task_saver, + data, + (GDestroyNotify) saver_data_free); doc = xed_tab_get_document (tab); g_return_if_fail (XED_IS_DOCUMENT (doc)); @@ -2295,20 +2432,12 @@ _xed_tab_save_as (XedTab *tab, } file = xed_document_get_file (doc); - prev_location = gtk_source_file_get_location (file); - if (prev_location == NULL || !g_file_equal (prev_location, location)) - { - /* Ignore modification time for a save to another location. */ - /* TODO do that in GtkSourceFileSaver. */ - save_flags |= GTK_SOURCE_FILE_SAVER_FLAGS_IGNORE_MODIFICATION_TIME; - } + data->saver = gtk_source_file_saver_new_with_target (GTK_SOURCE_BUFFER (doc), file, location); - tab->priv->saver = gtk_source_file_saver_new_with_target (GTK_SOURCE_BUFFER (doc), file, location); - - gtk_source_file_saver_set_encoding (tab->priv->saver, encoding); - gtk_source_file_saver_set_newline_type (tab->priv->saver, newline_type); - gtk_source_file_saver_set_flags (tab->priv->saver, save_flags); + gtk_source_file_saver_set_encoding (data->saver, encoding); + gtk_source_file_saver_set_newline_type (data->saver, newline_type); + gtk_source_file_saver_set_flags (data->saver, save_flags); save (tab); } @@ -2327,7 +2456,7 @@ get_page_setup (XedTab *tab) if (data == NULL) { - return _xed_app_get_default_page_setup (xed_app_get_default()); + return _xed_app_get_default_page_setup (XED_APP (g_application_get_default ())); } else { @@ -2349,7 +2478,7 @@ get_print_settings (XedTab *tab) if (data == NULL) { - settings = _xed_app_get_default_print_settings (xed_app_get_default()); + settings = _xed_app_get_default_print_settings (XED_APP (g_application_get_default ())); } else { @@ -2407,7 +2536,7 @@ store_print_settings (XedTab *tab, g_object_ref (settings), (GDestroyNotify)g_object_unref); /* make them the default */ - _xed_app_set_default_print_settings (xed_app_get_default (), settings); + _xed_app_set_default_print_settings (XED_APP (g_application_get_default ()), settings); page_setup = xed_print_job_get_page_setup (job); @@ -2416,7 +2545,7 @@ store_print_settings (XedTab *tab, g_object_ref (page_setup), (GDestroyNotify)g_object_unref); /* make it the default */ - _xed_app_set_default_page_setup (xed_app_get_default (), page_setup); + _xed_app_set_default_page_setup (XED_APP (g_application_get_default ()), page_setup); } static void diff --git a/xed/xed-tab.h b/xed/xed-tab.h index 9474268..43f0cf2 100644 --- a/xed/xed-tab.h +++ b/xed/xed-tab.h @@ -112,20 +112,46 @@ GtkWidget *_xed_tab_new_from_location (GFile *location, const GtkSourceEncoding *encoding, gint line_pos, gboolean create); + +GtkWidget *_xed_tab_new_from_stream (GInputStream *stream, + const GtkSourceEncoding *encoding, + gint line_pos); + gchar *_xed_tab_get_name (XedTab *tab); + gchar *_xed_tab_get_tooltips (XedTab *tab); + GdkPixbuf *_xed_tab_get_icon (XedTab *tab); -void _xed_tab_load (XedTab *tab, - GFile *location, + +void _xed_tab_load (XedTab *tab, + GFile *location, const GtkSourceEncoding *encoding, - gint line_pos, - gboolean create); + gint line_pos, + gboolean create); + +void _xed_tab_load_stream (XedTab *tab, + GInputStream *location, + const GtkSourceEncoding *encoding, + gint line_pos); + void _xed_tab_revert (XedTab *tab); -void _xed_tab_save (XedTab *tab); -void _xed_tab_save_as (XedTab *tab, - GFile *location, - const GtkSourceEncoding *encoding, - GtkSourceNewlineType newline_type); + +void _xed_tab_save_async (XedTab *tab, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + + +gboolean _xed_tab_save_finish (XedTab *tab, + GAsyncResult *result); + +void _xed_tab_save_as_async (XedTab *tab, + GFile *location, + const GtkSourceEncoding *encoding, + GtkSourceNewlineType newline_type, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); void _xed_tab_print (XedTab *tab); void _xed_tab_print_preview (XedTab *tab); diff --git a/xed/xed-view.c b/xed/xed-view.c index ef212ae..61f49ac 100644 --- a/xed/xed-view.c +++ b/xed/xed-view.c @@ -771,7 +771,7 @@ xed_view_set_font (XedView *view, GObject *settings; gchar *font; - settings = _xed_app_get_settings (xed_app_get_default ()); + settings = _xed_app_get_settings (XED_APP (g_application_get_default ())); font = xed_settings_get_system_font (XED_SETTINGS (settings)); font_desc = pango_font_description_from_string (font); diff --git a/xed/xed-window.c b/xed/xed-window.c index af5491f..14c75b1 100644 --- a/xed/xed-window.c +++ b/xed/xed-window.c @@ -65,7 +65,7 @@ enum TARGET_URI_LIST = 100 }; -G_DEFINE_TYPE(XedWindow, xed_window, GTK_TYPE_WINDOW) +G_DEFINE_TYPE(XedWindow, xed_window, GTK_TYPE_APPLICATION_WINDOW) static void recent_manager_changed (GtkRecentManager *manager, XedWindow *window); @@ -583,7 +583,7 @@ set_sensitivity_according_to_tab (XedWindow *window, view = xed_tab_get_view (tab); editable = gtk_text_view_get_editable (GTK_TEXT_VIEW(view)); - doc = XED_DOCUMENT(gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); + doc = XED_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); clipboard = gtk_widget_get_clipboard (GTK_WIDGET(window), GDK_SELECTION_CLIPBOARD); @@ -983,15 +983,19 @@ open_recent_file (GFile *location, XedWindow *window) { GSList *locations = NULL; + GSList *loaded = NULL; locations = g_slist_prepend (locations, (gpointer) location); - if (xed_commands_load_locations (window, locations, NULL, 0) != 1) + loaded = xed_commands_load_locations (window, locations, NULL, 0); + + if (!loaded || loaded->next) /* if it doesn't contain just 1 element */ { _xed_recent_remove (window, location); } g_slist_free (locations); + g_slist_free (loaded); } static void @@ -1803,7 +1807,7 @@ clone_window (XedWindow *origin) xed_debug (DEBUG_WINDOW); - app = xed_app_get_default (); + app = XED_APP (g_application_get_default ()); screen = gtk_window_get_screen (GTK_WINDOW(origin)); window = xed_app_create_window (app, screen); @@ -1915,7 +1919,7 @@ static void update_overwrite_mode_statusbar (GtkTextView *view, XedWindow *window) { - if (view != GTK_TEXT_VIEW(xed_window_get_active_view (window))) + if (view != GTK_TEXT_VIEW (xed_window_get_active_view (window))) { return; } @@ -1940,7 +1944,7 @@ set_title (XedWindow *window) if (window->priv->active_tab == NULL) { - gtk_window_set_title (GTK_WINDOW(window), "Xed"); + xed_app_set_window_title (XED_APP (g_application_get_default ()), window, "Xed"); return; } @@ -2012,7 +2016,7 @@ set_title (XedWindow *window) } } - gtk_window_set_title (GTK_WINDOW(window), title); + xed_app_set_window_title (XED_APP (g_application_get_default ()), window, title); g_free (dirname); g_free (name); @@ -2486,6 +2490,7 @@ load_uris_from_drop (XedWindow *window, { GSList *locations = NULL; gint i; + GSList *loaded; if (uri_list == NULL) { @@ -2498,7 +2503,9 @@ load_uris_from_drop (XedWindow *window, } locations = g_slist_reverse (locations); - xed_commands_load_locations (window, locations, NULL, 0); + loaded = xed_commands_load_locations (window, locations, NULL, 0); + + g_slist_free (loaded); g_slist_foreach (locations, (GFunc) g_object_unref, NULL); g_slist_free (locations); @@ -2704,7 +2711,7 @@ fullscreen_controls_build (XedWindow *window) priv->fullscreen_controls = gtk_window_new (GTK_WINDOW_POPUP); - gtk_window_set_transient_for (GTK_WINDOW(priv->fullscreen_controls), &window->window); + gtk_window_set_transient_for (GTK_WINDOW (priv->fullscreen_controls), GTK_WINDOW (&window->window)); window->priv->fullscreen_controls_container = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); gtk_container_set_border_width (GTK_CONTAINER (window->priv->fullscreen_controls_container), 6); @@ -3634,7 +3641,7 @@ xed_window_get_active_view (XedWindow *window) return NULL; } - view = xed_tab_get_view (XED_TAB(window->priv->active_tab)); + view = xed_tab_get_view (XED_TAB (window->priv->active_tab)); return view; } @@ -3663,7 +3670,7 @@ xed_window_get_active_document (XedWindow *window) return NULL; } - return XED_DOCUMENT(gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); + return XED_DOCUMENT (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view))); } GtkWidget * @@ -3693,13 +3700,35 @@ xed_window_create_tab (XedWindow *window, g_return_val_if_fail(XED_IS_WINDOW (window), NULL); tab = XED_TAB(_xed_tab_new ()); - gtk_widget_show (GTK_WIDGET(tab)); + gtk_widget_show (GTK_WIDGET (tab)); - xed_notebook_add_tab (XED_NOTEBOOK(window->priv->notebook), tab, -1, jump_to); + xed_notebook_add_tab (XED_NOTEBOOK (window->priv->notebook), tab, -1, jump_to); - if (!gtk_widget_get_visible (GTK_WIDGET(window))) + if (!gtk_widget_get_visible (GTK_WIDGET (window))) { - gtk_window_present (GTK_WINDOW(window)); + gtk_window_present (GTK_WINDOW (window)); + } + + return tab; +} + +static XedTab * +process_create_tab (XedWindow *window, + XedTab *tab, + gboolean jump_to) +{ + if (tab == NULL) + { + return NULL; + } + + gtk_widget_show (GTK_WIDGET (tab)); + + xed_notebook_add_tab (XED_NOTEBOOK (window->priv->notebook), tab, -1, jump_to); + + if (!gtk_widget_get_visible (GTK_WIDGET (window))) + { + gtk_window_present (GTK_WINDOW (window)); } return tab; @@ -3735,21 +3764,25 @@ xed_window_create_tab_from_location (XedWindow *window, g_return_val_if_fail(G_IS_FILE (location), NULL); tab = _xed_tab_new_from_location (location, encoding, line_pos, create); - if (tab == NULL) - { - return NULL; - } - gtk_widget_show (tab); + return process_create_tab (window, XED_TAB (tab), jump_to); +} - xed_notebook_add_tab (XED_NOTEBOOK(window->priv->notebook), XED_TAB(tab), -1, jump_to); +XedTab * +xed_window_create_tab_from_stream (XedWindow *window, + GInputStream *stream, + const GtkSourceEncoding *encoding, + gint line_pos, + gboolean jump_to) +{ + GtkWidget *tab; - if (!gtk_widget_get_visible (GTK_WIDGET(window))) - { - gtk_window_present (GTK_WINDOW(window)); - } + g_return_val_if_fail (XED_IS_WINDOW (window), NULL); + g_return_val_if_fail (G_IS_INPUT_STREAM (stream), NULL); - return XED_TAB(tab); + tab = _xed_tab_new_from_stream (stream, encoding, line_pos); + + return process_create_tab (window, XED_TAB (tab), jump_to); } /** @@ -3845,12 +3878,12 @@ void xed_window_close_tab (XedWindow *window, XedTab *tab) { - g_return_if_fail(XED_IS_WINDOW (window)); - g_return_if_fail(XED_IS_TAB (tab)); - g_return_if_fail((xed_tab_get_state (tab) != XED_TAB_STATE_SAVING) + g_return_if_fail (XED_IS_WINDOW (window)); + g_return_if_fail (XED_IS_TAB (tab)); + g_return_if_fail ((xed_tab_get_state (tab) != XED_TAB_STATE_SAVING) && (xed_tab_get_state (tab) != XED_TAB_STATE_SHOWING_PRINT_PREVIEW)); - xed_notebook_remove_tab (XED_NOTEBOOK(window->priv->notebook), tab); + xed_notebook_remove_tab (XED_NOTEBOOK (window->priv->notebook), tab); } /** @@ -4175,7 +4208,7 @@ _xed_window_fullscreen (XedWindow *window) } /* Go to fullscreen mode and hide bars */ - gtk_window_fullscreen (&window->window); + gtk_window_fullscreen (GTK_WINDOW (&window->window)); gtk_widget_hide (window->priv->menubar); @@ -4203,7 +4236,7 @@ _xed_window_unfullscreen (XedWindow *window) } /* Unfullscreen and show bars */ - gtk_window_unfullscreen (&window->window); + gtk_window_unfullscreen (GTK_WINDOW (&window->window)); g_signal_handlers_disconnect_by_func (window->priv->notebook, hide_notebook_tabs_on_fullscreen, window); gtk_widget_show (window->priv->menubar); diff --git a/xed/xed-window.h b/xed/xed-window.h index d25a3f3..ae7ad72 100644 --- a/xed/xed-window.h +++ b/xed/xed-window.h @@ -32,7 +32,7 @@ typedef struct _XedWindowClass XedWindowClass; struct _XedWindow { - GtkWindow window; + GtkApplicationWindow window; /*< private > */ XedWindowPrivate *priv; @@ -40,7 +40,7 @@ struct _XedWindow struct _XedWindowClass { - GtkWindowClass parent_class; + GtkApplicationWindowClass parent_class; /* Signals */ void (* tab_added) (XedWindow *window, XedTab *tab); @@ -50,13 +50,13 @@ struct _XedWindowClass void (* active_tab_state_changed) (XedWindow *window); }; -/* - * Public methods - */ +/* Public methods */ GType xed_window_get_type (void) G_GNUC_CONST; XedTab *xed_window_create_tab (XedWindow *window, gboolean jump_to); XedTab *xed_window_create_tab_from_location (XedWindow *window, GFile *location, const GtkSourceEncoding *encoding, gint line_pos, gboolean create, gboolean jump_to); +XedTab *xed_window_create_tab_from_stream (XedWindow *window, GInputStream *stream, const GtkSourceEncoding *encoding, + gint line_pos, gboolean jump_to); void xed_window_close_tab (XedWindow *window, XedTab *tab); void xed_window_close_all_tabs (XedWindow *window); void xed_window_close_tabs (XedWindow *window, const GList *tabs); diff --git a/xed/xed.c b/xed/xed.c index 5bf6685..7a4ada6 100644 --- a/xed/xed.c +++ b/xed/xed.c @@ -32,631 +32,25 @@ #include #endif -#include -#include -#include -#include - #include -#include -#include -#include - -#ifdef HAVE_INTROSPECTION -#include -#endif #include "xed-app.h" -#include "xed-commands.h" -#include "xed-debug.h" -#include "xed-dirs.h" -#include "xed-plugins-engine.h" -#include "xed-session.h" -#include "xed-utils.h" -#include "xed-window.h" - -#include "eggsmclient.h" -#include "eggdesktopfile.h" - -#ifndef ENABLE_GVFS_METADATA -#include "xed-metadata-manager.h" -#endif - -#include "bacon-message-connection.h" - -static guint32 startup_timestamp = 0; - -static BaconMessageConnection *connection; - -/* command line */ -static gint line_position = 0; -// static gchar *encoding_charset = NULL; -static gboolean new_window_option = FALSE; -static gboolean new_document_option = FALSE; -static gchar **remaining_args = NULL; -static GSList *file_list = NULL; - -static void -show_version_and_quit (void) -{ - g_print ("%s - Version %s\n", g_get_application_name (), VERSION); - - exit (0); -} - -// static void -// list_encodings_and_quit (void) -// { -// gint i = 0; -// const XedEncoding *enc; - -// while ((enc = xed_encoding_get_from_index (i)) != NULL) -// { -// g_print ("%s\n", xed_encoding_get_charset (enc)); - -// ++i; -// } - -// exit (0); -// } - -static const GOptionEntry options [] = -{ - { "version", 'V', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, - show_version_and_quit, N_("Show the application's version"), NULL }, - - // { "encoding", '\0', 0, G_OPTION_ARG_STRING, &encoding_charset, - // N_("Set the character encoding to be used to open the files listed on the command line"), N_("ENCODING")}, - - // { "list-encodings", '\0', G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, - // list_encodings_and_quit, N_("Display list of possible values for the encoding option"), NULL}, - - { "new-window", '\0', 0, G_OPTION_ARG_NONE, &new_window_option, - N_("Create a new top-level window in an existing instance of xed"), NULL }, - - { "new-document", '\0', 0, G_OPTION_ARG_NONE, &new_document_option, - N_("Create a new document in an existing instance of xed"), NULL }, - - { G_OPTION_REMAINING, '\0', 0, G_OPTION_ARG_FILENAME_ARRAY, &remaining_args, - NULL, N_("[FILE...]") }, /* collects file arguments */ - - {NULL} -}; - -static void -free_command_line_data (void) -{ - g_slist_foreach (file_list, (GFunc) g_object_unref, NULL); - g_slist_free (file_list); - file_list = NULL; - - g_strfreev (remaining_args); - remaining_args = NULL; - - // g_free (encoding_charset); - // encoding_charset = NULL; - - new_window_option = FALSE; - new_document_option = FALSE; - line_position = 0; -} - -static void -xed_get_command_line_data (void) -{ - if (remaining_args) - { - gint i; - - for (i = 0; remaining_args[i]; i++) - { - if (*remaining_args[i] == '+') - { - if (*(remaining_args[i] + 1) == '\0') - /* goto the last line of the document */ - line_position = G_MAXINT; - else - line_position = atoi (remaining_args[i] + 1); - } - else - { - GFile *file; - - file = g_file_new_for_commandline_arg (remaining_args[i]); - file_list = g_slist_prepend (file_list, file); - } - } - - file_list = g_slist_reverse (file_list); - } - - // if (encoding_charset && - // (xed_encoding_get_from_charset (encoding_charset) == NULL)) - // { - // g_print (_("%s: invalid encoding.\n"), - // encoding_charset); - // } -} - -static guint32 -get_startup_timestamp (void) -{ - const gchar *startup_id_env; - gchar *startup_id = NULL; - gchar *time_str; - gchar *end; - gulong retval = 0; - - /* we don't unset the env, since startup-notification - * may still need it */ - startup_id_env = g_getenv ("DESKTOP_STARTUP_ID"); - if (startup_id_env == NULL) - goto out; - - startup_id = g_strdup (startup_id_env); - - time_str = g_strrstr (startup_id, "_TIME"); - if (time_str == NULL) - goto out; - - errno = 0; - - /* Skip past the "_TIME" part */ - time_str += 5; - - retval = strtoul (time_str, &end, 0); - if (end == time_str || errno != 0) - retval = 0; - - out: - g_free (startup_id); - - return (retval > 0) ? retval : 0; -} - -static GdkDisplay * -display_open_if_needed (const gchar *name) -{ - GSList *displays; - GSList *l; - GdkDisplay *display = NULL; - - displays = gdk_display_manager_list_displays (gdk_display_manager_get ()); - - for (l = displays; l != NULL; l = l->next) - { - if (strcmp (gdk_display_get_name ((GdkDisplay *) l->data), name) == 0) - { - display = l->data; - break; - } - } - - g_slist_free (displays); - - return display != NULL ? display : gdk_display_open (name); -} - -/* serverside */ -static void -on_message_received (const char *message, - gpointer data) -{ - // const XedEncoding *encoding = NULL; - gchar **commands; - gchar **params; - gint workspace; - gint viewport_x; - gint viewport_y; - gchar *display_name; - gint screen_number; - gint i; - XedApp *app; - XedWindow *window; - GdkDisplay *display; - GdkScreen *screen; - - g_return_if_fail (message != NULL); - - xed_debug_message (DEBUG_APP, "Received message:\n%s\n", message); - - commands = g_strsplit (message, "\v", -1); - - /* header */ - params = g_strsplit (commands[0], "\t", 6); - startup_timestamp = atoi (params[0]); - display_name = params[1]; - screen_number = atoi (params[2]); - workspace = atoi (params[3]); - viewport_x = atoi (params[4]); - viewport_y = atoi (params[5]); - - display = display_open_if_needed (display_name); - if (display == NULL) - { - g_warning ("Could not open display %s\n", display_name); - g_strfreev (params); - goto out; - } - - screen = gdk_display_get_screen (display, screen_number); - - g_strfreev (params); - - /* body */ - for (i = 1; commands[i] != NULL; i++) - { - params = g_strsplit (commands[i], "\t", -1); - - if (strcmp (params[0], "NEW-WINDOW") == 0) - { - new_window_option = TRUE; - } - else if (strcmp (params[0], "NEW-DOCUMENT") == 0) - { - new_document_option = TRUE; - } - else if (strcmp (params[0], "OPEN-URIS") == 0) - { - gint n_uris, j; - gchar **uris; - - line_position = atoi (params[1]); - - // if (params[2] != '\0') - // encoding = xed_encoding_get_from_charset (params[2]); - - n_uris = atoi (params[3]); - uris = g_strsplit (params[4], " ", n_uris); - - for (j = 0; j < n_uris; j++) - { - GFile *file; - - file = g_file_new_for_uri (uris[j]); - file_list = g_slist_prepend (file_list, file); - } - - file_list = g_slist_reverse (file_list); - - /* the list takes ownerhip of the strings, - * only free the array */ - g_free (uris); - } - else - { - g_warning ("Unexpected bacon command"); - } - - g_strfreev (params); - } - - /* execute the commands */ - - app = xed_app_get_default (); - - if (new_window_option) - { - window = xed_app_create_window (app, screen); - } - else - { - /* get a window in the current workspace (if exists) and raise it */ - window = _xed_app_get_window_in_viewport (app, - screen, - workspace, - viewport_x, - viewport_y); - } - - if (file_list != NULL) - { - // _xed_cmd_load_files_from_prompt (window, - // file_list, - // encoding, - // line_position); - - if (new_document_option) - xed_window_create_tab (window, TRUE); - } - else - { - XedDocument *doc; - doc = xed_window_get_active_document (window); - - if (doc == NULL || - !xed_document_is_untouched (doc) || - new_document_option) - xed_window_create_tab (window, TRUE); - } - - /* set the proper interaction time on the window. - * Fall back to roundtripping to the X server when we - * don't have the timestamp, e.g. when launched from - * terminal. We also need to make sure that the window - * has been realized otherwise it will not work. lame. - */ - if (!gtk_widget_get_realized (GTK_WIDGET (window))) - gtk_widget_realize (GTK_WIDGET (window)); - - if (startup_timestamp <= 0) - startup_timestamp = gdk_x11_get_server_time (gtk_widget_get_window (GTK_WIDGET (window))); - - gdk_x11_window_set_user_time (gtk_widget_get_window (GTK_WIDGET (window)), - startup_timestamp); - - gtk_window_present (GTK_WINDOW (window)); - - out: - g_strfreev (commands); - - free_command_line_data (); -} - -/* clientside */ -static void -send_bacon_message (void) -{ - GdkScreen *screen; - GdkDisplay *display; - const gchar *display_name; - gint screen_number; - gint ws; - gint viewport_x; - gint viewport_y; - GString *command; - - /* the messages have the following format: - * <--- header ---> <---- body -----> - * timestamp \t display_name \t screen_number \t workspace \t viewport_x \t viewport_y \v OP1 \t arg \t arg \v OP2 \t arg \t arg|... - * - * when the arg is a list of uri, they are separated by a space. - * So the delimiters are \v for the commands, \t for the tokens in - * a command and ' ' for the uris: note that such delimiters cannot - * be part of an uri, this way parsing is easier. - */ - - xed_debug (DEBUG_APP); - - screen = gdk_screen_get_default (); - display = gdk_screen_get_display (screen); - - display_name = gdk_display_get_name (display); - screen_number = gdk_screen_get_number (screen); - - xed_debug_message (DEBUG_APP, "Display: %s", display_name); - xed_debug_message (DEBUG_APP, "Screen: %d", screen_number); - - ws = xed_utils_get_current_workspace (screen); - xed_utils_get_current_viewport (screen, &viewport_x, &viewport_y); - - command = g_string_new (NULL); - - /* header */ - g_string_append_printf (command, - "%" G_GUINT32_FORMAT "\t%s\t%d\t%d\t%d\t%d", - startup_timestamp, - display_name, - screen_number, - ws, - viewport_x, - viewport_y); - - /* NEW-WINDOW command */ - if (new_window_option) - { - command = g_string_append_c (command, '\v'); - command = g_string_append (command, "NEW-WINDOW"); - } - - /* NEW-DOCUMENT command */ - if (new_document_option) - { - command = g_string_append_c (command, '\v'); - command = g_string_append (command, "NEW-DOCUMENT"); - } - - /* OPEN_URIS command, optionally specify line_num and encoding */ - if (file_list) - { - GSList *l; - - command = g_string_append_c (command, '\v'); - command = g_string_append (command, "OPEN-URIS"); - - // g_string_append_printf (command, - // "\t%d\t%s\t%u\t", - // line_position, - // encoding_charset ? encoding_charset : "", - // g_slist_length (file_list)); - - for (l = file_list; l != NULL; l = l->next) - { - gchar *uri; - - uri = g_file_get_uri (G_FILE (l->data)); - command = g_string_append (command, uri); - if (l->next != NULL) - command = g_string_append_c (command, ' '); - - g_free (uri); - } - } - - xed_debug_message (DEBUG_APP, "Bacon Message: %s", command->str); - - bacon_message_connection_send (connection, - command->str); - - g_string_free (command, TRUE); -} int main (int argc, char *argv[]) { - GOptionContext *context; - XedPluginsEngine *engine; - XedWindow *window; - XedApp *app; - gboolean restored = FALSE; - GError *error = NULL; - gchar *dir; - gchar *icon_dir; + XedApp *app; + gint status; + app = g_object_new (XED_TYPE_APP, + "application-id", "org.x.editor", + "flags", G_APPLICATION_HANDLES_COMMAND_LINE, + NULL); - /* Setup debugging */ - xed_debug_init (); - xed_debug_message (DEBUG_APP, "Startup"); + status = g_application_run (G_APPLICATION (app), argc, argv); - setlocale (LC_ALL, ""); + g_object_unref (app); - dir = xed_dirs_get_xed_locale_dir (); - bindtextdomain (GETTEXT_PACKAGE, dir); - g_free (dir); - bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - textdomain (GETTEXT_PACKAGE); - - startup_timestamp = get_startup_timestamp(); - - /* Setup command line options */ - context = g_option_context_new (_("- Edit text files")); - g_option_context_add_main_entries (context, options, GETTEXT_PACKAGE); - g_option_context_add_group (context, gtk_get_option_group (FALSE)); - g_option_context_add_group (context, egg_sm_client_get_option_group ()); - -#ifdef HAVE_INTROSPECTION - g_option_context_add_group (context, g_irepository_get_option_group ()); -#endif - - gtk_init (&argc, &argv); - - if (!g_option_context_parse (context, &argc, &argv, &error)) - { - g_print(_("%s\nRun '%s --help' to see a full list of available command line options.\n"), - error->message, argv[0]); - g_error_free (error); - g_option_context_free (context); - return 1; - } - - g_option_context_free (context); - - xed_debug_message (DEBUG_APP, "Create bacon connection"); - - connection = bacon_message_connection_new ("xed"); - - if (connection != NULL) - { - if (!bacon_message_connection_get_is_server (connection)) - { - xed_debug_message (DEBUG_APP, "I'm a client"); - - xed_get_command_line_data (); - - send_bacon_message (); - - free_command_line_data (); - - /* we never popup a window... tell startup-notification - * that we are done. - */ - gdk_notify_startup_complete (); - - bacon_message_connection_free (connection); - - exit (0); - } - else - { - xed_debug_message (DEBUG_APP, "I'm a server"); - - bacon_message_connection_set_callback (connection, - on_message_received, - NULL); - } - } - else - { - g_warning ("Cannot create the 'xed' connection."); - } - - xed_debug_message (DEBUG_APP, "Set icon"); - - dir = xed_dirs_get_xed_data_dir (); - icon_dir = g_build_filename (dir, - "icons", - NULL); - g_free (dir); - - gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (), - icon_dir); - g_free (icon_dir); - - /* Set the associated .desktop file */ - egg_set_desktop_file (DATADIR "/applications/xed.desktop"); - - /* Init plugins engine */ - xed_debug_message (DEBUG_APP, "Init plugins"); - engine = xed_plugins_engine_get_default (); - - /* Initialize session management */ - xed_debug_message (DEBUG_APP, "Init session manager"); - xed_session_init (); - - if (xed_session_is_restored ()) - restored = xed_session_load (); - - if (!restored) - { - xed_debug_message (DEBUG_APP, "Analyze command line data"); - xed_get_command_line_data (); - - xed_debug_message (DEBUG_APP, "Get default app"); - app = xed_app_get_default (); - - xed_debug_message (DEBUG_APP, "Create main window"); - window = xed_app_create_window (app, NULL); - - // if (file_list != NULL) - // { - // const XedEncoding *encoding = NULL; - - // // if (encoding_charset) - // // encoding = xed_encoding_get_from_charset (encoding_charset); - - // xed_debug_message (DEBUG_APP, "Load files"); - // _xed_cmd_load_files_from_prompt (window, - // file_list, - // encoding, - // line_position); - // } - // else - // { - // xed_debug_message (DEBUG_APP, "Create tab"); - // xed_window_create_tab (window, TRUE); - // } - - xed_debug_message (DEBUG_APP, "Show window"); - gtk_widget_show (GTK_WIDGET (window)); - - free_command_line_data (); - } - - xed_debug_message (DEBUG_APP, "Start gtk-main"); - - gtk_main(); - - bacon_message_connection_free (connection); - - /* We kept the original engine reference here. So let's unref it to - * finalize it properly. - */ - g_object_unref (engine); - -#ifndef ENABLE_GVFS_METADATA - xed_metadata_manager_shutdown (); -#endif - - return 0; + return status; }