1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimpsessioninfo-dock.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 <string.h>
24
25 #include <gtk/gtk.h>
26
27 #include "libgimpconfig/gimpconfig.h"
28
29 #include "widgets-types.h"
30
31 #include "gimpdialogfactory.h"
32 #include "gimpdock.h"
33 #include "gimpdockbook.h"
34 #include "gimpdockcontainer.h"
35 #include "gimpdockwindow.h"
36 #include "gimpsessioninfo.h"
37 #include "gimpsessioninfo-aux.h"
38 #include "gimpsessioninfo-book.h"
39 #include "gimpsessioninfo-dock.h"
40 #include "gimpsessioninfo-private.h"
41 #include "gimptoolbox.h"
42
43
44 enum
45 {
46 SESSION_INFO_SIDE,
47 SESSION_INFO_POSITION,
48 SESSION_INFO_BOOK
49 };
50
51
52 static GimpAlignmentType gimp_session_info_dock_get_side (GimpDock *dock);
53
54
55 static GimpAlignmentType
gimp_session_info_dock_get_side(GimpDock * dock)56 gimp_session_info_dock_get_side (GimpDock *dock)
57 {
58 GimpAlignmentType result = -1;
59 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (dock));
60
61 if (GIMP_IS_DOCK_CONTAINER (toplevel))
62 {
63 GimpDockContainer *container = GIMP_DOCK_CONTAINER (toplevel);
64
65 result = gimp_dock_container_get_dock_side (container, dock);
66 }
67
68 return result;
69 }
70
71
72 /* public functions */
73
74 GimpSessionInfoDock *
gimp_session_info_dock_new(const gchar * dock_type)75 gimp_session_info_dock_new (const gchar *dock_type)
76 {
77 GimpSessionInfoDock *dock_info = NULL;
78
79 dock_info = g_slice_new0 (GimpSessionInfoDock);
80 dock_info->dock_type = g_strdup (dock_type);
81 dock_info->side = -1;
82
83 return dock_info;
84 }
85
86 void
gimp_session_info_dock_free(GimpSessionInfoDock * dock_info)87 gimp_session_info_dock_free (GimpSessionInfoDock *dock_info)
88 {
89 g_return_if_fail (dock_info != NULL);
90
91 g_clear_pointer (&dock_info->dock_type, g_free);
92
93 if (dock_info->books)
94 {
95 g_list_free_full (dock_info->books,
96 (GDestroyNotify) gimp_session_info_book_free);
97 dock_info->books = NULL;
98 }
99
100 g_slice_free (GimpSessionInfoDock, dock_info);
101 }
102
103 void
gimp_session_info_dock_serialize(GimpConfigWriter * writer,GimpSessionInfoDock * dock_info)104 gimp_session_info_dock_serialize (GimpConfigWriter *writer,
105 GimpSessionInfoDock *dock_info)
106 {
107 GList *list;
108
109 g_return_if_fail (writer != NULL);
110 g_return_if_fail (dock_info != NULL);
111
112 gimp_config_writer_open (writer, dock_info->dock_type);
113
114 if (dock_info->side != -1)
115 {
116 const char *side_text =
117 dock_info->side == GIMP_ALIGN_LEFT ? "left" : "right";
118
119 gimp_config_writer_open (writer, "side");
120 gimp_config_writer_print (writer, side_text, strlen (side_text));
121 gimp_config_writer_close (writer);
122 }
123
124 if (dock_info->position != 0)
125 {
126 gint position;
127
128 position = gimp_session_info_apply_position_accuracy (dock_info->position);
129
130 gimp_config_writer_open (writer, "position");
131 gimp_config_writer_printf (writer, "%d", position);
132 gimp_config_writer_close (writer);
133 }
134
135 for (list = dock_info->books; list; list = g_list_next (list))
136 gimp_session_info_book_serialize (writer, list->data);
137
138 gimp_config_writer_close (writer);
139 }
140
141 GTokenType
gimp_session_info_dock_deserialize(GScanner * scanner,gint scope,GimpSessionInfoDock ** dock_info,const gchar * dock_type)142 gimp_session_info_dock_deserialize (GScanner *scanner,
143 gint scope,
144 GimpSessionInfoDock **dock_info,
145 const gchar *dock_type)
146 {
147 GTokenType token;
148
149 g_return_val_if_fail (scanner != NULL, G_TOKEN_LEFT_PAREN);
150 g_return_val_if_fail (dock_info != NULL, G_TOKEN_LEFT_PAREN);
151
152 g_scanner_scope_add_symbol (scanner, scope, "side",
153 GINT_TO_POINTER (SESSION_INFO_SIDE));
154 g_scanner_scope_add_symbol (scanner, scope, "position",
155 GINT_TO_POINTER (SESSION_INFO_POSITION));
156 g_scanner_scope_add_symbol (scanner, scope, "book",
157 GINT_TO_POINTER (SESSION_INFO_BOOK));
158
159 *dock_info = gimp_session_info_dock_new (dock_type);
160
161 token = G_TOKEN_LEFT_PAREN;
162
163 while (g_scanner_peek_next_token (scanner) == token)
164 {
165 token = g_scanner_get_next_token (scanner);
166
167 switch (token)
168 {
169 case G_TOKEN_LEFT_PAREN:
170 token = G_TOKEN_SYMBOL;
171 break;
172
173 case G_TOKEN_SYMBOL:
174 switch (GPOINTER_TO_INT (scanner->value.v_symbol))
175 {
176 GimpSessionInfoBook *book;
177
178 case SESSION_INFO_SIDE:
179 token = G_TOKEN_IDENTIFIER;
180 if (g_scanner_peek_next_token (scanner) != token)
181 break;
182
183 g_scanner_get_next_token (scanner);
184
185 if (strcmp ("left", scanner->value.v_identifier) == 0)
186 (*dock_info)->side = GIMP_ALIGN_LEFT;
187 else
188 (*dock_info)->side = GIMP_ALIGN_RIGHT;
189 break;
190
191 case SESSION_INFO_POSITION:
192 token = G_TOKEN_INT;
193 if (! gimp_scanner_parse_int (scanner, &((*dock_info)->position)))
194 (*dock_info)->position = 0;
195 break;
196
197 case SESSION_INFO_BOOK:
198 g_scanner_set_scope (scanner, scope + 1);
199 token = gimp_session_info_book_deserialize (scanner, scope + 1,
200 &book);
201
202 if (token == G_TOKEN_LEFT_PAREN)
203 {
204 (*dock_info)->books = g_list_append ((*dock_info)->books, book);
205 g_scanner_set_scope (scanner, scope);
206 }
207 else
208 return token;
209
210 break;
211
212 default:
213 return token;
214 }
215 token = G_TOKEN_RIGHT_PAREN;
216 break;
217
218 case G_TOKEN_RIGHT_PAREN:
219 token = G_TOKEN_LEFT_PAREN;
220 break;
221
222 default:
223 break;
224 }
225 }
226
227 g_scanner_scope_remove_symbol (scanner, scope, "book");
228 g_scanner_scope_remove_symbol (scanner, scope, "position");
229 g_scanner_scope_remove_symbol (scanner, scope, "side");
230
231 return token;
232 }
233
234 GimpSessionInfoDock *
gimp_session_info_dock_from_widget(GimpDock * dock)235 gimp_session_info_dock_from_widget (GimpDock *dock)
236 {
237 GimpSessionInfoDock *dock_info;
238 GList *list;
239 GtkWidget *parent;
240
241 g_return_val_if_fail (GIMP_IS_DOCK (dock), NULL);
242
243 dock_info = gimp_session_info_dock_new (GIMP_IS_TOOLBOX (dock) ?
244 "gimp-toolbox" :
245 "gimp-dock");
246
247 for (list = gimp_dock_get_dockbooks (dock); list; list = g_list_next (list))
248 {
249 GimpSessionInfoBook *book;
250
251 book = gimp_session_info_book_from_widget (list->data);
252
253 dock_info->books = g_list_prepend (dock_info->books, book);
254 }
255
256 dock_info->books = g_list_reverse (dock_info->books);
257 dock_info->side = gimp_session_info_dock_get_side (dock);
258
259 parent = gtk_widget_get_parent (GTK_WIDGET (dock));
260
261 if (GTK_IS_PANED (parent))
262 {
263 GtkPaned *paned = GTK_PANED (parent);
264
265 if (GTK_WIDGET (dock) == gtk_paned_get_child2 (paned))
266 dock_info->position = gtk_paned_get_position (paned);
267 }
268
269 return dock_info;
270 }
271
272 GimpDock *
gimp_session_info_dock_restore(GimpSessionInfoDock * dock_info,GimpDialogFactory * factory,GdkScreen * screen,gint monitor,GimpDockContainer * dock_container)273 gimp_session_info_dock_restore (GimpSessionInfoDock *dock_info,
274 GimpDialogFactory *factory,
275 GdkScreen *screen,
276 gint monitor,
277 GimpDockContainer *dock_container)
278 {
279 gint n_books = 0;
280 GtkWidget *dock;
281 GList *iter;
282 GimpUIManager *ui_manager;
283
284 g_return_val_if_fail (GIMP_IS_DIALOG_FACTORY (factory), NULL);
285 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
286
287 ui_manager = gimp_dock_container_get_ui_manager (dock_container);
288 dock = gimp_dialog_factory_dialog_new (factory,
289 screen,
290 monitor,
291 ui_manager,
292 dock_info->dock_type,
293 -1 /*view_size*/,
294 FALSE /*present*/);
295
296 g_return_val_if_fail (GIMP_IS_DOCK (dock), NULL);
297
298 /* Add the dock to the dock window immediately so the stuff in the
299 * dock has access to e.g. a dialog factory
300 */
301 gimp_dock_container_add_dock (dock_container,
302 GIMP_DOCK (dock),
303 dock_info);
304
305 /* Note that if it is a toolbox, we will get here even though we
306 * don't have any books
307 */
308 for (iter = dock_info->books;
309 iter;
310 iter = g_list_next (iter))
311 {
312 GimpSessionInfoBook *book_info = iter->data;
313 GtkWidget *dockbook;
314
315 dockbook = GTK_WIDGET (gimp_session_info_book_restore (book_info,
316 GIMP_DOCK (dock)));
317
318 if (dockbook)
319 {
320 GtkWidget *parent = gtk_widget_get_parent (dockbook);
321
322 n_books++;
323
324 if (GTK_IS_PANED (parent))
325 {
326 GtkPaned *paned = GTK_PANED (parent);
327
328 if (dockbook == gtk_paned_get_child2 (paned))
329 gtk_paned_set_position (paned, book_info->position);
330 }
331 }
332 }
333
334 /* Now remove empty dockbooks from the list, check the comment in
335 * gimp_session_info_book_restore() which explains why the dock
336 * can contain empty dockbooks at all
337 */
338 if (dock_info->books)
339 {
340 GList *books;
341
342 books = g_list_copy (gimp_dock_get_dockbooks (GIMP_DOCK (dock)));
343
344 while (books)
345 {
346 GtkContainer *dockbook = books->data;
347 GList *children = gtk_container_get_children (dockbook);
348
349 if (children)
350 {
351 g_list_free (children);
352 }
353 else
354 {
355 g_object_ref (dockbook);
356 gimp_dock_remove_book (GIMP_DOCK (dock), GIMP_DOCKBOOK (dockbook));
357 gtk_widget_destroy (GTK_WIDGET (dockbook));
358 g_object_unref (dockbook);
359
360 n_books--;
361 }
362
363 books = g_list_remove (books, dockbook);
364 }
365 }
366
367 /* if we removed all books again, the dock was destroyed, so bail out */
368 if (dock_info->books && n_books == 0)
369 {
370 return NULL;
371 }
372
373 gtk_widget_show (dock);
374
375 return GIMP_DOCK (dock);
376 }
377