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