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.
This commit is contained in:
parent
b1af8c2c00
commit
be35c92c90
7 changed files with 1863 additions and 398 deletions
11
src/frame.c
11
src/frame.c
|
@ -2176,6 +2176,17 @@ delete_frame (Lisp_Object frame, Lisp_Object force)
|
|||
x_clear_frame_selections (f);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PGTK
|
||||
if (FRAME_PGTK_P (f))
|
||||
{
|
||||
/* Do special selection events now, in case the window gets
|
||||
destroyed by this deletion. Does this run Lisp code? */
|
||||
swallow_events (false);
|
||||
|
||||
pgtk_clear_frame_selections (f);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Free glyphs.
|
||||
This function must be called before the window tree of the
|
||||
frame is deleted because windows contain dynamically allocated
|
||||
|
|
|
@ -4003,14 +4003,19 @@ kbd_buffer_get_event (KBOARD **kbp,
|
|||
case SELECTION_REQUEST_EVENT:
|
||||
case SELECTION_CLEAR_EVENT:
|
||||
{
|
||||
#ifdef HAVE_X11
|
||||
#if defined HAVE_X11 || HAVE_PGTK
|
||||
/* Remove it from the buffer before processing it,
|
||||
since otherwise swallow_events will see it
|
||||
and process it again. */
|
||||
struct selection_input_event copy = event->sie;
|
||||
kbd_fetch_ptr = next_kbd_event (event);
|
||||
input_pending = readable_events (0);
|
||||
|
||||
#ifdef HAVE_X11
|
||||
x_handle_selection_event (©);
|
||||
#else
|
||||
pgtk_handle_selection_event (©);
|
||||
#endif
|
||||
#else
|
||||
/* We're getting selection request events, but we don't have
|
||||
a window system. */
|
||||
|
@ -4381,7 +4386,7 @@ process_special_events (void)
|
|||
if (event->kind == SELECTION_REQUEST_EVENT
|
||||
|| event->kind == SELECTION_CLEAR_EVENT)
|
||||
{
|
||||
#ifdef HAVE_X11
|
||||
#if defined HAVE_X11 || defined HAVE_PGTK
|
||||
|
||||
/* Remove the event from the fifo buffer before processing;
|
||||
otherwise swallow_events called recursively could see it
|
||||
|
@ -4406,7 +4411,12 @@ process_special_events (void)
|
|||
moved_events * sizeof *kbd_fetch_ptr);
|
||||
kbd_fetch_ptr = next_kbd_event (kbd_fetch_ptr);
|
||||
input_pending = readable_events (0);
|
||||
|
||||
#ifdef HAVE_X11
|
||||
x_handle_selection_event (©);
|
||||
#else
|
||||
pgtk_handle_selection_event (©);
|
||||
#endif
|
||||
#else
|
||||
/* We're getting selection request events, but we don't have
|
||||
a window system. */
|
||||
|
|
|
@ -27,6 +27,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
|||
# include "xterm.h" /* for struct selection_input_event */
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_PGTK
|
||||
#include "pgtkterm.h" /* for struct selection_input_event */
|
||||
#endif
|
||||
|
||||
INLINE_HEADER_BEGIN
|
||||
|
||||
/* Most code should use this macro to access Lisp fields in struct kboard. */
|
||||
|
@ -226,7 +230,7 @@ union buffered_input_event
|
|||
{
|
||||
ENUM_BF (event_kind) kind : EVENT_KIND_WIDTH;
|
||||
struct input_event ie;
|
||||
#ifdef HAVE_X11
|
||||
#if defined HAVE_X11 || defined HAVE_PGTK
|
||||
struct selection_input_event sie;
|
||||
#endif
|
||||
};
|
||||
|
|
2009
src/pgtkselect.c
2009
src/pgtkselect.c
File diff suppressed because it is too large
Load diff
|
@ -1,31 +0,0 @@
|
|||
/* Definitions and headers for selection of pure Gtk+3.
|
||||
Copyright (C) 1989, 1993, 2005, 2008-2022 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This file is part of GNU Emacs.
|
||||
|
||||
GNU Emacs is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or (at
|
||||
your option) any later version.
|
||||
|
||||
GNU Emacs 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||
|
||||
|
||||
#include "dispextern.h"
|
||||
#include "frame.h"
|
||||
|
||||
#ifdef HAVE_PGTK
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
extern void pgtk_selection_init (void);
|
||||
extern void pgtk_selection_lost (GtkWidget *, GdkEventSelection *, gpointer);
|
||||
|
||||
#endif /* HAVE_PGTK */
|
129
src/pgtkterm.c
129
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",
|
||||
|
|
|
@ -127,8 +127,14 @@ struct pgtk_display_info
|
|||
/* The generic display parameters corresponding to this PGTK display. */
|
||||
struct terminal *terminal;
|
||||
|
||||
/* This says how to access this display in Gdk. */
|
||||
GdkDisplay *gdpy;
|
||||
union
|
||||
{
|
||||
/* This says how to access this display through GDK. */
|
||||
GdkDisplay *gdpy;
|
||||
|
||||
/* An alias defined to make porting X code easier. */
|
||||
GdkDisplay *display;
|
||||
};
|
||||
|
||||
/* This is a cons cell of the form (NAME . FONT-LIST-CACHE). */
|
||||
Lisp_Object name_list_element;
|
||||
|
@ -210,6 +216,9 @@ struct pgtk_display_info
|
|||
/* Time of last mouse movement. */
|
||||
Time last_mouse_movement_time;
|
||||
|
||||
/* Time of last user interaction. */
|
||||
guint32 last_user_time;
|
||||
|
||||
/* The scroll bar in which the last motion event occurred. */
|
||||
void *last_mouse_scroll_bar;
|
||||
|
||||
|
@ -443,10 +452,11 @@ enum
|
|||
FRAME_GTK_OUTER_WIDGET (f) : \
|
||||
FRAME_GTK_WIDGET (f))
|
||||
|
||||
/* aliases */
|
||||
#define FRAME_PGTK_VIEW(f) FRAME_GTK_WIDGET (f)
|
||||
#define FRAME_X_WINDOW(f) FRAME_GTK_OUTER_WIDGET (f)
|
||||
#define FRAME_NATIVE_WINDOW(f) GTK_WINDOW (FRAME_X_WINDOW (f))
|
||||
#define FRAME_GDK_WINDOW(f) \
|
||||
(gtk_widget_get_window (FRAME_GTK_WIDGET (f)))
|
||||
|
||||
#define FRAME_X_DISPLAY(f) (FRAME_DISPLAY_INFO (f)->gdpy)
|
||||
|
||||
|
@ -484,6 +494,49 @@ enum
|
|||
#define FRAME_CR_SURFACE_DESIRED_HEIGHT(f) \
|
||||
((f)->output_data.pgtk->cr_surface_desired_height)
|
||||
|
||||
|
||||
/* If a struct input_event has a kind which is SELECTION_REQUEST_EVENT
|
||||
or SELECTION_CLEAR_EVENT, then its contents are really described
|
||||
by this structure. */
|
||||
|
||||
/* For an event of kind SELECTION_REQUEST_EVENT,
|
||||
this structure really describes the contents. */
|
||||
|
||||
struct selection_input_event
|
||||
{
|
||||
ENUM_BF (event_kind) kind : EVENT_KIND_WIDTH;
|
||||
struct pgtk_display_info *dpyinfo;
|
||||
/* We spell it with an "o" here because X does. */
|
||||
GdkWindow *requestor;
|
||||
GdkAtom selection, target, property;
|
||||
guint32 time;
|
||||
};
|
||||
|
||||
/* Unlike macros below, this can't be used as an lvalue. */
|
||||
INLINE GdkDisplay *
|
||||
SELECTION_EVENT_DISPLAY (struct selection_input_event *ev)
|
||||
{
|
||||
return ev->dpyinfo->display;
|
||||
}
|
||||
#define SELECTION_EVENT_DPYINFO(eventp) \
|
||||
((eventp)->dpyinfo)
|
||||
/* We spell it with an "o" here because X does. */
|
||||
#define SELECTION_EVENT_REQUESTOR(eventp) \
|
||||
((eventp)->requestor)
|
||||
#define SELECTION_EVENT_SELECTION(eventp) \
|
||||
((eventp)->selection)
|
||||
#define SELECTION_EVENT_TARGET(eventp) \
|
||||
((eventp)->target)
|
||||
#define SELECTION_EVENT_PROPERTY(eventp) \
|
||||
((eventp)->property)
|
||||
#define SELECTION_EVENT_TIME(eventp) \
|
||||
((eventp)->time)
|
||||
|
||||
extern void pgtk_handle_selection_event (struct selection_input_event *);
|
||||
extern void pgtk_clear_frame_selections (struct frame *);
|
||||
extern void pgtk_handle_property_notify (GdkEventProperty *);
|
||||
extern void pgtk_handle_selection_notify (GdkEventSelection *);
|
||||
|
||||
/* Display init/shutdown functions implemented in pgtkterm.c */
|
||||
extern struct pgtk_display_info *pgtk_term_init (Lisp_Object display_name,
|
||||
char *resource_name);
|
||||
|
@ -493,7 +546,7 @@ extern void pgtk_term_shutdown (int sig);
|
|||
extern void pgtk_clear_frame (struct frame *f);
|
||||
extern char *pgtk_xlfd_to_fontname (const char *xlfd);
|
||||
|
||||
/* Implemented in pgtkfns. */
|
||||
/* Implemented in pgtkfns.c. */
|
||||
extern void pgtk_set_doc_edited (void);
|
||||
extern const char *pgtk_get_defaults_value (const char *key);
|
||||
extern const char *pgtk_get_string_resource (XrmDatabase rdb,
|
||||
|
|
Loading…
Add table
Reference in a new issue