[tepl] ApplicationWindow: update paste sensitivity according to clipboard
- From: Sébastien Wilmet <swilmet src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tepl] ApplicationWindow: update paste sensitivity according to clipboard
- Date: Wed, 26 Jul 2017 19:57:12 +0000 (UTC)
commit 810db09f33837dce39e9fe6b69d7848fc8a44265
Author: Sébastien Wilmet <swilmet gnome org>
Date: Wed Jul 26 19:44:17 2017 +0200
ApplicationWindow: update paste sensitivity according to clipboard
I think it is a better implementation than in gedit. We look at all the
target atoms supported by GtkTextBuffer.
gedit connects to the GtkClipboard::owner-change signal when the
GtkWindow is realized. But I don't think this is still necessary with
GTK+ 3. The doc of gtk_widget_get_clipboard() says: “@widget must have a
GdkDisplay associated with it, so must be attached to a toplevel
window.”, but here @widget *is* a toplevel window, so I think the
GdkDisplay is already associated. I've tested and in
tepl_application_window_constructed(), the GtkApplicationWindow is not
realized but the GtkClipboard isn't NULL. So I think everything is fine.
tepl/tepl-application-window.c | 127 ++++++++++++++++++++++++++++++++++++++-
1 files changed, 123 insertions(+), 4 deletions(-)
---
diff --git a/tepl/tepl-application-window.c b/tepl/tepl-application-window.c
index 1653338..2cec80d 100644
--- a/tepl/tepl-application-window.c
+++ b/tepl/tepl-application-window.c
@@ -187,6 +187,109 @@ select_all_cb (GSimpleAction *action,
}
}
+/* @can_paste_according_to_clipboard: TRUE if calling
+ * tepl_view_paste_clipboard() will paste something.
+ */
+static void
+set_paste_action_sensitivity_according_to_clipboard (TeplApplicationWindow *tepl_window,
+ gboolean can_paste_according_to_clipboard)
+{
+ TeplView *view;
+ gboolean view_is_editable = FALSE;
+ GActionMap *action_map;
+ GAction *action;
+
+ view = tepl_tab_group_get_active_view (TEPL_TAB_GROUP (tepl_window));
+
+ if (view != NULL)
+ {
+ view_is_editable = gtk_text_view_get_editable (GTK_TEXT_VIEW (view));
+ }
+
+ action_map = G_ACTION_MAP (tepl_window->priv->gtk_window);
+ action = g_action_map_lookup_action (action_map, "tepl-paste");
+
+ /* Since this is called async, the disposal of the actions may have
+ * already happened. Ensure that we have an action before setting the
+ * state.
+ */
+ if (action != NULL)
+ {
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
+ view_is_editable &&
+ can_paste_according_to_clipboard);
+ }
+}
+
+static void
+clipboard_targets_received_cb (GtkClipboard *clipboard,
+ GdkAtom *atoms,
+ gint n_atoms,
+ gpointer user_data)
+{
+ TeplApplicationWindow *tepl_window = TEPL_APPLICATION_WINDOW (user_data);
+ TeplBuffer *active_buffer;
+ GtkTargetList *target_list;
+ gboolean can_paste = FALSE;
+ gint i;
+
+ active_buffer = tepl_tab_group_get_active_buffer (TEPL_TAB_GROUP (tepl_window));
+ if (active_buffer == NULL)
+ {
+ goto end;
+ }
+
+ target_list = gtk_text_buffer_get_paste_target_list (GTK_TEXT_BUFFER (active_buffer));
+
+ for (i = 0; i < n_atoms; i++)
+ {
+ if (gtk_target_list_find (target_list, atoms[i], NULL))
+ {
+ can_paste = TRUE;
+ break;
+ }
+ }
+
+end:
+ set_paste_action_sensitivity_according_to_clipboard (tepl_window, can_paste);
+
+ /* Async operation finished. */
+ g_object_unref (tepl_window->priv->gtk_window);
+}
+
+/* How to test this easily: with a clipboard manager like xsel:
+ * $ xsel --clipboard --clear
+ * $ echo -n "bloum!" | xsel --clipboard # -> GdkAtom "TEXT"
+ * Copy text in a GtkTextBuffer -> GdkAtom "GTK_TEXT_BUFFER_CONTENTS"
+ */
+static void
+update_paste_action_sensitivity (TeplApplicationWindow *tepl_window)
+{
+ GtkClipboard *clipboard;
+ GdkDisplay *display;
+
+ clipboard = gtk_widget_get_clipboard (GTK_WIDGET (tepl_window->priv->gtk_window),
+ GDK_SELECTION_CLIPBOARD);
+ g_return_if_fail (clipboard != NULL);
+
+ display = gtk_clipboard_get_display (clipboard);
+ if (!gdk_display_supports_selection_notification (display))
+ {
+ /* Do as if it can always paste, because if we set the paste
+ * action as insensitive, we won't get the notification when the
+ * clipboard contains something that we can paste (i.e.
+ * clipboard_owner_change_cb() will not be called).
+ */
+ set_paste_action_sensitivity_according_to_clipboard (tepl_window, TRUE);
+ return;
+ }
+
+ g_object_ref (tepl_window->priv->gtk_window);
+ gtk_clipboard_request_targets (clipboard,
+ clipboard_targets_received_cb,
+ tepl_window);
+}
+
static void
update_edit_actions_sensitivity (TeplApplicationWindow *tepl_window)
{
@@ -220,10 +323,8 @@ update_edit_actions_sensitivity (TeplApplicationWindow *tepl_window)
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
buffer_has_selection);
- /* TODO see if the clipboard isn't empty. */
- action = g_action_map_lookup_action (action_map, "tepl-paste");
- g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
- buffer != NULL);
+ /* For tepl-paste: */
+ update_paste_action_sensitivity (tepl_window);
action = g_action_map_lookup_action (action_map, "tepl-delete");
g_simple_action_set_enabled (G_SIMPLE_ACTION (action),
@@ -330,9 +431,18 @@ tepl_application_window_set_property (GObject *object,
}
static void
+clipboard_owner_change_cb (GtkClipboard *clipboard,
+ GdkEvent *event,
+ TeplApplicationWindow *tepl_window)
+{
+ update_paste_action_sensitivity (tepl_window);
+}
+
+static void
tepl_application_window_constructed (GObject *object)
{
TeplApplicationWindow *tepl_window = TEPL_APPLICATION_WINDOW (object);
+ GtkClipboard *clipboard;
if (G_OBJECT_CLASS (tepl_application_window_parent_class)->constructed != NULL)
{
@@ -340,6 +450,15 @@ tepl_application_window_constructed (GObject *object)
}
add_actions (tepl_window);
+
+ clipboard = gtk_widget_get_clipboard (GTK_WIDGET (tepl_window->priv->gtk_window),
+ GDK_SELECTION_CLIPBOARD);
+
+ g_signal_connect_object (clipboard,
+ "owner-change",
+ G_CALLBACK (clipboard_owner_change_cb),
+ tepl_window,
+ 0);
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]