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_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_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_CPPCHECK: trigger cppcheck static analysis.
# - PIKA_CI_FLATPAK: trigger the nightly flatpak build and publishing.
@ -375,7 +376,7 @@ pika-meson-raster-icons:
- ninja -C _build
- ninja -C _build test
## WINDOWS 64-bit CI (native MSYS2) ##
## WINDOWS x86_64 CI (native MSYS2) ##
deps-win64-native:
rules:
@ -462,7 +463,7 @@ packaging-win64-native:
- done-dll.list
needs: ["pika-win64-native"]
## WINDOWS 32-bit CI (native MSYS2) ##
## WINDOWS x86 CI (native MSYS2) ##
deps-win32-native:
rules:
@ -548,6 +549,96 @@ packaging-win32-native:
- done-dll.list
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) ##
deps-win64:
@ -822,6 +913,7 @@ win-installer-nightly:
dependencies:
- packaging-win64-native
- packaging-win32-native
- packaging-win-aarch64-native
# This is needed for the BMP image generation for the installer.
# See commit e1203e9f76f.
- pika-meson-debian
@ -835,7 +927,7 @@ win-installer-nightly:
script:
- 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"
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:
rules:

View File

@ -34,6 +34,7 @@
#include "core/pikaimage-colormap.h"
#include "widgets/pikaactiongroup.h"
#include "widgets/pikacolormapeditor.h"
#include "widgets/pikahelp-ids.h"
#include "actions.h"
@ -49,6 +50,12 @@ static const PikaActionEntry colormap_actions[] =
NC_("colormap-action", "_Edit Color..."), NULL, { NULL },
NC_("colormap-action", "Edit this color"),
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 }
};
@ -116,6 +123,7 @@ void
colormap_actions_update (PikaActionGroup *group,
gpointer data)
{
PikaColormapEditor *editor = PIKA_COLORMAP_EDITOR (data);
PikaImage *image = action_data_get_image (data);
PikaContext *context = action_data_get_context (data);
gboolean indexed = FALSE;
@ -154,6 +162,9 @@ colormap_actions_update (PikaActionGroup *group,
SET_SENSITIVE ("colormap-edit-color",
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",
indexed && num_colors < 256);

View File

@ -50,6 +50,16 @@ colormap_edit_color_cmd_callback (PikaAction *action,
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
colormap_add_color_cmd_callback (PikaAction *action,
GVariant *value,

View File

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

View File

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

View File

@ -50,7 +50,7 @@ _("Timestamp of the last update check.")
"Defines the color management behavior."
#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 \
_("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_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_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_SAMPLE_POINT, "PIKA_UNDO_GROUP_SAMPLE_POINT", "group-sample-point" },
{ 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_QUICK_MASK, NC_("undo-type", "Quick Mask"), 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_SAMPLE_POINT, NC_("undo-type", "Sample Point"), 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_QUICK_MASK, /*< desc="Quick Mask" >*/
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_SAMPLE_POINT, /*< desc="Sample Point" >*/
PIKA_UNDO_GROUP_DRAWABLE, /*< desc="Layer/Channel" >*/

View File

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

View File

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

View File

@ -202,6 +202,7 @@ pika_container_class_init (PikaContainerClass *klass)
klass->search = NULL;
klass->get_unique_names = NULL;
klass->get_child_by_name = NULL;
klass->get_children_by_name = NULL;
klass->get_child_by_index = NULL;
klass->get_child_index = NULL;
@ -885,6 +886,34 @@ pika_container_get_unique_names (PikaContainer *container)
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 *
pika_container_get_child_by_name (PikaContainer *container,
const gchar *name)

View File

@ -79,6 +79,8 @@ struct _PikaContainerClass
gboolean (* get_unique_names) (PikaContainer *container);
PikaObject * (* get_child_by_name) (PikaContainer *container,
const gchar *name);
GList * (* get_children_by_name) (PikaContainer *container,
const gchar *name);
PikaObject * (* get_child_by_index) (PikaContainer *container,
gint index);
gint (* get_child_index) (PikaContainer *container,
@ -121,6 +123,8 @@ PikaObject * pika_container_search (PikaContainer *contain
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,
const gchar *name);
PikaObject * pika_container_get_child_by_index (PikaContainer *container,

View File

@ -34,6 +34,7 @@
#include "pika-memsize.h"
#include "pikadata.h"
#include "pikaidtable.h"
#include "pikaimage.h"
#include "pikatag.h"
#include "pikatagged.h"
@ -51,6 +52,7 @@ enum
PROP_0,
PROP_ID,
PROP_FILE,
PROP_IMAGE,
PROP_WRITABLE,
PROP_DELETABLE,
PROP_MIME_TYPE
@ -61,6 +63,8 @@ struct _PikaDataPrivate
{
gint ID;
GFile *file;
PikaImage *image;
GQuark mime_type;
guint writable : 1;
guint deletable : 1;
@ -172,6 +176,11 @@ pika_data_class_init (PikaDataClass *klass)
G_TYPE_FILE,
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_param_spec_boolean ("writable", NULL, NULL,
FALSE,
@ -268,6 +277,12 @@ pika_data_set_property (GObject *object,
private->deletable);
break;
case PROP_IMAGE:
pika_data_set_image (data,
g_value_get_object (value),
private->writable,
private->deletable);
break;
case PROP_WRITABLE:
private->writable = g_value_get_boolean (value);
break;
@ -307,6 +322,10 @@ pika_data_get_property (GObject *object,
g_value_set_object (value, private->file);
break;
case PROP_IMAGE:
g_value_set_object (value, private->image);
break;
case PROP_WRITABLE:
g_value_set_boolean (value, private->writable);
break;
@ -462,7 +481,7 @@ pika_data_get_identifier (PikaTagged *tagged)
gchar *identifier = 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);
/* 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);
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)
{
@ -551,6 +570,10 @@ pika_data_get_collection (PikaData *data)
g_free (path);
}
else if (private->image)
{
collection = g_strdup_printf ("[image-id-%d]", pika_image_get_id (private->image));
}
else if (private->internal)
{
collection = g_strdup (private->collection);
@ -603,7 +626,7 @@ pika_data_save (PikaData *data,
g_return_val_if_fail (private->writable == TRUE, FALSE);
if (private->internal)
if (private->internal || private->image != NULL)
{
private->dirty = FALSE;
return TRUE;
@ -862,6 +885,8 @@ pika_data_set_file (PikaData *data,
if (private->internal)
return;
g_return_if_fail (private->image == NULL);
g_set_object (&private->file, file);
private->writable = FALSE;
@ -937,6 +962,53 @@ pika_data_get_file (PikaData *data)
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:
* @data: a #Pikadata object.

View File

@ -102,6 +102,11 @@ void pika_data_set_file (PikaData *data,
gboolean writable,
gboolean deletable);
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,
GFile *dest_dir);

View File

@ -403,6 +403,9 @@ pika_data_factory_real_data_save (PikaDataFactory *factory)
PikaData *data = list->data;
GError *error = NULL;
if (pika_data_get_image (data))
continue;
if (! pika_data_get_file (data))
pika_data_create_filename (data, writable_dir);
@ -460,6 +463,7 @@ pika_data_factory_real_data_duplicate (PikaDataFactory *factory,
gint copy_len;
gint number;
gchar *new_name;
GError *error = NULL;
ext = strrchr (name, '#');
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);
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));
g_object_unref (new_data);
g_clear_error (&error);
}
return new_data;
@ -674,8 +682,14 @@ pika_data_factory_data_new (PikaDataFactory *factory,
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));
g_object_unref (data);
g_clear_error (&error);
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 (error == NULL || *error == NULL, FALSE);
if (! pika_data_is_dirty (data))
if (! pika_data_is_dirty (data) || pika_data_get_image (data))
return TRUE;
if (! pika_data_get_file (data))

View File

@ -31,25 +31,43 @@
#include "core-types.h"
#include "config/pikageglconfig.h"
#include "gegl/pika-babl.h"
#include "gegl/pika-gegl-loops.h"
#include "pika.h"
#include "pikacontainer.h"
#include "pikadatafactory.h"
#include "pikadrawable.h"
#include "pikaimage.h"
#include "pikaimage-colormap.h"
#include "pikaimage-private.h"
#include "pikaimage-undo.h"
#include "pikaimage-undo-push.h"
#include "pikapalette.h"
#include "pika-intl.h"
typedef struct
{
GeglBuffer *buffer;
const Babl *format;
/* Shared by jobs. */
gboolean *found;
GRWLock *lock;
} IndexUsedJobData;
/* local function prototype */
static void pika_image_colormap_set_palette_entry (PikaImage *image,
const PikaRGB *color,
gint index);
static void pika_image_colormap_thread_is_index_used (IndexUsedJobData *data,
gint index);
/* public functions */
@ -80,7 +98,7 @@ pika_image_colormap_init (PikaImage *image)
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);
@ -319,9 +337,8 @@ pika_image_set_colormap (PikaImage *image,
pika_image_colormap_set_palette_entry (image, &color, i);
}
pika_data_thaw (PIKA_DATA (private->palette));
pika_image_colormap_changed (image, -1);
pika_data_thaw (PIKA_DATA (private->palette));
}
void
@ -347,6 +364,45 @@ pika_image_unset_colormap (PikaImage *image,
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
pika_image_get_colormap_entry (PikaImage *image,
gint color_index,
@ -420,6 +476,57 @@ pika_image_add_colormap_entry (PikaImage *image,
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 */
@ -442,3 +549,22 @@ pika_image_colormap_set_palette_entry (PikaImage *image,
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,
gboolean push_undo);
gboolean pika_image_colormap_is_index_used (PikaImage *image,
gint color_index);
void pika_image_get_colormap_entry (PikaImage *image,
gint color_index,
PikaRGB *color);
@ -59,6 +62,9 @@ void pika_image_set_colormap_entry (PikaImage *image,
void pika_image_add_colormap_entry (PikaImage *image,
const PikaRGB *color);
gboolean pika_image_delete_colormap_entry (PikaImage *image,
gint color_index,
gboolean push_undo);
#endif /* __PIKA_IMAGE_COLORMAP_H__ */

View File

@ -24,17 +24,22 @@
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include <gexiv2/gexiv2.h>
#include "libpikabase/pikabase.h"
#include "libpikacolor/pikacolor.h"
#include "core-types.h"
#include "pika.h"
#include "pikaimage.h"
#include "pikaimage-color-profile.h"
#include "pikaimage-metadata.h"
#include "pikaimage-private.h"
#include "pikaimage-rotate.h"
#include "pikaimage-undo.h"
#include "pikaimage-undo-push.h"
#include "pikalayer-new.h"
/* public functions */
@ -186,3 +191,110 @@ pika_image_metadata_update_colorspace (PikaImage *image)
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_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__ */

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 */

View File

@ -33,4 +33,10 @@ void pika_image_import_rotation_metadata (PikaImage *image,
PikaProgress *progress,
gboolean interactive);
void pika_image_apply_metadata_orientation (PikaImage *image,
PikaContext *context,
PikaMetadata *metadata,
PikaProgress *progress);
#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:
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:
return PIKA_DIRTY_IMAGE_STRUCTURE | PIKA_DIRTY_DRAWABLE;

View File

@ -45,6 +45,7 @@
#include "pikacontainer.h"
#include "pikacontext.h"
#include "pikaimage.h"
#include "pikaimage-metadata.h"
#include "pikaimagefile.h"
#include "pikapickable.h"
#include "pikaprogress.h"
@ -486,6 +487,23 @@ pika_imagefile_create_thumbnail (PikaImagefile *imagefile,
if (error && *error)
{
g_printerr ("Info: Thumbnail load procedure failed: %s\n"
" Falling back to metadata or file load.\n",
(*error)->message);
g_clear_error (error);
}
image = pika_image_metadata_load_thumbnail (private->pika, private->file, &width, &height, &format, error);
if (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);
@ -500,6 +518,7 @@ pika_imagefile_create_thumbnail (PikaImagefile *imagefile,
pika_thumbnail_set_info_from_image (private->thumbnail,
mime_type, image);
}
}
if (image)
{

View File

@ -76,6 +76,8 @@ static PikaObject * pika_list_search (PikaContainer *conta
PikaContainerSearchFunc func,
gpointer user_data);
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,
const gchar *name);
static PikaObject * pika_list_get_child_by_index (PikaContainer *container,
@ -115,6 +117,7 @@ pika_list_class_init (PikaListClass *klass)
container_class->foreach = pika_list_foreach;
container_class->search = pika_list_search;
container_class->get_unique_names = pika_list_get_unique_names;
container_class->get_children_by_name = pika_list_get_children_by_name;
container_class->get_child_by_name = pika_list_get_child_by_name;
container_class->get_child_by_index = pika_list_get_child_by_index;
container_class->get_child_index = pika_list_get_child_index;
@ -369,6 +372,29 @@ pika_list_get_unique_names (PikaContainer *container)
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 *
pika_list_get_child_by_name (PikaContainer *container,
const gchar *name)

View File

@ -33,6 +33,8 @@
#include "core-types.h"
#include "pika-memsize.h"
#include "pikaimage.h"
#include "pikaimage-undo-push.h"
#include "pikapalette.h"
#include "pikapalette-load.h"
#include "pikapalette-save.h"
@ -44,6 +46,12 @@
#define RGB_EPSILON 1e-6
enum
{
ENTRY_CHANGED,
LAST_SIGNAL
};
/* 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 void pika_palette_copy (PikaData *data,
PikaData *src_data);
static void pika_palette_real_entry_changed (PikaPalette *palette,
gint index);
static void pika_palette_entry_free (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
static guint signals[LAST_SIGNAL] = { 0 };
static void
pika_palette_class_init (PikaPaletteClass *klass)
@ -97,6 +108,14 @@ pika_palette_class_init (PikaPaletteClass *klass)
PikaViewableClass *viewable_class = PIKA_VIEWABLE_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;
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->get_extension = pika_palette_get_extension;
data_class->copy = pika_palette_copy;
klass->entry_changed = pika_palette_real_entry_changed;
}
static void
@ -344,6 +365,16 @@ pika_palette_copy (PikaData *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 *
pika_palette_get_checksum (PikaTagged *tagged)
{
@ -406,11 +437,17 @@ pika_palette_move_entry (PikaPalette *palette,
if (g_list_find (palette->colors, entry))
{
gint old_position = g_list_index (palette->colors, entry);
palette->colors = g_list_remove (palette->colors,
entry);
palette->colors = g_list_insert (palette->colors,
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));
}
}
@ -442,6 +479,10 @@ pika_palette_add_entry (PikaPalette *palette,
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));
return entry;
@ -456,12 +497,18 @@ pika_palette_delete_entry (PikaPalette *palette,
if (g_list_find (palette->colors, entry))
{
gint old_position = g_list_index (palette->colors, entry);
pika_palette_entry_free (entry);
palette->colors = g_list_remove (palette->colors, entry);
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));
}
}
@ -489,6 +536,9 @@ pika_palette_set_entry (PikaPalette *palette,
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));
return TRUE;
@ -497,7 +547,8 @@ pika_palette_set_entry (PikaPalette *palette,
gboolean
pika_palette_set_entry_color (PikaPalette *palette,
gint position,
const PikaRGB *color)
const PikaRGB *color,
gboolean push_undo_if_image)
{
PikaPaletteEntry *entry;
@ -509,8 +560,15 @@ pika_palette_set_entry_color (PikaPalette *palette,
if (! entry)
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;
if (! pika_data_is_frozen (PIKA_DATA (palette)))
g_signal_emit (palette, signals[ENTRY_CHANGED], 0, position);
pika_data_dirty (PIKA_DATA (palette));
return TRUE;
@ -535,6 +593,9 @@ pika_palette_set_entry_name (PikaPalette *palette,
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));
return TRUE;

View File

@ -56,6 +56,9 @@ struct _PikaPalette
struct _PikaPaletteClass
{
PikaDataClass parent_class;
void (* entry_changed) (PikaPalette *palette,
gint index);
};
@ -85,7 +88,8 @@ gboolean pika_palette_set_entry (PikaPalette *palette,
const PikaRGB *color);
gboolean pika_palette_set_entry_color (PikaPalette *palette,
gint position,
const PikaRGB *color);
const PikaRGB *color,
gboolean push_undo_if_image);
gboolean pika_palette_set_entry_name (PikaPalette *palette,
gint position,
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
* exactly equal.
*/
pika_palette_set_entry_color (palette, 0, color);
pika_palette_set_entry_color (palette, 0, color, FALSE);
return;
}

View File

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

View File

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

View File

@ -48,7 +48,7 @@ struct _PikaProgressInterface
gdouble (* get_value) (PikaProgress *progress);
void (* pulse) (PikaProgress *progress);
guint32 (* get_window_id) (PikaProgress *progress);
GBytes * (* get_window_id) (PikaProgress *progress);
gboolean (* message) (PikaProgress *progress,
Pika *pika,
@ -78,7 +78,7 @@ void pika_progress_set_value (PikaProgress *progress,
gdouble pika_progress_get_value (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,
Pika *pika,

View File

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

View File

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

View File

@ -151,6 +151,13 @@ quit_close_all_dialog_new (Pika *pika,
GClosure *closure;
gint rows;
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);
@ -206,8 +213,28 @@ quit_close_all_dialog_new (Pika *pika,
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;
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_size, 1);

View File

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

View File

@ -103,15 +103,16 @@ pika_display_shell_progress_pulse (PikaProgress *progress)
pika_progress_pulse (PIKA_PROGRESS (statusbar));
}
static guint32
static GBytes *
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))
return pika_window_get_native_id (GTK_WINDOW (toplevel));
if (shell->window_handle)
handle = g_bytes_ref (shell->window_handle);
return 0;
return handle;
}
static gboolean

View File

@ -27,6 +27,10 @@
#include <gegl.h>
#include <gtk/gtk.h>
#ifdef GDK_WINDOWING_WAYLAND
#include <gdk/gdkwayland.h>
#endif
#include "libpikabase/pikabase.h"
#include "libpikamath/pikamath.h"
#include "libpikacolor/pikacolor.h"
@ -587,6 +591,8 @@ pika_display_shell_constructed (GObject *object)
G_CALLBACK (pika_display_shell_canvas_grab_notify),
shell);
pika_widget_set_native_handle (GTK_WIDGET (shell), &shell->window_handle);
g_signal_connect (shell->canvas, "realize",
G_CALLBACK (pika_display_shell_canvas_realize),
shell);
@ -851,6 +857,17 @@ pika_display_shell_dispose (GObject *object)
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);
}

View File

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

View File

@ -1174,9 +1174,6 @@ pika_image_window_set_aux_info (PikaSessionManaged *session_managed,
else if (StartupInfo.wShowWindow == SW_SHOWMINIMIZED ||
StartupInfo.wShowWindow == SW_SHOWMINNOACTIVE ||
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));
else
/* Another show property not relevant to min/max.

View File

@ -2026,8 +2026,10 @@ static void
pika_tool_rectangle_update_options (PikaToolRectangle *rectangle)
{
PikaToolRectanglePrivate *private = rectangle->private;
gdouble x1, y1;
gdouble 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);
@ -2162,7 +2164,10 @@ static void
pika_tool_rectangle_update_status (PikaToolRectangle *rectangle)
{
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);
@ -2436,7 +2441,10 @@ pika_tool_rectangle_coord_on_handle (PikaToolRectangle *rectangle,
{
PikaToolRectanglePrivate *private = rectangle->private;
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 handle_x = 0;
gdouble handle_y = 0;
@ -2838,7 +2846,10 @@ pika_tool_rectangle_setup_snap_offsets (PikaToolRectangle *rectangle,
{
PikaToolWidget *widget = PIKA_TOOL_WIDGET (rectangle);
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;
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 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);

View File

@ -35,11 +35,15 @@
#include "core/pikabrush.h"
#include "core/pikabrush-load.h"
#include "core/pikabrush-private.h"
#include "core/pikacontainer.h"
#include "core/pikadrawable.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/pikalayer-new.h"
#include "core/pikaparamspecs.h"
#include "core/pikapickable.h"
#include "core/pikatempbuf.h"
#include "pdb/pikaprocedure.h"
@ -54,7 +58,9 @@
static PikaImage * file_gbr_brush_to_image (Pika *pika,
PikaBrush *brush);
static PikaBrush * file_gbr_image_to_brush (PikaImage *image,
PikaDrawable *drawable,
PikaContext *context,
gint n_drawables,
PikaDrawable **drawables,
const gchar *name,
gdouble spacing);
@ -121,7 +127,8 @@ file_gbr_save_invoker (PikaProcedure *procedure,
{
PikaValueArray *return_vals;
PikaImage *image;
PikaDrawable *drawable;
PikaDrawable **drawables;
gint n_drawables;
PikaBrush *brush;
const gchar *name;
GFile *file;
@ -131,12 +138,13 @@ file_gbr_save_invoker (PikaProcedure *procedure,
pika_set_busy (pika);
image = g_value_get_object (pika_value_array_index (args, 1));
drawable = g_value_get_object (pika_value_array_index (args, 2));
file = g_value_get_object (pika_value_array_index (args, 3));
spacing = g_value_get_int (pika_value_array_index (args, 4));
name = g_value_get_string (pika_value_array_index (args, 5));
n_drawables = g_value_get_int (pika_value_array_index (args, 2));
drawables = (PikaDrawable **) pika_value_get_object_array (pika_value_array_index (args, 3));
file = g_value_get_object (pika_value_array_index (args, 4));
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);
@ -418,14 +426,48 @@ file_gbr_brush_to_image (Pika *pika,
static PikaBrush *
file_gbr_image_to_brush (PikaImage *image,
PikaDrawable *drawable,
PikaContext *context,
gint n_drawables,
PikaDrawable **drawables,
const gchar *name,
gdouble spacing)
{
gint width = pika_item_get_width (PIKA_ITEM (drawable));
gint height = pika_item_get_height (PIKA_ITEM (drawable));
PikaBrush *brush;
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);
g_return_val_if_fail (drawables != NULL, NULL);
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;
g_return_val_if_fail (n_drawables > 0, NULL);
g_return_val_if_fail (drawables != NULL, NULL);
if (n_drawables > 1)
{

View File

@ -87,7 +87,7 @@ file_data_init (Pika *pika)
"1995-2019");
pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param",
pika_param_spec_enum ("run-mode",
"Dummy Param",
"Dummy parameter",
PIKA_TYPE_RUN_MODE,
@ -145,7 +145,7 @@ file_data_init (Pika *pika)
"1995-2019");
pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param",
pika_param_spec_enum ("run-mode",
"Dummy Param",
"Dummy parameter",
PIKA_TYPE_RUN_MODE,
@ -158,12 +158,17 @@ file_data_init (Pika *pika)
FALSE,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_drawable ("drawable",
"Drawable",
"Active drawable "
"of input image",
FALSE,
g_param_spec_int ("num-drawables",
"Num drawables",
"Number of drawables",
1, G_MAXINT, 1,
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,
g_param_spec_object ("file",
"File",
@ -219,7 +224,7 @@ file_data_init (Pika *pika)
"1999-2019");
pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param",
pika_param_spec_enum ("run-mode",
"Dummy Param",
"Dummy parameter",
PIKA_TYPE_RUN_MODE,
@ -277,7 +282,7 @@ file_data_init (Pika *pika)
"1999-2019");
pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param",
pika_param_spec_enum ("run-mode",
"Dummy Param",
"Dummy parameter",
PIKA_TYPE_RUN_MODE,
@ -363,7 +368,7 @@ file_data_init (Pika *pika)
"1997-2019");
pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param",
pika_param_spec_enum ("run-mode",
"Dummy Param",
"Dummy parameter",
PIKA_TYPE_RUN_MODE,
@ -420,7 +425,7 @@ file_data_init (Pika *pika)
"1995-2019");
pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param",
pika_param_spec_enum ("run-mode",
"Dummy Param",
"Dummy parameter",
PIKA_TYPE_RUN_MODE,
@ -433,7 +438,7 @@ file_data_init (Pika *pika)
FALSE,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
g_param_spec_int ("n-drawables",
g_param_spec_int ("num-drawables",
"Num drawables",
"Number of drawables",
1, G_MAXINT, 1,
@ -491,7 +496,7 @@ file_data_init (Pika *pika)
"Jehan", "Jehan", "2019");
pika_procedure_add_argument (procedure,
pika_param_spec_enum ("dummy-param",
pika_param_spec_enum ("run-mode",
"Dummy Param",
"Dummy parameter",
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));
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, 3)))
{
@ -385,11 +385,11 @@ file_open_thumbnail (Pika *pika,
MAX (0, g_value_get_int (pika_value_array_index (return_vals, 3)));
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:
*format = pika_babl_format (PIKA_RGB,
@ -424,7 +424,7 @@ file_open_thumbnail (Pika *pika,
babl_new_palette ("-pika-indexed-format-dummy",
&rgb, &rgba);
if (value == PIKA_INDEXED_IMAGE)
if (itype == PIKA_INDEXED_IMAGE)
*format = rgb;
else
*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
pika_gegl_convert_color_profile_progress (PikaProgress *progress,
gdouble value)

View File

@ -91,6 +91,15 @@ void pika_gegl_index_to_mask (GeglBuffer *indexed_buffer
GeglBuffer *mask_buffer,
const GeglRectangle *mask_rect,
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,
const GeglRectangle *src_rect,

View File

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

View File

@ -62,6 +62,8 @@
#include "core/pikacancelable.h"
#include "core/pikacontainer.h"
#include "core/pikacontext.h"
#include "core/pikadatafactory.h"
#include "core/pikadrawable.h"
#include "core/pikagradient.h"
#include "core/pikaimage.h"
#include "core/pikaimagefile.h"
@ -89,6 +91,7 @@
#include "widgets/pikamenufactory.h"
#include "widgets/pikapaletteselect.h"
#include "widgets/pikapatternselect.h"
#include "widgets/pikapickableselect.h"
#include "widgets/pikaprogressdialog.h"
#include "widgets/pikauimanager.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 PikaObject * gui_get_window_strategy (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,
PikaImage *image,
PikaUnit unit,
@ -156,18 +159,19 @@ static void gui_free_progress (Pika *pika,
static gboolean gui_pdb_dialog_new (Pika *pika,
PikaContext *context,
PikaProgress *progress,
PikaContainer *container,
GType object_type,
GBytes *parent_handle,
const gchar *title,
const gchar *callback_name,
const gchar *object_name,
PikaObject *object,
va_list args);
static gboolean gui_pdb_dialog_set (Pika *pika,
PikaContainer *container,
GType contents_type,
const gchar *callback_name,
const gchar *object_name,
PikaObject *object,
va_list args);
static gboolean gui_pdb_dialog_close (Pika *pika,
PikaContainer *container,
GType contents_type,
const gchar *callback_name);
static gboolean gui_recent_list_add_file (Pika *pika,
GFile *file,
@ -378,7 +382,7 @@ gui_get_empty_display (Pika *pika)
return display;
}
static guint32
static GBytes *
gui_display_get_window_id (PikaDisplay *display)
{
PikaDisplay *disp = PIKA_DISPLAY (display);
@ -386,13 +390,11 @@ gui_display_get_window_id (PikaDisplay *display)
if (shell)
{
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (shell));
if (GTK_IS_WINDOW (toplevel))
return pika_window_get_native_id (GTK_WINDOW (toplevel));
if (shell)
return g_bytes_ref (shell->window_handle);
}
return 0;
return NULL;
}
static PikaDisplay *
@ -524,7 +526,7 @@ gui_wait (Pika *pika,
input_pipe[1]);
g_value_set_string (pika_value_array_index (args, 3),
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_procedure_execute_async (procedure, pika,
@ -616,65 +618,74 @@ static gboolean
gui_pdb_dialog_new (Pika *pika,
PikaContext *context,
PikaProgress *progress,
PikaContainer *container,
GType contents_type,
GBytes *parent_handle,
const gchar *title,
const gchar *callback_name,
const gchar *object_name,
PikaObject *object,
va_list args)
{
GType dialog_type = G_TYPE_NONE;
const gchar *dialog_role = 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_role = "pika-brush-selection";
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_role = "pika-font-selection";
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_role = "pika-gradient-selection";
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_role = "pika-palette-selection";
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_role = "pika-pattern-selection";
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)
{
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))
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)
if (object || g_type_is_a (contents_type, PIKA_TYPE_DRAWABLE))
{
gint n_properties = 0;
gchar **names = NULL;
GValue *values = NULL;
GtkWidget *dialog;
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,
&n_properties, names, &values,
@ -684,10 +695,11 @@ gui_pdb_dialog_new (Pika *pika,
"help-id", help_id,
"pdb", pika->pdb,
"context", context,
"select-type", pika_container_get_children_type (container),
"select-type", contents_type,
"initial-object", object,
"callback-name", callback_name,
"menu-factory", menus_get_global_menu_factory (pika),
"use-header-bar", use_header_bar,
NULL);
names = pika_properties_append_valist (dialog_type,
@ -707,12 +719,7 @@ gui_pdb_dialog_new (Pika *pika,
pika_docked_set_show_button_bar (PIKA_DOCKED (view), FALSE);
if (progress)
{
guint32 window_id = pika_progress_get_window_id (progress);
if (window_id)
pika_window_set_transient_for (GTK_WINDOW (dialog), window_id);
}
pika_window_set_transient_for (GTK_WINDOW (dialog), progress);
gtk_widget_show (dialog);
@ -729,6 +736,9 @@ gui_pdb_dialog_new (Pika *pika,
g_source_unref (source);
}
if (parent_handle != NULL)
pika_window_set_transient_for_handle (GTK_WINDOW (dialog), parent_handle);
return TRUE;
}
}
@ -738,42 +748,65 @@ gui_pdb_dialog_new (Pika *pika,
static gboolean
gui_pdb_dialog_set (Pika *pika,
PikaContainer *container,
GType contents_type,
const gchar *callback_name,
const gchar *object_name,
PikaObject *object,
va_list args)
{
PikaPdbDialogClass *klass = NULL;
if (pika_container_get_children_type (container) == 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)
{
PikaContainer *container = NULL;
PikaPdbDialog *dialog;
if (contents_type == PIKA_TYPE_BRUSH)
{
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);
}
g_return_val_if_fail (klass != NULL, FALSE);
dialog = pika_pdb_dialog_get_by_callback (klass, callback_name);
if (dialog && dialog->select_type == pika_container_get_children_type (container))
{
PikaObject *object;
object = pika_container_get_child_by_name (container, object_name);
if (object)
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 *);
pika_context_set_by_type (dialog->context, dialog->select_type,
object);
if (g_type_is_a (contents_type, PIKA_TYPE_RESOURCE))
{
g_return_val_if_fail (container != NULL, FALSE);
pika_context_set_by_type (dialog->context, dialog->select_type, object);
}
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);
@ -782,29 +815,29 @@ gui_pdb_dialog_set (Pika *pika,
return TRUE;
}
}
}
return FALSE;
}
static gboolean
gui_pdb_dialog_close (Pika *pika,
PikaContainer *container,
GType contents_type,
const gchar *callback_name)
{
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);
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);
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);
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);
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);
else if (contents_type == PIKA_TYPE_DRAWABLE)
klass = g_type_class_peek (PIKA_TYPE_PICKABLE_SELECT);
if (klass)
{
@ -812,7 +845,7 @@ gui_pdb_dialog_close (Pika *pika,
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));
return TRUE;

View File

@ -90,6 +90,12 @@
#include "splash.h"
#include "themes.h"
#ifdef G_OS_WIN32
#include <windef.h>
#include <winbase.h>
#include <windows.h>
#endif
#ifdef GDK_WINDOWING_QUARTZ
#import <AppKit/AppKit.h>
@ -543,6 +549,11 @@ gui_restore_after_callback (Pika *pika,
PikaGuiConfig *gui_config = PIKA_GUI_CONFIG (pika->config);
PikaUIManager *image_ui_manager;
PikaDisplay *display;
#ifdef G_OS_WIN32
STARTUPINFO StartupInfo;
GetStartupInfo (&StartupInfo);
#endif
if (pika->be_verbose)
g_print ("INIT: %s\n", G_STRFUNC);
@ -610,11 +621,23 @@ gui_restore_after_callback (Pika *pika,
shell = pika_display_get_shell (display);
#ifdef G_OS_WIN32
themes_set_title_bar (pika);
#endif
if (gui_config->restore_session)
session_restore (pika, initial_monitor);
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 */
gtk_window_present (GTK_WINDOW (toplevel));
}
@ -925,12 +948,26 @@ gui_check_unique_accelerators (Pika *pika)
gchar **disabled_accels;
gint len;
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
* to choose), unless it's a secondary shortcut, and the
* 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_accels = accels;
@ -942,6 +979,20 @@ gui_check_unique_accelerators (Pika *pika)
disabled_accels = accels2;
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. */
len = g_strv_length (disabled_accels);
g_free (disabled_accels[remove]);
@ -949,12 +1000,11 @@ gui_check_unique_accelerators (Pika *pika)
&disabled_accels[remove + 1],
sizeof (char *) * (len - remove));
if (print_warning)
g_printerr ("Actions \"%s\" and \"%s\" use the same accelerator.\n"
" 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),
(const gchar **) disabled_accels);
}

View File

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

View File

@ -35,6 +35,10 @@
#include "core/pika.h"
#include "display/pikaimagewindow.h"
#include "widgets/pikawidgets-utils.h"
#include "themes.h"
#include "pika-intl.h"
@ -109,6 +113,10 @@ themes_init (Pika *pika)
pika);
themes_theme_change_notify (config, NULL, pika);
#ifdef G_OS_WIN32
themes_set_title_bar (pika);
#endif
}
void
@ -473,6 +481,10 @@ themes_theme_change_notify (PikaGuiConfig *config,
g_object_unref (theme_css);
gtk_style_context_reset_widgets (gdk_screen_get_default ());
#ifdef G_OS_WIN32
themes_set_title_bar (pika);
#endif
}
static void
@ -553,3 +565,22 @@ themes_theme_paths_notify (PikaExtensionManager *manager,
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,
...) G_GNUC_NULL_TERMINATED;
void themes_set_title_bar (Pika *pika);
#endif /* __THEMES_H__ */

View File

@ -28,7 +28,6 @@
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikabase/pikaprotocol.h"
#include "libpikaconfig/pikaconfig.h"
#include "menus-types.h"
@ -56,8 +55,7 @@ static GTokenType shortcuts_action_deserialize (GScanner *scanner,
enum
{
PROTOCOL_VERSION = 1,
FILE_VERSION,
FILE_VERSION = 1,
ACTION,
};
@ -68,7 +66,6 @@ shortcuts_rc_parse (GtkApplication *application,
GError **error)
{
GScanner *scanner;
gint protocol_version = PIKA_PROTOCOL_VERSION;
gint file_version = SHORTCUTS_RC_FILE_VERSION;
GTokenType token;
@ -81,9 +78,6 @@ shortcuts_rc_parse (GtkApplication *application,
if (! scanner)
return FALSE;
g_scanner_scope_add_symbol (scanner, 0,
"protocol-version",
GINT_TO_POINTER (PROTOCOL_VERSION));
g_scanner_scope_add_symbol (scanner, 0,
"file-version",
GINT_TO_POINTER (FILE_VERSION));
@ -92,9 +86,9 @@ shortcuts_rc_parse (GtkApplication *application,
token = G_TOKEN_LEFT_PAREN;
while (protocol_version == PIKA_PROTOCOL_VERSION &&
file_version == SHORTCUTS_RC_FILE_VERSION &&
g_scanner_peek_next_token (scanner) == token)
while (g_scanner_peek_next_token (scanner) == token ||
(token == G_TOKEN_SYMBOL &&
g_scanner_peek_next_token (scanner) == G_TOKEN_IDENTIFIER))
{
token = g_scanner_get_next_token (scanner);
@ -107,12 +101,6 @@ shortcuts_rc_parse (GtkApplication *application,
case G_TOKEN_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:
token = G_TOKEN_INT;
if (pika_scanner_parse_int (scanner, &file_version))
@ -129,6 +117,16 @@ shortcuts_rc_parse (GtkApplication *application,
}
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:
token = G_TOKEN_LEFT_PAREN;
break;
@ -138,25 +136,16 @@ shortcuts_rc_parse (GtkApplication *application,
}
}
if (protocol_version != PIKA_PROTOCOL_VERSION ||
file_version != SHORTCUTS_RC_FILE_VERSION ||
token != G_TOKEN_LEFT_PAREN)
if (file_version != SHORTCUTS_RC_FILE_VERSION)
{
if (protocol_version != PIKA_PROTOCOL_VERSION)
{
g_set_error (error,
PIKA_CONFIG_ERROR, PIKA_CONFIG_ERROR_VERSION,
_("Skipping '%s': wrong PIKA protocol version."),
pika_file_get_utf8_name (file));
g_printerr (_("Wrong shortcutsrc (%s) file format version: %d (expected: %d). "
"We tried to load shortcuts as well as possible.\n"),
pika_file_get_utf8_name (file),
file_version, SHORTCUTS_RC_FILE_VERSION);
}
else if (file_version != SHORTCUTS_RC_FILE_VERSION)
if (token != G_TOKEN_LEFT_PAREN)
{
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)
if (token != G_TOKEN_ERROR)
{
g_scanner_get_next_token (scanner);
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));
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_printf (writer, "%d", SHORTCUTS_RC_FILE_VERSION);
pika_config_writer_close (writer);

View File

@ -34,6 +34,8 @@
#include "pdb-types.h"
#include "core/pika.h"
#include "core/pikabrush.h"
#include "core/pikacontainer.h"
#include "core/pikadatafactory.h"
#include "core/pikaparamspecs.h"
@ -53,20 +55,24 @@ brushes_popup_invoker (PikaProcedure *procedure,
gboolean success = TRUE;
const gchar *brush_callback;
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));
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)
{
PikaContainer *container = pika_data_factory_get_container (pika->brush_factory);
if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, brush_callback) ||
! pika_pdb_dialog_new (pika, context, progress,
pika_data_factory_get_container (pika->brush_factory),
popup_title, brush_callback, initial_brush_name,
NULL))
pika_container_get_children_type (container),
parent_window, popup_title, brush_callback,
PIKA_OBJECT (initial_brush), NULL))
success = FALSE;
}
@ -89,9 +95,12 @@ brushes_close_popup_invoker (PikaProcedure *procedure,
if (success)
{
PikaContainer *container = pika_data_factory_get_container (pika->brush_factory);
if (pika->no_interface ||
! 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))
success = FALSE;
}
@ -110,18 +119,20 @@ brushes_set_popup_invoker (PikaProcedure *procedure,
{
gboolean success = TRUE;
const gchar *brush_callback;
const gchar *brush_name;
PikaBrush *brush;
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)
{
PikaContainer *container = pika_data_factory_get_container (pika->brush_factory);
if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, brush_callback) ||
! pika_pdb_dialog_set (pika, pika_data_factory_get_container (pika->brush_factory),
brush_callback, brush_name,
NULL))
! pika_pdb_dialog_set (pika,
pika_container_get_children_type (container),
brush_callback, PIKA_OBJECT (brush), NULL))
success = FALSE;
}
@ -163,11 +174,16 @@ register_brush_select_procs (PikaPDB *pdb)
NULL,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("initial-brush-name",
"initial brush name",
"The name of the brush to set as the initial choice",
FALSE, TRUE, FALSE,
NULL,
pika_param_spec_brush ("initial-brush",
"initial brush",
"The brush to set as the initial choice",
FALSE,
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);
g_object_unref (procedure);
@ -218,11 +234,10 @@ register_brush_select_procs (PikaPDB *pdb)
NULL,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("brush-name",
"brush name",
"The name of the brush to set as selected",
FALSE, FALSE, FALSE,
NULL,
pika_param_spec_brush ("brush",
"brush",
"The brush to set as selected",
FALSE,
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure);

View File

@ -148,20 +148,20 @@ display_get_window_handle_invoker (PikaProcedure *procedure,
gboolean success = TRUE;
PikaValueArray *return_vals;
PikaDisplay *display;
gint window = 0;
GBytes *handle = NULL;
display = g_value_get_object (pika_value_array_index (args, 0));
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,
error ? *error : NULL);
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;
}
@ -330,7 +330,8 @@ register_display_procs (PikaPDB *pdb)
"pika-display-get-window-handle");
pika_procedure_set_static_help (procedure,
"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);
pika_procedure_set_static_attribution (procedure,
"Sven Neumann <sven@gimp.org>",
@ -343,10 +344,10 @@ register_display_procs (PikaPDB *pdb)
FALSE,
PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure,
g_param_spec_int ("window",
"window",
"The native window handle or 0",
G_MININT32, G_MAXINT32, 0,
g_param_spec_boxed ("handle",
"handle",
"The native window handle or NULL",
G_TYPE_BYTES,
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure);

View File

@ -75,6 +75,57 @@ font_get_by_name_invoker (PikaProcedure *procedure,
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
register_font_procs (PikaPDB *pdb)
{
@ -87,8 +138,9 @@ register_font_procs (PikaPDB *pdb)
pika_object_set_static_name (PIKA_OBJECT (procedure),
"pika-font-get-by-name");
pika_procedure_set_static_help (procedure,
"Returns the font with the given name.",
"Returns the font with the given name.",
"Returns a 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);
pika_procedure_set_static_attribution (procedure,
"Michael Natterer <mitch@gimp.org>",
@ -109,4 +161,40 @@ register_font_procs (PikaPDB *pdb)
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, 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 "core/pika.h"
#include "core/pikacontainer.h"
#include "core/pikadatafactory.h"
#include "core/pikaparamspecs.h"
#include "text/pikafont.h"
#include "pikapdb.h"
#include "pikaprocedure.h"
@ -53,21 +55,25 @@ fonts_popup_invoker (PikaProcedure *procedure,
gboolean success = TRUE;
const gchar *font_callback;
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));
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)
{
PikaContainer *container = pika_data_factory_get_container (pika->font_factory);
if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, font_callback) ||
! pika_data_factory_data_wait (pika->font_factory) ||
! pika_pdb_dialog_new (pika, context, progress,
pika_data_factory_get_container (pika->font_factory),
popup_title, font_callback, initial_font_name,
NULL))
pika_container_get_children_type (container),
parent_window, popup_title, font_callback,
PIKA_OBJECT (initial_font), NULL))
success = FALSE;
}
@ -90,10 +96,12 @@ fonts_close_popup_invoker (PikaProcedure *procedure,
if (success)
{
PikaContainer *container = pika_data_factory_get_container (pika->font_factory);
if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, font_callback) ||
! pika_pdb_dialog_close (pika,
pika_data_factory_get_container (pika->font_factory),
pika_container_get_children_type (container),
font_callback))
success = FALSE;
}
@ -112,20 +120,21 @@ fonts_set_popup_invoker (PikaProcedure *procedure,
{
gboolean success = TRUE;
const gchar *font_callback;
const gchar *font_name;
PikaFont *font;
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)
{
PikaContainer *container = pika_data_factory_get_container (pika->font_factory);
if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, font_callback) ||
! pika_data_factory_data_wait (pika->font_factory) ||
! pika_pdb_dialog_set (pika,
pika_data_factory_get_container (pika->font_factory),
font_callback, font_name,
NULL))
pika_container_get_children_type (container),
font_callback, PIKA_OBJECT (font), NULL))
success = FALSE;
}
@ -167,11 +176,16 @@ register_font_select_procs (PikaPDB *pdb)
NULL,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("initial-font-name",
"initial font name",
pika_param_spec_font ("initial-font",
"initial font",
"The name of the initial font choice.",
FALSE, TRUE, FALSE,
NULL,
FALSE,
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);
g_object_unref (procedure);
@ -222,11 +236,10 @@ register_font_select_procs (PikaPDB *pdb)
NULL,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("font-name",
"font name",
"The name of the font to set as selected",
FALSE, FALSE, FALSE,
NULL,
pika_param_spec_font ("font",
"font",
"The font to set as selected",
FALSE,
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure);

View File

@ -34,6 +34,7 @@
#include "pdb-types.h"
#include "core/pika.h"
#include "core/pikacontainer.h"
#include "core/pikadatafactory.h"
#include "core/pikagradient.h"
#include "core/pikaparamspecs.h"
@ -54,14 +55,18 @@ gradients_popup_invoker (PikaProcedure *procedure,
gboolean success = TRUE;
const gchar *gradient_callback;
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));
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)
{
PikaContainer *container = pika_data_factory_get_container (pika->gradient_factory);
/* Formerly, this procedure had another parameter:
* 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,
@ -71,9 +76,9 @@ gradients_popup_invoker (PikaProcedure *procedure,
if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, gradient_callback) ||
! pika_pdb_dialog_new (pika, context, progress,
pika_data_factory_get_container (pika->gradient_factory),
popup_title, gradient_callback, initial_gradient_name,
NULL))
pika_container_get_children_type (container),
parent_window, popup_title, gradient_callback,
PIKA_OBJECT (initial_gradient), NULL))
success = FALSE;
}
@ -96,9 +101,12 @@ gradients_close_popup_invoker (PikaProcedure *procedure,
if (success)
{
PikaContainer *container = pika_data_factory_get_container (pika->gradient_factory);
if (pika->no_interface ||
! 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))
success = FALSE;
}
@ -117,18 +125,20 @@ gradients_set_popup_invoker (PikaProcedure *procedure,
{
gboolean success = TRUE;
const gchar *gradient_callback;
const gchar *gradient_name;
PikaGradient *gradient;
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)
{
PikaContainer *container = pika_data_factory_get_container (pika->gradient_factory);
if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, gradient_callback) ||
! pika_pdb_dialog_set (pika, pika_data_factory_get_container (pika->gradient_factory),
gradient_callback, gradient_name,
NULL))
! pika_pdb_dialog_set (pika,
pika_container_get_children_type (container),
gradient_callback, PIKA_OBJECT (gradient), NULL))
success = FALSE;
}
@ -170,11 +180,16 @@ register_gradient_select_procs (PikaPDB *pdb)
NULL,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("initial-gradient-name",
"initial gradient name",
"The name of the initial gradient choice",
FALSE, TRUE, FALSE,
NULL,
pika_param_spec_gradient ("initial-gradient",
"initial gradient",
"The initial gradient choice",
FALSE,
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);
g_object_unref (procedure);
@ -225,11 +240,10 @@ register_gradient_select_procs (PikaPDB *pdb)
NULL,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("gradient-name",
"gradient name",
"The name of the gradient to set as selected",
FALSE, FALSE, FALSE,
NULL,
pika_param_spec_gradient ("gradient",
"gradient",
"The gradient to set as selected",
FALSE,
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure);

View File

@ -55,6 +55,7 @@
#include "core/pikaimage.h"
#include "core/pikaitem.h"
#include "core/pikalayer.h"
#include "core/pikapalette.h"
#include "core/pikaparamspecs.h"
#include "core/pikapickable.h"
#include "core/pikaprogress.h"
@ -1575,6 +1576,35 @@ image_set_colormap_invoker (PikaProcedure *procedure,
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 *
image_get_metadata_invoker (PikaProcedure *procedure,
Pika *pika,
@ -4356,6 +4386,35 @@ register_image_procs (PikaPDB *pdb)
pika_pdb_register_procedure (pdb, 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
*/

View File

@ -34,7 +34,7 @@
#include "internal-procs.h"
/* 775 procedures registered total */
/* 779 procedures registered total */
void
internal_procs_init (PikaPDB *pdb)
@ -52,6 +52,7 @@ internal_procs_init (PikaPDB *pdb)
register_drawable_procs (pdb);
register_drawable_color_procs (pdb);
register_drawable_edit_procs (pdb);
register_drawable_select_procs (pdb);
register_dynamics_procs (pdb);
register_edit_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_color_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_edit_procs (PikaPDB *pdb);
void register_file_procs (PikaPDB *pdb);

View File

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

View File

@ -41,6 +41,7 @@
#include "core/pika.h"
#include "core/pikacontext.h"
#include "core/pikadatafactory.h"
#include "core/pikaimage-colormap.h"
#include "core/pikapalette.h"
#include "core/pikaparamspecs.h"
@ -308,10 +309,19 @@ palette_delete_entry_invoker (PikaProcedure *procedure,
PikaPaletteEntry *entry = pika_palette_get_entry (palette, entry_num);
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
{
success = FALSE;
}
}
else
success = FALSE;
}
@ -376,7 +386,7 @@ palette_entry_set_color_invoker (PikaProcedure *procedure,
if (success)
{
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
success = FALSE;
}
@ -687,7 +697,8 @@ register_palette_procs (PikaPDB *pdb)
"pika-palette-delete-entry");
pika_procedure_set_static_help (procedure,
"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);
pika_procedure_set_static_attribution (procedure,
"Michael Natterer <mitch@gimp.org>",

View File

@ -34,7 +34,9 @@
#include "pdb-types.h"
#include "core/pika.h"
#include "core/pikacontainer.h"
#include "core/pikadatafactory.h"
#include "core/pikapalette.h"
#include "core/pikaparamspecs.h"
#include "pikapdb.h"
@ -53,20 +55,24 @@ palettes_popup_invoker (PikaProcedure *procedure,
gboolean success = TRUE;
const gchar *palette_callback;
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));
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)
{
PikaContainer *container = pika_data_factory_get_container (pika->palette_factory);
if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, palette_callback) ||
! pika_pdb_dialog_new (pika, context, progress,
pika_data_factory_get_container (pika->palette_factory),
popup_title, palette_callback, initial_palette_name,
NULL))
pika_container_get_children_type (container),
parent_window, popup_title, palette_callback,
PIKA_OBJECT (initial_palette), NULL))
success = FALSE;
}
@ -89,9 +95,12 @@ palettes_close_popup_invoker (PikaProcedure *procedure,
if (success)
{
PikaContainer *container = pika_data_factory_get_container (pika->palette_factory);
if (pika->no_interface ||
! 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))
success = FALSE;
}
@ -110,18 +119,20 @@ palettes_set_popup_invoker (PikaProcedure *procedure,
{
gboolean success = TRUE;
const gchar *palette_callback;
const gchar *palette_name;
PikaPalette *palette;
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)
{
PikaContainer *container = pika_data_factory_get_container (pika->palette_factory);
if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, palette_callback) ||
! pika_pdb_dialog_set (pika, pika_data_factory_get_container (pika->palette_factory),
palette_callback, palette_name,
NULL))
! pika_pdb_dialog_set (pika,
pika_container_get_children_type (container),
palette_callback, PIKA_OBJECT (palette), NULL))
success = FALSE;
}
@ -163,11 +174,16 @@ register_palette_select_procs (PikaPDB *pdb)
NULL,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("initial-palette-name",
"initial palette name",
"The name of the palette to set as the initial choice.",
FALSE, TRUE, FALSE,
NULL,
pika_param_spec_palette ("initial-palette",
"initial palette",
"The palette to set as the initial choice.",
FALSE,
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);
g_object_unref (procedure);
@ -218,11 +234,10 @@ register_palette_select_procs (PikaPDB *pdb)
NULL,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("palette-name",
"palette name",
"The name of the palette to set as selected",
FALSE, FALSE, FALSE,
NULL,
pika_param_spec_palette ("palette",
"palette",
"The palette to set as selected",
FALSE,
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure);

View File

@ -256,7 +256,7 @@ register_pattern_procs (PikaPDB *pdb)
"pika-pattern-get-pixels");
pika_procedure_set_static_help (procedure,
"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);
pika_procedure_set_static_attribution (procedure,
"Michael Natterer <mitch@gimp.org>",

View File

@ -34,8 +34,10 @@
#include "pdb-types.h"
#include "core/pika.h"
#include "core/pikacontainer.h"
#include "core/pikadatafactory.h"
#include "core/pikaparamspecs.h"
#include "core/pikapattern.h"
#include "pikapdb.h"
#include "pikaprocedure.h"
@ -53,20 +55,24 @@ patterns_popup_invoker (PikaProcedure *procedure,
gboolean success = TRUE;
const gchar *pattern_callback;
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));
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)
{
PikaContainer *container = pika_data_factory_get_container (pika->pattern_factory);
if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, pattern_callback) ||
! pika_pdb_dialog_new (pika, context, progress,
pika_data_factory_get_container (pika->pattern_factory),
popup_title, pattern_callback, initial_pattern_name,
NULL))
pika_container_get_children_type (container),
parent_window, popup_title, pattern_callback,
PIKA_OBJECT (initial_pattern), NULL))
success = FALSE;
}
@ -89,9 +95,12 @@ patterns_close_popup_invoker (PikaProcedure *procedure,
if (success)
{
PikaContainer *container = pika_data_factory_get_container (pika->pattern_factory);
if (pika->no_interface ||
! 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))
success = FALSE;
}
@ -110,18 +119,20 @@ patterns_set_popup_invoker (PikaProcedure *procedure,
{
gboolean success = TRUE;
const gchar *pattern_callback;
const gchar *pattern_name;
PikaPattern *pattern;
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)
{
PikaContainer *container = pika_data_factory_get_container (pika->pattern_factory);
if (pika->no_interface ||
! pika_pdb_lookup_procedure (pika->pdb, pattern_callback) ||
! pika_pdb_dialog_set (pika, pika_data_factory_get_container (pika->pattern_factory),
pattern_callback, pattern_name,
NULL))
! pika_pdb_dialog_set (pika,
pika_container_get_children_type (container),
pattern_callback, PIKA_OBJECT (pattern), NULL))
success = FALSE;
}
@ -163,11 +174,16 @@ register_pattern_select_procs (PikaPDB *pdb)
NULL,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("initial-pattern-name",
"initial pattern name",
"The name of the pattern to set as the initial choice",
FALSE, TRUE, FALSE,
NULL,
pika_param_spec_pattern ("initial-pattern",
"initial pattern",
"The pattern to set as the initial choice",
FALSE,
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);
g_object_unref (procedure);
@ -218,11 +234,10 @@ register_pattern_select_procs (PikaPDB *pdb)
NULL,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("pattern-name",
"pattern name",
"The name of the pattern to set as selected",
FALSE, FALSE, FALSE,
NULL,
pika_param_spec_pattern ("pattern",
"pattern",
"The pattern to set as selected",
FALSE,
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure);

View File

@ -1167,47 +1167,6 @@ pdb_get_data_invoker (PikaProcedure *procedure,
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 *
pdb_set_data_invoker (PikaProcedure *procedure,
Pika *pika,
@ -2230,36 +2189,6 @@ register_pdb_procs (PikaPDB *pdb)
pika_pdb_register_procedure (pdb, 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
*/

View File

@ -105,6 +105,91 @@ pika_pdb_get_data_factory (Pika *pika,
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 *
pika_pdb_get_resource (Pika *pika,
GType data_type,

View File

@ -26,6 +26,11 @@
PikaDataFactory * pika_pdb_get_data_factory (Pika *pika,
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,
GType data_type,
const gchar *name,

View File

@ -193,14 +193,14 @@ progress_get_window_handle_invoker (PikaProcedure *procedure,
{
gboolean success = TRUE;
PikaValueArray *return_vals;
gint window = 0;
GBytes *handle = NULL;
PikaPlugIn *plug_in = pika->plug_in_manager->current_plug_in;
if (plug_in && plug_in->open)
{
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
success = FALSE;
@ -209,7 +209,7 @@ progress_get_window_handle_invoker (PikaProcedure *procedure,
error ? *error : NULL);
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;
}
@ -418,18 +418,19 @@ register_progress_procs (PikaPDB *pdb)
pika_object_set_static_name (PIKA_OBJECT (procedure),
"pika-progress-get-window-handle");
pika_procedure_set_static_help (procedure,
"Returns the native window ID 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.",
"Returns the native handle 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);
pika_procedure_set_static_attribution (procedure,
"Michael Natterer <mitch@gimp.org>",
"Michael Natterer",
"2004");
pika_procedure_add_return_value (procedure,
g_param_spec_int ("window",
"window",
"The progress bar's toplevel window",
G_MININT32, G_MAXINT32, 0,
g_param_spec_boxed ("handle",
"handle",
"The progress bar's toplevel window's handle",
G_TYPE_BYTES,
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure);

View File

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

View File

@ -39,6 +39,7 @@
#include "core/pikaimage.h"
#include "core/pikalayer.h"
#include "core/pikaparamspecs.h"
#include "text/pikafont.h"
#include "text/pikatext-compat.h"
#include "pikapdb.h"
@ -48,7 +49,7 @@
static PikaValueArray *
text_fontname_invoker (PikaProcedure *procedure,
text_font_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
@ -65,7 +66,7 @@ text_fontname_invoker (PikaProcedure *procedure,
gint border;
gboolean antialias;
gdouble size;
const gchar *fontname;
PikaFont *font;
PikaLayer *text_layer = NULL;
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));
antialias = g_value_get_boolean (pika_value_array_index (args, 6));
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)
{
@ -87,15 +88,9 @@ text_fontname_invoker (PikaProcedure *procedure,
success = FALSE;
if (success)
{
gchar *real_fontname = g_strdup_printf ("%s %d", fontname, (gint) size);
text_layer = text_render (image, drawable, context,
x, y, real_fontname, text,
x, y, font, size, text,
border, antialias);
g_free (real_fontname);
}
}
return_vals = pika_procedure_get_return_values (procedure, success,
@ -108,7 +103,7 @@ text_fontname_invoker (PikaProcedure *procedure,
}
static PikaValueArray *
text_get_extents_fontname_invoker (PikaProcedure *procedure,
text_get_extents_font_invoker (PikaProcedure *procedure,
Pika *pika,
PikaContext *context,
PikaProgress *progress,
@ -119,7 +114,7 @@ text_get_extents_fontname_invoker (PikaProcedure *procedure,
PikaValueArray *return_vals;
const gchar *text;
gdouble size;
const gchar *fontname;
PikaFont *font;
gint width = 0;
gint height = 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));
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)
{
gchar *real_fontname = g_strdup_printf ("%s %d", fontname, (gint) size);
success = text_get_extents (pika,
real_fontname, text,
font, size, text,
&width, &height,
&ascent, &descent);
g_free (real_fontname);
}
return_vals = pika_procedure_get_return_values (procedure, success,
@ -161,14 +152,15 @@ register_text_tool_procs (PikaPDB *pdb)
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-text-fontname");
"pika-text-font");
pika_procedure_set_static_help (procedure,
"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);
pika_procedure_set_static_attribution (procedure,
"Martin Edlman & Sven Neumann",
@ -220,22 +212,14 @@ register_text_tool_procs (PikaPDB *pdb)
pika_procedure_add_argument (procedure,
g_param_spec_double ("size",
"size",
"The size of text in either pixels or points",
"The size of text in pixels",
0, G_MAXDOUBLE, 0,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
g_param_spec_enum ("size-type",
"size type",
"The units of specified size",
PIKA_TYPE_SIZE_TYPE,
PIKA_PIXELS,
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_spec_font ("font",
"font",
"The font",
FALSE,
PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure,
pika_param_spec_layer ("text-layer",
@ -247,14 +231,16 @@ register_text_tool_procs (PikaPDB *pdb)
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-text-get-extents-fontname");
"pika-text-get-extents-font");
pika_procedure_set_static_help (procedure,
"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);
pika_procedure_set_static_attribution (procedure,
"Martin Edlman & Sven Neumann",
@ -274,41 +260,33 @@ register_text_tool_procs (PikaPDB *pdb)
0, G_MAXDOUBLE, 0,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
g_param_spec_enum ("size-type",
"size type",
"The units of specified size",
PIKA_TYPE_SIZE_TYPE,
PIKA_PIXELS,
PIKA_PARAM_READWRITE));
pika_procedure_add_argument (procedure,
pika_param_spec_string ("fontname",
"fontname",
pika_param_spec_font ("font",
"font",
"The name of the font",
FALSE, FALSE, FALSE,
NULL,
FALSE,
PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure,
g_param_spec_int ("width",
"width",
"The width of the specified font",
"The width of the glyph extents",
G_MININT32, G_MAXINT32, 0,
PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure,
g_param_spec_int ("height",
"height",
"The height of the specified font",
"The height of the glyph extents",
G_MININT32, G_MAXINT32, 0,
PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure,
g_param_spec_int ("ascent",
"ascent",
"The ascent of the specified font",
"The ascent of the glyph extents",
G_MININT32, G_MAXINT32, 0,
PIKA_PARAM_READWRITE));
pika_procedure_add_return_value (procedure,
g_param_spec_int ("descent",
"descent",
"The descent of the specified font",
"The descent of the glyph extents",
G_MININT32, G_MAXINT32, 0,
PIKA_PARAM_READWRITE));
pika_pdb_register_procedure (pdb, procedure);

View File

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

View File

@ -237,7 +237,7 @@ pika_plug_in_progress_pulse (PikaPlugIn *plug_in)
pika_progress_pulse (proc_frame->progress);
}
guint32
GBytes *
pika_plug_in_progress_get_window_id (PikaPlugIn *plug_in)
{
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,
gdouble percentage);
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,
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);
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,
* for example plug-ins/common/mkgen.pl if
* PIKA_TESTING_PLUGINDIRS=plug-ins/common
* for example back with autotools, there used to be a file
* 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))
{

View File

@ -830,6 +830,56 @@ plug_in_proc_arg_deserialize (GScanner *scanner,
}
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:
if (! pika_scanner_parse_int (scanner,
&param_def.meta.m_boolean.default_val))
@ -944,6 +994,11 @@ plug_in_proc_arg_deserialize (GScanner *scanner,
case GP_PARAM_DEF_TYPE_ID:
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:
g_free (param_def.meta.m_id_array.type_name);
break;
@ -1038,6 +1093,31 @@ plug_in_rc_write_proc_arg (PikaConfigWriter *writer,
param_def.meta.m_enum.default_val);
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:
pika_config_writer_printf (writer, "%d",
param_def.meta.m_boolean.default_val);

View File

@ -67,7 +67,6 @@ foreach test_name : app_tests
'PIKA_TESTING_ABS_TOP_SRCDIR=' + meson.project_source_root(),
'PIKA_TESTING_ABS_TOP_BUILDDIR='+ meson.project_build_root(),
'PIKA_TESTING_PLUGINDIRS=' + meson.project_build_root()/'plug-ins'/'common',
'PIKA_TESTING_PLUGINDIRS_BASENAME_IGNORES=mkgen.pl',
'UI_TEST=yes',
],
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));
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,
* hence their higher importance in measuring similarity.
*/

View File

@ -704,6 +704,7 @@ pika_font_factory_load_names (PikaContainer *container,
{
PangoFontDescription *pfd;
GString *xml;
GString *xml_bold_variant;
gchar *fontformat;
gchar *family = 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>");
/*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,
"<test name=\"family\"><string>%s</string></test>",
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);
g_string_append_printf (xml,
"<edit name=\"fullname\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
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);
family = g_markup_escape_text (family, -1);
g_string_append_printf (xml,
"<edit name=\"family\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
family);
g_string_append_printf (xml_bold_variant,
"<edit name=\"family\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
family);
g_free (family);
escaped_file = g_markup_escape_text (file, -1);
g_string_append_printf (xml,
"<edit name=\"file\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
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);
if (psname != NULL)
@ -824,6 +842,9 @@ pika_font_factory_load_names (PikaContainer *container,
g_string_append_printf (xml,
"<edit name=\"postscriptname\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
psname);
g_string_append_printf (xml_bold_variant,
"<edit name=\"postscriptname\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
psname);
g_free (psname);
}
@ -833,36 +854,64 @@ pika_font_factory_load_names (PikaContainer *container,
g_string_append_printf (xml,
"<edit name=\"style\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
style);
g_string_append_printf (xml_bold_variant,
"<edit name=\"style\" mode=\"assign\" binding=\"strong\"><string>%s</string></edit>",
style);
g_free (style);
}
g_string_append (xml_bold_variant, "<edit name=\"weight\" mode=\"assign\" binding=\"strong\"><const>bold</const></edit>");
if (weight != -1)
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);
if (width != -1)
{
g_string_append_printf (xml,
"<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)
{
g_string_append_printf (xml,
"<edit name=\"slant\" mode=\"assign\" binding=\"strong\"><int>%i</int></edit>",
"<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)
{
g_string_append_printf (xml,
"<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)
{
g_string_append_printf (xml,
"<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_bold_variant, "</match>\n");
FcConfigParseAndLoadFromMemory (FcConfigGetCurrent (), (const FcChar8 *) xml_bold_variant->str, FcTrue);
FcConfigParseAndLoadFromMemory (FcConfigGetCurrent (), (const FcChar8 *) xml->str, FcTrue);
pfd = pango_font_description_from_string (newname);
@ -877,6 +926,7 @@ pika_font_factory_load_names (PikaContainer *container,
pango_font_description_free (pfd);
g_free (newname);
g_string_free (xml, TRUE);
g_string_free (xml_bold_variant, TRUE);
}
if (n_ignored > 0)

View File

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

View File

@ -33,12 +33,14 @@ PikaLayer * text_render (PikaImage *image,
PikaContext *context,
gint text_x,
gint text_y,
const gchar *fontname,
PikaFont *font,
gdouble font_size,
const gchar *text,
gint border,
gboolean antialias);
gboolean text_get_extents (Pika *pika,
const gchar *fontname,
PikaFont *font,
gdouble font_size,
const gchar *text,
gint *width,
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)
#define parent_class pika_selection_options_parent_class
#define parent_class pika_align_options_parent_class
static guint align_options_signals[LAST_SIGNAL] = { 0 };
@ -205,6 +205,8 @@ pika_align_options_finalize (GObject *object)
if (PIKA_CONTEXT (options)->pika)
pika_align_options_image_changed (pika_get_user_context (PIKA_CONTEXT (options)->pika),
NULL, options);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
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,
_("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",
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_context_get_image (pika_get_user_context (PIKA_CONTEXT (options)->pika)),
options);

View File

@ -188,6 +188,11 @@ tool_manager_exit (Pika *pika)
tool_manager_image_changed,
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,
tool_manager->image_clean_handler_id);
pika_container_remove_handler (pika->images,

View File

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

View File

@ -366,6 +366,8 @@ pika_action_history_action_activated (PikaAction *action)
GList *link;
PikaActionHistoryItem *item;
g_return_if_fail (PIKA_IS_ACTION (action));
/* Silently return when called at the wrong time, like when the
* 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;
}
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 *
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);
gchar ** pika_action_get_display_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);

View File

@ -394,7 +394,87 @@ pika_action_group_add_action_with_accel (PikaActionGroup *group,
if ((accelerators != NULL && accelerators[0] != NULL &&
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);
}

View File

@ -282,7 +282,7 @@ pika_brush_select_run_callback (PikaPdbDialog *dialog,
dialog->caller_context,
NULL, error,
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_INT, PIKA_BRUSH_SELECT (dialog)->spacing,
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_palette_set_entry_color (palette, GPOINTER_TO_INT (data), &color);
pika_palette_set_entry_color (palette, GPOINTER_TO_INT (data), &color, FALSE);
}
static void

View File

@ -70,6 +70,10 @@ static gboolean pika_colormap_editor_entry_popup (GtkWidget *wi
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);
G_DEFINE_TYPE_WITH_CODE (PikaColormapEditor, pika_colormap_editor,
PIKA_TYPE_IMAGE_EDITOR,
@ -127,6 +131,9 @@ pika_colormap_editor_constructed (GObject *object)
pika_editor_add_action_button (PIKA_EDITOR (editor), "colormap",
"colormap-edit-color",
NULL);
pika_editor_add_action_button (PIKA_EDITOR (editor), "colormap",
"colormap-delete-color",
NULL);
pika_editor_add_action_button (PIKA_EDITOR (editor), "colormap",
"colormap-add-color-from-fg",
@ -197,6 +204,9 @@ pika_colormap_editor_set_context (PikaDocked *docked,
g_signal_connect (editor->selection, "popup-menu",
G_CALLBACK (pika_colormap_editor_entry_popup),
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));
}
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
pika_colormap_editor_get_index (PikaColormapEditor *editor,
const PikaRGB *search)
@ -411,3 +458,16 @@ pika_colormap_editor_color_clicked (PikaColormapEditor *editor,
else
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

@ -55,6 +55,8 @@ GType pika_colormap_editor_get_type (void) G_GNUC_CONST;
GtkWidget * pika_colormap_editor_new (PikaMenuFactory *menu_factory);
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,
const PikaRGB *search);

View File

@ -57,7 +57,8 @@
enum
{
PROP_0,
PROP_CONTEXT
PROP_CONTEXT,
PROP_INDEX
};
enum
@ -169,6 +170,10 @@ pika_colormap_selection_class_init (PikaColormapSelectionClass* klass)
PIKA_TYPE_CONTEXT,
PIKA_PARAM_READWRITE |
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
@ -285,6 +290,9 @@ pika_colormap_selection_get_property (GObject *object,
case PROP_CONTEXT:
g_value_set_object (value, selection->context);
break;
case PROP_INDEX:
g_value_set_int (value, selection->col_index);
break;
default:
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;
g_object_notify (G_OBJECT (selection), "index");
pika_palette_view_select_entry (PIKA_PALETTE_VIEW (selection->view),
pika_palette_get_entry (palette, index));
@ -789,6 +798,8 @@ pika_colormap_selection_set_palette (PikaColormapSelection *selection)
{
if (selection->active_palette)
{
pika_colormap_selection_set_index (selection, 0, NULL);
g_signal_handlers_disconnect_by_func (selection->active_palette,
G_CALLBACK (gtk_widget_queue_draw),
selection);

View File

@ -899,6 +899,7 @@ pika_container_tree_view_select_items (PikaContainerView *view,
GList *path;
gboolean free_paths = FALSE;
gboolean scroll_to_first = TRUE;
GtkTreePath *focused_path = NULL;
/* If @paths is not set, compute it ourselves. */
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,
tree_view);
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)
{
GtkTreePath *parent_path;
@ -1267,12 +1357,10 @@ pika_container_tree_view_button (GtkWidget *widget,
PikaContainerView *container_view = PIKA_CONTAINER_VIEW (tree_view);
GtkTreeViewColumn *column;
GtkTreePath *path;
gboolean handled = TRUE;
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),
bevent->x, bevent->y,
&path, &column, NULL, NULL))
@ -1283,10 +1371,10 @@ pika_container_tree_view_button (GtkWidget *widget,
GtkCellRenderer *edit_cell = NULL;
GdkRectangle column_area;
GtkTreeIter iter;
gboolean handled = TRUE;
gboolean multisel_mode;
GdkModifierType modifiers = (bevent->state & pika_get_all_modifiers_mask ());
handled = TRUE;
multisel_mode = (gtk_tree_selection_get_mode (tree_view->priv->selection)
== GTK_SELECTION_MULTIPLE);
@ -1301,6 +1389,19 @@ pika_container_tree_view_button (GtkWidget *widget,
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);
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);
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
{
@ -1616,8 +1717,13 @@ pika_container_tree_view_button (GtkWidget *widget,
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

View File

@ -1195,9 +1195,7 @@ pika_container_view_remove (PikaContainerView *view,
if (insert_data)
{
PIKA_CONTAINER_VIEW_GET_IFACE (view)->remove_item (view,
viewable,
insert_data);
PIKA_CONTAINER_VIEW_GET_IFACE (view)->remove_item (view, viewable, insert_data);
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);
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))
{

View File

@ -778,6 +778,31 @@ pika_editor_add_action_button (PikaEditor *editor,
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
pika_editor_set_show_name (PikaEditor *editor,
gboolean show)

View File

@ -89,6 +89,11 @@ GtkWidget * pika_editor_add_action_button (PikaEditor *editor,
const gchar *group_name,
const gchar *action_name,
...) 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,
gboolean show);

View File

@ -90,6 +90,8 @@ static gboolean pika_file_dialog_delete_event (GtkWidget *w
GdkEventAny *event);
static void pika_file_dialog_response (GtkDialog *dialog,
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 void pika_file_dialog_real_save_state (PikaFileDialog *dialog,
const gchar *state_name);
@ -108,7 +110,7 @@ static void pika_file_dialog_progress_set_value (PikaProgress *p
gdouble percentage);
static gdouble pika_file_dialog_progress_get_value (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,
GUserDirectory directory);
@ -229,6 +231,11 @@ pika_file_dialog_class_init (PikaFileDialogClass *klass)
static void
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
@ -372,6 +379,8 @@ pika_file_dialog_constructed (GObject *object)
dialog->progress = pika_progress_box_new ();
gtk_box_pack_end (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
dialog->progress, FALSE, FALSE, 0);
pika_widget_set_native_handle (GTK_WIDGET (dialog), &dialog->window_handle);
}
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 *
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));
}
static guint32
static GBytes *
pika_file_dialog_progress_get_window_id (PikaProgress *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;
GBytes *window_handle;
Pika *pika;
PikaImage *image;

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