forked from AuroraMiddleware/gtk
Add infrastructure for copy/paste and DND of rich text for GtkTextBuffer.
2006-03-07 Michael Natterer <mitch@imendio.com> Add infrastructure for copy/paste and DND of rich text for GtkTextBuffer. Fixes bug #324177. * gtk/gtktextbufferrichtext.[ch]: new files implementing a per-buffer registry of rich text formats. * gtk/gtk.h: #include gtktextbufferrichtext.h * gtk/gtktextbufferserialize.[ch]: new files implementing an internal serialization format that can handle all of a text buffer's tags and pixbufs. It's not useful for anything except tranfer between instances of GtkTextBuffer (Anders Carlsson). * gtk/Makefile.am: build the new files. * gtk/gtkclipboard.[ch]: added convenience APIs for rich text, just as they exist for plain text and pixbufs. * gtk/gtkselection.[ch]: added rich text convenience APIs here too. Return the target list from gtk_target_list_ref(). Register GtkTargetList as boxed type. Added gtk_target_table_new_from_list() and gtk_target_table_free(), which make converting between GtkTargetList and arrays of GtkTargetEntry considerably easier. * gtk/gtktextutil.[ch]: added _gtk_text_util_create_rich_drag_icon() which creates a fancy rich text icon (Matthias Clasen). * gtk/gtktextbuffer.[ch]: use all the new stuff above and implement copy and paste of rich text. Added APIs for getting the target lists used for copy and paste. Added public enum GtkTextBufferTargetInfo which contains the "info" IDs associated with the entries of the target lists. * gtk/gtktextview.c: use the new rich text APIs and GtkTextBuffer's new target list API to enable DND of rich text chunks. * gtk/gtk.symbols: export all the new symbols added. * tests/testtext.c: added rich text testing stuff.
This commit is contained in:
parent
1f5c294851
commit
6c1d990adc
44
ChangeLog
44
ChangeLog
@ -1,3 +1,47 @@
|
||||
2006-03-07 Michael Natterer <mitch@imendio.com>
|
||||
|
||||
Add infrastructure for copy/paste and DND of rich text for
|
||||
GtkTextBuffer. Fixes bug #324177.
|
||||
|
||||
* gtk/gtktextbufferrichtext.[ch]: new files implementing a
|
||||
per-buffer registry of rich text formats.
|
||||
|
||||
* gtk/gtk.h: #include gtktextbufferrichtext.h
|
||||
|
||||
* gtk/gtktextbufferserialize.[ch]: new files implementing an
|
||||
internal serialization format that can handle all of a text
|
||||
buffer's tags and pixbufs. It's not useful for anything except
|
||||
tranfer between instances of GtkTextBuffer (Anders Carlsson).
|
||||
|
||||
* gtk/Makefile.am: build the new files.
|
||||
|
||||
* gtk/gtkclipboard.[ch]: added convenience APIs for rich text,
|
||||
just as they exist for plain text and pixbufs.
|
||||
|
||||
* gtk/gtkselection.[ch]: added rich text convenience APIs here
|
||||
too. Return the target list from gtk_target_list_ref(). Register
|
||||
GtkTargetList as boxed type. Added
|
||||
gtk_target_table_new_from_list() and gtk_target_table_free(),
|
||||
which make converting between GtkTargetList and arrays of
|
||||
GtkTargetEntry considerably easier.
|
||||
|
||||
* gtk/gtktextutil.[ch]: added _gtk_text_util_create_rich_drag_icon()
|
||||
which creates a fancy rich text icon (Matthias Clasen).
|
||||
|
||||
* gtk/gtktextbuffer.[ch]: use all the new stuff above and
|
||||
implement copy and paste of rich text. Added APIs for getting the
|
||||
target lists used for copy and paste. Added public enum
|
||||
GtkTextBufferTargetInfo which contains the "info" IDs associated
|
||||
with the entries of the target lists.
|
||||
|
||||
* gtk/gtktextview.c: use the new rich text APIs and
|
||||
GtkTextBuffer's new target list API to enable DND of rich text
|
||||
chunks.
|
||||
|
||||
* gtk/gtk.symbols: export all the new symbols added.
|
||||
|
||||
* tests/testtext.c: added rich text testing stuff.
|
||||
|
||||
2006-03-06 Matthias Clasen <mclasen@redhat.com>
|
||||
|
||||
* gtk/gtktextview.c (text_window_invalidate_cursors): Take
|
||||
|
@ -1,3 +1,47 @@
|
||||
2006-03-07 Michael Natterer <mitch@imendio.com>
|
||||
|
||||
Add infrastructure for copy/paste and DND of rich text for
|
||||
GtkTextBuffer. Fixes bug #324177.
|
||||
|
||||
* gtk/gtktextbufferrichtext.[ch]: new files implementing a
|
||||
per-buffer registry of rich text formats.
|
||||
|
||||
* gtk/gtk.h: #include gtktextbufferrichtext.h
|
||||
|
||||
* gtk/gtktextbufferserialize.[ch]: new files implementing an
|
||||
internal serialization format that can handle all of a text
|
||||
buffer's tags and pixbufs. It's not useful for anything except
|
||||
tranfer between instances of GtkTextBuffer (Anders Carlsson).
|
||||
|
||||
* gtk/Makefile.am: build the new files.
|
||||
|
||||
* gtk/gtkclipboard.[ch]: added convenience APIs for rich text,
|
||||
just as they exist for plain text and pixbufs.
|
||||
|
||||
* gtk/gtkselection.[ch]: added rich text convenience APIs here
|
||||
too. Return the target list from gtk_target_list_ref(). Register
|
||||
GtkTargetList as boxed type. Added
|
||||
gtk_target_table_new_from_list() and gtk_target_table_free(),
|
||||
which make converting between GtkTargetList and arrays of
|
||||
GtkTargetEntry considerably easier.
|
||||
|
||||
* gtk/gtktextutil.[ch]: added _gtk_text_util_create_rich_drag_icon()
|
||||
which creates a fancy rich text icon (Matthias Clasen).
|
||||
|
||||
* gtk/gtktextbuffer.[ch]: use all the new stuff above and
|
||||
implement copy and paste of rich text. Added APIs for getting the
|
||||
target lists used for copy and paste. Added public enum
|
||||
GtkTextBufferTargetInfo which contains the "info" IDs associated
|
||||
with the entries of the target lists.
|
||||
|
||||
* gtk/gtktextview.c: use the new rich text APIs and
|
||||
GtkTextBuffer's new target list API to enable DND of rich text
|
||||
chunks.
|
||||
|
||||
* gtk/gtk.symbols: export all the new symbols added.
|
||||
|
||||
* tests/testtext.c: added rich text testing stuff.
|
||||
|
||||
2006-03-06 Matthias Clasen <mclasen@redhat.com>
|
||||
|
||||
* gtk/gtktextview.c (text_window_invalidate_cursors): Take
|
||||
|
@ -248,6 +248,7 @@ gtk_public_h_sources = \
|
||||
gtktearoffmenuitem.h \
|
||||
gtktext.h \
|
||||
gtktextbuffer.h \
|
||||
gtktextbufferrichtext.h \
|
||||
gtktextchild.h \
|
||||
gtktextdisplay.h \
|
||||
gtktextiter.h \
|
||||
@ -481,6 +482,9 @@ gtk_c_sources = \
|
||||
gtktext.c \
|
||||
gtktextbtree.c \
|
||||
gtktextbuffer.c \
|
||||
gtktextbufferrichtext.c \
|
||||
gtktextbufferserialize.c\
|
||||
gtktextbufferserialize.h\
|
||||
gtktextchild.c \
|
||||
gtktextdisplay.c \
|
||||
gtktextiter.c \
|
||||
|
@ -160,6 +160,7 @@
|
||||
#include <gtk/gtktearoffmenuitem.h>
|
||||
#include <gtk/gtktext.h>
|
||||
#include <gtk/gtktextbuffer.h>
|
||||
#include <gtk/gtktextbufferrichtext.h>
|
||||
#include <gtk/gtktextview.h>
|
||||
#include <gtk/gtktipsquery.h>
|
||||
#include <gtk/gtktoggleaction.h>
|
||||
|
@ -600,6 +600,7 @@ gtk_clipboard_get_owner
|
||||
gtk_clipboard_get_type G_GNUC_CONST
|
||||
gtk_clipboard_request_contents
|
||||
gtk_clipboard_request_image
|
||||
gtk_clipboard_request_rich_text
|
||||
gtk_clipboard_request_targets
|
||||
gtk_clipboard_request_text
|
||||
gtk_clipboard_set_can_store
|
||||
@ -610,9 +611,11 @@ gtk_clipboard_set_with_owner
|
||||
gtk_clipboard_store
|
||||
gtk_clipboard_wait_for_contents
|
||||
gtk_clipboard_wait_for_image
|
||||
gtk_clipboard_wait_for_rich_text
|
||||
gtk_clipboard_wait_for_targets
|
||||
gtk_clipboard_wait_for_text
|
||||
gtk_clipboard_wait_is_image_available
|
||||
gtk_clipboard_wait_is_rich_text_available
|
||||
gtk_clipboard_wait_is_text_available
|
||||
gtk_clipboard_wait_is_target_available
|
||||
#endif
|
||||
@ -2607,6 +2610,23 @@ gtk_rc_style_unref
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if IN_HEADER(__GTK_TEXT_BUFFER_RICH_TEXT_H__)
|
||||
#if IN_FILE(__GTK_TEXT_BUFFER_RICH_TEXT_C__)
|
||||
gtk_text_buffer_deserialize
|
||||
gtk_text_buffer_deserialize_get_can_create_tags
|
||||
gtk_text_buffer_deserialize_set_can_create_tags
|
||||
gtk_text_buffer_get_deserialize_formats
|
||||
gtk_text_buffer_get_serialize_formats
|
||||
gtk_text_buffer_register_deserialize_format
|
||||
gtk_text_buffer_register_deserialize_tagset
|
||||
gtk_text_buffer_register_serialize_format
|
||||
gtk_text_buffer_register_serialize_tagset
|
||||
gtk_text_buffer_serialize
|
||||
gtk_text_buffer_unregister_deserialize_format
|
||||
gtk_text_buffer_unregister_serialize_format
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if IN_HEADER(__GTK_RULER_H__)
|
||||
#if IN_FILE(__GTK_RULER_C__)
|
||||
gtk_ruler_draw_pos
|
||||
@ -2678,9 +2698,11 @@ gtk_selection_data_set_pixbuf
|
||||
gtk_selection_data_set_text
|
||||
gtk_selection_data_set_uris
|
||||
gtk_selection_data_targets_include_image
|
||||
gtk_selection_data_targets_include_rich_text
|
||||
gtk_selection_data_targets_include_text
|
||||
gtk_selection_data_targets_include_uri
|
||||
gtk_targets_include_image
|
||||
gtk_targets_include_rich_text
|
||||
gtk_targets_include_text
|
||||
gtk_targets_include_uri
|
||||
gtk_selection_owner_set
|
||||
@ -2688,14 +2710,18 @@ gtk_selection_owner_set_for_display
|
||||
gtk_selection_remove_all
|
||||
gtk_target_list_add
|
||||
gtk_target_list_add_image_targets
|
||||
gtk_target_list_add_rich_text_targets
|
||||
gtk_target_list_add_table
|
||||
gtk_target_list_add_text_targets
|
||||
gtk_target_list_add_uri_targets
|
||||
gtk_target_list_find
|
||||
gtk_target_list_get_type G_GNUC_CONST
|
||||
gtk_target_list_new
|
||||
gtk_target_list_ref
|
||||
gtk_target_list_remove
|
||||
gtk_target_list_unref
|
||||
gtk_target_table_new_from_list
|
||||
gtk_target_table_free
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@ -2934,6 +2960,7 @@ gtk_text_buffer_delete_selection
|
||||
gtk_text_buffer_end_user_action
|
||||
gtk_text_buffer_get_bounds
|
||||
gtk_text_buffer_get_char_count
|
||||
gtk_text_buffer_get_copy_target_list
|
||||
gtk_text_buffer_get_end_iter
|
||||
gtk_text_buffer_get_has_selection
|
||||
gtk_text_buffer_get_insert
|
||||
@ -2946,6 +2973,7 @@ gtk_text_buffer_get_iter_at_offset
|
||||
gtk_text_buffer_get_line_count
|
||||
gtk_text_buffer_get_mark
|
||||
gtk_text_buffer_get_modified
|
||||
gtk_text_buffer_get_paste_target_list
|
||||
gtk_text_buffer_get_selection_bound
|
||||
gtk_text_buffer_get_selection_bounds
|
||||
gtk_text_buffer_get_slice
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "gtkinvisible.h"
|
||||
#include "gtkmain.h"
|
||||
#include "gtkmarshalers.h"
|
||||
#include "gtktextbufferrichtext.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkalias.h"
|
||||
|
||||
@ -47,6 +48,7 @@ typedef struct _GtkClipboardClass GtkClipboardClass;
|
||||
|
||||
typedef struct _RequestContentsInfo RequestContentsInfo;
|
||||
typedef struct _RequestTextInfo RequestTextInfo;
|
||||
typedef struct _RequestRichTextInfo RequestRichTextInfo;
|
||||
typedef struct _RequestImageInfo RequestImageInfo;
|
||||
typedef struct _RequestTargetsInfo RequestTargetsInfo;
|
||||
|
||||
@ -97,6 +99,15 @@ struct _RequestTextInfo
|
||||
gpointer user_data;
|
||||
};
|
||||
|
||||
struct _RequestRichTextInfo
|
||||
{
|
||||
GtkClipboardRichTextReceivedFunc callback;
|
||||
GdkAtom *atoms;
|
||||
gint n_atoms;
|
||||
gint current_atom;
|
||||
gpointer user_data;
|
||||
};
|
||||
|
||||
struct _RequestImageInfo
|
||||
{
|
||||
GtkClipboardImageReceivedFunc callback;
|
||||
@ -927,7 +938,7 @@ request_text_received_func (GtkClipboard *clipboard,
|
||||
RequestTextInfo *info = data;
|
||||
gchar *result = NULL;
|
||||
|
||||
result = gtk_selection_data_get_text (selection_data);
|
||||
result = (gchar *) gtk_selection_data_get_text (selection_data);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
@ -992,6 +1003,80 @@ gtk_clipboard_request_text (GtkClipboard *clipboard,
|
||||
info);
|
||||
}
|
||||
|
||||
static void
|
||||
request_rich_text_received_func (GtkClipboard *clipboard,
|
||||
GtkSelectionData *selection_data,
|
||||
gpointer data)
|
||||
{
|
||||
RequestRichTextInfo *info = data;
|
||||
guint8 *result = NULL;
|
||||
gsize length = 0;
|
||||
|
||||
result = selection_data->data;
|
||||
length = selection_data->length;
|
||||
|
||||
info->current_atom++;
|
||||
|
||||
if ((!result || length < 1) && (info->current_atom < info->n_atoms))
|
||||
{
|
||||
gtk_clipboard_request_contents (clipboard, info->atoms[info->current_atom],
|
||||
request_rich_text_received_func,
|
||||
info);
|
||||
return;
|
||||
}
|
||||
|
||||
info->callback (clipboard, selection_data->target, result, length,
|
||||
info->user_data);
|
||||
g_free (info->atoms);
|
||||
g_free (info);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_clipboard_request_rich_text:
|
||||
* @clipboard: a #GtkClipboard
|
||||
* @buffer: a #GtkTextBuffer
|
||||
* @callback: a function to call when the text is received,
|
||||
* or the retrieval fails. (It will always be called
|
||||
* one way or the other.)
|
||||
* @user_data: user data to pass to @callback.
|
||||
*
|
||||
* Requests the contents of the clipboard as rich text. When the rich
|
||||
* text is later received, @callback will be called.
|
||||
*
|
||||
* The @text parameter to @callback will contain the resulting rich
|
||||
* text if the request succeeded, or %NULL if it failed. The @length
|
||||
* parameter will contain @text's length. This function can fail for
|
||||
* various reasons, in particular if the clipboard was empty or if the
|
||||
* contents of the clipboard could not be converted into rich text form.
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
void
|
||||
gtk_clipboard_request_rich_text (GtkClipboard *clipboard,
|
||||
GtkTextBuffer *buffer,
|
||||
GtkClipboardRichTextReceivedFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
RequestRichTextInfo *info;
|
||||
|
||||
g_return_if_fail (clipboard != NULL);
|
||||
g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
|
||||
g_return_if_fail (callback != NULL);
|
||||
|
||||
info = g_new (RequestRichTextInfo, 1);
|
||||
info->callback = callback;
|
||||
info->atoms = NULL;
|
||||
info->n_atoms = 0;
|
||||
info->current_atom = 0;
|
||||
info->user_data = user_data;
|
||||
|
||||
info->atoms = gtk_text_buffer_get_deserialize_formats (buffer, &info->n_atoms);
|
||||
|
||||
gtk_clipboard_request_contents (clipboard, info->atoms[info->current_atom],
|
||||
request_rich_text_received_func,
|
||||
info);
|
||||
}
|
||||
|
||||
static void
|
||||
request_image_received_func (GtkClipboard *clipboard,
|
||||
GtkSelectionData *selection_data,
|
||||
@ -1143,6 +1228,8 @@ typedef struct
|
||||
{
|
||||
GMainLoop *loop;
|
||||
gpointer data;
|
||||
GdkAtom format; /* used by rich text */
|
||||
gsize length; /* used by rich text */
|
||||
} WaitResults;
|
||||
|
||||
static void
|
||||
@ -1254,6 +1341,75 @@ gtk_clipboard_wait_for_text (GtkClipboard *clipboard)
|
||||
return results.data;
|
||||
}
|
||||
|
||||
static void
|
||||
clipboard_rich_text_received_func (GtkClipboard *clipboard,
|
||||
GdkAtom format,
|
||||
const guint8 *text,
|
||||
gsize length,
|
||||
gpointer data)
|
||||
{
|
||||
WaitResults *results = data;
|
||||
|
||||
results->data = g_memdup (text, length);
|
||||
results->format = format;
|
||||
results->length = length;
|
||||
g_main_loop_quit (results->loop);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_clipboard_wait_for_rich_text:
|
||||
* @clipboard: a #GtkClipboard
|
||||
* @buffer: a #GtkTextBuffer
|
||||
* @length: return location for the length of the returned data
|
||||
*
|
||||
* Requests the contents of the clipboard as rich text. This function
|
||||
* waits for the data to be received using the main loop, so events,
|
||||
* timeouts, etc, may be dispatched during the wait.
|
||||
*
|
||||
* Return value: a newly-allocated binary block of data which must
|
||||
* be freed with g_free(), or %NULL if retrieving
|
||||
* the selection data failed. (This could happen
|
||||
* for various reasons, in particular if the
|
||||
* clipboard was empty or if the contents of the
|
||||
* clipboard could not be converted into text form.)
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
guint8 *
|
||||
gtk_clipboard_wait_for_rich_text (GtkClipboard *clipboard,
|
||||
GtkTextBuffer *buffer,
|
||||
GdkAtom *format,
|
||||
gsize *length)
|
||||
{
|
||||
WaitResults results;
|
||||
|
||||
g_return_val_if_fail (clipboard != NULL, NULL);
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
|
||||
g_return_val_if_fail (format != NULL, NULL);
|
||||
g_return_val_if_fail (length != NULL, NULL);
|
||||
|
||||
results.data = NULL;
|
||||
results.loop = g_main_loop_new (NULL, TRUE);
|
||||
|
||||
gtk_clipboard_request_rich_text (clipboard, buffer,
|
||||
clipboard_rich_text_received_func,
|
||||
&results);
|
||||
|
||||
if (g_main_loop_is_running (results.loop))
|
||||
{
|
||||
GDK_THREADS_LEAVE ();
|
||||
g_main_loop_run (results.loop);
|
||||
GDK_THREADS_ENTER ();
|
||||
}
|
||||
|
||||
g_main_loop_unref (results.loop);
|
||||
|
||||
*format = results.format;
|
||||
*length = results.length;
|
||||
|
||||
return results.data;
|
||||
}
|
||||
|
||||
static void
|
||||
clipboard_image_received_func (GtkClipboard *clipboard,
|
||||
GdkPixbuf *pixbuf,
|
||||
@ -1361,6 +1517,45 @@ gtk_clipboard_wait_is_text_available (GtkClipboard *clipboard)
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_clipboard_wait_is_rich_text_available:
|
||||
* @clipboard: a #GtkClipboard
|
||||
* @buffer: a #GtkTextBuffer
|
||||
*
|
||||
* Test to see if there is rich text available to be pasted
|
||||
* This is done by requesting the TARGETS atom and checking
|
||||
* if it contains any of the supported rich text targets. This function
|
||||
* waits for the data to be received using the main loop, so events,
|
||||
* timeouts, etc, may be dispatched during the wait.
|
||||
*
|
||||
* This function is a little faster than calling
|
||||
* gtk_clipboard_wait_for_rich_text() since it doesn't need to retrieve
|
||||
* the actual text.
|
||||
*
|
||||
* Return value: %TRUE is there is rich text available, %FALSE otherwise.
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
gboolean
|
||||
gtk_clipboard_wait_is_rich_text_available (GtkClipboard *clipboard,
|
||||
GtkTextBuffer *buffer)
|
||||
{
|
||||
GtkSelectionData *data;
|
||||
gboolean result = FALSE;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_CLIPBOARD (clipboard), FALSE);
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
|
||||
|
||||
data = gtk_clipboard_wait_for_contents (clipboard, gdk_atom_intern_static_string ("TARGETS"));
|
||||
if (data)
|
||||
{
|
||||
result = gtk_selection_data_targets_include_rich_text (data, buffer);
|
||||
gtk_selection_data_free (data);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_clipboard_wait_is_image_available:
|
||||
* @clipboard: a #GtkClipboard
|
||||
|
@ -36,6 +36,11 @@ typedef void (* GtkClipboardReceivedFunc) (GtkClipboard *clipboard,
|
||||
typedef void (* GtkClipboardTextReceivedFunc) (GtkClipboard *clipboard,
|
||||
const gchar *text,
|
||||
gpointer data);
|
||||
typedef void (* GtkClipboardRichTextReceivedFunc) (GtkClipboard *clipboard,
|
||||
GdkAtom format,
|
||||
const guint8 *text,
|
||||
gsize length,
|
||||
gpointer data);
|
||||
typedef void (* GtkClipboardImageReceivedFunc) (GtkClipboard *clipboard,
|
||||
GdkPixbuf *pixbuf,
|
||||
gpointer data);
|
||||
@ -93,6 +98,10 @@ void gtk_clipboard_request_contents (GtkClipboard *clipboard,
|
||||
void gtk_clipboard_request_text (GtkClipboard *clipboard,
|
||||
GtkClipboardTextReceivedFunc callback,
|
||||
gpointer user_data);
|
||||
void gtk_clipboard_request_rich_text (GtkClipboard *clipboard,
|
||||
GtkTextBuffer *buffer,
|
||||
GtkClipboardRichTextReceivedFunc callback,
|
||||
gpointer user_data);
|
||||
void gtk_clipboard_request_image (GtkClipboard *clipboard,
|
||||
GtkClipboardImageReceivedFunc callback,
|
||||
gpointer user_data);
|
||||
@ -103,12 +112,18 @@ void gtk_clipboard_request_targets (GtkClipboard *clipboard,
|
||||
GtkSelectionData *gtk_clipboard_wait_for_contents (GtkClipboard *clipboard,
|
||||
GdkAtom target);
|
||||
gchar * gtk_clipboard_wait_for_text (GtkClipboard *clipboard);
|
||||
guint8 * gtk_clipboard_wait_for_rich_text (GtkClipboard *clipboard,
|
||||
GtkTextBuffer *buffer,
|
||||
GdkAtom *format,
|
||||
gsize *size);
|
||||
GdkPixbuf * gtk_clipboard_wait_for_image (GtkClipboard *clipboard);
|
||||
gboolean gtk_clipboard_wait_for_targets (GtkClipboard *clipboard,
|
||||
GdkAtom **targets,
|
||||
gint *n_targets);
|
||||
|
||||
gboolean gtk_clipboard_wait_is_text_available (GtkClipboard *clipboard);
|
||||
gboolean gtk_clipboard_wait_is_rich_text_available (GtkClipboard *clipboard,
|
||||
GtkTextBuffer *buffer);
|
||||
gboolean gtk_clipboard_wait_is_image_available (GtkClipboard *clipboard);
|
||||
gboolean gtk_clipboard_wait_is_target_available (GtkClipboard *clipboard,
|
||||
GdkAtom target);
|
||||
|
@ -58,6 +58,7 @@
|
||||
|
||||
#include "gtkmain.h"
|
||||
#include "gtkselection.h"
|
||||
#include "gtktextbufferrichtext.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gdk-pixbuf/gdk-pixbuf.h"
|
||||
|
||||
@ -213,13 +214,16 @@ gtk_target_list_new (const GtkTargetEntry *targets,
|
||||
*
|
||||
* Increases the reference count of a #GtkTargetList by one.
|
||||
*
|
||||
* Return value: the passed in #GtkTargetList.
|
||||
**/
|
||||
void
|
||||
GtkTargetList *
|
||||
gtk_target_list_ref (GtkTargetList *list)
|
||||
{
|
||||
g_return_if_fail (list != NULL);
|
||||
g_return_val_if_fail (list != NULL, NULL);
|
||||
|
||||
list->ref_count++;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -338,6 +342,45 @@ gtk_target_list_add_text_targets (GtkTargetList *list,
|
||||
gtk_target_list_add (list, text_plain_atom, 0, info);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_target_list_add_rich_text_targets:
|
||||
* @list: a #GtkTargetList
|
||||
* @info: an ID that will be passed back to the application
|
||||
* @deserializable: if %TRUE, then deserializable rich text formats
|
||||
* will be added, serializable formats otherwise.
|
||||
* @buffer: a #GtkTextBuffer.
|
||||
*
|
||||
* Appends the rich text targets registered with
|
||||
* gtk_text_buffer_register_serialize_format() or
|
||||
* gtk_text_buffer_register_deserialize_format() to the target list. All
|
||||
* targets are added with the same @info.
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
void
|
||||
gtk_target_list_add_rich_text_targets (GtkTargetList *list,
|
||||
guint info,
|
||||
gboolean deserializable,
|
||||
GtkTextBuffer *buffer)
|
||||
{
|
||||
GdkAtom *atoms;
|
||||
gint n_atoms;
|
||||
gint i;
|
||||
|
||||
g_return_if_fail (list != NULL);
|
||||
g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
|
||||
|
||||
if (deserializable)
|
||||
atoms = gtk_text_buffer_get_deserialize_formats (buffer, &n_atoms);
|
||||
else
|
||||
atoms = gtk_text_buffer_get_serialize_formats (buffer, &n_atoms);
|
||||
|
||||
for (i = 0; i < n_atoms; i++)
|
||||
gtk_target_list_add (list, atoms[i], 0, info);
|
||||
|
||||
g_free (atoms);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_target_list_add_image_targets:
|
||||
* @list: a #GtkTargetList
|
||||
@ -514,6 +557,72 @@ gtk_target_list_find (GtkTargetList *list,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_target_table_new_from_list:
|
||||
* @list: a #GtkTargetList
|
||||
* @n_targets: return location for the number ot targets in the table
|
||||
*
|
||||
* This function creates an #GtkTargetEntry array that contains the
|
||||
* same targets as the passed %list. The returned table is newly
|
||||
* allocated and should be freed using gtk_target_table_free() when no
|
||||
* longer needed.
|
||||
*
|
||||
* Return value: the new table.
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
GtkTargetEntry *
|
||||
gtk_target_table_new_from_list (GtkTargetList *list,
|
||||
gint *n_targets)
|
||||
{
|
||||
GtkTargetEntry *targets;
|
||||
GList *tmp_list;
|
||||
gint i;
|
||||
|
||||
g_return_val_if_fail (list != NULL, NULL);
|
||||
g_return_val_if_fail (n_targets != NULL, NULL);
|
||||
|
||||
*n_targets = g_list_length (list->list);
|
||||
targets = g_new0 (GtkTargetEntry, *n_targets);
|
||||
|
||||
for (i = 0, tmp_list = list->list;
|
||||
i < *n_targets;
|
||||
i++, tmp_list = g_list_next (tmp_list))
|
||||
{
|
||||
GtkTargetPair *pair = tmp_list->data;
|
||||
|
||||
targets[i].target = gdk_atom_name (pair->target);
|
||||
targets[i].flags = pair->flags;
|
||||
targets[i].info = pair->info;
|
||||
}
|
||||
|
||||
return targets;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_target_table_free:
|
||||
* @targets: a #GtkTargetEntry array
|
||||
* @n_targets: the number of entries in the array
|
||||
*
|
||||
* This function frees a target table as returned by
|
||||
* gtk_target_table_new_from_list()
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
void
|
||||
gtk_target_table_free (GtkTargetEntry *targets,
|
||||
gint n_targets)
|
||||
{
|
||||
gint i;
|
||||
|
||||
g_return_if_fail (targets == NULL || n_targets > 0);
|
||||
|
||||
for (i = 0; i < n_targets; i++)
|
||||
g_free (targets[i].target);
|
||||
|
||||
g_free (targets);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_selection_owner_set_for_display:
|
||||
* @display: the #Gdkdisplay where the selection is set
|
||||
@ -1609,6 +1718,53 @@ gtk_targets_include_text (GdkAtom *targets,
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_targets_include_rich_text:
|
||||
* @targets: an array of #GdkAtom<!-- -->s
|
||||
* @n_targets: the length of @targets
|
||||
* @buffer: a #GtkTextBuffer
|
||||
*
|
||||
* Determines if any of the targets in @targets can be used to
|
||||
* provide rich text.
|
||||
*
|
||||
* Return value: %TRUE if @targets include a suitable target for rich text,
|
||||
* otherwise %FALSE.
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
gboolean
|
||||
gtk_targets_include_rich_text (GdkAtom *targets,
|
||||
gint n_targets,
|
||||
GtkTextBuffer *buffer)
|
||||
{
|
||||
GdkAtom *rich_targets;
|
||||
gint n_rich_targets;
|
||||
gint i, j;
|
||||
gboolean result = FALSE;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
|
||||
|
||||
rich_targets = gtk_text_buffer_get_deserialize_formats (buffer,
|
||||
&n_rich_targets);
|
||||
|
||||
for (i = 0; i < n_targets; i++)
|
||||
{
|
||||
for (j = 0; j < n_rich_targets; j++)
|
||||
{
|
||||
if (targets[i] == rich_targets[j])
|
||||
{
|
||||
result = TRUE;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
g_free (rich_targets);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_selection_data_targets_include_text:
|
||||
* @selection_data: a #GtkSelectionData object
|
||||
@ -1638,6 +1794,42 @@ gtk_selection_data_targets_include_text (GtkSelectionData *selection_data)
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_selection_data_targets_include_rich_text:
|
||||
* @selection_data: a #GtkSelectionData object
|
||||
* @buffer: a #GtkTextBuffer
|
||||
*
|
||||
* Given a #GtkSelectionData object holding a list of targets,
|
||||
* determines if any of the targets in @targets can be used to
|
||||
* provide rich text.
|
||||
*
|
||||
* Return value: %TRUE if @selection_data holds a list of targets,
|
||||
* and a suitable target for rich text is included,
|
||||
* otherwise %FALSE.
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
gboolean
|
||||
gtk_selection_data_targets_include_rich_text (GtkSelectionData *selection_data,
|
||||
GtkTextBuffer *buffer)
|
||||
{
|
||||
GdkAtom *targets;
|
||||
gint n_targets;
|
||||
gboolean result = FALSE;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
|
||||
|
||||
init_atoms ();
|
||||
|
||||
if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets))
|
||||
{
|
||||
result = gtk_targets_include_rich_text (targets, n_targets, buffer);
|
||||
g_free (targets);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_targets_include_image:
|
||||
* @targets: an array of #GdkAtom<!-- -->s
|
||||
@ -2756,6 +2948,19 @@ gtk_selection_data_get_type (void)
|
||||
return our_type;
|
||||
}
|
||||
|
||||
GType
|
||||
gtk_target_list_get_type (void)
|
||||
{
|
||||
static GType our_type = 0;
|
||||
|
||||
if (our_type == 0)
|
||||
our_type = g_boxed_type_register_static (I_("GtkTargetList"),
|
||||
(GBoxedCopyFunc) gtk_target_list_ref,
|
||||
(GBoxedFreeFunc) gtk_target_list_unref);
|
||||
|
||||
return our_type;
|
||||
}
|
||||
|
||||
static int
|
||||
gtk_selection_bytes_per_item (gint format)
|
||||
{
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <gdk/gdk.h>
|
||||
#include <gtk/gtkenums.h>
|
||||
#include <gtk/gtkwidget.h>
|
||||
#include <gtk/gtktextiter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
@ -38,6 +39,7 @@ typedef struct _GtkTargetList GtkTargetList;
|
||||
typedef struct _GtkTargetEntry GtkTargetEntry;
|
||||
|
||||
#define GTK_TYPE_SELECTION_DATA (gtk_selection_data_get_type ())
|
||||
#define GTK_TYPE_TARGET_LIST (gtk_target_list_get_type ())
|
||||
|
||||
/* The contents of a selection are returned in a GtkSelectionData
|
||||
* structure. selection/target identify the request. type specifies
|
||||
@ -87,7 +89,7 @@ struct _GtkTargetPair {
|
||||
|
||||
GtkTargetList *gtk_target_list_new (const GtkTargetEntry *targets,
|
||||
guint ntargets);
|
||||
void gtk_target_list_ref (GtkTargetList *list);
|
||||
GtkTargetList *gtk_target_list_ref (GtkTargetList *list);
|
||||
void gtk_target_list_unref (GtkTargetList *list);
|
||||
void gtk_target_list_add (GtkTargetList *list,
|
||||
GdkAtom target,
|
||||
@ -95,6 +97,10 @@ void gtk_target_list_add (GtkTargetList *list,
|
||||
guint info);
|
||||
void gtk_target_list_add_text_targets (GtkTargetList *list,
|
||||
guint info);
|
||||
void gtk_target_list_add_rich_text_targets (GtkTargetList *list,
|
||||
guint info,
|
||||
gboolean deserializable,
|
||||
GtkTextBuffer *buffer);
|
||||
void gtk_target_list_add_image_targets (GtkTargetList *list,
|
||||
guint info,
|
||||
gboolean writable);
|
||||
@ -109,6 +115,11 @@ gboolean gtk_target_list_find (GtkTargetList *list,
|
||||
GdkAtom target,
|
||||
guint *info);
|
||||
|
||||
GtkTargetEntry * gtk_target_table_new_from_list (GtkTargetList *list,
|
||||
gint *n_targets);
|
||||
void gtk_target_table_free (GtkTargetEntry *targets,
|
||||
gint n_targets);
|
||||
|
||||
/* Public interface */
|
||||
|
||||
gboolean gtk_selection_owner_set (GtkWidget *widget,
|
||||
@ -153,11 +164,16 @@ gboolean gtk_selection_data_get_targets (GtkSelectionData *selection_d
|
||||
GdkAtom **targets,
|
||||
gint *n_atoms);
|
||||
gboolean gtk_selection_data_targets_include_text (GtkSelectionData *selection_data);
|
||||
gboolean gtk_selection_data_targets_include_rich_text (GtkSelectionData *selection_data,
|
||||
GtkTextBuffer *buffer);
|
||||
gboolean gtk_selection_data_targets_include_image (GtkSelectionData *selection_data,
|
||||
gboolean writable);
|
||||
gboolean gtk_selection_data_targets_include_uri (GtkSelectionData *selection_data);
|
||||
gboolean gtk_targets_include_text (GdkAtom *targets,
|
||||
gint n_targets);
|
||||
gboolean gtk_targets_include_rich_text (GdkAtom *targets,
|
||||
gint n_targets,
|
||||
GtkTextBuffer *buffer);
|
||||
gboolean gtk_targets_include_image (GdkAtom *targets,
|
||||
gint n_targets,
|
||||
gboolean writable);
|
||||
@ -186,6 +202,7 @@ GType gtk_selection_data_get_type (void) G_GNUC_CONST;
|
||||
GtkSelectionData *gtk_selection_data_copy (GtkSelectionData *data);
|
||||
void gtk_selection_data_free (GtkSelectionData *data);
|
||||
|
||||
GType gtk_target_list_get_type (void) G_GNUC_CONST;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* GTK - The GIMP Toolkit
|
||||
* gtktextbuffer.c Copyright (C) 2000 Red Hat, Inc.
|
||||
* Copyright (C) 2004 Nokia Corporation
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
@ -24,17 +25,17 @@
|
||||
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
#define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
|
||||
#include "gtkclipboard.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkinvisible.h"
|
||||
#include "gtkmarshalers.h"
|
||||
#include "gtktextbuffer.h"
|
||||
#include "gtktextbufferrichtext.h"
|
||||
#include "gtktextbtree.h"
|
||||
#include "gtktextiterprivate.h"
|
||||
#include "gtkprivate.h"
|
||||
@ -42,6 +43,22 @@
|
||||
#include "gtkalias.h"
|
||||
|
||||
|
||||
#define GTK_TEXT_BUFFER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_TEXT_BUFFER, GtkTextBufferPrivate))
|
||||
|
||||
typedef struct _GtkTextBufferPrivate GtkTextBufferPrivate;
|
||||
|
||||
struct _GtkTextBufferPrivate
|
||||
{
|
||||
GtkTargetList *copy_target_list;
|
||||
GtkTargetEntry *copy_target_entries;
|
||||
gint n_copy_target_entries;
|
||||
|
||||
GtkTargetList *paste_target_list;
|
||||
GtkTargetEntry *paste_target_entries;
|
||||
gint n_paste_target_entries;
|
||||
};
|
||||
|
||||
|
||||
typedef struct _ClipboardRequest ClipboardRequest;
|
||||
|
||||
struct _ClipboardRequest
|
||||
@ -77,22 +94,15 @@ enum {
|
||||
|
||||
/* Normal */
|
||||
PROP_TEXT,
|
||||
PROP_HAS_SELECTION
|
||||
};
|
||||
|
||||
enum {
|
||||
TARGET_STRING,
|
||||
TARGET_TEXT,
|
||||
TARGET_COMPOUND_TEXT,
|
||||
TARGET_UTF8_STRING,
|
||||
TARGET_TEXT_BUFFER_CONTENTS
|
||||
PROP_HAS_SELECTION,
|
||||
PROP_COPY_TARGET_LIST,
|
||||
PROP_PASTE_TARGET_LIST
|
||||
};
|
||||
|
||||
static void gtk_text_buffer_init (GtkTextBuffer *tkxt_buffer);
|
||||
static void gtk_text_buffer_class_init (GtkTextBufferClass *klass);
|
||||
static void gtk_text_buffer_finalize (GObject *object);
|
||||
|
||||
|
||||
static void gtk_text_buffer_real_insert_text (GtkTextBuffer *buffer,
|
||||
GtkTextIter *iter,
|
||||
const gchar *text,
|
||||
@ -127,6 +137,8 @@ static void update_selection_clipboards (GtkTextBuffer *buffer);
|
||||
|
||||
static GtkTextBuffer *create_clipboard_contents_buffer (GtkTextBuffer *buffer);
|
||||
|
||||
static void gtk_text_buffer_free_target_lists (GtkTextBuffer *buffer);
|
||||
|
||||
static GObjectClass *parent_class = NULL;
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
@ -138,6 +150,8 @@ static void gtk_text_buffer_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void gtk_text_buffer_notify (GObject *object,
|
||||
GParamSpec *pspec);
|
||||
|
||||
|
||||
GType
|
||||
@ -177,6 +191,7 @@ gtk_text_buffer_class_init (GtkTextBufferClass *klass)
|
||||
object_class->finalize = gtk_text_buffer_finalize;
|
||||
object_class->set_property = gtk_text_buffer_set_property;
|
||||
object_class->get_property = gtk_text_buffer_get_property;
|
||||
object_class->notify = gtk_text_buffer_notify;
|
||||
|
||||
klass->insert_text = gtk_text_buffer_real_insert_text;
|
||||
klass->insert_pixbuf = gtk_text_buffer_real_insert_pixbuf;
|
||||
@ -227,7 +242,39 @@ gtk_text_buffer_class_init (GtkTextBufferClass *klass)
|
||||
P_("Has selection"),
|
||||
P_("Whether the buffer has some text currently selected"),
|
||||
FALSE,
|
||||
G_PARAM_READABLE));
|
||||
GTK_PARAM_READABLE));
|
||||
|
||||
/**
|
||||
* GtkTextBuffer:copy-target-list:
|
||||
*
|
||||
* The list of targets this buffer supports for clipboard copying
|
||||
* and as DND source.
|
||||
*
|
||||
* Since: 2.10
|
||||
*/
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_COPY_TARGET_LIST,
|
||||
g_param_spec_boxed ("copy-target-list",
|
||||
P_("Copy target list"),
|
||||
P_("The list of targets this buffer supports for clipboard copying and DND source"),
|
||||
GTK_TYPE_TARGET_LIST,
|
||||
GTK_PARAM_READABLE));
|
||||
|
||||
/**
|
||||
* GtkTextBuffer:paste-target-list:
|
||||
*
|
||||
* The list of targets this buffer supports for clipboard pasting
|
||||
* and as DND destination.
|
||||
*
|
||||
* Since: 2.10
|
||||
*/
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_PASTE_TARGET_LIST,
|
||||
g_param_spec_boxed ("paste-target-list",
|
||||
P_("Paste target list"),
|
||||
P_("The list of targets this buffer supports for clipboard pasting and DND destination"),
|
||||
GTK_TYPE_TARGET_LIST,
|
||||
GTK_PARAM_READABLE));
|
||||
|
||||
signals[INSERT_TEXT] =
|
||||
g_signal_new (I_("insert_text"),
|
||||
@ -379,6 +426,8 @@ gtk_text_buffer_class_init (GtkTextBufferClass *klass)
|
||||
_gtk_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
|
||||
g_type_class_add_private (object_class, sizeof (GtkTextBufferPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
@ -386,6 +435,9 @@ gtk_text_buffer_init (GtkTextBuffer *buffer)
|
||||
{
|
||||
buffer->clipboard_contents_buffers = NULL;
|
||||
buffer->tag_table = NULL;
|
||||
|
||||
/* allow copying of arbiatray stuff in the internal rich text format */
|
||||
gtk_text_buffer_register_serialize_tagset (buffer, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -463,7 +515,8 @@ gtk_text_buffer_get_property (GObject *object,
|
||||
gtk_text_buffer_get_end_iter (text_buffer, &end);
|
||||
|
||||
g_value_set_string (value,
|
||||
gtk_text_buffer_get_text (text_buffer, &start, &end, FALSE));
|
||||
gtk_text_buffer_get_text (text_buffer,
|
||||
&start, &end, FALSE));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -471,11 +524,30 @@ gtk_text_buffer_get_property (GObject *object,
|
||||
g_value_set_boolean (value, text_buffer->has_selection);
|
||||
break;
|
||||
|
||||
case PROP_COPY_TARGET_LIST:
|
||||
g_value_set_boxed (value, gtk_text_buffer_get_copy_target_list (text_buffer));
|
||||
break;
|
||||
|
||||
case PROP_PASTE_TARGET_LIST:
|
||||
g_value_set_boxed (value, gtk_text_buffer_get_paste_target_list (text_buffer));
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_buffer_notify (GObject *object,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
if (!strcmp (pspec->name, "copy-target-list") ||
|
||||
!strcmp (pspec->name, "paste-target-list"))
|
||||
{
|
||||
gtk_text_buffer_free_target_lists (GTK_TEXT_BUFFER (object));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_buffer_new:
|
||||
* @table: a tag table, or NULL to create a new one
|
||||
@ -498,11 +570,14 @@ static void
|
||||
gtk_text_buffer_finalize (GObject *object)
|
||||
{
|
||||
GtkTextBuffer *buffer;
|
||||
GtkTextBufferPrivate *priv;
|
||||
|
||||
buffer = GTK_TEXT_BUFFER (object);
|
||||
|
||||
remove_all_selection_clipboards (buffer);
|
||||
|
||||
priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
|
||||
|
||||
if (buffer->tag_table)
|
||||
{
|
||||
_gtk_text_tag_table_remove_buffer (buffer->tag_table, buffer);
|
||||
@ -521,6 +596,8 @@ gtk_text_buffer_finalize (GObject *object)
|
||||
|
||||
buffer->log_attr_cache = NULL;
|
||||
|
||||
gtk_text_buffer_free_target_lists (buffer);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
@ -2840,18 +2917,32 @@ clipboard_get_selection_cb (GtkClipboard *clipboard,
|
||||
|
||||
if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
|
||||
{
|
||||
if (selection_data->target ==
|
||||
gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
|
||||
if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
|
||||
{
|
||||
/* Provide the address of the buffer; this will only be
|
||||
* used within-process
|
||||
*/
|
||||
gtk_selection_data_set (selection_data,
|
||||
gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
|
||||
selection_data->target,
|
||||
8, /* bytes */
|
||||
(void*)&buffer,
|
||||
sizeof (buffer));
|
||||
}
|
||||
else if (info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
|
||||
{
|
||||
guint8 *str;
|
||||
gsize len;
|
||||
|
||||
str = gtk_text_buffer_serialize (buffer, buffer,
|
||||
selection_data->target,
|
||||
&start, &end, &len);
|
||||
|
||||
gtk_selection_data_set (selection_data,
|
||||
selection_data->target,
|
||||
8, /* bytes */
|
||||
str, len);
|
||||
g_free (str);
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar *str;
|
||||
@ -2870,7 +2961,10 @@ create_clipboard_contents_buffer (GtkTextBuffer *buffer)
|
||||
|
||||
contents = gtk_text_buffer_new (gtk_text_buffer_get_tag_table (buffer));
|
||||
|
||||
g_object_set_data (G_OBJECT (contents), I_("gtk-text-buffer-clipboard"), GINT_TO_POINTER (1));
|
||||
g_object_set_data (G_OBJECT (contents), I_("gtk-text-buffer-clipboard-source"),
|
||||
buffer);
|
||||
g_object_set_data (G_OBJECT (contents), I_("gtk-text-buffer-clipboard"),
|
||||
GINT_TO_POINTER (1));
|
||||
|
||||
return contents;
|
||||
}
|
||||
@ -2882,24 +2976,43 @@ clipboard_get_contents_cb (GtkClipboard *clipboard,
|
||||
guint info,
|
||||
gpointer data)
|
||||
{
|
||||
GtkTextBuffer *contents;
|
||||
|
||||
contents = GTK_TEXT_BUFFER (data);
|
||||
GtkTextBuffer *contents = GTK_TEXT_BUFFER (data);
|
||||
|
||||
g_assert (contents); /* This should never be called unless we own the clipboard */
|
||||
|
||||
if (selection_data->target ==
|
||||
gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
|
||||
if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
|
||||
{
|
||||
/* Provide the address of the clipboard buffer; this will only
|
||||
* be used within-process. OK to supply a NULL value for contents.
|
||||
*/
|
||||
gtk_selection_data_set (selection_data,
|
||||
gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
|
||||
selection_data->target,
|
||||
8, /* bytes */
|
||||
(void*)&contents,
|
||||
sizeof (contents));
|
||||
}
|
||||
else if (info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
|
||||
{
|
||||
GtkTextBuffer *clipboard_source_buffer;
|
||||
GtkTextIter start, end;
|
||||
guint8 *str;
|
||||
gsize len;
|
||||
|
||||
clipboard_source_buffer = g_object_get_data (G_OBJECT (contents),
|
||||
"gtk-text-buffer-clipboard-source");
|
||||
|
||||
gtk_text_buffer_get_bounds (contents, &start, &end);
|
||||
|
||||
str = gtk_text_buffer_serialize (clipboard_source_buffer, contents,
|
||||
selection_data->target,
|
||||
&start, &end, &len);
|
||||
|
||||
gtk_selection_data_set (selection_data,
|
||||
selection_data->target,
|
||||
8, /* bytes */
|
||||
str, len);
|
||||
g_free (str);
|
||||
}
|
||||
else
|
||||
{
|
||||
gchar *str;
|
||||
@ -3052,7 +3165,8 @@ selection_data_get_buffer (GtkSelectionData *selection_data,
|
||||
if (gdk_window_get_window_type (owner) == GDK_WINDOW_FOREIGN)
|
||||
return NULL;
|
||||
|
||||
if (selection_data->type != gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
|
||||
if (selection_data->type !=
|
||||
gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
|
||||
return NULL;
|
||||
|
||||
if (selection_data->length != sizeof (src_buffer))
|
||||
@ -3099,6 +3213,62 @@ restore_iter (const GtkTextIter *iter,
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
clipboard_rich_text_received (GtkClipboard *clipboard,
|
||||
GdkAtom format,
|
||||
const guint8 *text,
|
||||
gsize length,
|
||||
gpointer data)
|
||||
{
|
||||
ClipboardRequest *request_data = data;
|
||||
GtkTextIter insert_point;
|
||||
gboolean retval = TRUE;
|
||||
GError *error = NULL;
|
||||
GtkTextBufferPrivate *priv;
|
||||
|
||||
priv = GTK_TEXT_BUFFER_GET_PRIVATE (request_data->buffer);
|
||||
|
||||
if (text != NULL && length > 0)
|
||||
{
|
||||
pre_paste_prep (request_data, &insert_point);
|
||||
|
||||
if (request_data->interactive)
|
||||
gtk_text_buffer_begin_user_action (request_data->buffer);
|
||||
|
||||
if (!request_data->interactive ||
|
||||
gtk_text_iter_can_insert (&insert_point,
|
||||
request_data->default_editable))
|
||||
{
|
||||
retval = gtk_text_buffer_deserialize (request_data->buffer,
|
||||
request_data->buffer,
|
||||
format,
|
||||
&insert_point,
|
||||
text, length,
|
||||
&error);
|
||||
}
|
||||
|
||||
if (!retval)
|
||||
{
|
||||
g_warning ("error pasting: %s\n", error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
if (request_data->interactive)
|
||||
gtk_text_buffer_end_user_action (request_data->buffer);
|
||||
|
||||
if (retval)
|
||||
{
|
||||
post_paste_cleanup (request_data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Request the text selection instead */
|
||||
gtk_clipboard_request_text (clipboard,
|
||||
clipboard_text_received,
|
||||
data);
|
||||
}
|
||||
|
||||
static void
|
||||
paste_from_buffer (ClipboardRequest *request_data,
|
||||
GtkTextBuffer *src_buffer,
|
||||
@ -3145,6 +3315,7 @@ clipboard_clipboard_buffer_received (GtkClipboard *clipboard,
|
||||
{
|
||||
ClipboardRequest *request_data = data;
|
||||
GtkTextBuffer *src_buffer;
|
||||
GtkTextBufferPrivate *priv;
|
||||
|
||||
src_buffer = selection_data_get_buffer (selection_data, request_data);
|
||||
|
||||
@ -3166,6 +3337,19 @@ clipboard_clipboard_buffer_received (GtkClipboard *clipboard,
|
||||
&start, &end);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
priv = GTK_TEXT_BUFFER_GET_PRIVATE (request_data->buffer);
|
||||
|
||||
if (gtk_clipboard_wait_is_rich_text_available (clipboard,
|
||||
request_data->buffer))
|
||||
{
|
||||
/* Request rich text */
|
||||
gtk_clipboard_request_rich_text (clipboard,
|
||||
request_data->buffer,
|
||||
clipboard_rich_text_received,
|
||||
data);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Request the text selection instead */
|
||||
@ -3174,14 +3358,7 @@ clipboard_clipboard_buffer_received (GtkClipboard *clipboard,
|
||||
data);
|
||||
}
|
||||
}
|
||||
|
||||
static const GtkTargetEntry targets[] = {
|
||||
{ "STRING", 0, TARGET_STRING },
|
||||
{ "TEXT", 0, TARGET_TEXT },
|
||||
{ "COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT },
|
||||
{ "UTF8_STRING", 0, TARGET_UTF8_STRING },
|
||||
{ "GTK_TEXT_BUFFER_CONTENTS", 0, TARGET_TEXT_BUFFER_CONTENTS }
|
||||
};
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
@ -3192,7 +3369,13 @@ typedef struct
|
||||
static void
|
||||
update_selection_clipboards (GtkTextBuffer *buffer)
|
||||
{
|
||||
GtkTextBufferPrivate *priv;
|
||||
GSList *tmp_list = buffer->selection_clipboards;
|
||||
|
||||
priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
|
||||
|
||||
gtk_text_buffer_get_copy_target_list (buffer);
|
||||
|
||||
while (tmp_list)
|
||||
{
|
||||
GtkTextIter start;
|
||||
@ -3214,7 +3397,9 @@ update_selection_clipboards (GtkTextBuffer *buffer)
|
||||
/* Even if we already have the selection, we need to update our
|
||||
* timestamp.
|
||||
*/
|
||||
if (!gtk_clipboard_set_with_owner (clipboard, targets, G_N_ELEMENTS (targets),
|
||||
if (!gtk_clipboard_set_with_owner (clipboard,
|
||||
priv->copy_target_entries,
|
||||
priv->n_copy_target_entries,
|
||||
clipboard_get_selection_cb,
|
||||
clipboard_clear_selection_cb,
|
||||
G_OBJECT (buffer)))
|
||||
@ -3525,6 +3710,8 @@ cut_or_copy (GtkTextBuffer *buffer,
|
||||
gboolean interactive,
|
||||
gboolean default_editable)
|
||||
{
|
||||
GtkTextBufferPrivate *priv;
|
||||
|
||||
/* We prefer to cut the selected region between selection_bound and
|
||||
* insertion point. If that region is empty, then we cut the region
|
||||
* between the "anchor" and the insertion point (this is for
|
||||
@ -3535,6 +3722,10 @@ cut_or_copy (GtkTextBuffer *buffer,
|
||||
GtkTextIter start;
|
||||
GtkTextIter end;
|
||||
|
||||
priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
|
||||
|
||||
gtk_text_buffer_get_copy_target_list (buffer);
|
||||
|
||||
if (!gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
|
||||
{
|
||||
/* Let's try the anchor thing */
|
||||
@ -3560,13 +3751,17 @@ cut_or_copy (GtkTextBuffer *buffer,
|
||||
|
||||
gtk_text_buffer_insert_range (contents, &ins, &start, &end);
|
||||
|
||||
if (!gtk_clipboard_set_with_data (clipboard, targets, G_N_ELEMENTS (targets),
|
||||
if (!gtk_clipboard_set_with_data (clipboard,
|
||||
priv->copy_target_entries,
|
||||
priv->n_copy_target_entries,
|
||||
clipboard_get_contents_cb,
|
||||
clipboard_clear_contents_cb,
|
||||
contents))
|
||||
g_object_unref (contents);
|
||||
else
|
||||
gtk_clipboard_set_can_store (clipboard, (GtkTargetEntry *)targets, G_N_ELEMENTS (targets) -1);
|
||||
gtk_clipboard_set_can_store (clipboard,
|
||||
priv->copy_target_entries + 1,
|
||||
priv->n_copy_target_entries - 1);
|
||||
|
||||
if (delete_region_after)
|
||||
{
|
||||
@ -3699,6 +3894,126 @@ gtk_text_buffer_end_user_action (GtkTextBuffer *buffer)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_buffer_free_target_lists (GtkTextBuffer *buffer)
|
||||
{
|
||||
GtkTextBufferPrivate *priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
|
||||
|
||||
if (priv->copy_target_list)
|
||||
{
|
||||
gtk_target_list_unref (priv->copy_target_list);
|
||||
priv->copy_target_list = NULL;
|
||||
|
||||
gtk_target_table_free (priv->copy_target_entries,
|
||||
priv->n_copy_target_entries);
|
||||
priv->copy_target_entries = NULL;
|
||||
priv->n_copy_target_entries = 0;
|
||||
}
|
||||
|
||||
if (priv->paste_target_list)
|
||||
{
|
||||
gtk_target_list_unref (priv->paste_target_list);
|
||||
priv->paste_target_list = NULL;
|
||||
|
||||
gtk_target_table_free (priv->paste_target_entries,
|
||||
priv->n_paste_target_entries);
|
||||
priv->paste_target_entries = NULL;
|
||||
priv->n_paste_target_entries = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static GtkTargetList *
|
||||
gtk_text_buffer_get_target_list (GtkTextBuffer *buffer,
|
||||
gboolean deserializable,
|
||||
GtkTargetEntry **entries,
|
||||
gint *n_entries)
|
||||
{
|
||||
GtkTargetList *target_list;
|
||||
|
||||
target_list = gtk_target_list_new (NULL, 0);
|
||||
|
||||
gtk_target_list_add (target_list,
|
||||
gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
|
||||
GTK_TARGET_SAME_APP,
|
||||
GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS);
|
||||
|
||||
gtk_target_list_add_rich_text_targets (target_list,
|
||||
GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT,
|
||||
deserializable,
|
||||
buffer);
|
||||
|
||||
gtk_target_list_add_text_targets (target_list,
|
||||
GTK_TEXT_BUFFER_TARGET_INFO_TEXT);
|
||||
|
||||
*entries = gtk_target_table_new_from_list (target_list, n_entries);
|
||||
|
||||
return target_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_buffer_get_copy_target_list:
|
||||
* @buffer: a #GtkTextBuffer
|
||||
*
|
||||
* This function returns the list of targets this text buffer can
|
||||
* provide for copying and as DND source. The targets in the list are
|
||||
* added with %info values from the #GtkTextBufferTargetInfo enum,
|
||||
* using gtk_target_list_add_rich_text_targets() and
|
||||
* gtk_target_list_add_text_targets()
|
||||
*
|
||||
* Return value: the #GtkTargetList
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
GtkTargetList *
|
||||
gtk_text_buffer_get_copy_target_list (GtkTextBuffer *buffer)
|
||||
{
|
||||
GtkTextBufferPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
|
||||
|
||||
priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
|
||||
|
||||
if (! priv->copy_target_list)
|
||||
priv->copy_target_list =
|
||||
gtk_text_buffer_get_target_list (buffer, FALSE,
|
||||
&priv->copy_target_entries,
|
||||
&priv->n_copy_target_entries);
|
||||
|
||||
return priv->copy_target_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_buffer_get_paste_target_list:
|
||||
* @buffer: a #GtkTextBuffer
|
||||
*
|
||||
* This function returns the list of targets this text buffer supports
|
||||
* for pasting and as DND destination. The targets in the list are
|
||||
* added with %info values from the #GtkTextBufferTargetInfo enum,
|
||||
* using gtk_target_list_add_rich_text_targets() and
|
||||
* gtk_target_list_add_text_targets()
|
||||
*
|
||||
* Return value: the #GtkTargetList
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
GtkTargetList *
|
||||
gtk_text_buffer_get_paste_target_list (GtkTextBuffer *buffer)
|
||||
{
|
||||
GtkTextBufferPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
|
||||
|
||||
priv = GTK_TEXT_BUFFER_GET_PRIVATE (buffer);
|
||||
|
||||
if (! priv->paste_target_list)
|
||||
priv->paste_target_list =
|
||||
gtk_text_buffer_get_target_list (buffer, TRUE,
|
||||
&priv->paste_target_entries,
|
||||
&priv->n_paste_target_entries);
|
||||
|
||||
return priv->paste_target_list;
|
||||
}
|
||||
|
||||
/*
|
||||
* Logical attribute cache
|
||||
*/
|
||||
|
@ -41,6 +41,16 @@ G_BEGIN_DECLS
|
||||
* GtkTextBTree is the PRIVATE internal representation of it.
|
||||
*/
|
||||
|
||||
/* these values are used as "info" for the targets contained in the
|
||||
* lists returned by gtk_text_buffer_get_copy,paste_target_list()
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS,
|
||||
GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT,
|
||||
GTK_TEXT_BUFFER_TARGET_INFO_TEXT
|
||||
} GtkTextBufferTargetInfo;
|
||||
|
||||
typedef struct _GtkTextBTree GtkTextBTree;
|
||||
|
||||
typedef struct _GtkTextLogAttrCache GtkTextLogAttrCache;
|
||||
@ -367,6 +377,9 @@ gboolean gtk_text_buffer_delete_selection (GtkTextBuffer *buffer,
|
||||
void gtk_text_buffer_begin_user_action (GtkTextBuffer *buffer);
|
||||
void gtk_text_buffer_end_user_action (GtkTextBuffer *buffer);
|
||||
|
||||
GtkTargetList * gtk_text_buffer_get_copy_target_list (GtkTextBuffer *buffer);
|
||||
GtkTargetList * gtk_text_buffer_get_paste_target_list (GtkTextBuffer *buffer);
|
||||
|
||||
/* INTERNAL private stuff */
|
||||
void _gtk_text_buffer_spew (GtkTextBuffer *buffer);
|
||||
|
||||
|
704
gtk/gtktextbufferrichtext.c
Normal file
704
gtk/gtktextbufferrichtext.c
Normal file
@ -0,0 +1,704 @@
|
||||
/* gtkrichtext.c
|
||||
*
|
||||
* Copyright (C) 2006 Imendio AB
|
||||
* Contact: Michael Natterer <mitch@imendio.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "gtktextbufferrichtext.h"
|
||||
#include "gtktextbufferserialize.h"
|
||||
#include "gtkalias.h"
|
||||
#include "gtkintl.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gchar *mime_type;
|
||||
gboolean can_create_tags;
|
||||
GdkAtom atom;
|
||||
gpointer function;
|
||||
gpointer user_data;
|
||||
GDestroyNotify user_data_destroy;
|
||||
} GtkRichTextFormat;
|
||||
|
||||
|
||||
static GList * register_format (GList *formats,
|
||||
const gchar *mime_type,
|
||||
gpointer function,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_destroy,
|
||||
GdkAtom *atom);
|
||||
static GList * unregister_format (GList *formats,
|
||||
GdkAtom atom);
|
||||
static GdkAtom * get_formats (GList *formats,
|
||||
gint *n_formats);
|
||||
static void free_format (GtkRichTextFormat *format);
|
||||
static void free_format_list (GList *formats);
|
||||
static GQuark serialize_quark (void);
|
||||
static GQuark deserialize_quark (void);
|
||||
|
||||
|
||||
/**
|
||||
* gtk_text_buffer_register_serialize_format:
|
||||
* @buffer: a #GtkTextBuffer
|
||||
* @mime_type: the format's mime-type
|
||||
* @function: the serialize function to register
|
||||
* @user_data: %function's user_data
|
||||
* @user_data_destroy: a function to call when user_data is no longer needed
|
||||
*
|
||||
* This function registers a rich text serialization %function along with
|
||||
* its %mime_type with the passed %buffer.
|
||||
*
|
||||
* Return value: the #GdkAtom that corresponds to the newly registered
|
||||
* format's mime-type.
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
GdkAtom
|
||||
gtk_text_buffer_register_serialize_format (GtkTextBuffer *buffer,
|
||||
const gchar *mime_type,
|
||||
GtkTextBufferSerializeFunc function,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_destroy)
|
||||
{
|
||||
GList *formats;
|
||||
GdkAtom atom;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), GDK_NONE);
|
||||
g_return_val_if_fail (mime_type != NULL && *mime_type != '\0', GDK_NONE);
|
||||
g_return_val_if_fail (function != NULL, GDK_NONE);
|
||||
|
||||
formats = g_object_steal_qdata (G_OBJECT (buffer), serialize_quark ());
|
||||
|
||||
formats = register_format (formats, mime_type,
|
||||
(gpointer) function,
|
||||
user_data, user_data_destroy,
|
||||
&atom);
|
||||
|
||||
g_object_set_qdata_full (G_OBJECT (buffer), serialize_quark (),
|
||||
formats, (GDestroyNotify) free_format_list);
|
||||
|
||||
g_object_notify (G_OBJECT (buffer), "copy-target-list");
|
||||
|
||||
return atom;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_buffer_register_serialize_tagset:
|
||||
* @buffer: a #GtkTextBuffer
|
||||
* @tagset_name: an optional tagset name, on %NULL
|
||||
*
|
||||
* This function registers GTK+'s internal rich text serialization
|
||||
* format with the passed %buffer. The internal format does not comply
|
||||
* to any standard rich text format and only works between #GtkTextBuffer
|
||||
* instances. It is capable of serializing all of a text buffer's tags
|
||||
* and embedded pixbufs.
|
||||
*
|
||||
* This function is just a wrapper around
|
||||
* gtk_text_buffer_register_serialize_format(). The %mime_type used
|
||||
* for registering is "application/x-gtk-text-buffer-rich-text", or
|
||||
* "application/x-gtk-text-buffer-rich-text;format=%tagset_name" if a
|
||||
* %tagset_name was passed.
|
||||
*
|
||||
* The %tagset_name can be used to restrict the transfer of rich text
|
||||
* to buffers with compatible sets of tags, in order to avoid unknown
|
||||
* tags from being pasted. It is probably the common case to pass an
|
||||
* identifier != %NULL here, since the %NULL tagset requires the
|
||||
* receiving buffer to deal with with pasting of arbitrary tags.
|
||||
*
|
||||
* Return value: the #GdkAtom that corresponds to the newly registered
|
||||
* format's mime-type.
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
GdkAtom
|
||||
gtk_text_buffer_register_serialize_tagset (GtkTextBuffer *buffer,
|
||||
const gchar *tagset_name)
|
||||
{
|
||||
gchar *mime_type = "application/x-gtk-text-buffer-rich-text";
|
||||
GdkAtom format;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), GDK_NONE);
|
||||
g_return_val_if_fail (tagset_name == NULL || *tagset_name != '\0', GDK_NONE);
|
||||
|
||||
if (tagset_name)
|
||||
mime_type =
|
||||
g_strdup_printf ("application/x-gtk-text-buffer-rich-text;format=%s",
|
||||
tagset_name);
|
||||
|
||||
format = gtk_text_buffer_register_serialize_format (buffer, mime_type,
|
||||
_gtk_text_buffer_serialize_rich_text,
|
||||
NULL, NULL);
|
||||
|
||||
if (tagset_name)
|
||||
g_free (mime_type);
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_buffer_register_deserialize_format:
|
||||
* @buffer: a #GtkTextBuffer
|
||||
* @mime_type: the format's mime-type
|
||||
* @function: the deserialize function to register
|
||||
* @user_data: %function's user_data
|
||||
* @user_data_destroy: a function to call when user_data is no longer needed
|
||||
*
|
||||
* This function registers a rich text deserialization %function along with
|
||||
* its %mime_type with the passed %buffer.
|
||||
*
|
||||
* Return value: the #GdkAtom that corresponds to the newly registered
|
||||
* format's mime-type.
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
GdkAtom
|
||||
gtk_text_buffer_register_deserialize_format (GtkTextBuffer *buffer,
|
||||
const gchar *mime_type,
|
||||
GtkTextBufferDeserializeFunc function,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_destroy)
|
||||
{
|
||||
GList *formats;
|
||||
GdkAtom atom;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), GDK_NONE);
|
||||
g_return_val_if_fail (mime_type != NULL && *mime_type != '\0', GDK_NONE);
|
||||
g_return_val_if_fail (function != NULL, GDK_NONE);
|
||||
|
||||
formats = g_object_steal_qdata (G_OBJECT (buffer), deserialize_quark ());
|
||||
|
||||
formats = register_format (formats, mime_type,
|
||||
(gpointer) function,
|
||||
user_data, user_data_destroy,
|
||||
&atom);
|
||||
|
||||
g_object_set_qdata_full (G_OBJECT (buffer), deserialize_quark (),
|
||||
formats, (GDestroyNotify) free_format_list);
|
||||
|
||||
g_object_notify (G_OBJECT (buffer), "paste-target-list");
|
||||
|
||||
return atom;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_buffer_register_deserialize_tagset:
|
||||
* @buffer: a #GtkTextBuffer
|
||||
* @tagset_name: an optional tagset name, on %NULL
|
||||
*
|
||||
* This function registers GTK+'s internal rich text serialization
|
||||
* format with the passed %buffer. See
|
||||
* gtk_text_buffer_register_serialize_tagset() for details.
|
||||
*
|
||||
* Return value: the #GdkAtom that corresponds to the newly registered
|
||||
* format's mime-type.
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
GdkAtom
|
||||
gtk_text_buffer_register_deserialize_tagset (GtkTextBuffer *buffer,
|
||||
const gchar *tagset_name)
|
||||
{
|
||||
gchar *mime_type = "application/x-gtk-text-buffer-rich-text";
|
||||
GdkAtom format;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), GDK_NONE);
|
||||
g_return_val_if_fail (tagset_name == NULL || *tagset_name != '\0', GDK_NONE);
|
||||
|
||||
if (tagset_name)
|
||||
mime_type =
|
||||
g_strdup_printf ("application/x-gtk-text-buffer-rich-text;format=%s",
|
||||
tagset_name);
|
||||
|
||||
format = gtk_text_buffer_register_deserialize_format (buffer, mime_type,
|
||||
_gtk_text_buffer_deserialize_rich_text,
|
||||
NULL, NULL);
|
||||
|
||||
if (tagset_name)
|
||||
g_free (mime_type);
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_buffer_unregister_serialize_format:
|
||||
* @buffer: a #GtkTextBuffer
|
||||
* @format: a #GdkAtom representing a registered rich text format.
|
||||
*
|
||||
* This function unregisters a rich text format that was previously
|
||||
* registered using gtk_text_buffer_register_serialize_format() or
|
||||
* gtk_text_buffer_register_serialize_tagset()
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
void
|
||||
gtk_text_buffer_unregister_serialize_format (GtkTextBuffer *buffer,
|
||||
GdkAtom format)
|
||||
{
|
||||
GList *formats;
|
||||
|
||||
g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
|
||||
g_return_if_fail (format != GDK_NONE);
|
||||
|
||||
formats = g_object_steal_qdata (G_OBJECT (buffer), serialize_quark ());
|
||||
|
||||
formats = unregister_format (formats, format);
|
||||
|
||||
g_object_set_qdata_full (G_OBJECT (buffer), serialize_quark (),
|
||||
formats, (GDestroyNotify) free_format_list);
|
||||
|
||||
g_object_notify (G_OBJECT (buffer), "copy-target-list");
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_buffer_unregister_deserialize_format:
|
||||
* @buffer: a #GtkTextBuffer
|
||||
* @format: a #GdkAtom representing a registered rich text format.
|
||||
*
|
||||
* This function unregisters a rich text format that was previously
|
||||
* registered using gtk_text_buffer_register_deserialize_format() or
|
||||
* gtk_text_buffer_register_deserialize_tagset()
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
void
|
||||
gtk_text_buffer_unregister_deserialize_format (GtkTextBuffer *buffer,
|
||||
GdkAtom format)
|
||||
{
|
||||
GList *formats;
|
||||
|
||||
g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
|
||||
g_return_if_fail (format != GDK_NONE);
|
||||
|
||||
formats = g_object_steal_qdata (G_OBJECT (buffer), deserialize_quark ());
|
||||
|
||||
formats = unregister_format (formats, format);
|
||||
|
||||
g_object_set_qdata_full (G_OBJECT (buffer), deserialize_quark (),
|
||||
formats, (GDestroyNotify) free_format_list);
|
||||
|
||||
g_object_notify (G_OBJECT (buffer), "paste-target-list");
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_buffer_deserialize_set_can_create_tags:
|
||||
* @buffer: a #GtkTextBuffer
|
||||
* @format: a #GdkAtom representing a registered rich text format
|
||||
* @can_create_tags: whether deserializing this format may create tags
|
||||
*
|
||||
* Use this function to allow a rich text deserialization function to
|
||||
* create new tags in the receiving buffer. Note that using this
|
||||
* function is almost always a bad idea, because the rich text
|
||||
* functions you register should know how to map the rich text format
|
||||
* they handler to your text buffers set of tags.
|
||||
*
|
||||
* The ability of creating new (arbitrary!) tags in the receiving buffer
|
||||
* is meant for special rich text formats like the internal one that
|
||||
* is registered using gtk_text_buffer_register_deserialize_tagset(),
|
||||
* because that format is essentially a dump of the internal structure
|
||||
* of the source buffer, including its tag names.
|
||||
*
|
||||
* You should allow creation of tags only if you know what you are
|
||||
* doing, e.g. if you defined a tagset name for your application
|
||||
* suite's text buffers and you know that it's fine to receive new
|
||||
* tags from these buffers, because you know that your application can
|
||||
* handle the newly created tags.
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
void
|
||||
gtk_text_buffer_deserialize_set_can_create_tags (GtkTextBuffer *buffer,
|
||||
GdkAtom format,
|
||||
gboolean can_create_tags)
|
||||
{
|
||||
GList *formats;
|
||||
GList *list;
|
||||
gchar *format_name;
|
||||
|
||||
g_return_if_fail (GTK_IS_TEXT_BUFFER (buffer));
|
||||
g_return_if_fail (format != GDK_NONE);
|
||||
|
||||
formats = g_object_get_qdata (G_OBJECT (buffer), deserialize_quark ());
|
||||
|
||||
for (list = formats; list; list = g_list_next (list))
|
||||
{
|
||||
GtkRichTextFormat *fmt = list->data;
|
||||
|
||||
if (fmt->atom == format)
|
||||
{
|
||||
fmt->can_create_tags = can_create_tags ? TRUE : FALSE;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
format_name = gdk_atom_name (format);
|
||||
g_warning ("%s: \"%s\" is not registered as deserializable format "
|
||||
"with text buffer %p",
|
||||
G_STRFUNC, format_name ? format_name : "not a GdkAtom", buffer);
|
||||
g_free (format_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_buffer_deserialize_get_can_create_tags:
|
||||
* @buffer: a #GtkTextBuffer
|
||||
* @format: a #GdkAtom representing a registered rich text format
|
||||
*
|
||||
* This functions returns the value set with
|
||||
* gtk_text_buffer_deserialize_set_can_create_tags()
|
||||
*
|
||||
* Return value: whether deserializing this format may create tags
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
gboolean
|
||||
gtk_text_buffer_deserialize_get_can_create_tags (GtkTextBuffer *buffer,
|
||||
GdkAtom format)
|
||||
{
|
||||
GList *formats;
|
||||
GList *list;
|
||||
gchar *format_name;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), FALSE);
|
||||
g_return_val_if_fail (format != GDK_NONE, FALSE);
|
||||
|
||||
formats = g_object_get_qdata (G_OBJECT (buffer), deserialize_quark ());
|
||||
|
||||
for (list = formats; list; list = g_list_next (list))
|
||||
{
|
||||
GtkRichTextFormat *fmt = list->data;
|
||||
|
||||
if (fmt->atom == format)
|
||||
{
|
||||
return fmt->can_create_tags;
|
||||
}
|
||||
}
|
||||
|
||||
format_name = gdk_atom_name (format);
|
||||
g_warning ("%s: \"%s\" is not registered as deserializable format "
|
||||
"with text buffer %p",
|
||||
G_STRFUNC, format_name ? format_name : "not a GdkAtom", buffer);
|
||||
g_free (format_name);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_buffer_get_serialize_formats:
|
||||
* @buffer: a #GtkTextBuffer
|
||||
* @n_formats: return location for the number of formats
|
||||
*
|
||||
* This function returns the rich text serialize formats registered
|
||||
* with %buffer using gtk_text_buffer_register_serialize_format() or
|
||||
* gtk_text_buffer_register_serialize_tagset()
|
||||
*
|
||||
* Return value: an array of #GdkAtom<!-- -->s representing the registered
|
||||
* formats.
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
GdkAtom *
|
||||
gtk_text_buffer_get_serialize_formats (GtkTextBuffer *buffer,
|
||||
gint *n_formats)
|
||||
{
|
||||
GList *formats;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
|
||||
g_return_val_if_fail (n_formats != NULL, NULL);
|
||||
|
||||
formats = g_object_get_qdata (G_OBJECT (buffer), serialize_quark ());
|
||||
|
||||
return get_formats (formats, n_formats);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_buffer_get_deserialize_formats:
|
||||
* @buffer: a #GtkTextBuffer
|
||||
* @n_formats: return location for the number of formats
|
||||
*
|
||||
* This function returns the rich text deserialize formats registered
|
||||
* with %buffer using gtk_text_buffer_register_deserialize_format() or
|
||||
* gtk_text_buffer_register_deserialize_tagset()
|
||||
*
|
||||
* Return value: an array of #GdkAtom<!-- -->s representing the registered
|
||||
* formats.
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
GdkAtom *
|
||||
gtk_text_buffer_get_deserialize_formats (GtkTextBuffer *buffer,
|
||||
gint *n_formats)
|
||||
{
|
||||
GList *formats;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
|
||||
g_return_val_if_fail (n_formats != NULL, NULL);
|
||||
|
||||
formats = g_object_get_qdata (G_OBJECT (buffer), deserialize_quark ());
|
||||
|
||||
return get_formats (formats, n_formats);
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_buffer_serialize:
|
||||
* @register_buffer: the #GtkTextBuffer %format is registered with
|
||||
* @content_buffer: the #GtkTextBuffer to serialize
|
||||
* @format: the rich text format to use for serializing
|
||||
* @start: start of block of text to serialize
|
||||
* @end: end of block of test to serialize
|
||||
* @length: return location for the length of the serialized data
|
||||
*
|
||||
* This function serializes the portion of text between %start
|
||||
* and %end in the rich text format represented by %format.
|
||||
*
|
||||
* %format<!-- -->s to be used must be registered using
|
||||
* gtk_text_buffer_register_serialize_format() or
|
||||
* gtk_text_buffer_register_serialize_tagset() beforehand.
|
||||
*
|
||||
* Return value: the serialized data, encoded as %format
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
guint8 *
|
||||
gtk_text_buffer_serialize (GtkTextBuffer *register_buffer,
|
||||
GtkTextBuffer *content_buffer,
|
||||
GdkAtom format,
|
||||
const GtkTextIter *start,
|
||||
const GtkTextIter *end,
|
||||
gsize *length)
|
||||
{
|
||||
GList *formats;
|
||||
GList *list;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (register_buffer), NULL);
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (content_buffer), NULL);
|
||||
g_return_val_if_fail (format != GDK_NONE, NULL);
|
||||
g_return_val_if_fail (start != NULL, NULL);
|
||||
g_return_val_if_fail (end != NULL, NULL);
|
||||
g_return_val_if_fail (length != NULL, NULL);
|
||||
|
||||
*length = 0;
|
||||
|
||||
formats = g_object_get_qdata (G_OBJECT (register_buffer),
|
||||
serialize_quark ());
|
||||
|
||||
for (list = formats; list; list = g_list_next (list))
|
||||
{
|
||||
GtkRichTextFormat *fmt = list->data;
|
||||
|
||||
if (fmt->atom == format)
|
||||
{
|
||||
GtkTextBufferSerializeFunc function = fmt->function;
|
||||
|
||||
return function (register_buffer, content_buffer,
|
||||
start, end, length, fmt->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_buffer_serialize:
|
||||
* @register_buffer: the #GtkTextBuffer %format is registered with
|
||||
* @content_buffer: the #GtkTextBuffer to deserialize into
|
||||
* @format: the rich text format to use for deserializing
|
||||
* @iter: insertion point for the deserialized text
|
||||
* @data: data to deserialize
|
||||
* @length: length of %data
|
||||
* @error: return loaction for a #GError
|
||||
*
|
||||
* This function deserializes rich text in format %format and inserts
|
||||
* it at %iter.
|
||||
*
|
||||
* %format<!-- -->s to be used must be registered using
|
||||
* gtk_text_buffer_register_deserialize_format() or
|
||||
* gtk_text_buffer_register_deserialize_tagset() beforehand.
|
||||
*
|
||||
* Return value: %TRUE on success, %FALSE otherwise.
|
||||
*
|
||||
* Since: 2.10
|
||||
**/
|
||||
gboolean
|
||||
gtk_text_buffer_deserialize (GtkTextBuffer *register_buffer,
|
||||
GtkTextBuffer *content_buffer,
|
||||
GdkAtom format,
|
||||
GtkTextIter *iter,
|
||||
const guint8 *data,
|
||||
gsize length,
|
||||
GError **error)
|
||||
{
|
||||
GList *formats;
|
||||
GList *list;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (register_buffer), FALSE);
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (content_buffer), FALSE);
|
||||
g_return_val_if_fail (format != GDK_NONE, FALSE);
|
||||
g_return_val_if_fail (iter != NULL, FALSE);
|
||||
g_return_val_if_fail (data != NULL, FALSE);
|
||||
g_return_val_if_fail (length > 0, FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
formats = g_object_get_qdata (G_OBJECT (register_buffer),
|
||||
deserialize_quark ());
|
||||
|
||||
for (list = formats; list; list = g_list_next (list))
|
||||
{
|
||||
GtkRichTextFormat *fmt = list->data;
|
||||
|
||||
if (fmt->atom == format)
|
||||
{
|
||||
GtkTextBufferDeserializeFunc function = fmt->function;
|
||||
gboolean success;
|
||||
|
||||
success = function (register_buffer, content_buffer,
|
||||
iter, data, length,
|
||||
fmt->can_create_tags,
|
||||
fmt->user_data,
|
||||
error);
|
||||
|
||||
if (!success && error != NULL && *error == NULL)
|
||||
g_set_error (error, 0, 0,
|
||||
_("Unknown error when trying to deserialize %s"),
|
||||
gdk_atom_name (format));
|
||||
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
g_set_error (error, 0, 0,
|
||||
_("No deserialize function found for format %s"),
|
||||
gdk_atom_name (format));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
||||
static GList *
|
||||
register_format (GList *formats,
|
||||
const gchar *mime_type,
|
||||
gpointer function,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_destroy,
|
||||
GdkAtom *atom)
|
||||
{
|
||||
GtkRichTextFormat *format;
|
||||
|
||||
*atom = gdk_atom_intern (mime_type, FALSE);
|
||||
|
||||
formats = unregister_format (formats, *atom);
|
||||
|
||||
format = g_new0 (GtkRichTextFormat, 1);
|
||||
|
||||
format->mime_type = g_strdup (mime_type);
|
||||
format->can_create_tags = FALSE;
|
||||
format->atom = *atom;
|
||||
format->function = function;
|
||||
format->user_data = user_data;
|
||||
format->user_data_destroy = user_data_destroy;
|
||||
|
||||
return g_list_append (formats, format);
|
||||
}
|
||||
|
||||
static GList *
|
||||
unregister_format (GList *formats,
|
||||
GdkAtom atom)
|
||||
{
|
||||
GList *list;
|
||||
|
||||
for (list = formats; list; list = g_list_next (list))
|
||||
{
|
||||
GtkRichTextFormat *format = list->data;
|
||||
|
||||
if (format->atom == atom)
|
||||
{
|
||||
free_format (format);
|
||||
|
||||
return g_list_delete_link (formats, list);
|
||||
}
|
||||
}
|
||||
|
||||
return formats;
|
||||
}
|
||||
|
||||
static GdkAtom *
|
||||
get_formats (GList *formats,
|
||||
gint *n_formats)
|
||||
{
|
||||
GdkAtom *array;
|
||||
GList *list;
|
||||
gint i;
|
||||
|
||||
*n_formats = g_list_length (formats);
|
||||
array = g_new0 (GdkAtom, *n_formats);
|
||||
|
||||
for (list = formats, i = 0; list; list = g_list_next (list), i++)
|
||||
{
|
||||
GtkRichTextFormat *format = list->data;
|
||||
|
||||
array[i] = format->atom;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
static void
|
||||
free_format (GtkRichTextFormat *format)
|
||||
{
|
||||
if (format->user_data_destroy)
|
||||
format->user_data_destroy (format->user_data);
|
||||
|
||||
g_free (format->mime_type);
|
||||
g_free (format);
|
||||
}
|
||||
|
||||
static void
|
||||
free_format_list (GList *formats)
|
||||
{
|
||||
g_list_foreach (formats, (GFunc) free_format, NULL);
|
||||
g_list_free (formats);
|
||||
}
|
||||
|
||||
static GQuark
|
||||
serialize_quark (void)
|
||||
{
|
||||
static GQuark quark = 0;
|
||||
|
||||
if (! quark)
|
||||
quark = g_quark_from_static_string ("gtk-text-buffer-serialize-formats");
|
||||
|
||||
return quark;
|
||||
}
|
||||
|
||||
static GQuark
|
||||
deserialize_quark (void)
|
||||
{
|
||||
static GQuark quark = 0;
|
||||
|
||||
if (! quark)
|
||||
quark = g_quark_from_static_string ("gtk-text-buffer-deserialize-formats");
|
||||
|
||||
return quark;
|
||||
}
|
||||
|
||||
#define __GTK_TEXT_BUFFER_RICH_TEXT_C__
|
||||
#include "gtkaliasdef.c"
|
92
gtk/gtktextbufferrichtext.h
Normal file
92
gtk/gtktextbufferrichtext.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* gtkrichtext.h
|
||||
*
|
||||
* Copyright (C) 2006 Imendio AB
|
||||
* Contact: Michael Natterer <mitch@imendio.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GTK_TEXT_BUFFER_RICH_TEXT_H__
|
||||
#define __GTK_TEXT_BUFFER_RICH_TEXT_H__
|
||||
|
||||
#include <gtk/gtktextbuffer.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef guint8 * (* GtkTextBufferSerializeFunc) (GtkTextBuffer *register_buffer,
|
||||
GtkTextBuffer *content_buffer,
|
||||
const GtkTextIter *start,
|
||||
const GtkTextIter *end,
|
||||
gsize *length,
|
||||
gpointer user_data);
|
||||
typedef gboolean (* GtkTextBufferDeserializeFunc) (GtkTextBuffer *register_buffer,
|
||||
GtkTextBuffer *content_buffer,
|
||||
GtkTextIter *iter,
|
||||
const guint8 *data,
|
||||
gsize length,
|
||||
gboolean create_tags,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
|
||||
GdkAtom gtk_text_buffer_register_serialize_format (GtkTextBuffer *buffer,
|
||||
const gchar *mime_type,
|
||||
GtkTextBufferSerializeFunc function,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_destroy);
|
||||
GdkAtom gtk_text_buffer_register_serialize_tagset (GtkTextBuffer *buffer,
|
||||
const gchar *tagset_name);
|
||||
|
||||
GdkAtom gtk_text_buffer_register_deserialize_format (GtkTextBuffer *buffer,
|
||||
const gchar *mime_type,
|
||||
GtkTextBufferDeserializeFunc function,
|
||||
gpointer user_data,
|
||||
GDestroyNotify user_data_destroy);
|
||||
GdkAtom gtk_text_buffer_register_deserialize_tagset (GtkTextBuffer *buffer,
|
||||
const gchar *tagset_name);
|
||||
|
||||
void gtk_text_buffer_unregister_serialize_format (GtkTextBuffer *buffer,
|
||||
GdkAtom format);
|
||||
void gtk_text_buffer_unregister_deserialize_format (GtkTextBuffer *buffer,
|
||||
GdkAtom format);
|
||||
|
||||
void gtk_text_buffer_deserialize_set_can_create_tags (GtkTextBuffer *buffer,
|
||||
GdkAtom format,
|
||||
gboolean can_create_tags);
|
||||
gboolean gtk_text_buffer_deserialize_get_can_create_tags (GtkTextBuffer *buffer,
|
||||
GdkAtom format);
|
||||
|
||||
GdkAtom * gtk_text_buffer_get_serialize_formats (GtkTextBuffer *buffer,
|
||||
gint *n_formats);
|
||||
GdkAtom * gtk_text_buffer_get_deserialize_formats (GtkTextBuffer *buffer,
|
||||
gint *n_formats);
|
||||
|
||||
guint8 * gtk_text_buffer_serialize (GtkTextBuffer *register_buffer,
|
||||
GtkTextBuffer *content_buffer,
|
||||
GdkAtom format,
|
||||
const GtkTextIter *start,
|
||||
const GtkTextIter *end,
|
||||
gsize *length);
|
||||
gboolean gtk_text_buffer_deserialize (GtkTextBuffer *register_buffer,
|
||||
GtkTextBuffer *content_buffer,
|
||||
GdkAtom format,
|
||||
GtkTextIter *iter,
|
||||
const guint8 *data,
|
||||
gsize length,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_TEXT_BUFFER_RICH_TEXT_H__ */
|
1877
gtk/gtktextbufferserialize.c
Normal file
1877
gtk/gtktextbufferserialize.c
Normal file
File diff suppressed because it is too large
Load Diff
43
gtk/gtktextbufferserialize.h
Normal file
43
gtk/gtktextbufferserialize.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* gtktextbufferserialize.h
|
||||
*
|
||||
* Copyright (C) 2004 Nokia Corporation.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GTK_TEXT_BUFFER_SERIALIZE_H__
|
||||
#define __GTK_TEXT_BUFFER_SERIALIZE_H__
|
||||
|
||||
#include <gtk/gtktextbuffer.h>
|
||||
|
||||
guint8 * _gtk_text_buffer_serialize_rich_text (GtkTextBuffer *register_buffer,
|
||||
GtkTextBuffer *content_buffer,
|
||||
const GtkTextIter *start,
|
||||
const GtkTextIter *end,
|
||||
gsize *length,
|
||||
gpointer user_data);
|
||||
|
||||
gboolean _gtk_text_buffer_deserialize_rich_text (GtkTextBuffer *register_buffer,
|
||||
GtkTextBuffer *content_buffer,
|
||||
GtkTextIter *iter,
|
||||
const guint8 *data,
|
||||
gsize length,
|
||||
gboolean create_tags,
|
||||
gpointer user_data,
|
||||
GError **error);
|
||||
|
||||
|
||||
#endif /* __GTK_TEXT_BUFFER_SERIALIZE_H__ */
|
@ -26,12 +26,19 @@
|
||||
|
||||
#include <config.h>
|
||||
#include "gtktextutil.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtktextview.h"
|
||||
|
||||
#define GTK_TEXT_USE_INTERNAL_UNSUPPORTED_API
|
||||
|
||||
#include "gtktextdisplay.h"
|
||||
#include "gtktextbuffer.h"
|
||||
#include "gtkmenuitem.h"
|
||||
#include "gtkintl.h"
|
||||
#include "gtkalias.h"
|
||||
|
||||
#define DRAG_ICON_MAX_WIDTH 250
|
||||
#define DRAG_ICON_LAYOUT_BORDER 2
|
||||
#define DRAG_ICON_MAX_HEIGHT 250
|
||||
#define DRAG_ICON_LAYOUT_BORDER 5
|
||||
#define DRAG_ICON_MAX_LINES 7
|
||||
#define ELLIPSIS_CHARACTER "\xe2\x80\xa6"
|
||||
|
||||
@ -238,3 +245,124 @@ _gtk_text_util_create_drag_icon (GtkWidget *widget,
|
||||
|
||||
return drawable;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_view_set_attributes_from_style (GtkTextView *text_view,
|
||||
GtkTextAttributes *values,
|
||||
GtkStyle *style)
|
||||
{
|
||||
values->appearance.bg_color = style->base[GTK_STATE_NORMAL];
|
||||
values->appearance.fg_color = style->text[GTK_STATE_NORMAL];
|
||||
|
||||
if (values->font)
|
||||
pango_font_description_free (values->font);
|
||||
|
||||
values->font = pango_font_description_copy (style->font_desc);
|
||||
}
|
||||
|
||||
GdkPixmap *
|
||||
_gtk_text_util_create_rich_drag_icon (GtkWidget *widget,
|
||||
GtkTextBuffer *buffer,
|
||||
GtkTextIter *start,
|
||||
GtkTextIter *end)
|
||||
{
|
||||
GdkDrawable *drawable = NULL;
|
||||
gint pixmap_height, pixmap_width;
|
||||
gint layout_width, layout_height;
|
||||
GtkTextBuffer *new_buffer;
|
||||
GtkTextLayout *layout;
|
||||
GtkTextAttributes *style;
|
||||
PangoContext *ltr_context, *rtl_context;
|
||||
GtkTextIter iter;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
|
||||
g_return_val_if_fail (GTK_IS_TEXT_BUFFER (buffer), NULL);
|
||||
g_return_val_if_fail (start != NULL, NULL);
|
||||
g_return_val_if_fail (end != NULL, NULL);
|
||||
|
||||
new_buffer = gtk_text_buffer_new (gtk_text_buffer_get_tag_table (buffer));
|
||||
gtk_text_buffer_get_start_iter (new_buffer, &iter);
|
||||
|
||||
gtk_text_buffer_insert_range (new_buffer, &iter, start, end);
|
||||
|
||||
gtk_text_buffer_get_start_iter (new_buffer, &iter);
|
||||
|
||||
layout = gtk_text_layout_new ();
|
||||
|
||||
ltr_context = gtk_widget_create_pango_context (widget);
|
||||
pango_context_set_base_dir (ltr_context, PANGO_DIRECTION_LTR);
|
||||
rtl_context = gtk_widget_create_pango_context (widget);
|
||||
pango_context_set_base_dir (rtl_context, PANGO_DIRECTION_RTL);
|
||||
|
||||
gtk_text_layout_set_contexts (layout, ltr_context, rtl_context);
|
||||
|
||||
g_object_unref (ltr_context);
|
||||
g_object_unref (rtl_context);
|
||||
|
||||
style = gtk_text_attributes_new ();
|
||||
|
||||
layout_width = widget->allocation.width;
|
||||
|
||||
if (GTK_IS_TEXT_VIEW (widget))
|
||||
{
|
||||
gtk_widget_ensure_style (widget);
|
||||
gtk_text_view_set_attributes_from_style (GTK_TEXT_VIEW (widget),
|
||||
style, widget->style);
|
||||
|
||||
layout_width = layout_width
|
||||
- gtk_text_view_get_border_window_size (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_LEFT)
|
||||
- gtk_text_view_get_border_window_size (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_RIGHT);
|
||||
}
|
||||
|
||||
style->direction = gtk_widget_get_direction (widget);
|
||||
style->wrap_mode = PANGO_WRAP_WORD_CHAR;
|
||||
|
||||
gtk_text_layout_set_default_style (layout, style);
|
||||
gtk_text_attributes_unref (style);
|
||||
|
||||
gtk_text_layout_set_buffer (layout, new_buffer);
|
||||
gtk_text_layout_set_cursor_visible (layout, FALSE);
|
||||
gtk_text_layout_set_screen_width (layout, layout_width);
|
||||
|
||||
gtk_text_layout_validate (layout, DRAG_ICON_MAX_HEIGHT);
|
||||
gtk_text_layout_get_size (layout, &layout_width, &layout_height);
|
||||
|
||||
g_print ("%s: layout size %d %d\n", G_STRFUNC, layout_width, layout_height);
|
||||
|
||||
layout_width = MIN (layout_width, DRAG_ICON_MAX_WIDTH);
|
||||
layout_height = MIN (layout_height, DRAG_ICON_MAX_HEIGHT);
|
||||
|
||||
pixmap_width = layout_width + DRAG_ICON_LAYOUT_BORDER * 2;
|
||||
pixmap_height = layout_height + DRAG_ICON_LAYOUT_BORDER * 2;
|
||||
|
||||
g_print ("%s: pixmap size %d %d\n", G_STRFUNC, pixmap_width, pixmap_height);
|
||||
|
||||
drawable = gdk_pixmap_new (widget->window,
|
||||
pixmap_width + 2, pixmap_height + 2, -1);
|
||||
|
||||
gdk_draw_rectangle (drawable,
|
||||
widget->style->base_gc [GTK_WIDGET_STATE (widget)],
|
||||
TRUE,
|
||||
0, 0,
|
||||
pixmap_width + 1,
|
||||
pixmap_height + 1);
|
||||
|
||||
gtk_text_layout_draw (layout, widget, drawable,
|
||||
widget->style->text_gc [GTK_WIDGET_STATE (widget)],
|
||||
- (1 + DRAG_ICON_LAYOUT_BORDER),
|
||||
- (1 + DRAG_ICON_LAYOUT_BORDER),
|
||||
0, 0,
|
||||
pixmap_width, pixmap_height, NULL);
|
||||
|
||||
gdk_draw_rectangle (drawable,
|
||||
widget->style->black_gc,
|
||||
FALSE,
|
||||
0, 0,
|
||||
pixmap_width + 1,
|
||||
pixmap_height + 1);
|
||||
|
||||
g_object_unref (layout);
|
||||
g_object_unref (new_buffer);
|
||||
|
||||
return drawable;
|
||||
}
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include <gtk/gtkwidget.h>
|
||||
#include <gtk/gtkmenushell.h>
|
||||
#include <gtk/gtkeditable.h>
|
||||
#include <gtk/gtktextbuffer.h>
|
||||
|
||||
|
||||
G_BEGIN_DECLS
|
||||
@ -50,5 +51,9 @@ G_END_DECLS
|
||||
GdkPixmap* _gtk_text_util_create_drag_icon (GtkWidget *widget,
|
||||
gchar *text,
|
||||
gsize len);
|
||||
GdkPixmap* _gtk_text_util_create_rich_drag_icon (GtkWidget *widget,
|
||||
GtkTextBuffer *buffer,
|
||||
GtkTextIter *start,
|
||||
GtkTextIter *end);
|
||||
|
||||
#endif /* __GTK_TEXT_UTIL_H__ */
|
||||
|
@ -39,6 +39,7 @@
|
||||
#include "gtkseparatormenuitem.h"
|
||||
#include "gtksettings.h"
|
||||
#include "gtkstock.h"
|
||||
#include "gtktextbufferrichtext.h"
|
||||
#include "gtktextdisplay.h"
|
||||
#include "gtktextview.h"
|
||||
#include "gtkimmulticontext.h"
|
||||
@ -314,6 +315,9 @@ static void gtk_text_view_mark_set_handler (GtkTextBuffer *buffer,
|
||||
const GtkTextIter *location,
|
||||
GtkTextMark *mark,
|
||||
gpointer data);
|
||||
static void gtk_text_view_target_list_notify (GtkTextBuffer *buffer,
|
||||
const GParamSpec *pspec,
|
||||
gpointer data);
|
||||
static void gtk_text_view_get_cursor_location (GtkTextView *text_view,
|
||||
GdkRectangle *pos);
|
||||
static void gtk_text_view_get_virtual_cursor_pos (GtkTextView *text_view,
|
||||
@ -414,10 +418,6 @@ static gint text_window_get_width (GtkTextWindow *win);
|
||||
static gint text_window_get_height (GtkTextWindow *win);
|
||||
|
||||
|
||||
static const GtkTargetEntry target_table[] = {
|
||||
{ "GTK_TEXT_BUFFER_CONTENTS", GTK_TARGET_SAME_APP, 0 },
|
||||
};
|
||||
|
||||
static GtkContainerClass *parent_class = NULL;
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
@ -1062,11 +1062,8 @@ gtk_text_view_init (GtkTextView *text_view)
|
||||
text_view->tabs = NULL;
|
||||
text_view->editable = TRUE;
|
||||
|
||||
gtk_drag_dest_set (widget,
|
||||
0,
|
||||
target_table, G_N_ELEMENTS (target_table),
|
||||
gtk_drag_dest_set (widget, 0, NULL, 0,
|
||||
GDK_ACTION_COPY | GDK_ACTION_MOVE);
|
||||
gtk_drag_dest_add_text_targets (widget);
|
||||
|
||||
text_view->virtual_cursor_x = -1;
|
||||
text_view->virtual_cursor_y = -1;
|
||||
@ -1190,6 +1187,9 @@ gtk_text_view_set_buffer (GtkTextView *text_view,
|
||||
g_signal_handlers_disconnect_by_func (text_view->buffer,
|
||||
gtk_text_view_mark_set_handler,
|
||||
text_view);
|
||||
g_signal_handlers_disconnect_by_func (text_view->buffer,
|
||||
gtk_text_view_target_list_notify,
|
||||
text_view);
|
||||
g_object_unref (text_view->buffer);
|
||||
text_view->dnd_mark = NULL;
|
||||
|
||||
@ -1225,7 +1225,13 @@ gtk_text_view_set_buffer (GtkTextView *text_view,
|
||||
text_view->first_para_pixels = 0;
|
||||
|
||||
g_signal_connect (text_view->buffer, "mark_set",
|
||||
G_CALLBACK (gtk_text_view_mark_set_handler), text_view);
|
||||
G_CALLBACK (gtk_text_view_mark_set_handler),
|
||||
text_view);
|
||||
g_signal_connect (text_view->buffer, "notify::paste-target-list",
|
||||
G_CALLBACK (gtk_text_view_target_list_notify),
|
||||
text_view);
|
||||
|
||||
gtk_text_view_target_list_notify (text_view->buffer, NULL, text_view);
|
||||
|
||||
if (GTK_WIDGET_REALIZED (text_view))
|
||||
{
|
||||
@ -5984,21 +5990,6 @@ gtk_text_view_reset_im_context (GtkTextView *text_view)
|
||||
}
|
||||
}
|
||||
|
||||
static gchar*
|
||||
_gtk_text_view_get_selected_text (GtkTextView *text_view)
|
||||
{
|
||||
GtkTextBuffer *buffer;
|
||||
GtkTextIter start, end;
|
||||
gchar *text = NULL;
|
||||
|
||||
buffer = gtk_text_view_get_buffer (text_view);
|
||||
|
||||
if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
|
||||
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
/*
|
||||
* DND feature
|
||||
*/
|
||||
@ -6008,29 +5999,30 @@ drag_begin_cb (GtkWidget *widget,
|
||||
GdkDragContext *context,
|
||||
gpointer data)
|
||||
{
|
||||
GtkTextView *text_view;
|
||||
gchar *text;
|
||||
GtkTextView *text_view = GTK_TEXT_VIEW (widget);
|
||||
GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
|
||||
GtkTextIter start;
|
||||
GtkTextIter end;
|
||||
GdkPixmap *pixmap = NULL;
|
||||
|
||||
g_signal_handlers_disconnect_by_func (widget, drag_begin_cb, NULL);
|
||||
|
||||
text_view = GTK_TEXT_VIEW (widget);
|
||||
|
||||
text = _gtk_text_view_get_selected_text (text_view);
|
||||
pixmap = _gtk_text_util_create_drag_icon (widget, text, -1);
|
||||
if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
|
||||
pixmap = _gtk_text_util_create_rich_drag_icon (widget, buffer, &start, &end);
|
||||
|
||||
if (pixmap)
|
||||
{
|
||||
gtk_drag_set_icon_pixmap (context,
|
||||
gdk_drawable_get_colormap (pixmap),
|
||||
pixmap,
|
||||
NULL,
|
||||
-2, -2);
|
||||
else
|
||||
gtk_drag_set_icon_default (context);
|
||||
|
||||
if (pixmap)
|
||||
g_object_unref (pixmap);
|
||||
g_free (text);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_drag_set_icon_default (context);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -6044,17 +6036,13 @@ gtk_text_view_start_selection_dnd (GtkTextView *text_view,
|
||||
text_view->drag_start_y = -1;
|
||||
text_view->pending_place_cursor_button = 0;
|
||||
|
||||
target_list = gtk_target_list_new (target_table,
|
||||
G_N_ELEMENTS (target_table));
|
||||
gtk_target_list_add_text_targets (target_list, 0);
|
||||
target_list = gtk_text_buffer_get_copy_target_list (get_buffer (text_view));
|
||||
|
||||
g_signal_connect (text_view, "drag-begin",
|
||||
G_CALLBACK (drag_begin_cb), NULL);
|
||||
gtk_drag_begin (GTK_WIDGET (text_view), target_list,
|
||||
GDK_ACTION_COPY | GDK_ACTION_MOVE,
|
||||
1, (GdkEvent*)event);
|
||||
|
||||
gtk_target_list_unref (target_list);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -6077,30 +6065,49 @@ gtk_text_view_drag_data_get (GtkWidget *widget,
|
||||
guint info,
|
||||
guint time)
|
||||
{
|
||||
GtkTextView *text_view;
|
||||
|
||||
text_view = GTK_TEXT_VIEW (widget);
|
||||
|
||||
if (selection_data->target == gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
|
||||
{
|
||||
GtkTextView *text_view = GTK_TEXT_VIEW (widget);
|
||||
GtkTextBuffer *buffer = gtk_text_view_get_buffer (text_view);
|
||||
|
||||
if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
|
||||
{
|
||||
gtk_selection_data_set (selection_data,
|
||||
gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"),
|
||||
8, /* bytes */
|
||||
(void*)&buffer,
|
||||
sizeof (buffer));
|
||||
}
|
||||
else
|
||||
else if (info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
|
||||
{
|
||||
gchar *str;
|
||||
GtkTextIter start;
|
||||
GtkTextIter end;
|
||||
guint8 *str = NULL;
|
||||
gsize len;
|
||||
|
||||
str = NULL;
|
||||
if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
|
||||
{
|
||||
/* Extract the selected text */
|
||||
str = gtk_text_buffer_serialize (buffer, buffer,
|
||||
selection_data->target,
|
||||
&start, &end,
|
||||
&len);
|
||||
}
|
||||
|
||||
if (gtk_text_buffer_get_selection_bounds (get_buffer (text_view),
|
||||
&start, &end))
|
||||
if (str)
|
||||
{
|
||||
gtk_selection_data_set (selection_data,
|
||||
selection_data->target,
|
||||
8, /* bytes */
|
||||
(guchar *) str, len);
|
||||
g_free (str);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkTextIter start;
|
||||
GtkTextIter end;
|
||||
gchar *str = NULL;
|
||||
|
||||
if (gtk_text_buffer_get_selection_bounds (buffer, &start, &end))
|
||||
{
|
||||
/* Extract the selected text */
|
||||
str = gtk_text_iter_get_visible_text (&start, &end);
|
||||
@ -6284,14 +6291,14 @@ insert_text_data (GtkTextView *text_view,
|
||||
GtkTextIter *drop_point,
|
||||
GtkSelectionData *selection_data)
|
||||
{
|
||||
gchar *str;
|
||||
guchar *str;
|
||||
|
||||
str = gtk_selection_data_get_text (selection_data);
|
||||
|
||||
if (str)
|
||||
{
|
||||
gtk_text_buffer_insert_interactive (get_buffer (text_view),
|
||||
drop_point, str, -1,
|
||||
drop_point, (gchar *) str, -1,
|
||||
text_view->editable);
|
||||
g_free (str);
|
||||
}
|
||||
@ -6329,7 +6336,7 @@ gtk_text_view_drag_data_received (GtkWidget *widget,
|
||||
|
||||
gtk_text_buffer_begin_user_action (buffer);
|
||||
|
||||
if (selection_data->target == gdk_atom_intern_static_string ("GTK_TEXT_BUFFER_CONTENTS"))
|
||||
if (info == GTK_TEXT_BUFFER_TARGET_INFO_BUFFER_CONTENTS)
|
||||
{
|
||||
GtkTextBuffer *src_buffer = NULL;
|
||||
GtkTextIter start, end;
|
||||
@ -6347,8 +6354,39 @@ gtk_text_view_drag_data_received (GtkWidget *widget,
|
||||
|
||||
if (gtk_text_buffer_get_tag_table (src_buffer) !=
|
||||
gtk_text_buffer_get_tag_table (buffer))
|
||||
{
|
||||
/* try to find a suitable rich text target instead */
|
||||
GdkAtom *atoms;
|
||||
gint n_atoms;
|
||||
GList *list;
|
||||
GdkAtom target = GDK_NONE;
|
||||
|
||||
copy_tags = FALSE;
|
||||
|
||||
atoms = gtk_text_buffer_get_deserialize_formats (buffer, &n_atoms);
|
||||
|
||||
for (list = context->targets; list; list = g_list_next (list))
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < n_atoms; i++)
|
||||
if (GUINT_TO_POINTER (atoms[i]) == list->data)
|
||||
{
|
||||
target = atoms[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_free (atoms);
|
||||
|
||||
if (target != GDK_NONE)
|
||||
{
|
||||
gtk_drag_get_data (widget, context, target, time);
|
||||
gtk_text_buffer_end_user_action (buffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (gtk_text_buffer_get_selection_bounds (src_buffer,
|
||||
&start,
|
||||
&end))
|
||||
@ -6371,6 +6409,25 @@ gtk_text_view_drag_data_received (GtkWidget *widget,
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (selection_data->length > 0 &&
|
||||
info == GTK_TEXT_BUFFER_TARGET_INFO_RICH_TEXT)
|
||||
{
|
||||
gboolean retval;
|
||||
GError *error = NULL;
|
||||
|
||||
retval = gtk_text_buffer_deserialize (buffer, buffer,
|
||||
selection_data->target,
|
||||
&drop_point,
|
||||
(guint8 *) selection_data->data,
|
||||
selection_data->length,
|
||||
&error);
|
||||
|
||||
if (!retval)
|
||||
{
|
||||
g_warning ("error pasting: %s\n", error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
else
|
||||
insert_text_data (text_view, &drop_point, selection_data);
|
||||
|
||||
@ -6825,6 +6882,14 @@ gtk_text_view_mark_set_handler (GtkTextBuffer *buffer,
|
||||
gtk_text_view_reset_im_context (text_view);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_view_target_list_notify (GtkTextBuffer *buffer,
|
||||
const GParamSpec *pspec,
|
||||
gpointer data)
|
||||
{
|
||||
gtk_drag_dest_set_target_list (data, gtk_text_buffer_get_paste_target_list (buffer));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_view_get_cursor_location (GtkTextView *text_view,
|
||||
GdkRectangle *pos)
|
||||
|
263
tests/testtext.c
263
tests/testtext.c
@ -1282,6 +1282,267 @@ do_properties (gpointer callback_data,
|
||||
create_prop_editor (G_OBJECT (view->text_view), 0);
|
||||
}
|
||||
|
||||
static void
|
||||
rich_text_store_populate (GtkListStore *store,
|
||||
GtkTextBuffer *buffer,
|
||||
gboolean deserialize)
|
||||
{
|
||||
GdkAtom *formats;
|
||||
gint n_formats;
|
||||
gint i;
|
||||
|
||||
gtk_list_store_clear (store);
|
||||
|
||||
if (deserialize)
|
||||
formats = gtk_text_buffer_get_deserialize_formats (buffer, &n_formats);
|
||||
else
|
||||
formats = gtk_text_buffer_get_serialize_formats (buffer, &n_formats);
|
||||
|
||||
for (i = 0; i < n_formats; i++)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
gchar *mime_type;
|
||||
gboolean can_create_tags = FALSE;
|
||||
|
||||
mime_type = gdk_atom_name (formats[i]);
|
||||
|
||||
if (deserialize)
|
||||
can_create_tags =
|
||||
gtk_text_buffer_deserialize_get_can_create_tags (buffer, formats[i]);
|
||||
|
||||
gtk_list_store_append (store, &iter);
|
||||
gtk_list_store_set (store, &iter,
|
||||
0, formats[i],
|
||||
1, mime_type,
|
||||
2, can_create_tags,
|
||||
-1);
|
||||
|
||||
g_free (mime_type);
|
||||
}
|
||||
|
||||
g_free (formats);
|
||||
}
|
||||
|
||||
static void
|
||||
rich_text_paste_target_list_notify (GtkTextBuffer *buffer,
|
||||
const GParamSpec *pspec,
|
||||
GtkListStore *store)
|
||||
{
|
||||
rich_text_store_populate (store, buffer, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
rich_text_copy_target_list_notify (GtkTextBuffer *buffer,
|
||||
const GParamSpec *pspec,
|
||||
GtkListStore *store)
|
||||
{
|
||||
rich_text_store_populate (store, buffer, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
rich_text_can_create_tags_toggled (GtkCellRendererToggle *toggle,
|
||||
const gchar *path,
|
||||
GtkTreeModel *model)
|
||||
{
|
||||
GtkTreeIter iter;
|
||||
|
||||
if (gtk_tree_model_get_iter_from_string (model, &iter, path))
|
||||
{
|
||||
GtkTextBuffer *buffer;
|
||||
GdkAtom format;
|
||||
gboolean can_create_tags;
|
||||
|
||||
buffer = g_object_get_data (G_OBJECT (model), "buffer");
|
||||
|
||||
gtk_tree_model_get (model, &iter,
|
||||
0, &format,
|
||||
2, &can_create_tags,
|
||||
-1);
|
||||
|
||||
gtk_text_buffer_deserialize_set_can_create_tags (buffer, format,
|
||||
!can_create_tags);
|
||||
|
||||
gtk_list_store_set (GTK_LIST_STORE (model), &iter,
|
||||
2, !can_create_tags,
|
||||
-1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rich_text_unregister_clicked (GtkWidget *button,
|
||||
GtkTreeView *tv)
|
||||
{
|
||||
GtkTreeSelection *sel = gtk_tree_view_get_selection (tv);
|
||||
GtkTreeModel *model;
|
||||
GtkTreeIter iter;
|
||||
|
||||
if (gtk_tree_selection_get_selected (sel, &model, &iter))
|
||||
{
|
||||
GtkTextBuffer *buffer;
|
||||
gboolean deserialize;
|
||||
GdkAtom format;
|
||||
|
||||
buffer = g_object_get_data (G_OBJECT (model), "buffer");
|
||||
deserialize = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (model),
|
||||
"deserialize"));
|
||||
|
||||
gtk_tree_model_get (model, &iter,
|
||||
0, &format,
|
||||
-1);
|
||||
|
||||
if (deserialize)
|
||||
gtk_text_buffer_unregister_deserialize_format (buffer, format);
|
||||
else
|
||||
gtk_text_buffer_unregister_serialize_format (buffer, format);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
rich_text_register_clicked (GtkWidget *button,
|
||||
GtkTreeView *tv)
|
||||
{
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *label;
|
||||
GtkWidget *entry;
|
||||
|
||||
dialog = gtk_dialog_new_with_buttons ("Register new Tagset",
|
||||
GTK_WINDOW (gtk_widget_get_toplevel (button)),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OK, GTK_RESPONSE_OK,
|
||||
NULL);
|
||||
label = gtk_label_new ("Enter tagset name or leave blank for "
|
||||
"unrestricted internal format:");
|
||||
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), label,
|
||||
FALSE, FALSE, 0);
|
||||
|
||||
entry = gtk_entry_new ();
|
||||
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), entry,
|
||||
FALSE, FALSE, 0);
|
||||
|
||||
gtk_widget_show_all (dialog);
|
||||
|
||||
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK)
|
||||
{
|
||||
GtkTreeModel *model = gtk_tree_view_get_model (tv);
|
||||
GtkTextBuffer *buffer = g_object_get_data (G_OBJECT (model), "buffer");
|
||||
const gchar *tagset = gtk_entry_get_text (GTK_ENTRY (entry));
|
||||
gboolean deserialize;
|
||||
|
||||
deserialize = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (model),
|
||||
"deserialize"));
|
||||
|
||||
if (tagset && ! strlen (tagset))
|
||||
tagset = NULL;
|
||||
|
||||
if (deserialize)
|
||||
gtk_text_buffer_register_deserialize_tagset (buffer, tagset);
|
||||
else
|
||||
gtk_text_buffer_register_serialize_tagset (buffer, tagset);
|
||||
}
|
||||
|
||||
gtk_widget_destroy (dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
do_rich_text (gpointer callback_data,
|
||||
guint deserialize,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
View *view = view_from_widget (widget);
|
||||
GtkTextBuffer *buffer;
|
||||
GtkWidget *dialog;
|
||||
GtkWidget *tv;
|
||||
GtkWidget *sw;
|
||||
GtkWidget *hbox;
|
||||
GtkWidget *button;
|
||||
GtkListStore *store;
|
||||
|
||||
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view->text_view));
|
||||
|
||||
dialog = gtk_dialog_new_with_buttons (deserialize ?
|
||||
"Rich Text Paste & Drop" :
|
||||
"Rich Text Copy & Drag",
|
||||
GTK_WINDOW (view->window),
|
||||
GTK_DIALOG_DESTROY_WITH_PARENT,
|
||||
GTK_STOCK_CLOSE, 0,
|
||||
NULL);
|
||||
g_signal_connect (dialog, "response",
|
||||
G_CALLBACK (gtk_widget_destroy),
|
||||
NULL);
|
||||
|
||||
store = gtk_list_store_new (3,
|
||||
G_TYPE_POINTER,
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_BOOLEAN);
|
||||
|
||||
g_object_set_data (G_OBJECT (store), "buffer", buffer);
|
||||
g_object_set_data (G_OBJECT (store), "deserialize",
|
||||
GUINT_TO_POINTER (deserialize));
|
||||
|
||||
tv = gtk_tree_view_new_with_model (GTK_TREE_MODEL (store));
|
||||
g_object_unref (store);
|
||||
|
||||
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tv),
|
||||
0, "Rich Text Format",
|
||||
gtk_cell_renderer_text_new (),
|
||||
"text", 1,
|
||||
NULL);
|
||||
|
||||
if (deserialize)
|
||||
{
|
||||
GtkCellRenderer *renderer = gtk_cell_renderer_toggle_new ();
|
||||
|
||||
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tv),
|
||||
1, "Can Create Tags",
|
||||
renderer,
|
||||
"active", 2,
|
||||
NULL);
|
||||
|
||||
g_signal_connect (renderer, "toggled",
|
||||
G_CALLBACK (rich_text_can_create_tags_toggled),
|
||||
store);
|
||||
}
|
||||
|
||||
sw = gtk_scrolled_window_new (NULL, NULL);
|
||||
gtk_widget_set_size_request (sw, 300, 100);
|
||||
gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), sw);
|
||||
|
||||
gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), tv);
|
||||
|
||||
hbox = gtk_hbox_new (FALSE, 6);
|
||||
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), hbox,
|
||||
FALSE, FALSE, 0);
|
||||
|
||||
button = gtk_button_new_with_label ("Unregister Selected Format");
|
||||
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
|
||||
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (rich_text_unregister_clicked),
|
||||
tv);
|
||||
|
||||
button = gtk_button_new_with_label ("Register New Tagset\n"
|
||||
"for the Internal Format");
|
||||
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
|
||||
|
||||
g_signal_connect (button, "clicked",
|
||||
G_CALLBACK (rich_text_register_clicked),
|
||||
tv);
|
||||
|
||||
if (deserialize)
|
||||
g_signal_connect_object (buffer, "notify::paste-target-list",
|
||||
G_CALLBACK (rich_text_paste_target_list_notify),
|
||||
G_OBJECT (store), 0);
|
||||
else
|
||||
g_signal_connect_object (buffer, "notify::copy-target-list",
|
||||
G_CALLBACK (rich_text_copy_target_list_notify),
|
||||
G_OBJECT (store), 0);
|
||||
|
||||
rich_text_store_populate (store, buffer, deserialize);
|
||||
|
||||
gtk_widget_show_all (dialog);
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
RESPONSE_FORWARD,
|
||||
@ -1697,6 +1958,8 @@ static GtkItemFactoryEntry menu_items[] =
|
||||
{ "/Attributes/No colors", NULL, do_apply_colors, FALSE, NULL },
|
||||
{ "/Attributes/Remove all tags", NULL, do_remove_tags, 0, NULL },
|
||||
{ "/Attributes/Properties", NULL, do_properties, 0, NULL },
|
||||
{ "/Attributes/Rich Text copy & drag", NULL, do_rich_text, 0, NULL },
|
||||
{ "/Attributes/Rich Text paste & drop", NULL, do_rich_text, 1, NULL },
|
||||
{ "/_Test", NULL, NULL, 0, "<Branch>" },
|
||||
{ "/Test/_Example", NULL, do_example, 0, NULL },
|
||||
{ "/Test/_Insert and scroll", NULL, do_insert_and_scroll, 0, NULL },
|
||||
|
Loading…
Reference in New Issue
Block a user