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