/*
* e-selection.c
*
* This program 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) version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with the program; if not, see <http://www.gnu.org/licenses/>
*
*
* Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
*
*/
/**
* SECTION: e-selection
* @short_description: selection and clipboard utilities
* @include: e-util/e-selection.h
**/
#include "e-selection.h"
#include <string.h>
typedef struct _RequestTextInfo RequestTextInfo;
typedef struct _WaitForDataResults WaitForDataResults;
struct _RequestTextInfo {
GtkClipboardTextReceivedFunc callback;
gpointer user_data;
};
struct _WaitForDataResults {
GMainLoop *loop;
gpointer data;
};
enum {
ATOM_CALENDAR,
ATOM_X_VCALENDAR,
NUM_CALENDAR_ATOMS
};
enum {
ATOM_DIRECTORY,
ATOM_X_VCARD,
NUM_DIRECTORY_ATOMS
};
enum {
ATOM_HTML,
NUM_HTML_ATOMS
};
static GdkAtom calendar_atoms[NUM_CALENDAR_ATOMS];
static GdkAtom directory_atoms[NUM_DIRECTORY_ATOMS];
static GdkAtom html_atoms[NUM_HTML_ATOMS];
static void
init_atoms (void)
{
static gboolean initialized = FALSE;
if (initialized)
return;
/* Calendar Atoms */
calendar_atoms[ATOM_CALENDAR] =
gdk_atom_intern_static_string ("text/calendar");
calendar_atoms[ATOM_X_VCALENDAR] =
gdk_atom_intern_static_string ("text/x-vcalendar");
/* Directory Atoms */
directory_atoms[ATOM_DIRECTORY] =
gdk_atom_intern_static_string ("text/directory");
directory_atoms[ATOM_X_VCARD] =
gdk_atom_intern_static_string ("text/x-vcard");
/* HTML Atoms */
html_atoms[ATOM_HTML] =
gdk_atom_intern_static_string ("text/html");
initialized = TRUE;
}
static void
clipboard_wait_for_text_cb (GtkClipboard *clipboard,
const gchar *source,
WaitForDataResults *results)
{
results->data = g_strdup (source);
g_main_loop_quit (results->loop);
}
void
e_target_list_add_calendar_targets (GtkTargetList *list,
guint info)
{
gint ii;
g_return_if_fail (list != NULL);
init_atoms ();
for (ii = 0; ii < NUM_CALENDAR_ATOMS; ii++)
gtk_target_list_add (list, calendar_atoms[ii], 0, info);
}
void
e_target_list_add_directory_targets (GtkTargetList *list,
guint info)
{
gint ii;
g_return_if_fail (list != NULL);
init_atoms ();
for (ii = 0; ii < NUM_DIRECTORY_ATOMS; ii++)
gtk_target_list_add (list, directory_atoms[ii], 0, info);
}
void
e_target_list_add_html_targets (GtkTargetList *list,
guint info)
{
gint ii;
g_return_if_fail (list != NULL);
init_atoms ();
for (ii = 0; ii < NUM_HTML_ATOMS; ii++)
gtk_target_list_add (list, html_atoms[ii], 0, info);
}
gboolean
e_selection_data_set_calendar (GtkSelectionData *selection_data,
const gchar *source,
gint length)
{
GdkAtom atom;
gint ii;
g_return_val_if_fail (selection_data != NULL, FALSE);
g_return_val_if_fail (source != NULL, FALSE);
if (length < 0)
length = strlen (source);
init_atoms ();
atom = gtk_selection_data_get_target (selection_data);
/* All calendar atoms are treated the same. */
for (ii = 0; ii < NUM_CALENDAR_ATOMS; ii++) {
if (atom == calendar_atoms[ii]) {
gtk_selection_data_set (
selection_data, atom, 8,
(guchar *) source, length);
return TRUE;
}
}
return FALSE;
}
gboolean
e_selection_data_set_directory (GtkSelectionData *selection_data,
const gchar *source,
gint length)
{
GdkAtom atom;
gint ii;
g_return_val_if_fail (selection_data != NULL, FALSE);
g_return_val_if_fail (source != NULL, FALSE);
if (length < 0)
length = strlen (source);
init_atoms ();
atom = gtk_selection_data_get_target (selection_data);
/* All directory atoms are treated the same. */
for (ii = 0; ii < NUM_DIRECTORY_ATOMS; ii++) {
if (atom == directory_atoms[ii]) {
gtk_selection_data_set (
selection_data, atom, 8,
(guchar *) source, length);
return TRUE;
}
}
return FALSE;
}
gboolean
e_selection_data_set_html (GtkSelectionData *selection_data,
const gchar *source,
gint length)
{
GdkAtom atom;
gint ii;
g_return_val_if_fail (selection_data != NULL, FALSE);
g_return_val_if_fail (source != NULL, FALSE);
if (length < 0)
length = strlen (source);
init_atoms ();
atom = gtk_selection_data_get_target (selection_data);
/* All HTML atoms are treated the same. */
for (ii = 0; ii < NUM_HTML_ATOMS; ii++) {
if (atom == html_atoms[ii]) {
gtk_selection_data_set (
selection_data, atom, 8,
(guchar *) source, length);
return TRUE;
}
}
return FALSE;
}
gchar *
e_selection_data_get_calendar (GtkSelectionData *selection_data)
{
GdkAtom data_type;
const guchar *data = NULL;
gint ii;
/* XXX May need to do encoding and line ending conversions
* here. Not worrying about it for now. */
g_return_val_if_fail (selection_data != NULL, NULL);
data = gtk_selection_data_get_data (selection_data);
data_type = gtk_selection_data_get_data_type (selection_data);
/* All calendar atoms are treated the same. */
for (ii = 0; ii < NUM_CALENDAR_ATOMS; ii++)
if (data_type == calendar_atoms[ii])
return g_strdup ((gchar *) data);
return NULL;
}
gchar *
e_selection_data_get_directory (GtkSelectionData *selection_data)
{
GdkAtom data_type;
const guchar *data = NULL;
gint ii;
/* XXX May need to do encoding and line ending conversions
* here. Not worrying about it for now. */
g_return_val_if_fail (selection_data != NULL, NULL);
data = gtk_selection_data_get_data (selection_data);
data_type = gtk_selection_data_get_data_type (selection_data);
/* All directory atoms are treated the same. */
for (ii = 0; ii < NUM_DIRECTORY_ATOMS; ii++)
if (data_type == directory_atoms[ii])
return g_strdup ((gchar *) data);
return NULL;
}
gchar *
e_selection_data_get_html (GtkSelectionData *selection_data)
{
GdkAtom data_type;
const guchar *data = NULL;
gchar *utf8_text;
gint length;
gint ii;
GError *error = NULL;
/* XXX May need to do encoding conversions here.
* Not worrying about it for now. */
g_return_val_if_fail (selection_data != NULL, NULL);
data = gtk_selection_data_get_data (selection_data);
length = gtk_selection_data_get_length (selection_data);
data_type = gtk_selection_data_get_data_type (selection_data);
/* First validate the data. Assume it's UTF-8 or UTF-16. */
if (g_utf8_validate ((const gchar *) data, length - 1, NULL))
utf8_text = g_strdup ((const gchar *) data);
else
utf8_text = g_convert (
(const gchar *) data, length,
"UTF-8", "UTF-16", NULL, NULL, &error);
if (error != NULL) {
g_warning ("%s", error->message);
g_error_free (error);
}
/* All HTML atoms are treated the same. */
for (ii = 0; ii < NUM_HTML_ATOMS; ii++)
if (data_type == html_atoms[ii])
return utf8_text;
g_free (utf8_text);
return NULL;
}
gboolean
e_selection_data_targets_include_calendar (GtkSelectionData *selection_data)
{
GdkAtom *targets;
gint n_targets;
gboolean result = FALSE;
g_return_val_if_fail (selection_data != NULL, FALSE);
if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets)) {
result = e_targets_include_calendar (targets, n_targets);
g_free (targets);
}
return result;
}
gboolean
e_selection_data_targets_include_directory (GtkSelectionData *selection_data)
{
GdkAtom *targets;
gint n_targets;
gboolean result = FALSE;
g_return_val_if_fail (selection_data != NULL, FALSE);
if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets)) {
result = e_targets_include_directory (targets, n_targets);
g_free (targets);
}
return result;
}
gboolean
e_selection_data_targets_include_html (GtkSelectionData *selection_data)
{
GdkAtom *targets;
gint n_targets;
gboolean result = FALSE;
g_return_val_if_fail (selection_data != NULL, FALSE);
if (gtk_selection_data_get_targets (selection_data, &targets, &n_targets)) {
result = e_targets_include_html (targets, n_targets);
g_free (targets);
}
return result;
}
gboolean
e_targets_include_calendar (GdkAtom *targets,
gint n_targets)
{
gint ii, jj;
g_return_val_if_fail (targets != NULL || n_targets == 0, FALSE);
init_atoms ();
for (ii = 0; ii < n_targets; ii++)
for (jj = 0; jj < NUM_CALENDAR_ATOMS; jj++)
if (targets[ii] == calendar_atoms[jj])
return TRUE;
return FALSE;
}
gboolean
e_targets_include_directory (GdkAtom *targets,
gint n_targets)
{
gint ii, jj;
g_return_val_if_fail (targets != NULL || n_targets == 0, FALSE);
init_atoms ();
for (ii = 0; ii < n_targets; ii++)
for (jj = 0; jj < NUM_DIRECTORY_ATOMS; jj++)
if (targets[ii] == directory_atoms[jj])
return TRUE;
return FALSE;
}
gboolean
e_targets_include_html (GdkAtom *targets,
gint n_targets)
{
gint ii, jj;
g_return_val_if_fail (targets != NULL || n_targets == 0, FALSE);
init_atoms ();
for (ii = 0; ii < n_targets; ii++)
for (jj = 0; jj < NUM_HTML_ATOMS; jj++)
if (targets[ii] == html_atoms[jj])
return TRUE;
return FALSE;
}
static void
clipboard_get_calendar (GtkClipboard *clipboard,
GtkSelectionData *selection_data,
guint info,
gchar *source)
{
e_selection_data_set_calendar (selection_data, source, -1);
}
static void
clipboard_clear_calendar (GtkClipboard *clipboard,
gchar *source)
{
g_free (source);
}
void
e_clipboard_set_calendar (GtkClipboard *clipboard,
const gchar *source,
gint length)
{
GtkTargetList *list;
GtkTargetEntry *targets;
gint n_targets;
g_return_if_fail (clipboard != NULL);
g_return_if_fail (source != NULL);
list = gtk_target_list_new (NULL, 0);
e_target_list_add_calendar_targets (list, 0);
targets = gtk_target_table_new_from_list (list, &n_targets);
if (length < 0)
length = strlen (source);
gtk_clipboard_set_with_data (
clipboard, targets, n_targets,
(GtkClipboardGetFunc) clipboard_get_calendar,
(GtkClipboardClearFunc) clipboard_clear_calendar,
g_strndup (source, length));
gtk_clipboard_set_can_store (clipboard, NULL, 0);
gtk_target_table_free (targets, n_targets);
gtk_target_list_unref (list);
}
static void
clipboard_get_directory (GtkClipboard *clipboard,
GtkSelectionData *selection_data,
guint info,
gchar *source)
{
e_selection_data_set_directory (selection_data, source, -1);
}
static void
clipboard_clear_directory (GtkClipboard *clipboard,
gchar *source)
{
g_free (source);
}
void
e_clipboard_set_directory (GtkClipboard *clipboard,
const gchar *source,
gint length)
{
GtkTargetList *list;
GtkTargetEntry *targets;
gint n_targets;
g_return_if_fail (clipboard != NULL);
g_return_if_fail (source != NULL);
list = gtk_target_list_new (NULL, 0);
e_target_list_add_directory_targets (list, 0);
targets = gtk_target_table_new_from_list (list, &n_targets);
if (length < 0)
length = strlen (source);
gtk_clipboard_set_with_data (
clipboard, targets, n_targets,
(GtkClipboardGetFunc) clipboard_get_directory,
(GtkClipboardClearFunc) clipboard_clear_directory,
g_strndup (source, length));
gtk_clipboard_set_can_store (clipboard, NULL, 0);
gtk_target_table_free (targets, n_targets);
gtk_target_list_unref (list);
}
static void
clipboard_get_html (GtkClipboard *clipboard,
GtkSelectionData *selection_data,
guint info,
gchar *source)
{
e_selection_data_set_html (selection_data, source, -1);
}
static void
clipboard_clear_html (GtkClipboard *clipboard,
gchar *source)
{
g_free (source);
}
void
e_clipboard_set_html (GtkClipboard *clipboard,
const gchar *source,
gint length)
{
GtkTargetList *list;
GtkTargetEntry *targets;
gint n_targets;
g_return_if_fail (clipboard != NULL);
g_return_if_fail (source != NULL);
list = gtk_target_list_new (NULL, 0);
e_target_list_add_html_targets (list, 0);
targets = gtk_target_table_new_from_list (list, &n_targets);
if (length < 0)
length = strlen (source);
gtk_clipboard_set_with_data (
clipboard, targets, n_targets,
(GtkClipboardGetFunc) clipboard_get_html,
(GtkClipboardClearFunc) clipboard_clear_html,
g_strndup (source, length));
gtk_clipboard_set_can_store (clipboard, NULL, 0);
gtk_target_table_free (targets, n_targets);
gtk_target_list_unref (list);
}
static void
clipboard_request_calendar_cb (GtkClipboard *clipboard,
GtkSelectionData *selection_data,
RequestTextInfo *info)
{
gchar *source;
source = e_selection_data_get_calendar (selection_data);
info->callback (clipboard, source, info->user_data);
g_free (source);
g_slice_free (RequestTextInfo, info);
}
void
e_clipboard_request_calendar (GtkClipboard *clipboard,
GtkClipboardTextReceivedFunc callback,
gpointer user_data)
{
RequestTextInfo *info;
g_return_if_fail (clipboard != NULL);
g_return_if_fail (callback != NULL);
init_atoms ();
info = g_slice_new (RequestTextInfo);
info->callback = callback;
info->user_data = user_data;
gtk_clipboard_request_contents (
clipboard, calendar_atoms[ATOM_CALENDAR],
(GtkClipboardReceivedFunc)
clipboard_request_calendar_cb, info);
}
static void
clipboard_request_directory_cb (GtkClipboard *clipboard,
GtkSelectionData *selection_data,
RequestTextInfo *info)
{
gchar *source;
source = e_selection_data_get_directory (selection_data);
info->callback (clipboard, source, info->user_data);
g_free (source);
g_slice_free (RequestTextInfo, info);
}
void
e_clipboard_request_directory (GtkClipboard *clipboard,
GtkClipboardTextReceivedFunc callback,
gpointer user_data)
{
RequestTextInfo *info;
g_return_if_fail (clipboard != NULL);
g_return_if_fail (callback != NULL);
init_atoms ();
info = g_slice_new (RequestTextInfo);
info->callback = callback;
info->user_data = user_data;
gtk_clipboard_request_contents (
clipboard, directory_atoms[ATOM_DIRECTORY],
(GtkClipboardReceivedFunc)
clipboard_request_directory_cb, info);
}
static void
clipboard_request_html_cb (GtkClipboard *clipboard,
GtkSelectionData *selection_data,
RequestTextInfo *info)
{
gchar *source;
source = e_selection_data_get_html (selection_data);
info->callback (clipboard, source, info->user_data);
g_free (source);
g_slice_free (RequestTextInfo, info);
}
void
e_clipboard_request_html (GtkClipboard *clipboard,
GtkClipboardTextReceivedFunc callback,
gpointer user_data)
{
RequestTextInfo *info;
g_return_if_fail (clipboard != NULL);
g_return_if_fail (callback != NULL);
init_atoms ();
info = g_slice_new (RequestTextInfo);
info->callback = callback;
info->user_data = user_data;
gtk_clipboard_request_contents (
clipboard, html_atoms[ATOM_HTML],
(GtkClipboardReceivedFunc)
clipboard_request_html_cb, info);
}
gchar *
e_clipboard_wait_for_calendar (GtkClipboard *clipboard)
{
WaitForDataResults results;
g_return_val_if_fail (clipboard != NULL, NULL);
results.data = NULL;
results.loop = g_main_loop_new (NULL, TRUE);
e_clipboard_request_calendar (
clipboard, (GtkClipboardTextReceivedFunc)
clipboard_wait_for_text_cb, &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);
return results.data;
}
gchar *
e_clipboard_wait_for_directory (GtkClipboard *clipboard)
{
WaitForDataResults results;
g_return_val_if_fail (clipboard != NULL, NULL);
results.data = NULL;
results.loop = g_main_loop_new (NULL, TRUE);
e_clipboard_request_directory (
clipboard, (GtkClipboardTextReceivedFunc)
clipboard_wait_for_text_cb, &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);
return results.data;
}
gchar *
e_clipboard_wait_for_html (GtkClipboard *clipboard)
{
WaitForDataResults results;
g_return_val_if_fail (clipboard != NULL, NULL);
results.data = NULL;
results.loop = g_main_loop_new (NULL, TRUE);
e_clipboard_request_html (
clipboard, (GtkClipboardTextReceivedFunc)
clipboard_wait_for_text_cb, &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);
return results.data;
}
gboolean
e_clipboard_wait_is_calendar_available (GtkClipboard *clipboard)
{
GdkAtom *targets;
gint n_targets;
gboolean result = FALSE;
if (gtk_clipboard_wait_for_targets (clipboard, &targets, &n_targets)) {
result = e_targets_include_calendar (targets, n_targets);
g_free (targets);
}
return result;
}
gboolean
e_clipboard_wait_is_directory_available (GtkClipboard *clipboard)
{
GdkAtom *targets;
gint n_targets;
gboolean result = FALSE;
if (gtk_clipboard_wait_for_targets (clipboard, &targets, &n_targets)) {
result = e_targets_include_directory (targets, n_targets);
g_free (targets);
}
return result;
}
gboolean
e_clipboard_wait_is_html_available (GtkClipboard *clipboard)
{
GdkAtom *targets;
gint n_targets;
gboolean result = FALSE;
if (gtk_clipboard_wait_for_targets (clipboard, &targets, &n_targets)) {
result = e_targets_include_html (targets, n_targets);
g_free (targets);
}
return result;
}
void
e_drag_dest_add_calendar_targets (GtkWidget *widget)
{
GtkTargetList *target_list;
g_return_if_fail (GTK_IS_WIDGET (widget));
target_list = gtk_drag_source_get_target_list (widget);
if (target_list != NULL)
gtk_target_list_ref (target_list);
else
target_list = gtk_target_list_new (NULL, 0);
e_target_list_add_calendar_targets (target_list, 0);
gtk_drag_dest_set_target_list (widget, target_list);
gtk_target_list_unref (target_list);
}
void
e_drag_dest_add_directory_targets (GtkWidget *widget)
{
GtkTargetList *target_list;
g_return_if_fail (GTK_IS_WIDGET (widget));
target_list = gtk_drag_source_get_target_list (widget);
if (target_list != NULL)
gtk_target_list_ref (target_list);
else
target_list = gtk_target_list_new (NULL, 0);
e_target_list_add_directory_targets (target_list, 0);
gtk_drag_dest_set_target_list (widget, target_list);
gtk_target_list_unref (target_list);
}
void
e_drag_dest_add_html_targets (GtkWidget *widget)
{
GtkTargetList *target_list;
g_return_if_fail (GTK_IS_WIDGET (widget));
target_list = gtk_drag_source_get_target_list (widget);
if (target_list != NULL)
gtk_target_list_ref (target_list);
else
target_list = gtk_target_list_new (NULL, 0);
e_target_list_add_html_targets (target_list, 0);
gtk_drag_dest_set_target_list (widget, target_list);
gtk_target_list_unref (target_list);
}
void
e_drag_source_add_calendar_targets (GtkWidget *widget)
{
GtkTargetList *target_list;
g_return_if_fail (GTK_IS_WIDGET (widget));
target_list = gtk_drag_source_get_target_list (widget);
if (target_list != NULL)
gtk_target_list_ref (target_list);
else
target_list = gtk_target_list_new (NULL, 0);
e_target_list_add_calendar_targets (target_list, 0);
gtk_drag_source_set_target_list (widget, target_list);
gtk_target_list_unref (target_list);
}
void
e_drag_source_add_directory_targets (GtkWidget *widget)
{
GtkTargetList *target_list;
g_return_if_fail (GTK_IS_WIDGET (widget));
target_list = gtk_drag_source_get_target_list (widget);
if (target_list != NULL)
gtk_target_list_ref (target_list);
else
target_list = gtk_target_list_new (NULL, 0);
e_target_list_add_directory_targets (target_list, 0);
gtk_drag_source_set_target_list (widget, target_list);
gtk_target_list_unref (target_list);
}
void
e_drag_source_add_html_targets (GtkWidget *widget)
{
GtkTargetList *target_list;
g_return_if_fail (GTK_IS_WIDGET (widget));
target_list = gtk_drag_source_get_target_list (widget);
if (target_list != NULL)
gtk_target_list_ref (target_list);
else
target_list = gtk_target_list_new (NULL, 0);
e_target_list_add_html_targets (target_list, 0);
gtk_drag_source_set_target_list (widget, target_list);
gtk_target_list_unref (target_list);
}