diff options
author | Po Lu <luangruo@yahoo.com> | 2022-06-21 22:03:42 +0800 |
---|---|---|
committer | Po Lu <luangruo@yahoo.com> | 2022-06-21 22:05:21 +0800 |
commit | be35c92c90d455739a6ff9d4beefa2b35d044852 (patch) | |
tree | 19c5be6b9e09ccb45c58a5008f8f956f3ad92d57 /src/pgtkterm.c | |
parent | b1af8c2c00aefe6aa554a468e65b6e07c9f14722 (diff) | |
download | emacs-be35c92c90d455739a6ff9d4beefa2b35d044852.tar.gz |
Rewrite PGTK selection code from scratch
* src/frame.c (delete_frame): Clear selections and swallow
special events.
* src/keyboard.c (kbd_buffer_get_event, process_special_events):
Also handle selection events on PGTK.
* src/keyboard.h (union buffered_input_event): Include selection
events on PGTK.
* src/pgtkselect.c (symbol_to_gtk_clipboard, LOCAL_SELECTION):
New functions and macros.
(selection_type_to_quarks, get_func, clear_func): Delete
functions.
(pgtk_selection_init, pgtk_selection_lost):
(pgtk_selection_usable): New functions.
(Fpgtk_own_selection_internal, Fpgtk_disown_selection_internal)
(Fpgtk_selection_exists_p, Fpgtk_selection_owner_p)
(Fpgtk_get_selection_internal): Complete rewrite.
(syms_of_pgtkselect): Update defsyms and add more hooks.
* src/pgtkselect.h: Delete file.
* src/pgtkterm.c (evq_enqueue): Set last user time based on the
event.
(pgtk_any_window_to_frame, button_event): Fix coding style.
(pgtk_set_event_handler): Add selection events.
(pgtk_find_selection_owner, pgtk_selection_event): New
functions.
(pgtk_term_init): Remove call to `pgtk_selection_init'.
* src/pgtkterm.h (struct pgtk_display_info): New field
`display'.
(enum selection_input_event): New struct. New macros for
accessing its fields.
Diffstat (limited to 'src/pgtkterm.c')
-rw-r--r-- | src/pgtkterm.c | 129 |
1 files changed, 112 insertions, 17 deletions
diff --git a/src/pgtkterm.c b/src/pgtkterm.c index da958a6664a..91874ff58a5 100644 --- a/src/pgtkterm.c +++ b/src/pgtkterm.c @@ -61,7 +61,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include "buffer.h" #include "font.h" #include "xsettings.h" -#include "pgtkselect.h" #include "emacsgtkfixed.h" #ifdef GDK_WINDOWING_WAYLAND @@ -290,6 +289,9 @@ static void evq_enqueue (union buffered_input_event *ev) { struct event_queue_t *evq = &event_q; + struct frame *frame; + struct pgtk_display_info *dpyinfo; + if (evq->cap == 0) { evq->cap = 4; @@ -303,6 +305,27 @@ evq_enqueue (union buffered_input_event *ev) } evq->q[evq->nr++] = *ev; + + if (ev->ie.kind != SELECTION_REQUEST_EVENT + && ev->ie.kind != SELECTION_CLEAR_EVENT) + { + frame = NULL; + + if (WINDOWP (ev->ie.frame_or_window)) + frame = WINDOW_XFRAME (XWINDOW (ev->ie.frame_or_window)); + + if (FRAMEP (ev->ie.frame_or_window)) + frame = XFRAME (ev->ie.frame_or_window); + + if (frame) + { + dpyinfo = FRAME_DISPLAY_INFO (frame); + + if (dpyinfo->last_user_time < ev->ie.timestamp) + dpyinfo->last_user_time = ev->ie.timestamp; + } + } + raise (SIGIO); } @@ -4809,16 +4832,16 @@ pgtk_any_window_to_frame (GdkWindow *window) return NULL; FOR_EACH_FRAME (tail, frame) - { - if (found) - break; - f = XFRAME (frame); - if (FRAME_PGTK_P (f)) - { - if (pgtk_window_is_of_frame (f, window)) - found = f; - } - } + { + if (found) + break; + f = XFRAME (frame); + if (FRAME_PGTK_P (f)) + { + if (pgtk_window_is_of_frame (f, window)) + found = f; + } + } return found; } @@ -5868,8 +5891,7 @@ construct_mouse_click (struct input_event *result, } static gboolean -button_event (GtkWidget *widget, - GdkEvent *event, +button_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data) { union buffered_input_event inev; @@ -6174,6 +6196,8 @@ pgtk_monitors_changed_cb (GdkScreen *screen, gpointer user_data) evq_enqueue (&inev); } +static gboolean pgtk_selection_event (GtkWidget *, GdkEvent *, gpointer); + void pgtk_set_event_handler (struct frame *f) { @@ -6225,14 +6249,20 @@ pgtk_set_event_handler (struct frame *f) G_CALLBACK (button_event), NULL); g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "scroll-event", G_CALLBACK (scroll_event), NULL); - g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "selection-clear-event", - G_CALLBACK (pgtk_selection_lost), NULL); g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "configure-event", G_CALLBACK (configure_event), NULL); g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "drag-data-received", G_CALLBACK (drag_data_received), NULL); g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "draw", G_CALLBACK (pgtk_handle_draw), NULL); + g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "property-notify-event", + G_CALLBACK (pgtk_selection_event), NULL); + g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "selection-clear-event", + G_CALLBACK (pgtk_selection_event), NULL); + g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "selection-request-event", + G_CALLBACK (pgtk_selection_event), NULL); + g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "selection-notify-event", + G_CALLBACK (pgtk_selection_event), NULL); g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "event", G_CALLBACK (pgtk_handle_event), NULL); } @@ -6292,6 +6322,73 @@ same_x_server (const char *name1, const char *name2) && (*name2 == '.' || *name2 == '\0')); } +static struct frame * +pgtk_find_selection_owner (GdkWindow *window) +{ + Lisp_Object tail, tem; + struct frame *f; + + FOR_EACH_FRAME (tail, tem) + { + f = XFRAME (tem); + + if (FRAME_PGTK_P (f) + && (FRAME_GDK_WINDOW (f) == window)) + return f; + } + + return NULL; +} + +static gboolean +pgtk_selection_event (GtkWidget *widget, GdkEvent *event, + gpointer user_data) +{ + struct frame *f; + union buffered_input_event inev; + + if (event->type == GDK_PROPERTY_NOTIFY) + pgtk_handle_property_notify (&event->property); + else if (event->type == GDK_SELECTION_CLEAR + || event->type == GDK_SELECTION_REQUEST) + { + f = pgtk_find_selection_owner (event->selection.window); + + if (f) + { + EVENT_INIT (inev.ie); + + inev.sie.kind = (event->type == GDK_SELECTION_CLEAR + ? SELECTION_CLEAR_EVENT + : SELECTION_REQUEST_EVENT); + + SELECTION_EVENT_DPYINFO (&inev.sie) = FRAME_DISPLAY_INFO (f); + SELECTION_EVENT_SELECTION (&inev.sie) = event->selection.selection; + SELECTION_EVENT_TIME (&inev.sie) = event->selection.time; + + if (event->type == GDK_SELECTION_REQUEST) + { + /* FIXME: when does GDK destroy the requestor GdkWindow + object? + + It would make sense to wait for the transfer to + complete. But I don't know if GDK actually does + that. */ + SELECTION_EVENT_REQUESTOR (&inev.sie) = event->selection.requestor; + SELECTION_EVENT_TARGET (&inev.sie) = event->selection.target; + SELECTION_EVENT_PROPERTY (&inev.sie) = event->selection.property; + } + + evq_enqueue (&inev); + return TRUE; + } + } + else if (event->type == GDK_SELECTION_NOTIFY) + pgtk_handle_selection_notify (&event->selection); + + return FALSE; +} + /* Open a connection to X display DISPLAY_NAME, and return the structure that describes the open display. If we cannot contact the display, return null. */ @@ -6525,8 +6622,6 @@ pgtk_term_init (Lisp_Object display_name, char *resource_name) xsettings_initialize (dpyinfo); - pgtk_selection_init (); - pgtk_im_init (dpyinfo); g_signal_connect (G_OBJECT (dpyinfo->gdpy), "seat-added", |