1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 2009 Martin Nordholts <martinn@src.gnome.org>
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 <stdlib.h>
19 #include <string.h>
20
21 #include <gegl.h>
22 #include <gtk/gtk.h>
23 #include <gdk/gdkkeysyms.h>
24
25 #include "libgimpbase/gimpbase.h"
26 #include "libgimpmath/gimpmath.h"
27 #include "libgimpwidgets/gimpwidgets.h"
28
29 #include "dialogs/dialogs-types.h"
30
31 #include "display/gimpdisplay.h"
32 #include "display/gimpdisplayshell.h"
33 #include "display/gimpdisplayshell-scale.h"
34 #include "display/gimpdisplayshell-transform.h"
35 #include "display/gimpimagewindow.h"
36
37 #include "widgets/gimpdialogfactory.h"
38 #include "widgets/gimpdock.h"
39 #include "widgets/gimpdockable.h"
40 #include "widgets/gimpdockbook.h"
41 #include "widgets/gimpdockcontainer.h"
42 #include "widgets/gimpdocked.h"
43 #include "widgets/gimpdockwindow.h"
44 #include "widgets/gimphelp-ids.h"
45 #include "widgets/gimpsessioninfo.h"
46 #include "widgets/gimpsessioninfo-aux.h"
47 #include "widgets/gimpsessionmanaged.h"
48 #include "widgets/gimptoolbox.h"
49 #include "widgets/gimptooloptionseditor.h"
50 #include "widgets/gimpuimanager.h"
51 #include "widgets/gimpwidgets-utils.h"
52
53 #include "core/gimp.h"
54 #include "core/gimpchannel.h"
55 #include "core/gimpcontext.h"
56 #include "core/gimpimage.h"
57 #include "core/gimplayer.h"
58 #include "core/gimplayer-new.h"
59 #include "core/gimptoolinfo.h"
60 #include "core/gimptooloptions.h"
61
62 #include "tests.h"
63
64 #include "gimp-app-test-utils.h"
65
66
67 #define GIMP_UI_WINDOW_POSITION_EPSILON 30
68 #define GIMP_UI_POSITION_EPSILON 1
69 #define GIMP_UI_ZOOM_EPSILON 0.01
70
71 #define ADD_TEST(function) \
72 g_test_add_data_func ("/gimp-ui/" #function, gimp, function);
73
74
75 /* Put this in the code below when you want the test to pause so you
76 * can do measurements of widgets on the screen for example
77 */
78 #define GIMP_PAUSE (g_usleep (20 * 1000 * 1000))
79
80
81 typedef gboolean (*GimpUiTestFunc) (GObject *object);
82
83
84 static void gimp_ui_synthesize_delete_event (GtkWidget *widget);
85 static gboolean gimp_ui_synthesize_click (GtkWidget *widget,
86 gint x,
87 gint y,
88 gint button,
89 GdkModifierType modifiers);
90 static GtkWidget * gimp_ui_find_window (GimpDialogFactory *dialog_factory,
91 GimpUiTestFunc predicate);
92 static gboolean gimp_ui_not_toolbox_window (GObject *object);
93 static gboolean gimp_ui_multicolumn_not_toolbox_window (GObject *object);
94 static gboolean gimp_ui_is_gimp_layer_list (GObject *object);
95 static int gimp_ui_aux_data_eqiuvalent (gconstpointer _a,
96 gconstpointer _b);
97 static void gimp_ui_switch_window_mode (Gimp *gimp);
98
99
100 /**
101 * tool_options_editor_updates:
102 * @data:
103 *
104 * Makes sure that the tool options editor is updated when the tool
105 * changes.
106 **/
107 static void
tool_options_editor_updates(gconstpointer data)108 tool_options_editor_updates (gconstpointer data)
109 {
110 Gimp *gimp = GIMP (data);
111 GimpDisplay *display = GIMP_DISPLAY (gimp_get_empty_display (gimp));
112 GimpDisplayShell *shell = gimp_display_get_shell (display);
113 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (shell));
114 GimpImageWindow *image_window = GIMP_IMAGE_WINDOW (toplevel);
115 GimpUIManager *ui_manager = gimp_image_window_get_ui_manager (image_window);
116 GtkWidget *dockable = gimp_dialog_factory_dialog_new (gimp_dialog_factory_get_singleton (),
117 gtk_widget_get_screen (toplevel),
118 gimp_widget_get_monitor (toplevel),
119 NULL /*ui_manager*/,
120 "gimp-tool-options",
121 -1 /*view_size*/,
122 FALSE /*present*/);
123 GimpToolOptionsEditor *editor = GIMP_TOOL_OPTIONS_EDITOR (gtk_bin_get_child (GTK_BIN (dockable)));
124
125 /* First select the rect select tool */
126 gimp_ui_manager_activate_action (ui_manager,
127 "tools",
128 "tools-rect-select");
129 g_assert_cmpstr (GIMP_HELP_TOOL_RECT_SELECT,
130 ==,
131 gimp_tool_options_editor_get_tool_options (editor)->
132 tool_info->help_id);
133
134 /* Change tool and make sure the change is taken into account by the
135 * tool options editor
136 */
137 gimp_ui_manager_activate_action (ui_manager,
138 "tools",
139 "tools-ellipse-select");
140 g_assert_cmpstr (GIMP_HELP_TOOL_ELLIPSE_SELECT,
141 ==,
142 gimp_tool_options_editor_get_tool_options (editor)->
143 tool_info->help_id);
144 }
145
146 static GtkWidget *
gimp_ui_get_dialog(const gchar * identifier)147 gimp_ui_get_dialog (const gchar *identifier)
148 {
149 GtkWidget *result = NULL;
150 GList *iter;
151
152 for (iter = gimp_dialog_factory_get_open_dialogs (gimp_dialog_factory_get_singleton ());
153 iter;
154 iter = g_list_next (iter))
155 {
156 GtkWidget *dialog = GTK_WIDGET (iter->data);
157 GimpDialogFactoryEntry *entry = NULL;
158
159 gimp_dialog_factory_from_widget (dialog, &entry);
160
161 if (strcmp (entry->identifier, identifier) == 0)
162 {
163 result = dialog;
164 break;
165 }
166 }
167
168 return result;
169 }
170
171 static void
automatic_tab_style(gconstpointer data)172 automatic_tab_style (gconstpointer data)
173 {
174 GtkWidget *channel_dockable = gimp_ui_get_dialog ("gimp-channel-list");
175 GimpDockable *dockable;
176 GimpUIManager *ui_manager;
177 g_assert (channel_dockable != NULL);
178
179 dockable = GIMP_DOCKABLE (channel_dockable);
180
181 gimp_test_run_mainloop_until_idle ();
182
183 /* The channel dockable is the only dockable, it has enough space
184 * for the icon-blurb
185 */
186 g_assert_cmpint (GIMP_TAB_STYLE_ICON_BLURB,
187 ==,
188 gimp_dockable_get_actual_tab_style (dockable));
189
190 /* Add some dockables to the channel dockable dockbook */
191 ui_manager =
192 gimp_dockbook_get_ui_manager (gimp_dockable_get_dockbook (dockable));
193 gimp_ui_manager_activate_action (ui_manager,
194 "dockable",
195 "dialogs-sample-points");
196 gimp_ui_manager_activate_action (ui_manager,
197 "dockable",
198 "dialogs-vectors");
199 gimp_test_run_mainloop_until_idle ();
200
201 /* Now there is not enough space to have icon-blurb for channel
202 * dockable, make sure it's just an icon now
203 */
204 g_assert_cmpint (GIMP_TAB_STYLE_ICON,
205 ==,
206 gimp_dockable_get_actual_tab_style (dockable));
207
208 /* Close the two dockables we added */
209 gimp_ui_manager_activate_action (ui_manager,
210 "dockable",
211 "dockable-close-tab");
212 gimp_ui_manager_activate_action (ui_manager,
213 "dockable",
214 "dockable-close-tab");
215 gimp_test_run_mainloop_until_idle ();
216
217 /* We should now be back on icon-blurb */
218 g_assert_cmpint (GIMP_TAB_STYLE_ICON_BLURB,
219 ==,
220 gimp_dockable_get_actual_tab_style (dockable));
221 }
222
223 static void
create_new_image_via_dialog(gconstpointer data)224 create_new_image_via_dialog (gconstpointer data)
225 {
226 Gimp *gimp = GIMP (data);
227 GimpImage *image;
228 GimpLayer *layer;
229
230 image = gimp_test_utils_create_image_from_dialog (gimp);
231
232 /* Add a layer to the image to make it more useful in later tests */
233 layer = gimp_layer_new (image,
234 gimp_image_get_width (image),
235 gimp_image_get_height (image),
236 gimp_image_get_layer_format (image, TRUE),
237 "Layer for testing",
238 GIMP_OPACITY_OPAQUE,
239 GIMP_LAYER_MODE_NORMAL);
240
241 gimp_image_add_layer (image, layer,
242 GIMP_IMAGE_ACTIVE_PARENT, -1, TRUE);
243 gimp_test_run_mainloop_until_idle ();
244 }
245
246 static void
keyboard_zoom_focus(gconstpointer data)247 keyboard_zoom_focus (gconstpointer data)
248 {
249 Gimp *gimp = GIMP (data);
250 GimpDisplay *display = GIMP_DISPLAY (gimp_get_display_iter (gimp)->data);
251 GimpDisplayShell *shell = gimp_display_get_shell (display);
252 GimpImageWindow *window = gimp_display_shell_get_window (shell);
253 gint image_x;
254 gint image_y;
255 gint shell_x_before_zoom;
256 gint shell_y_before_zoom;
257 gdouble factor_before_zoom;
258 gint shell_x_after_zoom;
259 gint shell_y_after_zoom;
260 gdouble factor_after_zoom;
261
262 /* We need to use a point that is within the visible (exposed) part
263 * of the canvas
264 */
265 image_x = 400;
266 image_y = 50;
267
268 /* Setup zoom focus on the bottom right part of the image. We avoid
269 * 0,0 because that's essentially a particularly easy special case.
270 */
271 gimp_display_shell_transform_xy (shell,
272 image_x,
273 image_y,
274 &shell_x_before_zoom,
275 &shell_y_before_zoom);
276 gimp_display_shell_push_zoom_focus_pointer_pos (shell,
277 shell_x_before_zoom,
278 shell_y_before_zoom);
279 factor_before_zoom = gimp_zoom_model_get_factor (shell->zoom);
280
281 /* Do the zoom */
282 gimp_test_utils_synthesize_key_event (GTK_WIDGET (window), GDK_KEY_plus);
283 gimp_test_run_mainloop_until_idle ();
284
285 /* Make sure the zoom focus point remained fixed */
286 gimp_display_shell_transform_xy (shell,
287 image_x,
288 image_y,
289 &shell_x_after_zoom,
290 &shell_y_after_zoom);
291 factor_after_zoom = gimp_zoom_model_get_factor (shell->zoom);
292
293 /* First of all make sure a zoom happened at all. If this assert
294 * fails, it means that the zoom didn't happen. Possible causes:
295 *
296 * * gdk_test_simulate_key() failed to map 'GDK_KEY_plus' to the proper
297 * 'plus' X keysym, probably because it is mapped to a keycode
298 * with modifiers like 'shift'. Run "xmodmap -pk | grep plus" to
299 * find out. Make sure 'plus' is the first keysym for the given
300 * keycode. If not, use "xmodmap <keycode> = plus" to correct it.
301 */
302 g_assert_cmpfloat (fabs (factor_before_zoom - factor_after_zoom),
303 >=,
304 GIMP_UI_ZOOM_EPSILON);
305
306 #ifdef __GNUC__
307 #warning disabled zoom test, it fails randomly, no clue how to fix it
308 #endif
309 #if 0
310 g_assert_cmpint (ABS (shell_x_after_zoom - shell_x_before_zoom),
311 <=,
312 GIMP_UI_POSITION_EPSILON);
313 g_assert_cmpint (ABS (shell_y_after_zoom - shell_y_before_zoom),
314 <=,
315 GIMP_UI_POSITION_EPSILON);
316 #endif
317 }
318
319 /**
320 * alt_click_is_layer_to_selection:
321 * @data:
322 *
323 * Makes sure that we can alt-click on a layer to do
324 * layer-to-selection. Also makes sure that the layer clicked on is
325 * not set as the active layer.
326 **/
327 static void
alt_click_is_layer_to_selection(gconstpointer data)328 alt_click_is_layer_to_selection (gconstpointer data)
329 {
330 #if __GNUC__
331 #warning FIXME: please fix alt_click_is_layer_to_selection test
332 #endif
333 #if 0
334 Gimp *gimp = GIMP (data);
335 GimpImage *image = GIMP_IMAGE (gimp_get_image_iter (gimp)->data);
336 GimpChannel *selection = gimp_image_get_mask (image);
337 GimpLayer *active_layer;
338 GtkWidget *dockable;
339 GtkWidget *gtk_tree_view;
340 gint assumed_layer_x;
341 gint assumed_empty_layer_y;
342 gint assumed_background_layer_y;
343
344 /* Hardcode assumptions of where the layers are in the
345 * GtkTreeView. Doesn't feel worth adding proper API for this. One
346 * can just use GIMP_PAUSE and re-measure new coordinates if we
347 * start to layout layers in the GtkTreeView differently
348 */
349 assumed_layer_x = 96;
350 assumed_empty_layer_y = 16;
351 assumed_background_layer_y = 42;
352
353 /* Store the active layer, it shall not change during the execution
354 * of this test
355 */
356 active_layer = gimp_image_get_active_layer (image);
357
358 /* Find the layer tree view to click in. Note that there is a
359 * potential problem with gtk_test_find_widget and GtkNotebook: it
360 * will return e.g. a GtkTreeView from another page if that page is
361 * "on top" of the reference label.
362 */
363 dockable = gimp_ui_find_window (gimp_dialog_factory_get_singleton (),
364 gimp_ui_is_gimp_layer_list);
365 gtk_tree_view = gtk_test_find_widget (dockable,
366 "Lock:",
367 GTK_TYPE_TREE_VIEW);
368
369 /* First make sure there is no selection */
370 g_assert (gimp_channel_is_empty (selection));
371
372 /* Now simulate alt-click on the background layer */
373 g_assert (gimp_ui_synthesize_click (gtk_tree_view,
374 assumed_layer_x,
375 assumed_background_layer_y,
376 1 /*button*/,
377 GDK_MOD1_MASK));
378 gimp_test_run_mainloop_until_idle ();
379
380 /* Make sure we got a selection and that the active layer didn't
381 * change
382 */
383 g_assert (! gimp_channel_is_empty (selection));
384 g_assert (gimp_image_get_active_layer (image) == active_layer);
385
386 /* Now simulate alt-click on the empty layer */
387 g_assert (gimp_ui_synthesize_click (gtk_tree_view,
388 assumed_layer_x,
389 assumed_empty_layer_y,
390 1 /*button*/,
391 GDK_MOD1_MASK));
392 gimp_test_run_mainloop_until_idle ();
393
394 /* Make sure that emptied the selection and that the active layer
395 * still didn't change
396 */
397 g_assert (gimp_channel_is_empty (selection));
398 g_assert (gimp_image_get_active_layer (image) == active_layer);
399 #endif
400 }
401
402 static void
restore_recently_closed_multi_column_dock(gconstpointer data)403 restore_recently_closed_multi_column_dock (gconstpointer data)
404 {
405 Gimp *gimp = GIMP (data);
406 GtkWidget *dock_window = NULL;
407 gint n_session_infos_before_close = -1;
408 gint n_session_infos_after_close = -1;
409 gint n_session_infos_after_restore = -1;
410 GList *session_infos = NULL;
411
412 /* Find a non-toolbox dock window */
413 dock_window = gimp_ui_find_window (gimp_dialog_factory_get_singleton (),
414 gimp_ui_multicolumn_not_toolbox_window);
415 g_assert (dock_window != NULL);
416
417 /* Count number of docks */
418 session_infos = gimp_dialog_factory_get_session_infos (gimp_dialog_factory_get_singleton ());
419 n_session_infos_before_close = g_list_length (session_infos);
420
421 /* Close one of the dock windows */
422 gimp_ui_synthesize_delete_event (GTK_WIDGET (dock_window));
423 gimp_test_run_mainloop_until_idle ();
424
425 /* Make sure the number of session infos went down */
426 session_infos = gimp_dialog_factory_get_session_infos (gimp_dialog_factory_get_singleton ());
427 n_session_infos_after_close = g_list_length (session_infos);
428 g_assert_cmpint (n_session_infos_before_close,
429 >,
430 n_session_infos_after_close);
431
432 #ifdef __GNUC__
433 #warning FIXME test disabled until we depend on GTK+ >= 2.24.11
434 #endif
435 #if 0
436 /* Restore the (only available) closed dock and make sure the session
437 * infos in the global dock factory are increased again
438 */
439 gimp_ui_manager_activate_action (gimp_test_utils_get_ui_manager (gimp),
440 "windows",
441 /* FIXME: This is severely hardcoded */
442 "windows-recent-0003");
443 gimp_test_run_mainloop_until_idle ();
444 session_infos = gimp_dialog_factory_get_session_infos (gimp_dialog_factory_get_singleton ());
445 n_session_infos_after_restore = g_list_length (session_infos);
446 g_assert_cmpint (n_session_infos_after_close,
447 <,
448 n_session_infos_after_restore);
449 #endif
450 }
451
452 /**
453 * tab_toggle_dont_change_dock_window_position:
454 * @data:
455 *
456 * Makes sure that when dock windows are hidden with Tab and shown
457 * again, their positions and sizes are not changed. We don't really
458 * use Tab though, we only simulate its effect.
459 **/
460 static void
tab_toggle_dont_change_dock_window_position(gconstpointer data)461 tab_toggle_dont_change_dock_window_position (gconstpointer data)
462 {
463 Gimp *gimp = GIMP (data);
464 GtkWidget *dock_window = NULL;
465 gint x_before_hide = -1;
466 gint y_before_hide = -1;
467 gint w_before_hide = -1;
468 gint h_before_hide = -1;
469 gint x_after_show = -1;
470 gint y_after_show = -1;
471 gint w_after_show = -1;
472 gint h_after_show = -1;
473
474 /* Find a non-toolbox dock window */
475 dock_window = gimp_ui_find_window (gimp_dialog_factory_get_singleton (),
476 gimp_ui_not_toolbox_window);
477 g_assert (dock_window != NULL);
478 g_assert (gtk_widget_get_visible (dock_window));
479
480 /* Get the position and size */
481 gimp_test_run_mainloop_until_idle ();
482 gtk_window_get_position (GTK_WINDOW (dock_window),
483 &x_before_hide,
484 &y_before_hide);
485 gtk_window_get_size (GTK_WINDOW (dock_window),
486 &w_before_hide,
487 &h_before_hide);
488
489 /* Hide all dock windows */
490 gimp_ui_manager_activate_action (gimp_test_utils_get_ui_manager (gimp),
491 "windows",
492 "windows-hide-docks");
493 gimp_test_run_mainloop_until_idle ();
494 g_assert (! gtk_widget_get_visible (dock_window));
495
496 /* Show them again */
497 gimp_ui_manager_activate_action (gimp_test_utils_get_ui_manager (gimp),
498 "windows",
499 "windows-hide-docks");
500 gimp_test_run_mainloop_until_idle ();
501 g_assert (gtk_widget_get_visible (dock_window));
502
503 /* Get the position and size again and make sure it's the same as
504 * before
505 */
506 gtk_window_get_position (GTK_WINDOW (dock_window),
507 &x_after_show,
508 &y_after_show);
509 gtk_window_get_size (GTK_WINDOW (dock_window),
510 &w_after_show,
511 &h_after_show);
512 g_assert_cmpint ((int)abs (x_before_hide - x_after_show), <=, GIMP_UI_WINDOW_POSITION_EPSILON);
513 g_assert_cmpint ((int)abs (y_before_hide - y_after_show), <=, GIMP_UI_WINDOW_POSITION_EPSILON);
514 g_assert_cmpint ((int)abs (w_before_hide - w_after_show), <=, GIMP_UI_WINDOW_POSITION_EPSILON);
515 g_assert_cmpint ((int)abs (h_before_hide - h_after_show), <=, GIMP_UI_WINDOW_POSITION_EPSILON);
516 }
517
518 static void
switch_to_single_window_mode(gconstpointer data)519 switch_to_single_window_mode (gconstpointer data)
520 {
521 Gimp *gimp = GIMP (data);
522
523 /* Switch to single-window mode. We consider this test as passed if
524 * we don't get any GLib warnings/errors
525 */
526 gimp_ui_switch_window_mode (gimp);
527 }
528
529 static void
gimp_ui_toggle_docks_in_single_window_mode(Gimp * gimp)530 gimp_ui_toggle_docks_in_single_window_mode (Gimp *gimp)
531 {
532 GimpDisplay *display = GIMP_DISPLAY (gimp_get_display_iter (gimp)->data);
533 GimpDisplayShell *shell = gimp_display_get_shell (display);
534 GtkWidget *toplevel = GTK_WIDGET (gimp_display_shell_get_window (shell));
535 gint x_temp = -1;
536 gint y_temp = -1;
537 gint x_before_hide = -1;
538 gint y_before_hide = -1;
539 gint x_after_hide = -1;
540 gint y_after_hide = -1;
541 g_assert (shell);
542 g_assert (toplevel);
543
544 /* Get toplevel coordinate of image origin */
545 gimp_test_run_mainloop_until_idle ();
546 gimp_display_shell_transform_xy (shell,
547 0.0, 0.0,
548 &x_temp, &y_temp);
549 gtk_widget_translate_coordinates (GTK_WIDGET (shell),
550 toplevel,
551 x_temp, y_temp,
552 &x_before_hide, &y_before_hide);
553
554 /* Hide all dock windows */
555 gimp_ui_manager_activate_action (gimp_test_utils_get_ui_manager (gimp),
556 "windows",
557 "windows-hide-docks");
558 gimp_test_run_mainloop_until_idle ();
559
560 /* Get toplevel coordinate of image origin */
561 gimp_test_run_mainloop_until_idle ();
562 gimp_display_shell_transform_xy (shell,
563 0.0, 0.0,
564 &x_temp, &y_temp);
565 gtk_widget_translate_coordinates (GTK_WIDGET (shell),
566 toplevel,
567 x_temp, y_temp,
568 &x_after_hide, &y_after_hide);
569
570 g_assert_cmpint ((int)abs (x_after_hide - x_before_hide), <=, GIMP_UI_POSITION_EPSILON);
571 g_assert_cmpint ((int)abs (y_after_hide - y_before_hide), <=, GIMP_UI_POSITION_EPSILON);
572 }
573
574 static void
hide_docks_in_single_window_mode(gconstpointer data)575 hide_docks_in_single_window_mode (gconstpointer data)
576 {
577 Gimp *gimp = GIMP (data);
578 gimp_ui_toggle_docks_in_single_window_mode (gimp);
579 }
580
581 static void
show_docks_in_single_window_mode(gconstpointer data)582 show_docks_in_single_window_mode (gconstpointer data)
583 {
584 Gimp *gimp = GIMP (data);
585 gimp_ui_toggle_docks_in_single_window_mode (gimp);
586 }
587
588 static void
maximize_state_in_aux_data(gconstpointer data)589 maximize_state_in_aux_data (gconstpointer data)
590 {
591 Gimp *gimp = GIMP (data);
592 GimpDisplay *display = GIMP_DISPLAY (gimp_get_display_iter (gimp)->data);
593 GimpDisplayShell *shell = gimp_display_get_shell (display);
594 GimpImageWindow *window = gimp_display_shell_get_window (shell);
595 gint i;
596
597 for (i = 0; i < 2; i++)
598 {
599 GList *aux_info = NULL;
600 GimpSessionInfoAux *target_info;
601 gboolean target_max_state;
602
603 if (i == 0)
604 {
605 target_info = gimp_session_info_aux_new ("maximized" , "yes");
606 target_max_state = TRUE;
607 }
608 else
609 {
610 target_info = gimp_session_info_aux_new ("maximized", "no");
611 target_max_state = FALSE;
612 }
613
614 /* Set the aux info to out target data */
615 aux_info = g_list_append (aux_info, target_info);
616 gimp_session_managed_set_aux_info (GIMP_SESSION_MANAGED (window), aux_info);
617 g_list_free (aux_info);
618
619 /* Give the WM a chance to maximize/unmaximize us */
620 gimp_test_run_mainloop_until_idle ();
621 g_usleep (500 * 1000);
622 gimp_test_run_mainloop_until_idle ();
623
624 /* Make sure the maximize/unmaximize happened */
625 g_assert (gimp_image_window_is_maximized (window) == target_max_state);
626
627 /* Make sure we can read out the window state again */
628 aux_info = gimp_session_managed_get_aux_info (GIMP_SESSION_MANAGED (window));
629 g_assert (g_list_find_custom (aux_info, target_info, gimp_ui_aux_data_eqiuvalent));
630 g_list_free_full (aux_info,
631 (GDestroyNotify) gimp_session_info_aux_free);
632
633 gimp_session_info_aux_free (target_info);
634 }
635 }
636
637 static void
switch_back_to_multi_window_mode(gconstpointer data)638 switch_back_to_multi_window_mode (gconstpointer data)
639 {
640 Gimp *gimp = GIMP (data);
641
642 /* Switch back to multi-window mode. We consider this test as passed
643 * if we don't get any GLib warnings/errors
644 */
645 gimp_ui_switch_window_mode (gimp);
646 }
647
648 static void
close_image(gconstpointer data)649 close_image (gconstpointer data)
650 {
651 Gimp *gimp = GIMP (data);
652 int undo_count = 4;
653
654 /* Undo all changes so we don't need to find the 'Do you want to
655 * save?'-dialog and its 'No' button
656 */
657 while (undo_count--)
658 {
659 gimp_ui_manager_activate_action (gimp_test_utils_get_ui_manager (gimp),
660 "edit",
661 "edit-undo");
662 gimp_test_run_mainloop_until_idle ();
663 }
664
665 /* Close the image */
666 gimp_ui_manager_activate_action (gimp_test_utils_get_ui_manager (gimp),
667 "view",
668 "view-close");
669 gimp_test_run_mainloop_until_idle ();
670
671 /* Did it really disappear? */
672 g_assert_cmpint (g_list_length (gimp_get_image_iter (gimp)), ==, 0);
673 }
674
675 /**
676 * repeatedly_switch_window_mode:
677 * @data:
678 *
679 * Makes sure that the size of the image window is properly handled
680 * when repeatedly switching between window modes.
681 **/
682 static void
repeatedly_switch_window_mode(gconstpointer data)683 repeatedly_switch_window_mode (gconstpointer data)
684 {
685 #ifdef __GNUC__
686 #warning FIXME: plesase fix repeatedly_switch_window_mode test
687 #endif
688 #if 0
689 Gimp *gimp = GIMP (data);
690 GimpDisplay *display = GIMP_DISPLAY (gimp_get_empty_display (gimp));
691 GimpDisplayShell *shell = gimp_display_get_shell (display);
692 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (shell));
693
694 gint expected_initial_height;
695 gint expected_initial_width;
696 gint expected_second_height;
697 gint expected_second_width;
698 gint initial_width;
699 gint initial_height;
700 gint second_width;
701 gint second_height;
702
703 /* We need this for some reason */
704 gimp_test_run_mainloop_until_idle ();
705
706 /* Remember the multi-window mode size */
707 gtk_window_get_size (GTK_WINDOW (toplevel),
708 &expected_initial_width,
709 &expected_initial_height);
710
711 /* Switch to single-window mode */
712 gimp_ui_switch_window_mode (gimp);
713
714 /* Remember the single-window mode size */
715 gtk_window_get_size (GTK_WINDOW (toplevel),
716 &expected_second_width,
717 &expected_second_height);
718
719 /* Make sure they differ, otherwise the test is pointless */
720 g_assert_cmpint (expected_initial_width, !=, expected_second_width);
721 g_assert_cmpint (expected_initial_height, !=, expected_second_height);
722
723 /* Switch back to multi-window mode */
724 gimp_ui_switch_window_mode (gimp);
725
726 /* Make sure the size is the same as before */
727 gtk_window_get_size (GTK_WINDOW (toplevel), &initial_width, &initial_height);
728 g_assert_cmpint (expected_initial_width, ==, initial_width);
729 g_assert_cmpint (expected_initial_height, ==, initial_height);
730
731 /* Switch to single-window mode again... */
732 gimp_ui_switch_window_mode (gimp);
733
734 /* Make sure the size is the same as before */
735 gtk_window_get_size (GTK_WINDOW (toplevel), &second_width, &second_height);
736 g_assert_cmpint (expected_second_width, ==, second_width);
737 g_assert_cmpint (expected_second_height, ==, second_height);
738
739 /* Finally switch back to multi-window mode since that was the mode
740 * when we started
741 */
742 gimp_ui_switch_window_mode (gimp);
743 #endif
744 }
745
746 /**
747 * window_roles:
748 * @data:
749 *
750 * Makes sure that different windows have the right roles specified.
751 **/
752 static void
window_roles(gconstpointer data)753 window_roles (gconstpointer data)
754 {
755 GtkWidget *dock = NULL;
756 GtkWidget *toolbox = NULL;
757 GimpDockWindow *dock_window = NULL;
758 GimpDockWindow *toolbox_window = NULL;
759
760 dock = gimp_dock_with_window_new (gimp_dialog_factory_get_singleton (),
761 gdk_screen_get_default (),
762 0,
763 FALSE /*toolbox*/);
764 toolbox = gimp_dock_with_window_new (gimp_dialog_factory_get_singleton (),
765 gdk_screen_get_default (),
766 0,
767 TRUE /*toolbox*/);
768 dock_window = gimp_dock_window_from_dock (GIMP_DOCK (dock));
769 toolbox_window = gimp_dock_window_from_dock (GIMP_DOCK (toolbox));
770
771 g_assert_cmpint (g_str_has_prefix (gtk_window_get_role (GTK_WINDOW (dock_window)), "gimp-dock-"), ==,
772 TRUE);
773 g_assert_cmpint (g_str_has_prefix (gtk_window_get_role (GTK_WINDOW (toolbox_window)), "gimp-toolbox-"), ==,
774 TRUE);
775
776 /* When we get here we have a ref count of one, but the signals we
777 * emit cause the reference count to become less than zero for some
778 * reason. So we're lazy and simply ignore to unref these
779 g_object_unref (toolbox);
780 g_object_unref (dock);
781 */
782 }
783
784 static void
paintbrush_is_standard_tool(gconstpointer data)785 paintbrush_is_standard_tool (gconstpointer data)
786 {
787 Gimp *gimp = GIMP (data);
788 GimpContext *user_context = gimp_get_user_context (gimp);
789 GimpToolInfo *tool_info = gimp_context_get_tool (user_context);
790
791 g_assert_cmpstr (tool_info->help_id,
792 ==,
793 "gimp-tool-paintbrush");
794 }
795
796 /**
797 * gimp_ui_synthesize_delete_event:
798 * @widget:
799 *
800 * Synthesize a delete event to @widget.
801 **/
802 static void
gimp_ui_synthesize_delete_event(GtkWidget * widget)803 gimp_ui_synthesize_delete_event (GtkWidget *widget)
804 {
805 GdkWindow *window = NULL;
806 GdkEvent *event = NULL;
807
808 window = gtk_widget_get_window (widget);
809 g_assert (window);
810
811 event = gdk_event_new (GDK_DELETE);
812 event->any.window = g_object_ref (window);
813 event->any.send_event = TRUE;
814 gtk_main_do_event (event);
815 gdk_event_free (event);
816 }
817
818 static gboolean
gimp_ui_synthesize_click(GtkWidget * widget,gint x,gint y,gint button,GdkModifierType modifiers)819 gimp_ui_synthesize_click (GtkWidget *widget,
820 gint x,
821 gint y,
822 gint button, /*1..3*/
823 GdkModifierType modifiers)
824 {
825 return (gdk_test_simulate_button (gtk_widget_get_window (widget),
826 x, y,
827 button,
828 modifiers,
829 GDK_BUTTON_PRESS) &&
830 gdk_test_simulate_button (gtk_widget_get_window (widget),
831 x, y,
832 button,
833 modifiers,
834 GDK_BUTTON_RELEASE));
835 }
836
837 static GtkWidget *
gimp_ui_find_window(GimpDialogFactory * dialog_factory,GimpUiTestFunc predicate)838 gimp_ui_find_window (GimpDialogFactory *dialog_factory,
839 GimpUiTestFunc predicate)
840 {
841 GList *iter = NULL;
842 GtkWidget *dock_window = NULL;
843
844 g_return_val_if_fail (predicate != NULL, NULL);
845
846 for (iter = gimp_dialog_factory_get_session_infos (dialog_factory);
847 iter;
848 iter = g_list_next (iter))
849 {
850 GtkWidget *widget = gimp_session_info_get_widget (iter->data);
851
852 if (predicate (G_OBJECT (widget)))
853 {
854 dock_window = widget;
855 break;
856 }
857 }
858
859 return dock_window;
860 }
861
862 static gboolean
gimp_ui_not_toolbox_window(GObject * object)863 gimp_ui_not_toolbox_window (GObject *object)
864 {
865 return (GIMP_IS_DOCK_WINDOW (object) &&
866 ! gimp_dock_window_has_toolbox (GIMP_DOCK_WINDOW (object)));
867 }
868
869 static gboolean
gimp_ui_multicolumn_not_toolbox_window(GObject * object)870 gimp_ui_multicolumn_not_toolbox_window (GObject *object)
871 {
872 gboolean not_toolbox_window;
873 GimpDockWindow *dock_window;
874 GimpDockContainer *dock_container;
875 GList *docks;
876
877 if (! GIMP_IS_DOCK_WINDOW (object))
878 return FALSE;
879
880 dock_window = GIMP_DOCK_WINDOW (object);
881 dock_container = GIMP_DOCK_CONTAINER (object);
882 docks = gimp_dock_container_get_docks (dock_container);
883
884 not_toolbox_window = (! gimp_dock_window_has_toolbox (dock_window) &&
885 g_list_length (docks) > 1);
886
887 g_list_free (docks);
888
889 return not_toolbox_window;
890 }
891
892 static gboolean
gimp_ui_is_gimp_layer_list(GObject * object)893 gimp_ui_is_gimp_layer_list (GObject *object)
894 {
895 GimpDialogFactoryEntry *entry = NULL;
896
897 if (! GTK_IS_WIDGET (object))
898 return FALSE;
899
900 gimp_dialog_factory_from_widget (GTK_WIDGET (object), &entry);
901
902 return strcmp (entry->identifier, "gimp-layer-list") == 0;
903 }
904
905 static int
gimp_ui_aux_data_eqiuvalent(gconstpointer _a,gconstpointer _b)906 gimp_ui_aux_data_eqiuvalent (gconstpointer _a, gconstpointer _b)
907 {
908 GimpSessionInfoAux *a = (GimpSessionInfoAux*) _a;
909 GimpSessionInfoAux *b = (GimpSessionInfoAux*) _b;
910 return (strcmp (a->name, b->name) || strcmp (a->value, b->value));
911 }
912
913 static void
gimp_ui_switch_window_mode(Gimp * gimp)914 gimp_ui_switch_window_mode (Gimp *gimp)
915 {
916 gimp_ui_manager_activate_action (gimp_test_utils_get_ui_manager (gimp),
917 "windows",
918 "windows-use-single-window-mode");
919 gimp_test_run_mainloop_until_idle ();
920
921 /* Add a small sleep to let things stabilize */
922 g_usleep (500 * 1000);
923 gimp_test_run_mainloop_until_idle ();
924 }
925
main(int argc,char ** argv)926 int main(int argc, char **argv)
927 {
928 Gimp *gimp = NULL;
929 gint result = -1;
930
931 gimp_test_bail_if_no_display ();
932 gtk_test_init (&argc, &argv, NULL);
933
934 gimp_test_utils_set_gimp2_directory ("GIMP_TESTING_ABS_TOP_SRCDIR",
935 "app/tests/gimpdir");
936 gimp_test_utils_setup_menus_path ();
937
938 /* Start up GIMP */
939 gimp = gimp_init_for_gui_testing (TRUE /*show_gui*/);
940 gimp_test_run_mainloop_until_idle ();
941
942 /* Add tests. Note that the order matters. For example,
943 * 'paintbrush_is_standard_tool' can't be after
944 * 'tool_options_editor_updates'
945 */
946 ADD_TEST (paintbrush_is_standard_tool);
947 ADD_TEST (tool_options_editor_updates);
948 ADD_TEST (automatic_tab_style);
949 ADD_TEST (create_new_image_via_dialog);
950 ADD_TEST (keyboard_zoom_focus);
951 ADD_TEST (alt_click_is_layer_to_selection);
952 ADD_TEST (restore_recently_closed_multi_column_dock);
953 ADD_TEST (tab_toggle_dont_change_dock_window_position);
954 ADD_TEST (switch_to_single_window_mode);
955 #warning FIXME: hide/show docks doesn't work when running make check
956 #if 0
957 ADD_TEST (hide_docks_in_single_window_mode);
958 ADD_TEST (show_docks_in_single_window_mode);
959 #endif
960 #warning FIXME: maximize_state_in_aux_data doesn't work without WM
961 #if 0
962 ADD_TEST (maximize_state_in_aux_data);
963 #endif
964 ADD_TEST (switch_back_to_multi_window_mode);
965 ADD_TEST (close_image);
966 ADD_TEST (repeatedly_switch_window_mode);
967 ADD_TEST (window_roles);
968
969 /* Run the tests and return status */
970 result = g_test_run ();
971
972 /* Don't write files to the source dir */
973 gimp_test_utils_set_gimp2_directory ("GIMP_TESTING_ABS_TOP_BUILDDIR",
974 "app/tests/gimpdir-output");
975
976 /* Exit properly so we don't break script-fu plug-in wire */
977 gimp_exit (gimp, TRUE);
978
979 return result;
980 }
981