diff options
Diffstat (limited to '')
-rw-r--r-- | app/tests/gimp-app-test-utils.c | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/app/tests/gimp-app-test-utils.c b/app/tests/gimp-app-test-utils.c new file mode 100644 index 0000000..33b8bdd --- /dev/null +++ b/app/tests/gimp-app-test-utils.c @@ -0,0 +1,460 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 2009 Martin Nordholts <martinn@src.gnome.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl.h> +#include <gtk/gtk.h> + +#include "display/display-types.h" + +#include "display/gimpdisplay.h" +#include "display/gimpdisplayshell.h" +#include "display/gimpimagewindow.h" + +#include "widgets/gimpuimanager.h" +#include "widgets/gimpdialogfactory.h" + +#include "core/gimp.h" +#include "core/gimpimage.h" +#include "core/gimplayer.h" +#include "core/gimplayer-new.h" + +#include "tests.h" + +#include "gimp-app-test-utils.h" + +#ifdef G_OS_WIN32 +/* SendInput() requirement is Windows 2000 pro or over. + * We may need to set WINVER to make sure the compiler does not try to + * compile for on older version of win32, thus breaking the build. + * See + * http://msdn.microsoft.com/en-us/library/aa383745%28v=vs.85%29.aspx#setting_winver_or__win32_winnt + */ +#define WINVER 0x0500 +#include <windows.h> +#endif /* G_OS_WIN32 */ + +#ifdef GDK_WINDOWING_QUARTZ +// only to get keycode definitions from HIToolbox/Events.h +#include <Carbon/Carbon.h> +#include <Cocoa/Cocoa.h> +#endif /* GDK_WINDOWING_QUARTZ */ + +void +gimp_test_utils_set_env_to_subdir (const gchar *root_env_var, + const gchar *subdir, + const gchar *target_env_var) +{ + const gchar *root_dir = NULL; + gchar *target_dir = NULL; + + /* Get root dir */ + root_dir = g_getenv (root_env_var); + if (! root_dir) + g_printerr ("*\n" + "* The env var %s is not set, you are probably running\n" + "* in a debugger. Set it manually, e.g.:\n" + "*\n" + "* set env %s=%s/source/gimp\n" + "*\n", + root_env_var, + root_env_var, g_get_home_dir ()); + + /* Construct path and setup target env var */ + target_dir = g_build_filename (root_dir, subdir, NULL); + g_setenv (target_env_var, target_dir, TRUE); + g_free (target_dir); +} + +void +gimp_test_utils_set_env_to_subpath (const gchar *root_env_var1, + const gchar *root_env_var2, + const gchar *subdir, + const gchar *target_env_var) +{ + const gchar *root_dir1 = NULL; + const gchar *root_dir2 = NULL; + gchar *target_dir1 = NULL; + gchar *target_dir2 = NULL; + gchar *target_path = NULL; + + /* Get root dir */ + root_dir1 = g_getenv (root_env_var1); + if (! root_dir1) + g_printerr ("*\n" + "* The env var %s is not set, you are probably running\n" + "* in a debugger. Set it manually, e.g.:\n" + "*\n" + "* set env %s=%s/source/gimp\n" + "*\n", + root_env_var1, + root_env_var1, g_get_home_dir ()); + + root_dir2 = g_getenv (root_env_var2); + if (! root_dir2) + g_printerr ("*\n" + "* The env var %s is not set, you are probably running\n" + "* in a debugger. Set it manually, e.g.:\n" + "*\n" + "* set env %s=%s/source/gimp\n" + "*\n", + root_env_var2, + root_env_var2, g_get_home_dir ()); + + /* Construct path and setup target env var */ + target_dir1 = g_build_filename (root_dir1, subdir, NULL); + target_dir2 = g_build_filename (root_dir2, subdir, NULL); + + target_path = g_strconcat (target_dir1, G_SEARCHPATH_SEPARATOR_S, + target_dir2, NULL); + + g_free (target_dir1); + g_free (target_dir2); + + g_setenv (target_env_var, target_path, TRUE); + g_free (target_path); +} + + +/** + * gimp_test_utils_set_gimp2_directory: + * @root_env_var: Either "GIMP_TESTING_ABS_TOP_SRCDIR" or + * "GIMP_TESTING_ABS_TOP_BUILDDIR" + * @subdir: Subdir, may be %NULL + * + * Sets GIMP2_DIRECTORY to the source dir @root_env_var/@subdir. The + * environment variables is set up by the test runner, see Makefile.am + **/ +void +gimp_test_utils_set_gimp2_directory (const gchar *root_env_var, + const gchar *subdir) +{ + gimp_test_utils_set_env_to_subdir (root_env_var, + subdir, + "GIMP2_DIRECTORY" /*target_env_var*/); +} + +/** + * gimp_test_utils_setup_menus_path: + * + * Sets GIMP_TESTING_MENUS_PATH to "$top_srcdir/menus:$top_builddir/menus". + **/ +void +gimp_test_utils_setup_menus_path (void) +{ + /* GIMP_TESTING_ABS_TOP_SRCDIR is set by the automake test runner, + * see Makefile.am + */ + gimp_test_utils_set_env_to_subpath ("GIMP_TESTING_ABS_TOP_SRCDIR", + "GIMP_TESTING_ABS_TOP_BUILDDIR", + "menus", + "GIMP_TESTING_MENUS_PATH"); +} + +/** + * gimp_test_utils_create_image: + * @gimp: A #Gimp instance. + * @width: Width of image (and layer) + * @height: Height of image (and layer) + * + * Creates a new image of a given size with one layer of same size and + * a display. + * + * Returns: The new #GimpImage. + **/ +void +gimp_test_utils_create_image (Gimp *gimp, + gint width, + gint height) +{ + GimpImage *image; + GimpLayer *layer; + + image = gimp_image_new (gimp, width, height, + GIMP_RGB, GIMP_PRECISION_U8_GAMMA); + + layer = gimp_layer_new (image, + width, + height, + gimp_image_get_layer_format (image, TRUE), + "layer1", + 1.0, + GIMP_LAYER_MODE_NORMAL); + + gimp_image_add_layer (image, + layer, + NULL /*parent*/, + 0 /*position*/, + FALSE /*push_undo*/); + + gimp_create_display (gimp, + image, + GIMP_UNIT_PIXEL, + 1.0 /*scale*/, + NULL, 0); +} + +/** + * gimp_test_utils_synthesize_key_event: + * @widget: Widget to target. + * @keyval: Keyval, e.g. GDK_Return + * + * Simulates a keypress and release with gdk_test_simulate_key(). + **/ +void +gimp_test_utils_synthesize_key_event (GtkWidget *widget, + guint keyval) +{ +#if defined G_OS_WIN32 && ! GTK_CHECK_VERSION (2, 24, 25) + /* gdk_test_simulate_key() has no implementation for win32 until + * GTK+ 2.24.25. + * TODO: remove the below hack when our GTK+ requirement is over 2.24.25. */ + GdkKeymapKey *keys = NULL; + gint n_keys = 0; + INPUT ip; + gint i; + + ip.type = INPUT_KEYBOARD; + ip.ki.wScan = 0; + ip.ki.time = 0; + ip.ki.dwExtraInfo = 0; + if (gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), keyval, &keys, &n_keys)) + { + for (i = 0; i < n_keys; i++) + { + ip.ki.dwFlags = 0; + /* AltGr press. */ + if (keys[i].group) + { + /* According to some virtualbox code I found, AltGr is + * simulated on win32 with LCtrl+RAlt */ + ip.ki.wVk = VK_CONTROL; + SendInput(1, &ip, sizeof(INPUT)); + ip.ki.wVk = VK_MENU; + SendInput(1, &ip, sizeof(INPUT)); + } + /* Shift press. */ + if (keys[i].level) + { + ip.ki.wVk = VK_SHIFT; + SendInput(1, &ip, sizeof(INPUT)); + } + /* Key pressed. */ + ip.ki.wVk = keys[i].keycode; + SendInput(1, &ip, sizeof(INPUT)); + + ip.ki.dwFlags = KEYEVENTF_KEYUP; + /* Key released. */ + SendInput(1, &ip, sizeof(INPUT)); + /* Shift release. */ + if (keys[i].level) + { + ip.ki.wVk = VK_SHIFT; + SendInput(1, &ip, sizeof(INPUT)); + } + /* AltrGr release. */ + if (keys[i].group) + { + ip.ki.wVk = VK_MENU; + SendInput(1, &ip, sizeof(INPUT)); + ip.ki.wVk = VK_CONTROL; + SendInput(1, &ip, sizeof(INPUT)); + } + /* No need to loop for alternative keycodes. We want only one + * key generated. */ + break; + } + g_free (keys); + } + else + { + g_warning ("%s: no win32 key mapping found for keyval %d.", G_STRFUNC, keyval); + } +#elif defined(GDK_WINDOWING_QUARTZ) + +GdkKeymapKey *keys = NULL; +gint n_keys = 0; +gint i; +CGEventRef keyUp, keyDown; + +if (gdk_keymap_get_entries_for_keyval (gdk_keymap_get_for_display (gdk_display_get_default ()), keyval, &keys, &n_keys)) + { + /* XXX not in use yet */ + CGEventRef commandDown = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)kVK_Command, true); + CGEventRef commandUp = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)kVK_Command, false); + + CGEventRef shiftDown = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)kVK_Shift, true); + CGEventRef shiftUp = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)kVK_Shift, false); + + CGEventRef optionDown = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)kVK_Option, true); + CGEventRef optionUp = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)kVK_Option, false); + + for (i = 0; i < n_keys; i++) + { + /* Option press. */ + if (keys[i].group) + { + CGEventPost (kCGHIDEventTap, optionDown); + } + /* Shift press. */ + if (keys[i].level) + { + CGEventPost(kCGHIDEventTap, shiftDown); + } + keyDown = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)keys[i].keycode, true); + keyUp = CGEventCreateKeyboardEvent (NULL, (CGKeyCode)keys[i].keycode, false); + /* Key pressed. */ + CGEventPost (kCGHIDEventTap, keyDown); + CFRelease (keyDown); + usleep (100); + /* key released */ + CGEventPost (kCGHIDEventTap, keyUp); + CFRelease (keyUp); + + /* Shift release. */ + if (keys[i].level) + { + CGEventPost (kCGHIDEventTap, shiftDown); + } + + /* Option release. */ + if (keys[i].group) + { + CGEventPost (kCGHIDEventTap, optionUp); + } + /* No need to loop for alternative keycodes. We want only one + * key generated. */ + break; + } + CFRelease (commandDown); + CFRelease (commandUp); + CFRelease (shiftDown); + CFRelease (shiftUp); + CFRelease (optionDown); + CFRelease (optionUp); + g_free (keys); + } +else + { + g_warning ("%s: no macOS key mapping found for keyval %d.", G_STRFUNC, keyval); + } + +#else /* G_OS_WIN32 && ! GTK_CHECK_VERSION (2, 24, 25) && ! GDK_WINDOWING_QUARTZ */ + gdk_test_simulate_key (gtk_widget_get_window (widget), + -1, -1, /*x, y*/ + keyval, + 0 /*modifiers*/, + GDK_KEY_PRESS); + gdk_test_simulate_key (gtk_widget_get_window (widget), + -1, -1, /*x, y*/ + keyval, + 0 /*modifiers*/, + GDK_KEY_RELEASE); +#endif /* G_OS_WIN32 && ! GTK_CHECK_VERSION (2, 24, 25) */ +} + +/** + * gimp_test_utils_get_ui_manager: + * @gimp: The #Gimp instance. + * + * Returns the "best" #GimpUIManager to use when performing + * actions. It gives the ui manager of the empty display if it exists, + * otherwise it gives it the ui manager of the first display. + * + * Returns: The #GimpUIManager. + **/ +GimpUIManager * +gimp_test_utils_get_ui_manager (Gimp *gimp) +{ + GimpDisplay *display = NULL; + GimpDisplayShell *shell = NULL; + GtkWidget *toplevel = NULL; + GimpImageWindow *image_window = NULL; + GimpUIManager *ui_manager = NULL; + + display = GIMP_DISPLAY (gimp_get_empty_display (gimp)); + + /* If there were not empty display, assume that there is at least + * one image display and use that + */ + if (! display) + display = GIMP_DISPLAY (gimp_get_display_iter (gimp)->data); + + shell = gimp_display_get_shell (display); + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (shell)); + image_window = GIMP_IMAGE_WINDOW (toplevel); + ui_manager = gimp_image_window_get_ui_manager (image_window); + + return ui_manager; +} + +/** + * gimp_test_utils_create_image_from_dalog: + * @gimp: + * + * Creates a new image using the "New image" dialog, and then returns + * the #GimpImage created. + * + * Returns: The created #GimpImage. + **/ +GimpImage * +gimp_test_utils_create_image_from_dialog (Gimp *gimp) +{ + GimpImage *image = NULL; + GtkWidget *new_image_dialog = NULL; + guint n_initial_images = g_list_length (gimp_get_image_iter (gimp)); + guint n_images = -1; + gint tries_left = 100; + GimpUIManager *ui_manager = gimp_test_utils_get_ui_manager (gimp); + + /* Bring up the new image dialog */ + gimp_ui_manager_activate_action (ui_manager, + "image", + "image-new"); + gimp_test_run_mainloop_until_idle (); + + /* Get the GtkWindow of the dialog */ + new_image_dialog = + gimp_dialog_factory_dialog_raise (gimp_dialog_factory_get_singleton (), + gdk_screen_get_default (), 0, + "gimp-image-new-dialog", + -1 /*view_size*/); + + /* Press the focused widget, it should be the Ok button. It will + * take a while for the image to be created so loop for a while + */ + gtk_widget_activate (gtk_window_get_focus (GTK_WINDOW (new_image_dialog))); + do + { + g_usleep (20 * 1000); + gimp_test_run_mainloop_until_idle (); + n_images = g_list_length (gimp_get_image_iter (gimp)); + } + while (tries_left-- && + n_images != n_initial_images + 1); + + /* Make sure there now is one image more than initially */ + g_assert_cmpint (n_images, + ==, + n_initial_images + 1); + + image = GIMP_IMAGE (gimp_get_image_iter (gimp)->data); + + return image; +} + |