/* GIMP - The GNU Image Manipulation Program * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * gimpsessioninfo.c * Copyright (C) 2001-2008 Michael Natterer * * 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 3 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, see . */ #include "config.h" #include #include #include #include "libgimpconfig/gimpconfig.h" #include "libgimpwidgets/gimpwidgets.h" #include "widgets-types.h" #include "config/gimpguiconfig.h" #include "widgets/gimpdockcontainer.h" #include "core/gimp.h" #include "core/gimpcontext.h" #include "gimpdialogfactory.h" #include "gimpdock.h" #include "gimpdockwindow.h" #include "gimpsessioninfo.h" #include "gimpsessioninfo-aux.h" #include "gimpsessioninfo-book.h" #include "gimpsessioninfo-dock.h" #include "gimpsessioninfo-private.h" #include "gimpsessionmanaged.h" #include "gimp-log.h" enum { SESSION_INFO_FACTORY_ENTRY, SESSION_INFO_POSITION, SESSION_INFO_SIZE, SESSION_INFO_MONITOR, SESSION_INFO_OPEN, SESSION_INFO_AUX, SESSION_INFO_DOCK, SESSION_INFO_GIMP_DOCK, SESSION_INFO_GIMP_TOOLBOX }; #define DEFAULT_SCREEN -1 #define DEFAULT_MONITOR -1 typedef struct { GimpSessionInfo *info; GimpDialogFactory *factory; GdkScreen *screen; gint monitor; GtkWidget *dialog; } GimpRestoreDocksData; static void gimp_session_info_config_iface_init (GimpConfigInterface *iface); static void gimp_session_info_finalize (GObject *object); static gint64 gimp_session_info_get_memsize (GimpObject *object, gint64 *gui_size); static gboolean gimp_session_info_serialize (GimpConfig *config, GimpConfigWriter *writer, gpointer data); static gboolean gimp_session_info_deserialize (GimpConfig *config, GScanner *scanner, gint nest_level, gpointer data); static gboolean gimp_session_info_is_for_dock_window (GimpSessionInfo *info); static void gimp_session_info_dialog_show (GtkWidget *widget, GimpSessionInfo *info); static gboolean gimp_session_info_restore_docks (GimpRestoreDocksData *data); G_DEFINE_TYPE_WITH_CODE (GimpSessionInfo, gimp_session_info, GIMP_TYPE_OBJECT, G_ADD_PRIVATE (GimpSessionInfo) G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG, gimp_session_info_config_iface_init)) #define parent_class gimp_session_info_parent_class static void gimp_session_info_class_init (GimpSessionInfoClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GimpObjectClass *gimp_object_class = GIMP_OBJECT_CLASS (klass); object_class->finalize = gimp_session_info_finalize; gimp_object_class->get_memsize = gimp_session_info_get_memsize; } static void gimp_session_info_init (GimpSessionInfo *info) { info->p = gimp_session_info_get_instance_private (info); info->p->monitor = DEFAULT_MONITOR; info->p->screen = DEFAULT_SCREEN; } static void gimp_session_info_config_iface_init (GimpConfigInterface *iface) { iface->serialize = gimp_session_info_serialize; iface->deserialize = gimp_session_info_deserialize; } static void gimp_session_info_finalize (GObject *object) { GimpSessionInfo *info = GIMP_SESSION_INFO (object); gimp_session_info_clear_info (info); gimp_session_info_set_widget (info, NULL); G_OBJECT_CLASS (parent_class)->finalize (object); } static gint64 gimp_session_info_get_memsize (GimpObject *object, gint64 *gui_size) { #if 0 GimpSessionInfo *info = GIMP_SESSION_INFO (object); #endif gint64 memsize = 0; return memsize + GIMP_OBJECT_CLASS (parent_class)->get_memsize (object, gui_size); } static gboolean gimp_session_info_serialize (GimpConfig *config, GimpConfigWriter *writer, gpointer data) { GimpSessionInfo *info = GIMP_SESSION_INFO (config); GList *iter = NULL; gint x; gint y; gint width; gint height; if (info->p->factory_entry && info->p->factory_entry->identifier) { gimp_config_writer_open (writer, "factory-entry"); gimp_config_writer_string (writer, info->p->factory_entry->identifier); gimp_config_writer_close (writer); } x = gimp_session_info_apply_position_accuracy (info->p->x); y = gimp_session_info_apply_position_accuracy (info->p->y); width = gimp_session_info_apply_position_accuracy (info->p->width); height = gimp_session_info_apply_position_accuracy (info->p->height); gimp_config_writer_open (writer, "position"); gimp_config_writer_printf (writer, "%d %d", x, y); gimp_config_writer_close (writer); if (info->p->width > 0 && info->p->height > 0) { gimp_config_writer_open (writer, "size"); gimp_config_writer_printf (writer, "%d %d", width, height); gimp_config_writer_close (writer); } if (info->p->monitor != DEFAULT_MONITOR) { gimp_config_writer_open (writer, "monitor"); gimp_config_writer_printf (writer, "%d", info->p->monitor); gimp_config_writer_close (writer); } if (info->p->open) { gimp_config_writer_open (writer, "open-on-exit"); if (info->p->screen != DEFAULT_SCREEN) gimp_config_writer_printf (writer, "%d", info->p->screen); gimp_config_writer_close (writer); } if (info->p->aux_info) gimp_session_info_aux_serialize (writer, info->p->aux_info); for (iter = info->p->docks; iter; iter = g_list_next (iter)) gimp_session_info_dock_serialize (writer, iter->data); return TRUE; } /* * This function is just like gimp_scanner_parse_int(), but it is allows * to detect the special value '-0'. This is used as in X geometry strings. */ static gboolean gimp_session_info_parse_offset (GScanner *scanner, gint *dest, gboolean *negative) { if (g_scanner_peek_next_token (scanner) == '-') { *negative = TRUE; g_scanner_get_next_token (scanner); } else { *negative = FALSE; } if (g_scanner_peek_next_token (scanner) != G_TOKEN_INT) return FALSE; g_scanner_get_next_token (scanner); if (*negative) *dest = -scanner->value.v_int64; else *dest = scanner->value.v_int64; return TRUE; } static gboolean gimp_session_info_deserialize (GimpConfig *config, GScanner *scanner, gint nest_level, gpointer data) { GimpSessionInfo *info = GIMP_SESSION_INFO (config); GTokenType token; guint scope_id; guint old_scope_id; scope_id = g_type_qname (G_TYPE_FROM_INSTANCE (config)); old_scope_id = g_scanner_set_scope (scanner, scope_id); g_scanner_scope_add_symbol (scanner, scope_id, "factory-entry", GINT_TO_POINTER (SESSION_INFO_FACTORY_ENTRY)); g_scanner_scope_add_symbol (scanner, scope_id, "position", GINT_TO_POINTER (SESSION_INFO_POSITION)); g_scanner_scope_add_symbol (scanner, scope_id, "size", GINT_TO_POINTER (SESSION_INFO_SIZE)); g_scanner_scope_add_symbol (scanner, scope_id, "monitor", GINT_TO_POINTER (SESSION_INFO_MONITOR)); g_scanner_scope_add_symbol (scanner, scope_id, "open-on-exit", GINT_TO_POINTER (SESSION_INFO_OPEN)); g_scanner_scope_add_symbol (scanner, scope_id, "aux-info", GINT_TO_POINTER (SESSION_INFO_AUX)); g_scanner_scope_add_symbol (scanner, scope_id, "gimp-dock", GINT_TO_POINTER (SESSION_INFO_GIMP_DOCK)); g_scanner_scope_add_symbol (scanner, scope_id, "gimp-toolbox", GINT_TO_POINTER (SESSION_INFO_GIMP_TOOLBOX)); /* For sessionrc files from version <= GIMP 2.6 */ g_scanner_scope_add_symbol (scanner, scope_id, "dock", GINT_TO_POINTER (SESSION_INFO_DOCK)); token = G_TOKEN_LEFT_PAREN; while (g_scanner_peek_next_token (scanner) == token) { token = g_scanner_get_next_token (scanner); switch (token) { case G_TOKEN_LEFT_PAREN: token = G_TOKEN_SYMBOL; break; case G_TOKEN_SYMBOL: switch (GPOINTER_TO_INT (scanner->value.v_symbol)) { case SESSION_INFO_FACTORY_ENTRY: { gchar *identifier = NULL; GimpDialogFactoryEntry *entry = NULL; token = G_TOKEN_STRING; if (! gimp_scanner_parse_string (scanner, &identifier)) goto error; entry = gimp_dialog_factory_find_entry (gimp_dialog_factory_get_singleton (), identifier); if (! entry) goto error; gimp_session_info_set_factory_entry (info, entry); g_free (identifier); } break; case SESSION_INFO_POSITION: token = G_TOKEN_INT; if (! gimp_session_info_parse_offset (scanner, &info->p->x, &info->p->right_align)) goto error; if (! gimp_session_info_parse_offset (scanner, &info->p->y, &info->p->bottom_align)) goto error; break; case SESSION_INFO_SIZE: token = G_TOKEN_INT; if (! gimp_scanner_parse_int (scanner, &info->p->width)) goto error; if (! gimp_scanner_parse_int (scanner, &info->p->height)) goto error; break; case SESSION_INFO_MONITOR: token = G_TOKEN_INT; if (! gimp_scanner_parse_int (scanner, &info->p->monitor)) goto error; break; case SESSION_INFO_OPEN: info->p->open = TRUE; /* the screen number is optional */ if (g_scanner_peek_next_token (scanner) == G_TOKEN_RIGHT_PAREN) break; token = G_TOKEN_INT; if (! gimp_scanner_parse_int (scanner, &info->p->screen)) goto error; break; case SESSION_INFO_AUX: token = gimp_session_info_aux_deserialize (scanner, &info->p->aux_info); if (token != G_TOKEN_LEFT_PAREN) goto error; break; case SESSION_INFO_GIMP_TOOLBOX: case SESSION_INFO_GIMP_DOCK: case SESSION_INFO_DOCK: { GimpSessionInfoDock *dock_info = NULL; const gchar *dock_type = NULL; /* Handle old sessionrc:s from versions <= GIMP 2.6 */ if (GPOINTER_TO_INT (scanner->value.v_symbol) == SESSION_INFO_DOCK && info->p->factory_entry && info->p->factory_entry->identifier && strcmp ("gimp-toolbox-window", info->p->factory_entry->identifier) == 0) { dock_type = "gimp-toolbox"; } else { dock_type = ((GPOINTER_TO_INT (scanner->value.v_symbol) == SESSION_INFO_GIMP_TOOLBOX) ? "gimp-toolbox" : "gimp-dock"); } g_scanner_set_scope (scanner, scope_id + 1); token = gimp_session_info_dock_deserialize (scanner, scope_id + 1, &dock_info, dock_type); if (token == G_TOKEN_LEFT_PAREN) { g_scanner_set_scope (scanner, scope_id); info->p->docks = g_list_append (info->p->docks, dock_info); } else goto error; } break; default: break; } token = G_TOKEN_RIGHT_PAREN; break; case G_TOKEN_RIGHT_PAREN: token = G_TOKEN_LEFT_PAREN; break; default: break; } } error: /* If we don't have docks, assume it is a toolbox dock window from a * sessionrc file from GIMP <= 2.6 and add a toolbox dock manually */ if (! info->p->docks && info->p->factory_entry && strcmp ("gimp-toolbox-window", info->p->factory_entry->identifier) == 0) { info->p->docks = g_list_append (info->p->docks, gimp_session_info_dock_new ("gimp-toolbox")); } g_scanner_scope_remove_symbol (scanner, scope_id, "factory-entry"); g_scanner_scope_remove_symbol (scanner, scope_id, "position"); g_scanner_scope_remove_symbol (scanner, scope_id, "size"); g_scanner_scope_remove_symbol (scanner, scope_id, "open-on-exit"); g_scanner_scope_remove_symbol (scanner, scope_id, "aux-info"); g_scanner_scope_remove_symbol (scanner, scope_id, "gimp-dock"); g_scanner_scope_remove_symbol (scanner, scope_id, "gimp-toolbox"); g_scanner_scope_remove_symbol (scanner, scope_id, "dock"); g_scanner_set_scope (scanner, old_scope_id); return gimp_config_deserialize_return (scanner, token, nest_level); } /** * gimp_session_info_is_for_dock_window: * @info: * * Helper function to determine if the session info is for a dock. It * uses the dialog factory entry state and the associated widget state * if any to determine that. * * Returns: %TRUE if session info is for a dock, %FALSE otherwise. **/ static gboolean gimp_session_info_is_for_dock_window (GimpSessionInfo *info) { gboolean entry_state_for_dock = info->p->factory_entry == NULL; gboolean widget_state_for_dock = (info->p->widget == NULL || GIMP_IS_DOCK_WINDOW (info->p->widget)); return entry_state_for_dock && widget_state_for_dock; } static void gimp_session_info_dialog_show (GtkWidget *widget, GimpSessionInfo *info) { gtk_window_move (GTK_WINDOW (widget), info->p->x, info->p->y); } static gboolean gimp_session_info_restore_docks (GimpRestoreDocksData *data) { GimpSessionInfo *info = data->info; GimpDialogFactory *factory = data->factory; GdkScreen *screen = data->screen; gint monitor = data->monitor; GtkWidget *dialog = data->dialog; GList *iter; if (GIMP_IS_DOCK_CONTAINER (dialog)) { /* We expect expect there to always be docks. In sessionrc files * from <= 2.6 not all dock window entries had dock entries, but we * take care of that during sessionrc parsing */ for (iter = info->p->docks; iter; iter = g_list_next (iter)) { GimpSessionInfoDock *dock_info = (GimpSessionInfoDock *) iter->data; GtkWidget *dock; dock = GTK_WIDGET (gimp_session_info_dock_restore (dock_info, factory, screen, monitor, GIMP_DOCK_CONTAINER (dialog))); if (dock && dock_info->position != 0) { GtkWidget *parent = gtk_widget_get_parent (dock); if (GTK_IS_PANED (parent)) { GtkPaned *paned = GTK_PANED (parent); if (dock == gtk_paned_get_child2 (paned)) gtk_paned_set_position (paned, dock_info->position); } } } } gimp_session_info_clear_info (info); g_object_unref (dialog); g_object_unref (screen); g_object_unref (factory); g_object_unref (info); g_slice_free (GimpRestoreDocksData, data); return FALSE; } /* public functions */ GimpSessionInfo * gimp_session_info_new (void) { return g_object_new (GIMP_TYPE_SESSION_INFO, NULL); } void gimp_session_info_restore (GimpSessionInfo *info, GimpDialogFactory *factory, GdkScreen *screen, gint monitor) { GtkWidget *dialog = NULL; GimpRestoreDocksData *data; g_return_if_fail (GIMP_IS_SESSION_INFO (info)); g_return_if_fail (GIMP_IS_DIALOG_FACTORY (factory)); g_return_if_fail (GDK_IS_SCREEN (screen)); g_object_ref (info); if (info->p->screen != DEFAULT_SCREEN) { GdkDisplay *display; GdkScreen *info_screen; display = gdk_display_get_default (); info_screen = gdk_display_get_screen (display, info->p->screen); if (info_screen) screen = info_screen; } info->p->open = FALSE; info->p->screen = DEFAULT_SCREEN; if (info->p->factory_entry && info->p->factory_entry->restore_func) { dialog = info->p->factory_entry->restore_func (factory, screen, monitor, info); } else g_printerr ("EEEEK\n"); if (GIMP_IS_SESSION_MANAGED (dialog) && info->p->aux_info) gimp_session_managed_set_aux_info (GIMP_SESSION_MANAGED (dialog), info->p->aux_info); /* In single-window mode, gimp_session_managed_set_aux_info() * will set the size of the dock areas at the sides. If we don't * wait for those areas to get their size-allocation, we can't * properly restore the docks inside them, so do that in an idle * callback. */ /* Objects are unreffed again in the callback */ data = g_slice_new0 (GimpRestoreDocksData); data->info = g_object_ref (info); data->factory = g_object_ref (factory); data->screen = g_object_ref (screen); data->monitor = monitor; data->dialog = dialog ? g_object_ref (dialog) : NULL; g_idle_add ((GSourceFunc) gimp_session_info_restore_docks, data); g_object_unref (info); } /** * gimp_session_info_apply_geometry: * @info: * @screen: * @current_monitor: * * Apply the geometry stored in the session info object to the * associated widget. **/ void gimp_session_info_apply_geometry (GimpSessionInfo *info, GdkScreen *screen, gint current_monitor, gboolean apply_stored_monitor) { GdkRectangle rect; GdkRectangle work_rect; gchar geom[32]; gint monitor; gint width; gint height; g_return_if_fail (GIMP_IS_SESSION_INFO (info)); g_return_if_fail (GTK_IS_WINDOW (info->p->widget)); g_return_if_fail (GDK_IS_SCREEN (screen)); monitor = current_monitor; if (apply_stored_monitor) { gint n_monitors; n_monitors = gdk_screen_get_n_monitors (screen); if (info->p->monitor != DEFAULT_MONITOR && info->p->monitor < n_monitors) { monitor = info->p->monitor; } else { monitor = gdk_screen_get_primary_monitor (screen); } } gdk_screen_get_monitor_geometry (screen, monitor, &rect); gdk_screen_get_monitor_workarea (screen, monitor, &work_rect); info->p->x += rect.x; info->p->y += rect.y; if (gimp_session_info_get_remember_size (info) && info->p->width > 0 && info->p->height > 0) { width = info->p->width; height = info->p->height; } else { GtkRequisition requisition; gtk_widget_size_request (info->p->widget, &requisition); width = requisition.width; height = requisition.height; } info->p->x = CLAMP (info->p->x, work_rect.x, work_rect.x + work_rect.width - width); info->p->y = CLAMP (info->p->y, work_rect.y, work_rect.y + work_rect.height - height); if (info->p->right_align && info->p->bottom_align) { g_strlcpy (geom, "-0-0", sizeof (geom)); } else if (info->p->right_align) { g_snprintf (geom, sizeof (geom), "-0%+d", info->p->y); } else if (info->p->bottom_align) { g_snprintf (geom, sizeof (geom), "%+d-0", info->p->x); } else { g_snprintf (geom, sizeof (geom), "%+d%+d", info->p->x, info->p->y); } gtk_window_parse_geometry (GTK_WINDOW (info->p->widget), geom); if (gimp_session_info_get_remember_size (info) && info->p->width > 0 && info->p->height > 0) { gtk_window_set_default_size (GTK_WINDOW (info->p->widget), info->p->width, info->p->height); } /* Window managers and windowing systems suck. They have their own * ideas about WM standards and when it's appropriate to honor * user/application-set window positions and when not. Therefore, * use brute force and "manually" position dialogs whenever they * are shown. This is important especially for transient dialogs, * because window managers behave even "smarter" then... */ if (GTK_IS_DIALOG (info->p->widget)) g_signal_connect (info->p->widget, "show", G_CALLBACK (gimp_session_info_dialog_show), info); } /** * gimp_session_info_read_geometry: * @info: A #GimpSessionInfo * @cevent A #GdkEventConfigure. If set, use the size from here * instead of from the window allocation. * * Read geometry related information from the associated widget. **/ void gimp_session_info_read_geometry (GimpSessionInfo *info, GdkEventConfigure *cevent) { GdkWindow *window; GdkScreen *screen; g_return_if_fail (GIMP_IS_SESSION_INFO (info)); g_return_if_fail (GTK_IS_WINDOW (info->p->widget)); window = gtk_widget_get_window (info->p->widget); screen = gtk_widget_get_screen (info->p->widget); if (window) { gint x, y; gint monitor; GdkRectangle geometry; gdk_window_get_root_origin (window, &x, &y); /* Don't write negative values to the sessionrc, they are * interpreted as relative to the right, respective bottom edge * of the screen. */ info->p->x = MAX (0, x); info->p->y = MAX (0, y); monitor = gdk_screen_get_monitor_at_point (screen, info->p->x, info->p->y); gdk_screen_get_monitor_geometry (screen, monitor, &geometry); /* Always store window coordinates relative to the monitor */ info->p->x -= geometry.x; info->p->y -= geometry.y; if (gimp_session_info_get_remember_size (info)) { int width; int height; if (cevent) { width = cevent->width; height = cevent->height; } else { GtkAllocation allocation; gtk_widget_get_allocation (info->p->widget, &allocation); width = allocation.width; height = allocation.height; } info->p->width = width; info->p->height = height; } else { info->p->width = 0; info->p->height = 0; } info->p->monitor = DEFAULT_MONITOR; if (monitor != gdk_screen_get_primary_monitor (screen)) info->p->monitor = monitor; } info->p->open = FALSE; if (gimp_session_info_get_remember_if_open (info)) { GimpDialogVisibilityState visibility; visibility = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (info->p->widget), GIMP_DIALOG_VISIBILITY_KEY)); switch (visibility) { case GIMP_DIALOG_VISIBILITY_UNKNOWN: info->p->open = gtk_widget_get_visible (info->p->widget); break; case GIMP_DIALOG_VISIBILITY_INVISIBLE: info->p->open = FALSE; break; case GIMP_DIALOG_VISIBILITY_HIDDEN: case GIMP_DIALOG_VISIBILITY_VISIBLE: /* Even if a dialog is hidden (with Windows->Hide docks) it * is still considered open. It will be restored the next * time GIMP starts */ info->p->open = TRUE; break; } } info->p->screen = DEFAULT_SCREEN; if (info->p->open) { GdkDisplay *display = gtk_widget_get_display (info->p->widget); if (screen != gdk_display_get_default_screen (display)) info->p->screen = gdk_screen_get_number (screen); } } void gimp_session_info_get_info (GimpSessionInfo *info) { g_return_if_fail (GIMP_IS_SESSION_INFO (info)); g_return_if_fail (GTK_IS_WIDGET (info->p->widget)); gimp_session_info_read_geometry (info, NULL /*cevent*/); if (GIMP_IS_SESSION_MANAGED (info->p->widget)) info->p->aux_info = gimp_session_managed_get_aux_info (GIMP_SESSION_MANAGED (info->p->widget)); if (GIMP_IS_DOCK_CONTAINER (info->p->widget)) { GimpDockContainer *dock_container = GIMP_DOCK_CONTAINER (info->p->widget); GList *iter = NULL; GList *docks; docks = gimp_dock_container_get_docks (dock_container); for (iter = docks; iter; iter = g_list_next (iter)) { GimpDock *dock = GIMP_DOCK (iter->data); info->p->docks = g_list_append (info->p->docks, gimp_session_info_dock_from_widget (dock)); } g_list_free (docks); } } /** * gimp_session_info_get_info_with_widget: * @info: * @widget: #GtkWidget to use * * Temporarily sets @widget on @info and calls * gimp_session_info_get_info(), then restores the old widget that was * set. **/ void gimp_session_info_get_info_with_widget (GimpSessionInfo *info, GtkWidget *widget) { GtkWidget *old_widget; g_return_if_fail (GIMP_IS_SESSION_INFO (info)); g_return_if_fail (GTK_IS_WIDGET (widget)); old_widget = gimp_session_info_get_widget (info); gimp_session_info_set_widget (info, widget); gimp_session_info_get_info (info); gimp_session_info_set_widget (info, old_widget); } void gimp_session_info_clear_info (GimpSessionInfo *info) { g_return_if_fail (GIMP_IS_SESSION_INFO (info)); if (info->p->aux_info) { g_list_free_full (info->p->aux_info, (GDestroyNotify) gimp_session_info_aux_free); info->p->aux_info = NULL; } if (info->p->docks) { g_list_free_full (info->p->docks, (GDestroyNotify) gimp_session_info_dock_free); info->p->docks = NULL; } } gboolean gimp_session_info_is_singleton (GimpSessionInfo *info) { g_return_val_if_fail (GIMP_IS_SESSION_INFO (info), FALSE); return (! gimp_session_info_is_for_dock_window (info) && info->p->factory_entry && info->p->factory_entry->singleton); } gboolean gimp_session_info_is_session_managed (GimpSessionInfo *info) { g_return_val_if_fail (GIMP_IS_SESSION_INFO (info), FALSE); return (gimp_session_info_is_for_dock_window (info) || (info->p->factory_entry && info->p->factory_entry->session_managed)); } gboolean gimp_session_info_get_remember_size (GimpSessionInfo *info) { g_return_val_if_fail (GIMP_IS_SESSION_INFO (info), FALSE); return (gimp_session_info_is_for_dock_window (info) || (info->p->factory_entry && info->p->factory_entry->remember_size)); } gboolean gimp_session_info_get_remember_if_open (GimpSessionInfo *info) { g_return_val_if_fail (GIMP_IS_SESSION_INFO (info), FALSE); return (gimp_session_info_is_for_dock_window (info) || (info->p->factory_entry && info->p->factory_entry->remember_if_open)); } GtkWidget * gimp_session_info_get_widget (GimpSessionInfo *info) { g_return_val_if_fail (GIMP_IS_SESSION_INFO (info), FALSE); return info->p->widget; } void gimp_session_info_set_widget (GimpSessionInfo *info, GtkWidget *widget) { g_return_if_fail (GIMP_IS_SESSION_INFO (info)); if (GTK_IS_DIALOG (info->p->widget)) g_signal_handlers_disconnect_by_func (info->p->widget, gimp_session_info_dialog_show, info); info->p->widget = widget; } GimpDialogFactoryEntry * gimp_session_info_get_factory_entry (GimpSessionInfo *info) { g_return_val_if_fail (GIMP_IS_SESSION_INFO (info), FALSE); return info->p->factory_entry; } void gimp_session_info_set_factory_entry (GimpSessionInfo *info, GimpDialogFactoryEntry *entry) { g_return_if_fail (GIMP_IS_SESSION_INFO (info)); info->p->factory_entry = entry; } gboolean gimp_session_info_get_open (GimpSessionInfo *info) { g_return_val_if_fail (GIMP_IS_SESSION_INFO (info), FALSE); return info->p->open; } gint gimp_session_info_get_x (GimpSessionInfo *info) { g_return_val_if_fail (GIMP_IS_SESSION_INFO (info), 0); return info->p->x; } gint gimp_session_info_get_y (GimpSessionInfo *info) { g_return_val_if_fail (GIMP_IS_SESSION_INFO (info), 0); return info->p->y; } gint gimp_session_info_get_width (GimpSessionInfo *info) { g_return_val_if_fail (GIMP_IS_SESSION_INFO (info), 0); return info->p->width; } gint gimp_session_info_get_height (GimpSessionInfo *info) { g_return_val_if_fail (GIMP_IS_SESSION_INFO (info), 0); return info->p->height; } static gint position_accuracy = 0; /** * gimp_session_info_set_position_accuracy: * @accuracy: * * When writing sessionrc, make positions and sizes a multiple of * @accuracy. Meant to be used by test cases that does regression * testing on session managed window positions and sizes, to allow for * some deviations from the original setup, that the window manager * might impose. **/ void gimp_session_info_set_position_accuracy (gint accuracy) { position_accuracy = accuracy; } /** * gimp_session_info_apply_position_accuracy: * @position: * * Rounds @position to the nearest multiple of what was set with * gimp_session_info_set_position_accuracy(). * * Returns: Result. **/ gint gimp_session_info_apply_position_accuracy (gint position) { if (position_accuracy > 0) { gint to_floor = position + position_accuracy / 2; return to_floor - to_floor % position_accuracy; } return position; }