Compare commits

...

15 Commits

Author SHA1 Message Date
Matthias Clasen
5ffe8e53d2 GdkClipboard: always provide content types
It is a bit awkward if gdk_clipboard_get_content_types
returns nothing for text or image content. So, just return
the 'standard' content types: 'text/plain' and 'image/png'.
2014-06-16 17:05:00 -04:00
Matthias Clasen
777673e933 GdkClipboard: Add docs
Add a first round of doc comments.
2014-06-16 17:05:00 -04:00
Matthias Clasen
cc5d0d610b GdkClipboard: Add docs
Add a first round of doc comments.
2014-06-16 11:01:02 -04:00
Matthias Clasen
7be04cd2b1 More todo items 2014-06-16 08:33:55 -04:00
Matthias Clasen
867cd7e715 Add a quick todo list 2014-06-16 08:29:54 -04:00
Matthias Clasen
ecac4f0158 testclipboard2: better cleanup
Quit when the window is closed, to test owner-change notification
in the case where the owner goes away.
2014-06-16 08:28:01 -04:00
Matthias Clasen
308220ed15 Make testclipboard2 look nicer 2014-06-16 08:08:18 -04:00
Matthias Clasen
99ed426f01 Add an interactive test for GdkClipboard
This test can put text, images or data content on the clipboard
and receive such data as well. Button sensitivity is updated
based on the availability of suitable clipboard content.
2014-06-16 07:01:11 -04:00
Matthias Clasen
6b074dc0dd Hook clipboard into event handling
This commit makes GDK send clipboard-related events to the
GdkClipboard implementation first, before converting them
to GDK events and sending them up. This will let the old
clipboard implementation continue to work until it is no
longer needed.
2014-06-16 06:53:43 -04:00
Matthias Clasen
0b62a6c7d3 Add an X clipboard implementation
This is a basic X implementation of the GdkClipboard API.
Some things are still missing, such as handling for MULTIPLE
or INCR.
2014-06-16 06:53:38 -04:00
Matthias Clasen
eae294001d GdkDisplay: Export a function privately
Export the function to request selection notification, so we can
use it in the X clipboard implementation.
2014-06-16 06:25:23 -04:00
Matthias Clasen
11d7532ea5 Add some tests for the new clipboard API
This adds basic tests exercising the GdkClipboard API with
the fallback implementation.
2014-06-16 06:25:23 -04:00
Matthias Clasen
86bce6197e Add a fallback implementation
This is a local-only GdkClipboard implementation. It is useful for
test purposes, and as a fallback for 'primary' on platforms that
don't have a primary clipboard.
2014-06-16 06:25:23 -04:00
Matthias Clasen
24e570db39 Add GdkDisplay API to get clipboards
The obvious APIs. No backend implementation yet.
2014-06-16 06:25:23 -04:00
Matthias Clasen
aa16eee0d1 A GdkClipboard API draft
This commit adds a GdkClipboard object which is intended to
replace GtkClipboard, eventually. Currently, it supports setting
text, pixbufs and general data with mime types.
2014-06-16 06:13:22 -04:00
22 changed files with 3055 additions and 24 deletions

View File

@@ -24,6 +24,7 @@
<xi:include href="xml/gdkscreen.xml" />
<xi:include href="xml/gdkdevicemanager.xml" />
<xi:include href="xml/gdkdevice.xml" />
<xi:include href="xml/gdkclipboard.xml" />
<xi:include href="xml/regions.xml" />
<xi:include href="xml/pixbufs.xml" />
<xi:include href="xml/rgba_colors.xml" />

View File

@@ -156,6 +156,8 @@ gdk_display_supports_input_shapes
gdk_display_supports_composite
gdk_display_get_app_launch_context
gdk_display_notify_startup_complete
gdk_display_get_clipboard
gdk_display_get_primary
<SUBSECTION Standard>
GDK_DISPLAY
@@ -1273,3 +1275,28 @@ gdk_frame_timings_get_predicted_presentation_time
<SUBSECTION Private>
gdk_frame_get_type
</SECTION>
<SECTION>
<TITLE>GdkClipboard</TITLE>
<FILE>gdkclipboard</FILE>
GdkClipboard
gdk_clipboard_get_text_async
gdk_clipboard_get_text_finish
gdk_clipboard_set_text
gdk_clipboard_text_available
gdk_clipboard_get_image_async
gdk_clipboard_get_image_finish
gdk_clipboard_set_image
gdk_clipboard_image_available
gdk_clipboard_get_bytes_async
gdk_clipboard_get_bytes_finish
gdk_clipboard_set_bytes
gdk_clipboard_get_data_async
gdk_clipboard_get_data_finish
gdk_clipboard_set_data
gdk_clipboard_data_available
gdk_clipboard_clear
gdk_clipboard_get_content_types
<SUBSECTION Private>
gdk_clipboard_get_type
</SECTION>

View File

@@ -67,6 +67,8 @@ gdk_public_h_sources = \
gdk.h \
gdkapplaunchcontext.h \
gdkcairo.h \
gdkclipboard.h \
gdkclipboardfallback.h \
gdkcursor.h \
gdkdevice.h \
gdkdevicemanager.h \
@@ -103,6 +105,7 @@ gdk_h_sources = \
gdk_private_headers = \
gdkapplaunchcontextprivate.h \
gdkclipboardprivate.h \
gdkcursorprivate.h \
gdkdevicemanagerprivate.h \
gdkdeviceprivate.h \
@@ -111,9 +114,9 @@ gdk_private_headers = \
gdkdndprivate.h \
gdkframeclockidle.h \
gdkframeclockprivate.h \
gdkscreenprivate.h \
gdkinternals.h \
gdkintl.h \
gdkscreenprivate.h \
gdkkeysprivate.h \
gdkvisualprivate.h \
gdkx.h
@@ -126,6 +129,8 @@ gdk_c_sources = \
gdk.c \
gdkapplaunchcontext.c \
gdkcairo.c \
gdkclipboard.c \
gdkclipboardfallback.c \
gdkcursor.c \
gdkdeprecated.c \
gdkdevice.c \

View File

@@ -31,6 +31,8 @@
#include <gdk/gdkversionmacros.h>
#include <gdk/gdkapplaunchcontext.h>
#include <gdk/gdkcairo.h>
#include <gdk/gdkclipboard.h>
#include <gdk/gdkclipboardfallback.h>
#include <gdk/gdkcursor.h>
#include <gdk/gdkdevice.h>
#include <gdk/gdkdevicemanager.h>

681
gdk/gdkclipboard.c Normal file
View File

@@ -0,0 +1,681 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2014 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gdk/gdkclipboardprivate.h>
/**
* SECTION:gdkclipboard
* @Short_description: A clipboard class
* @Title: GdkClipboard
*
* The #GdkClipboard object represent a clipboard of data that
* is shared between different processes or between different widgets
* in the same process. GDK backends are responsible for implementing
* the #GdkClipboard API using their platforms data exchange mechanisms.
*
* GDK supports two different clipboards, which are historically named
* CLIPBOARD and PRIMARY. To obtain these clipboards, use
* gdk_display_get_clipboard() and gdk_display_get_primary(). The
* CLIPBOARD is supposed to be controlled explicitly by the user (e.g.
* using the common Ctrl-X/Ctrl-V shortcuts). The PRIMARY clipboard
* is supposed to always correspond to 'the current selection', which
* is a somewhat fuzzy concept. On platforms that don't support this
* distinction, GDK will provide a fallback implementation for the
* PRIMARY clipboard that only allows local data exchange inside the
* application.
*
* A GdkClipboard can hold data in different formats and types. Content
* types are represented as strings with mime types, such as "application/pdf".
*
* The most important data types, text and images, are supported explicitly
* with the functions gdk_clipboard_set_text(), gdk_clipboard_get_text_async(),
* gdk_clipboard_text_available() for text and gdk_clipboard_set_image(),
* gdk_clipboard_get_image_async() and gdk_clipboard_image_available()
* for images.
*
* To store other content in a GdkClipboard, use gdk_clipboard_set_bytes()
* or gdk_clipboard_set_data() and their corresponding getter functions.
*
* GdkClipboard was introduced in GTK+ 3.14.
*/
typedef struct _GdkClipboardPrivate GdkClipboardPrivate;
struct _GdkClipboardPrivate
{
GdkClipboardContent content;
gchar **content_types;
};
enum {
CHANGED,
N_SIGNALS
};
static guint signals[N_SIGNALS] = { 0 };
G_DEFINE_TYPE_WITH_PRIVATE (GdkClipboard, gdk_clipboard, G_TYPE_OBJECT)
static void
gdk_clipboard_init (GdkClipboard *clipboard)
{
}
static void
gdk_clipboard_finalize (GObject *object)
{
GdkClipboard *clipboard = GDK_CLIPBOARD (object);
GdkClipboardPrivate *priv = gdk_clipboard_get_instance_private (clipboard);
g_strfreev (priv->content_types);
G_OBJECT_CLASS (gdk_clipboard_parent_class)->finalize (object);
}
static void
gdk_clipboard_class_init (GdkClipboardClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
object_class->finalize = gdk_clipboard_finalize;
signals[CHANGED] =
g_signal_new ("changed",
G_TYPE_FROM_CLASS (class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GdkClipboardClass, changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
void
_gdk_clipboard_set_available_content (GdkClipboard *clipboard,
GdkClipboardContent content,
const gchar **content_types)
{
GdkClipboardPrivate *priv = gdk_clipboard_get_instance_private (clipboard);
const gchar *text_content_types[] = { "text/plain", NULL };
const gchar *image_content_types[] = { "image/png", NULL };
if (content_types == NULL)
{
if (content == TEXT_CONTENT)
content_types = text_content_types;
else if (content == IMAGE_CONTENT)
content_types = image_content_types;
}
priv->content = content;
g_strfreev (priv->content_types);
priv->content_types = g_strdupv ((gchar **)content_types);
g_signal_emit (clipboard, signals[CHANGED], 0);
}
GdkClipboardContent
_gdk_clipboard_get_available_content (GdkClipboard *clipboard)
{
GdkClipboardPrivate *priv = gdk_clipboard_get_instance_private (clipboard);
return priv->content;
}
/**
* gdk_clipboard_get_content_types:
* @clipboard: a #GdkClipboard
*
* Gets the content types for which the clipboard can currently
* provide content.
*
* Note that text and image data is not represented by content types.
* Instead, use gdk_clipboard_text_available() and
* gdk_clipboard_image_available() to check for text or image
* content.
*
* Returns: (transfer none): Content type of the current content
*
* Since: 3.14
*/
const gchar **
gdk_clipboard_get_content_types (GdkClipboard *clipboard)
{
GdkClipboardPrivate *priv;
g_return_val_if_fail (GDK_IS_CLIPBOARD (clipboard), NULL);
priv = gdk_clipboard_get_instance_private (clipboard);
return (const gchar **)priv->content_types;
}
static gboolean
strv_contains (const gchar **strv, const gchar *s)
{
gint i;
for (i = 0; strv[i]; i++)
{
if (g_strcmp0 (strv[i], s) == 0)
return TRUE;
}
return FALSE;
}
/**
* gdk_clipboard_data_available:
* @clipboard: a #GdkClipboard
* @content_type: the content type to check for
*
* Returns whether the clipboard can currently provide content
* of the given type.
*
* Note that text and image data is not represented by content types.
* Instead, use gdk_clipboard_text_available() and
* gdk_clipboard_image_available() to check for text or image
* content.
*
* Returns: (transfer none): %TRUE if content of the given type is available
*
* Since: 3.14
*/
gboolean
gdk_clipboard_data_available (GdkClipboard *clipboard,
const gchar *content_type)
{
GdkClipboardPrivate *priv;
g_return_val_if_fail (GDK_IS_CLIPBOARD (clipboard), FALSE);
priv = gdk_clipboard_get_instance_private (clipboard);
return priv->content_types != NULL &&
strv_contains ((const gchar **)priv->content_types, content_type);
}
/**
* gdk_clipboard_get_text_async:
* @clipboard: a #GdkClipboard
* @cancellable: (allow-none): a #GCancellable
* @callback: the callback to call when the text is available
* @user_data: data that gets passed to @callback
*
* Retrieves the text content of the clipboard. This may involve
* inter-process communication with the current owner of the system
* clipboard. Therefore, it is implemented as an asynchronous
* operation.
*
* When the asynchronous operation is completed, @callback is called.
* It should call gdk_clipboard_get_text_finish() to retrieve the text.
*
* Since: 3.14
*/
void
gdk_clipboard_get_text_async (GdkClipboard *clipboard,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_return_if_fail (GDK_IS_CLIPBOARD (clipboard));
GDK_CLIPBOARD_GET_CLASS (clipboard)->get_text_async (clipboard, cancellable, callback, user_data);
}
/**
* gdk_clipboard_get_text_finish:
* @clipboard: a #GdkClipboard
* @res: the #GAsyncResult
* @error: return location for an error
*
* Obtains the result of a gdk_clipboard_get_text_async() call.
* This function may only be called from a callback passed
* to gdk_clipboard_get_text_async().
*
* If the clipboard does not contain text, %NULL is returned.
*
* Returns: (transfer full): the current text content of the clipboard
*
* Since: 3.14
*/
gchar *
gdk_clipboard_get_text_finish (GdkClipboard *clipboard,
GAsyncResult *res,
GError **error)
{
g_return_val_if_fail (GDK_IS_CLIPBOARD (clipboard), NULL);
return GDK_CLIPBOARD_GET_CLASS (clipboard)->get_text_finish (clipboard, res, error);
}
/**
* gdk_clipboard_set_text:
* @clipboard: a #GdkClipboard
* @text: the text to store in the clipboard
*
* Sets the clipboard content to the given text.
*
* The clipboard makes a copy of the text and provides it
* to requestors until the clipboard gets overwritten with
* new content from this or another process, or until
* gdk_clipboard_clear() is called.
*
* Since: 3.14
*/
void
gdk_clipboard_set_text (GdkClipboard *clipboard,
const gchar *text)
{
g_return_if_fail (GDK_IS_CLIPBOARD (clipboard));
GDK_CLIPBOARD_GET_CLASS (clipboard)->set_text (clipboard, text);
}
/**
* gdk_clipboard_text_available:
* @clipboard:
*
* Returns whether the clipboard currently contains text.
*
* Returns: %TRUE if the clipboard contains text
*
* Since: 3.14
*/
gboolean
gdk_clipboard_text_available (GdkClipboard *clipboard)
{
GdkClipboardPrivate *priv;
g_return_val_if_fail (GDK_IS_CLIPBOARD (clipboard), FALSE);
priv = gdk_clipboard_get_instance_private (clipboard);
return ((priv->content & TEXT_CONTENT) != 0);
}
/**
* gdk_clipboard_get_image_async:
* @clipboard: a #GdkClipboard
* @cancellable: (allow-none): a #GCancellable
* @callback: the callback to call when the text is available
* @user_data: data that gets passed to @callback
*
* Retrieves the image content of the clipboard. This may involve
* inter-process communication with the current owner of the system
* clipboard. Therefore, it is implemented as an asynchronous
* operation.
*
* When the asynchronous operation is completed, @callback is called.
* It should call gdk_clipboard_get_image_finish() to retrieve the text.
*
* Since: 3.14
*/
void
gdk_clipboard_get_image_async (GdkClipboard *clipboard,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_return_if_fail (GDK_IS_CLIPBOARD (clipboard));
GDK_CLIPBOARD_GET_CLASS (clipboard)->get_image_async (clipboard, cancellable, callback, user_data);
}
/**
* gdk_clipboard_get_image_finish:
* @clipboard: a #GdkClipboard
* @res: the #GAsyncResult
* @error: return location for an error
*
* Obtains the result of a gdk_clipboard_get_image_async() call.
* This function may only be called from a callback passed
* to gdk_clipboard_get_image_async().
*
* If the clipboard does not contain an image, %NULL is returned.
*
* Returns: (transfer full): the current image content of the clipboard
*
* Since: 3.14
*/
GdkPixbuf *
gdk_clipboard_get_image_finish (GdkClipboard *clipboard,
GAsyncResult *res,
GError **error)
{
g_return_val_if_fail (GDK_IS_CLIPBOARD (clipboard), NULL);
return GDK_CLIPBOARD_GET_CLASS (clipboard)->get_image_finish (clipboard, res, error);
}
/**
* gdk_clipboard_set_image:
* @clipboard: a #GdkClipboard
* @pixbuf: the image to store in the clipboard
*
* Sets the clipboard content to the given image.
*
* The clipboard takes a reference on @pixbuf and provides it
* to requestors until the clipboard gets overwritten with
* new content from this or another process, or until
* gdk_clipboard_clear() is called.
*
* Since: 3.14
*/
void
gdk_clipboard_set_image (GdkClipboard *clipboard,
GdkPixbuf *pixbuf)
{
g_return_if_fail (GDK_IS_CLIPBOARD (clipboard));
GDK_CLIPBOARD_GET_CLASS (clipboard)->set_image (clipboard, pixbuf);
}
/**
* gdk_clipboard_image_available:
* @clipboard:
*
* Returns whether the clipboard currently contains an image.
*
* Returns: %TRUE if the clipboard contains an image
*
* Since: 3.14
*/
gboolean
gdk_clipboard_image_available (GdkClipboard *clipboard)
{
GdkClipboardPrivate *priv;
g_return_val_if_fail (GDK_IS_CLIPBOARD (clipboard), FALSE);
priv = gdk_clipboard_get_instance_private (clipboard);
return (priv->content & IMAGE_CONTENT) != 0;
}
/**
* gdk_clipboard_get_data_async:
* @clipboard: a #GdkClipboard
* @content_type: the type of content to retrieve
* @cancellable: (allow-none): a #GCancellable
* @callback: the callback to call when the text is available
* @user_data: data that gets passed to @callback
*
* Retrieves the content of the clipboard with the given content type.
* This may involve inter-process communication with the current owner
* of the system clipboard. Therefore, it is implemented as an
* asynchronous operation.
*
* When the asynchronous operation is completed, @callback is called.
* It should call gdk_clipboard_get_data_finish() to retrieve the text.
*
* Since: 3.14
*/
void
gdk_clipboard_get_data_async (GdkClipboard *clipboard,
const gchar *content_type,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_return_if_fail (GDK_IS_CLIPBOARD (clipboard));
GDK_CLIPBOARD_GET_CLASS (clipboard)->get_data_async (clipboard, content_type, cancellable, callback, user_data);
}
/**
* gdk_clipboard_get_data_finish:
* @clipboard: a #GdkClipboard
* @res: the #GAsyncResult
* @error: return location for an error
*
* Obtains the result of a gdk_clipboard_get_data_async() call.
* This function may only be called from a callback passed
* to gdk_clipboard_get_data_async().
*
* If the clipboard does not contain content with the type that
* was passed to gdk_clipboard_get_data_async(), %NULL is returned.
*
* Returns: (transfer full): an input stream from which the current
* content of the clipboard can be read
*
* Since: 3.14
*/
GInputStream *
gdk_clipboard_get_data_finish (GdkClipboard *clipboard,
GAsyncResult *res,
GError **error)
{
g_return_val_if_fail (GDK_IS_CLIPBOARD (clipboard), NULL);
return GDK_CLIPBOARD_GET_CLASS (clipboard)->get_data_finish (clipboard, res, error);
}
/**
* gdk_clipboard_set_data:
* @clipboard: a #GdkClipboard
* @content_types: content types that can be provided
* @callback: the function that will be called to retrieve the content
* @user_data: user data that gets passed to @callback
* @destroy: destroy notify for @user_data
*
* Sets the clipboard content. The content will be retrieved on demand
* by the @callback function.
*
* Since: 3.14
*/
void
gdk_clipboard_set_data (GdkClipboard *clipboard,
const gchar **content_types,
GdkClipboardProvider callback,
gpointer user_data,
GDestroyNotify destroy)
{
g_return_if_fail (GDK_IS_CLIPBOARD (clipboard));
GDK_CLIPBOARD_GET_CLASS (clipboard)->set_data (clipboard, content_types, callback, user_data, destroy);
}
/**
* gdk_clipboard_clear:
* @clipboard: a #GdkClipboard
*
* Clears the clipboard.
*
* If the clipboard is currently holding the system clipboard,
* this implies that the clipboard will no longer provide content
* to other processes. If the system clipboard is currently held
* by another process, this call will drop any cached content,
* and the next call to get content will retrieve it from the
* other process again.
*
* Since: 3.14
*/
void
gdk_clipboard_clear (GdkClipboard *clipboard)
{
g_return_if_fail (GDK_IS_CLIPBOARD (clipboard));
GDK_CLIPBOARD_GET_CLASS (clipboard)->clear (clipboard);
}
typedef struct {
GAsyncReadyCallback callback;
gpointer user_data;
} GetBytesData;
static void
get_bytes (GObject *object,
GAsyncResult *res,
gpointer user_data)
{
GdkClipboard *clipboard = GDK_CLIPBOARD (object);
GetBytesData *data = user_data;
GError *error;
GBytes *bytes;
GInputStream *istream;
GOutputStream *ostream;
error = NULL;
bytes = NULL;
istream = gdk_clipboard_get_data_finish (clipboard, res, &error);
if (istream)
{
ostream = g_memory_output_stream_new_resizable ();
g_output_stream_splice (ostream, istream, G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE | G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, NULL, NULL);
bytes = g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (ostream));
g_object_unref (ostream);
g_object_unref (istream);
}
g_object_set_data (G_OBJECT (res), "error", error);
g_object_set_data (G_OBJECT (res), "bytes", bytes);
data->callback (object, res, data->user_data);
g_free (data);
}
/**
* gdk_clipboard_get_bytes_async:
* @clipboard: a #GdkClipboard
* @content_type: the type of content to retrieve
* @cancellable: (allow-none): a #GCancellable
* @callback: the callback to call when the text is available
* @user_data: data that gets passed to @callback
*
* Retrieves the content of the clipboard with the given content type
* as a #GBytes. This may involve inter-process communication with the
* current owner of the system clipboard. Therefore, it is implemented
* as an asynchronous operation.
*
* When the asynchronous operation is completed, @callback is called.
* It should call gdk_clipboard_get_bytes_finish() to retrieve the text.
*
* Since: 3.14
*/
void
gdk_clipboard_get_bytes_async (GdkClipboard *clipboard,
const gchar *content_type,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GetBytesData *data;
g_return_if_fail (GDK_IS_CLIPBOARD (clipboard));
data = g_new (GetBytesData, 1);
data->callback = callback;
data->user_data = user_data;
gdk_clipboard_get_data_async (clipboard, content_type, cancellable, get_bytes, data);
}
/**
* gdk_clipboard_get_bytes_finish:
* @clipboard: a #GdkClipboard
* @res: the #GAsyncResult
* @error: return location for an error
*
* Obtains the result of a gdk_clipboard_get_bytes_async() call.
* This function may only be called from a callback passed
* to gdk_clipboard_get_bytes_async().
*
* If the clipboard does not contain content with the type that
* was passed to gdk_clipboard_get_bytes_async(), %NULL is returned.
*
* Returns: (transfer full): a #GBytes with the current
* content of the clipboard
*
* Since: 3.14
*/
GBytes *
gdk_clipboard_get_bytes_finish (GdkClipboard *clipboard,
GAsyncResult *res,
GError **error)
{
g_return_val_if_fail (GDK_IS_CLIPBOARD (clipboard), NULL);
GError *inner;
GBytes *bytes;
inner = g_object_get_data (G_OBJECT (res), "error");
bytes = g_object_get_data (G_OBJECT (res), "bytes");
if (inner)
g_propagate_error (error, inner);
return bytes;
}
static void
set_bytes (GdkClipboard *clipboard,
const gchar *content_type,
GOutputStream *stream,
gpointer user_data)
{
GBytes *bytes = user_data;
GBytes *rest;
gssize written;
g_bytes_ref (bytes);
while (TRUE)
{
written = g_output_stream_write_bytes (stream, bytes, NULL, NULL);
if (written == g_bytes_get_size (bytes) || written == -1)
break;
rest = g_bytes_new_from_bytes (bytes, written, g_bytes_get_size (bytes) - written);
g_bytes_unref (bytes);
bytes = rest;
}
g_bytes_unref (bytes);
}
/**
* gdk_clipboard_set_bytes:
* @clipboard: a #GdkClipboard
* @bytes: the content in a #GBytes
* @content_types: content types that can be provided
*
* Sets the clipboard content from a #GBytes.
*
* The clipboard takes a reference on @bytes and provides
* its content to requestors until the clipboard gets
* overwritten with new content from this or another
* process, or until gdk_clipboard_clear() is called.
*
* Since: 3.14
*/
void
gdk_clipboard_set_bytes (GdkClipboard *clipboard,
GBytes *bytes,
const gchar *content_type)
{
g_return_if_fail (GDK_IS_CLIPBOARD (clipboard));
const gchar *ctypes[2];
ctypes[0] = content_type;
ctypes[1] = NULL;
/* create stream from bytes */
gdk_clipboard_set_data (clipboard, ctypes, set_bytes, g_bytes_ref (bytes), (GDestroyNotify) g_bytes_unref);
}

124
gdk/gdkclipboard.h Normal file
View File

@@ -0,0 +1,124 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2014 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_CLIPBOARD_H__
#define __GDK_CLIPBOARD_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
#include <gdk/gdkversionmacros.h>
#include <gdk/gdktypes.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
G_BEGIN_DECLS
#define GDK_TYPE_CLIPBOARD (gdk_clipboard_get_type ())
#define GDK_CLIPBOARD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_CLIPBOARD, GdkClipboard))
#define GDK_IS_CLIPBOARD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_CLIPBOARD))
typedef struct _GdkClipboard GdkClipboard;
typedef void (* GdkClipboardProvider) (GdkClipboard *clipboard,
const gchar *content_type,
GOutputStream *output,
gpointer user_data);
GDK_AVAILABLE_IN_3_14
GType gdk_clipboard_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_14
void gdk_clipboard_get_text_async (GdkClipboard *clipboard,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GDK_AVAILABLE_IN_3_14
gchar * gdk_clipboard_get_text_finish (GdkClipboard *clipboard,
GAsyncResult *res,
GError **error);
GDK_AVAILABLE_IN_3_14
void gdk_clipboard_set_text (GdkClipboard *clipboard,
const gchar *text);
GDK_AVAILABLE_IN_3_14
gboolean gdk_clipboard_text_available (GdkClipboard *clipboard);
GDK_AVAILABLE_IN_3_14
void gdk_clipboard_get_image_async (GdkClipboard *clipboard,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GDK_AVAILABLE_IN_3_14
GdkPixbuf * gdk_clipboard_get_image_finish (GdkClipboard *clipboard,
GAsyncResult *res,
GError **error);
GDK_AVAILABLE_IN_3_14
void gdk_clipboard_set_image (GdkClipboard *clipboard,
GdkPixbuf *pixbuf);
GDK_AVAILABLE_IN_3_14
gboolean gdk_clipboard_image_available (GdkClipboard *clipboard);
GDK_AVAILABLE_IN_3_14
void gdk_clipboard_get_bytes_async (GdkClipboard *clipboard,
const gchar *content_type,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GDK_AVAILABLE_IN_3_14
GBytes * gdk_clipboard_get_bytes_finish (GdkClipboard *clipboard,
GAsyncResult *res,
GError **error);
GDK_AVAILABLE_IN_3_14
void gdk_clipboard_set_bytes (GdkClipboard *clipboard,
GBytes *data,
const gchar *content_type);
GDK_AVAILABLE_IN_3_14
void gdk_clipboard_get_data_async (GdkClipboard *clipboard,
const gchar *content_type,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GDK_AVAILABLE_IN_3_14
GInputStream * gdk_clipboard_get_data_finish (GdkClipboard *clipboard,
GAsyncResult *res,
GError **error);
GDK_AVAILABLE_IN_3_14
void gdk_clipboard_set_data (GdkClipboard *clipboard,
const gchar **content_types,
GdkClipboardProvider callback,
gpointer user_data,
GDestroyNotify destroy);
GDK_AVAILABLE_IN_3_14
gboolean gdk_clipboard_data_available (GdkClipboard *clipboard,
const gchar *content_type);
GDK_AVAILABLE_IN_3_14
void gdk_clipboard_clear (GdkClipboard *clipboard);
GDK_AVAILABLE_IN_3_14
const gchar **gdk_clipboard_get_content_types (GdkClipboard *clipboard);
G_END_DECLS
#endif /* __GDK_CLIPBOARD_H__ */

333
gdk/gdkclipboardfallback.c Normal file
View File

@@ -0,0 +1,333 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2014 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gdk/gdkclipboardprivate.h>
#include <gdk/gdkclipboardfallback.h>
typedef struct _GdkClipboardFallbackClass GdkClipboardFallbackClass;
struct _GdkClipboardFallback
{
GdkClipboard parent;
gchar *text;
GdkPixbuf *pixbuf;
GdkClipboardProvider provider;
gpointer data;
GDestroyNotify destroy;
};
struct _GdkClipboardFallbackClass
{
GdkClipboardClass parent_class;
};
G_DEFINE_TYPE (GdkClipboardFallback, gdk_clipboard_fallback, GDK_TYPE_CLIPBOARD)
static void
clear_data (GdkClipboardFallback *cf)
{
if (cf->text)
{
g_free (cf->text);
cf->text = NULL;
}
if (cf->pixbuf)
{
g_object_unref (cf->pixbuf);
cf->pixbuf = NULL;
}
if (cf->provider)
{
if (cf->destroy)
cf->destroy (cf->data);
cf->provider = NULL;
cf->data = NULL;
cf->destroy = NULL;
}
}
static void
gdk_clipboard_fallback_get_text_async (GdkClipboard *clipboard,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *res;
res = g_simple_async_result_new (G_OBJECT (clipboard),
callback, user_data,
gdk_clipboard_fallback_get_text_async);
g_simple_async_result_complete (res);
g_object_unref (res);
}
static gchar *
gdk_clipboard_fallback_get_text_finish (GdkClipboard *clipboard,
GAsyncResult *res,
GError **error)
{
GdkClipboardFallback *cf = GDK_CLIPBOARD_FALLBACK (clipboard);
g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (cf), gdk_clipboard_fallback_get_text_async), NULL);
if (_gdk_clipboard_get_available_content (clipboard) != TEXT_CONTENT)
{
/* FIXME: set error ? */
return NULL;
}
return g_strdup (cf->text);
}
static void
gdk_clipboard_fallback_set_text (GdkClipboard *clipboard,
const gchar *text)
{
GdkClipboardFallback *cf = GDK_CLIPBOARD_FALLBACK (clipboard);
clear_data (cf);
cf->text = g_strdup (text);
_gdk_clipboard_set_available_content (clipboard, TEXT_CONTENT, NULL);
}
static void
gdk_clipboard_fallback_get_image_async (GdkClipboard *clipboard,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *res;
res = g_simple_async_result_new (G_OBJECT (clipboard),
callback, user_data,
gdk_clipboard_fallback_get_image_async);
g_simple_async_result_complete (res);
g_object_unref (res);
}
static GdkPixbuf *
gdk_clipboard_fallback_get_image_finish (GdkClipboard *clipboard,
GAsyncResult *res,
GError **error)
{
GdkClipboardFallback *cf = GDK_CLIPBOARD_FALLBACK (clipboard);
g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (cf), gdk_clipboard_fallback_get_image_async), NULL);
if (_gdk_clipboard_get_available_content (clipboard) != IMAGE_CONTENT)
{
/* FIXME: set error ? */
return NULL;
}
return g_object_ref (cf->pixbuf);
}
static void
gdk_clipboard_fallback_set_image (GdkClipboard *clipboard,
GdkPixbuf *pixbuf)
{
GdkClipboardFallback *cf = GDK_CLIPBOARD_FALLBACK (clipboard);
clear_data (cf);
cf->pixbuf = g_object_ref (pixbuf);
_gdk_clipboard_set_available_content (clipboard, IMAGE_CONTENT, NULL);
}
static void
gdk_clipboard_fallback_get_data_async (GdkClipboard *clipboard,
const gchar *content_type,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *res;
res = g_simple_async_result_new (G_OBJECT (clipboard),
callback, user_data,
gdk_clipboard_fallback_get_data_async);
g_object_set_data (G_OBJECT (res), "ctype", (gpointer) content_type);
g_simple_async_result_complete (res);
g_object_unref (res);
}
typedef struct
{
GOutputStream parent;
GMemoryInputStream *is;
} ReadbackOutputStream;
typedef struct
{
GOutputStreamClass parent_class;
} ReadbackOutputStreamClass;
G_DEFINE_TYPE (ReadbackOutputStream, readback_output_stream, G_TYPE_OUTPUT_STREAM)
static void
readback_output_stream_init (ReadbackOutputStream *stream)
{
}
static gssize
readback_output_stream_write (GOutputStream *stream,
const void *buffer,
gsize count,
GCancellable *cancellable,
GError **error)
{
ReadbackOutputStream *rs = (ReadbackOutputStream *)stream;
if (count)
g_memory_input_stream_add_data (rs->is, g_memdup (buffer, count), count, g_free);
return count;
}
static void
readback_output_stream_finalize (GObject *obj)
{
ReadbackOutputStream *rs = (ReadbackOutputStream *)obj;
g_object_unref (rs->is);
G_OBJECT_CLASS (readback_output_stream_parent_class)->finalize (obj);
}
static void
readback_output_stream_class_init (ReadbackOutputStreamClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GOutputStreamClass *ostream_class = G_OUTPUT_STREAM_CLASS (class);
object_class->finalize = readback_output_stream_finalize;
ostream_class->write_fn = readback_output_stream_write;
}
static GOutputStream *
readback_output_stream_new (GMemoryInputStream *is)
{
ReadbackOutputStream *stream;
stream = g_object_new (readback_output_stream_get_type (), NULL);
stream->is = g_object_ref (is);
return G_OUTPUT_STREAM (stream);
}
static GInputStream *
gdk_clipboard_fallback_get_data_finish (GdkClipboard *clipboard,
GAsyncResult *res,
GError **error)
{
GdkClipboardFallback *cf = GDK_CLIPBOARD_FALLBACK (clipboard);
const gchar *ctype;
GOutputStream *ostream = NULL;
GInputStream *istream = NULL;
g_return_val_if_fail (g_simple_async_result_is_valid (res, G_OBJECT (cf), gdk_clipboard_fallback_get_data_async), NULL);
ctype = (const gchar *) g_object_get_data (G_OBJECT (res), "ctype");
if (!gdk_clipboard_data_available (clipboard, ctype))
{
/* FIXME: set error ? */
return NULL;
}
istream = g_memory_input_stream_new ();
ostream = readback_output_stream_new (G_MEMORY_INPUT_STREAM (istream));
cf->provider (clipboard, ctype, ostream, cf->data);
g_object_unref (ostream);
return istream;
}
static void
gdk_clipboard_fallback_set_data (GdkClipboard *clipboard,
const gchar **content_types,
GdkClipboardProvider provider,
gpointer data,
GDestroyNotify destroy)
{
GdkClipboardFallback *cf = GDK_CLIPBOARD_FALLBACK (clipboard);
clear_data (cf);
cf->provider = provider;
cf->data = data;
cf->destroy = destroy;
_gdk_clipboard_set_available_content (clipboard, OTHER_CONTENT, content_types);
}
static void
gdk_clipboard_fallback_clear (GdkClipboard *clipboard)
{
GdkClipboardFallback *cf = GDK_CLIPBOARD_FALLBACK (clipboard);
clear_data (cf);
_gdk_clipboard_set_available_content (clipboard, NO_CONTENT, NULL);
}
static void
gdk_clipboard_fallback_init (GdkClipboardFallback *clipboard)
{
}
static void
gdk_clipboard_fallback_finalize (GObject *object)
{
GdkClipboardFallback *cf = GDK_CLIPBOARD_FALLBACK (object);
clear_data (cf);
G_OBJECT_CLASS (gdk_clipboard_fallback_parent_class)->finalize (object);
}
static void
gdk_clipboard_fallback_class_init (GdkClipboardFallbackClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GdkClipboardClass *clipboard_class = GDK_CLIPBOARD_CLASS (class);
object_class->finalize = gdk_clipboard_fallback_finalize;
clipboard_class->get_text_async = gdk_clipboard_fallback_get_text_async;
clipboard_class->get_text_finish = gdk_clipboard_fallback_get_text_finish;
clipboard_class->set_text = gdk_clipboard_fallback_set_text;
clipboard_class->get_image_async = gdk_clipboard_fallback_get_image_async;
clipboard_class->get_image_finish = gdk_clipboard_fallback_get_image_finish;
clipboard_class->set_image = gdk_clipboard_fallback_set_image;
clipboard_class->get_data_async = gdk_clipboard_fallback_get_data_async;
clipboard_class->get_data_finish = gdk_clipboard_fallback_get_data_finish;
clipboard_class->set_data = gdk_clipboard_fallback_set_data;
clipboard_class->clear = gdk_clipboard_fallback_clear;
}
GdkClipboard *
gdk_clipboard_fallback_new (void)
{
return GDK_CLIPBOARD (g_object_new (GDK_TYPE_CLIPBOARD_FALLBACK, NULL));
}

View File

@@ -0,0 +1,44 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2014 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_CLIPBOARD_FALLBACK_H__
#define __GDK_CLIPBOARD_FALLBACK_H__
#if !defined (__GDK_H_INSIDE__) && !defined (GDK_COMPILATION)
#error "Only <gdk/gdk.h> can be included directly."
#endif
#include <gdk/gdkclipboard.h>
G_BEGIN_DECLS
#define GDK_TYPE_CLIPBOARD_FALLBACK (gdk_clipboard_fallback_get_type ())
#define GDK_CLIPBOARD_FALLBACK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_CLIPBOARD_FALLBACK, GdkClipboardFallback))
#define GDK_IS_CLIPBOARD_FALLBACK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_CLIPBOARD_FALLBACK))
typedef struct _GdkClipboardFallback GdkClipboardFallback;
GDK_AVAILABLE_IN_3_14
GType gdk_clipboard_fallback_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_3_14
GdkClipboard *gdk_clipboard_fallback_new (void);
G_END_DECLS
#endif /* __GDK_CLIPBOARD_FALLBACK_H__ */

99
gdk/gdkclipboardprivate.h Normal file
View File

@@ -0,0 +1,99 @@
/*
* Copyright (C) 2014 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_CLIPBOARD_PRIVATE_H__
#define __GDK_CLIPBOARD_PRIVATE_H__
#include <gdk/gdkclipboard.h>
G_BEGIN_DECLS
#define GDK_CLIPBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDK_TYPE_CLIPBOARD, GdkClipboardClass))
#define GDK_IS_CLIPBOARD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDK_TYPE_CLIPBOARD))
#define GDK_CLIPBOARD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GDK_TYPE_CLIPBOARD, GdkClipboardClass))
typedef struct _GdkClipboardClass GdkClipboardClass;
struct _GdkClipboard
{
GObject parent;
};
struct _GdkClipboardClass
{
GObjectClass parent_class;
/* signals */
void (* changed) (GdkClipboard *clipboard);
/* vfuncs */
void (* get_text_async) (GdkClipboard *clipboard,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gchar * (* get_text_finish) (GdkClipboard *clipboard,
GAsyncResult *res,
GError **error);
void (* set_text) (GdkClipboard *clipboard,
const gchar *text);
void (* get_image_async) (GdkClipboard *clipboard,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GdkPixbuf * (* get_image_finish) (GdkClipboard *clipboard,
GAsyncResult *res,
GError **error);
void (* set_image) (GdkClipboard *clipboard,
GdkPixbuf *pixbuf);
void (* get_data_async) (GdkClipboard *clipboard,
const gchar *content_type,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
GInputStream * (* get_data_finish) (GdkClipboard *clipboard,
GAsyncResult *res,
GError **error);
void (* set_data) (GdkClipboard *clipboard,
const gchar **content_types,
GdkClipboardProvider provider,
gpointer data,
GDestroyNotify destroy);
void (* clear) (GdkClipboard *clipboard);
};
typedef enum {
NO_CONTENT = 0,
OTHER_CONTENT = 1 << 0,
TEXT_CONTENT = 1 << 1,
IMAGE_CONTENT = 1 << 2
} GdkClipboardContent;
void
_gdk_clipboard_set_available_content (GdkClipboard *clipboard,
GdkClipboardContent content,
const gchar **content_types);
GdkClipboardContent
_gdk_clipboard_get_available_content (GdkClipboard *clipboard);
G_END_DECLS
#endif /* __GDK_CLIPBOARD_PRIVATE_H__ */

View File

@@ -2225,3 +2225,44 @@ gdk_error_trap_pop (void)
{
return gdk_error_trap_pop_internal (TRUE);
}
/**
* gdk_display_get_clipboard:
* @display: a #GdkDisplay
*
* Returns the #GdkClipboard for this display. This is a per-display
* singleton object and is backed by the system CLIPBOARD, if the
* platform supports it.
*
* Returns: (transfer none): the #GdkClipboard representing the system CLIPBOARD
*
* Since: 3.14
*/
GdkClipboard *
gdk_display_get_clipboard (GdkDisplay *display)
{
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
return GDK_DISPLAY_GET_CLASS (display)->get_clipboard (display);
}
/**
* gdk_display_get_primary:
* @display: a #GdkDisplay
*
* Returns the 'primary' #GdkClipboard for this display. This is a
* per-display singleton object and is backed by the system PRIMARY clipboard,
* if the platform supports it.
*
* Returns: (transfer none): the #GdkClipboard representing the system
* PRIMARY clipboard
*
* Since: 3.14
*/
GdkClipboard *
gdk_display_get_primary (GdkDisplay *display)
{
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
return GDK_DISPLAY_GET_CLASS (display)->get_primary (display);
}

View File

@@ -30,6 +30,7 @@
#include <gdk/gdktypes.h>
#include <gdk/gdkevents.h>
#include <gdk/gdkdevicemanager.h>
#include <gdk/gdkclipboard.h>
G_BEGIN_DECLS
@@ -171,6 +172,12 @@ GdkDeviceManager * gdk_display_get_device_manager (GdkDisplay *display);
GDK_AVAILABLE_IN_ALL
GdkAppLaunchContext *gdk_display_get_app_launch_context (GdkDisplay *display);
GDK_AVAILABLE_IN_3_14
GdkClipboard * gdk_display_get_clipboard (GdkDisplay *display);
GDK_AVAILABLE_IN_3_14
GdkClipboard * gdk_display_get_primary (GdkDisplay *display);
G_END_DECLS
#endif /* __GDK_DISPLAY_H__ */

View File

@@ -225,6 +225,9 @@ struct _GdkDisplayClass
gchar * (*utf8_to_string_target) (GdkDisplay *display,
const gchar *text);
GdkClipboard * (*get_clipboard) (GdkDisplay *display);
GdkClipboard * (*get_primary) (GdkDisplay *display);
/* Signals */
void (*opened) (GdkDisplay *display);
void (*closed) (GdkDisplay *display,

View File

@@ -23,6 +23,7 @@ libgdk_x11_la_SOURCES = \
gdkapplaunchcontext-x11.c \
gdkasync.c \
gdkasync.h \
gdkclipboard-x11.c \
gdkcursor-x11.c \
gdkdevice-core-x11.c \
gdkdevice-xi2.c \

1014
gdk/x11/gdkclipboard-x11.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,49 @@
/* GDK - The GIMP Drawing Kit
* Copyright (C) 2014 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GDK_CLIPBOARD_X11_H__
#define __GDK_CLIPBOARD_X11_H__
#include "gdk/gdkclipboard.h"
#include <X11/Xlib.h>
G_BEGIN_DECLS
#define GDK_TYPE_CLIPBOARD_X11 (gdk_clipboard_x11_get_type ())
#define GDK_CLIPBOARD_X11(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDK_TYPE_CLIPBOARD_X11, GdkClipboardX11))
#define GDK_IS_CLIPBOARD_X11(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDK_TYPE_CLIPBOARD_X11))
typedef struct _GdkClipboardX11 GdkClipboardX11;
GType gdk_clipboard_x11_get_type (void) G_GNUC_CONST;
GdkClipboardX11 *gdk_clipboard_x11_new (GdkDisplay *display,
const gchar *selection);
gboolean gdk_clipboard_x11_handle_selection_clear (GdkClipboardX11 *cb,
XSelectionClearEvent *event);
gboolean gdk_clipboard_x11_handle_selection_request (GdkClipboardX11 *cb,
XSelectionRequestEvent *event);
gboolean gdk_clipboard_x11_handle_selection_notify (GdkClipboardX11 *cb,
XSelectionEvent *event);
gboolean gdk_clipboard_x11_handle_selection_owner_change (GdkClipboardX11 *cb,
XEvent *event);
G_END_DECLS
#endif /* __GDK_CLIPBOARD_X11_H__ */

View File

@@ -886,7 +886,11 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
g_message ("selection clear:\twindow: %ld",
xevent->xproperty.window));
if (_gdk_x11_selection_filter_clear_event (&xevent->xselectionclear))
if (gdk_clipboard_x11_handle_selection_clear (display_x11->clipboard, &xevent->xselectionclear))
return_val = FALSE;
else if (gdk_clipboard_x11_handle_selection_clear (display_x11->primary, &xevent->xselectionclear))
return_val = FALSE;
else if (_gdk_x11_selection_filter_clear_event (&xevent->xselectionclear))
{
event->selection.type = GDK_SELECTION_CLEAR;
event->selection.window = window;
@@ -895,7 +899,6 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
}
else
return_val = FALSE;
break;
case SelectionRequest:
@@ -903,18 +906,24 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
g_message ("selection request:\twindow: %ld",
xevent->xproperty.window));
event->selection.type = GDK_SELECTION_REQUEST;
event->selection.window = window;
event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.selection);
event->selection.target = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.target);
event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.property);
if (xevent->xselectionrequest.requestor != None)
event->selection.requestor = gdk_x11_window_foreign_new_for_display (display,
xevent->xselectionrequest.requestor);
if (gdk_clipboard_x11_handle_selection_request (display_x11->clipboard, &xevent->xselectionrequest))
return_val = FALSE;
else if (gdk_clipboard_x11_handle_selection_request (display_x11->primary, &xevent->xselectionrequest))
return_val = FALSE;
else
event->selection.requestor = NULL;
event->selection.time = xevent->xselectionrequest.time;
{
event->selection.type = GDK_SELECTION_REQUEST;
event->selection.window = window;
event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.selection);
event->selection.target = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.target);
event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselectionrequest.property);
if (xevent->xselectionrequest.requestor != None)
event->selection.requestor = gdk_x11_window_foreign_new_for_display (display,
xevent->xselectionrequest.requestor);
else
event->selection.requestor = NULL;
event->selection.time = xevent->xselectionrequest.time;
}
break;
case SelectionNotify:
@@ -922,16 +931,22 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
g_message ("selection notify:\twindow: %ld",
xevent->xproperty.window));
event->selection.type = GDK_SELECTION_NOTIFY;
event->selection.window = window;
event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.selection);
event->selection.target = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.target);
if (xevent->xselection.property == None)
event->selection.property = GDK_NONE;
if (gdk_clipboard_x11_handle_selection_notify (display_x11->clipboard, &xevent->xselection))
return_val = FALSE;
else if (gdk_clipboard_x11_handle_selection_notify (display_x11->primary, &xevent->xselection))
return_val = FALSE;
else
event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.property);
event->selection.time = xevent->xselection.time;
{
event->selection.type = GDK_SELECTION_NOTIFY;
event->selection.window = window;
event->selection.selection = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.selection);
event->selection.target = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.target);
if (xevent->xselection.property == None)
event->selection.property = GDK_NONE;
else
event->selection.property = gdk_x11_xatom_to_atom_for_display (display, xevent->xselection.property);
event->selection.time = xevent->xselection.time;
}
break;
case ColormapNotify:
@@ -970,6 +985,8 @@ gdk_x11_display_translate_event (GdkEventTranslator *translator,
XFixesSelectionNotifyEvent *selection_notify = (XFixesSelectionNotifyEvent *)xevent;
_gdk_x11_screen_process_owner_change (screen, xevent);
gdk_clipboard_x11_handle_selection_owner_change (display_x11->clipboard, xevent);
gdk_clipboard_x11_handle_selection_owner_change (display_x11->primary, xevent);
event->owner_change.type = GDK_OWNER_CHANGE;
event->owner_change.window = window;
@@ -1870,6 +1887,12 @@ gdk_x11_display_finalize (GObject *object)
{
GdkX11Display *display_x11 = GDK_X11_DISPLAY (object);
/* Clipboards */
if (display_x11->clipboard)
g_object_unref (display_x11->clipboard);
if (display_x11->primary)
g_object_unref (display_x11->primary);
/* Keymap */
if (display_x11->keymap)
g_object_unref (display_x11->keymap);
@@ -2202,7 +2225,7 @@ gdk_x11_display_supports_selection_notification (GdkDisplay *display)
return display_x11->have_xfixes;
}
static gboolean
gboolean
gdk_x11_display_request_selection_notification (GdkDisplay *display,
GdkAtom selection)
@@ -2847,6 +2870,32 @@ gdk_x11_display_get_keymap (GdkDisplay *display)
return display_x11->keymap;
}
static GdkClipboard *
gdk_x11_display_get_clipboard (GdkDisplay *display)
{
GdkX11Display *display_x11;
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
display_x11 = GDK_X11_DISPLAY (display);
if (!display_x11->clipboard)
display_x11->clipboard = gdk_clipboard_x11_new (display, "CLIPBOARD");
return GDK_CLIPBOARD (display_x11->clipboard);
}
static GdkClipboard *
gdk_x11_display_get_primary (GdkDisplay *display)
{
GdkX11Display *display_x11;
g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
display_x11 = GDK_X11_DISPLAY (display);
if (!display_x11->primary)
display_x11->primary = gdk_clipboard_x11_new (display, "PRIMARY");
return GDK_CLIPBOARD (display_x11->primary);
}
static void
gdk_x11_display_class_init (GdkX11DisplayClass * class)
{
@@ -2901,6 +2950,8 @@ gdk_x11_display_class_init (GdkX11DisplayClass * class)
display_class->convert_selection = _gdk_x11_display_convert_selection;
display_class->text_property_to_utf8_list = _gdk_x11_display_text_property_to_utf8_list;
display_class->utf8_to_string_target = _gdk_x11_display_utf8_to_string_target;
display_class->get_clipboard = gdk_x11_display_get_clipboard;
display_class->get_primary = gdk_x11_display_get_primary;
_gdk_x11_windowing_init ();
}

View File

@@ -27,6 +27,7 @@
#include "gdkwindow.h"
#include "gdkinternals.h"
#include "gdkmain.h"
#include "gdkclipboard-x11.h"
#include <X11/X.h>
#include <X11/Xlib.h>
@@ -124,6 +125,9 @@ struct _GdkX11Display
GSList *error_traps;
gint wm_moveresize_button;
GdkClipboardX11 *clipboard;
GdkClipboardX11 *primary;
};
struct _GdkX11DisplayClass

View File

@@ -321,6 +321,10 @@ cairo_surface_t * _gdk_x11_window_create_bitmap_surface (GdkWindow *window,
extern const gint _gdk_x11_event_mask_table[];
extern const gint _gdk_x11_event_mask_table_size;
gboolean gdk_x11_display_request_selection_notification (GdkDisplay *display,
GdkAtom selection);
#define GDK_SCREEN_DISPLAY(screen) (GDK_X11_SCREEN (screen)->display)
#define GDK_SCREEN_XROOTWIN(screen) (GDK_X11_SCREEN (screen)->xroot_window)
#define GDK_WINDOW_SCREEN(win) (gdk_window_get_screen (win))

View File

@@ -45,6 +45,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \
testcairo \
testcalendar \
testclipboard \
testclipboard2 \
testcolorchooser \
testcombo \
testcombochange \
@@ -189,6 +190,7 @@ testbuttons_DEPENDENCIES = $(TEST_DEPS)
testcairo_DEPENDENCIES = $(TEST_DEPS)
testcalendar_DEPENDENCIES = $(TEST_DEPS)
testclipboard_DEPENDENCIES = $(TEST_DEPS)
testclipboard2_DEPENDENCIES = $(TEST_DEPS)
testcolorchooser_DEPENDENCIES = $(TEST_DEPS)
testcombo_DEPENDENCIES = $(TEST_DEPS)
testcombochange_DEPENDENCIES = $(TEST_DEPS)

243
tests/testclipboard2.c Normal file
View File

@@ -0,0 +1,243 @@
#include <gtk/gtk.h>
#include <string.h>
static GdkClipboard *clipboard;
static void
clear (GtkWidget *entry)
{
gdk_clipboard_clear (clipboard);
}
/* text */
static void
copy_text (GtkWidget *w)
{
gdk_clipboard_set_text (clipboard, gtk_entry_get_text (GTK_ENTRY (w)));
}
static void
text_received (GObject *source,
GAsyncResult *res,
gpointer data)
{
gchar *text;
GtkWidget *entry = data;
GError *error = NULL;
text = gdk_clipboard_get_text_finish (GDK_CLIPBOARD (source), res, &error);
if (!text)
{
g_print ("error receiving text: %s\n", error ? error->message : "no error set");
if (error)
g_error_free (error);
return;
}
gtk_entry_set_text (GTK_ENTRY (entry), text);
g_free (text);
}
static void
paste_text (GtkWidget *w)
{
gdk_clipboard_get_text_async (clipboard, NULL, text_received, w);
}
static void
has_text (GtkWidget *w)
{
gtk_widget_set_sensitive (w, gdk_clipboard_text_available (clipboard));
}
/* image */
static void
copy_image (GtkWidget *w)
{
gdk_clipboard_set_image (clipboard, gtk_image_get_pixbuf (GTK_IMAGE (w)));
}
static void
image_received (GObject *source,
GAsyncResult *res,
gpointer data)
{
GtkWidget *image = data;
GdkPixbuf *pixbuf;
GError *error = NULL;
pixbuf = gdk_clipboard_get_image_finish (GDK_CLIPBOARD (source), res, &error);
if (!pixbuf)
{
g_print ("error receiving image: %s\n", error ? error->message : "no error set");
if (error)
g_error_free (error);
return;
}
gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
g_object_unref (pixbuf);
}
static void
paste_image (GtkWidget *w)
{
gdk_clipboard_get_image_async (clipboard, NULL, image_received, w);
}
static void
has_image (GtkWidget *w)
{
gtk_widget_set_sensitive (w, gdk_clipboard_image_available (clipboard));
}
/* data */
static void
provider (GdkClipboard *clipboard,
const gchar *content_type,
GOutputStream *output,
gpointer data)
{
gchar *text = data;
g_output_stream_write_all (output, text, strlen (text), NULL, NULL, NULL);
g_output_stream_close (output, NULL, NULL);
}
static void
copy_data (GtkWidget *w)
{
const gchar *types[2] = { "foo/bar", NULL };
gdk_clipboard_set_data (clipboard, types, provider,
(gpointer)g_strdup (gtk_entry_get_text (GTK_ENTRY (w))), g_free);
}
static void
data_received (GObject *source,
GAsyncResult *res,
gpointer data)
{
GInputStream *is;
GError *error = NULL;
gchar buffer[128];
gssize size;
GtkWidget *w = data;
is = gdk_clipboard_get_data_finish (GDK_CLIPBOARD (source), res, &error);
if (!is)
return;
size = g_input_stream_read (is, buffer, 128, NULL, NULL);
if (size == -1)
{
g_object_unref (is);
return;
}
gtk_entry_set_text (GTK_ENTRY (w), buffer);
g_object_unref (is);
}
static void
paste_data (GtkWidget *w)
{
gdk_clipboard_get_data_async (clipboard, "foo/bar", NULL, data_received, w);
}
static void
has_data (GtkWidget *w)
{
gtk_widget_set_sensitive (w, gdk_clipboard_data_available (clipboard, "foo/bar"));
}
int
main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *grid;
GtkWidget *entry;
GtkWidget *button;
GtkWidget *image;
GtkWidget *label;
gtk_init (NULL, NULL);
clipboard = gdk_display_get_clipboard (gdk_display_get_default ());
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect (window, "delete-event", G_CALLBACK (gtk_main_quit), NULL);
grid = gtk_grid_new ();
gtk_grid_set_row_spacing (GTK_GRID (grid), 10);
gtk_grid_set_column_spacing (GTK_GRID (grid), 10);
g_object_set (grid, "margin", 10, NULL);
gtk_container_add (GTK_CONTAINER (window), grid);
label = gtk_label_new ("Text");
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
gtk_grid_attach (GTK_GRID (grid), label, 0, 0, 1, 1);
entry = gtk_entry_new ();
gtk_widget_set_valign (entry, GTK_ALIGN_BASELINE);
gtk_grid_attach (GTK_GRID (grid), entry, 1, 0, 1, 1);
button = gtk_button_new_with_label ("Copy");
gtk_widget_set_valign (button, GTK_ALIGN_BASELINE);
gtk_grid_attach (GTK_GRID (grid), button, 2, 0, 1, 1);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (copy_text), entry);
button = gtk_button_new_with_label ("Paste");
gtk_widget_set_valign (button, GTK_ALIGN_BASELINE);
gtk_grid_attach (GTK_GRID (grid), button, 3, 0, 1, 1);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (paste_text), entry);
g_signal_connect_swapped (clipboard, "changed", G_CALLBACK (has_text), button);
label = gtk_label_new ("Image");
gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
gtk_grid_attach (GTK_GRID (grid), label, 0, 1, 1, 1);
image = gtk_image_new ();
gtk_widget_set_valign (image, GTK_ALIGN_CENTER);
if (argc > 1)
gtk_image_set_from_file (GTK_IMAGE (image), argv[1]);
else
gtk_image_set_from_resource (GTK_IMAGE (image), "/org/gtk/libgtk/theme/Adwaita/assets/slider-vert-scale-has-marks-above@2.png");
gtk_grid_attach (GTK_GRID (grid), image, 1, 1, 1, 1);
button = gtk_button_new_with_label ("Copy");
gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
gtk_grid_attach (GTK_GRID (grid), button, 2, 1, 1, 1);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (copy_image), image);
button = gtk_button_new_with_label ("Paste");
gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
gtk_grid_attach (GTK_GRID (grid), button, 3, 1, 1, 1);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (paste_image), image);
g_signal_connect_swapped (clipboard, "changed", G_CALLBACK (has_image), button);
label = gtk_label_new ("Data");
gtk_widget_set_valign (label, GTK_ALIGN_BASELINE);
gtk_grid_attach (GTK_GRID (grid), label, 0, 2, 1, 1);
entry = gtk_entry_new ();
gtk_widget_set_valign (entry, GTK_ALIGN_BASELINE);
gtk_grid_attach (GTK_GRID (grid), entry, 1, 2, 1, 1);
button = gtk_button_new_with_label ("Copy");
gtk_widget_set_valign (button, GTK_ALIGN_BASELINE);
gtk_grid_attach (GTK_GRID (grid), button, 2, 2, 1, 1);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (copy_data), entry);
button = gtk_button_new_with_label ("Paste");
gtk_widget_set_valign (button, GTK_ALIGN_BASELINE);
gtk_grid_attach (GTK_GRID (grid), button, 3, 2, 1, 1);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (paste_data), entry);
g_signal_connect_swapped (clipboard, "changed", G_CALLBACK (has_data), button);
button = gtk_button_new_with_label ("Clear Clipboard");
gtk_grid_attach (GTK_GRID (grid), button, 2, 3, 2, 1);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (clear), entry);
g_signal_emit_by_name (clipboard, "changed", 0);
gtk_widget_show_all (window);
gtk_main ();
return 0;
}

View File

@@ -22,6 +22,7 @@ TEST_PROGS += \
encoding \
display \
keysyms \
clipboard \
$(NULL)
CLEANFILES = \

295
testsuite/gdk/clipboard.c Normal file
View File

@@ -0,0 +1,295 @@
#include <stdlib.h>
#include <gdk/gdk.h>
static void
count_changed (GdkClipboard *clipboard, gpointer data)
{
gint *count = data;
*count += 1;
}
typedef struct {
gboolean called;
gchar *text;
GdkPixbuf *pixbuf;
GBytes *bytes;
GError *error;
GMainLoop *loop;
} GetData;
static void
get_text (GObject *source, GAsyncResult *res, gpointer data)
{
GetData *gd = data;
gd->text = gdk_clipboard_get_text_finish (GDK_CLIPBOARD (source), res, &gd->error);
gd->called = TRUE;
}
static void
get_image (GObject *source, GAsyncResult *res, gpointer data)
{
GetData *gd = data;
gd->pixbuf = gdk_clipboard_get_image_finish (GDK_CLIPBOARD (source), res, &gd->error);
gd->called = TRUE;
}
static void
get_bytes (GObject *source, GAsyncResult *res, gpointer data)
{
GetData *gd = data;
gd->bytes = gdk_clipboard_get_bytes_finish (GDK_CLIPBOARD (source), res, &gd->error);
gd->called = TRUE;
}
static gboolean
wait_get (gpointer data)
{
GetData *gd = data;
if (gd->called)
{
g_main_loop_quit (gd->loop);
return G_SOURCE_REMOVE;
}
return G_SOURCE_CONTINUE;
}
static void
test_clipboard_text (void)
{
GdkClipboard *clipboard;
const gchar **content_types;
gint count;
GetData *gd;
count = 0;
clipboard = gdk_clipboard_fallback_new ();
g_signal_connect (clipboard, "changed", G_CALLBACK (count_changed), &count);
g_assert (!gdk_clipboard_text_available (clipboard));
g_assert (!gdk_clipboard_image_available (clipboard));
g_assert (!gdk_clipboard_data_available (clipboard, "application/octet-stream"));
content_types = gdk_clipboard_get_content_types (clipboard);
g_assert (content_types == NULL);
gdk_clipboard_set_text (clipboard, "ABC");
g_assert (gdk_clipboard_text_available (clipboard));
g_assert (!gdk_clipboard_image_available (clipboard));
g_assert (!gdk_clipboard_data_available (clipboard, "application/octet-stream"));
g_assert_cmpint (count, ==, 1);
gd = g_new0 (GetData, 1);
gdk_clipboard_get_text_async (clipboard, NULL, get_text, gd);
gd->loop = g_main_loop_new (NULL, FALSE);
g_idle_add (wait_get, gd);
g_main_loop_run (gd->loop);
g_assert_cmpstr (gd->text, ==, "ABC");
g_assert_no_error (gd->error);
g_free (gd->text);
g_main_loop_unref (gd->loop);
g_free (gd);
gdk_clipboard_clear (clipboard);
g_assert (!gdk_clipboard_text_available (clipboard));
g_assert (!gdk_clipboard_image_available (clipboard));
g_assert (!gdk_clipboard_data_available (clipboard, "application/octet-stream"));
g_assert_cmpint (count, ==, 2);
g_object_unref (clipboard);
}
static void
test_clipboard_image (void)
{
GdkClipboard *clipboard;
const gchar **content_types;
gint count;
GdkPixbuf *pixbuf;
GetData *gd;
count = 0;
clipboard = gdk_clipboard_fallback_new ();
g_signal_connect (clipboard, "changed", G_CALLBACK (count_changed), &count);
g_assert (!gdk_clipboard_text_available (clipboard));
g_assert (!gdk_clipboard_image_available (clipboard));
g_assert (!gdk_clipboard_data_available (clipboard, "application/octet-stream"));
content_types = gdk_clipboard_get_content_types (clipboard);
g_assert (content_types == NULL);
pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 16, 16);
gdk_clipboard_set_image (clipboard, pixbuf);
g_assert (!gdk_clipboard_text_available (clipboard));
g_assert (gdk_clipboard_image_available (clipboard));
g_assert (!gdk_clipboard_data_available (clipboard, "application/octet-stream"));
g_assert_cmpint (count, ==, 1);
g_assert_cmpint (G_OBJECT (pixbuf)->ref_count, >=, 2);
gd = g_new0 (GetData, 1);
gdk_clipboard_get_image_async (clipboard, NULL, get_image, gd);
gd->loop = g_main_loop_new (NULL, FALSE);
g_idle_add (wait_get, gd);
g_main_loop_run (gd->loop);
g_assert (gd->pixbuf == pixbuf);
g_assert_no_error (gd->error);
g_assert_cmpint (G_OBJECT (pixbuf)->ref_count, >=, 3);
g_object_unref (gd->pixbuf);
g_main_loop_unref (gd->loop);
g_free (gd);
gdk_clipboard_clear (clipboard);
g_assert_cmpint (G_OBJECT (pixbuf)->ref_count, ==, 1);
g_object_unref (pixbuf);
g_assert (!gdk_clipboard_text_available (clipboard));
g_assert (!gdk_clipboard_image_available (clipboard));
g_assert (!gdk_clipboard_data_available (clipboard, "application/octet-stream"));
g_assert_cmpint (count, ==, 2);
g_object_unref (clipboard);
}
static void
test_clipboard_bytes (void)
{
GdkClipboard *clipboard;
const gchar **content_types;
gint count;
GBytes *bytes;
GetData *gd;
count = 0;
clipboard = gdk_clipboard_fallback_new ();
g_signal_connect (clipboard, "changed", G_CALLBACK (count_changed), &count);
g_assert (!gdk_clipboard_text_available (clipboard));
g_assert (!gdk_clipboard_image_available (clipboard));
g_assert (!gdk_clipboard_data_available (clipboard, "application/octet-stream"));
content_types = gdk_clipboard_get_content_types (clipboard);
g_assert (content_types == NULL);
bytes = g_bytes_new_static ("012346789", 10);
gdk_clipboard_set_bytes (clipboard, bytes, "application/octet-stream");
g_assert (!gdk_clipboard_text_available (clipboard));
g_assert (!gdk_clipboard_image_available (clipboard));
g_assert (gdk_clipboard_data_available (clipboard, "application/octet-stream"));
g_assert_cmpint (count, ==, 1);
gd = g_new0 (GetData, 1);
gdk_clipboard_get_bytes_async (clipboard, "application/octet-stream", NULL, get_bytes, gd);
gd->loop = g_main_loop_new (NULL, FALSE);
g_idle_add (wait_get, gd);
g_main_loop_run (gd->loop);
g_assert (g_bytes_equal (gd->bytes, bytes));
g_assert_no_error (gd->error);
g_bytes_unref (gd->bytes);
g_main_loop_unref (gd->loop);
g_free (gd);
gdk_clipboard_clear (clipboard);
g_bytes_unref (bytes);
g_assert (!gdk_clipboard_text_available (clipboard));
g_assert (!gdk_clipboard_image_available (clipboard));
g_assert (!gdk_clipboard_data_available (clipboard, "application/octet-stream"));
g_assert_cmpint (count, ==, 2);
g_object_unref (clipboard);
}
static gboolean freed;
static void
free_data (gpointer data)
{
freed = TRUE;
g_free (data);
}
static void
provider (GdkClipboard *clipboard,
const gchar *content_type,
GOutputStream *output,
gpointer user_data)
{
}
static void
test_clipboard_data (void)
{
GdkClipboard *clipboard;
gint count;
const gchar *content_types[3] = {
"application/octet-stream",
"application/pdf",
NULL
};
count = 0;
clipboard = gdk_clipboard_fallback_new ();
g_signal_connect (clipboard, "changed", G_CALLBACK (count_changed), &count);
g_assert (!gdk_clipboard_text_available (clipboard));
g_assert (!gdk_clipboard_image_available (clipboard));
g_assert (!gdk_clipboard_data_available (clipboard, "application/octet-stream"));
gdk_clipboard_set_data (clipboard, content_types,
provider, g_strdup ("0123456789"), free_data);
g_assert (!gdk_clipboard_text_available (clipboard));
g_assert (!gdk_clipboard_image_available (clipboard));
g_assert (gdk_clipboard_data_available (clipboard, "application/octet-stream"));
g_assert (gdk_clipboard_data_available (clipboard, "application/pdf"));
g_assert (!gdk_clipboard_data_available (clipboard, "yellow submarine"));
g_assert_cmpint (count, ==, 1);
g_object_unref (clipboard);
g_assert (freed);
}
int
main (int argc, char *argv[])
{
g_test_init (&argc, &argv, NULL);
gdk_init (NULL, NULL);
g_test_add_func ("/clipboard/text", test_clipboard_text);
g_test_add_func ("/clipboard/image", test_clipboard_image);
g_test_add_func ("/clipboard/bytes", test_clipboard_bytes);
g_test_add_func ("/clipboard/data", test_clipboard_data);
return g_test_run ();
}