1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include <string.h>
21 
22 #include <gegl.h>
23 #include <gtk/gtk.h>
24 
25 #include "libgimpbase/gimpbase.h"
26 
27 #include "actions-types.h"
28 
29 #include "core/gimp.h"
30 #include "core/gimp-utils.h"
31 #include "core/gimpcontext.h"
32 #include "core/gimpimage.h"
33 #include "core/gimpprojectable.h"
34 #include "core/gimpprojection.h"
35 
36 #include "gegl/gimp-gegl-utils.h"
37 
38 #include "widgets/gimpaction.h"
39 #include "widgets/gimpactiongroup.h"
40 #include "widgets/gimpmenufactory.h"
41 #include "widgets/gimpuimanager.h"
42 
43 #include "display/gimpdisplay.h"
44 #include "display/gimpdisplayshell.h"
45 #include "display/gimpimagewindow.h"
46 
47 #include "menus/menus.h"
48 
49 #include "actions.h"
50 #include "debug-commands.h"
51 
52 
53 /*  local function prototypes  */
54 
55 static gboolean  debug_benchmark_projection    (GimpDisplay *display);
56 static gboolean  debug_show_image_graph        (GimpImage   *source_image);
57 
58 static void      debug_dump_menus_recurse_menu (GtkWidget   *menu,
59                                                 gint         depth,
60                                                 gchar       *path);
61 
62 static void      debug_print_qdata             (GimpObject  *object);
63 static void      debug_print_qdata_foreach     (GQuark       key_id,
64                                                 gpointer     data,
65                                                 gpointer     user_data);
66 
67 static gboolean  debug_accel_find_func         (GtkAccelKey *key,
68                                                 GClosure    *closure,
69                                                 gpointer     data);
70 
71 
72 /*  public functions  */
73 
74 void
debug_mem_profile_cmd_callback(GimpAction * action,GVariant * value,gpointer data)75 debug_mem_profile_cmd_callback (GimpAction *action,
76                                 GVariant   *value,
77                                 gpointer    data)
78 {
79   extern gboolean  gimp_debug_memsize;
80   Gimp            *gimp;
81   return_if_no_gimp (gimp, data);
82 
83   gimp_debug_memsize = TRUE;
84 
85   gimp_object_get_memsize (GIMP_OBJECT (gimp), NULL);
86 
87   gimp_debug_memsize = FALSE;
88 }
89 
90 void
debug_benchmark_projection_cmd_callback(GimpAction * action,GVariant * value,gpointer data)91 debug_benchmark_projection_cmd_callback (GimpAction *action,
92                                          GVariant   *value,
93                                          gpointer    data)
94 {
95   GimpDisplay *display;
96   return_if_no_display (display, data);
97 
98   g_idle_add ((GSourceFunc) debug_benchmark_projection, g_object_ref (display));
99 }
100 
101 void
debug_show_image_graph_cmd_callback(GimpAction * action,GVariant * value,gpointer data)102 debug_show_image_graph_cmd_callback (GimpAction *action,
103                                      GVariant   *value,
104                                      gpointer    data)
105 {
106   GimpImage *source_image = NULL;
107   return_if_no_image (source_image, data);
108 
109   g_idle_add ((GSourceFunc) debug_show_image_graph, g_object_ref (source_image));
110 }
111 
112 void
debug_dump_menus_cmd_callback(GimpAction * action,GVariant * value,gpointer data)113 debug_dump_menus_cmd_callback (GimpAction *action,
114                                GVariant   *value,
115                                gpointer    data)
116 {
117   GList *list;
118 
119   for (list = gimp_menu_factory_get_registered_menus (global_menu_factory);
120        list;
121        list = g_list_next (list))
122     {
123       GimpMenuFactoryEntry *entry = list->data;
124       GList                *managers;
125 
126       managers = gimp_ui_managers_from_name (entry->identifier);
127 
128       if (managers)
129         {
130           GimpUIManager *manager = managers->data;
131           GList         *list;
132 
133           for (list = manager->registered_uis; list; list = g_list_next (list))
134             {
135               GimpUIManagerUIEntry *ui_entry = list->data;
136 
137               if (GTK_IS_MENU_SHELL (ui_entry->widget))
138                 {
139                   g_print ("\n\n"
140                            "========================================\n"
141                            "Menu: %s%s\n"
142                            "========================================\n\n",
143                            entry->identifier, ui_entry->ui_path);
144 
145                   debug_dump_menus_recurse_menu (ui_entry->widget, 1,
146                                                  entry->identifier);
147                   g_print ("\n");
148                 }
149             }
150         }
151     }
152 }
153 
154 void
debug_dump_managers_cmd_callback(GimpAction * action,GVariant * value,gpointer data)155 debug_dump_managers_cmd_callback (GimpAction *action,
156                                   GVariant   *value,
157                                   gpointer    data)
158 {
159   GList *list;
160 
161   for (list = gimp_menu_factory_get_registered_menus (global_menu_factory);
162        list;
163        list = g_list_next (list))
164     {
165       GimpMenuFactoryEntry *entry = list->data;
166       GList                *managers;
167 
168       managers = gimp_ui_managers_from_name (entry->identifier);
169 
170       if (managers)
171         {
172           g_print ("\n\n"
173                    "========================================\n"
174                    "UI Manager: %s\n"
175                    "========================================\n\n",
176                    entry->identifier);
177 
178           g_print ("%s\n", gimp_ui_manager_get_ui (managers->data));
179         }
180     }
181 }
182 
183 void
debug_dump_keyboard_shortcuts_cmd_callback(GimpAction * action,GVariant * value,gpointer data)184 debug_dump_keyboard_shortcuts_cmd_callback (GimpAction *action,
185                                             GVariant   *value,
186                                             gpointer    data)
187 {
188   GimpDisplay      *display;
189   GimpImageWindow  *window;
190   GimpUIManager    *manager;
191   GtkAccelGroup    *accel_group;
192   GList            *group_it;
193   GList            *strings = NULL;
194   return_if_no_display (display, data);
195 
196   window  = gimp_display_shell_get_window (gimp_display_get_shell (display));
197   manager = gimp_image_window_get_ui_manager (window);
198 
199   accel_group = gimp_ui_manager_get_accel_group (manager);
200 
201   /* Gather formatted strings of keyboard shortcuts */
202   for (group_it = gimp_ui_manager_get_action_groups (manager);
203        group_it;
204        group_it = g_list_next (group_it))
205     {
206       GimpActionGroup *group     = group_it->data;
207       GList           *actions   = NULL;
208       GList           *action_it = NULL;
209 
210       actions = gimp_action_group_list_actions (group);
211       actions = g_list_sort (actions, (GCompareFunc) gimp_action_name_compare);
212 
213       for (action_it = actions; action_it; action_it = g_list_next (action_it))
214         {
215           GimpAction  *action        = action_it->data;
216           const gchar *name          = gimp_action_get_name (action);
217           GClosure    *accel_closure = NULL;
218 
219           if (strstr (name, "-menu")  ||
220               strstr (name, "-popup") ||
221               name[0] == '<')
222               continue;
223 
224           accel_closure = gimp_action_get_accel_closure (action);
225 
226           if (accel_closure)
227             {
228               GtkAccelKey *key = gtk_accel_group_find (accel_group,
229                                                        debug_accel_find_func,
230                                                        accel_closure);
231               if (key            &&
232                   key->accel_key &&
233                   key->accel_flags & GTK_ACCEL_VISIBLE)
234                 {
235                   const gchar *label_tmp;
236                   gchar       *label;
237                   gchar       *key_string;
238 
239                   label_tmp  = gimp_action_get_label (action);
240                   label      = gimp_strip_uline (label_tmp);
241                   key_string = gtk_accelerator_get_label (key->accel_key,
242                                                           key->accel_mods);
243 
244                   strings = g_list_prepend (strings,
245                                             g_strdup_printf ("%-20s %s",
246                                                              key_string, label));
247 
248                   g_free (key_string);
249                   g_free (label);
250                 }
251             }
252         }
253 
254       g_list_free (actions);
255     }
256 
257   /* Sort and prints the strings */
258   {
259     GList *string_it = NULL;
260 
261     strings = g_list_sort (strings, (GCompareFunc) strcmp);
262 
263     for (string_it = strings; string_it; string_it = g_list_next (string_it))
264       {
265         g_print ("%s\n", (gchar *) string_it->data);
266         g_free (string_it->data);
267       }
268 
269     g_list_free (strings);
270   }
271 }
272 
273 void
debug_dump_attached_data_cmd_callback(GimpAction * action,GVariant * value,gpointer data)274 debug_dump_attached_data_cmd_callback (GimpAction *action,
275                                        GVariant   *value,
276                                        gpointer    data)
277 {
278   Gimp        *gimp         = action_data_get_gimp (data);
279   GimpContext *user_context = gimp_get_user_context (gimp);
280 
281   debug_print_qdata (GIMP_OBJECT (gimp));
282   debug_print_qdata (GIMP_OBJECT (user_context));
283 }
284 
285 
286 /*  private functions  */
287 
288 static gboolean
debug_benchmark_projection(GimpDisplay * display)289 debug_benchmark_projection (GimpDisplay *display)
290 {
291   GimpImage *image = gimp_display_get_image (display);
292 
293   if (image)
294     {
295       GimpProjection *projection = gimp_image_get_projection (image);
296 
297       gimp_projection_stop_rendering (projection);
298 
299       GIMP_TIMER_START ();
300 
301       gimp_image_invalidate_all (image);
302       gimp_projection_flush_now (projection, TRUE);
303 
304       GIMP_TIMER_END ("Validation of the entire projection");
305 
306       g_object_unref (display);
307     }
308 
309   return FALSE;
310 }
311 
312 static gboolean
debug_show_image_graph(GimpImage * source_image)313 debug_show_image_graph (GimpImage *source_image)
314 {
315   GeglNode   *image_graph;
316   GeglNode   *output_node;
317   GimpImage  *new_image;
318   GeglNode   *introspect;
319   GeglNode   *sink;
320   GeglBuffer *buffer;
321   gchar      *new_name;
322 
323   image_graph = gimp_projectable_get_graph (GIMP_PROJECTABLE (source_image));
324 
325   output_node = gegl_node_get_output_proxy (image_graph, "output");
326 
327   introspect = gegl_node_new_child (NULL,
328                                     "operation", "gegl:introspect",
329                                     "node",      output_node,
330                                     NULL);
331   sink = gegl_node_new_child (NULL,
332                               "operation", "gegl:buffer-sink",
333                               "buffer",    &buffer,
334                               NULL);
335 
336   gegl_node_link_many (introspect, sink, NULL);
337   gegl_node_process (sink);
338 
339   new_name = g_strdup_printf ("%s GEGL graph",
340                               gimp_image_get_display_name (source_image));
341 
342   new_image = gimp_create_image_from_buffer (source_image->gimp,
343                                              buffer, new_name);
344   gimp_image_set_file (new_image, g_file_new_for_uri (new_name));
345 
346   g_free (new_name);
347 
348   g_object_unref (buffer);
349 
350   g_object_unref (sink);
351   g_object_unref (introspect);
352 
353   g_object_unref (source_image);
354 
355   return FALSE;
356 }
357 
358 static void
debug_dump_menus_recurse_menu(GtkWidget * menu,gint depth,gchar * path)359 debug_dump_menus_recurse_menu (GtkWidget *menu,
360                                gint       depth,
361                                gchar     *path)
362 {
363   GList *children;
364   GList *list;
365 
366   children = gtk_container_get_children (GTK_CONTAINER (menu));
367 
368   for (list = children; list; list = g_list_next (list))
369     {
370       GtkWidget *menu_item = GTK_WIDGET (list->data);
371       GtkWidget *child     = gtk_bin_get_child (GTK_BIN (menu_item));
372 
373       if (GTK_IS_LABEL (child))
374         {
375           GtkWidget   *submenu;
376           const gchar *label;
377           gchar       *full_path;
378           gchar       *help_page;
379           gchar       *format_str;
380 
381           label = gtk_label_get_text (GTK_LABEL (child));
382           full_path = g_strconcat (path, "/", label, NULL);
383 
384           help_page = g_object_get_data (G_OBJECT (menu_item), "gimp-help-id");
385           help_page = g_strdup (help_page);
386 
387           format_str = g_strdup_printf ("%%%ds%%%ds %%-20s %%s\n",
388                                         depth * 2, depth * 2 - 40);
389           g_print (format_str,
390                    "", label, "", help_page ? help_page : "");
391           g_free (format_str);
392           g_free (help_page);
393 
394           submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (menu_item));
395 
396           if (submenu)
397             debug_dump_menus_recurse_menu (submenu, depth + 1, full_path);
398 
399           g_free (full_path);
400         }
401     }
402 
403   g_list_free (children);
404 }
405 
406 static void
debug_print_qdata(GimpObject * object)407 debug_print_qdata (GimpObject *object)
408 {
409   g_print ("\nData attached to '%s':\n\n", gimp_object_get_name (object));
410   g_datalist_foreach (&G_OBJECT (object)->qdata,
411                       debug_print_qdata_foreach,
412                       NULL);
413   g_print ("\n");
414 }
415 
416 static void
debug_print_qdata_foreach(GQuark key_id,gpointer data,gpointer user_data)417 debug_print_qdata_foreach (GQuark   key_id,
418                            gpointer data,
419                            gpointer user_data)
420 {
421   g_print ("%s: %p\n", g_quark_to_string (key_id), data);
422 }
423 
424 static gboolean
debug_accel_find_func(GtkAccelKey * key,GClosure * closure,gpointer data)425 debug_accel_find_func (GtkAccelKey *key,
426                        GClosure    *closure,
427                        gpointer     data)
428 {
429   return (GClosure *) data == closure;
430 }
431