diff options
Diffstat (limited to 'widgets')
-rw-r--r-- | widgets/misc/e-focus-tracker.c | 14 | ||||
-rw-r--r-- | widgets/misc/e-selectable.c | 58 | ||||
-rw-r--r-- | widgets/misc/e-selectable.h | 4 | ||||
-rw-r--r-- | widgets/misc/e-web-view.c | 243 | ||||
-rw-r--r-- | widgets/misc/e-web-view.h | 10 |
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); |