xed/xed/xed-app.c

1356 lines
34 KiB
C

/*
* xed-app.c
* This file is part of xed
*
* Copyright (C) 2005-2006 - 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$
*/
#include <config.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <glib/gi18n.h>
#include <libpeas/peas-extension-set.h>
#include <gtksourceview/gtksource.h>
#ifdef ENABLE_INTROSPECTION
#include <girepository.h>
#endif
#include "xed-app.h"
#include "xed-commands.h"
#include "xed-notebook.h"
#include "xed-debug.h"
#include "xed-utils.h"
#include "xed-enum-types.h"
#include "xed-dirs.h"
#include "xed-app-activatable.h"
#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"
#define XED_APP_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), XED_TYPE_APP, XedAppPrivate))
/* Properties */
enum
{
PROP_0,
};
struct _XedAppPrivate
{
XedPluginsEngine *engine;
GtkPageSetup *page_setup;
GtkPrintSettings *print_settings;
GObject *settings;
GSettings *window_settings;
GSettings *editor_settings;
PeasExtensionSet *extensions;
/* command line parsing */
gboolean new_window;
gboolean new_document;
gchar *geometry;
const GtkSourceEncoding *encoding;
GInputStream *stdin_stream;
GSList *file_list;
gint line_position;
GApplicationCommandLine *command_line;
};
G_DEFINE_TYPE (XedApp, xed_app, GTK_TYPE_APPLICATION)
static const GOptionEntry options[] =
{
/* Version */
{
"version", 'V', 0, G_OPTION_ARG_NONE, NULL,
N_("Show the application's version"), NULL
},
/* List available encodings */
{
"list-encodings", '\0', 0, G_OPTION_ARG_NONE, NULL,
N_("Display list of possible values for the encoding option"),
NULL
},
/* 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)
{
XedApp *app = XED_APP (object);
g_clear_object (&app->priv->window_settings);
g_clear_object (&app->priv->editor_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);
}
static void
xed_app_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
switch (prop_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
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
set_initial_theme_style (XedApp *app)
{
if (g_settings_get_boolean (app->priv->editor_settings, XED_SETTINGS_PREFER_DARK_THEME))
{
GtkSettings *gtk_settings;
gtk_settings = gtk_settings_get_default ();
g_object_set (G_OBJECT (gtk_settings), "gtk-application-prefer-dark-theme", TRUE, NULL);
}
}
static void
theme_changed (GtkSettings *settings,
GParamSpec *pspec,
gpointer data)
{
static GtkCssProvider *provider;
gchar *theme;
GdkScreen *screen;
g_object_get (settings, "gtk-theme-name", &theme, NULL);
screen = gdk_screen_get_default ();
if (g_str_equal (theme, "Adwaita"))
{
if (provider == NULL)
{
GFile *file;
provider = gtk_css_provider_new ();
file = g_file_new_for_uri ("resource:///org/x/editor/css/xed.adwaita.css");
gtk_css_provider_load_from_file (provider, file, NULL);
g_object_unref (file);
}
gtk_style_context_add_provider_for_screen (screen,
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
}
else if (provider != NULL)
{
gtk_style_context_remove_provider_for_screen (screen, GTK_STYLE_PROVIDER (provider));
g_clear_object (&provider);
}
g_free (theme);
}
static void
setup_theme_extensions (void)
{
GtkSettings *settings;
settings = gtk_settings_get_default ();
g_signal_connect (settings, "notify::gtk-theme-name",
G_CALLBACK (theme_changed), NULL);
theme_changed (settings, NULL, NULL);
}
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
GError *error = NULL;
GFile *css_file;
GtkCssProvider *provider;
G_APPLICATION_CLASS (xed_app_parent_class)->startup (application);
/* Setup debugging */
xed_debug_init ();
xed_debug_message (DEBUG_APP, "Startup");
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);
setup_theme_extensions ();
#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");
app->priv->editor_settings = g_settings_new ("org.x.editor.preferences.editor");
set_initial_theme_style (app);
/* Load custom css */
css_file = g_file_new_for_uri ("resource:///org/x/editor/css/xed-style.css");
provider = gtk_css_provider_new ();
if (gtk_css_provider_load_from_file (provider, css_file, &error))
{
gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
GTK_STYLE_PROVIDER (provider),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
}
else
{
g_warning ("Could not load css provider: %s", error->message);
g_error_free (error);
}
/*
* 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 (XedApp *app,
XedTab *tab)
{
g_object_set_data_full (G_OBJECT (tab),
"XedTabCommandLineWait",
g_object_ref (app->priv->command_line),
(GDestroyNotify)g_object_unref);
}
static void
set_command_line_wait_doc (XedDocument *doc,
XedApp *app)
{
XedTab *tab = xed_tab_get_from_document (doc);
set_command_line_wait (app, tab);
}
static void
open_files (GApplication *application,
gboolean new_window,
gboolean new_document,
gchar *geometry,
gint line_position,
const GtkSourceEncoding *encoding,
GInputStream *stdin_stream,
GSList *file_list,
GApplicationCommandLine *command_line)
{
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 (XED_APP (application), 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_doc, XED_APP (application));
}
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 (XED_APP (application), tab);
}
}
gtk_window_present (GTK_WINDOW (window));
}
static void
xed_app_activate (GApplication *application)
{
XedAppPrivate *priv = XED_APP (application)->priv;
open_files (application,
priv->new_window,
priv->new_document,
priv->geometry,
priv->line_position,
priv->encoding,
priv->stdin_stream,
priv->file_list,
priv->command_line);
}
static void
clear_options (XedApp *app)
{
XedAppPrivate *priv = app->priv;
g_free (priv->geometry);
g_clear_object (&priv->stdin_stream);
g_slist_free_full (priv->file_list, g_object_unref);
priv->new_window = FALSE;
priv->new_document = FALSE;
priv->geometry = NULL;
priv->encoding = NULL;
priv->file_list = NULL;
priv->line_position = 0;
priv->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)
{
XedAppPrivate *priv;
GVariantDict *options;
const gchar *encoding_charset;
const gchar **remaining_args;
priv = XED_APP (application)->priv;
options = g_application_command_line_get_options_dict (cl);
g_variant_dict_lookup (options, "new-window", "b", &priv->new_window);
g_variant_dict_lookup (options, "new-document", "b", &priv->new_document);
g_variant_dict_lookup (options, "geometry", "s", &priv->geometry);
if (g_variant_dict_contains (options, "wait"))
{
priv->command_line = cl;
}
if (g_variant_dict_lookup (options, "encoding", "&s", &encoding_charset))
{
priv->encoding = gtk_source_encoding_get_from_charset (encoding_charset);
if (priv->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 */
priv->line_position = G_MAXINT;
}
else
{
get_line_position (remaining_args[i] + 1, &priv->line_position);
}
}
else if (*remaining_args[i] == '-' && *(remaining_args[i] + 1) == '\0')
{
priv->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]);
priv->file_list = g_slist_prepend (priv->file_list, file);
}
}
priv->file_list = g_slist_reverse (priv->file_list);
g_free (remaining_args);
}
g_application_activate (application);
clear_options (XED_APP (application));
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;
}
/* Note: when launched from command line we do not reach this method
* since we manually handle the command line parameters in order to
* parse +LINE, stdin, etc.
* However this method is called when open() is called via dbus, for
* instance when double clicking on a file in nautilus
*/
static void
xed_app_open (GApplication *application,
GFile **files,
gint n_files,
const gchar *hint)
{
gint i;
GSList *file_list = NULL;
for (i = 0; i < n_files; i++)
{
file_list = g_slist_prepend (file_list, files[i]);
}
file_list = g_slist_reverse (file_list);
open_files (application,
FALSE,
FALSE,
NULL,
0,
NULL,
NULL,
file_list,
NULL);
g_slist_free (file_list);
}
static gboolean
ensure_user_config_dir (void)
{
const gchar *config_dir;
gboolean ret = TRUE;
gint res;
config_dir = xed_dirs_get_user_config_dir ();
if (config_dir == NULL)
{
g_warning ("Could not get config directory\n");
return FALSE;
}
res = g_mkdir_with_parents (config_dir, 0755);
if (res < 0)
{
g_warning ("Could not create config directory\n");
ret = FALSE;
}
return ret;
}
static void
save_accels (void)
{
gchar *filename;
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);
gtk_accel_map_save (filename);
g_free (filename);
}
}
static gchar *
get_page_setup_file (void)
{
const gchar *config_dir;
gchar *setup = NULL;
config_dir = xed_dirs_get_user_config_dir ();
if (config_dir != NULL)
{
setup = g_build_filename (config_dir, XED_PAGE_SETUP_FILE, NULL);
}
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));
/* GTK+ can still hold references to some xed objects, for example
* XedDocument for the clipboard. So the metadata-manager should be
* shutdown after.
*/
G_APPLICATION_CLASS (xed_app_parent_class)->shutdown (app);
#ifndef ENABLE_GVFS_METADATA
xed_metadata_manager_shutdown ();
#endif
xed_dirs_shutdown ();
}
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->open = xed_app_open;
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)
{
gchar *filename;
GError *error = NULL;
g_return_if_fail (app->priv->page_setup == NULL);
filename = get_page_setup_file ();
app->priv->page_setup = gtk_page_setup_new_from_file (filename, &error);
if (error)
{
/* Ignore file not found error */
if (error->domain != G_FILE_ERROR || error->code != G_FILE_ERROR_NOENT)
{
g_warning ("%s", error->message);
}
g_error_free (error);
}
g_free (filename);
/* fall back to default settings */
if (app->priv->page_setup == NULL)
{
app->priv->page_setup = gtk_page_setup_new ();
}
}
static void
load_print_settings (XedApp *app)
{
gchar *filename;
GError *error = NULL;
g_return_if_fail (app->priv->print_settings == NULL);
filename = get_print_settings_file ();
app->priv->print_settings = gtk_print_settings_new_from_file (filename, &error);
if (error)
{
/* Ignore file not found error */
if (error->domain != G_FILE_ERROR || error->code != G_FILE_ERROR_NOENT)
{
g_warning ("%s", error->message);
}
g_error_free (error);
}
g_free (filename);
/* fall back to default settings */
if (app->priv->print_settings == NULL)
{
app->priv->print_settings = gtk_print_settings_new ();
}
}
static void
xed_app_init (XedApp *app)
{
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 ();
}
static gboolean
window_delete_event (XedWindow *window,
GdkEvent *event,
XedApp *app)
{
XedWindowState ws;
ws = xed_window_get_state (window);
if (ws &
(XED_WINDOW_STATE_SAVING |
XED_WINDOW_STATE_PRINTING |
XED_WINDOW_STATE_SAVING_SESSION))
{
return TRUE;
}
_xed_cmd_file_quit (NULL, window);
/* Do not destroy the window */
return TRUE;
}
/* Generates a unique string for a window role */
static gchar *
gen_role (void)
{
GTimeVal result;
static gint serial;
g_get_current_time (&result);
return g_strdup_printf ("xed-window-%ld-%ld-%d-%s",
result.tv_sec,
result.tv_usec,
serial++,
g_get_host_name ());
}
static XedWindow *
xed_app_create_window_real (XedApp *app,
gboolean set_geometry,
const gchar *role)
{
XedWindow *window;
window = g_object_new (XED_TYPE_WINDOW, "application", app, NULL);
xed_debug_message (DEBUG_APP, "Window created");
if (role != NULL)
{
gtk_window_set_role (GTK_WINDOW (window), role);
}
else
{
gchar *newrole;
newrole = gen_role ();
gtk_window_set_role (GTK_WINDOW (window), newrole);
g_free (newrole);
}
if (set_geometry)
{
GdkWindowState state;
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)
{
gtk_window_maximize (GTK_WINDOW (window));
}
else
{
gtk_window_unmaximize (GTK_WINDOW (window));
}
if ((state & GDK_WINDOW_STATE_STICKY ) != 0)
{
gtk_window_stick (GTK_WINDOW (window));
}
else
{
gtk_window_unstick (GTK_WINDOW (window));
}
}
g_signal_connect (window, "delete_event", G_CALLBACK (window_delete_event), app);
return window;
}
/**
* xed_app_create_window:
* @app: the #XedApp
* @screen: (allow-none):
*
* Create a new #XedWindow part of @app.
*
* Return value: (transfer none): the new #XedWindow
*/
XedWindow *
xed_app_create_window (XedApp *app,
GdkScreen *screen)
{
XedWindow *window;
window = xed_app_create_window_real (app, TRUE, NULL);
if (screen != NULL)
{
gtk_window_set_screen (GTK_WINDOW (window), screen);
}
return window;
}
/*
* Same as _create_window, but doesn't set the geometry.
* The session manager takes care of it. Used in mate-session.
*/
XedWindow *
_xed_app_restore_window (XedApp *app,
const gchar *role)
{
XedWindow *window;
window = xed_app_create_window_real (app, FALSE, role);
return window;
}
/**
* xed_app_get_main_windows:
* @app: the #GeditApp
*
* 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 container):
* a newly allocated list of #XedWindow objects
*/
GList *
xed_app_get_main_windows (XedApp *app)
{
GList *res = NULL;
GList *windows, *l;
g_return_val_if_fail (XED_IS_APP (app), NULL);
windows = gtk_application_get_windows (GTK_APPLICATION (app));
for (l = windows; l != NULL; l = g_list_next (l))
{
if (XED_IS_WINDOW (l->data))
{
res = g_list_prepend (res, l->data);
}
}
return g_list_reverse (res);
}
/**
* xed_app_get_documents:
* @app: the #XedApp
*
* Returns all the documents currently open in #XedApp.
*
* Return value: (element-type Xed.Document) (transfer container):
* a newly allocated list of #XedDocument objects
*/
GList *
xed_app_get_documents (XedApp *app)
{
GList *res = NULL;
GList *windows, *l;
g_return_val_if_fail (XED_IS_APP (app), 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 (l->data)));
}
return res;
}
/**
* xed_app_get_views:
* @app: the #XedApp
*
* Returns all the views currently present in #XedApp.
*
* Return value: (element-type Xed.View) (transfer container):
* a newly allocated list of #XedView objects
*/
GList *
xed_app_get_views (XedApp *app)
{
GList *res = NULL;
GList *windows, *l;
g_return_val_if_fail (XED_IS_APP (app), 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 (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)
{
g_return_val_if_fail (XED_IS_APP (app), NULL);
if (app->priv->page_setup == NULL)
{
load_page_setup (app);
}
return gtk_page_setup_copy (app->priv->page_setup);
}
void
_xed_app_set_default_page_setup (XedApp *app,
GtkPageSetup *page_setup)
{
g_return_if_fail (XED_IS_APP (app));
g_return_if_fail (GTK_IS_PAGE_SETUP (page_setup));
if (app->priv->page_setup != NULL)
{
g_object_unref (app->priv->page_setup);
}
app->priv->page_setup = g_object_ref (page_setup);
}
/* Returns a copy */
GtkPrintSettings *
_xed_app_get_default_print_settings (XedApp *app)
{
g_return_val_if_fail (XED_IS_APP (app), NULL);
if (app->priv->print_settings == NULL)
{
load_print_settings (app);
}
return gtk_print_settings_copy (app->priv->print_settings);
}
void
_xed_app_set_default_print_settings (XedApp *app,
GtkPrintSettings *settings)
{
g_return_if_fail (XED_IS_APP (app));
g_return_if_fail (GTK_IS_PRINT_SETTINGS (settings));
if (app->priv->print_settings != NULL)
{
g_object_unref (app->priv->print_settings);
}
app->priv->print_settings = g_object_ref (settings);
}
GObject *
_xed_app_get_settings (XedApp *app)
{
g_return_val_if_fail (XED_IS_APP (app), NULL);
return app->priv->settings;
}