Commit 6423529b authored by Sven Neumann's avatar Sven Neumann Committed by Sven Neumann

app/gui/Makefile.am new files implementing a clipboard for image data

2004-07-02  Sven Neumann  <sven@gimp.org>

	* app/gui/Makefile.am
	* app/gui/clipboard.[ch]: new files implementing a clipboard for
	image data based on GDK_SELECTION_CLIPBOARD (bug #133247).

	* app/actions/edit-actions.c
	* app/actions/edit-commands.c: use the new clipboard API.

	* app/gui/gui.c: initialize and shutdown the clipboard.

	* app/core/gimpbuffer.c: cosmetics.

	* app/actions/actions.c
	* app/menus/menus.c: added sanity checks to exit functions.

	* app/display/gimpdisplayshell-dnd.[ch]: let
	gimp_display_shell_drop_svg() take a guchar * buffer.

	* app/widgets/gimpselectiondata.c (gimp_selection_data_get_pixbuf):
	fixed the implementation.
parent 9d19bf2a
2004-07-02 Sven Neumann <sven@gimp.org>
* app/gui/Makefile.am
* app/gui/clipboard.[ch]: new files implementing a clipboard for
image data based on GDK_SELECTION_CLIPBOARD (bug #133247).
* app/actions/edit-actions.c
* app/actions/edit-commands.c: use the new clipboard API.
* app/gui/gui.c: initialize and shutdown the clipboard.
* app/core/gimpbuffer.c: cosmetics.
* app/actions/actions.c
* app/menus/menus.c: added sanity checks to exit functions.
* app/display/gimpdisplayshell-dnd.[ch]: let
gimp_display_shell_drop_svg() take a guchar * buffer.
* app/widgets/gimpselectiondata.c (gimp_selection_data_get_pixbuf):
fixed the implementation.
2004-07-02 Michael Natterer <mitch@gimp.org>
* plug-ins/gimpressionist/Makefile.am
......
......@@ -187,8 +187,6 @@ static GimpActionFactoryEntry action_groups[] =
view_actions_update }
};
static gboolean actions_initialized = FALSE;
/* public functions */
......@@ -198,9 +196,7 @@ actions_init (Gimp *gimp)
gint i;
g_return_if_fail (GIMP_IS_GIMP (gimp));
g_return_if_fail (actions_initialized == FALSE);
actions_initialized = TRUE;
g_return_if_fail (global_action_factory == NULL);
global_action_factory = gimp_action_factory_new (gimp);
......@@ -215,6 +211,8 @@ void
actions_exit (Gimp *gimp)
{
g_return_if_fail (GIMP_IS_GIMP (gimp));
g_return_if_fail (global_action_factory != NULL);
g_return_if_fail (global_action_factory->gimp == gimp);
g_object_unref (global_action_factory);
global_action_factory = NULL;
......
......@@ -36,6 +36,8 @@
#include "widgets/gimpactiongroup.h"
#include "widgets/gimphelp-ids.h"
#include "gui/clipboard.h"
#include "actions.h"
#include "edit-actions.h"
#include "edit-commands.h"
......@@ -196,6 +198,7 @@ edit_actions_update (GimpActionGroup *group,
gchar *undo_name = NULL;
gchar *redo_name = NULL;
gboolean undo_enabled = FALSE;
gboolean clipboard = FALSE;
gimage = action_data_get_image (data);
......@@ -223,8 +226,11 @@ edit_actions_update (GimpActionGroup *group,
g_strdup_printf (_("_Redo %s"),
gimp_object_get_name (GIMP_OBJECT (redo)));
}
clipboard = clipboard_is_available (gimage->gimp);
}
#define SET_LABEL(action,label) \
gimp_action_group_set_action_label (group, action, (label))
#define SET_SENSITIVE(action,condition) \
......@@ -240,14 +246,14 @@ edit_actions_update (GimpActionGroup *group,
g_free (undo_name);
g_free (redo_name);
SET_SENSITIVE ("edit-cut", drawable);
SET_SENSITIVE ("edit-copy", drawable);
SET_SENSITIVE ("edit-paste", gimage && group->gimp->global_buffer);
SET_SENSITIVE ("edit-paste-into", gimage && group->gimp->global_buffer);
SET_SENSITIVE ("edit-cut", drawable);
SET_SENSITIVE ("edit-copy", drawable);
SET_SENSITIVE ("edit-paste", clipboard);
SET_SENSITIVE ("edit-paste-into", clipboard);
SET_SENSITIVE ("edit-named-cut", drawable);
SET_SENSITIVE ("edit-named-copy", drawable);
SET_SENSITIVE ("edit-named-paste", drawable);
SET_SENSITIVE ("edit-named-cut", drawable);
SET_SENSITIVE ("edit-named-copy", drawable);
SET_SENSITIVE ("edit-named-paste", drawable);
SET_SENSITIVE ("edit-clear", drawable);
SET_SENSITIVE ("edit-fill-fg", drawable);
......@@ -265,11 +271,11 @@ static void
edit_actions_buffer_changed (Gimp *gimp,
GimpActionGroup *group)
{
gboolean buf = (gimp->global_buffer != NULL);
gboolean paste = clipboard_is_available (gimp);
gimp_action_group_set_action_sensitive (group, "edit-paste", buf);
gimp_action_group_set_action_sensitive (group, "edit-paste-into", buf);
gimp_action_group_set_action_sensitive (group, "edit-paste-as-new", buf);
gimp_action_group_set_action_sensitive (group, "edit-paste", paste);
gimp_action_group_set_action_sensitive (group, "edit-paste-into", paste);
gimp_action_group_set_action_sensitive (group, "edit-paste-as-new", paste);
}
static void
......
......@@ -42,6 +42,7 @@
#include "widgets/gimpdialogfactory.h"
#include "gui/dialogs.h"
#include "gui/clipboard.h"
#include "actions.h"
#include "edit-commands.h"
......@@ -149,22 +150,24 @@ static void
edit_paste (GimpDisplay *gdisp,
gboolean paste_into)
{
if (gdisp->gimage->gimp->global_buffer)
{
GimpDisplayShell *shell;
gint x, y, width, height;
GimpBuffer *buffer = clipboard_get_buffer (gdisp->gimage->gimp);
shell = GIMP_DISPLAY_SHELL (gdisp->shell);
if (buffer)
{
GimpDisplayShell *shell = GIMP_DISPLAY_SHELL (gdisp->shell);
gint x, y;
gint width, height;
gimp_display_shell_untransform_viewport (shell, &x, &y, &width, &height);
if (gimp_edit_paste (gdisp->gimage,
gimp_image_active_drawable (gdisp->gimage),
gdisp->gimage->gimp->global_buffer,
paste_into, x, y, width, height))
buffer, paste_into, x, y, width, height))
{
gimp_image_flush (gdisp->gimage);
}
g_object_unref (buffer);
}
}
......@@ -192,12 +195,18 @@ void
edit_paste_as_new_cmd_callback (GtkAction *action,
gpointer data)
{
Gimp *gimp;
Gimp *gimp;
GimpBuffer *buffer;
return_if_no_gimp (gimp, data);
if (gimp->global_buffer)
gimp_edit_paste_as_new (gimp, action_data_get_image (data),
gimp->global_buffer);
buffer = clipboard_get_buffer (gimp);
if (buffer)
{
gimp_edit_paste_as_new (gimp, action_data_get_image (data), buffer);
g_object_unref (buffer);
}
}
void
......
......@@ -219,7 +219,7 @@ gimp_buffer_get_new_preview (GimpViewable *viewable,
gint width,
gint height)
{
GimpBuffer *buffer;
GimpBuffer *buffer = GIMP_BUFFER (viewable);
TempBuf *temp_buf;
gint buffer_width;
gint buffer_height;
......@@ -227,7 +227,6 @@ gimp_buffer_get_new_preview (GimpViewable *viewable,
PixelRegion destPR;
gint bytes;
buffer = GIMP_BUFFER (viewable);
buffer_width = tile_manager_width (buffer->tiles);
buffer_height = tile_manager_height (buffer->tiles);
......@@ -277,9 +276,7 @@ static gchar *
gimp_buffer_get_description (GimpViewable *viewable,
gchar **tooltip)
{
GimpBuffer *buffer;
buffer = GIMP_BUFFER (viewable);
GimpBuffer *buffer = GIMP_BUFFER (viewable);
if (tooltip)
*tooltip = NULL;
......
......@@ -151,7 +151,7 @@ gimp_display_shell_drop_vectors (GtkWidget *widget,
void
gimp_display_shell_drop_svg (GtkWidget *widget,
const gchar *svg_data,
const guchar *svg_data,
gsize svg_data_len,
gpointer data)
{
......@@ -164,7 +164,8 @@ gimp_display_shell_drop_svg (GtkWidget *widget,
if (gimage->gimp->busy)
return;
if (! gimp_vectors_import_buffer (gimage, svg_data, svg_data_len,
if (! gimp_vectors_import_buffer (gimage,
(const gchar *) svg_data, svg_data_len,
TRUE, TRUE, -1, &error))
{
g_message (error->message);
......
......@@ -27,7 +27,7 @@ void gimp_display_shell_drop_vectors (GtkWidget *widget,
GimpViewable *viewable,
gpointer data);
void gimp_display_shell_drop_svg (GtkWidget *widget,
const gchar *svg_data,
const guchar *svg_data,
gsize svg_data_length,
gpointer data);
void gimp_display_shell_drop_pattern (GtkWidget *widget,
......
......@@ -7,6 +7,8 @@ dialogs_sources = \
about-dialog.h \
brush-select.c \
brush-select.h \
clipboard.c \
clipboard.h \
color-notebook.c \
color-notebook.h \
convert-dialog.c \
......
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <gtk/gtk.h>
#include "gui-types.h"
#include "base/pixel-region.h"
#include "base/tile-manager.h"
#include "core/gimp.h"
#include "core/gimpbuffer.h"
#include "core/gimpviewable.h"
#include "widgets/gimpdnd.h"
#include "widgets/gimpselectiondata.h"
#include "clipboard.h"
#include "gimp-intl.h"
static const GtkTargetEntry target_entry = GIMP_TARGET_PNG;
static void clipboard_buffer_changed (Gimp *gimp);
static void clipboard_set (Gimp *gimp,
GimpBuffer *buffer);
static void clipboard_get (GtkClipboard *clipboard,
GtkSelectionData *selection_data,
guint info,
Gimp *gimp);
static gboolean clipboard_wait_is_available (void);
void
clipboard_init (Gimp *gimp)
{
g_return_if_fail (GIMP_IS_GIMP (gimp));
clipboard_set (gimp, gimp->global_buffer);
g_signal_connect_object (gimp, "buffer_changed",
G_CALLBACK (clipboard_buffer_changed),
NULL, 0);
}
void
clipboard_exit (Gimp *gimp)
{
g_return_if_fail (GIMP_IS_GIMP (gimp));
g_signal_handlers_disconnect_by_func (gimp,
G_CALLBACK (clipboard_buffer_changed),
NULL);
clipboard_set (gimp, NULL);
}
/**
* clipboard_is_available:
* @gimp: pointer to #Gimp
*
* Tests if there's image data in the clipboard. If the global cut
* buffer of @gimp is empty, this function checks if there's image
* data in %GDK_SELECTION_CLIPBOARD. This is done in a main-loop
* similar to gtk_clipboard_wait_is_text_available(). The same caveats
* apply here.
*
* Return value: %TRUE if there's image data in the clipboard, %FALSE otherwise
**/
gboolean
clipboard_is_available (Gimp *gimp)
{
g_return_val_if_fail (GIMP_IS_GIMP (gimp), FALSE);
if (gimp->global_buffer)
return TRUE;
return clipboard_wait_is_available ();
}
static TileManager *
tile_manager_new_from_pixbuf (GdkPixbuf *pixbuf)
{
TileManager *tiles;
guchar *pixels;
PixelRegion destPR;
gint width;
gint height;
gint rowstride;
gint channels;
gint y;
g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
rowstride = gdk_pixbuf_get_rowstride (pixbuf);
channels = gdk_pixbuf_get_n_channels (pixbuf);
tiles = tile_manager_new (width, height, channels);
pixel_region_init (&destPR, tiles, 0, 0, width, height, TRUE);
for (y = 0, pixels = gdk_pixbuf_get_pixels (pixbuf);
y < height;
y++, pixels += rowstride)
{
pixel_region_set_row (&destPR, 0, y, width, pixels);
}
return tiles;
}
/**
* clipboard_get_buffer:
* @gimp: pointer to #Gimp
*
* Retrieves either image data from %GDK_SELECTION_CLIPBOARD or from
* the global cut buffer of @gimp.
*
* The returned #GimpBuffer needs to be unref'ed when it's no longer
* needed.
*
* Return value: a reference to a #GimpBuffer or %NULL if there's no
* image data
**/
GimpBuffer *
clipboard_get_buffer (Gimp *gimp)
{
GimpBuffer *buffer = NULL;
GtkClipboard *clipboard;
g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL);
clipboard = gtk_clipboard_get_for_display (gdk_display_get_default (),
GDK_SELECTION_CLIPBOARD);
if (clipboard &&
gtk_clipboard_get_owner (clipboard) != G_OBJECT (gimp) &&
clipboard_wait_is_available ())
{
GtkSelectionData *data;
GdkAtom atom = gdk_atom_intern (target_entry.target, FALSE);
gimp_set_busy (gimp);
data = gtk_clipboard_wait_for_contents (clipboard, atom);
if (data)
{
GdkPixbuf *pixbuf = gimp_selection_data_get_pixbuf (data);
gtk_selection_data_free (data);
if (pixbuf)
{
TileManager *tiles = tile_manager_new_from_pixbuf (pixbuf);
g_object_unref (pixbuf);
buffer = gimp_buffer_new (tiles, _("Clipboard"), FALSE);
}
}
gimp_unset_busy (gimp);
}
if (! buffer && gimp->global_buffer)
buffer = g_object_ref (gimp->global_buffer);
return buffer;
}
static void
clipboard_buffer_changed (Gimp *gimp)
{
clipboard_set (gimp, gimp->global_buffer);
}
static void
clipboard_set (Gimp *gimp,
GimpBuffer *buffer)
{
GtkClipboard *clipboard;
clipboard = gtk_clipboard_get_for_display (gdk_display_get_default (),
GDK_SELECTION_CLIPBOARD);
if (! clipboard)
return;
if (buffer)
{
gtk_clipboard_set_with_owner (clipboard,
&target_entry, 1,
(GtkClipboardGetFunc) clipboard_get,
(GtkClipboardClearFunc) NULL,
G_OBJECT (gimp));
}
else if (gtk_clipboard_get_owner (clipboard) == G_OBJECT (gimp))
{
gtk_clipboard_clear (clipboard);
}
}
static gboolean
clipboard_wait_is_available (void)
{
GtkClipboard *clipboard;
gboolean result = FALSE;
clipboard = gtk_clipboard_get_for_display (gdk_display_get_default (),
GDK_SELECTION_CLIPBOARD);
if (clipboard)
{
GtkSelectionData *data;
data = gtk_clipboard_wait_for_contents (clipboard,
gdk_atom_intern ("TARGETS",
FALSE));
if (data)
{
GdkAtom *targets;
gint n_targets;
if (gtk_selection_data_get_targets (data, &targets, &n_targets))
{
GdkAtom atom = gdk_atom_intern (target_entry.target, FALSE);
gint i;
for (i = 0; i < n_targets; i++)
if (targets[i] == atom)
result = TRUE;
g_free (targets);
}
gtk_selection_data_free (data);
}
}
return result;
}
static void
clipboard_get (GtkClipboard *clipboard,
GtkSelectionData *selection_data,
guint info,
Gimp *gimp)
{
GimpBuffer *buffer = gimp->global_buffer;
GdkPixbuf *pixbuf;
gimp_set_busy (gimp);
pixbuf = gimp_viewable_get_pixbuf (GIMP_VIEWABLE (buffer),
gimp_buffer_get_width (buffer),
gimp_buffer_get_height (buffer));
if (pixbuf)
{
GdkAtom atom = gdk_atom_intern (target_entry.target, FALSE);
gimp_selection_data_set_pixbuf (selection_data, atom, pixbuf);
}
else
{
g_warning ("%s: gimp_viewable_get_pixbuf() failed", G_STRFUNC);
}
gimp_unset_busy (gimp);
}
/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef __CLIPBOARD_H__
#define __CLIPBOARD_H__
void clipboard_init (Gimp *gimp);
void clipboard_exit (Gimp *gimp);
gboolean clipboard_is_available (Gimp *gimp);
GimpBuffer * clipboard_get_buffer (Gimp *gimp);
#endif /* __CLIPBOARD_H__ */
......@@ -62,6 +62,7 @@
#include "menus/menus.h"
#include "clipboard.h"
#include "color-history.h"
#include "dialogs.h"
#include "gui.h"
......@@ -324,6 +325,7 @@ gui_restore_callback (Gimp *gimp,
actions_init (gimp);
menus_init (gimp);
clipboard_init (gimp);
render_init (gimp);
dialogs_init (gimp);
......@@ -453,6 +455,7 @@ gui_exit_after_callback (Gimp *gimp,
g_object_unref (image_ui_manager);
image_ui_manager = NULL;
clipboard_exit (gimp);
menus_exit (gimp);
actions_exit (gimp);
render_exit (gimp);
......
......@@ -50,20 +50,13 @@ static void menu_can_change_accels (GimpGuiConfig *config);
GimpMenuFactory *global_menu_factory = NULL;
/* private variables */
static gboolean menus_initialized = FALSE;
/* public functions */
void
menus_init (Gimp *gimp)
{
g_return_if_fail (GIMP_IS_GIMP (gimp));
g_return_if_fail (menus_initialized == FALSE);
menus_initialized = TRUE;
g_return_if_fail (global_menu_factory == NULL);
/* We need to make sure the property is installed before using it */
g_type_class_ref (GTK_TYPE_MENU);
......@@ -288,6 +281,9 @@ void
menus_exit (Gimp *gimp)
{
g_return_if_fail (GIMP_IS_GIMP (gimp));
g_return_if_fail (global_menu_factory != NULL);
g_return_if_fail (global_menu_factory->gimp == gimp);
g_object_unref (global_menu_factory);
global_menu_factory = NULL;
......
......@@ -421,7 +421,9 @@ gimp_selection_data_set_pixbuf (GtkSelectionData *selection,
g_return_if_fail (atom != GDK_NONE);
g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
if (gdk_pixbuf_save_to_buffer (pixbuf, &buffer, &buffer_size, "png", &error))
if (gdk_pixbuf_save_to_buffer (pixbuf,
&buffer, &buffer_size, "png",
&error, NULL))
{
gtk_selection_data_set (selection, atom,
8, (guchar *) buffer, buffer_size);
......@@ -452,9 +454,11 @@ gimp_selection_data_get_pixbuf (GtkSelectionData *selection)
loader = gdk_pixbuf_loader_new ();
if (gdk_pixbuf_loader_write (loader,
selection->data, selection->length, &error))
selection->data, selection->length, &error) &&
gdk_pixbuf_loader_close (loader, &error))
{
pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
g_object_ref (pixbuf);
}
else
{
......
......@@ -135,6 +135,7 @@ app/file/file-utils.c
app/gui/about-dialog.c
app/gui/brush-select.c
app/gui/clipboard.c
<