1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimpsessioninfo-book.c
5 * Copyright (C) 2001-2007 Michael Natterer <mitch@gimp.org>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <gtk/gtk.h>
24
25 #include "libgimpconfig/gimpconfig.h"
26
27 #include "widgets-types.h"
28
29 #include "gimpdialogfactory.h"
30 #include "gimpdock.h"
31 #include "gimpdockbook.h"
32 #include "gimpsessioninfo.h"
33 #include "gimpsessioninfo-book.h"
34 #include "gimpsessioninfo-dockable.h"
35
36
37 enum
38 {
39 SESSION_INFO_BOOK_POSITION,
40 SESSION_INFO_BOOK_CURRENT_PAGE,
41 SESSION_INFO_BOOK_DOCKABLE
42 };
43
44
45 /* public functions */
46
47 GimpSessionInfoBook *
gimp_session_info_book_new(void)48 gimp_session_info_book_new (void)
49 {
50 return g_slice_new0 (GimpSessionInfoBook);
51 }
52
53 void
gimp_session_info_book_free(GimpSessionInfoBook * info)54 gimp_session_info_book_free (GimpSessionInfoBook *info)
55 {
56 g_return_if_fail (info != NULL);
57
58 if (info->dockables)
59 {
60 g_list_free_full (info->dockables,
61 (GDestroyNotify) gimp_session_info_dockable_free);
62 info->dockables = NULL;
63 }
64
65 g_slice_free (GimpSessionInfoBook, info);
66 }
67
68 void
gimp_session_info_book_serialize(GimpConfigWriter * writer,GimpSessionInfoBook * info)69 gimp_session_info_book_serialize (GimpConfigWriter *writer,
70 GimpSessionInfoBook *info)
71 {
72 GList *pages;
73
74 g_return_if_fail (writer != NULL);
75 g_return_if_fail (info != NULL);
76
77 gimp_config_writer_open (writer, "book");
78
79 if (info->position != 0)
80 {
81 gint position;
82
83 position = gimp_session_info_apply_position_accuracy (info->position);
84
85 gimp_config_writer_open (writer, "position");
86 gimp_config_writer_printf (writer, "%d", position);
87 gimp_config_writer_close (writer);
88 }
89
90 gimp_config_writer_open (writer, "current-page");
91 gimp_config_writer_printf (writer, "%d", info->current_page);
92 gimp_config_writer_close (writer);
93
94 for (pages = info->dockables; pages; pages = g_list_next (pages))
95 gimp_session_info_dockable_serialize (writer, pages->data);
96
97 gimp_config_writer_close (writer);
98 }
99
100 GTokenType
gimp_session_info_book_deserialize(GScanner * scanner,gint scope,GimpSessionInfoBook ** book)101 gimp_session_info_book_deserialize (GScanner *scanner,
102 gint scope,
103 GimpSessionInfoBook **book)
104 {
105 GimpSessionInfoBook *info;
106 GTokenType token;
107
108 g_return_val_if_fail (scanner != NULL, G_TOKEN_LEFT_PAREN);
109 g_return_val_if_fail (book != NULL, G_TOKEN_LEFT_PAREN);
110
111 g_scanner_scope_add_symbol (scanner, scope, "position",
112 GINT_TO_POINTER (SESSION_INFO_BOOK_POSITION));
113 g_scanner_scope_add_symbol (scanner, scope, "current-page",
114 GINT_TO_POINTER (SESSION_INFO_BOOK_CURRENT_PAGE));
115 g_scanner_scope_add_symbol (scanner, scope, "dockable",
116 GINT_TO_POINTER (SESSION_INFO_BOOK_DOCKABLE));
117
118 info = gimp_session_info_book_new ();
119
120 token = G_TOKEN_LEFT_PAREN;
121
122 while (g_scanner_peek_next_token (scanner) == token)
123 {
124 token = g_scanner_get_next_token (scanner);
125
126 switch (token)
127 {
128 case G_TOKEN_LEFT_PAREN:
129 token = G_TOKEN_SYMBOL;
130 break;
131
132 case G_TOKEN_SYMBOL:
133 switch (GPOINTER_TO_INT (scanner->value.v_symbol))
134 {
135 GimpSessionInfoDockable *dockable;
136
137 case SESSION_INFO_BOOK_POSITION:
138 token = G_TOKEN_INT;
139 if (! gimp_scanner_parse_int (scanner, &info->position))
140 goto error;
141 break;
142
143 case SESSION_INFO_BOOK_CURRENT_PAGE:
144 token = G_TOKEN_INT;
145 if (! gimp_scanner_parse_int (scanner, &info->current_page))
146 goto error;
147 break;
148
149 case SESSION_INFO_BOOK_DOCKABLE:
150 g_scanner_set_scope (scanner, scope + 1);
151 token = gimp_session_info_dockable_deserialize (scanner,
152 scope + 1,
153 &dockable);
154
155 if (token == G_TOKEN_LEFT_PAREN)
156 {
157 info->dockables = g_list_append (info->dockables, dockable);
158 g_scanner_set_scope (scanner, scope);
159 }
160 else
161 goto error;
162
163 break;
164
165 default:
166 goto error;
167 }
168 token = G_TOKEN_RIGHT_PAREN;
169 break;
170
171 case G_TOKEN_RIGHT_PAREN:
172 token = G_TOKEN_LEFT_PAREN;
173 break;
174
175 default:
176 break;
177 }
178 }
179
180 *book = info;
181
182 g_scanner_scope_remove_symbol (scanner, scope, "position");
183 g_scanner_scope_remove_symbol (scanner, scope, "current-page");
184 g_scanner_scope_remove_symbol (scanner, scope, "dockable");
185
186 return token;
187
188 error:
189 *book = NULL;
190
191 gimp_session_info_book_free (info);
192
193 return token;
194 }
195
196 GimpSessionInfoBook *
gimp_session_info_book_from_widget(GimpDockbook * dockbook)197 gimp_session_info_book_from_widget (GimpDockbook *dockbook)
198 {
199 GimpSessionInfoBook *info;
200 GtkWidget *parent;
201 GList *children;
202 GList *list;
203
204 g_return_val_if_fail (GIMP_IS_DOCKBOOK (dockbook), NULL);
205
206 info = gimp_session_info_book_new ();
207
208 parent = gtk_widget_get_parent (GTK_WIDGET (dockbook));
209
210 if (GTK_IS_PANED (parent))
211 {
212 GtkPaned *paned = GTK_PANED (parent);
213
214 if (GTK_WIDGET (dockbook) == gtk_paned_get_child2 (paned))
215 info->position = gtk_paned_get_position (paned);
216 }
217
218 info->current_page =
219 gtk_notebook_get_current_page (GTK_NOTEBOOK (dockbook));
220
221 children = gtk_container_get_children (GTK_CONTAINER (dockbook));
222
223 for (list = children; list; list = g_list_next (list))
224 {
225 GimpSessionInfoDockable *dockable;
226
227 dockable = gimp_session_info_dockable_from_widget (list->data);
228
229 info->dockables = g_list_prepend (info->dockables, dockable);
230 }
231
232 info->dockables = g_list_reverse (info->dockables);
233
234 g_list_free (children);
235
236 return info;
237 }
238
239 GimpDockbook *
gimp_session_info_book_restore(GimpSessionInfoBook * info,GimpDock * dock)240 gimp_session_info_book_restore (GimpSessionInfoBook *info,
241 GimpDock *dock)
242 {
243 GimpDialogFactory *dialog_factory;
244 GimpMenuFactory *menu_factory;
245 GtkWidget *dockbook;
246 GList *pages;
247 gint n_dockables = 0;
248
249 g_return_val_if_fail (info != NULL, NULL);
250 g_return_val_if_fail (GIMP_IS_DOCK (dock), NULL);
251
252 dialog_factory = gimp_dock_get_dialog_factory (dock);
253 menu_factory = gimp_dialog_factory_get_menu_factory (dialog_factory);
254
255 dockbook = gimp_dockbook_new (menu_factory);
256
257 gimp_dock_add_book (dock, GIMP_DOCKBOOK (dockbook), -1);
258
259 for (pages = info->dockables; pages; pages = g_list_next (pages))
260 {
261 GimpSessionInfoDockable *dockable_info = pages->data;
262 GimpDockable *dockable;
263
264 dockable = gimp_session_info_dockable_restore (dockable_info, dock);
265
266 if (dockable)
267 {
268 gimp_dockbook_add (GIMP_DOCKBOOK (dockbook), dockable, -1);
269 n_dockables++;
270 }
271 }
272
273 if (info->current_page <
274 gtk_notebook_get_n_pages (GTK_NOTEBOOK (dockbook)))
275 {
276 gtk_notebook_set_current_page (GTK_NOTEBOOK (dockbook),
277 info->current_page);
278 }
279 else if (n_dockables > 1)
280 {
281 gtk_notebook_set_current_page (GTK_NOTEBOOK (dockbook), 0);
282 }
283
284 /* Return the dockbook even if no dockable could be restored
285 * (n_dockables == 0) because otherwise we would have to remove it
286 * from the dock right here, which could implicitly destroy the
287 * dock and make catching restore errors much harder on higher
288 * levels. Instead, we check for restored empty dockbooks in our
289 * caller.
290 */
291 return GIMP_DOCKBOOK (dockbook);
292 }
293