Updated with upstream update

This commit is contained in:
Cassowary 2023-10-30 15:55:30 -07:00
parent 098531073c
commit 3bbdd873ef
584 changed files with 91827 additions and 70362 deletions

View File

@ -18,7 +18,8 @@
# - PIKA_CI_CROSSROAD_WIN64: trigger the crossroad/meson build for Win 64-bit. # - PIKA_CI_CROSSROAD_WIN64: trigger the crossroad/meson build for Win 64-bit.
# - PIKA_CI_MSYS2_WIN32: trigger the native MSYS2 build for Win 32-bit. # - PIKA_CI_MSYS2_WIN32: trigger the native MSYS2 build for Win 32-bit.
# - PIKA_CI_MSYS2_WIN64: trigger the native MSYS2 build for Win 64-bit. # - PIKA_CI_MSYS2_WIN64: trigger the native MSYS2 build for Win 64-bit.
# - PIKA_CI_WIN_INSTALLER: trigger both native MSYS2 builds then creates Windows installer. # - PIKA_CI_MSYS2_WIN_AARCH64: trigger the native MSYS2 build for Windows/Aarch64.
# - PIKA_CI_WIN_INSTALLER: trigger all native MSYS2 builds then creates Windows installer.
# - PIKA_CI_SOURCES: trigger the meson/gcc build and the source tarball job. # - PIKA_CI_SOURCES: trigger the meson/gcc build and the source tarball job.
# - PIKA_CI_CPPCHECK: trigger cppcheck static analysis. # - PIKA_CI_CPPCHECK: trigger cppcheck static analysis.
# - PIKA_CI_FLATPAK: trigger the nightly flatpak build and publishing. # - PIKA_CI_FLATPAK: trigger the nightly flatpak build and publishing.
@ -375,7 +376,7 @@ pika-meson-raster-icons:
- ninja -C _build - ninja -C _build
- ninja -C _build test - ninja -C _build test
## WINDOWS 64-bit CI (native MSYS2) ## ## WINDOWS x86_64 CI (native MSYS2) ##
deps-win64-native: deps-win64-native:
rules: rules:
@ -462,7 +463,7 @@ packaging-win64-native:
- done-dll.list - done-dll.list
needs: ["pika-win64-native"] needs: ["pika-win64-native"]
## WINDOWS 32-bit CI (native MSYS2) ## ## WINDOWS x86 CI (native MSYS2) ##
deps-win32-native: deps-win32-native:
rules: rules:
@ -548,6 +549,96 @@ packaging-win32-native:
- done-dll.list - done-dll.list
needs: ["pika-win32-native"] needs: ["pika-win32-native"]
## WINDOWS Aarch64 CI (native MSYS2) ##
deps-win-aarch64-native:
rules:
# On releases.
- if: '$CI_COMMIT_TAG != null'
# Custom builds though web GUI, API or schedules.
- if: '$PIKA_CI_MSYS2_WIN_AARCH64 != null'
- if: '$PIKA_CI_WIN_INSTALLER != null'
# Merge requests with appropriate label.
- if: '$CI_MERGE_REQUEST_LABELS =~ /.*5. Windows Installer.*/'
stage: dependencies
variables:
MSYSTEM: "CLANGARM64"
CHERE_INVOKING: "yes"
tags:
- windows-aarch64
script:
- C:\msys64\usr\bin\pacman --noconfirm -Syyuu
- C:\msys64\usr\bin\bash -lc "bash -x ./build/windows/gitlab-ci/build-deps-msys2.sh"
artifacts:
name: "${CI_JOB_NAME}-${CI_COMMIT_REF_SLUG}"
when: always
expire_in: 2 hours
paths:
- _install-arm64
needs: []
pika-win-aarch64-native:
rules:
# On releases.
- if: '$CI_COMMIT_TAG != null'
# Custom builds though web GUI, API or schedules.
- if: '$PIKA_CI_MSYS2_WIN_AARCH64 != null'
- if: '$PIKA_CI_WIN_INSTALLER != null'
# Merge requests with appropriate label.
- if: '$CI_MERGE_REQUEST_LABELS =~ /.*5. Windows Installer.*/'
stage: pika
variables:
MSYSTEM: "CLANGARM64"
CHERE_INVOKING: "yes"
tags:
- windows-aarch64
script:
# Temporary patch until we use the latest LLVM.
- git apply ./build/windows/patches/0001-clang-rc-files-fix.patch
- git apply ./build/windows/patches/0004-clang-windres.patch
- C:\msys64\usr\bin\pacman --noconfirm -Syyuu
- C:\msys64\usr\bin\bash -lc "bash -x ./build/windows/gitlab-ci/build-pika-msys2.sh"
artifacts:
name: "${CI_JOB_NAME}-${CI_COMMIT_REF_SLUG}"
when: always
expire_in: 1 day
paths:
- _install-arm64
- _build-arm64/build/windows/installer/
- _build-arm64/meson-*/
cache:
paths:
- _ccache/
needs: ["deps-win-aarch64-native"]
packaging-win-aarch64-native:
rules:
# On releases.
- if: '$CI_COMMIT_TAG != null'
# Custom builds though web GUI, API or schedules.
- if: '$PIKA_CI_WIN_INSTALLER != null'
# Merge requests with appropriate label.
- if: '$CI_MERGE_REQUEST_LABELS =~ /.*5. Windows Installer.*/'
stage: packaging
variables:
MSYSTEM: "CLANGARM64"
CHERE_INVOKING: "yes"
tags:
- windows-aarch64
script:
- C:\msys64\usr\bin\pacman --noconfirm -Syyuu
- C:\msys64\usr\bin\bash -lc "bash -x ./build/windows/gitlab-ci/package-pika-msys2.sh"
- cd pika-arm64
- C:\msys64\usr\bin\bash -lc "bash -x ../build/windows/gitlab-ci/split-debug-msys2.sh"
artifacts:
name: "${CI_JOB_NAME}-${CI_COMMIT_REF_SLUG}"
when: always
expire_in: 1 day
paths:
- pika-arm64
- done-dll.list
needs: ["pika-win-aarch64-native"]
## WINDOWS 64-bit CI (cross-build crossroad) ## ## WINDOWS 64-bit CI (cross-build crossroad) ##
deps-win64: deps-win64:
@ -822,6 +913,7 @@ win-installer-nightly:
dependencies: dependencies:
- packaging-win64-native - packaging-win64-native
- packaging-win32-native - packaging-win32-native
- packaging-win-aarch64-native
# This is needed for the BMP image generation for the installer. # This is needed for the BMP image generation for the installer.
# See commit e1203e9f76f. # See commit e1203e9f76f.
- pika-meson-debian - pika-meson-debian
@ -835,7 +927,7 @@ win-installer-nightly:
script: script:
- C:\msys64\usr\bin\pacman --noconfirm -Syyuu - C:\msys64\usr\bin\pacman --noconfirm -Syyuu
- C:\msys64\usr\bin\bash -lc "bash -x ./build/windows/gitlab-ci/installer-pika-msys2.sh > installer.log 2>&1" - C:\msys64\usr\bin\bash -lc "bash -x ./build/windows/gitlab-ci/installer-pika-msys2.sh > installer.log 2>&1"
needs: ["packaging-win32-native", "packaging-win64-native", "pika-meson-debian"] needs: ["packaging-win32-native", "packaging-win64-native", "packaging-win-aarch64-native", "pika-meson-debian"]
sources-meson: sources-meson:
rules: rules:

View File

@ -34,6 +34,7 @@
#include "core/pikaimage-colormap.h" #include "core/pikaimage-colormap.h"
#include "widgets/pikaactiongroup.h" #include "widgets/pikaactiongroup.h"
#include "widgets/pikacolormapeditor.h"
#include "widgets/pikahelp-ids.h" #include "widgets/pikahelp-ids.h"
#include "actions.h" #include "actions.h"
@ -49,6 +50,12 @@ static const PikaActionEntry colormap_actions[] =
NC_("colormap-action", "_Edit Color..."), NULL, { NULL }, NC_("colormap-action", "_Edit Color..."), NULL, { NULL },
NC_("colormap-action", "Edit this color"), NC_("colormap-action", "Edit this color"),
colormap_edit_color_cmd_callback, colormap_edit_color_cmd_callback,
PIKA_HELP_INDEXED_PALETTE_EDIT },
{ "colormap-delete-color", PIKA_ICON_EDIT_DELETE,
NC_("colormap-action", "_Delete Color..."), NULL, { NULL },
NC_("colormap-action", "Delete this color"),
colormap_delete_color_cmd_callback,
PIKA_HELP_INDEXED_PALETTE_EDIT } PIKA_HELP_INDEXED_PALETTE_EDIT }
}; };
@ -116,13 +123,14 @@ void
colormap_actions_update (PikaActionGroup *group, colormap_actions_update (PikaActionGroup *group,
gpointer data) gpointer data)
{ {
PikaImage *image = action_data_get_image (data); PikaColormapEditor *editor = PIKA_COLORMAP_EDITOR (data);
PikaContext *context = action_data_get_context (data); PikaImage *image = action_data_get_image (data);
gboolean indexed = FALSE; PikaContext *context = action_data_get_context (data);
gboolean drawable_indexed = FALSE; gboolean indexed = FALSE;
gint num_colors = 0; gboolean drawable_indexed = FALSE;
PikaRGB fg; gint num_colors = 0;
PikaRGB bg; PikaRGB fg;
PikaRGB bg;
if (image) if (image)
{ {
@ -154,6 +162,9 @@ colormap_actions_update (PikaActionGroup *group,
SET_SENSITIVE ("colormap-edit-color", SET_SENSITIVE ("colormap-edit-color",
indexed && num_colors > 0); indexed && num_colors > 0);
SET_SENSITIVE ("colormap-delete-color",
indexed && num_colors > 0 &&
pika_colormap_editor_is_color_deletable (editor));
SET_SENSITIVE ("colormap-add-color-from-fg", SET_SENSITIVE ("colormap-add-color-from-fg",
indexed && num_colors < 256); indexed && num_colors < 256);

View File

@ -50,6 +50,16 @@ colormap_edit_color_cmd_callback (PikaAction *action,
pika_colormap_editor_edit_color (editor); pika_colormap_editor_edit_color (editor);
} }
void
colormap_delete_color_cmd_callback (PikaAction *action,
GVariant *value,
gpointer data)
{
PikaColormapEditor *editor = PIKA_COLORMAP_EDITOR (data);
pika_colormap_editor_delete_color (editor);
}
void void
colormap_add_color_cmd_callback (PikaAction *action, colormap_add_color_cmd_callback (PikaAction *action,
GVariant *value, GVariant *value,

View File

@ -26,6 +26,9 @@
void colormap_edit_color_cmd_callback (PikaAction *action, void colormap_edit_color_cmd_callback (PikaAction *action,
GVariant *value, GVariant *value,
gpointer data); gpointer data);
void colormap_delete_color_cmd_callback (PikaAction *action,
GVariant *value,
gpointer data);
void colormap_add_color_cmd_callback (PikaAction *action, void colormap_add_color_cmd_callback (PikaAction *action,
GVariant *value, GVariant *value,
gpointer data); gpointer data);

View File

@ -446,7 +446,7 @@ pika_gegl_procedure_new (Pika *pika,
FALSE, FALSE,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
g_param_spec_int ("n-drawables", g_param_spec_int ("num-drawables",
"N drawables", "N drawables",
"The number of drawables", "The number of drawables",
0, G_MAXINT32, 0, 0, G_MAXINT32, 0,

View File

@ -50,7 +50,7 @@ _("Timestamp of the last update check.")
"Defines the color management behavior." "Defines the color management behavior."
#define COLOR_PROFILE_POLICY_BLURB \ #define COLOR_PROFILE_POLICY_BLURB \
_("How to handle embedded color profiles when opening a file.") _("What to do when opening a file with an embedded ICC color profile.")
#define COLOR_PROFILE_PATH_BLURB \ #define COLOR_PROFILE_PATH_BLURB \
_("Sets the default folder path for all color profile file dialogs.") _("Sets the default folder path for all color profile file dialogs.")

View File

@ -1195,6 +1195,7 @@ pika_undo_type_get_type (void)
{ PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE, "PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE", "group-image-vectors-merge" }, { PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE, "PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE", "group-image-vectors-merge" },
{ PIKA_UNDO_GROUP_IMAGE_QUICK_MASK, "PIKA_UNDO_GROUP_IMAGE_QUICK_MASK", "group-image-quick-mask" }, { PIKA_UNDO_GROUP_IMAGE_QUICK_MASK, "PIKA_UNDO_GROUP_IMAGE_QUICK_MASK", "group-image-quick-mask" },
{ PIKA_UNDO_GROUP_IMAGE_GRID, "PIKA_UNDO_GROUP_IMAGE_GRID", "group-image-grid" }, { PIKA_UNDO_GROUP_IMAGE_GRID, "PIKA_UNDO_GROUP_IMAGE_GRID", "group-image-grid" },
{ PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP, "PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP", "group-image-colormap-remap" },
{ PIKA_UNDO_GROUP_GUIDE, "PIKA_UNDO_GROUP_GUIDE", "group-guide" }, { PIKA_UNDO_GROUP_GUIDE, "PIKA_UNDO_GROUP_GUIDE", "group-guide" },
{ PIKA_UNDO_GROUP_SAMPLE_POINT, "PIKA_UNDO_GROUP_SAMPLE_POINT", "group-sample-point" }, { PIKA_UNDO_GROUP_SAMPLE_POINT, "PIKA_UNDO_GROUP_SAMPLE_POINT", "group-sample-point" },
{ PIKA_UNDO_GROUP_DRAWABLE, "PIKA_UNDO_GROUP_DRAWABLE", "group-drawable" }, { PIKA_UNDO_GROUP_DRAWABLE, "PIKA_UNDO_GROUP_DRAWABLE", "group-drawable" },
@ -1303,6 +1304,7 @@ pika_undo_type_get_type (void)
{ PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE, NC_("undo-type", "Merge paths"), NULL }, { PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE, NC_("undo-type", "Merge paths"), NULL },
{ PIKA_UNDO_GROUP_IMAGE_QUICK_MASK, NC_("undo-type", "Quick Mask"), NULL }, { PIKA_UNDO_GROUP_IMAGE_QUICK_MASK, NC_("undo-type", "Quick Mask"), NULL },
{ PIKA_UNDO_GROUP_IMAGE_GRID, NC_("undo-type", "Grid"), NULL }, { PIKA_UNDO_GROUP_IMAGE_GRID, NC_("undo-type", "Grid"), NULL },
{ PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP, NC_("undo-type", "Colormap remapping"), NULL },
{ PIKA_UNDO_GROUP_GUIDE, NC_("undo-type", "Guide"), NULL }, { PIKA_UNDO_GROUP_GUIDE, NC_("undo-type", "Guide"), NULL },
{ PIKA_UNDO_GROUP_SAMPLE_POINT, NC_("undo-type", "Sample Point"), NULL }, { PIKA_UNDO_GROUP_SAMPLE_POINT, NC_("undo-type", "Sample Point"), NULL },
{ PIKA_UNDO_GROUP_DRAWABLE, NC_("undo-type", "Layer/Channel"), NULL }, { PIKA_UNDO_GROUP_DRAWABLE, NC_("undo-type", "Layer/Channel"), NULL },

View File

@ -548,6 +548,7 @@ typedef enum /*< pdb-skip >*/
PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE, /*< desc="Merge paths" >*/ PIKA_UNDO_GROUP_IMAGE_VECTORS_MERGE, /*< desc="Merge paths" >*/
PIKA_UNDO_GROUP_IMAGE_QUICK_MASK, /*< desc="Quick Mask" >*/ PIKA_UNDO_GROUP_IMAGE_QUICK_MASK, /*< desc="Quick Mask" >*/
PIKA_UNDO_GROUP_IMAGE_GRID, /*< desc="Grid" >*/ PIKA_UNDO_GROUP_IMAGE_GRID, /*< desc="Grid" >*/
PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP, /*< desc="Colormap remapping" >*/
PIKA_UNDO_GROUP_GUIDE, /*< desc="Guide" >*/ PIKA_UNDO_GROUP_GUIDE, /*< desc="Guide" >*/
PIKA_UNDO_GROUP_SAMPLE_POINT, /*< desc="Sample Point" >*/ PIKA_UNDO_GROUP_SAMPLE_POINT, /*< desc="Sample Point" >*/
PIKA_UNDO_GROUP_DRAWABLE, /*< desc="Layer/Channel" >*/ PIKA_UNDO_GROUP_DRAWABLE, /*< desc="Layer/Channel" >*/

View File

@ -33,8 +33,10 @@
#include "pikacontainer.h" #include "pikacontainer.h"
#include "pikacontext.h" #include "pikacontext.h"
#include "pikadisplay.h" #include "pikadisplay.h"
#include "pikadrawable.h"
#include "pikaimage.h" #include "pikaimage.h"
#include "pikaprogress.h" #include "pikaprogress.h"
#include "pikaresource.h"
#include "pikawaitable.h" #include "pikawaitable.h"
#include "about.h" #include "about.h"
@ -325,17 +327,17 @@ pika_get_empty_display (Pika *pika)
return NULL; return NULL;
} }
guint32 GBytes *
pika_get_display_window_id (Pika *pika, pika_get_display_window_id (Pika *pika,
PikaDisplay *display) PikaDisplay *display)
{ {
g_return_val_if_fail (PIKA_IS_PIKA (pika), -1); g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
g_return_val_if_fail (PIKA_IS_DISPLAY (display), -1); g_return_val_if_fail (PIKA_IS_DISPLAY (display), NULL);
if (pika->gui.display_get_window_id) if (pika->gui.display_get_window_id)
return pika->gui.display_get_window_id (display); return pika->gui.display_get_window_id (display);
return -1; return NULL;
} }
PikaDisplay * PikaDisplay *
@ -407,10 +409,11 @@ gboolean
pika_pdb_dialog_new (Pika *pika, pika_pdb_dialog_new (Pika *pika,
PikaContext *context, PikaContext *context,
PikaProgress *progress, PikaProgress *progress,
PikaContainer *container, GType contents_type,
GBytes *parent_handle,
const gchar *title, const gchar *title,
const gchar *callback_name, const gchar *callback_name,
const gchar *object_name, PikaObject *object,
...) ...)
{ {
gboolean retval = FALSE; gboolean retval = FALSE;
@ -418,7 +421,10 @@ pika_pdb_dialog_new (Pika *pika,
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE); g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), FALSE); g_return_val_if_fail (PIKA_IS_CONTEXT (context), FALSE);
g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), FALSE); g_return_val_if_fail (progress == NULL || PIKA_IS_PROGRESS (progress), FALSE);
g_return_val_if_fail (PIKA_IS_CONTAINER (container), FALSE); g_return_val_if_fail (g_type_is_a (contents_type, PIKA_TYPE_RESOURCE) ||
g_type_is_a (contents_type, PIKA_TYPE_DRAWABLE), FALSE);
g_return_val_if_fail (object == NULL ||
g_type_is_a (G_TYPE_FROM_INSTANCE (object), contents_type), FALSE);
g_return_val_if_fail (title != NULL, FALSE); g_return_val_if_fail (title != NULL, FALSE);
g_return_val_if_fail (callback_name != NULL, FALSE); g_return_val_if_fail (callback_name != NULL, FALSE);
@ -426,12 +432,11 @@ pika_pdb_dialog_new (Pika *pika,
{ {
va_list args; va_list args;
va_start (args, object_name); va_start (args, object);
retval = pika->gui.pdb_dialog_new (pika, context, progress, retval = pika->gui.pdb_dialog_new (pika, context, progress,
container, title, contents_type, parent_handle, title,
callback_name, object_name, callback_name, object, args);
args);
va_end (args); va_end (args);
} }
@ -440,27 +445,28 @@ pika_pdb_dialog_new (Pika *pika,
} }
gboolean gboolean
pika_pdb_dialog_set (Pika *pika, pika_pdb_dialog_set (Pika *pika,
PikaContainer *container, GType contents_type,
const gchar *callback_name, const gchar *callback_name,
const gchar *object_name, PikaObject *object,
...) ...)
{ {
gboolean retval = FALSE; gboolean retval = FALSE;
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE); g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
g_return_val_if_fail (PIKA_IS_CONTAINER (container), FALSE); g_return_val_if_fail (g_type_is_a (contents_type, PIKA_TYPE_RESOURCE) ||
contents_type == PIKA_TYPE_DRAWABLE, FALSE);
g_return_val_if_fail (callback_name != NULL, FALSE); g_return_val_if_fail (callback_name != NULL, FALSE);
g_return_val_if_fail (object_name != NULL, FALSE); g_return_val_if_fail (object == NULL || g_type_is_a (G_TYPE_FROM_INSTANCE (object), contents_type), FALSE);
if (pika->gui.pdb_dialog_set) if (pika->gui.pdb_dialog_set)
{ {
va_list args; va_list args;
va_start (args, object_name); va_start (args, object);
retval = pika->gui.pdb_dialog_set (pika, container, callback_name, retval = pika->gui.pdb_dialog_set (pika, contents_type, callback_name,
object_name, args); object, args);
va_end (args); va_end (args);
} }
@ -470,15 +476,16 @@ pika_pdb_dialog_set (Pika *pika,
gboolean gboolean
pika_pdb_dialog_close (Pika *pika, pika_pdb_dialog_close (Pika *pika,
PikaContainer *container, GType contents_type,
const gchar *callback_name) const gchar *callback_name)
{ {
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE); g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
g_return_val_if_fail (PIKA_IS_CONTAINER (container), FALSE); g_return_val_if_fail (g_type_is_a (contents_type, PIKA_TYPE_RESOURCE) ||
contents_type == PIKA_TYPE_DRAWABLE, FALSE);
g_return_val_if_fail (callback_name != NULL, FALSE); g_return_val_if_fail (callback_name != NULL, FALSE);
if (pika->gui.pdb_dialog_close) if (pika->gui.pdb_dialog_close)
return pika->gui.pdb_dialog_close (pika, container, callback_name); return pika->gui.pdb_dialog_close (pika, contents_type, callback_name);
return FALSE; return FALSE;
} }

View File

@ -58,7 +58,7 @@ struct _PikaGui
PikaObject * (* get_window_strategy) (Pika *pika); PikaObject * (* get_window_strategy) (Pika *pika);
PikaDisplay * (* get_empty_display) (Pika *pika); PikaDisplay * (* get_empty_display) (Pika *pika);
guint32 (* display_get_window_id) (PikaDisplay *display); GBytes * (* display_get_window_id) (PikaDisplay *display);
PikaDisplay * (* display_create) (Pika *pika, PikaDisplay * (* display_create) (Pika *pika,
PikaImage *image, PikaImage *image,
PikaUnit unit, PikaUnit unit,
@ -77,18 +77,19 @@ struct _PikaGui
gboolean (* pdb_dialog_new) (Pika *pika, gboolean (* pdb_dialog_new) (Pika *pika,
PikaContext *context, PikaContext *context,
PikaProgress *progress, PikaProgress *progress,
PikaContainer *container, GType contents_type,
GBytes *parent_handle,
const gchar *title, const gchar *title,
const gchar *callback_name, const gchar *callback_name,
const gchar *object_name, PikaObject *object,
va_list args); va_list args);
gboolean (* pdb_dialog_set) (Pika *pika, gboolean (* pdb_dialog_set) (Pika *pika,
PikaContainer *container, GType contents_type,
const gchar *callback_name, const gchar *callback_name,
const gchar *object_name, PikaObject *object,
va_list args); va_list args);
gboolean (* pdb_dialog_close) (Pika *pika, gboolean (* pdb_dialog_close) (Pika *pika,
PikaContainer *container, GType contents_type,
const gchar *callback_name); const gchar *callback_name);
gboolean (* recent_list_add_file) (Pika *pika, gboolean (* recent_list_add_file) (Pika *pika,
GFile *file, GFile *file,
@ -126,7 +127,7 @@ PikaDisplay * pika_get_display_by_id (Pika *pika,
gint ID); gint ID);
gint pika_get_display_id (Pika *pika, gint pika_get_display_id (Pika *pika,
PikaDisplay *display); PikaDisplay *display);
guint32 pika_get_display_window_id (Pika *pika, GBytes * pika_get_display_window_id (Pika *pika,
PikaDisplay *display); PikaDisplay *display);
PikaDisplay * pika_create_display (Pika *pika, PikaDisplay * pika_create_display (Pika *pika,
PikaImage *image, PikaImage *image,
@ -175,19 +176,21 @@ GFile * pika_get_icon_theme_dir (Pika *pika);
gboolean pika_pdb_dialog_new (Pika *pika, gboolean pika_pdb_dialog_new (Pika *pika,
PikaContext *context, PikaContext *context,
PikaProgress *progress, PikaProgress *progress,
PikaContainer *container, GType contents_type,
GBytes *parent_handle,
const gchar *title, const gchar *title,
const gchar *callback_name, const gchar *callback_name,
const gchar *object_name, PikaObject *object,
...) G_GNUC_NULL_TERMINATED; ...) G_GNUC_NULL_TERMINATED;
gboolean pika_pdb_dialog_set (Pika *pika, gboolean pika_pdb_dialog_set (Pika *pika,
PikaContainer *container, GType contents_type,
const gchar *callback_name, const gchar *callback_name,
const gchar *object_name, PikaObject *object,
...) G_GNUC_NULL_TERMINATED; ...) G_GNUC_NULL_TERMINATED;
gboolean pika_pdb_dialog_close (Pika *pika, gboolean pika_pdb_dialog_close (Pika *pika,
PikaContainer *container, GType contents_type,
const gchar *callback_name); const gchar *callback_name);
gboolean pika_recent_list_add_file (Pika *pika, gboolean pika_recent_list_add_file (Pika *pika,
GFile *file, GFile *file,
const gchar *mime_type); const gchar *mime_type);

View File

@ -202,6 +202,7 @@ pika_container_class_init (PikaContainerClass *klass)
klass->search = NULL; klass->search = NULL;
klass->get_unique_names = NULL; klass->get_unique_names = NULL;
klass->get_child_by_name = NULL; klass->get_child_by_name = NULL;
klass->get_children_by_name = NULL;
klass->get_child_by_index = NULL; klass->get_child_by_index = NULL;
klass->get_child_index = NULL; klass->get_child_index = NULL;
@ -885,6 +886,34 @@ pika_container_get_unique_names (PikaContainer *container)
return FALSE; return FALSE;
} }
GList *
pika_container_get_children_by_name (PikaContainer *container,
const gchar *name)
{
g_return_val_if_fail (PIKA_IS_CONTAINER (container), NULL);
if (!name)
return NULL;
if (PIKA_CONTAINER_GET_CLASS (container)->get_children_by_name != NULL &&
! pika_container_get_unique_names (container))
{
return PIKA_CONTAINER_GET_CLASS (container)->get_children_by_name (container,
name);
}
else
{
PikaObject *child;
child = PIKA_CONTAINER_GET_CLASS (container)->get_child_by_name (container, name);
if (child != NULL)
return g_list_prepend (NULL, child);
else
return NULL;
}
}
PikaObject * PikaObject *
pika_container_get_child_by_name (PikaContainer *container, pika_container_get_child_by_name (PikaContainer *container,
const gchar *name) const gchar *name)

View File

@ -79,6 +79,8 @@ struct _PikaContainerClass
gboolean (* get_unique_names) (PikaContainer *container); gboolean (* get_unique_names) (PikaContainer *container);
PikaObject * (* get_child_by_name) (PikaContainer *container, PikaObject * (* get_child_by_name) (PikaContainer *container,
const gchar *name); const gchar *name);
GList * (* get_children_by_name) (PikaContainer *container,
const gchar *name);
PikaObject * (* get_child_by_index) (PikaContainer *container, PikaObject * (* get_child_by_index) (PikaContainer *container,
gint index); gint index);
gint (* get_child_index) (PikaContainer *container, gint (* get_child_index) (PikaContainer *container,
@ -121,6 +123,8 @@ PikaObject * pika_container_search (PikaContainer *contain
gboolean pika_container_get_unique_names (PikaContainer *container); gboolean pika_container_get_unique_names (PikaContainer *container);
GList * pika_container_get_children_by_name (PikaContainer *container,
const gchar *name);
PikaObject * pika_container_get_child_by_name (PikaContainer *container, PikaObject * pika_container_get_child_by_name (PikaContainer *container,
const gchar *name); const gchar *name);
PikaObject * pika_container_get_child_by_index (PikaContainer *container, PikaObject * pika_container_get_child_by_index (PikaContainer *container,

View File

@ -34,6 +34,7 @@
#include "pika-memsize.h" #include "pika-memsize.h"
#include "pikadata.h" #include "pikadata.h"
#include "pikaidtable.h" #include "pikaidtable.h"
#include "pikaimage.h"
#include "pikatag.h" #include "pikatag.h"
#include "pikatagged.h" #include "pikatagged.h"
@ -51,6 +52,7 @@ enum
PROP_0, PROP_0,
PROP_ID, PROP_ID,
PROP_FILE, PROP_FILE,
PROP_IMAGE,
PROP_WRITABLE, PROP_WRITABLE,
PROP_DELETABLE, PROP_DELETABLE,
PROP_MIME_TYPE PROP_MIME_TYPE
@ -59,8 +61,10 @@ enum
struct _PikaDataPrivate struct _PikaDataPrivate
{ {
gint ID; gint ID;
GFile *file; GFile *file;
PikaImage *image;
GQuark mime_type; GQuark mime_type;
guint writable : 1; guint writable : 1;
guint deletable : 1; guint deletable : 1;
@ -172,6 +176,11 @@ pika_data_class_init (PikaDataClass *klass)
G_TYPE_FILE, G_TYPE_FILE,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_IMAGE,
g_param_spec_object ("image", NULL, NULL,
PIKA_TYPE_IMAGE,
PIKA_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_WRITABLE, g_object_class_install_property (object_class, PROP_WRITABLE,
g_param_spec_boolean ("writable", NULL, NULL, g_param_spec_boolean ("writable", NULL, NULL,
FALSE, FALSE,
@ -268,6 +277,12 @@ pika_data_set_property (GObject *object,
private->deletable); private->deletable);
break; break;
case PROP_IMAGE:
pika_data_set_image (data,
g_value_get_object (value),
private->writable,
private->deletable);
break;
case PROP_WRITABLE: case PROP_WRITABLE:
private->writable = g_value_get_boolean (value); private->writable = g_value_get_boolean (value);
break; break;
@ -307,6 +322,10 @@ pika_data_get_property (GObject *object,
g_value_set_object (value, private->file); g_value_set_object (value, private->file);
break; break;
case PROP_IMAGE:
g_value_set_object (value, private->image);
break;
case PROP_WRITABLE: case PROP_WRITABLE:
g_value_set_boolean (value, private->writable); g_value_set_boolean (value, private->writable);
break; break;
@ -462,7 +481,7 @@ pika_data_get_identifier (PikaTagged *tagged)
gchar *identifier = NULL; gchar *identifier = NULL;
gchar *collection = NULL; gchar *collection = NULL;
g_return_val_if_fail (private->internal || private->file != NULL, NULL); g_return_val_if_fail (private->internal || private->file != NULL || private->image != NULL, NULL);
collection = pika_data_get_collection (data); collection = pika_data_get_collection (data);
/* The identifier is guaranteed to be unique because we use 2 directory /* The identifier is guaranteed to be unique because we use 2 directory
@ -503,7 +522,7 @@ pika_data_get_collection (PikaData *data)
PikaDataPrivate *private = PIKA_DATA_GET_PRIVATE (data); PikaDataPrivate *private = PIKA_DATA_GET_PRIVATE (data);
gchar *collection = NULL; gchar *collection = NULL;
g_return_val_if_fail (private->internal || private->file != NULL, NULL); g_return_val_if_fail (private->internal || private->file != NULL || private->image != NULL, NULL);
if (private->file) if (private->file)
{ {
@ -551,6 +570,10 @@ pika_data_get_collection (PikaData *data)
g_free (path); g_free (path);
} }
else if (private->image)
{
collection = g_strdup_printf ("[image-id-%d]", pika_image_get_id (private->image));
}
else if (private->internal) else if (private->internal)
{ {
collection = g_strdup (private->collection); collection = g_strdup (private->collection);
@ -603,7 +626,7 @@ pika_data_save (PikaData *data,
g_return_val_if_fail (private->writable == TRUE, FALSE); g_return_val_if_fail (private->writable == TRUE, FALSE);
if (private->internal) if (private->internal || private->image != NULL)
{ {
private->dirty = FALSE; private->dirty = FALSE;
return TRUE; return TRUE;
@ -862,6 +885,8 @@ pika_data_set_file (PikaData *data,
if (private->internal) if (private->internal)
return; return;
g_return_if_fail (private->image == NULL);
g_set_object (&private->file, file); g_set_object (&private->file, file);
private->writable = FALSE; private->writable = FALSE;
@ -937,6 +962,53 @@ pika_data_get_file (PikaData *data)
return private->file; return private->file;
} }
/**
* pika_data_set_image:
* @data: A #PikaData object
* @image: Image to assign to @data.
* @writable: %TRUE if we want to be able to write to this file.
* @deletable: %TRUE if we want to be able to delete this file.
*
* This function assigns an image to @data. This can only be done if no file has
* been assigned (a non-internal data can be attached either to a file or to an
* image).
**/
void
pika_data_set_image (PikaData *data,
PikaImage *image,
gboolean writable,
gboolean deletable)
{
PikaDataPrivate *private;
g_return_if_fail (PIKA_IS_DATA (data));
g_return_if_fail (PIKA_IS_IMAGE (image));
private = PIKA_DATA_GET_PRIVATE (data);
if (private->internal)
return;
g_return_if_fail (private->file == NULL);
g_set_object (&private->image, image);
private->writable = writable ? TRUE : FALSE;
private->deletable = deletable ? TRUE : FALSE;
}
PikaImage *
pika_data_get_image (PikaData *data)
{
PikaDataPrivate *private;
g_return_val_if_fail (PIKA_IS_DATA (data), NULL);
private = PIKA_DATA_GET_PRIVATE (data);
return private->image;
}
/** /**
* pika_data_create_filename: * pika_data_create_filename:
* @data: a #Pikadata object. * @data: a #Pikadata object.

View File

@ -102,6 +102,11 @@ void pika_data_set_file (PikaData *data,
gboolean writable, gboolean writable,
gboolean deletable); gboolean deletable);
GFile * pika_data_get_file (PikaData *data); GFile * pika_data_get_file (PikaData *data);
void pika_data_set_image (PikaData *data,
PikaImage *image,
gboolean writable,
gboolean deletable);
PikaImage * pika_data_get_image (PikaData *data);
void pika_data_create_filename (PikaData *data, void pika_data_create_filename (PikaData *data,
GFile *dest_dir); GFile *dest_dir);

View File

@ -403,6 +403,9 @@ pika_data_factory_real_data_save (PikaDataFactory *factory)
PikaData *data = list->data; PikaData *data = list->data;
GError *error = NULL; GError *error = NULL;
if (pika_data_get_image (data))
continue;
if (! pika_data_get_file (data)) if (! pika_data_get_file (data))
pika_data_create_filename (data, writable_dir); pika_data_create_filename (data, writable_dir);
@ -460,6 +463,7 @@ pika_data_factory_real_data_duplicate (PikaDataFactory *factory,
gint copy_len; gint copy_len;
gint number; gint number;
gchar *new_name; gchar *new_name;
GError *error = NULL;
ext = strrchr (name, '#'); ext = strrchr (name, '#');
copy_len = strlen (_("copy")); copy_len = strlen (_("copy"));
@ -479,8 +483,12 @@ pika_data_factory_real_data_duplicate (PikaDataFactory *factory,
pika_object_take_name (PIKA_OBJECT (new_data), new_name); pika_object_take_name (PIKA_OBJECT (new_data), new_name);
if (! pika_data_factory_data_save_single (factory, new_data, &error))
g_critical ("%s: data saving failed: %s", G_STRFUNC, error->message);
pika_container_add (priv->container, PIKA_OBJECT (new_data)); pika_container_add (priv->container, PIKA_OBJECT (new_data));
g_object_unref (new_data); g_object_unref (new_data);
g_clear_error (&error);
} }
return new_data; return new_data;
@ -674,8 +682,14 @@ pika_data_factory_data_new (PikaDataFactory *factory,
if (data) if (data)
{ {
GError *error = NULL;
if (! pika_data_factory_data_save_single (factory, data, &error))
g_critical ("%s: data saving failed: %s", G_STRFUNC, error->message);
pika_container_add (priv->container, PIKA_OBJECT (data)); pika_container_add (priv->container, PIKA_OBJECT (data));
g_object_unref (data); g_object_unref (data);
g_clear_error (&error);
return data; return data;
} }
@ -750,7 +764,7 @@ pika_data_factory_data_save_single (PikaDataFactory *factory,
g_return_val_if_fail (PIKA_IS_DATA (data), FALSE); g_return_val_if_fail (PIKA_IS_DATA (data), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
if (! pika_data_is_dirty (data)) if (! pika_data_is_dirty (data) || pika_data_get_image (data))
return TRUE; return TRUE;
if (! pika_data_get_file (data)) if (! pika_data_get_file (data))

View File

@ -31,25 +31,43 @@
#include "core-types.h" #include "core-types.h"
#include "config/pikageglconfig.h"
#include "gegl/pika-babl.h" #include "gegl/pika-babl.h"
#include "gegl/pika-gegl-loops.h"
#include "pika.h" #include "pika.h"
#include "pikacontainer.h" #include "pikacontainer.h"
#include "pikadatafactory.h" #include "pikadatafactory.h"
#include "pikadrawable.h"
#include "pikaimage.h" #include "pikaimage.h"
#include "pikaimage-colormap.h" #include "pikaimage-colormap.h"
#include "pikaimage-private.h" #include "pikaimage-private.h"
#include "pikaimage-undo.h"
#include "pikaimage-undo-push.h" #include "pikaimage-undo-push.h"
#include "pikapalette.h" #include "pikapalette.h"
#include "pika-intl.h" #include "pika-intl.h"
typedef struct
{
GeglBuffer *buffer;
const Babl *format;
/* Shared by jobs. */
gboolean *found;
GRWLock *lock;
} IndexUsedJobData;
/* local function prototype */ /* local function prototype */
static void pika_image_colormap_set_palette_entry (PikaImage *image, static void pika_image_colormap_set_palette_entry (PikaImage *image,
const PikaRGB *color, const PikaRGB *color,
gint index); gint index);
static void pika_image_colormap_thread_is_index_used (IndexUsedJobData *data,
gint index);
/* public functions */ /* public functions */
@ -80,7 +98,7 @@ pika_image_colormap_init (PikaImage *image)
pika_palette_set_columns (private->palette, 16); pika_palette_set_columns (private->palette, 16);
pika_data_make_internal (PIKA_DATA (private->palette), palette_id); pika_data_set_image (PIKA_DATA (private->palette), image, TRUE, FALSE);
palettes = pika_data_factory_get_container (image->pika->palette_factory); palettes = pika_data_factory_get_container (image->pika->palette_factory);
@ -319,9 +337,8 @@ pika_image_set_colormap (PikaImage *image,
pika_image_colormap_set_palette_entry (image, &color, i); pika_image_colormap_set_palette_entry (image, &color, i);
} }
pika_data_thaw (PIKA_DATA (private->palette));
pika_image_colormap_changed (image, -1); pika_image_colormap_changed (image, -1);
pika_data_thaw (PIKA_DATA (private->palette));
} }
void void
@ -347,6 +364,45 @@ pika_image_unset_colormap (PikaImage *image,
pika_image_colormap_changed (image, -1); pika_image_colormap_changed (image, -1);
} }
gboolean
pika_image_colormap_is_index_used (PikaImage *image,
gint color_index)
{
GList *layers;
GList *iter;
GThreadPool *pool;
GRWLock lock;
gboolean found = FALSE;
gint num_processors;
g_rw_lock_init (&lock);
num_processors = PIKA_GEGL_CONFIG (image->pika->config)->num_processors;
layers = pika_image_get_layer_list (image);
pool = g_thread_pool_new_full ((GFunc) pika_image_colormap_thread_is_index_used,
GINT_TO_POINTER (color_index),
(GDestroyNotify) g_free,
num_processors, TRUE, NULL);
for (iter = layers; iter; iter = g_list_next (iter))
{
IndexUsedJobData *job_data;
job_data = g_malloc (sizeof (IndexUsedJobData ));
job_data->buffer = pika_drawable_get_buffer (iter->data);
job_data->format = pika_drawable_get_format_without_alpha (iter->data);
job_data->found = &found;
job_data->lock = &lock;
g_thread_pool_push (pool, job_data, NULL);
}
g_thread_pool_free (pool, FALSE, TRUE);
g_rw_lock_clear (&lock);
g_list_free (layers);
return found;
}
void void
pika_image_get_colormap_entry (PikaImage *image, pika_image_get_colormap_entry (PikaImage *image,
gint color_index, gint color_index,
@ -420,6 +476,57 @@ pika_image_add_colormap_entry (PikaImage *image,
pika_image_colormap_changed (image, -1); pika_image_colormap_changed (image, -1);
} }
gboolean
pika_image_delete_colormap_entry (PikaImage *image,
gint color_index,
gboolean push_undo)
{
g_return_val_if_fail (PIKA_IS_IMAGE (image), FALSE);
if (! pika_image_colormap_is_index_used (image, color_index))
{
PikaImagePrivate *private;
PikaPaletteEntry *entry;
GList *layers;
GList *iter;
if (push_undo)
{
pika_image_undo_group_start (image, PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP,
C_("undo-type", "Delete Colormap entry"));
pika_image_undo_push_image_colormap (image, NULL);
}
private = PIKA_IMAGE_GET_PRIVATE (image);
layers = pika_image_get_layer_list (image);
for (iter = layers; iter; iter = g_list_next (iter))
{
if (push_undo)
pika_image_undo_push_drawable_mod (image, NULL, iter->data, TRUE);
pika_gegl_shift_index (pika_drawable_get_buffer (iter->data), NULL,
pika_drawable_get_format (iter->data),
color_index, -1);
}
entry = pika_palette_get_entry (private->palette, color_index);
pika_palette_delete_entry (private->palette, entry);
g_list_free (layers);
if (push_undo)
pika_image_undo_group_end (image);
pika_image_colormap_changed (image, -1);
return TRUE;
}
return FALSE;
}
/* private functions */ /* private functions */
@ -442,3 +549,22 @@ pika_image_colormap_set_palette_entry (PikaImage *image,
pika_palette_set_entry (private->palette, index, name, color); pika_palette_set_entry (private->palette, index, name, color);
} }
static void
pika_image_colormap_thread_is_index_used (IndexUsedJobData *data,
gint index)
{
g_rw_lock_reader_lock (data->lock);
if (*data->found)
{
g_rw_lock_reader_unlock (data->lock);
return;
}
g_rw_lock_reader_unlock (data->lock);
if (pika_gegl_is_index_used (data->buffer, NULL, data->format, index))
{
g_rw_lock_writer_lock (data->lock);
*data->found = TRUE;
g_rw_lock_writer_unlock (data->lock);
}
}

View File

@ -49,6 +49,9 @@ void pika_image_set_colormap (PikaImage *image,
void pika_image_unset_colormap (PikaImage *image, void pika_image_unset_colormap (PikaImage *image,
gboolean push_undo); gboolean push_undo);
gboolean pika_image_colormap_is_index_used (PikaImage *image,
gint color_index);
void pika_image_get_colormap_entry (PikaImage *image, void pika_image_get_colormap_entry (PikaImage *image,
gint color_index, gint color_index,
PikaRGB *color); PikaRGB *color);
@ -59,6 +62,9 @@ void pika_image_set_colormap_entry (PikaImage *image,
void pika_image_add_colormap_entry (PikaImage *image, void pika_image_add_colormap_entry (PikaImage *image,
const PikaRGB *color); const PikaRGB *color);
gboolean pika_image_delete_colormap_entry (PikaImage *image,
gint color_index,
gboolean push_undo);
#endif /* __PIKA_IMAGE_COLORMAP_H__ */ #endif /* __PIKA_IMAGE_COLORMAP_H__ */

View File

@ -24,17 +24,22 @@
#include <cairo.h> #include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h> #include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h> #include <gegl.h>
#include <gexiv2/gexiv2.h>
#include "libpikabase/pikabase.h" #include "libpikabase/pikabase.h"
#include "libpikacolor/pikacolor.h" #include "libpikacolor/pikacolor.h"
#include "core-types.h" #include "core-types.h"
#include "pika.h"
#include "pikaimage.h" #include "pikaimage.h"
#include "pikaimage-color-profile.h" #include "pikaimage-color-profile.h"
#include "pikaimage-metadata.h" #include "pikaimage-metadata.h"
#include "pikaimage-private.h" #include "pikaimage-private.h"
#include "pikaimage-rotate.h"
#include "pikaimage-undo.h"
#include "pikaimage-undo-push.h" #include "pikaimage-undo-push.h"
#include "pikalayer-new.h"
/* public functions */ /* public functions */
@ -186,3 +191,110 @@ pika_image_metadata_update_colorspace (PikaImage *image)
pika_metadata_set_colorspace (metadata, space); pika_metadata_set_colorspace (metadata, space);
} }
} }
/**
* pika_image_metadata_load_thumbnail:
* @pika: The #Pika object.
* @file: A #GFile image.
* @full_image_width: the width of the full image (not the thumbnail).
* @full_image_height: the height of the full image (not the thumbnail).
* @error: Return location for error message
*
* Retrieves a thumbnail from metadata in @file if present.
* It does not need to actually load the full image, only the metadata through
* GExiv2, which makes it fast.
*
* Returns: (transfer none) (nullable): a #PikaImage of the @file thumbnail.
*/
PikaImage *
pika_image_metadata_load_thumbnail (Pika *pika,
GFile *file,
gint *full_image_width,
gint *full_image_height,
const Babl **format,
GError **error)
{
PikaMetadata *metadata;
GInputStream *input_stream;
GdkPixbuf *pixbuf;
guint8 *thumbnail_buffer;
gint thumbnail_size;
PikaImage *image = NULL;
g_return_val_if_fail (G_IS_FILE (file), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
metadata = pika_metadata_load_from_file (file, error);
if (! metadata)
return NULL;
if (! gexiv2_metadata_get_exif_thumbnail (GEXIV2_METADATA (metadata),
&thumbnail_buffer,
&thumbnail_size))
{
g_object_unref (metadata);
return NULL;
}
input_stream = g_memory_input_stream_new_from_data (thumbnail_buffer,
thumbnail_size,
(GDestroyNotify) g_free);
pixbuf = gdk_pixbuf_new_from_stream (input_stream, NULL, error);
g_object_unref (input_stream);
if (pixbuf)
{
PikaLayer *layer;
image = pika_image_new (pika,
gdk_pixbuf_get_width (pixbuf),
gdk_pixbuf_get_height (pixbuf),
PIKA_RGB, PIKA_PRECISION_U8_NON_LINEAR);
pika_image_undo_disable (image);
/* XXX This is possibly wrong, because an image of a given color space may
* have a thumbnail stored in a different colorspace. This is even more
* true with PIKA which always exports RGB thumbnails (see code in
* pika_image_metadata_save_filter()), even for say grayscale images.
* Nevertheless other software may store thumbnail using the same
* colorspace.
*/
*format = pika_pixbuf_get_format (pixbuf);
layer = pika_layer_new_from_pixbuf (pixbuf, image,
pika_image_get_layer_format (image, FALSE),
/* No need to localize; this image is short-lived. */
"Background",
PIKA_OPACITY_OPAQUE,
pika_image_get_default_new_layer_mode (image));
g_object_unref (pixbuf);
pika_image_add_layer (image, layer, NULL, 0, FALSE);
pika_image_apply_metadata_orientation (image, pika_get_user_context (pika), metadata, NULL);
}
/* This is the unoriented dimensions. Should we switch when there is a 90 or
* 270 degree rotation? We don't actually know if the metadata orientation is
* correct.
*/
*full_image_width = gexiv2_metadata_get_pixel_width (GEXIV2_METADATA (metadata));
*full_image_height = gexiv2_metadata_get_pixel_height (GEXIV2_METADATA (metadata));
if (*full_image_width < 1 || *full_image_height < 1)
{
/* Dimensions stored in metadata might be less accurate, yet it's still
* informational.
*/
*full_image_width = gexiv2_metadata_try_get_metadata_pixel_width (GEXIV2_METADATA (metadata), NULL);
*full_image_height = gexiv2_metadata_try_get_metadata_pixel_width (GEXIV2_METADATA (metadata), NULL);
}
if (*full_image_width < 1 || *full_image_height < 1)
{
*full_image_width = 0;
*full_image_height = 0;
}
g_object_unref (metadata);
return image;
}

View File

@ -33,5 +33,12 @@ void pika_image_metadata_update_bits_per_sample (PikaImage *image);
void pika_image_metadata_update_resolution (PikaImage *image); void pika_image_metadata_update_resolution (PikaImage *image);
void pika_image_metadata_update_colorspace (PikaImage *image); void pika_image_metadata_update_colorspace (PikaImage *image);
PikaImage * pika_image_metadata_load_thumbnail (Pika *pika,
GFile *file,
gint *full_image_width,
gint *full_image_height,
const Babl **format,
GError **error);
#endif /* __PIKA_IMAGE_METADATA_H__ */ #endif /* __PIKA_IMAGE_METADATA_H__ */

View File

@ -282,6 +282,17 @@ pika_image_import_rotation_metadata (PikaImage *image,
} }
} }
void
pika_image_apply_metadata_orientation (PikaImage *image,
PikaContext *context,
PikaMetadata *metadata,
PikaProgress *progress)
{
pika_image_metadata_rotate (image, context,
gexiv2_metadata_try_get_orientation (GEXIV2_METADATA (metadata), NULL),
progress);
}
/* Private Functions */ /* Private Functions */

View File

@ -23,14 +23,20 @@
#define __PIKA_IMAGE_ROTATE_H__ #define __PIKA_IMAGE_ROTATE_H__
void pika_image_rotate (PikaImage *image, void pika_image_rotate (PikaImage *image,
PikaContext *context, PikaContext *context,
PikaRotationType rotate_type, PikaRotationType rotate_type,
PikaProgress *progress); PikaProgress *progress);
void pika_image_import_rotation_metadata (PikaImage *image,
PikaContext *context,
PikaProgress *progress,
gboolean interactive);
void pika_image_apply_metadata_orientation (PikaImage *image,
PikaContext *context,
PikaMetadata *metadata,
PikaProgress *progress);
void pika_image_import_rotation_metadata (PikaImage *image,
PikaContext *context,
PikaProgress *progress,
gboolean interactive);
#endif /* __PIKA_IMAGE_ROTATE_H__ */ #endif /* __PIKA_IMAGE_ROTATE_H__ */

View File

@ -625,6 +625,9 @@ pika_image_undo_dirty_from_type (PikaUndoType undo_type)
case PIKA_UNDO_GROUP_IMAGE_CONVERT: case PIKA_UNDO_GROUP_IMAGE_CONVERT:
return PIKA_DIRTY_IMAGE | PIKA_DIRTY_DRAWABLE; return PIKA_DIRTY_IMAGE | PIKA_DIRTY_DRAWABLE;
case PIKA_UNDO_GROUP_IMAGE_COLORMAP_REMAP:
return PIKA_DIRTY_IMAGE | PIKA_DIRTY_DRAWABLE;
case PIKA_UNDO_GROUP_IMAGE_LAYERS_MERGE: case PIKA_UNDO_GROUP_IMAGE_LAYERS_MERGE:
return PIKA_DIRTY_IMAGE_STRUCTURE | PIKA_DIRTY_DRAWABLE; return PIKA_DIRTY_IMAGE_STRUCTURE | PIKA_DIRTY_DRAWABLE;

View File

@ -45,6 +45,7 @@
#include "pikacontainer.h" #include "pikacontainer.h"
#include "pikacontext.h" #include "pikacontext.h"
#include "pikaimage.h" #include "pikaimage.h"
#include "pikaimage-metadata.h"
#include "pikaimagefile.h" #include "pikaimagefile.h"
#include "pikapickable.h" #include "pikapickable.h"
#include "pikaprogress.h" #include "pikaprogress.h"
@ -486,19 +487,37 @@ pika_imagefile_create_thumbnail (PikaImagefile *imagefile,
if (error && *error) if (error && *error)
{ {
g_printerr ("Info: Thumbnail load procedure failed: %s\n" g_printerr ("Info: Thumbnail load procedure failed: %s\n"
" Falling back to file load procedure.\n", " Falling back to metadata or file load.\n",
(*error)->message); (*error)->message);
g_clear_error (error); g_clear_error (error);
} }
image = file_open_image (private->pika, context, progress, image = pika_image_metadata_load_thumbnail (private->pika, private->file, &width, &height, &format, error);
private->file,
FALSE, NULL, PIKA_RUN_NONINTERACTIVE,
&status, &mime_type, error);
if (image) if (image)
pika_thumbnail_set_info_from_image (private->thumbnail, {
mime_type, image); pika_thumbnail_set_info (private->thumbnail,
mime_type, width, height,
format, 0);
}
else
{
if (error && *error)
{
g_printerr ("Info: metadata load failed: %s\n"
" Falling back to file load procedure.\n",
(*error)->message);
g_clear_error (error);
}
image = file_open_image (private->pika, context, progress,
private->file,
FALSE, NULL, PIKA_RUN_NONINTERACTIVE,
&status, &mime_type, error);
if (image)
pika_thumbnail_set_info_from_image (private->thumbnail,
mime_type, image);
}
} }
if (image) if (image)

View File

@ -76,6 +76,8 @@ static PikaObject * pika_list_search (PikaContainer *conta
PikaContainerSearchFunc func, PikaContainerSearchFunc func,
gpointer user_data); gpointer user_data);
static gboolean pika_list_get_unique_names (PikaContainer *container); static gboolean pika_list_get_unique_names (PikaContainer *container);
static GList * pika_list_get_children_by_name (PikaContainer *container,
const gchar *name);
static PikaObject * pika_list_get_child_by_name (PikaContainer *container, static PikaObject * pika_list_get_child_by_name (PikaContainer *container,
const gchar *name); const gchar *name);
static PikaObject * pika_list_get_child_by_index (PikaContainer *container, static PikaObject * pika_list_get_child_by_index (PikaContainer *container,
@ -101,23 +103,24 @@ pika_list_class_init (PikaListClass *klass)
PikaObjectClass *pika_object_class = PIKA_OBJECT_CLASS (klass); PikaObjectClass *pika_object_class = PIKA_OBJECT_CLASS (klass);
PikaContainerClass *container_class = PIKA_CONTAINER_CLASS (klass); PikaContainerClass *container_class = PIKA_CONTAINER_CLASS (klass);
object_class->finalize = pika_list_finalize; object_class->finalize = pika_list_finalize;
object_class->set_property = pika_list_set_property; object_class->set_property = pika_list_set_property;
object_class->get_property = pika_list_get_property; object_class->get_property = pika_list_get_property;
pika_object_class->get_memsize = pika_list_get_memsize; pika_object_class->get_memsize = pika_list_get_memsize;
container_class->add = pika_list_add; container_class->add = pika_list_add;
container_class->remove = pika_list_remove; container_class->remove = pika_list_remove;
container_class->reorder = pika_list_reorder; container_class->reorder = pika_list_reorder;
container_class->clear = pika_list_clear; container_class->clear = pika_list_clear;
container_class->have = pika_list_have; container_class->have = pika_list_have;
container_class->foreach = pika_list_foreach; container_class->foreach = pika_list_foreach;
container_class->search = pika_list_search; container_class->search = pika_list_search;
container_class->get_unique_names = pika_list_get_unique_names; container_class->get_unique_names = pika_list_get_unique_names;
container_class->get_child_by_name = pika_list_get_child_by_name; container_class->get_children_by_name = pika_list_get_children_by_name;
container_class->get_child_by_index = pika_list_get_child_by_index; container_class->get_child_by_name = pika_list_get_child_by_name;
container_class->get_child_index = pika_list_get_child_index; container_class->get_child_by_index = pika_list_get_child_by_index;
container_class->get_child_index = pika_list_get_child_index;
g_object_class_install_property (object_class, PROP_UNIQUE_NAMES, g_object_class_install_property (object_class, PROP_UNIQUE_NAMES,
g_param_spec_boolean ("unique-names", g_param_spec_boolean ("unique-names",
@ -369,6 +372,29 @@ pika_list_get_unique_names (PikaContainer *container)
return list->unique_names; return list->unique_names;
} }
static GList *
pika_list_get_children_by_name (PikaContainer *container,
const gchar *name)
{
PikaList *list = PIKA_LIST (container);
GList *children = NULL;
GList *iter;
for (iter = list->queue->head; iter; iter = g_list_next (iter))
{
PikaObject *object = iter->data;
if (! strcmp (pika_object_get_name (object), name))
{
children = g_list_prepend (children, object);
if (list->unique_names)
return children;
}
}
return children;
}
static PikaObject * static PikaObject *
pika_list_get_child_by_name (PikaContainer *container, pika_list_get_child_by_name (PikaContainer *container,
const gchar *name) const gchar *name)

View File

@ -33,6 +33,8 @@
#include "core-types.h" #include "core-types.h"
#include "pika-memsize.h" #include "pika-memsize.h"
#include "pikaimage.h"
#include "pikaimage-undo-push.h"
#include "pikapalette.h" #include "pikapalette.h"
#include "pikapalette-load.h" #include "pikapalette-load.h"
#include "pikapalette-save.h" #include "pikapalette-save.h"
@ -44,6 +46,12 @@
#define RGB_EPSILON 1e-6 #define RGB_EPSILON 1e-6
enum
{
ENTRY_CHANGED,
LAST_SIGNAL
};
/* local function prototypes */ /* local function prototypes */
@ -75,6 +83,8 @@ static gchar * pika_palette_get_description (PikaViewable *viewa
static const gchar * pika_palette_get_extension (PikaData *data); static const gchar * pika_palette_get_extension (PikaData *data);
static void pika_palette_copy (PikaData *data, static void pika_palette_copy (PikaData *data,
PikaData *src_data); PikaData *src_data);
static void pika_palette_real_entry_changed (PikaPalette *palette,
gint index);
static void pika_palette_entry_free (PikaPaletteEntry *entry); static void pika_palette_entry_free (PikaPaletteEntry *entry);
static gint64 pika_palette_entry_get_memsize (PikaPaletteEntry *entry, static gint64 pika_palette_entry_get_memsize (PikaPaletteEntry *entry,
@ -88,6 +98,7 @@ G_DEFINE_TYPE_WITH_CODE (PikaPalette, pika_palette, PIKA_TYPE_DATA,
#define parent_class pika_palette_parent_class #define parent_class pika_palette_parent_class
static guint signals[LAST_SIGNAL] = { 0 };
static void static void
pika_palette_class_init (PikaPaletteClass *klass) pika_palette_class_init (PikaPaletteClass *klass)
@ -97,6 +108,14 @@ pika_palette_class_init (PikaPaletteClass *klass)
PikaViewableClass *viewable_class = PIKA_VIEWABLE_CLASS (klass); PikaViewableClass *viewable_class = PIKA_VIEWABLE_CLASS (klass);
PikaDataClass *data_class = PIKA_DATA_CLASS (klass); PikaDataClass *data_class = PIKA_DATA_CLASS (klass);
signals[ENTRY_CHANGED] = g_signal_new ("entry-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaPaletteClass, entry_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
G_TYPE_INT);
object_class->finalize = pika_palette_finalize; object_class->finalize = pika_palette_finalize;
pika_object_class->get_memsize = pika_palette_get_memsize; pika_object_class->get_memsize = pika_palette_get_memsize;
@ -110,6 +129,8 @@ pika_palette_class_init (PikaPaletteClass *klass)
data_class->save = pika_palette_save; data_class->save = pika_palette_save;
data_class->get_extension = pika_palette_get_extension; data_class->get_extension = pika_palette_get_extension;
data_class->copy = pika_palette_copy; data_class->copy = pika_palette_copy;
klass->entry_changed = pika_palette_real_entry_changed;
} }
static void static void
@ -344,6 +365,16 @@ pika_palette_copy (PikaData *data,
pika_data_thaw (data); pika_data_thaw (data);
} }
static void
pika_palette_real_entry_changed (PikaPalette *palette,
gint index)
{
PikaImage *image = pika_data_get_image (PIKA_DATA (palette));
if (image != NULL)
pika_image_colormap_changed (image, index);
}
static gchar * static gchar *
pika_palette_get_checksum (PikaTagged *tagged) pika_palette_get_checksum (PikaTagged *tagged)
{ {
@ -406,11 +437,17 @@ pika_palette_move_entry (PikaPalette *palette,
if (g_list_find (palette->colors, entry)) if (g_list_find (palette->colors, entry))
{ {
gint old_position = g_list_index (palette->colors, entry);
palette->colors = g_list_remove (palette->colors, palette->colors = g_list_remove (palette->colors,
entry); entry);
palette->colors = g_list_insert (palette->colors, palette->colors = g_list_insert (palette->colors,
entry, position); entry, position);
if (! pika_data_is_frozen (PIKA_DATA (palette)))
for (gint i = MIN (position, old_position); i <= MAX (position, old_position); i++)
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, i);
pika_data_dirty (PIKA_DATA (palette)); pika_data_dirty (PIKA_DATA (palette));
} }
} }
@ -442,6 +479,10 @@ pika_palette_add_entry (PikaPalette *palette,
palette->n_colors += 1; palette->n_colors += 1;
if (! pika_data_is_frozen (PIKA_DATA (palette)))
for (gint i = position; i < palette->n_colors; i++)
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, i);
pika_data_dirty (PIKA_DATA (palette)); pika_data_dirty (PIKA_DATA (palette));
return entry; return entry;
@ -456,12 +497,18 @@ pika_palette_delete_entry (PikaPalette *palette,
if (g_list_find (palette->colors, entry)) if (g_list_find (palette->colors, entry))
{ {
gint old_position = g_list_index (palette->colors, entry);
pika_palette_entry_free (entry); pika_palette_entry_free (entry);
palette->colors = g_list_remove (palette->colors, entry); palette->colors = g_list_remove (palette->colors, entry);
palette->n_colors--; palette->n_colors--;
if (! pika_data_is_frozen (PIKA_DATA (palette)))
for (gint i = old_position; i < palette->n_colors; i++)
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, i);
pika_data_dirty (PIKA_DATA (palette)); pika_data_dirty (PIKA_DATA (palette));
} }
} }
@ -489,6 +536,9 @@ pika_palette_set_entry (PikaPalette *palette,
entry->name = g_strdup (name); entry->name = g_strdup (name);
if (! pika_data_is_frozen (PIKA_DATA (palette)))
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, position);
pika_data_dirty (PIKA_DATA (palette)); pika_data_dirty (PIKA_DATA (palette));
return TRUE; return TRUE;
@ -497,7 +547,8 @@ pika_palette_set_entry (PikaPalette *palette,
gboolean gboolean
pika_palette_set_entry_color (PikaPalette *palette, pika_palette_set_entry_color (PikaPalette *palette,
gint position, gint position,
const PikaRGB *color) const PikaRGB *color,
gboolean push_undo_if_image)
{ {
PikaPaletteEntry *entry; PikaPaletteEntry *entry;
@ -509,8 +560,15 @@ pika_palette_set_entry_color (PikaPalette *palette,
if (! entry) if (! entry)
return FALSE; return FALSE;
if (push_undo_if_image && pika_data_get_image (PIKA_DATA (palette)))
pika_image_undo_push_image_colormap (pika_data_get_image (PIKA_DATA (palette)),
C_("undo-type", "Change Colormap entry"));
entry->color = *color; entry->color = *color;
if (! pika_data_is_frozen (PIKA_DATA (palette)))
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, position);
pika_data_dirty (PIKA_DATA (palette)); pika_data_dirty (PIKA_DATA (palette));
return TRUE; return TRUE;
@ -535,6 +593,9 @@ pika_palette_set_entry_name (PikaPalette *palette,
entry->name = g_strdup (name); entry->name = g_strdup (name);
if (! pika_data_is_frozen (PIKA_DATA (palette)))
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, position);
pika_data_dirty (PIKA_DATA (palette)); pika_data_dirty (PIKA_DATA (palette));
return TRUE; return TRUE;

View File

@ -56,6 +56,9 @@ struct _PikaPalette
struct _PikaPaletteClass struct _PikaPaletteClass
{ {
PikaDataClass parent_class; PikaDataClass parent_class;
void (* entry_changed) (PikaPalette *palette,
gint index);
}; };
@ -85,7 +88,8 @@ gboolean pika_palette_set_entry (PikaPalette *palette,
const PikaRGB *color); const PikaRGB *color);
gboolean pika_palette_set_entry_color (PikaPalette *palette, gboolean pika_palette_set_entry_color (PikaPalette *palette,
gint position, gint position,
const PikaRGB *color); const PikaRGB *color,
gboolean push_undo_if_image);
gboolean pika_palette_set_entry_name (PikaPalette *palette, gboolean pika_palette_set_entry_name (PikaPalette *palette,
gint position, gint position,
const gchar *name); const gchar *name);

View File

@ -217,7 +217,7 @@ pika_palette_mru_add (PikaPaletteMru *mru,
/* Even though they are nearly the same color, let's make them /* Even though they are nearly the same color, let's make them
* exactly equal. * exactly equal.
*/ */
pika_palette_set_entry_color (palette, 0, color); pika_palette_set_entry_color (palette, 0, color, FALSE);
return; return;
} }

View File

@ -78,7 +78,7 @@ static void pika_pdb_progress_progress_set_value (PikaProgress *progress
gdouble percentage); gdouble percentage);
static gdouble pika_pdb_progress_progress_get_value (PikaProgress *progress); static gdouble pika_pdb_progress_progress_get_value (PikaProgress *progress);
static void pika_pdb_progress_progress_pulse (PikaProgress *progress); static void pika_pdb_progress_progress_pulse (PikaProgress *progress);
static guint32 pika_pdb_progress_progress_get_window_id (PikaProgress *progress); static GBytes * pika_pdb_progress_progress_get_window_id (PikaProgress *progress);
static GObjectClass *parent_class = NULL; static GObjectClass *parent_class = NULL;
@ -241,14 +241,13 @@ pika_pdb_progress_set_property (GObject *object,
} }
} }
static gdouble static void
pika_pdb_progress_run_callback (PikaPdbProgress *progress, pika_pdb_progress_run_callback (PikaPdbProgress *progress,
PikaProgressCommand command, PikaProgressCommand command,
const gchar *text, const gchar *text,
gdouble value) gdouble value,
GBytes **handle)
{ {
gdouble retval = 0;
if (progress->callback_name && ! progress->callback_busy) if (progress->callback_name && ! progress->callback_busy)
{ {
PikaValueArray *return_vals; PikaValueArray *return_vals;
@ -274,17 +273,16 @@ pika_pdb_progress_run_callback (PikaPdbProgress *progress,
g_type_name (G_TYPE_FROM_INSTANCE (progress))); g_type_name (G_TYPE_FROM_INSTANCE (progress)));
} }
else if (pika_value_array_length (return_vals) >= 2 && else if (pika_value_array_length (return_vals) >= 2 &&
G_VALUE_HOLDS_DOUBLE (pika_value_array_index (return_vals, 1))) handle != NULL &&
G_VALUE_HOLDS_BOXED (pika_value_array_index (return_vals, 1)))
{ {
retval = g_value_get_double (pika_value_array_index (return_vals, 1)); *handle = g_value_dup_boxed (pika_value_array_index (return_vals, 1));
} }
pika_value_array_unref (return_vals); pika_value_array_unref (return_vals);
progress->callback_busy = FALSE; progress->callback_busy = FALSE;
} }
return retval;
} }
static PikaProgress * static PikaProgress *
@ -298,7 +296,7 @@ pika_pdb_progress_progress_start (PikaProgress *progress,
{ {
pika_pdb_progress_run_callback (pdb_progress, pika_pdb_progress_run_callback (pdb_progress,
PIKA_PROGRESS_COMMAND_START, PIKA_PROGRESS_COMMAND_START,
message, 0.0); message, 0.0, NULL);
pdb_progress->active = TRUE; pdb_progress->active = TRUE;
pdb_progress->value = 0.0; pdb_progress->value = 0.0;
@ -318,7 +316,7 @@ pika_pdb_progress_progress_end (PikaProgress *progress)
{ {
pika_pdb_progress_run_callback (pdb_progress, pika_pdb_progress_run_callback (pdb_progress,
PIKA_PROGRESS_COMMAND_END, PIKA_PROGRESS_COMMAND_END,
NULL, 0.0); NULL, 0.0, NULL);
pdb_progress->active = FALSE; pdb_progress->active = FALSE;
pdb_progress->value = 0.0; pdb_progress->value = 0.0;
@ -342,7 +340,7 @@ pika_pdb_progress_progress_set_text (PikaProgress *progress,
if (pdb_progress->active) if (pdb_progress->active)
pika_pdb_progress_run_callback (pdb_progress, pika_pdb_progress_run_callback (pdb_progress,
PIKA_PROGRESS_COMMAND_SET_TEXT, PIKA_PROGRESS_COMMAND_SET_TEXT,
message, 0.0); message, 0.0, NULL);
} }
static void static void
@ -355,7 +353,7 @@ pika_pdb_progress_progress_set_value (PikaProgress *progress,
{ {
pika_pdb_progress_run_callback (pdb_progress, pika_pdb_progress_run_callback (pdb_progress,
PIKA_PROGRESS_COMMAND_SET_VALUE, PIKA_PROGRESS_COMMAND_SET_VALUE,
NULL, percentage); NULL, percentage, NULL);
pdb_progress->value = percentage; pdb_progress->value = percentage;
} }
} }
@ -377,18 +375,19 @@ pika_pdb_progress_progress_pulse (PikaProgress *progress)
if (pdb_progress->active) if (pdb_progress->active)
pika_pdb_progress_run_callback (pdb_progress, pika_pdb_progress_run_callback (pdb_progress,
PIKA_PROGRESS_COMMAND_PULSE, PIKA_PROGRESS_COMMAND_PULSE,
NULL, 0.0); NULL, 0.0, NULL);
} }
static guint32 static GBytes *
pika_pdb_progress_progress_get_window_id (PikaProgress *progress) pika_pdb_progress_progress_get_window_id (PikaProgress *progress)
{ {
PikaPdbProgress *pdb_progress = PIKA_PDB_PROGRESS (progress); PikaPdbProgress *pdb_progress = PIKA_PDB_PROGRESS (progress);
GBytes *handle = NULL;
return (guint32) pika_pdb_progress_run_callback (pdb_progress,
pika_pdb_progress_run_callback (pdb_progress, PIKA_PROGRESS_COMMAND_GET_WINDOW,
PIKA_PROGRESS_COMMAND_GET_WINDOW, NULL, 0.0, &handle);
NULL, 0.0); return handle;
} }
PikaPdbProgress * PikaPdbProgress *

View File

@ -209,7 +209,7 @@ pika_progress_pulse (PikaProgress *progress)
progress_iface->pulse (progress); progress_iface->pulse (progress);
} }
guint32 GBytes *
pika_progress_get_window_id (PikaProgress *progress) pika_progress_get_window_id (PikaProgress *progress)
{ {
PikaProgressInterface *progress_iface; PikaProgressInterface *progress_iface;
@ -221,7 +221,7 @@ pika_progress_get_window_id (PikaProgress *progress)
if (progress_iface->get_window_id) if (progress_iface->get_window_id)
return progress_iface->get_window_id (progress); return progress_iface->get_window_id (progress);
return 0; return NULL;
} }
gboolean gboolean

View File

@ -48,7 +48,7 @@ struct _PikaProgressInterface
gdouble (* get_value) (PikaProgress *progress); gdouble (* get_value) (PikaProgress *progress);
void (* pulse) (PikaProgress *progress); void (* pulse) (PikaProgress *progress);
guint32 (* get_window_id) (PikaProgress *progress); GBytes * (* get_window_id) (PikaProgress *progress);
gboolean (* message) (PikaProgress *progress, gboolean (* message) (PikaProgress *progress,
Pika *pika, Pika *pika,
@ -78,7 +78,7 @@ void pika_progress_set_value (PikaProgress *progress,
gdouble pika_progress_get_value (PikaProgress *progress); gdouble pika_progress_get_value (PikaProgress *progress);
void pika_progress_pulse (PikaProgress *progress); void pika_progress_pulse (PikaProgress *progress);
guint32 pika_progress_get_window_id (PikaProgress *progress); GBytes * pika_progress_get_window_id (PikaProgress *progress);
gboolean pika_progress_message (PikaProgress *progress, gboolean pika_progress_message (PikaProgress *progress,
Pika *pika, Pika *pika,

View File

@ -59,7 +59,7 @@ static void pika_sub_progress_set_value (PikaProgress *prog
gdouble percentage); gdouble percentage);
static gdouble pika_sub_progress_get_value (PikaProgress *progress); static gdouble pika_sub_progress_get_value (PikaProgress *progress);
static void pika_sub_progress_pulse (PikaProgress *progress); static void pika_sub_progress_pulse (PikaProgress *progress);
static guint32 pika_sub_progress_get_window_id (PikaProgress *progress); static GBytes * pika_sub_progress_get_window_id (PikaProgress *progress);
static gboolean pika_sub_progress_message (PikaProgress *progress, static gboolean pika_sub_progress_message (PikaProgress *progress,
Pika *pika, Pika *pika,
PikaMessageSeverity severity, PikaMessageSeverity severity,
@ -228,7 +228,7 @@ pika_sub_progress_pulse (PikaProgress *progress)
pika_progress_pulse (sub->progress); pika_progress_pulse (sub->progress);
} }
static guint32 static GBytes *
pika_sub_progress_get_window_id (PikaProgress *progress) pika_sub_progress_get_window_id (PikaProgress *progress)
{ {
PikaSubProgress *sub = PIKA_SUB_PROGRESS (progress); PikaSubProgress *sub = PIKA_SUB_PROGRESS (progress);
@ -236,7 +236,7 @@ pika_sub_progress_get_window_id (PikaProgress *progress)
if (sub->progress) if (sub->progress)
return pika_progress_get_window_id (sub->progress); return pika_progress_get_window_id (sub->progress);
return 0; return NULL;
} }
static gboolean static gboolean

View File

@ -221,7 +221,7 @@ dialogs_about_get (PikaDialogFactory *factory,
PikaUIManager *ui_manager, PikaUIManager *ui_manager,
gint view_size) gint view_size)
{ {
return about_dialog_create (context->pika->edit_config); return about_dialog_create (context->pika);
} }
GtkWidget * GtkWidget *

View File

@ -151,6 +151,13 @@ quit_close_all_dialog_new (Pika *pika,
GClosure *closure; GClosure *closure;
gint rows; gint rows;
gint view_size; gint view_size;
GdkRectangle geometry;
GdkMonitor *monitor;
gint max_rows;
gint scale_factor;
const gfloat rows_per_height = 32 / 1440.0f;
const gint greatest_max_rows = 36;
const gint least_max_rows = 6;
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL); g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
@ -206,8 +213,28 @@ quit_close_all_dialog_new (Pika *pika,
private->box = PIKA_MESSAGE_DIALOG (private->dialog)->box; private->box = PIKA_MESSAGE_DIALOG (private->dialog)->box;
monitor = pika_widget_get_monitor (private->dialog);
scale_factor = gdk_monitor_get_scale_factor (monitor);
gdk_monitor_get_geometry (monitor, &geometry);
if (scale_factor > 1)
{
#ifdef GDK_WINDOWING_WIN32
max_rows = (geometry.height * scale_factor * rows_per_height)
/ (scale_factor + 1);
#else
max_rows = (geometry.height * rows_per_height) / (scale_factor + 1);
#endif
}
else
{
max_rows = geometry.height * rows_per_height;
}
max_rows = CLAMP (max_rows, least_max_rows, greatest_max_rows);
view_size = pika->config->layer_preview_size; view_size = pika->config->layer_preview_size;
rows = CLAMP (pika_container_get_n_children (private->images), 3, 6); rows = CLAMP (pika_container_get_n_children (private->images), 3, max_rows);
view = pika_container_tree_view_new (private->images, private->context, view = pika_container_tree_view_new (private->images, private->context,
view_size, 1); view_size, 1);

View File

@ -110,7 +110,7 @@ static void pika_display_progress_set_value (PikaProgress *progre
gdouble percentage); gdouble percentage);
static gdouble pika_display_progress_get_value (PikaProgress *progress); static gdouble pika_display_progress_get_value (PikaProgress *progress);
static void pika_display_progress_pulse (PikaProgress *progress); static void pika_display_progress_pulse (PikaProgress *progress);
static guint32 pika_display_progress_get_window_id (PikaProgress *progress); static GBytes * pika_display_progress_get_window_id (PikaProgress *progress);
static gboolean pika_display_progress_message (PikaProgress *progress, static gboolean pika_display_progress_message (PikaProgress *progress,
Pika *pika, Pika *pika,
PikaMessageSeverity severity, PikaMessageSeverity severity,
@ -323,7 +323,7 @@ pika_display_progress_pulse (PikaProgress *progress)
pika_progress_pulse (PIKA_PROGRESS (display->priv->shell)); pika_progress_pulse (PIKA_PROGRESS (display->priv->shell));
} }
static guint32 static GBytes *
pika_display_progress_get_window_id (PikaProgress *progress) pika_display_progress_get_window_id (PikaProgress *progress)
{ {
PikaDisplayImpl *display = PIKA_DISPLAY_IMPL (progress); PikaDisplayImpl *display = PIKA_DISPLAY_IMPL (progress);
@ -331,7 +331,7 @@ pika_display_progress_get_window_id (PikaProgress *progress)
if (display->priv->shell) if (display->priv->shell)
return pika_progress_get_window_id (PIKA_PROGRESS (display->priv->shell)); return pika_progress_get_window_id (PIKA_PROGRESS (display->priv->shell));
return 0; return NULL;
} }
static gboolean static gboolean

View File

@ -103,15 +103,16 @@ pika_display_shell_progress_pulse (PikaProgress *progress)
pika_progress_pulse (PIKA_PROGRESS (statusbar)); pika_progress_pulse (PIKA_PROGRESS (statusbar));
} }
static guint32 static GBytes *
pika_display_shell_progress_get_window_id (PikaProgress *progress) pika_display_shell_progress_get_window_id (PikaProgress *progress)
{ {
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (progress)); PikaDisplayShell *shell = PIKA_DISPLAY_SHELL (progress);
GBytes *handle = NULL;
if (GTK_IS_WINDOW (toplevel)) if (shell->window_handle)
return pika_window_get_native_id (GTK_WINDOW (toplevel)); handle = g_bytes_ref (shell->window_handle);
return 0; return handle;
} }
static gboolean static gboolean

View File

@ -27,6 +27,10 @@
#include <gegl.h> #include <gegl.h>
#include <gtk/gtk.h> #include <gtk/gtk.h>
#ifdef GDK_WINDOWING_WAYLAND
#include <gdk/gdkwayland.h>
#endif
#include "libpikabase/pikabase.h" #include "libpikabase/pikabase.h"
#include "libpikamath/pikamath.h" #include "libpikamath/pikamath.h"
#include "libpikacolor/pikacolor.h" #include "libpikacolor/pikacolor.h"
@ -587,6 +591,8 @@ pika_display_shell_constructed (GObject *object)
G_CALLBACK (pika_display_shell_canvas_grab_notify), G_CALLBACK (pika_display_shell_canvas_grab_notify),
shell); shell);
pika_widget_set_native_handle (GTK_WIDGET (shell), &shell->window_handle);
g_signal_connect (shell->canvas, "realize", g_signal_connect (shell->canvas, "realize",
G_CALLBACK (pika_display_shell_canvas_realize), G_CALLBACK (pika_display_shell_canvas_realize),
shell); shell);
@ -851,6 +857,17 @@ pika_display_shell_dispose (GObject *object)
shell->display = NULL; shell->display = NULL;
if (shell->window_handle != NULL)
{
#ifdef GDK_WINDOWING_WAYLAND
if (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ()) &&
/* The GdkWindow is likely already destroyed. */
gtk_widget_get_window (GTK_WIDGET (shell)) != NULL)
gdk_wayland_window_unexport_handle (gtk_widget_get_window (GTK_WIDGET (shell)));
#endif
g_clear_pointer (&shell->window_handle, g_bytes_unref);
}
G_OBJECT_CLASS (parent_class)->dispose (object); G_OBJECT_CLASS (parent_class)->dispose (object);
} }

View File

@ -55,6 +55,8 @@ struct _PikaDisplayShell
PikaDisplay *display; PikaDisplay *display;
GBytes *window_handle;
PikaUIManager *popup_manager; PikaUIManager *popup_manager;
GdkMonitor *initial_monitor; GdkMonitor *initial_monitor;

View File

@ -1174,9 +1174,6 @@ pika_image_window_set_aux_info (PikaSessionManaged *session_managed,
else if (StartupInfo.wShowWindow == SW_SHOWMINIMIZED || else if (StartupInfo.wShowWindow == SW_SHOWMINIMIZED ||
StartupInfo.wShowWindow == SW_SHOWMINNOACTIVE || StartupInfo.wShowWindow == SW_SHOWMINNOACTIVE ||
StartupInfo.wShowWindow == SW_MINIMIZE) StartupInfo.wShowWindow == SW_MINIMIZE)
/* XXX Iconification does not seem to work. I see the
* window being iconified and immediately re-raised.
* I leave this piece of code for later improvement. */
gtk_window_iconify (GTK_WINDOW (session_managed)); gtk_window_iconify (GTK_WINDOW (session_managed));
else else
/* Another show property not relevant to min/max. /* Another show property not relevant to min/max.

View File

@ -2026,8 +2026,10 @@ static void
pika_tool_rectangle_update_options (PikaToolRectangle *rectangle) pika_tool_rectangle_update_options (PikaToolRectangle *rectangle)
{ {
PikaToolRectanglePrivate *private = rectangle->private; PikaToolRectanglePrivate *private = rectangle->private;
gdouble x1, y1; gdouble x1 = 0;
gdouble x2, y2; gdouble y1 = 0;
gdouble x2 = 0;
gdouble y2 = 0;
pika_tool_rectangle_get_public_rect (rectangle, &x1, &y1, &x2, &y2); pika_tool_rectangle_get_public_rect (rectangle, &x1, &y1, &x2, &y2);
@ -2162,7 +2164,10 @@ static void
pika_tool_rectangle_update_status (PikaToolRectangle *rectangle) pika_tool_rectangle_update_status (PikaToolRectangle *rectangle)
{ {
PikaToolRectanglePrivate *private = rectangle->private; PikaToolRectanglePrivate *private = rectangle->private;
gdouble x1, y1, x2, y2; gdouble x1 = 0;
gdouble y1 = 0;
gdouble x2 = 0;
gdouble y2 = 0;
pika_tool_rectangle_get_public_rect (rectangle, &x1, &y1, &x2, &y2); pika_tool_rectangle_get_public_rect (rectangle, &x1, &y1, &x2, &y2);
@ -2436,7 +2441,10 @@ pika_tool_rectangle_coord_on_handle (PikaToolRectangle *rectangle,
{ {
PikaToolRectanglePrivate *private = rectangle->private; PikaToolRectanglePrivate *private = rectangle->private;
PikaDisplayShell *shell; PikaDisplayShell *shell;
gdouble x1, y1, x2, y2; gdouble x1 = 0;
gdouble y1 = 0;
gdouble x2 = 0;
gdouble y2 = 0;
gdouble rect_w, rect_h; gdouble rect_w, rect_h;
gdouble handle_x = 0; gdouble handle_x = 0;
gdouble handle_y = 0; gdouble handle_y = 0;
@ -2838,7 +2846,10 @@ pika_tool_rectangle_setup_snap_offsets (PikaToolRectangle *rectangle,
{ {
PikaToolWidget *widget = PIKA_TOOL_WIDGET (rectangle); PikaToolWidget *widget = PIKA_TOOL_WIDGET (rectangle);
PikaToolRectanglePrivate *private = rectangle->private; PikaToolRectanglePrivate *private = rectangle->private;
gdouble x1, y1, x2, y2; gdouble x1 = 0;
gdouble y1 = 0;
gdouble x2 = 0;
gdouble y2 = 0;
gdouble coord_x, coord_y; gdouble coord_x, coord_y;
pika_tool_rectangle_get_public_rect (rectangle, &x1, &y1, &x2, &y2); pika_tool_rectangle_get_public_rect (rectangle, &x1, &y1, &x2, &y2);
@ -4185,7 +4196,10 @@ pika_tool_rectangle_point_in_rectangle (PikaToolRectangle *rectangle,
gdouble x, gdouble x,
gdouble y) gdouble y)
{ {
gdouble x1, y1, x2, y2; gdouble x1 = 0;
gdouble y1 = 0;
gdouble x2 = 0;
gdouble y2 = 0;
g_return_val_if_fail (PIKA_IS_TOOL_RECTANGLE (rectangle), FALSE); g_return_val_if_fail (PIKA_IS_TOOL_RECTANGLE (rectangle), FALSE);

View File

@ -35,11 +35,15 @@
#include "core/pikabrush.h" #include "core/pikabrush.h"
#include "core/pikabrush-load.h" #include "core/pikabrush-load.h"
#include "core/pikabrush-private.h" #include "core/pikabrush-private.h"
#include "core/pikacontainer.h"
#include "core/pikadrawable.h" #include "core/pikadrawable.h"
#include "core/pikaimage.h" #include "core/pikaimage.h"
#include "core/pikalayer-new.h" #include "core/pikaimage-merge.h"
#include "core/pikaimage-new.h"
#include "core/pikaimage-resize.h" #include "core/pikaimage-resize.h"
#include "core/pikalayer-new.h"
#include "core/pikaparamspecs.h" #include "core/pikaparamspecs.h"
#include "core/pikapickable.h"
#include "core/pikatempbuf.h" #include "core/pikatempbuf.h"
#include "pdb/pikaprocedure.h" #include "pdb/pikaprocedure.h"
@ -51,12 +55,14 @@
/* local function prototypes */ /* local function prototypes */
static PikaImage * file_gbr_brush_to_image (Pika *pika, static PikaImage * file_gbr_brush_to_image (Pika *pika,
PikaBrush *brush); PikaBrush *brush);
static PikaBrush * file_gbr_image_to_brush (PikaImage *image, static PikaBrush * file_gbr_image_to_brush (PikaImage *image,
PikaDrawable *drawable, PikaContext *context,
const gchar *name, gint n_drawables,
gdouble spacing); PikaDrawable **drawables,
const gchar *name,
gdouble spacing);
/* public functions */ /* public functions */
@ -119,24 +125,26 @@ file_gbr_save_invoker (PikaProcedure *procedure,
const PikaValueArray *args, const PikaValueArray *args,
GError **error) GError **error)
{ {
PikaValueArray *return_vals; PikaValueArray *return_vals;
PikaImage *image; PikaImage *image;
PikaDrawable *drawable; PikaDrawable **drawables;
PikaBrush *brush; gint n_drawables;
const gchar *name; PikaBrush *brush;
GFile *file; const gchar *name;
gint spacing; GFile *file;
gboolean success; gint spacing;
gboolean success;
pika_set_busy (pika); pika_set_busy (pika);
image = g_value_get_object (pika_value_array_index (args, 1)); image = g_value_get_object (pika_value_array_index (args, 1));
drawable = g_value_get_object (pika_value_array_index (args, 2)); n_drawables = g_value_get_int (pika_value_array_index (args, 2));
file = g_value_get_object (pika_value_array_index (args, 3)); drawables = (PikaDrawable **) pika_value_get_object_array (pika_value_array_index (args, 3));
spacing = g_value_get_int (pika_value_array_index (args, 4)); file = g_value_get_object (pika_value_array_index (args, 4));
name = g_value_get_string (pika_value_array_index (args, 5)); spacing = g_value_get_int (pika_value_array_index (args, 5));
name = g_value_get_string (pika_value_array_index (args, 6));
brush = file_gbr_image_to_brush (image, drawable, name, spacing); brush = file_gbr_image_to_brush (image, context, n_drawables, drawables, name, spacing);
pika_data_set_file (PIKA_DATA (brush), file, TRUE, TRUE); pika_data_set_file (PIKA_DATA (brush), file, TRUE, TRUE);
@ -417,15 +425,49 @@ file_gbr_brush_to_image (Pika *pika,
} }
static PikaBrush * static PikaBrush *
file_gbr_image_to_brush (PikaImage *image, file_gbr_image_to_brush (PikaImage *image,
PikaDrawable *drawable, PikaContext *context,
const gchar *name, gint n_drawables,
gdouble spacing) PikaDrawable **drawables,
const gchar *name,
gdouble spacing)
{ {
gint width = pika_item_get_width (PIKA_ITEM (drawable)); PikaBrush *brush;
gint height = pika_item_get_height (PIKA_ITEM (drawable)); PikaImage *subimage = NULL;
PikaDrawable *drawable;
gint width;
gint height;
return file_gbr_drawable_to_brush (drawable, g_return_val_if_fail (n_drawables > 0, NULL);
GEGL_RECTANGLE (0, 0, width, height), g_return_val_if_fail (drawables != NULL, NULL);
name, spacing);
if (n_drawables > 1)
{
GList *drawable_list = NULL;
for (gint i = 0; i < n_drawables; i++)
drawable_list = g_list_prepend (drawable_list, drawables[i]);
subimage = pika_image_new_from_drawables (image->pika, drawable_list, FALSE, FALSE);
g_list_free (drawable_list);
pika_container_remove (image->pika->images, PIKA_OBJECT (subimage));
pika_image_resize_to_layers (subimage, context,
NULL, NULL, NULL, NULL, NULL);
drawable = PIKA_DRAWABLE (pika_image_merge_visible_layers (subimage, context, PIKA_CLIP_TO_IMAGE,
FALSE, TRUE, NULL));
pika_pickable_flush (PIKA_PICKABLE (subimage));
}
else
{
drawable = drawables[0];
}
width = pika_item_get_width (PIKA_ITEM (drawable));
height = pika_item_get_height (PIKA_ITEM (drawable));
brush = file_gbr_drawable_to_brush (drawable,
GEGL_RECTANGLE (0, 0, width, height),
name, spacing);
g_clear_object (&subimage);
return brush;
} }

View File

@ -260,6 +260,7 @@ file_pat_image_to_pattern (PikaImage *image,
gint height; gint height;
g_return_val_if_fail (n_drawables > 0, NULL); g_return_val_if_fail (n_drawables > 0, NULL);
g_return_val_if_fail (drawables != NULL, NULL);
if (n_drawables > 1) if (n_drawables > 1)
{ {

View File

@ -87,7 +87,7 @@ file_data_init (Pika *pika)
"1995-2019"); "1995-2019");
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param", pika_param_spec_enum ("run-mode",
"Dummy Param", "Dummy Param",
"Dummy parameter", "Dummy parameter",
PIKA_TYPE_RUN_MODE, PIKA_TYPE_RUN_MODE,
@ -145,7 +145,7 @@ file_data_init (Pika *pika)
"1995-2019"); "1995-2019");
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param", pika_param_spec_enum ("run-mode",
"Dummy Param", "Dummy Param",
"Dummy parameter", "Dummy parameter",
PIKA_TYPE_RUN_MODE, PIKA_TYPE_RUN_MODE,
@ -158,12 +158,17 @@ file_data_init (Pika *pika)
FALSE, FALSE,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_drawable ("drawable", g_param_spec_int ("num-drawables",
"Drawable", "Num drawables",
"Active drawable " "Number of drawables",
"of input image", 1, G_MAXINT, 1,
FALSE, PIKA_PARAM_READWRITE));
PIKA_PARAM_READWRITE)); pika_procedure_add_argument (procedure,
pika_param_spec_object_array ("drawables",
"Drawables",
"Selected drawables",
PIKA_TYPE_DRAWABLE,
PIKA_PARAM_READWRITE | PIKA_PARAM_NO_VALIDATE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
g_param_spec_object ("file", g_param_spec_object ("file",
"File", "File",
@ -219,7 +224,7 @@ file_data_init (Pika *pika)
"1999-2019"); "1999-2019");
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param", pika_param_spec_enum ("run-mode",
"Dummy Param", "Dummy Param",
"Dummy parameter", "Dummy parameter",
PIKA_TYPE_RUN_MODE, PIKA_TYPE_RUN_MODE,
@ -277,7 +282,7 @@ file_data_init (Pika *pika)
"1999-2019"); "1999-2019");
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param", pika_param_spec_enum ("run-mode",
"Dummy Param", "Dummy Param",
"Dummy parameter", "Dummy parameter",
PIKA_TYPE_RUN_MODE, PIKA_TYPE_RUN_MODE,
@ -363,7 +368,7 @@ file_data_init (Pika *pika)
"1997-2019"); "1997-2019");
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param", pika_param_spec_enum ("run-mode",
"Dummy Param", "Dummy Param",
"Dummy parameter", "Dummy parameter",
PIKA_TYPE_RUN_MODE, PIKA_TYPE_RUN_MODE,
@ -420,7 +425,7 @@ file_data_init (Pika *pika)
"1995-2019"); "1995-2019");
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param", pika_param_spec_enum ("run-mode",
"Dummy Param", "Dummy Param",
"Dummy parameter", "Dummy parameter",
PIKA_TYPE_RUN_MODE, PIKA_TYPE_RUN_MODE,
@ -433,7 +438,7 @@ file_data_init (Pika *pika)
FALSE, FALSE,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
g_param_spec_int ("n-drawables", g_param_spec_int ("num-drawables",
"Num drawables", "Num drawables",
"Number of drawables", "Number of drawables",
1, G_MAXINT, 1, 1, G_MAXINT, 1,
@ -491,7 +496,7 @@ file_data_init (Pika *pika)
"Jehan", "Jehan", "2019"); "Jehan", "Jehan", "2019");
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param", pika_param_spec_enum ("run-mode",
"Dummy Param", "Dummy Param",
"Dummy parameter", "Dummy parameter",
PIKA_TYPE_RUN_MODE, PIKA_TYPE_RUN_MODE,

View File

@ -374,7 +374,7 @@ file_open_thumbnail (Pika *pika,
{ {
image = g_value_get_object (pika_value_array_index (return_vals, 1)); image = g_value_get_object (pika_value_array_index (return_vals, 1));
if (pika_value_array_length (return_vals) >= 3 && if (pika_value_array_length (return_vals) >= 4 &&
G_VALUE_HOLDS_INT (pika_value_array_index (return_vals, 2)) && G_VALUE_HOLDS_INT (pika_value_array_index (return_vals, 2)) &&
G_VALUE_HOLDS_INT (pika_value_array_index (return_vals, 3))) G_VALUE_HOLDS_INT (pika_value_array_index (return_vals, 3)))
{ {
@ -385,11 +385,11 @@ file_open_thumbnail (Pika *pika,
MAX (0, g_value_get_int (pika_value_array_index (return_vals, 3))); MAX (0, g_value_get_int (pika_value_array_index (return_vals, 3)));
if (pika_value_array_length (return_vals) >= 5 && if (pika_value_array_length (return_vals) >= 5 &&
G_VALUE_HOLDS_INT (pika_value_array_index (return_vals, 4))) G_VALUE_HOLDS_ENUM (pika_value_array_index (return_vals, 4)))
{ {
gint value = g_value_get_int (pika_value_array_index (return_vals, 4)); PikaImageType itype = g_value_get_enum (pika_value_array_index (return_vals, 4));
switch (value) switch (itype)
{ {
case PIKA_RGB_IMAGE: case PIKA_RGB_IMAGE:
*format = pika_babl_format (PIKA_RGB, *format = pika_babl_format (PIKA_RGB,
@ -424,7 +424,7 @@ file_open_thumbnail (Pika *pika,
babl_new_palette ("-pika-indexed-format-dummy", babl_new_palette ("-pika-indexed-format-dummy",
&rgb, &rgba); &rgb, &rgba);
if (value == PIKA_INDEXED_IMAGE) if (itype == PIKA_INDEXED_IMAGE)
*format = rgb; *format = rgb;
else else
*format = rgba; *format = rgba;

View File

@ -918,6 +918,98 @@ pika_gegl_index_to_mask (GeglBuffer *indexed_buffer,
}); });
} }
gboolean
pika_gegl_is_index_used (GeglBuffer *indexed_buffer,
const GeglRectangle *indexed_rect,
const Babl *indexed_format,
gint index)
{
GeglBufferIterator *iter;
gboolean found = FALSE;
if (! indexed_rect)
indexed_rect = gegl_buffer_get_extent (indexed_buffer);
iter = gegl_buffer_iterator_new (indexed_buffer, indexed_rect, 0,
indexed_format,
GEGL_ACCESS_READ, GEGL_ABYSS_NONE, 1);
/* I initially had an implementation using gegl_parallel_distribute_area()
* which turned out to be much slower than the simpler iteration on the whole
* buffer at once. I think the cost of threading and using GRWLock is just far
* too high for such very basic value check.
* See gegl_parallel_distribute_area() implementation in commit dbaa8b6a1c.
*/
while (gegl_buffer_iterator_next (iter))
{
const guchar *indexed = (const guchar *) iter->items[0].data;
gint count = iter->length;
while (count--)
{
if (*indexed == index)
{
/*
* Position of one item using this color index:
gint x = iter->items[0].roi.x + (iter->length - count - 1) % iter->items[0].roi.width;
gint y = iter->items[0].roi.y + (gint) ((iter->length - count - 1) / iter->items[0].roi.width);
*/
found = TRUE;
break;
}
indexed++;
}
if (found)
{
gegl_buffer_iterator_stop (iter);
break;
}
}
return found;
}
void
pika_gegl_shift_index (GeglBuffer *indexed_buffer,
const GeglRectangle *indexed_rect,
const Babl *indexed_format,
gint from_index,
gint shift)
{
gboolean indexed_format_has_alpha;
if (! indexed_rect)
indexed_rect = gegl_buffer_get_extent (indexed_buffer);
indexed_format_has_alpha = babl_format_has_alpha (indexed_format);
gegl_parallel_distribute_area (
indexed_rect, PIXELS_PER_THREAD,
[=] (const GeglRectangle *indexed_area)
{
GeglBufferIterator *iter;
iter = gegl_buffer_iterator_new (indexed_buffer, indexed_area, 0,
indexed_format,
GEGL_ACCESS_READWRITE, GEGL_ABYSS_NONE, 1);
while (gegl_buffer_iterator_next (iter))
{
guchar *indexed = (guchar *) iter->items[0].data;
gint count = iter->length;
while (count--)
{
if (*indexed >= from_index)
*indexed += shift;
indexed += (indexed_format_has_alpha ? 2 : 1);
}
}
});
}
static void static void
pika_gegl_convert_color_profile_progress (PikaProgress *progress, pika_gegl_convert_color_profile_progress (PikaProgress *progress,
gdouble value) gdouble value)

View File

@ -91,6 +91,15 @@ void pika_gegl_index_to_mask (GeglBuffer *indexed_buffer
GeglBuffer *mask_buffer, GeglBuffer *mask_buffer,
const GeglRectangle *mask_rect, const GeglRectangle *mask_rect,
gint index); gint index);
gboolean pika_gegl_is_index_used (GeglBuffer *indexed_buffer,
const GeglRectangle *indexed_rect,
const Babl *indexed_format,
gint index);
void pika_gegl_shift_index (GeglBuffer *indexed_buffer,
const GeglRectangle *indexed_rect,
const Babl *indexed_format,
gint from_index,
gint shift);
void pika_gegl_convert_color_profile (GeglBuffer *src_buffer, void pika_gegl_convert_color_profile (GeglBuffer *src_buffer,
const GeglRectangle *src_rect, const GeglRectangle *src_rect,

View File

@ -287,10 +287,7 @@ progress_error_dialog (PikaProgress *progress)
} }
else else
{ {
guint32 window_id = pika_progress_get_window_id (progress); pika_window_set_transient_for (GTK_WINDOW (dialog), progress);
if (window_id)
pika_window_set_transient_for (GTK_WINDOW (dialog), window_id);
} }
} }

View File

@ -62,6 +62,8 @@
#include "core/pikacancelable.h" #include "core/pikacancelable.h"
#include "core/pikacontainer.h" #include "core/pikacontainer.h"
#include "core/pikacontext.h" #include "core/pikacontext.h"
#include "core/pikadatafactory.h"
#include "core/pikadrawable.h"
#include "core/pikagradient.h" #include "core/pikagradient.h"
#include "core/pikaimage.h" #include "core/pikaimage.h"
#include "core/pikaimagefile.h" #include "core/pikaimagefile.h"
@ -89,6 +91,7 @@
#include "widgets/pikamenufactory.h" #include "widgets/pikamenufactory.h"
#include "widgets/pikapaletteselect.h" #include "widgets/pikapaletteselect.h"
#include "widgets/pikapatternselect.h" #include "widgets/pikapatternselect.h"
#include "widgets/pikapickableselect.h"
#include "widgets/pikaprogressdialog.h" #include "widgets/pikaprogressdialog.h"
#include "widgets/pikauimanager.h" #include "widgets/pikauimanager.h"
#include "widgets/pikawidgets-utils.h" #include "widgets/pikawidgets-utils.h"
@ -136,7 +139,7 @@ static GFile * gui_get_theme_dir (Pika *pika);
static GFile * gui_get_icon_theme_dir (Pika *pika); static GFile * gui_get_icon_theme_dir (Pika *pika);
static PikaObject * gui_get_window_strategy (Pika *pika); static PikaObject * gui_get_window_strategy (Pika *pika);
static PikaDisplay * gui_get_empty_display (Pika *pika); static PikaDisplay * gui_get_empty_display (Pika *pika);
static guint32 gui_display_get_window_id (PikaDisplay *display); static GBytes * gui_display_get_window_id (PikaDisplay *display);
static PikaDisplay * gui_display_create (Pika *pika, static PikaDisplay * gui_display_create (Pika *pika,
PikaImage *image, PikaImage *image,
PikaUnit unit, PikaUnit unit,
@ -156,18 +159,19 @@ static void gui_free_progress (Pika *pika,
static gboolean gui_pdb_dialog_new (Pika *pika, static gboolean gui_pdb_dialog_new (Pika *pika,
PikaContext *context, PikaContext *context,
PikaProgress *progress, PikaProgress *progress,
PikaContainer *container, GType object_type,
GBytes *parent_handle,
const gchar *title, const gchar *title,
const gchar *callback_name, const gchar *callback_name,
const gchar *object_name, PikaObject *object,
va_list args); va_list args);
static gboolean gui_pdb_dialog_set (Pika *pika, static gboolean gui_pdb_dialog_set (Pika *pika,
PikaContainer *container, GType contents_type,
const gchar *callback_name, const gchar *callback_name,
const gchar *object_name, PikaObject *object,
va_list args); va_list args);
static gboolean gui_pdb_dialog_close (Pika *pika, static gboolean gui_pdb_dialog_close (Pika *pika,
PikaContainer *container, GType contents_type,
const gchar *callback_name); const gchar *callback_name);
static gboolean gui_recent_list_add_file (Pika *pika, static gboolean gui_recent_list_add_file (Pika *pika,
GFile *file, GFile *file,
@ -378,7 +382,7 @@ gui_get_empty_display (Pika *pika)
return display; return display;
} }
static guint32 static GBytes *
gui_display_get_window_id (PikaDisplay *display) gui_display_get_window_id (PikaDisplay *display)
{ {
PikaDisplay *disp = PIKA_DISPLAY (display); PikaDisplay *disp = PIKA_DISPLAY (display);
@ -386,13 +390,11 @@ gui_display_get_window_id (PikaDisplay *display)
if (shell) if (shell)
{ {
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (shell)); if (shell)
return g_bytes_ref (shell->window_handle);
if (GTK_IS_WINDOW (toplevel))
return pika_window_get_native_id (GTK_WINDOW (toplevel));
} }
return 0; return NULL;
} }
static PikaDisplay * static PikaDisplay *
@ -516,16 +518,16 @@ gui_wait (Pika *pika,
args = pika_procedure_get_arguments (procedure); args = pika_procedure_get_arguments (procedure);
pika_value_array_truncate (args, 5); pika_value_array_truncate (args, 5);
g_value_set_enum (pika_value_array_index (args, 0), g_value_set_enum (pika_value_array_index (args, 0),
PIKA_RUN_INTERACTIVE); PIKA_RUN_INTERACTIVE);
g_value_set_int (pika_value_array_index (args, 1), g_value_set_int (pika_value_array_index (args, 1),
output_pipe[0]); output_pipe[0]);
g_value_set_int (pika_value_array_index (args, 2), g_value_set_int (pika_value_array_index (args, 2),
input_pipe[1]); input_pipe[1]);
g_value_set_string (pika_value_array_index (args, 3), g_value_set_string (pika_value_array_index (args, 3),
message); message);
g_value_set_int (pika_value_array_index (args, 4), g_value_set_boolean (pika_value_array_index (args, 4),
PIKA_IS_CANCELABLE (waitable)); PIKA_IS_CANCELABLE (waitable));
pika_procedure_execute_async (procedure, pika, pika_procedure_execute_async (procedure, pika,
pika_get_user_context (pika), pika_get_user_context (pika),
@ -616,65 +618,74 @@ static gboolean
gui_pdb_dialog_new (Pika *pika, gui_pdb_dialog_new (Pika *pika,
PikaContext *context, PikaContext *context,
PikaProgress *progress, PikaProgress *progress,
PikaContainer *container, GType contents_type,
GBytes *parent_handle,
const gchar *title, const gchar *title,
const gchar *callback_name, const gchar *callback_name,
const gchar *object_name, PikaObject *object,
va_list args) va_list args)
{ {
GType dialog_type = G_TYPE_NONE; GType dialog_type = G_TYPE_NONE;
const gchar *dialog_role = NULL; const gchar *dialog_role = NULL;
const gchar *help_id = NULL; const gchar *help_id = NULL;
if (pika_container_get_children_type (container) == PIKA_TYPE_BRUSH) if (contents_type == PIKA_TYPE_BRUSH)
{ {
dialog_type = PIKA_TYPE_BRUSH_SELECT; dialog_type = PIKA_TYPE_BRUSH_SELECT;
dialog_role = "pika-brush-selection"; dialog_role = "pika-brush-selection";
help_id = PIKA_HELP_BRUSH_DIALOG; help_id = PIKA_HELP_BRUSH_DIALOG;
} }
else if (pika_container_get_children_type (container) == PIKA_TYPE_FONT) else if (contents_type == PIKA_TYPE_FONT)
{ {
dialog_type = PIKA_TYPE_FONT_SELECT; dialog_type = PIKA_TYPE_FONT_SELECT;
dialog_role = "pika-font-selection"; dialog_role = "pika-font-selection";
help_id = PIKA_HELP_FONT_DIALOG; help_id = PIKA_HELP_FONT_DIALOG;
} }
else if (pika_container_get_children_type (container) == PIKA_TYPE_GRADIENT) else if (contents_type == PIKA_TYPE_GRADIENT)
{ {
dialog_type = PIKA_TYPE_GRADIENT_SELECT; dialog_type = PIKA_TYPE_GRADIENT_SELECT;
dialog_role = "pika-gradient-selection"; dialog_role = "pika-gradient-selection";
help_id = PIKA_HELP_GRADIENT_DIALOG; help_id = PIKA_HELP_GRADIENT_DIALOG;
} }
else if (pika_container_get_children_type (container) == PIKA_TYPE_PALETTE) else if (contents_type == PIKA_TYPE_PALETTE)
{ {
dialog_type = PIKA_TYPE_PALETTE_SELECT; dialog_type = PIKA_TYPE_PALETTE_SELECT;
dialog_role = "pika-palette-selection"; dialog_role = "pika-palette-selection";
help_id = PIKA_HELP_PALETTE_DIALOG; help_id = PIKA_HELP_PALETTE_DIALOG;
} }
else if (pika_container_get_children_type (container) == PIKA_TYPE_PATTERN) else if (contents_type == PIKA_TYPE_PATTERN)
{ {
dialog_type = PIKA_TYPE_PATTERN_SELECT; dialog_type = PIKA_TYPE_PATTERN_SELECT;
dialog_role = "pika-pattern-selection"; dialog_role = "pika-pattern-selection";
help_id = PIKA_HELP_PATTERN_DIALOG; help_id = PIKA_HELP_PATTERN_DIALOG;
} }
else if (g_type_is_a (contents_type, PIKA_TYPE_DRAWABLE))
{
dialog_type = PIKA_TYPE_PICKABLE_SELECT;
dialog_role = "pika-pickable-selection";
}
else
{
g_return_val_if_reached (FALSE);
}
if (dialog_type != G_TYPE_NONE) if (dialog_type != G_TYPE_NONE)
{ {
PikaObject *object = NULL; if (! object && ! g_type_is_a (contents_type, PIKA_TYPE_DRAWABLE))
object = pika_context_get_by_type (context, contents_type);
if (object_name && strlen (object_name)) if (object || g_type_is_a (contents_type, PIKA_TYPE_DRAWABLE))
object = pika_container_get_child_by_name (container, object_name);
if (! object)
object = pika_context_get_by_type (context,
pika_container_get_children_type (container));
if (object)
{ {
gint n_properties = 0; gint n_properties = 0;
gchar **names = NULL; gchar **names = NULL;
GValue *values = NULL; GValue *values = NULL;
GtkWidget *dialog; GtkWidget *dialog;
GtkWidget *view; GtkWidget *view;
gboolean use_header_bar;
g_object_get (gtk_settings_get_default (),
"gtk-dialogs-use-header", &use_header_bar,
NULL);
names = pika_properties_append (dialog_type, names = pika_properties_append (dialog_type,
&n_properties, names, &values, &n_properties, names, &values,
@ -684,10 +695,11 @@ gui_pdb_dialog_new (Pika *pika,
"help-id", help_id, "help-id", help_id,
"pdb", pika->pdb, "pdb", pika->pdb,
"context", context, "context", context,
"select-type", pika_container_get_children_type (container), "select-type", contents_type,
"initial-object", object, "initial-object", object,
"callback-name", callback_name, "callback-name", callback_name,
"menu-factory", menus_get_global_menu_factory (pika), "menu-factory", menus_get_global_menu_factory (pika),
"use-header-bar", use_header_bar,
NULL); NULL);
names = pika_properties_append_valist (dialog_type, names = pika_properties_append_valist (dialog_type,
@ -707,27 +719,25 @@ gui_pdb_dialog_new (Pika *pika,
pika_docked_set_show_button_bar (PIKA_DOCKED (view), FALSE); pika_docked_set_show_button_bar (PIKA_DOCKED (view), FALSE);
if (progress) if (progress)
{ pika_window_set_transient_for (GTK_WINDOW (dialog), progress);
guint32 window_id = pika_progress_get_window_id (progress);
if (window_id)
pika_window_set_transient_for (GTK_WINDOW (dialog), window_id);
}
gtk_widget_show (dialog); gtk_widget_show (dialog);
/* workaround for bug #360106 */ /* workaround for bug #360106 */
{ {
GSource *source = g_timeout_source_new (100); GSource *source = g_timeout_source_new (100);
GClosure *closure; GClosure *closure;
closure = g_cclosure_new_object (G_CALLBACK (gui_pdb_dialog_present), closure = g_cclosure_new_object (G_CALLBACK (gui_pdb_dialog_present),
G_OBJECT (dialog)); G_OBJECT (dialog));
g_source_set_closure (source, closure); g_source_set_closure (source, closure);
g_source_attach (source, NULL); g_source_attach (source, NULL);
g_source_unref (source); g_source_unref (source);
} }
if (parent_handle != NULL)
pika_window_set_transient_for_handle (GTK_WINDOW (dialog), parent_handle);
return TRUE; return TRUE;
} }
@ -738,73 +748,96 @@ gui_pdb_dialog_new (Pika *pika,
static gboolean static gboolean
gui_pdb_dialog_set (Pika *pika, gui_pdb_dialog_set (Pika *pika,
PikaContainer *container, GType contents_type,
const gchar *callback_name, const gchar *callback_name,
const gchar *object_name, PikaObject *object,
va_list args) va_list args)
{ {
PikaPdbDialogClass *klass = NULL; PikaPdbDialogClass *klass = NULL;
PikaContainer *container = NULL;
PikaPdbDialog *dialog;
if (pika_container_get_children_type (container) == PIKA_TYPE_BRUSH) if (contents_type == PIKA_TYPE_BRUSH)
klass = g_type_class_peek (PIKA_TYPE_BRUSH_SELECT);
else if (pika_container_get_children_type (container) == PIKA_TYPE_FONT)
klass = g_type_class_peek (PIKA_TYPE_FONT_SELECT);
else if (pika_container_get_children_type (container) == PIKA_TYPE_GRADIENT)
klass = g_type_class_peek (PIKA_TYPE_GRADIENT_SELECT);
else if (pika_container_get_children_type (container) == PIKA_TYPE_PALETTE)
klass = g_type_class_peek (PIKA_TYPE_PALETTE_SELECT);
else if (pika_container_get_children_type (container) == PIKA_TYPE_PATTERN)
klass = g_type_class_peek (PIKA_TYPE_PATTERN_SELECT);
if (klass)
{ {
PikaPdbDialog *dialog; klass = g_type_class_peek (PIKA_TYPE_BRUSH_SELECT);
container = pika_data_factory_get_container (pika->brush_factory);
}
else if (contents_type == PIKA_TYPE_FONT)
{
klass = g_type_class_peek (PIKA_TYPE_FONT_SELECT);
container = pika_data_factory_get_container (pika->font_factory);
}
else if (contents_type == PIKA_TYPE_GRADIENT)
{
klass = g_type_class_peek (PIKA_TYPE_GRADIENT_SELECT);
container = pika_data_factory_get_container (pika->gradient_factory);
}
else if (contents_type == PIKA_TYPE_PALETTE)
{
klass = g_type_class_peek (PIKA_TYPE_PALETTE_SELECT);
container = pika_data_factory_get_container (pika->palette_factory);
}
else if (contents_type == PIKA_TYPE_PATTERN)
{
klass = g_type_class_peek (PIKA_TYPE_PATTERN_SELECT);
container = pika_data_factory_get_container (pika->pattern_factory);
}
else if (contents_type == PIKA_TYPE_DRAWABLE)
{
klass = g_type_class_peek (PIKA_TYPE_PICKABLE_SELECT);
}
dialog = pika_pdb_dialog_get_by_callback (klass, callback_name); g_return_val_if_fail (klass != NULL, FALSE);
if (dialog && dialog->select_type == pika_container_get_children_type (container)) dialog = pika_pdb_dialog_get_by_callback (klass, callback_name);
if (dialog != NULL &&
dialog->select_type == contents_type &&
(container == NULL || pika_container_get_child_index (container, object) != -1))
{
const gchar *prop_name = va_arg (args, const gchar *);
if (g_type_is_a (contents_type, PIKA_TYPE_RESOURCE))
{ {
PikaObject *object; g_return_val_if_fail (container != NULL, FALSE);
pika_context_set_by_type (dialog->context, dialog->select_type, object);
object = pika_container_get_child_by_name (container, object_name);
if (object)
{
const gchar *prop_name = va_arg (args, const gchar *);
pika_context_set_by_type (dialog->context, dialog->select_type,
object);
if (prop_name)
g_object_set_valist (G_OBJECT (dialog), prop_name, args);
gtk_window_present (GTK_WINDOW (dialog));
return TRUE;
}
} }
else
{
g_return_val_if_fail (klass->set_object != NULL, FALSE);
klass->set_object (dialog, object);
}
if (prop_name)
g_object_set_valist (G_OBJECT (dialog), prop_name, args);
gtk_window_present (GTK_WINDOW (dialog));
return TRUE;
} }
return FALSE; return FALSE;
} }
static gboolean static gboolean
gui_pdb_dialog_close (Pika *pika, gui_pdb_dialog_close (Pika *pika,
PikaContainer *container, GType contents_type,
const gchar *callback_name) const gchar *callback_name)
{ {
PikaPdbDialogClass *klass = NULL; PikaPdbDialogClass *klass = NULL;
if (pika_container_get_children_type (container) == PIKA_TYPE_BRUSH) if (contents_type == PIKA_TYPE_BRUSH)
klass = g_type_class_peek (PIKA_TYPE_BRUSH_SELECT); klass = g_type_class_peek (PIKA_TYPE_BRUSH_SELECT);
else if (pika_container_get_children_type (container) == PIKA_TYPE_FONT) else if (contents_type == PIKA_TYPE_FONT)
klass = g_type_class_peek (PIKA_TYPE_FONT_SELECT); klass = g_type_class_peek (PIKA_TYPE_FONT_SELECT);
else if (pika_container_get_children_type (container) == PIKA_TYPE_GRADIENT) else if (contents_type == PIKA_TYPE_GRADIENT)
klass = g_type_class_peek (PIKA_TYPE_GRADIENT_SELECT); klass = g_type_class_peek (PIKA_TYPE_GRADIENT_SELECT);
else if (pika_container_get_children_type (container) == PIKA_TYPE_PALETTE) else if (contents_type == PIKA_TYPE_PALETTE)
klass = g_type_class_peek (PIKA_TYPE_PALETTE_SELECT); klass = g_type_class_peek (PIKA_TYPE_PALETTE_SELECT);
else if (pika_container_get_children_type (container) == PIKA_TYPE_PATTERN) else if (contents_type == PIKA_TYPE_PATTERN)
klass = g_type_class_peek (PIKA_TYPE_PATTERN_SELECT); klass = g_type_class_peek (PIKA_TYPE_PATTERN_SELECT);
else if (contents_type == PIKA_TYPE_DRAWABLE)
klass = g_type_class_peek (PIKA_TYPE_PICKABLE_SELECT);
if (klass) if (klass)
{ {
@ -812,7 +845,7 @@ gui_pdb_dialog_close (Pika *pika,
dialog = pika_pdb_dialog_get_by_callback (klass, callback_name); dialog = pika_pdb_dialog_get_by_callback (klass, callback_name);
if (dialog && dialog->select_type == pika_container_get_children_type (container)) if (dialog && dialog->select_type == contents_type)
{ {
gtk_widget_destroy (GTK_WIDGET (dialog)); gtk_widget_destroy (GTK_WIDGET (dialog));
return TRUE; return TRUE;

View File

@ -90,6 +90,12 @@
#include "splash.h" #include "splash.h"
#include "themes.h" #include "themes.h"
#ifdef G_OS_WIN32
#include <windef.h>
#include <winbase.h>
#include <windows.h>
#endif
#ifdef GDK_WINDOWING_QUARTZ #ifdef GDK_WINDOWING_QUARTZ
#import <AppKit/AppKit.h> #import <AppKit/AppKit.h>
@ -543,6 +549,11 @@ gui_restore_after_callback (Pika *pika,
PikaGuiConfig *gui_config = PIKA_GUI_CONFIG (pika->config); PikaGuiConfig *gui_config = PIKA_GUI_CONFIG (pika->config);
PikaUIManager *image_ui_manager; PikaUIManager *image_ui_manager;
PikaDisplay *display; PikaDisplay *display;
#ifdef G_OS_WIN32
STARTUPINFO StartupInfo;
GetStartupInfo (&StartupInfo);
#endif
if (pika->be_verbose) if (pika->be_verbose)
g_print ("INIT: %s\n", G_STRFUNC); g_print ("INIT: %s\n", G_STRFUNC);
@ -610,11 +621,23 @@ gui_restore_after_callback (Pika *pika,
shell = pika_display_get_shell (display); shell = pika_display_get_shell (display);
#ifdef G_OS_WIN32
themes_set_title_bar (pika);
#endif
if (gui_config->restore_session) if (gui_config->restore_session)
session_restore (pika, initial_monitor); session_restore (pika, initial_monitor);
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (shell)); toplevel = gtk_widget_get_toplevel (GTK_WIDGET (shell));
#ifdef G_OS_WIN32
/* Prevents window from reappearing on start-up if the user
* requested it to be minimized via window hints
*/
if (StartupInfo.wShowWindow != SW_SHOWMINIMIZED &&
StartupInfo.wShowWindow != SW_SHOWMINNOACTIVE &&
StartupInfo.wShowWindow != SW_MINIMIZE)
#endif
/* move keyboard focus to the display */ /* move keyboard focus to the display */
gtk_window_present (GTK_WINDOW (toplevel)); gtk_window_present (GTK_WINDOW (toplevel));
} }
@ -925,12 +948,26 @@ gui_check_unique_accelerators (Pika *pika)
gchar **disabled_accels; gchar **disabled_accels;
gint len; gint len;
gint remove; gint remove;
gboolean print_warning = TRUE;
action = g_action_map_lookup_action (G_ACTION_MAP (pika->app),
actions[i]);
/* Just keep the first one (no reason other than we have /* Just keep the first one (no reason other than we have
* to choose), unless it's a secondary shortcut, and the * to choose), unless it's a secondary shortcut, and the
* second is a primary shortcut. * second is a primary shortcut.
*/ */
if (l == 0 && j != 0) if ((l == 0 && j != 0) ||
/* If the first action is one of "view-zoom-1-*" and
* the shortcut default, we assume it's because of our
* trick to transform `Shift+num` shortcuts based on
* layout and we happen to be on a layout where it
* clashes with other shortcuts. In this case, we
* drop the duplicate shortcut on the zoom action. See
* special code in
* pika_action_group_add_action_with_accel()
*/
(g_str_has_prefix (actions[i], "view-zoom-1-") &&
pika_action_is_default_accel (PIKA_ACTION (action), accels[j])))
{ {
disabled_action = actions[i]; disabled_action = actions[i];
disabled_accels = accels; disabled_accels = accels;
@ -942,6 +979,20 @@ gui_check_unique_accelerators (Pika *pika)
disabled_accels = accels2; disabled_accels = accels2;
remove = l; remove = l;
} }
action = g_action_map_lookup_action (G_ACTION_MAP (pika->app),
disabled_action);
if (g_str_has_prefix (disabled_action, "view-zoom-1-") &&
pika_action_is_default_accel (PIKA_ACTION (action), disabled_accels[remove]))
/* We drop the shortcut **silently** because it will be
* a case where we have 2 default accelerators clashing
* (because of the conversion code) while not being a
* real bug. Clashes with custom accelerators are
* handled by shortcuts_action_deserialize().
*/
print_warning = FALSE;
/* Remove only the duplicate shortcut but keep others. */ /* Remove only the duplicate shortcut but keep others. */
len = g_strv_length (disabled_accels); len = g_strv_length (disabled_accels);
g_free (disabled_accels[remove]); g_free (disabled_accels[remove]);
@ -949,12 +1000,11 @@ gui_check_unique_accelerators (Pika *pika)
&disabled_accels[remove + 1], &disabled_accels[remove + 1],
sizeof (char *) * (len - remove)); sizeof (char *) * (len - remove));
g_printerr ("Actions \"%s\" and \"%s\" use the same accelerator.\n" if (print_warning)
" Disabling the accelerator on \"%s\".\n", g_printerr ("Actions \"%s\" and \"%s\" use the same accelerator.\n"
actions[i], actions[k], disabled_action); " Disabling the accelerator on \"%s\".\n",
actions[i], actions[k], disabled_action);
action = g_action_map_lookup_action (G_ACTION_MAP (pika->app),
disabled_action);
pika_action_set_accels (PIKA_ACTION (action), pika_action_set_accels (PIKA_ACTION (action),
(const gchar **) disabled_accels); (const gchar **) disabled_accels);
} }

View File

@ -29,6 +29,12 @@
#include <gdk/gdkwayland.h> #include <gdk/gdkwayland.h>
#endif #endif
#ifdef G_OS_WIN32
#include <windef.h>
#include <winbase.h>
#include <windows.h>
#endif
#include "libpikabase/pikabase.h" #include "libpikabase/pikabase.h"
#include "libpikamath/pikamath.h" #include "libpikamath/pikamath.h"
#include "libpikacolor/pikacolor.h" #include "libpikacolor/pikacolor.h"
@ -125,6 +131,11 @@ splash_create (Pika *pika,
GdkRectangle workarea; GdkRectangle workarea;
gint max_width; gint max_width;
gint max_height; gint max_height;
#ifdef G_OS_WIN32
STARTUPINFO StartupInfo;
GetStartupInfo (&StartupInfo);
#endif
g_return_if_fail (splash == NULL); g_return_if_fail (splash == NULL);
g_return_if_fail (GDK_IS_MONITOR (monitor)); g_return_if_fail (GDK_IS_MONITOR (monitor));
@ -255,6 +266,13 @@ splash_create (Pika *pika,
gtk_widget_show (splash->window); gtk_widget_show (splash->window);
#ifdef G_OS_WIN32
if (StartupInfo.wShowWindow == SW_SHOWMINIMIZED ||
StartupInfo.wShowWindow == SW_SHOWMINNOACTIVE ||
StartupInfo.wShowWindow == SW_MINIMIZE)
gtk_window_iconify (GTK_WINDOW (splash->window));
#endif
if (FALSE) if (FALSE)
splash->timer = g_timer_new (); splash->timer = g_timer_new ();
} }

View File

@ -35,6 +35,10 @@
#include "core/pika.h" #include "core/pika.h"
#include "display/pikaimagewindow.h"
#include "widgets/pikawidgets-utils.h"
#include "themes.h" #include "themes.h"
#include "pika-intl.h" #include "pika-intl.h"
@ -109,6 +113,10 @@ themes_init (Pika *pika)
pika); pika);
themes_theme_change_notify (config, NULL, pika); themes_theme_change_notify (config, NULL, pika);
#ifdef G_OS_WIN32
themes_set_title_bar (pika);
#endif
} }
void void
@ -473,6 +481,10 @@ themes_theme_change_notify (PikaGuiConfig *config,
g_object_unref (theme_css); g_object_unref (theme_css);
gtk_style_context_reset_widgets (gdk_screen_get_default ()); gtk_style_context_reset_widgets (gdk_screen_get_default ());
#ifdef G_OS_WIN32
themes_set_title_bar (pika);
#endif
} }
static void static void
@ -553,3 +565,22 @@ themes_theme_paths_notify (PikaExtensionManager *manager,
g_list_free_full (path, (GDestroyNotify) g_object_unref); g_list_free_full (path, (GDestroyNotify) g_object_unref);
} }
} }
void
themes_set_title_bar (Pika *pika)
{
#ifdef G_OS_WIN32
GList *windows = pika_get_image_windows (pika);
GList *iter;
for (iter = windows; iter; iter = g_list_next (iter))
{
GtkWidget *window = GTK_WIDGET (windows->data);
pika_window_set_title_bar_theme (pika, window, TRUE);
}
if (windows)
g_list_free (windows);
#endif
}

View File

@ -34,5 +34,6 @@ GFile * themes_get_theme_file (Pika *pika,
const gchar *first_component, const gchar *first_component,
...) G_GNUC_NULL_TERMINATED; ...) G_GNUC_NULL_TERMINATED;
void themes_set_title_bar (Pika *pika);
#endif /* __THEMES_H__ */ #endif /* __THEMES_H__ */

View File

@ -28,7 +28,6 @@
#include <gtk/gtk.h> #include <gtk/gtk.h>
#include "libpikabase/pikabase.h" #include "libpikabase/pikabase.h"
#include "libpikabase/pikaprotocol.h"
#include "libpikaconfig/pikaconfig.h" #include "libpikaconfig/pikaconfig.h"
#include "menus-types.h" #include "menus-types.h"
@ -56,8 +55,7 @@ static GTokenType shortcuts_action_deserialize (GScanner *scanner,
enum enum
{ {
PROTOCOL_VERSION = 1, FILE_VERSION = 1,
FILE_VERSION,
ACTION, ACTION,
}; };
@ -68,8 +66,7 @@ shortcuts_rc_parse (GtkApplication *application,
GError **error) GError **error)
{ {
GScanner *scanner; GScanner *scanner;
gint protocol_version = PIKA_PROTOCOL_VERSION; gint file_version = SHORTCUTS_RC_FILE_VERSION;
gint file_version = SHORTCUTS_RC_FILE_VERSION;
GTokenType token; GTokenType token;
g_return_val_if_fail (GTK_IS_APPLICATION (application), FALSE); g_return_val_if_fail (GTK_IS_APPLICATION (application), FALSE);
@ -81,9 +78,6 @@ shortcuts_rc_parse (GtkApplication *application,
if (! scanner) if (! scanner)
return FALSE; return FALSE;
g_scanner_scope_add_symbol (scanner, 0,
"protocol-version",
GINT_TO_POINTER (PROTOCOL_VERSION));
g_scanner_scope_add_symbol (scanner, 0, g_scanner_scope_add_symbol (scanner, 0,
"file-version", "file-version",
GINT_TO_POINTER (FILE_VERSION)); GINT_TO_POINTER (FILE_VERSION));
@ -92,9 +86,9 @@ shortcuts_rc_parse (GtkApplication *application,
token = G_TOKEN_LEFT_PAREN; token = G_TOKEN_LEFT_PAREN;
while (protocol_version == PIKA_PROTOCOL_VERSION && while (g_scanner_peek_next_token (scanner) == token ||
file_version == SHORTCUTS_RC_FILE_VERSION && (token == G_TOKEN_SYMBOL &&
g_scanner_peek_next_token (scanner) == token) g_scanner_peek_next_token (scanner) == G_TOKEN_IDENTIFIER))
{ {
token = g_scanner_get_next_token (scanner); token = g_scanner_get_next_token (scanner);
@ -107,12 +101,6 @@ shortcuts_rc_parse (GtkApplication *application,
case G_TOKEN_SYMBOL: case G_TOKEN_SYMBOL:
switch (GPOINTER_TO_INT (scanner->value.v_symbol)) switch (GPOINTER_TO_INT (scanner->value.v_symbol))
{ {
case PROTOCOL_VERSION:
token = G_TOKEN_INT;
if (pika_scanner_parse_int (scanner, &protocol_version))
token = G_TOKEN_RIGHT_PAREN;
break;
case FILE_VERSION: case FILE_VERSION:
token = G_TOKEN_INT; token = G_TOKEN_INT;
if (pika_scanner_parse_int (scanner, &file_version)) if (pika_scanner_parse_int (scanner, &file_version))
@ -127,7 +115,17 @@ shortcuts_rc_parse (GtkApplication *application,
default: default:
break; break;
} }
break; break;
case G_TOKEN_IDENTIFIER:
g_printerr ("%s: ignoring unknown symbol '%s'.\n", G_STRFUNC, scanner->value.v_string);
while ((token = g_scanner_get_next_token (scanner)) != G_TOKEN_EOF)
{
if (token == G_TOKEN_RIGHT_PAREN)
break;
}
token = G_TOKEN_LEFT_PAREN;
break;
case G_TOKEN_RIGHT_PAREN: case G_TOKEN_RIGHT_PAREN:
token = G_TOKEN_LEFT_PAREN; token = G_TOKEN_LEFT_PAREN;
@ -138,25 +136,16 @@ shortcuts_rc_parse (GtkApplication *application,
} }
} }
if (protocol_version != PIKA_PROTOCOL_VERSION || if (file_version != SHORTCUTS_RC_FILE_VERSION)
file_version != SHORTCUTS_RC_FILE_VERSION ||
token != G_TOKEN_LEFT_PAREN)
{ {
if (protocol_version != PIKA_PROTOCOL_VERSION) g_printerr (_("Wrong shortcutsrc (%s) file format version: %d (expected: %d). "
{ "We tried to load shortcuts as well as possible.\n"),
g_set_error (error, pika_file_get_utf8_name (file),
PIKA_CONFIG_ERROR, PIKA_CONFIG_ERROR_VERSION, file_version, SHORTCUTS_RC_FILE_VERSION);
_("Skipping '%s': wrong PIKA protocol version."), }
pika_file_get_utf8_name (file)); if (token != G_TOKEN_LEFT_PAREN)
} {
else if (file_version != SHORTCUTS_RC_FILE_VERSION) if (token != G_TOKEN_ERROR)
{
g_set_error (error,
PIKA_CONFIG_ERROR, PIKA_CONFIG_ERROR_VERSION,
_("Skipping '%s': wrong shortcutsrc file format version."),
pika_file_get_utf8_name (file));
}
else if (token != G_TOKEN_ERROR)
{ {
g_scanner_get_next_token (scanner); g_scanner_get_next_token (scanner);
g_scanner_unexp_token (scanner, token, NULL, NULL, NULL, g_scanner_unexp_token (scanner, token, NULL, NULL, NULL,
@ -194,10 +183,6 @@ shortcuts_rc_write (GtkApplication *application,
actions = g_action_group_list_actions (G_ACTION_GROUP (application)); actions = g_action_group_list_actions (G_ACTION_GROUP (application));
pika_config_writer_open (writer, "protocol-version");
pika_config_writer_printf (writer, "%d", PIKA_PROTOCOL_VERSION);
pika_config_writer_close (writer);
pika_config_writer_open (writer, "file-version"); pika_config_writer_open (writer, "file-version");
pika_config_writer_printf (writer, "%d", SHORTCUTS_RC_FILE_VERSION); pika_config_writer_printf (writer, "%d", SHORTCUTS_RC_FILE_VERSION);
pika_config_writer_close (writer); pika_config_writer_close (writer);

View File

@ -34,6 +34,8 @@
#include "pdb-types.h" #include "pdb-types.h"
#include "core/pika.h" #include "core/pika.h"
#include "core/pikabrush.h"
#include "core/pikacontainer.h"
#include "core/pikadatafactory.h" #include "core/pikadatafactory.h"
#include "core/pikaparamspecs.h" #include "core/pikaparamspecs.h"
@ -53,20 +55,24 @@ brushes_popup_invoker (PikaProcedure *procedure,
gboolean success = TRUE; gboolean success = TRUE;
const gchar *brush_callback; const gchar *brush_callback;
const gchar *popup_title; const gchar *popup_title;
const gchar *initial_brush_name; PikaBrush *initial_brush;
GBytes *parent_window;
brush_callback = g_value_get_string (pika_value_array_index (args, 0)); brush_callback = g_value_get_string (pika_value_array_index (args, 0));
popup_title = g_value_get_string (pika_value_array_index (args, 1)); popup_title = g_value_get_string (pika_value_array_index (args, 1));
initial_brush_name = g_value_get_string (pika_value_array_index (args, 2)); initial_brush = g_value_get_object (pika_value_array_index (args, 2));
parent_window = g_value_get_boxed (pika_value_array_index (args, 3));
if (success) if (success)
{ {
if (pika->no_interface || PikaContainer *container = pika_data_factory_get_container (pika->brush_factory);
if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, brush_callback) || ! pika_pdb_lookup_procedure (pika->pdb, brush_callback) ||
! pika_pdb_dialog_new (pika, context, progress, ! pika_pdb_dialog_new (pika, context, progress,
pika_data_factory_get_container (pika->brush_factory), pika_container_get_children_type (container),
popup_title, brush_callback, initial_brush_name, parent_window, popup_title, brush_callback,
NULL)) PIKA_OBJECT (initial_brush), NULL))
success = FALSE; success = FALSE;
} }
@ -89,9 +95,12 @@ brushes_close_popup_invoker (PikaProcedure *procedure,
if (success) if (success)
{ {
PikaContainer *container = pika_data_factory_get_container (pika->brush_factory);
if (pika->no_interface || if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, brush_callback) || ! pika_pdb_lookup_procedure (pika->pdb, brush_callback) ||
! pika_pdb_dialog_close (pika, pika_data_factory_get_container (pika->brush_factory), ! pika_pdb_dialog_close (pika,
pika_container_get_children_type (container),
brush_callback)) brush_callback))
success = FALSE; success = FALSE;
} }
@ -110,18 +119,20 @@ brushes_set_popup_invoker (PikaProcedure *procedure,
{ {
gboolean success = TRUE; gboolean success = TRUE;
const gchar *brush_callback; const gchar *brush_callback;
const gchar *brush_name; PikaBrush *brush;
brush_callback = g_value_get_string (pika_value_array_index (args, 0)); brush_callback = g_value_get_string (pika_value_array_index (args, 0));
brush_name = g_value_get_string (pika_value_array_index (args, 1)); brush = g_value_get_object (pika_value_array_index (args, 1));
if (success) if (success)
{ {
PikaContainer *container = pika_data_factory_get_container (pika->brush_factory);
if (pika->no_interface || if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, brush_callback) || ! pika_pdb_lookup_procedure (pika->pdb, brush_callback) ||
! pika_pdb_dialog_set (pika, pika_data_factory_get_container (pika->brush_factory), ! pika_pdb_dialog_set (pika,
brush_callback, brush_name, pika_container_get_children_type (container),
NULL)) brush_callback, PIKA_OBJECT (brush), NULL))
success = FALSE; success = FALSE;
} }
@ -163,12 +174,17 @@ register_brush_select_procs (PikaPDB *pdb)
NULL, NULL,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_string ("initial-brush-name", pika_param_spec_brush ("initial-brush",
"initial brush name", "initial brush",
"The name of the brush to set as the initial choice", "The brush to set as the initial choice",
FALSE, TRUE, FALSE, FALSE,
NULL, PIKA_PARAM_READWRITE));
PIKA_PARAM_READWRITE)); pika_procedure_add_argument (procedure,
g_param_spec_boxed ("parent-window",
"parent window",
"An optional parent window handle for the popup to be set transient to",
G_TYPE_BYTES,
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure); pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);
@ -218,12 +234,11 @@ register_brush_select_procs (PikaPDB *pdb)
NULL, NULL,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_string ("brush-name", pika_param_spec_brush ("brush",
"brush name", "brush",
"The name of the brush to set as selected", "The brush to set as selected",
FALSE, FALSE, FALSE, FALSE,
NULL, PIKA_PARAM_READWRITE));
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure); pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);
} }

View File

@ -148,20 +148,20 @@ display_get_window_handle_invoker (PikaProcedure *procedure,
gboolean success = TRUE; gboolean success = TRUE;
PikaValueArray *return_vals; PikaValueArray *return_vals;
PikaDisplay *display; PikaDisplay *display;
gint window = 0; GBytes *handle = NULL;
display = g_value_get_object (pika_value_array_index (args, 0)); display = g_value_get_object (pika_value_array_index (args, 0));
if (success) if (success)
{ {
window = (gint32) pika_get_display_window_id (pika, display); handle = pika_get_display_window_id (pika, display);
} }
return_vals = pika_procedure_get_return_values (procedure, success, return_vals = pika_procedure_get_return_values (procedure, success,
error ? *error : NULL); error ? *error : NULL);
if (success) if (success)
g_value_set_int (pika_value_array_index (return_vals, 1), window); g_value_take_boxed (pika_value_array_index (return_vals, 1), handle);
return return_vals; return return_vals;
} }
@ -330,7 +330,8 @@ register_display_procs (PikaPDB *pdb)
"pika-display-get-window-handle"); "pika-display-get-window-handle");
pika_procedure_set_static_help (procedure, pika_procedure_set_static_help (procedure,
"Get a handle to the native window for an image display.", "Get a handle to the native window for an image display.",
"This procedure returns a handle to the native window for a given image display. For example in the X backend of GDK, a native window handle is an Xlib XID. A value of 0 is returned for an invalid display or if this function is unimplemented for the windowing system that is being used.", "This procedure returns a handle to the native window for a given image display.\n"
"It can be different types of data depending on the platform you are running on. For example in the X backend of GDK, a native window handle is an Xlib XID whereas on Wayland, it is a string handle. A value of NULL is returned for an invalid display or if this function is unimplemented for the windowing system that is being used.",
NULL); NULL);
pika_procedure_set_static_attribution (procedure, pika_procedure_set_static_attribution (procedure,
"Sven Neumann <sven@gimp.org>", "Sven Neumann <sven@gimp.org>",
@ -343,11 +344,11 @@ register_display_procs (PikaPDB *pdb)
FALSE, FALSE,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure, pika_procedure_add_return_value (procedure,
g_param_spec_int ("window", g_param_spec_boxed ("handle",
"window", "handle",
"The native window handle or 0", "The native window handle or NULL",
G_MININT32, G_MAXINT32, 0, G_TYPE_BYTES,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure); pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);

View File

@ -75,6 +75,57 @@ font_get_by_name_invoker (PikaProcedure *procedure,
return return_vals; return return_vals;
} }
static PikaValueArray *
fonts_get_by_name_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error)
{
gboolean success = TRUE;
PikaValueArray *return_vals;
const gchar *name;
gint num_fonts = 0;
PikaFont **fonts = NULL;
name = g_value_get_string (pika_value_array_index (args, 0));
if (success)
{
GList *list;
list = pika_pdb_get_resources (pika, PIKA_TYPE_FONT, name, PIKA_PDB_DATA_ACCESS_READ, error);
if (list == NULL)
success = FALSE;
num_fonts = g_list_length (list);
if (num_fonts > 0)
{
gint i = 0;
fonts = g_new (PikaFont *, num_fonts);
for (GList *iter = list; i < num_fonts; i++, iter = g_list_next (iter))
fonts[i] = g_object_ref (iter->data);
}
g_list_free (list);
}
return_vals = pika_procedure_get_return_values (procedure, success,
error ? *error : NULL);
if (success)
{
g_value_set_int (pika_value_array_index (return_vals, 1), num_fonts);
pika_value_take_object_array (pika_value_array_index (return_vals, 2), PIKA_TYPE_FONT, (GObject **) fonts, num_fonts);
}
return return_vals;
}
void void
register_font_procs (PikaPDB *pdb) register_font_procs (PikaPDB *pdb)
{ {
@ -87,8 +138,9 @@ register_font_procs (PikaPDB *pdb)
pika_object_set_static_name (PIKA_OBJECT (procedure), pika_object_set_static_name (PIKA_OBJECT (procedure),
"pika-font-get-by-name"); "pika-font-get-by-name");
pika_procedure_set_static_help (procedure, pika_procedure_set_static_help (procedure,
"Returns the font with the given name.", "Returns a font with the given name.",
"Returns the font with the given name.", "If several fonts are named identically, the one which is returned by this function should be considered random. This can be used when you know you won't have multiple fonts of this name or that you don't want to choose (non-interactive scripts, etc.).\n"
"If you need more control, you should use 'pika-fonts-get-by-name' instead.",
NULL); NULL);
pika_procedure_set_static_attribution (procedure, pika_procedure_set_static_attribution (procedure,
"Michael Natterer <mitch@gimp.org>", "Michael Natterer <mitch@gimp.org>",
@ -109,4 +161,40 @@ register_font_procs (PikaPDB *pdb)
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure); pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);
/*
* pika-fonts-get-by-name
*/
procedure = pika_procedure_new (fonts_get_by_name_invoker);
pika_object_set_static_name (PIKA_OBJECT (procedure),
"pika-fonts-get-by-name");
pika_procedure_set_static_help (procedure,
"Returns the fonts with the given name.",
"Returns the fonts with the given name. There may be more than one.",
NULL);
pika_procedure_set_static_attribution (procedure,
"Jehan",
"Jehan",
"2023");
pika_procedure_add_argument (procedure,
pika_param_spec_string ("name",
"name",
"The name of the font",
FALSE, FALSE, TRUE,
NULL,
PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure,
g_param_spec_int ("num-fonts",
"num fonts",
"The number of fonts with the given name",
0, G_MAXINT32, 0,
PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure,
pika_param_spec_object_array ("fonts",
"fonts",
"The fonts with the given name",
PIKA_TYPE_FONT,
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure);
} }

View File

@ -34,8 +34,10 @@
#include "pdb-types.h" #include "pdb-types.h"
#include "core/pika.h" #include "core/pika.h"
#include "core/pikacontainer.h"
#include "core/pikadatafactory.h" #include "core/pikadatafactory.h"
#include "core/pikaparamspecs.h" #include "core/pikaparamspecs.h"
#include "text/pikafont.h"
#include "pikapdb.h" #include "pikapdb.h"
#include "pikaprocedure.h" #include "pikaprocedure.h"
@ -53,21 +55,25 @@ fonts_popup_invoker (PikaProcedure *procedure,
gboolean success = TRUE; gboolean success = TRUE;
const gchar *font_callback; const gchar *font_callback;
const gchar *popup_title; const gchar *popup_title;
const gchar *initial_font_name; PikaFont *initial_font;
GBytes *parent_window;
font_callback = g_value_get_string (pika_value_array_index (args, 0)); font_callback = g_value_get_string (pika_value_array_index (args, 0));
popup_title = g_value_get_string (pika_value_array_index (args, 1)); popup_title = g_value_get_string (pika_value_array_index (args, 1));
initial_font_name = g_value_get_string (pika_value_array_index (args, 2)); initial_font = g_value_get_object (pika_value_array_index (args, 2));
parent_window = g_value_get_boxed (pika_value_array_index (args, 3));
if (success) if (success)
{ {
PikaContainer *container = pika_data_factory_get_container (pika->font_factory);
if (pika->no_interface || if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, font_callback) || ! pika_pdb_lookup_procedure (pika->pdb, font_callback) ||
! pika_data_factory_data_wait (pika->font_factory) || ! pika_data_factory_data_wait (pika->font_factory) ||
! pika_pdb_dialog_new (pika, context, progress, ! pika_pdb_dialog_new (pika, context, progress,
pika_data_factory_get_container (pika->font_factory), pika_container_get_children_type (container),
popup_title, font_callback, initial_font_name, parent_window, popup_title, font_callback,
NULL)) PIKA_OBJECT (initial_font), NULL))
success = FALSE; success = FALSE;
} }
@ -90,10 +96,12 @@ fonts_close_popup_invoker (PikaProcedure *procedure,
if (success) if (success)
{ {
PikaContainer *container = pika_data_factory_get_container (pika->font_factory);
if (pika->no_interface || if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, font_callback) || ! pika_pdb_lookup_procedure (pika->pdb, font_callback) ||
! pika_pdb_dialog_close (pika, ! pika_pdb_dialog_close (pika,
pika_data_factory_get_container (pika->font_factory), pika_container_get_children_type (container),
font_callback)) font_callback))
success = FALSE; success = FALSE;
} }
@ -112,20 +120,21 @@ fonts_set_popup_invoker (PikaProcedure *procedure,
{ {
gboolean success = TRUE; gboolean success = TRUE;
const gchar *font_callback; const gchar *font_callback;
const gchar *font_name; PikaFont *font;
font_callback = g_value_get_string (pika_value_array_index (args, 0)); font_callback = g_value_get_string (pika_value_array_index (args, 0));
font_name = g_value_get_string (pika_value_array_index (args, 1)); font = g_value_get_object (pika_value_array_index (args, 1));
if (success) if (success)
{ {
PikaContainer *container = pika_data_factory_get_container (pika->font_factory);
if (pika->no_interface || if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, font_callback) || ! pika_pdb_lookup_procedure (pika->pdb, font_callback) ||
! pika_data_factory_data_wait (pika->font_factory) || ! pika_data_factory_data_wait (pika->font_factory) ||
! pika_pdb_dialog_set (pika, ! pika_pdb_dialog_set (pika,
pika_data_factory_get_container (pika->font_factory), pika_container_get_children_type (container),
font_callback, font_name, font_callback, PIKA_OBJECT (font), NULL))
NULL))
success = FALSE; success = FALSE;
} }
@ -167,12 +176,17 @@ register_font_select_procs (PikaPDB *pdb)
NULL, NULL,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_string ("initial-font-name", pika_param_spec_font ("initial-font",
"initial font name", "initial font",
"The name of the initial font choice.", "The name of the initial font choice.",
FALSE, TRUE, FALSE, FALSE,
NULL, PIKA_PARAM_READWRITE));
PIKA_PARAM_READWRITE)); pika_procedure_add_argument (procedure,
g_param_spec_boxed ("parent-window",
"parent window",
"An optional parent window handle for the popup to be set transient to",
G_TYPE_BYTES,
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure); pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);
@ -222,12 +236,11 @@ register_font_select_procs (PikaPDB *pdb)
NULL, NULL,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_string ("font-name", pika_param_spec_font ("font",
"font name", "font",
"The name of the font to set as selected", "The font to set as selected",
FALSE, FALSE, FALSE, FALSE,
NULL, PIKA_PARAM_READWRITE));
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure); pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);
} }

View File

@ -34,6 +34,7 @@
#include "pdb-types.h" #include "pdb-types.h"
#include "core/pika.h" #include "core/pika.h"
#include "core/pikacontainer.h"
#include "core/pikadatafactory.h" #include "core/pikadatafactory.h"
#include "core/pikagradient.h" #include "core/pikagradient.h"
#include "core/pikaparamspecs.h" #include "core/pikaparamspecs.h"
@ -54,14 +55,18 @@ gradients_popup_invoker (PikaProcedure *procedure,
gboolean success = TRUE; gboolean success = TRUE;
const gchar *gradient_callback; const gchar *gradient_callback;
const gchar *popup_title; const gchar *popup_title;
const gchar *initial_gradient_name; PikaGradient *initial_gradient;
GBytes *parent_window;
gradient_callback = g_value_get_string (pika_value_array_index (args, 0)); gradient_callback = g_value_get_string (pika_value_array_index (args, 0));
popup_title = g_value_get_string (pika_value_array_index (args, 1)); popup_title = g_value_get_string (pika_value_array_index (args, 1));
initial_gradient_name = g_value_get_string (pika_value_array_index (args, 2)); initial_gradient = g_value_get_object (pika_value_array_index (args, 2));
parent_window = g_value_get_boxed (pika_value_array_index (args, 3));
if (success) if (success)
{ {
PikaContainer *container = pika_data_factory_get_container (pika->gradient_factory);
/* Formerly, this procedure had another parameter: /* Formerly, this procedure had another parameter:
* the sample size of the gradient's data passed in the changed callback. * the sample size of the gradient's data passed in the changed callback.
* Now the sample size is determined by core, and in the future, * Now the sample size is determined by core, and in the future,
@ -71,9 +76,9 @@ gradients_popup_invoker (PikaProcedure *procedure,
if (pika->no_interface || if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, gradient_callback) || ! pika_pdb_lookup_procedure (pika->pdb, gradient_callback) ||
! pika_pdb_dialog_new (pika, context, progress, ! pika_pdb_dialog_new (pika, context, progress,
pika_data_factory_get_container (pika->gradient_factory), pika_container_get_children_type (container),
popup_title, gradient_callback, initial_gradient_name, parent_window, popup_title, gradient_callback,
NULL)) PIKA_OBJECT (initial_gradient), NULL))
success = FALSE; success = FALSE;
} }
@ -96,9 +101,12 @@ gradients_close_popup_invoker (PikaProcedure *procedure,
if (success) if (success)
{ {
PikaContainer *container = pika_data_factory_get_container (pika->gradient_factory);
if (pika->no_interface || if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, gradient_callback) || ! pika_pdb_lookup_procedure (pika->pdb, gradient_callback) ||
! pika_pdb_dialog_close (pika, pika_data_factory_get_container (pika->gradient_factory), ! pika_pdb_dialog_close (pika,
pika_container_get_children_type (container),
gradient_callback)) gradient_callback))
success = FALSE; success = FALSE;
} }
@ -117,18 +125,20 @@ gradients_set_popup_invoker (PikaProcedure *procedure,
{ {
gboolean success = TRUE; gboolean success = TRUE;
const gchar *gradient_callback; const gchar *gradient_callback;
const gchar *gradient_name; PikaGradient *gradient;
gradient_callback = g_value_get_string (pika_value_array_index (args, 0)); gradient_callback = g_value_get_string (pika_value_array_index (args, 0));
gradient_name = g_value_get_string (pika_value_array_index (args, 1)); gradient = g_value_get_object (pika_value_array_index (args, 1));
if (success) if (success)
{ {
PikaContainer *container = pika_data_factory_get_container (pika->gradient_factory);
if (pika->no_interface || if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, gradient_callback) || ! pika_pdb_lookup_procedure (pika->pdb, gradient_callback) ||
! pika_pdb_dialog_set (pika, pika_data_factory_get_container (pika->gradient_factory), ! pika_pdb_dialog_set (pika,
gradient_callback, gradient_name, pika_container_get_children_type (container),
NULL)) gradient_callback, PIKA_OBJECT (gradient), NULL))
success = FALSE; success = FALSE;
} }
@ -170,12 +180,17 @@ register_gradient_select_procs (PikaPDB *pdb)
NULL, NULL,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_string ("initial-gradient-name", pika_param_spec_gradient ("initial-gradient",
"initial gradient name", "initial gradient",
"The name of the initial gradient choice", "The initial gradient choice",
FALSE, TRUE, FALSE, FALSE,
NULL, PIKA_PARAM_READWRITE));
PIKA_PARAM_READWRITE)); pika_procedure_add_argument (procedure,
g_param_spec_boxed ("parent-window",
"parent window",
"An optional parent window handle for the popup to be set transient to",
G_TYPE_BYTES,
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure); pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);
@ -225,12 +240,11 @@ register_gradient_select_procs (PikaPDB *pdb)
NULL, NULL,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_string ("gradient-name", pika_param_spec_gradient ("gradient",
"gradient name", "gradient",
"The name of the gradient to set as selected", "The gradient to set as selected",
FALSE, FALSE, FALSE, FALSE,
NULL, PIKA_PARAM_READWRITE));
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure); pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);
} }

View File

@ -55,6 +55,7 @@
#include "core/pikaimage.h" #include "core/pikaimage.h"
#include "core/pikaitem.h" #include "core/pikaitem.h"
#include "core/pikalayer.h" #include "core/pikalayer.h"
#include "core/pikapalette.h"
#include "core/pikaparamspecs.h" #include "core/pikaparamspecs.h"
#include "core/pikapickable.h" #include "core/pikapickable.h"
#include "core/pikaprogress.h" #include "core/pikaprogress.h"
@ -1575,6 +1576,35 @@ image_set_colormap_invoker (PikaProcedure *procedure,
error ? *error : NULL); error ? *error : NULL);
} }
static PikaValueArray *
image_get_palette_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error)
{
gboolean success = TRUE;
PikaValueArray *return_vals;
PikaImage *image;
PikaPalette *colormap = NULL;
image = g_value_get_object (pika_value_array_index (args, 0));
if (success)
{
colormap = pika_image_get_colormap_palette (image);
}
return_vals = pika_procedure_get_return_values (procedure, success,
error ? *error : NULL);
if (success)
g_value_set_object (pika_value_array_index (return_vals, 1), colormap);
return return_vals;
}
static PikaValueArray * static PikaValueArray *
image_get_metadata_invoker (PikaProcedure *procedure, image_get_metadata_invoker (PikaProcedure *procedure,
Pika *pika, Pika *pika,
@ -4356,6 +4386,35 @@ register_image_procs (PikaPDB *pdb)
pika_pdb_register_procedure (pdb, procedure); pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);
/*
* pika-image-get-palette
*/
procedure = pika_procedure_new (image_get_palette_invoker);
pika_object_set_static_name (PIKA_OBJECT (procedure),
"pika-image-get-palette");
pika_procedure_set_static_help (procedure,
"Returns the image's colormap",
"This procedure returns the image's colormap as a PikaPalette. If the image is not in Indexed color mode, %NULL is returned.",
NULL);
pika_procedure_set_static_attribution (procedure,
"Jehan",
"Jehan",
"2023");
pika_procedure_add_argument (procedure,
pika_param_spec_image ("image",
"image",
"The image",
FALSE,
PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure,
pika_param_spec_palette ("colormap",
"colormap",
"The image's colormap.",
FALSE,
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure);
/* /*
* pika-image-get-metadata * pika-image-get-metadata
*/ */

View File

@ -34,7 +34,7 @@
#include "internal-procs.h" #include "internal-procs.h"
/* 775 procedures registered total */ /* 779 procedures registered total */
void void
internal_procs_init (PikaPDB *pdb) internal_procs_init (PikaPDB *pdb)
@ -52,6 +52,7 @@ internal_procs_init (PikaPDB *pdb)
register_drawable_procs (pdb); register_drawable_procs (pdb);
register_drawable_color_procs (pdb); register_drawable_color_procs (pdb);
register_drawable_edit_procs (pdb); register_drawable_edit_procs (pdb);
register_drawable_select_procs (pdb);
register_dynamics_procs (pdb); register_dynamics_procs (pdb);
register_edit_procs (pdb); register_edit_procs (pdb);
register_file_procs (pdb); register_file_procs (pdb);

View File

@ -39,6 +39,7 @@ void register_display_procs (PikaPDB *pdb);
void register_drawable_procs (PikaPDB *pdb); void register_drawable_procs (PikaPDB *pdb);
void register_drawable_color_procs (PikaPDB *pdb); void register_drawable_color_procs (PikaPDB *pdb);
void register_drawable_edit_procs (PikaPDB *pdb); void register_drawable_edit_procs (PikaPDB *pdb);
void register_drawable_select_procs (PikaPDB *pdb);
void register_dynamics_procs (PikaPDB *pdb); void register_dynamics_procs (PikaPDB *pdb);
void register_edit_procs (PikaPDB *pdb); void register_edit_procs (PikaPDB *pdb);
void register_file_procs (PikaPDB *pdb); void register_file_procs (PikaPDB *pdb);

View File

@ -19,6 +19,7 @@ libappinternalprocs_sources = [
'drawable-cmds.c', 'drawable-cmds.c',
'drawable-color-cmds.c', 'drawable-color-cmds.c',
'drawable-edit-cmds.c', 'drawable-edit-cmds.c',
'drawable-select-cmds.c',
'dynamics-cmds.c', 'dynamics-cmds.c',
'edit-cmds.c', 'edit-cmds.c',
'file-cmds.c', 'file-cmds.c',

View File

@ -41,6 +41,7 @@
#include "core/pika.h" #include "core/pika.h"
#include "core/pikacontext.h" #include "core/pikacontext.h"
#include "core/pikadatafactory.h" #include "core/pikadatafactory.h"
#include "core/pikaimage-colormap.h"
#include "core/pikapalette.h" #include "core/pikapalette.h"
#include "core/pikaparamspecs.h" #include "core/pikaparamspecs.h"
@ -308,9 +309,18 @@ palette_delete_entry_invoker (PikaProcedure *procedure,
PikaPaletteEntry *entry = pika_palette_get_entry (palette, entry_num); PikaPaletteEntry *entry = pika_palette_get_entry (palette, entry_num);
if (entry) if (entry)
pika_palette_delete_entry (palette, entry); {
PikaImage *image = pika_data_get_image (PIKA_DATA (palette));
if (image != NULL)
success = pika_image_delete_colormap_entry (image, entry_num, TRUE);
else
pika_palette_delete_entry (palette, entry);
}
else else
success = FALSE; {
success = FALSE;
}
} }
else else
success = FALSE; success = FALSE;
@ -376,7 +386,7 @@ palette_entry_set_color_invoker (PikaProcedure *procedure,
if (success) if (success)
{ {
if (pika_data_is_writable (PIKA_DATA (palette))) if (pika_data_is_writable (PIKA_DATA (palette)))
success = pika_palette_set_entry_color (palette, entry_num, &color); success = pika_palette_set_entry_color (palette, entry_num, &color, TRUE);
else else
success = FALSE; success = FALSE;
} }
@ -687,7 +697,8 @@ register_palette_procs (PikaPDB *pdb)
"pika-palette-delete-entry"); "pika-palette-delete-entry");
pika_procedure_set_static_help (procedure, pika_procedure_set_static_help (procedure,
"Deletes an entry from the palette.", "Deletes an entry from the palette.",
"Deletes an entry from the palette. Returns an error if the index is out or range. Returns an error if the palette is not editable.", "This function will fail and return %FALSE if the index is out or range or if the palette is not editable.\n"
"Additionally if the palette belongs to an indexed image, it will only be possible to delete palette colors not in use in the image.",
NULL); NULL);
pika_procedure_set_static_attribution (procedure, pika_procedure_set_static_attribution (procedure,
"Michael Natterer <mitch@gimp.org>", "Michael Natterer <mitch@gimp.org>",

View File

@ -34,7 +34,9 @@
#include "pdb-types.h" #include "pdb-types.h"
#include "core/pika.h" #include "core/pika.h"
#include "core/pikacontainer.h"
#include "core/pikadatafactory.h" #include "core/pikadatafactory.h"
#include "core/pikapalette.h"
#include "core/pikaparamspecs.h" #include "core/pikaparamspecs.h"
#include "pikapdb.h" #include "pikapdb.h"
@ -53,20 +55,24 @@ palettes_popup_invoker (PikaProcedure *procedure,
gboolean success = TRUE; gboolean success = TRUE;
const gchar *palette_callback; const gchar *palette_callback;
const gchar *popup_title; const gchar *popup_title;
const gchar *initial_palette_name; PikaPalette *initial_palette;
GBytes *parent_window;
palette_callback = g_value_get_string (pika_value_array_index (args, 0)); palette_callback = g_value_get_string (pika_value_array_index (args, 0));
popup_title = g_value_get_string (pika_value_array_index (args, 1)); popup_title = g_value_get_string (pika_value_array_index (args, 1));
initial_palette_name = g_value_get_string (pika_value_array_index (args, 2)); initial_palette = g_value_get_object (pika_value_array_index (args, 2));
parent_window = g_value_get_boxed (pika_value_array_index (args, 3));
if (success) if (success)
{ {
PikaContainer *container = pika_data_factory_get_container (pika->palette_factory);
if (pika->no_interface || if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, palette_callback) || ! pika_pdb_lookup_procedure (pika->pdb, palette_callback) ||
! pika_pdb_dialog_new (pika, context, progress, ! pika_pdb_dialog_new (pika, context, progress,
pika_data_factory_get_container (pika->palette_factory), pika_container_get_children_type (container),
popup_title, palette_callback, initial_palette_name, parent_window, popup_title, palette_callback,
NULL)) PIKA_OBJECT (initial_palette), NULL))
success = FALSE; success = FALSE;
} }
@ -89,9 +95,12 @@ palettes_close_popup_invoker (PikaProcedure *procedure,
if (success) if (success)
{ {
PikaContainer *container = pika_data_factory_get_container (pika->palette_factory);
if (pika->no_interface || if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, palette_callback) || ! pika_pdb_lookup_procedure (pika->pdb, palette_callback) ||
! pika_pdb_dialog_close (pika, pika_data_factory_get_container (pika->palette_factory), ! pika_pdb_dialog_close (pika,
pika_container_get_children_type (container),
palette_callback)) palette_callback))
success = FALSE; success = FALSE;
} }
@ -110,18 +119,20 @@ palettes_set_popup_invoker (PikaProcedure *procedure,
{ {
gboolean success = TRUE; gboolean success = TRUE;
const gchar *palette_callback; const gchar *palette_callback;
const gchar *palette_name; PikaPalette *palette;
palette_callback = g_value_get_string (pika_value_array_index (args, 0)); palette_callback = g_value_get_string (pika_value_array_index (args, 0));
palette_name = g_value_get_string (pika_value_array_index (args, 1)); palette = g_value_get_object (pika_value_array_index (args, 1));
if (success) if (success)
{ {
PikaContainer *container = pika_data_factory_get_container (pika->palette_factory);
if (pika->no_interface || if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, palette_callback) || ! pika_pdb_lookup_procedure (pika->pdb, palette_callback) ||
! pika_pdb_dialog_set (pika, pika_data_factory_get_container (pika->palette_factory), ! pika_pdb_dialog_set (pika,
palette_callback, palette_name, pika_container_get_children_type (container),
NULL)) palette_callback, PIKA_OBJECT (palette), NULL))
success = FALSE; success = FALSE;
} }
@ -163,12 +174,17 @@ register_palette_select_procs (PikaPDB *pdb)
NULL, NULL,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_string ("initial-palette-name", pika_param_spec_palette ("initial-palette",
"initial palette name", "initial palette",
"The name of the palette to set as the initial choice.", "The palette to set as the initial choice.",
FALSE, TRUE, FALSE, FALSE,
NULL, PIKA_PARAM_READWRITE));
PIKA_PARAM_READWRITE)); pika_procedure_add_argument (procedure,
g_param_spec_boxed ("parent-window",
"parent window",
"An optional parent window handle for the popup to be set transient to",
G_TYPE_BYTES,
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure); pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);
@ -218,12 +234,11 @@ register_palette_select_procs (PikaPDB *pdb)
NULL, NULL,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_string ("palette-name", pika_param_spec_palette ("palette",
"palette name", "palette",
"The name of the palette to set as selected", "The palette to set as selected",
FALSE, FALSE, FALSE, FALSE,
NULL, PIKA_PARAM_READWRITE));
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure); pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);
} }

View File

@ -256,7 +256,7 @@ register_pattern_procs (PikaPDB *pdb)
"pika-pattern-get-pixels"); "pika-pattern-get-pixels");
pika_procedure_set_static_help (procedure, pika_procedure_set_static_help (procedure,
"Gets information about the pattern (including pixels).", "Gets information about the pattern (including pixels).",
"Gets information about the pattern: the pattern extents (width and height), its bpp, and its pixel data. The pixel data is an array in C or a list in some languages.", "Gets information about the pattern: the pattern extents (width and height), its bpp, and its pixel data.",
NULL); NULL);
pika_procedure_set_static_attribution (procedure, pika_procedure_set_static_attribution (procedure,
"Michael Natterer <mitch@gimp.org>", "Michael Natterer <mitch@gimp.org>",

View File

@ -34,8 +34,10 @@
#include "pdb-types.h" #include "pdb-types.h"
#include "core/pika.h" #include "core/pika.h"
#include "core/pikacontainer.h"
#include "core/pikadatafactory.h" #include "core/pikadatafactory.h"
#include "core/pikaparamspecs.h" #include "core/pikaparamspecs.h"
#include "core/pikapattern.h"
#include "pikapdb.h" #include "pikapdb.h"
#include "pikaprocedure.h" #include "pikaprocedure.h"
@ -53,20 +55,24 @@ patterns_popup_invoker (PikaProcedure *procedure,
gboolean success = TRUE; gboolean success = TRUE;
const gchar *pattern_callback; const gchar *pattern_callback;
const gchar *popup_title; const gchar *popup_title;
const gchar *initial_pattern_name; PikaPattern *initial_pattern;
GBytes *parent_window;
pattern_callback = g_value_get_string (pika_value_array_index (args, 0)); pattern_callback = g_value_get_string (pika_value_array_index (args, 0));
popup_title = g_value_get_string (pika_value_array_index (args, 1)); popup_title = g_value_get_string (pika_value_array_index (args, 1));
initial_pattern_name = g_value_get_string (pika_value_array_index (args, 2)); initial_pattern = g_value_get_object (pika_value_array_index (args, 2));
parent_window = g_value_get_boxed (pika_value_array_index (args, 3));
if (success) if (success)
{ {
PikaContainer *container = pika_data_factory_get_container (pika->pattern_factory);
if (pika->no_interface || if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, pattern_callback) || ! pika_pdb_lookup_procedure (pika->pdb, pattern_callback) ||
! pika_pdb_dialog_new (pika, context, progress, ! pika_pdb_dialog_new (pika, context, progress,
pika_data_factory_get_container (pika->pattern_factory), pika_container_get_children_type (container),
popup_title, pattern_callback, initial_pattern_name, parent_window, popup_title, pattern_callback,
NULL)) PIKA_OBJECT (initial_pattern), NULL))
success = FALSE; success = FALSE;
} }
@ -89,9 +95,12 @@ patterns_close_popup_invoker (PikaProcedure *procedure,
if (success) if (success)
{ {
PikaContainer *container = pika_data_factory_get_container (pika->pattern_factory);
if (pika->no_interface || if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, pattern_callback) || ! pika_pdb_lookup_procedure (pika->pdb, pattern_callback) ||
! pika_pdb_dialog_close (pika, pika_data_factory_get_container (pika->pattern_factory), ! pika_pdb_dialog_close (pika,
pika_container_get_children_type (container),
pattern_callback)) pattern_callback))
success = FALSE; success = FALSE;
} }
@ -110,18 +119,20 @@ patterns_set_popup_invoker (PikaProcedure *procedure,
{ {
gboolean success = TRUE; gboolean success = TRUE;
const gchar *pattern_callback; const gchar *pattern_callback;
const gchar *pattern_name; PikaPattern *pattern;
pattern_callback = g_value_get_string (pika_value_array_index (args, 0)); pattern_callback = g_value_get_string (pika_value_array_index (args, 0));
pattern_name = g_value_get_string (pika_value_array_index (args, 1)); pattern = g_value_get_object (pika_value_array_index (args, 1));
if (success) if (success)
{ {
PikaContainer *container = pika_data_factory_get_container (pika->pattern_factory);
if (pika->no_interface || if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, pattern_callback) || ! pika_pdb_lookup_procedure (pika->pdb, pattern_callback) ||
! pika_pdb_dialog_set (pika, pika_data_factory_get_container (pika->pattern_factory), ! pika_pdb_dialog_set (pika,
pattern_callback, pattern_name, pika_container_get_children_type (container),
NULL)) pattern_callback, PIKA_OBJECT (pattern), NULL))
success = FALSE; success = FALSE;
} }
@ -163,12 +174,17 @@ register_pattern_select_procs (PikaPDB *pdb)
NULL, NULL,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_string ("initial-pattern-name", pika_param_spec_pattern ("initial-pattern",
"initial pattern name", "initial pattern",
"The name of the pattern to set as the initial choice", "The pattern to set as the initial choice",
FALSE, TRUE, FALSE, FALSE,
NULL, PIKA_PARAM_READWRITE));
PIKA_PARAM_READWRITE)); pika_procedure_add_argument (procedure,
g_param_spec_boxed ("parent-window",
"parent window",
"An optional parent window handle for the popup to be set transient to",
G_TYPE_BYTES,
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure); pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);
@ -218,12 +234,11 @@ register_pattern_select_procs (PikaPDB *pdb)
NULL, NULL,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_string ("pattern-name", pika_param_spec_pattern ("pattern",
"pattern name", "pattern",
"The name of the pattern to set as selected", "The pattern to set as selected",
FALSE, FALSE, FALSE, FALSE,
NULL, PIKA_PARAM_READWRITE));
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure); pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);
} }

View File

@ -1167,47 +1167,6 @@ pdb_get_data_invoker (PikaProcedure *procedure,
return return_vals; return return_vals;
} }
static PikaValueArray *
pdb_get_data_size_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
const PikaValueArray *args,
GError **error)
{
gboolean success = TRUE;
PikaValueArray *return_vals;
const gchar *identifier;
gint bytes = 0;
identifier = g_value_get_string (pika_value_array_index (args, 0));
if (success)
{
if (pika_is_canonical_identifier (identifier))
{
if (! pika_plug_in_manager_get_data (pika->plug_in_manager,
identifier, &bytes))
success = FALSE;
}
else
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_INVALID_ARGUMENT,
_("Data label '%s' is not a canonical identifier"),
identifier);
success = FALSE;
}
}
return_vals = pika_procedure_get_return_values (procedure, success,
error ? *error : NULL);
if (success)
g_value_set_int (pika_value_array_index (return_vals, 1), bytes);
return return_vals;
}
static PikaValueArray * static PikaValueArray *
pdb_set_data_invoker (PikaProcedure *procedure, pdb_set_data_invoker (PikaProcedure *procedure,
Pika *pika, Pika *pika,
@ -2230,36 +2189,6 @@ register_pdb_procs (PikaPDB *pdb)
pika_pdb_register_procedure (pdb, procedure); pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);
/*
* pika-pdb-get-data-size
*/
procedure = pika_procedure_new (pdb_get_data_size_invoker);
pika_object_set_static_name (PIKA_OBJECT (procedure),
"pika-pdb-get-data-size");
pika_procedure_set_static_help (procedure,
"Returns size of data associated with the specified identifier.",
"This procedure returns the size of any data which may have been associated with the specified identifier. If no data has been associated with the identifier, an error is returned.",
NULL);
pika_procedure_set_static_attribution (procedure,
"Nick Lamb",
"Nick Lamb",
"1998");
pika_procedure_add_argument (procedure,
pika_param_spec_string ("identifier",
"identifier",
"The identifier associated with data",
FALSE, FALSE, TRUE,
NULL,
PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure,
g_param_spec_int ("bytes",
"bytes",
"The number of bytes in the data",
1, G_MAXINT32, 1,
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure);
/* /*
* pika-pdb-set-data * pika-pdb-set-data
*/ */

View File

@ -105,6 +105,91 @@ pika_pdb_get_data_factory (Pika *pika,
g_return_val_if_reached (NULL); g_return_val_if_reached (NULL);
} }
GList *
pika_pdb_get_resources (Pika *pika,
GType data_type,
const gchar *name,
PikaPDBDataAccess access,
GError **error)
{
GList *resources;
PikaDataFactory *factory;
PikaContainer *container;
const gchar *label;
g_return_val_if_fail (PIKA_IS_PIKA (pika), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
label = pika_pdb_get_data_label (data_type);
if (! name || ! strlen (name))
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_INVALID_ARGUMENT,
/* TRANSLATOR: %s is a data label from the
* PDB-error-data-label context.
*/
C_("PDB-error-message", "%s name cannot be empty"),
g_type_name (data_type));
return NULL;
}
factory = pika_pdb_get_data_factory (pika, data_type);
g_return_val_if_fail (PIKA_IS_DATA_FACTORY (factory), NULL);
container = pika_data_factory_get_container (factory);
resources = pika_container_get_children_by_name (container, name);
if (! resources && ! strcmp (name, "Standard"))
{
PikaData *resource;
resource = pika_data_factory_data_get_standard (factory, pika_get_user_context (pika));
g_return_val_if_fail (resource != NULL, NULL);
resources = g_list_prepend (NULL, resource);
}
if (! resources)
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_INVALID_ARGUMENT,
/* TRANSLATOR: the first %s is a data label from the
* PDB-error-data-label context. The second %s is a data
* name.
*/
C_("PDB-error-message", "%s '%s' not found"), label, name);
}
else if ((access & PIKA_PDB_DATA_ACCESS_WRITE) ||
(access & PIKA_PDB_DATA_ACCESS_RENAME))
{
for (GList *iter = resources; iter; iter = iter->next)
{
if ((access & PIKA_PDB_DATA_ACCESS_WRITE) &&
! pika_data_is_writable (PIKA_DATA (iter->data)))
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_INVALID_ARGUMENT,
/* TRANSLATOR: the first %s is a data label from the
* PDB-error-data-label context. The second %s is a data
* name.
*/
C_("PDB-error-message", "%s '%s' is not editable"), label, name);
return NULL;
}
else if ((access & PIKA_PDB_DATA_ACCESS_RENAME) &&
! pika_viewable_is_name_editable (PIKA_VIEWABLE (iter->data)))
{
g_set_error (error, PIKA_PDB_ERROR, PIKA_PDB_ERROR_INVALID_ARGUMENT,
/* TRANSLATOR: the first %s is a data label from the
* PDB-error-data-label context. The second %s is a data
* name.
*/
C_("PDB-error-message", "%s '%s' is not renamable"), label, name);
return NULL;
}
}
}
return resources;
}
PikaResource * PikaResource *
pika_pdb_get_resource (Pika *pika, pika_pdb_get_resource (Pika *pika,
GType data_type, GType data_type,

View File

@ -26,6 +26,11 @@
PikaDataFactory * pika_pdb_get_data_factory (Pika *pika, PikaDataFactory * pika_pdb_get_data_factory (Pika *pika,
GType data_type); GType data_type);
GList * pika_pdb_get_resources (Pika *pika,
GType data_type,
const gchar *name,
PikaPDBDataAccess access,
GError **error);
PikaResource * pika_pdb_get_resource (Pika *pika, PikaResource * pika_pdb_get_resource (Pika *pika,
GType data_type, GType data_type,
const gchar *name, const gchar *name,

View File

@ -193,14 +193,14 @@ progress_get_window_handle_invoker (PikaProcedure *procedure,
{ {
gboolean success = TRUE; gboolean success = TRUE;
PikaValueArray *return_vals; PikaValueArray *return_vals;
gint window = 0; GBytes *handle = NULL;
PikaPlugIn *plug_in = pika->plug_in_manager->current_plug_in; PikaPlugIn *plug_in = pika->plug_in_manager->current_plug_in;
if (plug_in && plug_in->open) if (plug_in && plug_in->open)
{ {
if (! pika->no_interface) if (! pika->no_interface)
window = pika_plug_in_progress_get_window_id (plug_in); handle = pika_plug_in_progress_get_window_id (plug_in);
} }
else else
success = FALSE; success = FALSE;
@ -209,7 +209,7 @@ progress_get_window_handle_invoker (PikaProcedure *procedure,
error ? *error : NULL); error ? *error : NULL);
if (success) if (success)
g_value_set_int (pika_value_array_index (return_vals, 1), window); g_value_take_boxed (pika_value_array_index (return_vals, 1), handle);
return return_vals; return return_vals;
} }
@ -418,19 +418,20 @@ register_progress_procs (PikaPDB *pdb)
pika_object_set_static_name (PIKA_OBJECT (procedure), pika_object_set_static_name (PIKA_OBJECT (procedure),
"pika-progress-get-window-handle"); "pika-progress-get-window-handle");
pika_procedure_set_static_help (procedure, pika_procedure_set_static_help (procedure,
"Returns the native window ID of the toplevel window this plug-in's progress is displayed in.", "Returns the native handle of the toplevel window this plug-in's progress is displayed in.",
"This function returns the native window ID of the toplevel window this plug-in\'s progress is displayed in.", "This function returns the native handle allowing to identify the toplevel window this plug-in's progress is displayed in.\n"
"This handle can be of various types (integer, string, etc.) depending on the platform you are running on which is why it returns a GBytes. There are usually no reasons to call this directly.",
NULL); NULL);
pika_procedure_set_static_attribution (procedure, pika_procedure_set_static_attribution (procedure,
"Michael Natterer <mitch@gimp.org>", "Michael Natterer <mitch@gimp.org>",
"Michael Natterer", "Michael Natterer",
"2004"); "2004");
pika_procedure_add_return_value (procedure, pika_procedure_add_return_value (procedure,
g_param_spec_int ("window", g_param_spec_boxed ("handle",
"window", "handle",
"The progress bar's toplevel window", "The progress bar's toplevel window's handle",
G_MININT32, G_MAXINT32, 0, G_TYPE_BYTES,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure); pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);

View File

@ -67,14 +67,14 @@ text_layer_new_invoker (PikaProcedure *procedure,
PikaValueArray *return_vals; PikaValueArray *return_vals;
PikaImage *image; PikaImage *image;
const gchar *text; const gchar *text;
const gchar *fontname; PikaFont *font;
gdouble size; gdouble size;
PikaUnit unit; PikaUnit unit;
PikaTextLayer *layer = NULL; PikaTextLayer *layer = NULL;
image = g_value_get_object (pika_value_array_index (args, 0)); image = g_value_get_object (pika_value_array_index (args, 0));
text = g_value_get_string (pika_value_array_index (args, 1)); text = g_value_get_string (pika_value_array_index (args, 1));
fontname = g_value_get_string (pika_value_array_index (args, 2)); font = g_value_get_object (pika_value_array_index (args, 2));
size = g_value_get_double (pika_value_array_index (args, 3)); size = g_value_get_double (pika_value_array_index (args, 3));
unit = g_value_get_int (pika_value_array_index (args, 4)); unit = g_value_get_int (pika_value_array_index (args, 4));
@ -87,7 +87,7 @@ text_layer_new_invoker (PikaProcedure *procedure,
pika_text = g_object_new (PIKA_TYPE_TEXT, pika_text = g_object_new (PIKA_TYPE_TEXT,
"text", text, "text", text,
"font", fontname, "font", font,
"font-size", size, "font-size", size,
"font-size-unit", unit, "font-size-unit", unit,
"color", &color, "color", &color,
@ -259,26 +259,26 @@ text_layer_get_font_invoker (PikaProcedure *procedure,
gboolean success = TRUE; gboolean success = TRUE;
PikaValueArray *return_vals; PikaValueArray *return_vals;
PikaTextLayer *layer; PikaTextLayer *layer;
gchar *font = NULL; PikaFont *font = NULL;
layer = g_value_get_object (pika_value_array_index (args, 0)); layer = g_value_get_object (pika_value_array_index (args, 0));
if (success) if (success)
{ {
PikaFont *font_obj;
g_object_get (pika_text_layer_get_text (layer), g_object_get (pika_text_layer_get_text (layer),
"font", &font_obj, "font", &font,
NULL); NULL);
font = g_strdup (pika_font_get_lookup_name (font_obj)); /* The PikaText keeps a reference. Therefore unref before returning the
g_object_unref (font_obj); * pointer so that we don't leak a reference.
*/
g_object_unref (font);
} }
return_vals = pika_procedure_get_return_values (procedure, success, return_vals = pika_procedure_get_return_values (procedure, success,
error ? *error : NULL); error ? *error : NULL);
if (success) if (success)
g_value_take_string (pika_value_array_index (return_vals, 1), font); g_value_set_object (pika_value_array_index (return_vals, 1), font);
return return_vals; return return_vals;
} }
@ -293,10 +293,10 @@ text_layer_set_font_invoker (PikaProcedure *procedure,
{ {
gboolean success = TRUE; gboolean success = TRUE;
PikaTextLayer *layer; PikaTextLayer *layer;
const gchar *font; PikaFont *font;
layer = g_value_get_object (pika_value_array_index (args, 0)); layer = g_value_get_object (pika_value_array_index (args, 0));
font = g_value_get_string (pika_value_array_index (args, 1)); font = g_value_get_object (pika_value_array_index (args, 1));
if (success) if (success)
{ {
@ -1028,12 +1028,11 @@ register_text_layer_procs (PikaPDB *pdb)
NULL, NULL,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_string ("fontname", pika_param_spec_font ("font",
"fontname", "font",
"The name of the font", "The font to write the text with",
FALSE, FALSE, FALSE, FALSE,
NULL, PIKA_PARAM_READWRITE));
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
g_param_spec_double ("size", g_param_spec_double ("size",
"size", "size",
@ -1186,7 +1185,7 @@ register_text_layer_procs (PikaPDB *pdb)
"pika-text-layer-get-font"); "pika-text-layer-get-font");
pika_procedure_set_static_help (procedure, pika_procedure_set_static_help (procedure,
"Get the font from a text layer as string.", "Get the font from a text layer as string.",
"This procedure returns the name of the font from a text layer.", "This procedure returns the font from a text layer.",
NULL); NULL);
pika_procedure_set_static_attribution (procedure, pika_procedure_set_static_attribution (procedure,
"Marcus Heese <heese@cip.ifi.lmu.de>", "Marcus Heese <heese@cip.ifi.lmu.de>",
@ -1199,12 +1198,11 @@ register_text_layer_procs (PikaPDB *pdb)
FALSE, FALSE,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure, pika_procedure_add_return_value (procedure,
pika_param_spec_string ("font", pika_param_spec_font ("font",
"font", "font",
"The font which is used in the specified text layer.", "The font which is used in the specified text layer.",
FALSE, FALSE, FALSE, FALSE,
NULL, PIKA_PARAM_READWRITE));
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure); pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);
@ -1229,12 +1227,11 @@ register_text_layer_procs (PikaPDB *pdb)
FALSE, FALSE,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
pika_param_spec_string ("font", pika_param_spec_font ("font",
"font", "font",
"The new font to use", "The new font to use",
FALSE, FALSE, FALSE, FALSE,
NULL, PIKA_PARAM_READWRITE));
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure); pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure); g_object_unref (procedure);

View File

@ -39,6 +39,7 @@
#include "core/pikaimage.h" #include "core/pikaimage.h"
#include "core/pikalayer.h" #include "core/pikalayer.h"
#include "core/pikaparamspecs.h" #include "core/pikaparamspecs.h"
#include "text/pikafont.h"
#include "text/pikatext-compat.h" #include "text/pikatext-compat.h"
#include "pikapdb.h" #include "pikapdb.h"
@ -48,12 +49,12 @@
static PikaValueArray * static PikaValueArray *
text_fontname_invoker (PikaProcedure *procedure, text_font_invoker (PikaProcedure *procedure,
Pika *pika, Pika *pika,
PikaContext *context, PikaContext *context,
PikaProgress *progress, PikaProgress *progress,
const PikaValueArray *args, const PikaValueArray *args,
GError **error) GError **error)
{ {
gboolean success = TRUE; gboolean success = TRUE;
PikaValueArray *return_vals; PikaValueArray *return_vals;
@ -65,7 +66,7 @@ text_fontname_invoker (PikaProcedure *procedure,
gint border; gint border;
gboolean antialias; gboolean antialias;
gdouble size; gdouble size;
const gchar *fontname; PikaFont *font;
PikaLayer *text_layer = NULL; PikaLayer *text_layer = NULL;
image = g_value_get_object (pika_value_array_index (args, 0)); image = g_value_get_object (pika_value_array_index (args, 0));
@ -76,7 +77,7 @@ text_fontname_invoker (PikaProcedure *procedure,
border = g_value_get_int (pika_value_array_index (args, 5)); border = g_value_get_int (pika_value_array_index (args, 5));
antialias = g_value_get_boolean (pika_value_array_index (args, 6)); antialias = g_value_get_boolean (pika_value_array_index (args, 6));
size = g_value_get_double (pika_value_array_index (args, 7)); size = g_value_get_double (pika_value_array_index (args, 7));
fontname = g_value_get_string (pika_value_array_index (args, 9)); font = g_value_get_object (pika_value_array_index (args, 8));
if (success) if (success)
{ {
@ -87,15 +88,9 @@ text_fontname_invoker (PikaProcedure *procedure,
success = FALSE; success = FALSE;
if (success) if (success)
{ text_layer = text_render (image, drawable, context,
gchar *real_fontname = g_strdup_printf ("%s %d", fontname, (gint) size); x, y, font, size, text,
border, antialias);
text_layer = text_render (image, drawable, context,
x, y, real_fontname, text,
border, antialias);
g_free (real_fontname);
}
} }
return_vals = pika_procedure_get_return_values (procedure, success, return_vals = pika_procedure_get_return_values (procedure, success,
@ -108,18 +103,18 @@ text_fontname_invoker (PikaProcedure *procedure,
} }
static PikaValueArray * static PikaValueArray *
text_get_extents_fontname_invoker (PikaProcedure *procedure, text_get_extents_font_invoker (PikaProcedure *procedure,
Pika *pika, Pika *pika,
PikaContext *context, PikaContext *context,
PikaProgress *progress, PikaProgress *progress,
const PikaValueArray *args, const PikaValueArray *args,
GError **error) GError **error)
{ {
gboolean success = TRUE; gboolean success = TRUE;
PikaValueArray *return_vals; PikaValueArray *return_vals;
const gchar *text; const gchar *text;
gdouble size; gdouble size;
const gchar *fontname; PikaFont *font;
gint width = 0; gint width = 0;
gint height = 0; gint height = 0;
gint ascent = 0; gint ascent = 0;
@ -127,18 +122,14 @@ text_get_extents_fontname_invoker (PikaProcedure *procedure,
text = g_value_get_string (pika_value_array_index (args, 0)); text = g_value_get_string (pika_value_array_index (args, 0));
size = g_value_get_double (pika_value_array_index (args, 1)); size = g_value_get_double (pika_value_array_index (args, 1));
fontname = g_value_get_string (pika_value_array_index (args, 3)); font = g_value_get_object (pika_value_array_index (args, 2));
if (success) if (success)
{ {
gchar *real_fontname = g_strdup_printf ("%s %d", fontname, (gint) size);
success = text_get_extents (pika, success = text_get_extents (pika,
real_fontname, text, font, size, text,
&width, &height, &width, &height,
&ascent, &descent); &ascent, &descent);
g_free (real_fontname);
} }
return_vals = pika_procedure_get_return_values (procedure, success, return_vals = pika_procedure_get_return_values (procedure, success,
@ -161,14 +152,15 @@ register_text_tool_procs (PikaPDB *pdb)
PikaProcedure *procedure; PikaProcedure *procedure;
/* /*
* pika-text-fontname * pika-text-font
*/ */
procedure = pika_procedure_new (text_fontname_invoker); procedure = pika_procedure_new (text_font_invoker);
pika_object_set_static_name (PIKA_OBJECT (procedure), pika_object_set_static_name (PIKA_OBJECT (procedure),
"pika-text-fontname"); "pika-text-font");
pika_procedure_set_static_help (procedure, pika_procedure_set_static_help (procedure,
"Add text at the specified location as a floating selection or a new layer.", "Add text at the specified location as a floating selection or a new layer.",
"This tool requires a fontname matching an installed PangoFT2 font. You can specify the fontsize in units of pixels or points, and the appropriate metric is specified using the size_type argument. The x and y parameters together control the placement of the new text by specifying the upper left corner of the text bounding box. If the specified drawable parameter is valid, the text will be created as a floating selection attached to the drawable. If the drawable parameter is not valid (%NULL), the text will appear as a new layer. Finally, a border can be specified around the final rendered text. The border is measured in pixels. Parameter size-type is not used and is currently ignored. If you need to display a font in points, divide the size in points by 72.0 and multiply it by the image's vertical resolution.", "The x and y parameters together control the placement of the new text by specifying the upper left corner of the text bounding box. If the specified drawable parameter is valid, the text will be created as a floating selection attached to the drawable. If the drawable parameter is not valid (%NULL), the text will appear as a new layer. Finally, a border can be specified around the final rendered text. The border is measured in pixels.\n"
"The size is always in pixels. If you need to display a font in points, divide the size in points by 72.0 and multiply it by the image's vertical resolution.",
NULL); NULL);
pika_procedure_set_static_attribution (procedure, pika_procedure_set_static_attribution (procedure,
"Martin Edlman & Sven Neumann", "Martin Edlman & Sven Neumann",
@ -220,23 +212,15 @@ register_text_tool_procs (PikaPDB *pdb)
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
g_param_spec_double ("size", g_param_spec_double ("size",
"size", "size",
"The size of text in either pixels or points", "The size of text in pixels",
0, G_MAXDOUBLE, 0, 0, G_MAXDOUBLE, 0,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
g_param_spec_enum ("size-type", pika_param_spec_font ("font",
"size type", "font",
"The units of specified size", "The font",
PIKA_TYPE_SIZE_TYPE, FALSE,
PIKA_PIXELS, PIKA_PARAM_READWRITE));
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("fontname",
"fontname",
"The name of the font",
FALSE, FALSE, FALSE,
NULL,
PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure, pika_procedure_add_return_value (procedure,
pika_param_spec_layer ("text-layer", pika_param_spec_layer ("text-layer",
"text layer", "text layer",
@ -247,14 +231,16 @@ register_text_tool_procs (PikaPDB *pdb)
g_object_unref (procedure); g_object_unref (procedure);
/* /*
* pika-text-get-extents-fontname * pika-text-get-extents-font
*/ */
procedure = pika_procedure_new (text_get_extents_fontname_invoker); procedure = pika_procedure_new (text_get_extents_font_invoker);
pika_object_set_static_name (PIKA_OBJECT (procedure), pika_object_set_static_name (PIKA_OBJECT (procedure),
"pika-text-get-extents-fontname"); "pika-text-get-extents-font");
pika_procedure_set_static_help (procedure, pika_procedure_set_static_help (procedure,
"Get extents of the bounding box for the specified text.", "Get extents of the bounding box for the specified text.",
"This tool returns the width and height of a bounding box for the specified text string with the specified font information. Ascent and descent for the specified font are returned as well. Parameter size-type is not used and is currently ignored. If you need to display a font in points, divide the size in points by 72.0 and multiply it by the vertical resolution of the image you are taking into account.", "This tool returns the width and height of a bounding box for the specified text rendered with the specified font information. Ascent and descent of the glyph extents are returned as well.\n"
"The ascent is the distance from the baseline to the highest point of the character. This is positive if the glyph ascends above the baseline. The descent is the distance from the baseline to the lowest point of the character. This is positive if the glyph descends below the baseline.\n"
"The size is always in pixels. If you need to set a font in points, divide the size in points by 72.0 and multiply it by the vertical resolution of the image you are taking into account.",
NULL); NULL);
pika_procedure_set_static_attribution (procedure, pika_procedure_set_static_attribution (procedure,
"Martin Edlman & Sven Neumann", "Martin Edlman & Sven Neumann",
@ -274,41 +260,33 @@ register_text_tool_procs (PikaPDB *pdb)
0, G_MAXDOUBLE, 0, 0, G_MAXDOUBLE, 0,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure, pika_procedure_add_argument (procedure,
g_param_spec_enum ("size-type", pika_param_spec_font ("font",
"size type", "font",
"The units of specified size", "The name of the font",
PIKA_TYPE_SIZE_TYPE, FALSE,
PIKA_PIXELS, PIKA_PARAM_READWRITE));
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("fontname",
"fontname",
"The name of the font",
FALSE, FALSE, FALSE,
NULL,
PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure, pika_procedure_add_return_value (procedure,
g_param_spec_int ("width", g_param_spec_int ("width",
"width", "width",
"The width of the specified font", "The width of the glyph extents",
G_MININT32, G_MAXINT32, 0, G_MININT32, G_MAXINT32, 0,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure, pika_procedure_add_return_value (procedure,
g_param_spec_int ("height", g_param_spec_int ("height",
"height", "height",
"The height of the specified font", "The height of the glyph extents",
G_MININT32, G_MAXINT32, 0, G_MININT32, G_MAXINT32, 0,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure, pika_procedure_add_return_value (procedure,
g_param_spec_int ("ascent", g_param_spec_int ("ascent",
"ascent", "ascent",
"The ascent of the specified font", "The ascent of the glyph extents",
G_MININT32, G_MAXINT32, 0, G_MININT32, G_MAXINT32, 0,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure, pika_procedure_add_return_value (procedure,
g_param_spec_int ("descent", g_param_spec_int ("descent",
"descent", "descent",
"The descent of the specified font", "The descent of the glyph extents",
G_MININT32, G_MAXINT32, 0, G_MININT32, G_MAXINT32, 0,
PIKA_PARAM_READWRITE)); PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure); pika_pdb_register_procedure (pdb, procedure);

View File

@ -439,14 +439,18 @@ pika_update_about_dialog (PikaCoreConfig *config,
const GParamSpec *pspec, const GParamSpec *pspec,
gpointer user_data) gpointer user_data)
{ {
#ifndef PIKA_CONSOLE_COMPILATION
Pika *pika = user_data;
#endif
g_signal_handlers_disconnect_by_func (config, g_signal_handlers_disconnect_by_func (config,
(GCallback) pika_update_about_dialog, (GCallback) pika_update_about_dialog,
NULL); user_data);
if (config->last_known_release != NULL) if (config->last_known_release != NULL)
{ {
#ifndef PIKA_CONSOLE_COMPILATION #ifndef PIKA_CONSOLE_COMPILATION
gtk_widget_show (about_dialog_create (config)); gtk_widget_show (about_dialog_create (pika));
#else #else
g_printerr (_("A new version of PIKA (%s) was released.\n" g_printerr (_("A new version of PIKA (%s) was released.\n"
"It is recommended to update."), "It is recommended to update."),
@ -643,7 +647,7 @@ pika_update_auto_check (PikaCoreConfig *config,
g_signal_connect (config, "notify::last-known-release", g_signal_connect (config, "notify::last-known-release",
(GCallback) pika_update_about_dialog, (GCallback) pika_update_about_dialog,
NULL); pika);
pika_update_check (config); pika_update_check (config);

View File

@ -237,7 +237,7 @@ pika_plug_in_progress_pulse (PikaPlugIn *plug_in)
pika_progress_pulse (proc_frame->progress); pika_progress_pulse (proc_frame->progress);
} }
guint32 GBytes *
pika_plug_in_progress_get_window_id (PikaPlugIn *plug_in) pika_plug_in_progress_get_window_id (PikaPlugIn *plug_in)
{ {
PikaPlugInProcFrame *proc_frame; PikaPlugInProcFrame *proc_frame;

View File

@ -38,7 +38,7 @@ void pika_plug_in_progress_set_text (PikaPlugIn *plug_in,
void pika_plug_in_progress_set_value (PikaPlugIn *plug_in, void pika_plug_in_progress_set_value (PikaPlugIn *plug_in,
gdouble percentage); gdouble percentage);
void pika_plug_in_progress_pulse (PikaPlugIn *plug_in); void pika_plug_in_progress_pulse (PikaPlugIn *plug_in);
guint32 pika_plug_in_progress_get_window_id (PikaPlugIn *plug_in); GBytes * pika_plug_in_progress_get_window_id (PikaPlugIn *plug_in);
gboolean pika_plug_in_progress_install (PikaPlugIn *plug_in, gboolean pika_plug_in_progress_install (PikaPlugIn *plug_in,
const gchar *progress_callback); const gchar *progress_callback);

View File

@ -665,10 +665,11 @@ pika_plug_in_manager_add_from_file (PikaPlugInManager *manager,
basename = g_path_get_basename (filename); basename = g_path_get_basename (filename);
g_free (filename); g_free (filename);
/* When we scan build dirs for plug-ins, there will be some /* When we scan build dirs for plug-ins, there might be some
* executable files that are not plug-ins that we want to ignore, * executable files that are not plug-ins that we want to ignore,
* for example plug-ins/common/mkgen.pl if * for example back with autotools, there used to be a file
* PIKA_TESTING_PLUGINDIRS=plug-ins/common * plug-ins/common/mkgen.pl if PIKA_TESTING_PLUGINDIRS=plug-ins/common
* Such files should be listed in PIKA_TESTING_PLUGINDIRS_BASENAME_IGNORES
*/ */
if (pika_plug_in_manager_ignore_plugin_basename (basename)) if (pika_plug_in_manager_ignore_plugin_basename (basename))
{ {

View File

@ -830,6 +830,56 @@ plug_in_proc_arg_deserialize (GScanner *scanner,
} }
break; break;
case GP_PARAM_DEF_TYPE_CHOICE:
{
PikaChoice *choice;
gint n_choices;
if (! pika_scanner_parse_string (scanner,
&param_def.meta.m_choice.default_val) ||
! pika_scanner_parse_int (scanner, &n_choices))
{
token = G_TOKEN_INT;
goto error;
}
choice = pika_choice_new ();
param_def.meta.m_choice.choice = choice;
for (int i = 0; i < n_choices; i++)
{
gchar *nick = NULL;
gchar *label = NULL;
gchar *help = NULL;
gint id;
if (! pika_scanner_parse_string (scanner, &nick))
{
token = G_TOKEN_STRING;
goto error;
}
if (! pika_scanner_parse_int (scanner, &id))
{
token = G_TOKEN_INT;
goto error;
}
if (! pika_scanner_parse_string (scanner, &label) ||
! pika_scanner_parse_string (scanner, &help))
{
token = G_TOKEN_STRING;
g_free (nick);
g_free (label);
g_free (help);
goto error;
}
pika_choice_add (choice, nick, id, label, help);
g_free (nick);
g_free (label);
g_free (help);
}
}
break;
case GP_PARAM_DEF_TYPE_BOOLEAN: case GP_PARAM_DEF_TYPE_BOOLEAN:
if (! pika_scanner_parse_int (scanner, if (! pika_scanner_parse_int (scanner,
&param_def.meta.m_boolean.default_val)) &param_def.meta.m_boolean.default_val))
@ -944,6 +994,11 @@ plug_in_proc_arg_deserialize (GScanner *scanner,
case GP_PARAM_DEF_TYPE_ID: case GP_PARAM_DEF_TYPE_ID:
break; break;
case GP_PARAM_DEF_TYPE_CHOICE:
g_clear_object (&param_def.meta.m_choice.choice);
g_free (param_def.meta.m_choice.default_val);
break;
case GP_PARAM_DEF_TYPE_ID_ARRAY: case GP_PARAM_DEF_TYPE_ID_ARRAY:
g_free (param_def.meta.m_id_array.type_name); g_free (param_def.meta.m_id_array.type_name);
break; break;
@ -1038,6 +1093,31 @@ plug_in_rc_write_proc_arg (PikaConfigWriter *writer,
param_def.meta.m_enum.default_val); param_def.meta.m_enum.default_val);
break; break;
case GP_PARAM_DEF_TYPE_CHOICE:
{
GList *choices;
choices = pika_choice_list_nicks (param_def.meta.m_choice.choice);
pika_config_writer_string (writer, param_def.meta.m_choice.default_val);
pika_config_writer_printf (writer, "%d", g_list_length (choices));
for (GList *iter = choices; iter; iter = iter->next)
{
const gchar *nick = iter->data;
const gchar *label;
const gchar *help;
gint id;
pika_choice_get_documentation (param_def.meta.m_choice.choice,
nick, &label, &help);
id = pika_choice_get_id (param_def.meta.m_choice.choice, nick);
pika_config_writer_string (writer, nick);
pika_config_writer_printf (writer, "%d", id);
pika_config_writer_string (writer, label);
pika_config_writer_string (writer, help);
}
}
break;
case GP_PARAM_DEF_TYPE_BOOLEAN: case GP_PARAM_DEF_TYPE_BOOLEAN:
pika_config_writer_printf (writer, "%d", pika_config_writer_printf (writer, "%d",
param_def.meta.m_boolean.default_val); param_def.meta.m_boolean.default_val);

View File

@ -66,8 +66,7 @@ foreach test_name : app_tests
env: [ env: [
'PIKA_TESTING_ABS_TOP_SRCDIR=' + meson.project_source_root(), 'PIKA_TESTING_ABS_TOP_SRCDIR=' + meson.project_source_root(),
'PIKA_TESTING_ABS_TOP_BUILDDIR='+ meson.project_build_root(), 'PIKA_TESTING_ABS_TOP_BUILDDIR='+ meson.project_build_root(),
'PIKA_TESTING_PLUGINDIRS=' + meson.project_build_root()/'plug-ins'/'common', 'PIKA_TESTING_PLUGINDIRS=' + meson.project_build_root()/'plug-ins'/'common',
'PIKA_TESTING_PLUGINDIRS_BASENAME_IGNORES=mkgen.pl',
'UI_TEST=yes', 'UI_TEST=yes',
], ],
suite: 'app', suite: 'app',

View File

@ -406,13 +406,6 @@ pika_font_deserialize_create (GType type,
font = PIKA_FONT (pika_container_get_child_by_index (fonts_container, i)); font = PIKA_FONT (pika_container_get_child_by_index (fonts_container, i));
if (fonthash != NULL && font->hash != NULL && !g_strcmp0 (font->hash, fonthash))
{
most_similar_font_index = i;
g_clear_pointer (&similar_fonts, g_list_free);
break;
}
/* Some attrs are more identifying than others, /* Some attrs are more identifying than others,
* hence their higher importance in measuring similarity. * hence their higher importance in measuring similarity.
*/ */

View File

@ -704,6 +704,7 @@ pika_font_factory_load_names (PikaContainer *container,
{ {
PangoFontDescription *pfd; PangoFontDescription *pfd;
GString *xml; GString *xml;
GString *xml_bold_variant;
gchar *fontformat; gchar *fontformat;
gchar *family = NULL; gchar *family = NULL;
gchar *style = NULL; gchar *style = NULL;
@ -796,26 +797,43 @@ pika_font_factory_load_names (PikaContainer *container,
xml = g_string_new ("<?xml version=\"1.0\"?>\n<match>"); xml = g_string_new ("<?xml version=\"1.0\"?>\n<match>");
/*We can't use faux bold (sometimes real bold) unless it is specified in fontconfig*/
xml_bold_variant = g_string_new ("<?xml version=\"1.0\"?>\n<match>");
g_string_append_printf (xml, g_string_append_printf (xml,
"<test name=\"family\"><string>%s</string></test>", "<test name=\"family\"><string>%s</string></test>",
newname); newname);
g_string_append_printf (xml_bold_variant,
"<test name=\"family\"><string>%s</string></test>",
newname);
g_string_append (xml_bold_variant,
"<test name=\"weight\" compare=\"eq\"><const>bold</const></test>");
escaped_fullname = g_markup_escape_text (fullname, -1); escaped_fullname = g_markup_escape_text (fullname, -1);
g_string_append_printf (xml, g_string_append_printf (xml,
"<edit name=\"fullname\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>", "<edit name=\"fullname\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
escaped_fullname); escaped_fullname);
g_string_append_printf (xml_bold_variant,
"<edit name=\"fullname\" mode=\"prepend\" binding=\"strong\"><string>%s</string></edit>",
escaped_fullname);
g_free (escaped_fullname); g_free (escaped_fullname);
family = g_markup_escape_text (family, -1); family = g_markup_escape_text (family, -1);
g_string_append_printf (xml, g_string_append_printf (xml,
"<edit name=\"family\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>", "<edit name=\"family\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
family); family);
g_string_append_printf (xml_bold_variant,
"<edit name=\"family\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
family);
g_free (family); g_free (family);
escaped_file = g_markup_escape_text (file, -1); escaped_file = g_markup_escape_text (file, -1);
g_string_append_printf (xml, g_string_append_printf (xml,
"<edit name=\"file\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>", "<edit name=\"file\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
escaped_file); escaped_file);
g_string_append_printf (xml_bold_variant,
"<edit name=\"file\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
escaped_file);
g_free (escaped_file); g_free (escaped_file);
if (psname != NULL) if (psname != NULL)
@ -824,6 +842,9 @@ pika_font_factory_load_names (PikaContainer *container,
g_string_append_printf (xml, g_string_append_printf (xml,
"<edit name=\"postscriptname\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>", "<edit name=\"postscriptname\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
psname); psname);
g_string_append_printf (xml_bold_variant,
"<edit name=\"postscriptname\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
psname);
g_free (psname); g_free (psname);
} }
@ -833,36 +854,64 @@ pika_font_factory_load_names (PikaContainer *container,
g_string_append_printf (xml, g_string_append_printf (xml,
"<edit name=\"style\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>", "<edit name=\"style\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
style); style);
g_string_append_printf (xml_bold_variant,
"<edit name=\"style\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
style);
g_free (style); g_free (style);
} }
g_string_append (xml_bold_variant, "<edit name=\"weight\" mode=\"assign\" binding=\"strong\"><const>bold</const></edit>");
if (weight != -1) if (weight != -1)
g_string_append_printf (xml, g_string_append_printf (xml,
"<edit name=\"weight\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>", "<edit name=\"weight\" mode=\"prepend\" binding=\"strong\"><int>%i</int></edit>",
weight); weight);
if (width != -1) if (width != -1)
g_string_append_printf (xml, {
"<edit name=\"width\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>", g_string_append_printf (xml,
width); "<edit name=\"width\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>",
width);
g_string_append_printf (xml_bold_variant,
"<edit name=\"width\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>",
width);
}
if (slant != -1) if (slant != -1)
g_string_append_printf (xml, {
"<edit name=\"slant\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>", g_string_append_printf (xml,
slant); "<edit name=\"slant\" mode=\"prepend\" binding=\"strong\"><int>%i</int></edit>",
slant);
g_string_append_printf (xml_bold_variant,
"<edit name=\"slant\" mode=\"prepend\" binding=\"strong\"><int>%i</int></edit>",
slant);
}
if (fontversion != -1) if (fontversion != -1)
g_string_append_printf (xml, {
"<edit name=\"fontversion\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>", g_string_append_printf (xml,
fontversion); "<edit name=\"fontversion\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>",
fontversion);
g_string_append_printf (xml_bold_variant,
"<edit name=\"fontversion\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>",
fontversion);
}
if (index != -1) if (index != -1)
g_string_append_printf (xml, {
"<edit name=\"index\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>", g_string_append_printf (xml,
index); "<edit name=\"index\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>",
index);
g_string_append_printf (xml_bold_variant,
"<edit name=\"index\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>",
index);
}
g_string_append (xml, "</match>\n"); g_string_append (xml, "</match>\n");
g_string_append (xml_bold_variant, "</match>\n");
FcConfigParseAndLoadFromMemory (FcConfigGetCurrent (), (const FcChar8 *) xml_bold_variant->str, FcTrue);
FcConfigParseAndLoadFromMemory (FcConfigGetCurrent (), (const FcChar8 *) xml->str, FcTrue); FcConfigParseAndLoadFromMemory (FcConfigGetCurrent (), (const FcChar8 *) xml->str, FcTrue);
pfd = pango_font_description_from_string (newname); pfd = pango_font_description_from_string (newname);
@ -877,6 +926,7 @@ pika_font_factory_load_names (PikaContainer *container,
pango_font_description_free (pfd); pango_font_description_free (pfd);
g_free (newname); g_free (newname);
g_string_free (xml, TRUE); g_string_free (xml, TRUE);
g_string_free (xml_bold_variant, TRUE);
} }
if (n_ignored > 0) if (n_ignored > 0)

View File

@ -42,6 +42,7 @@
#include "core/pikaimage-undo.h" #include "core/pikaimage-undo.h"
#include "core/pikalayer-floating-selection.h" #include "core/pikalayer-floating-selection.h"
#include "pikafont.h"
#include "pikatext.h" #include "pikatext.h"
#include "pikatext-compat.h" #include "pikatext-compat.h"
#include "pikatextlayer.h" #include "pikatextlayer.h"
@ -55,24 +56,22 @@ text_render (PikaImage *image,
PikaContext *context, PikaContext *context,
gint text_x, gint text_x,
gint text_y, gint text_y,
const gchar *fontname, PikaFont *font,
gdouble font_size,
const gchar *text, const gchar *text,
gint border, gint border,
gboolean antialias) gboolean antialias)
{ {
PangoFontDescription *desc; PikaText *gtext;
PikaText *gtext; PikaLayer *layer;
PikaLayer *layer; PikaRGB color;
PikaRGB color;
gchar *font;
gdouble size;
g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL); g_return_val_if_fail (PIKA_IS_IMAGE (image), NULL);
g_return_val_if_fail (drawable == NULL || PIKA_IS_DRAWABLE (drawable), NULL); g_return_val_if_fail (drawable == NULL || PIKA_IS_DRAWABLE (drawable), NULL);
g_return_val_if_fail (drawable == NULL || g_return_val_if_fail (drawable == NULL ||
pika_item_is_attached (PIKA_ITEM (drawable)), NULL); pika_item_is_attached (PIKA_ITEM (drawable)), NULL);
g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL); g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL);
g_return_val_if_fail (fontname != NULL, NULL); g_return_val_if_fail (PIKA_IS_FONT (font), NULL);
g_return_val_if_fail (text != NULL, NULL); g_return_val_if_fail (text != NULL, NULL);
if (! pika_data_factory_data_wait (image->pika->font_factory)) if (! pika_data_factory_data_wait (image->pika->font_factory))
@ -81,27 +80,17 @@ text_render (PikaImage *image,
if (border < 0) if (border < 0)
border = 0; border = 0;
desc = pango_font_description_from_string (fontname);
size = PANGO_PIXELS (pango_font_description_get_size (desc));
pango_font_description_unset_fields (desc, PANGO_FONT_MASK_SIZE);
font = pango_font_description_to_string (desc);
pango_font_description_free (desc);
pika_context_get_foreground (context, &color); pika_context_get_foreground (context, &color);
gtext = g_object_new (PIKA_TYPE_TEXT, gtext = g_object_new (PIKA_TYPE_TEXT,
"text", text, "text", text,
"font", font, "font", font,
"font-size", size, "font-size", font_size,
"antialias", antialias, "antialias", antialias,
"border", border, "border", border,
"color", &color, "color", &color,
NULL); NULL);
g_free (font);
layer = pika_text_layer_new (image, gtext); layer = pika_text_layer_new (image, gtext);
g_object_unref (gtext); g_object_unref (gtext);
@ -142,7 +131,8 @@ text_render (PikaImage *image,
gboolean gboolean
text_get_extents (Pika *pika, text_get_extents (Pika *pika,
const gchar *fontname, PikaFont *font,
gdouble font_size,
const gchar *text, const gchar *text,
gint *width, gint *width,
gint *height, gint *height,
@ -154,9 +144,10 @@ text_get_extents (Pika *pika,
PangoLayout *layout; PangoLayout *layout;
PangoFontMap *fontmap; PangoFontMap *fontmap;
PangoRectangle rect; PangoRectangle rect;
gchar *real_fontname;
g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE); g_return_val_if_fail (PIKA_IS_PIKA (pika), FALSE);
g_return_val_if_fail (fontname != NULL, FALSE); g_return_val_if_fail (PIKA_IS_FONT (font), FALSE);
g_return_val_if_fail (text != NULL, FALSE); g_return_val_if_fail (text != NULL, FALSE);
if (! pika_data_factory_data_wait (pika->font_factory)) if (! pika_data_factory_data_wait (pika->font_factory))
@ -175,9 +166,11 @@ text_get_extents (Pika *pika,
layout = pango_layout_new (context); layout = pango_layout_new (context);
g_object_unref (context); g_object_unref (context);
font_desc = pango_font_description_from_string (fontname); real_fontname = g_strdup_printf ("%s %d", pika_font_get_lookup_name (font), (gint) font_size);
font_desc = pango_font_description_from_string (real_fontname);
pango_layout_set_font_description (layout, font_desc); pango_layout_set_font_description (layout, font_desc);
pango_font_description_free (font_desc); pango_font_description_free (font_desc);
g_free (real_fontname);
pango_layout_set_text (layout, text, -1); pango_layout_set_text (layout, text, -1);
@ -202,7 +195,7 @@ text_get_extents (Pika *pika,
if (ascent) if (ascent)
*ascent = PANGO_ASCENT (rect); *ascent = PANGO_ASCENT (rect);
if (descent) if (descent)
*descent = - PANGO_DESCENT (rect); *descent = PANGO_DESCENT (rect);
} }
g_object_unref (layout); g_object_unref (layout);

View File

@ -33,12 +33,14 @@ PikaLayer * text_render (PikaImage *image,
PikaContext *context, PikaContext *context,
gint text_x, gint text_x,
gint text_y, gint text_y,
const gchar *fontname, PikaFont *font,
gdouble font_size,
const gchar *text, const gchar *text,
gint border, gint border,
gboolean antialias); gboolean antialias);
gboolean text_get_extents (Pika *pika, gboolean text_get_extents (Pika *pika,
const gchar *fontname, PikaFont *font,
gdouble font_size,
const gchar *text, const gchar *text,
gint *width, gint *width,
gint *height, gint *height,

View File

@ -121,7 +121,7 @@ static void pika_align_options_pivot_changed (PikaPivotSelector *sele
G_DEFINE_TYPE_WITH_PRIVATE (PikaAlignOptions, pika_align_options, PIKA_TYPE_TOOL_OPTIONS) G_DEFINE_TYPE_WITH_PRIVATE (PikaAlignOptions, pika_align_options, PIKA_TYPE_TOOL_OPTIONS)
#define parent_class pika_selection_options_parent_class #define parent_class pika_align_options_parent_class
static guint align_options_signals[LAST_SIGNAL] = { 0 }; static guint align_options_signals[LAST_SIGNAL] = { 0 };
@ -205,6 +205,8 @@ pika_align_options_finalize (GObject *object)
if (PIKA_CONTEXT (options)->pika) if (PIKA_CONTEXT (options)->pika)
pika_align_options_image_changed (pika_get_user_context (PIKA_CONTEXT (options)->pika), pika_align_options_image_changed (pika_get_user_context (PIKA_CONTEXT (options)->pika),
NULL, options); NULL, options);
G_OBJECT_CLASS (parent_class)->finalize (object);
} }
static void static void
@ -544,10 +546,10 @@ pika_align_options_gui (PikaToolOptions *tool_options)
pika_align_options_button_new (options, PIKA_DISTRIBUTE_EVEN_VERTICAL_GAP, hbox, pika_align_options_button_new (options, PIKA_DISTRIBUTE_EVEN_VERTICAL_GAP, hbox,
_("Distribute vertically with even vertical gaps")); _("Distribute vertically with even vertical gaps"));
g_signal_connect (pika_get_user_context (PIKA_CONTEXT (options)->pika), g_signal_connect_object (pika_get_user_context (PIKA_CONTEXT (options)->pika),
"image-changed", "image-changed",
G_CALLBACK (pika_align_options_image_changed), G_CALLBACK (pika_align_options_image_changed),
tool_options); tool_options, 0);
pika_align_options_image_changed (pika_get_user_context (PIKA_CONTEXT (options)->pika), pika_align_options_image_changed (pika_get_user_context (PIKA_CONTEXT (options)->pika),
pika_context_get_image (pika_get_user_context (PIKA_CONTEXT (options)->pika)), pika_context_get_image (pika_get_user_context (PIKA_CONTEXT (options)->pika)),
options); options);

View File

@ -188,6 +188,11 @@ tool_manager_exit (Pika *pika)
tool_manager_image_changed, tool_manager_image_changed,
tool_manager); tool_manager);
if (tool_manager->image)
g_signal_handlers_disconnect_by_func (tool_manager->image,
tool_manager_selected_layers_changed,
tool_manager);
pika_container_remove_handler (pika->images, pika_container_remove_handler (pika->images,
tool_manager->image_clean_handler_id); tool_manager->image_clean_handler_id);
pika_container_remove_handler (pika->images, pika_container_remove_handler (pika->images,

View File

@ -161,7 +161,9 @@ libappwidgets_sources = [
'pikapatternselect.c', 'pikapatternselect.c',
'pikapdbdialog.c', 'pikapdbdialog.c',
'pikapickablebutton.c', 'pikapickablebutton.c',
'pikapickablechooser.c',
'pikapickablepopup.c', 'pikapickablepopup.c',
'pikapickableselect.c',
'pikapivotselector.c', 'pikapivotselector.c',
'pikapixbuf.c', 'pikapixbuf.c',
'pikapluginview.c', 'pikapluginview.c',

View File

@ -366,6 +366,8 @@ pika_action_history_action_activated (PikaAction *action)
GList *link; GList *link;
PikaActionHistoryItem *item; PikaActionHistoryItem *item;
g_return_if_fail (PIKA_IS_ACTION (action));
/* Silently return when called at the wrong time, like when the /* Silently return when called at the wrong time, like when the
* activated action was "quit" and the history is already gone. * activated action was "quit" and the history is already gone.
*/ */

View File

@ -693,6 +693,39 @@ pika_action_use_default_accels (PikaAction *action)
return TRUE; return TRUE;
} }
gboolean
pika_action_is_default_accel (PikaAction *action,
const gchar *accel)
{
gchar **default_accels;
guint accelerator_key = 0;
GdkModifierType accelerator_mods = 0;
g_return_val_if_fail (PIKA_IS_ACTION (action), TRUE);
g_return_val_if_fail (accel != NULL, TRUE);
gtk_accelerator_parse (accel, &accelerator_key, &accelerator_mods);
g_return_val_if_fail (accelerator_key != 0 || accelerator_mods == 0, FALSE);
default_accels = GET_PRIVATE (action)->default_accels;
if (default_accels == NULL)
return FALSE;
for (gint i = 0; default_accels[i] != NULL; i++)
{
guint default_key;
GdkModifierType default_mods;
gtk_accelerator_parse (default_accels[i], &default_key, &default_mods);
if (default_key == accelerator_key && default_mods == accelerator_mods)
return TRUE;
}
return FALSE;
}
const gchar * const gchar *
pika_action_get_menu_path (PikaAction *action) pika_action_get_menu_path (PikaAction *action)
{ {

View File

@ -119,6 +119,8 @@ const gchar ** pika_action_get_default_accels (PikaAction *action);
const gchar ** pika_action_get_accels (PikaAction *action); const gchar ** pika_action_get_accels (PikaAction *action);
gchar ** pika_action_get_display_accels (PikaAction *action); gchar ** pika_action_get_display_accels (PikaAction *action);
gboolean pika_action_use_default_accels (PikaAction *action); gboolean pika_action_use_default_accels (PikaAction *action);
gboolean pika_action_is_default_accel (PikaAction *action,
const gchar *accel);
const gchar * pika_action_get_menu_path (PikaAction *action); const gchar * pika_action_get_menu_path (PikaAction *action);

View File

@ -394,7 +394,87 @@ pika_action_group_add_action_with_accel (PikaActionGroup *group,
if ((accelerators != NULL && accelerators[0] != NULL && if ((accelerators != NULL && accelerators[0] != NULL &&
g_strcmp0 (accelerators[0], "") != 0)) g_strcmp0 (accelerators[0], "") != 0))
pika_action_set_default_accels (action, (const gchar **) accelerators); {
guint i = 0;
GdkDisplay *display;
GdkKeymap *keymap;
gchar *accel_strs[] = { NULL, NULL, NULL, NULL};
display = gdk_display_get_default ();
keymap = gdk_keymap_get_for_display (display);
while (accelerators[i] != NULL)
{
/**
* Shifted numeric key accelerators ("<shift>0" .. "<shift>9") do
* not work with GTK3 so the following code converts these
* accelerators to the shifted character (or the un-shifted
* character in the case of an azerty keyboard for example) that
* relates to the selected numeric character. This takes into
* account the keyboard layout that is being used when PIKA starts.
* This means that the appropriate characters will be shown for the
* shortcuts in the menus and keyboard preferences.
**/
guint accelerator_key;
GdkModifierType accelerator_modifier;
gboolean accelerator_string_set;
accelerator_string_set = FALSE;
gtk_accelerator_parse (accelerators[i],
&accelerator_key,
&accelerator_modifier);
if ((accelerator_key >= '0') &&
(accelerator_key <= '9') &&
(accelerator_modifier == GDK_SHIFT_MASK))
{
gboolean result;
gint count;
GdkKeymapKey key;
GdkKeymapKey *keys = NULL;
guint non_number_keyval;
result = gdk_keymap_get_entries_for_keyval (keymap,
accelerator_key,
&keys,
&count);
if (result && (count > 0))
{
key.keycode = keys[0].keycode;
key.group = 0;
key.level = 1;
non_number_keyval = gdk_keymap_lookup_key (keymap, &key);
if (non_number_keyval == accelerator_key)
{
/**
* the number shifted is the number - assume keyboard
* such as azerty where the numbers are on the shifted
* key and the other characters are obtained without
* the shift
**/
key.level = 0;
non_number_keyval = gdk_keymap_lookup_key (keymap, &key);
}
accel_strs[i] = g_strdup (gdk_keyval_name (non_number_keyval));
accelerator_string_set = TRUE;
}
g_free (keys);
}
if (! accelerator_string_set)
accel_strs[i] = g_strdup (accelerators[i]);
i++;
}
pika_action_set_default_accels (action, (const gchar **) accel_strs);
/* free up to 3 accelerator strings (4th entry is always NULL) */
for (guint i = 0; i < 3; i++)
g_free (accel_strs[i]);
}
pika_action_set_group (action, group); pika_action_set_group (action, group);
} }

View File

@ -282,7 +282,7 @@ pika_brush_select_run_callback (PikaPdbDialog *dialog,
dialog->caller_context, dialog->caller_context,
NULL, error, NULL, error,
dialog->callback_name, dialog->callback_name,
G_TYPE_STRING, pika_object_get_name (object), PIKA_TYPE_RESOURCE, object,
G_TYPE_DOUBLE, pika_context_get_opacity (dialog->context) * 100.0, G_TYPE_DOUBLE, pika_context_get_opacity (dialog->context) * 100.0,
G_TYPE_INT, PIKA_BRUSH_SELECT (dialog)->spacing, G_TYPE_INT, PIKA_BRUSH_SELECT (dialog)->spacing,
PIKA_TYPE_LAYER_MODE, pika_context_get_paint_mode (dialog->context), PIKA_TYPE_LAYER_MODE, pika_context_get_paint_mode (dialog->context),

View File

@ -538,7 +538,7 @@ pika_color_history_color_changed (GtkWidget *widget,
pika_color_area_get_color (PIKA_COLOR_AREA (widget), &color); pika_color_area_get_color (PIKA_COLOR_AREA (widget), &color);
pika_palette_set_entry_color (palette, GPOINTER_TO_INT (data), &color); pika_palette_set_entry_color (palette, GPOINTER_TO_INT (data), &color, FALSE);
} }
static void static void

View File

@ -47,29 +47,33 @@
#include "pika-intl.h" #include "pika-intl.h"
static void pika_colormap_editor_docked_iface_init (PikaDockedInterface *face); static void pika_colormap_editor_docked_iface_init (PikaDockedInterface *face);
static void pika_colormap_editor_constructed (GObject *object); static void pika_colormap_editor_constructed (GObject *object);
static void pika_colormap_editor_dispose (GObject *object); static void pika_colormap_editor_dispose (GObject *object);
static void pika_colormap_editor_unmap (GtkWidget *widget); static void pika_colormap_editor_unmap (GtkWidget *widget);
static void pika_colormap_editor_set_context (PikaDocked *docked, static void pika_colormap_editor_set_context (PikaDocked *docked,
PikaContext *context); PikaContext *context);
static void pika_colormap_editor_color_update (PikaColorDialog *dialog, static void pika_colormap_editor_color_update (PikaColorDialog *dialog,
const PikaRGB *color, const PikaRGB *color,
PikaColorDialogState state, PikaColorDialogState state,
PikaColormapEditor *editor); PikaColormapEditor *editor);
static gboolean pika_colormap_editor_entry_button_press (GtkWidget *widget,
GdkEvent *event,
gpointer user_data);
static gboolean pika_colormap_editor_entry_popup (GtkWidget *widget,
gpointer user_data);
static void pika_colormap_editor_color_clicked (PikaColormapEditor *editor,
PikaPaletteEntry *entry,
GdkModifierType state);
static void pika_colormap_editor_notify_index (PikaColormapSelection *selection,
const GParamSpec *pspec,
PikaColormapEditor *editor);
static gboolean pika_colormap_editor_entry_button_press (GtkWidget *widget,
GdkEvent *event,
gpointer user_data);
static gboolean pika_colormap_editor_entry_popup (GtkWidget *widget,
gpointer user_data);
static void pika_colormap_editor_color_clicked (PikaColormapEditor *editor,
PikaPaletteEntry *entry,
GdkModifierType state);
G_DEFINE_TYPE_WITH_CODE (PikaColormapEditor, pika_colormap_editor, G_DEFINE_TYPE_WITH_CODE (PikaColormapEditor, pika_colormap_editor,
PIKA_TYPE_IMAGE_EDITOR, PIKA_TYPE_IMAGE_EDITOR,
@ -127,6 +131,9 @@ pika_colormap_editor_constructed (GObject *object)
pika_editor_add_action_button (PIKA_EDITOR (editor), "colormap", pika_editor_add_action_button (PIKA_EDITOR (editor), "colormap",
"colormap-edit-color", "colormap-edit-color",
NULL); NULL);
pika_editor_add_action_button (PIKA_EDITOR (editor), "colormap",
"colormap-delete-color",
NULL);
pika_editor_add_action_button (PIKA_EDITOR (editor), "colormap", pika_editor_add_action_button (PIKA_EDITOR (editor), "colormap",
"colormap-add-color-from-fg", "colormap-add-color-from-fg",
@ -197,6 +204,9 @@ pika_colormap_editor_set_context (PikaDocked *docked,
g_signal_connect (editor->selection, "popup-menu", g_signal_connect (editor->selection, "popup-menu",
G_CALLBACK (pika_colormap_editor_entry_popup), G_CALLBACK (pika_colormap_editor_entry_popup),
editor); editor);
g_signal_connect (editor->selection, "notify::index",
G_CALLBACK (pika_colormap_editor_notify_index),
editor);
} }
} }
@ -281,6 +291,43 @@ pika_colormap_editor_edit_color (PikaColormapEditor *editor)
gtk_window_present (GTK_WINDOW (editor->color_dialog)); gtk_window_present (GTK_WINDOW (editor->color_dialog));
} }
void
pika_colormap_editor_delete_color (PikaColormapEditor *editor)
{
PikaColormapSelection *selection;
PikaImage *image;
gint index;
g_return_if_fail (PIKA_IS_COLORMAP_EDITOR (editor));
g_return_if_fail (pika_colormap_editor_is_color_deletable (editor));
image = PIKA_IMAGE_EDITOR (editor)->image;
selection = PIKA_COLORMAP_SELECTION (editor->selection);
index = pika_colormap_selection_get_index (selection, NULL);
pika_image_delete_colormap_entry (image, index, TRUE);
}
gboolean
pika_colormap_editor_is_color_deletable (PikaColormapEditor *editor)
{
PikaColormapSelection *selection;
PikaImage *image;
gint index;
g_return_val_if_fail (PIKA_IS_COLORMAP_EDITOR (editor), FALSE);
image = PIKA_IMAGE_EDITOR (editor)->image;
selection = PIKA_COLORMAP_SELECTION (editor->selection);
index = pika_colormap_selection_get_index (selection, NULL);
if (index == -1)
/* No colormap. */
return FALSE;
else
return ! pika_image_colormap_is_index_used (image, index);
}
gint gint
pika_colormap_editor_get_index (PikaColormapEditor *editor, pika_colormap_editor_get_index (PikaColormapEditor *editor,
const PikaRGB *search) const PikaRGB *search)
@ -411,3 +458,16 @@ pika_colormap_editor_color_clicked (PikaColormapEditor *editor,
else else
pika_context_set_foreground (image_editor->context, &entry->color); pika_context_set_foreground (image_editor->context, &entry->color);
} }
static void
pika_colormap_editor_notify_index (PikaColormapSelection *selection,
const GParamSpec *pspec,
PikaColormapEditor *editor)
{
g_return_if_fail (PIKA_IS_COLORMAP_EDITOR (editor));
pika_editor_set_action_sensitive (PIKA_EDITOR (editor), "colormap",
"colormap-delete-color",
pika_colormap_editor_is_color_deletable (editor),
_("The color is used in this indexed image"));
}

View File

@ -50,19 +50,21 @@ struct _PikaColormapEditorClass
}; };
GType pika_colormap_editor_get_type (void) G_GNUC_CONST; GType pika_colormap_editor_get_type (void) G_GNUC_CONST;
GtkWidget * pika_colormap_editor_new (PikaMenuFactory *menu_factory); GtkWidget * pika_colormap_editor_new (PikaMenuFactory *menu_factory);
void pika_colormap_editor_edit_color (PikaColormapEditor *editor); void pika_colormap_editor_edit_color (PikaColormapEditor *editor);
void pika_colormap_editor_delete_color (PikaColormapEditor *editor);
gboolean pika_colormap_editor_is_color_deletable (PikaColormapEditor *editor);
gint pika_colormap_editor_get_index (PikaColormapEditor *editor, gint pika_colormap_editor_get_index (PikaColormapEditor *editor,
const PikaRGB *search); const PikaRGB *search);
gboolean pika_colormap_editor_set_index (PikaColormapEditor *editor, gboolean pika_colormap_editor_set_index (PikaColormapEditor *editor,
gint index, gint index,
PikaRGB *color); PikaRGB *color);
gint pika_colormap_editor_max_index (PikaColormapEditor *editor); gint pika_colormap_editor_max_index (PikaColormapEditor *editor);
#endif /* __PIKA_COLORMAP_EDITOR_H__ */ #endif /* __PIKA_COLORMAP_EDITOR_H__ */

View File

@ -57,7 +57,8 @@
enum enum
{ {
PROP_0, PROP_0,
PROP_CONTEXT PROP_CONTEXT,
PROP_INDEX
}; };
enum enum
@ -169,6 +170,10 @@ pika_colormap_selection_class_init (PikaColormapSelectionClass* klass)
PIKA_TYPE_CONTEXT, PIKA_TYPE_CONTEXT,
PIKA_PARAM_READWRITE | PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT)); G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_INDEX,
g_param_spec_int ("index", NULL, NULL,
0, G_MAXINT, 0,
PIKA_PARAM_READABLE));
} }
static void static void
@ -285,6 +290,9 @@ pika_colormap_selection_get_property (GObject *object,
case PROP_CONTEXT: case PROP_CONTEXT:
g_value_set_object (value, selection->context); g_value_set_object (value, selection->context);
break; break;
case PROP_INDEX:
g_value_set_int (value, selection->col_index);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@ -433,6 +441,7 @@ pika_colormap_selection_set_index (PikaColormapSelection *selection,
selection->col_index = index; selection->col_index = index;
g_object_notify (G_OBJECT (selection), "index");
pika_palette_view_select_entry (PIKA_PALETTE_VIEW (selection->view), pika_palette_view_select_entry (PIKA_PALETTE_VIEW (selection->view),
pika_palette_get_entry (palette, index)); pika_palette_get_entry (palette, index));
@ -789,6 +798,8 @@ pika_colormap_selection_set_palette (PikaColormapSelection *selection)
{ {
if (selection->active_palette) if (selection->active_palette)
{ {
pika_colormap_selection_set_index (selection, 0, NULL);
g_signal_handlers_disconnect_by_func (selection->active_palette, g_signal_handlers_disconnect_by_func (selection->active_palette,
G_CALLBACK (gtk_widget_queue_draw), G_CALLBACK (gtk_widget_queue_draw),
selection); selection);

View File

@ -899,6 +899,7 @@ pika_container_tree_view_select_items (PikaContainerView *view,
GList *path; GList *path;
gboolean free_paths = FALSE; gboolean free_paths = FALSE;
gboolean scroll_to_first = TRUE; gboolean scroll_to_first = TRUE;
GtkTreePath *focused_path = NULL;
/* If @paths is not set, compute it ourselves. */ /* If @paths is not set, compute it ourselves. */
if (g_list_length (items) != g_list_length (paths)) if (g_list_length (items) != g_list_length (paths))
@ -926,6 +927,95 @@ pika_container_tree_view_select_items (PikaContainerView *view,
pika_container_tree_view_selection_changed, pika_container_tree_view_selection_changed,
tree_view); tree_view);
gtk_tree_selection_unselect_all (tree_view->priv->selection); gtk_tree_selection_unselect_all (tree_view->priv->selection);
gtk_tree_view_get_cursor (tree_view->view, &focused_path, NULL);
if (focused_path != NULL)
{
GtkTreePath *closer_up = NULL;
GtkTreePath *closer_down = NULL;
for (path = paths; path; path = path->next)
{
if (gtk_tree_path_compare (path->data, focused_path) == 0)
{
break;
}
else if (gtk_tree_path_compare (path->data, focused_path) == -1)
{
if (closer_up == NULL || gtk_tree_path_compare (path->data, closer_up) == 1)
closer_up = path->data;
}
else
{
if (closer_down == NULL || gtk_tree_path_compare (path->data, closer_down) == -1)
closer_down = path->data;
}
}
if (path == NULL)
{
/* The current cursor is not part of the selection. This may happen in
* particular with a ctrl-click interaction which would deselect the
* item the cursor is now on.
*/
g_clear_pointer (&focused_path, gtk_tree_path_free);
if (closer_up != NULL || closer_down != NULL)
{
GtkTreePath *first = NULL;
GtkTreePath *last = NULL;
if (gtk_tree_view_get_visible_range (tree_view->view, &first, &last))
{
if (closer_up != NULL &&
gtk_tree_path_compare (closer_up, first) >= 0 &&
gtk_tree_path_compare (closer_up, last) <= 0)
focused_path = gtk_tree_path_copy (closer_up);
else if (closer_down != NULL &&
gtk_tree_path_compare (closer_down, first) >= 0 &&
gtk_tree_path_compare (closer_down, last) <= 0)
focused_path = gtk_tree_path_copy (closer_down);
}
if (focused_path == NULL)
{
if (closer_up != NULL)
focused_path = gtk_tree_path_copy (closer_up);
else
focused_path = gtk_tree_path_copy (closer_down);
}
gtk_tree_path_free (first);
gtk_tree_path_free (last);
}
else if (paths != NULL)
{
focused_path = gtk_tree_path_copy (paths->data);
}
}
}
else if (paths != NULL)
{
focused_path = gtk_tree_path_copy (paths->data);
}
/* Setting a cursor will reset the selection, so we must do it first. We don't
* want to change the cursor (which is likely the last clicked item), yet we
* also want to make sure that the cursor cannot end up out of the selected
* items, leading to discrepancy between pointer and keyboard navigation. This
* is why we set the cursor with this priority:
* 1. unchanged if it stays within selection;
* 2. closer item above the current cursor, if visible;
* 3. closer item below the current cursor, if visible;
* 4. closer item above the current cursor (even though invisible, which will
* make the view scroll up);
* 5. closer item below the current cursor if there are no items above (view
* will scroll down);
* 6. top selected item if there was no current cursor;
* 7. nothing if no selected items.
*/
if (focused_path != NULL)
gtk_tree_view_set_cursor (tree_view->view, focused_path, NULL, FALSE);
gtk_tree_path_free (focused_path);
for (item = items, path = paths; item && path; item = item->next, path = path->next) for (item = items, path = paths; item && path; item = item->next, path = path->next)
{ {
GtkTreePath *parent_path; GtkTreePath *parent_path;
@ -1267,12 +1357,10 @@ pika_container_tree_view_button (GtkWidget *widget,
PikaContainerView *container_view = PIKA_CONTAINER_VIEW (tree_view); PikaContainerView *container_view = PIKA_CONTAINER_VIEW (tree_view);
GtkTreeViewColumn *column; GtkTreeViewColumn *column;
GtkTreePath *path; GtkTreePath *path;
gboolean handled = TRUE;
tree_view->priv->dnd_renderer = NULL; tree_view->priv->dnd_renderer = NULL;
if (bevent->type != GDK_BUTTON_RELEASE && ! gtk_widget_has_focus (widget))
gtk_widget_grab_focus (widget);
if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget), if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (widget),
bevent->x, bevent->y, bevent->x, bevent->y,
&path, &column, NULL, NULL)) &path, &column, NULL, NULL))
@ -1283,10 +1371,10 @@ pika_container_tree_view_button (GtkWidget *widget,
GtkCellRenderer *edit_cell = NULL; GtkCellRenderer *edit_cell = NULL;
GdkRectangle column_area; GdkRectangle column_area;
GtkTreeIter iter; GtkTreeIter iter;
gboolean handled = TRUE;
gboolean multisel_mode; gboolean multisel_mode;
GdkModifierType modifiers = (bevent->state & pika_get_all_modifiers_mask ()); GdkModifierType modifiers = (bevent->state & pika_get_all_modifiers_mask ());
handled = TRUE;
multisel_mode = (gtk_tree_selection_get_mode (tree_view->priv->selection) multisel_mode = (gtk_tree_selection_get_mode (tree_view->priv->selection)
== GTK_SELECTION_MULTIPLE); == GTK_SELECTION_MULTIPLE);
@ -1301,6 +1389,19 @@ pika_container_tree_view_button (GtkWidget *widget,
multisel_mode = FALSE; multisel_mode = FALSE;
} }
/* We need to grab focus after a button click, in order to make keyboard
* navigation possible. For multi-selection though, actual selection will
* happen in pika_container_tree_view_selection_changed() but the widget
* must already be focused or the handler won't run.
* Whereas for single selection, grab must happen after we changed the
* selection (which will happen in this function) otherwise we end up
* first scrolling to the current selection. So we have a separate
* gtk_widget_grab_focus() at the end of the function.
* See also commit 3e101922 and MR !1128.
*/
if (multisel_mode && bevent->type == GDK_BUTTON_PRESS && ! gtk_widget_has_focus (widget))
gtk_widget_grab_focus (widget);
gtk_tree_model_get_iter (tree_view->model, &iter, path); gtk_tree_model_get_iter (tree_view->model, &iter, path);
renderer = pika_container_tree_store_get_renderer (PIKA_CONTAINER_TREE_STORE (tree_view->model), &iter); renderer = pika_container_tree_store_get_renderer (PIKA_CONTAINER_TREE_STORE (tree_view->model), &iter);
@ -1607,7 +1708,7 @@ pika_container_tree_view_button (GtkWidget *widget,
gtk_tree_path_free (path); gtk_tree_path_free (path);
g_object_unref (renderer); g_object_unref (renderer);
return multisel_mode ? handled : (bevent->type == GDK_BUTTON_RELEASE ? FALSE : TRUE); handled = (multisel_mode ? handled : (bevent->type == GDK_BUTTON_RELEASE ? FALSE : TRUE));
} }
else else
{ {
@ -1616,8 +1717,13 @@ pika_container_tree_view_button (GtkWidget *widget,
pika_editor_popup_menu_at_pointer (PIKA_EDITOR (tree_view), (GdkEvent *) bevent); pika_editor_popup_menu_at_pointer (PIKA_EDITOR (tree_view), (GdkEvent *) bevent);
} }
return TRUE; handled = TRUE;
} }
if (handled && bevent->type == GDK_BUTTON_PRESS && ! gtk_widget_has_focus (widget))
gtk_widget_grab_focus (widget);
return handled;
} }
/* We want to zoom on each 1/4 scroll events to roughly match zooming /* We want to zoom on each 1/4 scroll events to roughly match zooming

View File

@ -1195,9 +1195,7 @@ pika_container_view_remove (PikaContainerView *view,
if (insert_data) if (insert_data)
{ {
PIKA_CONTAINER_VIEW_GET_IFACE (view)->remove_item (view, PIKA_CONTAINER_VIEW_GET_IFACE (view)->remove_item (view, viewable, insert_data);
viewable,
insert_data);
g_hash_table_remove (private->item_hash, viewable); g_hash_table_remove (private->item_hash, viewable);
} }

View File

@ -226,7 +226,7 @@ pika_data_factory_view_constructed (GObject *object)
G_OBJECT_CLASS (parent_class)->constructed (object); G_OBJECT_CLASS (parent_class)->constructed (object);
pika_container_editor_set_selection_mode (editor, GTK_SELECTION_MULTIPLE); pika_container_editor_set_selection_mode (editor, GTK_SELECTION_SINGLE);
if (PIKA_IS_CONTAINER_TREE_VIEW (editor->view)) if (PIKA_IS_CONTAINER_TREE_VIEW (editor->view))
{ {

View File

@ -778,6 +778,31 @@ pika_editor_add_action_button (PikaEditor *editor,
return button; return button;
} }
void
pika_editor_set_action_sensitive (PikaEditor *editor,
const gchar *group_name,
const gchar *action_name,
gboolean sensitive,
const gchar *reason)
{
PikaActionGroup *group;
PikaAction *action;
g_return_if_fail (PIKA_IS_EDITOR (editor));
g_return_if_fail (action_name != NULL);
g_return_if_fail (editor->priv->ui_manager != NULL);
group = pika_ui_manager_get_action_group (editor->priv->ui_manager,
group_name);
g_return_if_fail (group != NULL);
action = pika_action_group_get_action (group, action_name);
g_return_if_fail (action != NULL);
pika_action_set_sensitive (action, sensitive, reason);
}
void void
pika_editor_set_show_name (PikaEditor *editor, pika_editor_set_show_name (PikaEditor *editor,
gboolean show) gboolean show)

View File

@ -89,6 +89,11 @@ GtkWidget * pika_editor_add_action_button (PikaEditor *editor,
const gchar *group_name, const gchar *group_name,
const gchar *action_name, const gchar *action_name,
...) G_GNUC_NULL_TERMINATED; ...) G_GNUC_NULL_TERMINATED;
void pika_editor_set_action_sensitive (PikaEditor *editor,
const gchar *group_name,
const gchar *action_name,
gboolean sensitive,
const gchar *reason);
void pika_editor_set_show_name (PikaEditor *editor, void pika_editor_set_show_name (PikaEditor *editor,
gboolean show); gboolean show);

View File

@ -90,6 +90,8 @@ static gboolean pika_file_dialog_delete_event (GtkWidget *w
GdkEventAny *event); GdkEventAny *event);
static void pika_file_dialog_response (GtkDialog *dialog, static void pika_file_dialog_response (GtkDialog *dialog,
gint response_id); gint response_id);
static void pika_file_dialog_map (PikaFileDialog *dialog,
gpointer data);
static GFile * pika_file_dialog_real_get_default_folder (PikaFileDialog *dialog); static GFile * pika_file_dialog_real_get_default_folder (PikaFileDialog *dialog);
static void pika_file_dialog_real_save_state (PikaFileDialog *dialog, static void pika_file_dialog_real_save_state (PikaFileDialog *dialog,
const gchar *state_name); const gchar *state_name);
@ -108,7 +110,7 @@ static void pika_file_dialog_progress_set_value (PikaProgress *p
gdouble percentage); gdouble percentage);
static gdouble pika_file_dialog_progress_get_value (PikaProgress *progress); static gdouble pika_file_dialog_progress_get_value (PikaProgress *progress);
static void pika_file_dialog_progress_pulse (PikaProgress *progress); static void pika_file_dialog_progress_pulse (PikaProgress *progress);
static guint32 pika_file_dialog_progress_get_window_id (PikaProgress *progress); static GBytes * pika_file_dialog_progress_get_window_id (PikaProgress *progress);
static void pika_file_dialog_add_user_dir (PikaFileDialog *dialog, static void pika_file_dialog_add_user_dir (PikaFileDialog *dialog,
GUserDirectory directory); GUserDirectory directory);
@ -229,6 +231,11 @@ pika_file_dialog_class_init (PikaFileDialogClass *klass)
static void static void
pika_file_dialog_init (PikaFileDialog *dialog) pika_file_dialog_init (PikaFileDialog *dialog)
{ {
#ifdef G_OS_WIN32
g_signal_connect (dialog, "map",
G_CALLBACK (pika_file_dialog_map),
NULL);
#endif
} }
static void static void
@ -372,6 +379,8 @@ pika_file_dialog_constructed (GObject *object)
dialog->progress = pika_progress_box_new (); dialog->progress = pika_progress_box_new ();
gtk_box_pack_end (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), gtk_box_pack_end (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
dialog->progress, FALSE, FALSE, 0); dialog->progress, FALSE, FALSE, 0);
pika_widget_set_native_handle (GTK_WIDGET (dialog), &dialog->window_handle);
} }
static void static void
@ -422,6 +431,15 @@ pika_file_dialog_response (GtkDialog *dialog,
} }
} }
static void
pika_file_dialog_map (PikaFileDialog *dialog,
gpointer data)
{
#ifdef G_OS_WIN32
pika_window_set_title_bar_theme (dialog->pika, GTK_WIDGET (dialog), FALSE);
#endif
}
static GFile * static GFile *
pika_file_dialog_real_get_default_folder (PikaFileDialog *dialog) pika_file_dialog_real_get_default_folder (PikaFileDialog *dialog)
{ {
@ -579,12 +597,12 @@ pika_file_dialog_progress_pulse (PikaProgress *progress)
pika_progress_pulse (PIKA_PROGRESS (dialog->progress)); pika_progress_pulse (PIKA_PROGRESS (dialog->progress));
} }
static guint32 static GBytes *
pika_file_dialog_progress_get_window_id (PikaProgress *progress) pika_file_dialog_progress_get_window_id (PikaProgress *progress)
{ {
PikaFileDialog *dialog = PIKA_FILE_DIALOG (progress); PikaFileDialog *dialog = PIKA_FILE_DIALOG (progress);
return pika_window_get_native_id (GTK_WINDOW (dialog)); return dialog->window_handle;
} }

View File

@ -42,6 +42,8 @@ struct _PikaFileDialog
{ {
GtkFileChooserDialog parent_instance; GtkFileChooserDialog parent_instance;
GBytes *window_handle;
Pika *pika; Pika *pika;
PikaImage *image; PikaImage *image;

Some files were not shown because too many files have changed in this diff Show More