aboutsummaryrefslogtreecommitdiffstats
path: root/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'widgets')
-rw-r--r--widgets/misc/e-focus-tracker.c14
-rw-r--r--widgets/misc/e-selectable.c58
-rw-r--r--widgets/misc/e-selectable.h4
-rw-r--r--widgets/misc/e-web-view.c243
-rw-r--r--widgets/misc/e-web-view.h10
5 files changed, 315 insertions, 14 deletions
diff --git a/widgets/misc/e-focus-tracker.c b/widgets/misc/e-focus-tracker.c
index d1cb32adde..8eb1b25d56 100644
--- a/widgets/misc/e-focus-tracker.c
+++ b/widgets/misc/e-focus-tracker.c
@@ -360,6 +360,10 @@ focus_tracker_dispose (GObject *object)
gtk_clipboard_get (GDK_SELECTION_PRIMARY),
G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, object);
+ g_signal_handlers_disconnect_matched (
+ gtk_clipboard_get (GDK_SELECTION_CLIPBOARD),
+ G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, object);
+
if (priv->window != NULL) {
g_signal_handlers_disconnect_matched (
priv->window, G_SIGNAL_MATCH_DATA,
@@ -427,6 +431,16 @@ focus_tracker_constructed (GObject *object)
g_signal_connect_swapped (
clipboard, "owner-change",
G_CALLBACK (e_focus_tracker_update_actions), object);
+
+ /* Listen for "owner-change" signals from the default clipboard
+ * so we can update the paste action when the user cuts or copies
+ * something. This is how GEdit does it. */
+
+ clipboard = gtk_clipboard_get (GDK_SELECTION_CLIPBOARD);
+
+ g_signal_connect_swapped (
+ clipboard, "owner-change",
+ G_CALLBACK (e_focus_tracker_update_actions), object);
}
static void
diff --git a/widgets/misc/e-selectable.c b/widgets/misc/e-selectable.c
index bb5948cc13..da998d320d 100644
--- a/widgets/misc/e-selectable.c
+++ b/widgets/misc/e-selectable.c
@@ -21,6 +21,28 @@
#include "e-selectable.h"
+static void
+selectable_class_init (ESelectableInterface *interface)
+{
+ g_object_interface_install_property (
+ interface,
+ g_param_spec_boxed (
+ "copy-target-list",
+ "Copy Target List",
+ NULL,
+ GTK_TYPE_TARGET_LIST,
+ G_PARAM_READABLE));
+
+ g_object_interface_install_property (
+ interface,
+ g_param_spec_boxed (
+ "paste-target-list",
+ "Paste Target List",
+ NULL,
+ GTK_TYPE_TARGET_LIST,
+ G_PARAM_READABLE));
+}
+
GType
e_selectable_get_type (void)
{
@@ -31,7 +53,7 @@ e_selectable_get_type (void)
sizeof (ESelectableInterface),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
- (GClassInitFunc) NULL,
+ (GClassInitFunc) selectable_class_init,
(GClassFinalizeFunc) NULL,
NULL, /* class_data */
0, /* instance_size */
@@ -43,7 +65,7 @@ e_selectable_get_type (void)
type = g_type_register_static (
G_TYPE_INTERFACE, "ESelectable", &type_info, 0);
- g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
+ g_type_interface_add_prerequisite (type, GTK_TYPE_WIDGET);
}
return type;
@@ -131,3 +153,35 @@ e_selectable_select_all (ESelectable *selectable)
if (interface->select_all != NULL)
interface->select_all (selectable);
}
+
+GtkTargetList *
+e_selectable_get_copy_target_list (ESelectable *selectable)
+{
+ GtkTargetList *target_list;
+
+ g_return_val_if_fail (E_IS_SELECTABLE (selectable), NULL);
+
+ g_object_get (selectable, "copy-target-list", &target_list, NULL);
+
+ /* We want to return a borrowed reference to the target
+ * list, so undo the reference that g_object_get() added. */
+ gtk_target_list_unref (target_list);
+
+ return target_list;
+}
+
+GtkTargetList *
+e_selectable_get_paste_target_list (ESelectable *selectable)
+{
+ GtkTargetList *target_list;
+
+ g_return_val_if_fail (E_IS_SELECTABLE (selectable), NULL);
+
+ g_object_get (selectable, "paste-target-list", &target_list, NULL);
+
+ /* We want to return a borrowed reference to the target
+ * list, so undo the reference that g_object_get() added. */
+ gtk_target_list_unref (target_list);
+
+ return target_list;
+}
diff --git a/widgets/misc/e-selectable.h b/widgets/misc/e-selectable.h
index fca400ce65..c9a0b6dded 100644
--- a/widgets/misc/e-selectable.h
+++ b/widgets/misc/e-selectable.h
@@ -70,6 +70,10 @@ void e_selectable_copy_clipboard (ESelectable *selectable);
void e_selectable_paste_clipboard (ESelectable *selectable);
void e_selectable_delete_selection (ESelectable *selectable);
void e_selectable_select_all (ESelectable *selectable);
+GtkTargetList * e_selectable_get_copy_target_list
+ (ESelectable *selectable);
+GtkTargetList * e_selectable_get_paste_target_list
+ (ESelectable *selectable);
G_END_DECLS
diff --git a/widgets/misc/e-web-view.c b/widgets/misc/e-web-view.c
index 31516bf04d..a5f98a4edc 100644
--- a/widgets/misc/e-web-view.c
+++ b/widgets/misc/e-web-view.c
@@ -50,6 +50,9 @@ struct _EWebViewPrivate {
GtkAction *print_proxy;
GtkAction *save_as_proxy;
+ GtkTargetList *copy_target_list;
+ GtkTargetList *paste_target_list;
+
/* Lockdown Options */
guint disable_printing : 1;
guint disable_save_to_disk : 1;
@@ -68,15 +71,21 @@ enum {
PROP_0,
PROP_ANIMATE,
PROP_CARET_MODE,
+ PROP_COPY_TARGET_LIST,
PROP_DISABLE_PRINTING,
PROP_DISABLE_SAVE_TO_DISK,
+ PROP_EDITABLE,
PROP_OPEN_PROXY,
+ PROP_PASTE_TARGET_LIST,
PROP_PRINT_PROXY,
PROP_SAVE_AS_PROXY,
PROP_SELECTED_URI
};
enum {
+ COPY_CLIPBOARD,
+ CUT_CLIPBOARD,
+ PASTE_CLIPBOARD,
POPUP_EVENT,
STATUS_MESSAGE,
STOP_LOADING,
@@ -488,6 +497,12 @@ web_view_set_property (GObject *object,
g_value_get_boolean (value));
return;
+ case PROP_EDITABLE:
+ e_web_view_set_editable (
+ E_WEB_VIEW (object),
+ g_value_get_boolean (value));
+ return;
+
case PROP_OPEN_PROXY:
e_web_view_set_open_proxy (
E_WEB_VIEW (object),
@@ -535,6 +550,12 @@ web_view_get_property (GObject *object,
E_WEB_VIEW (object)));
return;
+ case PROP_COPY_TARGET_LIST:
+ g_value_set_boxed (
+ value, e_web_view_get_copy_target_list (
+ E_WEB_VIEW (object)));
+ return;
+
case PROP_DISABLE_PRINTING:
g_value_set_boolean (
value, e_web_view_get_disable_printing (
@@ -547,12 +568,24 @@ web_view_get_property (GObject *object,
E_WEB_VIEW (object)));
return;
+ case PROP_EDITABLE:
+ g_value_set_boolean (
+ value, e_web_view_get_editable (
+ E_WEB_VIEW (object)));
+ return;
+
case PROP_OPEN_PROXY:
g_value_set_object (
value, e_web_view_get_open_proxy (
E_WEB_VIEW (object)));
return;
+ case PROP_PASTE_TARGET_LIST:
+ g_value_set_boxed (
+ value, e_web_view_get_paste_target_list (
+ E_WEB_VIEW (object)));
+ return;
+
case PROP_PRINT_PROXY:
g_value_set_object (
value, e_web_view_get_print_proxy (
@@ -602,6 +635,16 @@ web_view_dispose (GObject *object)
priv->save_as_proxy = NULL;
}
+ if (priv->copy_target_list != NULL) {
+ gtk_target_list_unref (priv->copy_target_list);
+ priv->copy_target_list = NULL;
+ }
+
+ if (priv->paste_target_list != NULL) {
+ gtk_target_list_unref (priv->paste_target_list);
+ priv->paste_target_list = NULL;
+ }
+
/* Chain up to parent's dispose() method. */
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@@ -765,6 +808,26 @@ web_view_extract_uri (EWebView *web_view,
return uri;
}
+static void
+web_view_copy_clipboard (EWebView *web_view)
+{
+ gtk_html_command (GTK_HTML (web_view), "copy");
+}
+
+static void
+web_view_cut_clipboard (EWebView *web_view)
+{
+ if (e_web_view_get_editable (web_view))
+ gtk_html_command (GTK_HTML (web_view), "cut");
+}
+
+static void
+web_view_paste_clipboard (EWebView *web_view)
+{
+ if (e_web_view_get_editable (web_view))
+ gtk_html_command (GTK_HTML (web_view), "paste");
+}
+
static gboolean
web_view_popup_event (EWebView *web_view,
GdkEventButton *event,
@@ -865,39 +928,76 @@ web_view_selectable_update_actions (ESelectable *selectable,
{
EWebView *web_view;
GtkAction *action;
- const gchar *tooltip;
+ /*GtkTargetList *target_list;*/
+ gboolean can_paste = FALSE;
+ gboolean editable;
+ gboolean have_selection;
gboolean sensitive;
+ const gchar *tooltip;
+ /*gint ii;*/
web_view = E_WEB_VIEW (selectable);
+ editable = e_web_view_get_editable (web_view);
+ have_selection = e_web_view_is_selection_active (web_view);
- /* Copy Clipboard */
-
- action = e_web_view_get_action (web_view, "copy-clipboard");
- sensitive = gtk_action_get_sensitive (action);
- tooltip = gtk_action_get_tooltip (action);
+ /* XXX GtkHtml implements its own clipboard instead of using
+ * GDK_SELECTION_CLIPBOARD, so we don't get notifications
+ * when the clipboard contents change. The logic below
+ * is what we would do if GtkHtml worked properly.
+ * Instead, we need to keep the Paste action sensitive so
+ * its accelerator overrides GtkHtml's key binding. */
+#if 0
+ target_list = e_selectable_get_paste_target_list (selectable);
+ for (ii = 0; ii < n_clipboard_targets && !can_paste; ii++)
+ can_paste = gtk_target_list_find (
+ target_list, clipboard_targets[ii], NULL);
+#endif
+ can_paste = TRUE;
+
+ action = e_focus_tracker_get_cut_clipboard_action (focus_tracker);
+ sensitive = editable && have_selection;
+ tooltip = _("Cut the selection");
+ gtk_action_set_sensitive (action, sensitive);
+ gtk_action_set_tooltip (action, tooltip);
action = e_focus_tracker_get_copy_clipboard_action (focus_tracker);
+ sensitive = have_selection;
+ tooltip = _("Copy the selection");
gtk_action_set_sensitive (action, sensitive);
gtk_action_set_tooltip (action, tooltip);
- /* Select All */
-
- action = e_web_view_get_action (web_view, "select-all");
- sensitive = gtk_action_get_sensitive (action);
- tooltip = gtk_action_get_tooltip (action);
+ action = e_focus_tracker_get_paste_clipboard_action (focus_tracker);
+ sensitive = editable && can_paste;
+ tooltip = _("Paste the clipboard");
+ gtk_action_set_sensitive (action, sensitive);
+ gtk_action_set_tooltip (action, tooltip);
action = e_focus_tracker_get_select_all_action (focus_tracker);
+ sensitive = TRUE;
+ tooltip = _("Select all text and images");
gtk_action_set_sensitive (action, sensitive);
gtk_action_set_tooltip (action, tooltip);
}
static void
+web_view_selectable_cut_clipboard (ESelectable *selectable)
+{
+ e_web_view_cut_clipboard (E_WEB_VIEW (selectable));
+}
+
+static void
web_view_selectable_copy_clipboard (ESelectable *selectable)
{
e_web_view_copy_clipboard (E_WEB_VIEW (selectable));
}
static void
+web_view_selectable_paste_clipboard (ESelectable *selectable)
+{
+ e_web_view_paste_clipboard (E_WEB_VIEW (selectable));
+}
+
+static void
web_view_selectable_select_all (ESelectable *selectable)
{
e_web_view_select_all (E_WEB_VIEW (selectable));
@@ -930,6 +1030,9 @@ web_view_class_init (EWebViewClass *class)
html_class->iframe_created = web_view_iframe_created;
class->extract_uri = web_view_extract_uri;
+ class->copy_clipboard = web_view_copy_clipboard;
+ class->cut_clipboard = web_view_cut_clipboard;
+ class->paste_clipboard = web_view_paste_clipboard;
class->popup_event = web_view_popup_event;
class->stop_loading = web_view_stop_loading;
class->update_actions = web_view_update_actions;
@@ -954,6 +1057,12 @@ web_view_class_init (EWebViewClass *class)
FALSE,
G_PARAM_READWRITE));
+ /* Inherited from ESelectableInterface */
+ g_object_class_override_property (
+ object_class,
+ PROP_COPY_TARGET_LIST,
+ "copy-target-list");
+
g_object_class_install_property (
object_class,
PROP_DISABLE_PRINTING,
@@ -976,6 +1085,16 @@ web_view_class_init (EWebViewClass *class)
g_object_class_install_property (
object_class,
+ PROP_EDITABLE,
+ g_param_spec_boolean (
+ "editable",
+ "Editable",
+ NULL,
+ FALSE,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (
+ object_class,
PROP_OPEN_PROXY,
g_param_spec_object (
"open-proxy",
@@ -984,6 +1103,12 @@ web_view_class_init (EWebViewClass *class)
GTK_TYPE_ACTION,
G_PARAM_READWRITE));
+ /* Inherited from ESelectableInterface */
+ g_object_class_override_property (
+ object_class,
+ PROP_PASTE_TARGET_LIST,
+ "paste-target-list");
+
g_object_class_install_property (
object_class,
PROP_PRINT_PROXY,
@@ -1014,6 +1139,33 @@ web_view_class_init (EWebViewClass *class)
NULL,
G_PARAM_READWRITE));
+ signals[COPY_CLIPBOARD] = g_signal_new (
+ "copy-clipboard",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EWebViewClass, copy_clipboard),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[CUT_CLIPBOARD] = g_signal_new (
+ "cut-clipboard",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EWebViewClass, cut_clipboard),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[PASTE_CLIPBOARD] = g_signal_new (
+ "paste-clipboard",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (EWebViewClass, paste_clipboard),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
signals[POPUP_EVENT] = g_signal_new (
"popup-event",
G_TYPE_FROM_CLASS (class),
@@ -1058,7 +1210,9 @@ static void
web_view_selectable_init (ESelectableInterface *interface)
{
interface->update_actions = web_view_selectable_update_actions;
+ interface->cut_clipboard = web_view_selectable_cut_clipboard;
interface->copy_clipboard = web_view_selectable_copy_clipboard;
+ interface->paste_clipboard = web_view_selectable_paste_clipboard;
interface->select_all = web_view_selectable_select_all;
}
@@ -1067,6 +1221,7 @@ web_view_init (EWebView *web_view)
{
GtkUIManager *ui_manager;
GtkActionGroup *action_group;
+ GtkTargetList *target_list;
EPopupAction *popup_action;
const gchar *domain = GETTEXT_PACKAGE;
const gchar *id;
@@ -1081,6 +1236,12 @@ web_view_init (EWebView *web_view)
ui_manager, "connect-proxy",
G_CALLBACK (web_view_connect_proxy_cb), web_view);
+ target_list = gtk_target_list_new (NULL, 0);
+ web_view->priv->copy_target_list = target_list;
+
+ target_list = gtk_target_list_new (NULL, 0);
+ web_view->priv->paste_target_list = target_list;
+
action_group = gtk_action_group_new ("uri");
gtk_action_group_set_translation_domain (action_group, domain);
gtk_ui_manager_insert_action_group (ui_manager, action_group, 0);
@@ -1287,6 +1448,14 @@ e_web_view_set_caret_mode (EWebView *web_view,
g_object_notify (G_OBJECT (web_view), "caret-mode");
}
+GtkTargetList *
+e_web_view_get_copy_target_list (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ return web_view->priv->copy_target_list;
+}
+
gboolean
e_web_view_get_disable_printing (EWebView *web_view)
{
@@ -1325,6 +1494,32 @@ e_web_view_set_disable_save_to_disk (EWebView *web_view,
g_object_notify (G_OBJECT (web_view), "disable-save-to-disk");
}
+gboolean
+e_web_view_get_editable (EWebView *web_view)
+{
+ /* XXX This is just here to maintain symmetry
+ * with e_web_view_set_editable(). */
+
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), FALSE);
+
+ return gtk_html_get_editable (GTK_HTML (web_view));
+}
+
+void
+e_web_view_set_editable (EWebView *web_view,
+ gboolean editable)
+{
+ /* XXX GtkHTML does not utilize GObject properties as well
+ * as it could. This just wraps gtk_html_set_editable()
+ * so we can get a "notify::editable" signal. */
+
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ gtk_html_set_editable (GTK_HTML (web_view), editable);
+
+ g_object_notify (G_OBJECT (web_view), "editable");
+}
+
const gchar *
e_web_view_get_selected_uri (EWebView *web_view)
{
@@ -1372,6 +1567,14 @@ e_web_view_set_open_proxy (EWebView *web_view,
g_object_notify (G_OBJECT (web_view), "open-proxy");
}
+GtkTargetList *
+e_web_view_get_paste_target_list (EWebView *web_view)
+{
+ g_return_val_if_fail (E_IS_WEB_VIEW (web_view), NULL);
+
+ return web_view->priv->paste_target_list;
+}
+
GtkAction *
e_web_view_get_print_proxy (EWebView *web_view)
{
@@ -1477,7 +1680,15 @@ e_web_view_copy_clipboard (EWebView *web_view)
{
g_return_if_fail (E_IS_WEB_VIEW (web_view));
- gtk_html_command (GTK_HTML (web_view), "copy");
+ g_signal_emit (web_view, signals[COPY_CLIPBOARD], 0);
+}
+
+void
+e_web_view_cut_clipboard (EWebView *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ g_signal_emit (web_view, signals[CUT_CLIPBOARD], 0);
}
gboolean
@@ -1488,6 +1699,14 @@ e_web_view_is_selection_active (EWebView *web_view)
return gtk_html_command (GTK_HTML (web_view), "is-selection-active");
}
+void
+e_web_view_paste_clipboard (EWebView *web_view)
+{
+ g_return_if_fail (E_IS_WEB_VIEW (web_view));
+
+ g_signal_emit (web_view, signals[PASTE_CLIPBOARD], 0);
+}
+
gboolean
e_web_view_scroll_forward (EWebView *web_view)
{
diff --git a/widgets/misc/e-web-view.h b/widgets/misc/e-web-view.h
index 123965c7d0..788eadb1b7 100644
--- a/widgets/misc/e-web-view.h
+++ b/widgets/misc/e-web-view.h
@@ -71,6 +71,9 @@ struct _EWebViewClass {
GtkHTML *frame);
/* Signals */
+ void (*copy_clipboard) (EWebView *web_view);
+ void (*cut_clipboard) (EWebView *web_view);
+ void (*paste_clipboard) (EWebView *web_view);
gboolean (*popup_event) (EWebView *web_view,
GdkEventButton *event,
const gchar *uri);
@@ -91,6 +94,7 @@ void e_web_view_set_animate (EWebView *web_view,
gboolean e_web_view_get_caret_mode (EWebView *web_view);
void e_web_view_set_caret_mode (EWebView *web_view,
gboolean caret_mode);
+GtkTargetList * e_web_view_get_copy_target_list (EWebView *web_view);
gboolean e_web_view_get_disable_printing (EWebView *web_view);
void e_web_view_set_disable_printing (EWebView *web_view,
gboolean disable_printing);
@@ -99,12 +103,16 @@ gboolean e_web_view_get_disable_save_to_disk
void e_web_view_set_disable_save_to_disk
(EWebView *web_view,
gboolean disable_save_to_disk);
+gboolean e_web_view_get_editable (EWebView *web_view);
+void e_web_view_set_editable (EWebView *web_view,
+ gboolean editable);
const gchar * e_web_view_get_selected_uri (EWebView *web_view);
void e_web_view_set_selected_uri (EWebView *web_view,
const gchar *selected_uri);
GtkAction * e_web_view_get_open_proxy (EWebView *web_view);
void e_web_view_set_open_proxy (EWebView *web_view,
GtkAction *open_proxy);
+GtkTargetList * e_web_view_get_paste_target_list(EWebView *web_view);
GtkAction * e_web_view_get_print_proxy (EWebView *web_view);
void e_web_view_set_print_proxy (EWebView *web_view,
GtkAction *print_proxy);
@@ -119,7 +127,9 @@ gchar * e_web_view_extract_uri (EWebView *web_view,
GdkEventButton *event,
GtkHTML *frame);
void e_web_view_copy_clipboard (EWebView *web_view);
+void e_web_view_cut_clipboard (EWebView *web_view);
gboolean e_web_view_is_selection_active (EWebView *web_view);
+void e_web_view_paste_clipboard (EWebView *web_view);
gboolean e_web_view_scroll_forward (EWebView *web_view);
gboolean e_web_view_scroll_backward (EWebView *web_view);
void e_web_view_select_all (EWebView *web_view);