Make responding to selection requests work inside popups
* src/xfns.c (Fx_file_dialog): * src/xmenu.c (x_menu_wait_for_event, create_and_show_popup_menu) (create_and_show_dialog, x_menu_show): Defer selection requests. * src/xselect.c (x_get_foreign_selection) (x_handle_selection_notify): Add some more info to selection trace. * src/xterm.c (x_defer_selection_requests): Make non-static. (x_release_selection_requests_and_flush): New function. (x_dnd_begin_drag_and_drop): Use DEFER_SELECTIONS instead. (x_wait_for_cell_change): Fix initial value of rc for pushed back events. (handle_one_xevent): Allow GTK to respond to selections in its windows too. * src/xterm.h (DEFER_SELECTIONS): New slug of code.
This commit is contained in:
parent
90f3da0ccd
commit
22d3f0e95a
5 changed files with 86 additions and 18 deletions
|
@ -8885,6 +8885,9 @@ DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0,
|
|||
/* Prevent redisplay. */
|
||||
specbind (Qinhibit_redisplay, Qt);
|
||||
|
||||
/* Defer selection requests. */
|
||||
DEFER_SELECTIONS;
|
||||
|
||||
block_input ();
|
||||
|
||||
/* Create the dialog with PROMPT as title, using DIR as initial
|
||||
|
|
24
src/xmenu.c
24
src/xmenu.c
|
@ -198,6 +198,10 @@ x_menu_wait_for_event (void *data)
|
|||
struct x_display_info *dpyinfo;
|
||||
int n = 0;
|
||||
|
||||
/* ISTM that if timer_check is okay, this should be too, since
|
||||
both can run random Lisp. */
|
||||
x_handle_pending_selection_requests ();
|
||||
|
||||
FD_ZERO (&read_fds);
|
||||
for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
|
||||
{
|
||||
|
@ -1579,6 +1583,8 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
|
|||
}
|
||||
#endif
|
||||
|
||||
DEFER_SELECTIONS;
|
||||
|
||||
/* Display the menu. */
|
||||
gtk_widget_show_all (menu);
|
||||
|
||||
|
@ -1868,6 +1874,8 @@ create_and_show_popup_menu (struct frame *f, widget_value *first_wv,
|
|||
{
|
||||
specpdl_ref specpdl_count = SPECPDL_INDEX ();
|
||||
|
||||
DEFER_SELECTIONS;
|
||||
|
||||
record_unwind_protect_int (pop_down_menu, (int) menu_id);
|
||||
#ifdef HAVE_XINPUT2
|
||||
record_unwind_protect_ptr (leave_toolkit_menu, f);
|
||||
|
@ -2199,6 +2207,8 @@ create_and_show_dialog (struct frame *f, widget_value *first_wv)
|
|||
if (menu)
|
||||
{
|
||||
specpdl_ref specpdl_count = SPECPDL_INDEX ();
|
||||
|
||||
DEFER_SELECTIONS;
|
||||
record_unwind_protect_ptr (pop_down_menu, menu);
|
||||
|
||||
/* Display the menu. */
|
||||
|
@ -2255,6 +2265,8 @@ create_and_show_dialog (struct frame *f, widget_value *first_wv)
|
|||
{
|
||||
specpdl_ref count = SPECPDL_INDEX ();
|
||||
|
||||
DEFER_SELECTIONS;
|
||||
|
||||
/* xdialog_show_unwind is responsible for popping the dialog box down. */
|
||||
|
||||
record_unwind_protect_int (pop_down_menu, (int) dialog_id);
|
||||
|
@ -2715,18 +2727,18 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
|
|||
y = max (y, 1);
|
||||
XMenuLocate (FRAME_X_DISPLAY (f), menu, 0, 0, x, y,
|
||||
&ulx, &uly, &width, &height);
|
||||
if (ulx+width > dispwidth)
|
||||
if (ulx + width > dispwidth)
|
||||
{
|
||||
x -= (ulx + width) - dispwidth;
|
||||
ulx = dispwidth - width;
|
||||
}
|
||||
if (uly+height > dispheight)
|
||||
if (uly + height > dispheight)
|
||||
{
|
||||
y -= (uly + height) - dispheight;
|
||||
uly = dispheight - height;
|
||||
}
|
||||
#ifndef HAVE_X_WINDOWS
|
||||
if (FRAME_HAS_MINIBUF_P (f) && uly+height > dispheight - 1)
|
||||
if (FRAME_HAS_MINIBUF_P (f) && uly + height > dispheight - 1)
|
||||
{
|
||||
/* Move the menu away of the echo area, to avoid overwriting the
|
||||
menu with help echo messages or vice versa. */
|
||||
|
@ -2750,8 +2762,8 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
|
|||
/* If position was not given by a mouse click, adjust so upper left
|
||||
corner of the menu as a whole ends up at given coordinates. This
|
||||
is what x-popup-menu says in its documentation. */
|
||||
x += width/2;
|
||||
y += 1.5*height/(maxlines+2);
|
||||
x += width / 2;
|
||||
y += 1.5 * height/ (maxlines + 2);
|
||||
}
|
||||
|
||||
XMenuSetAEQ (menu, true);
|
||||
|
@ -2759,6 +2771,8 @@ x_menu_show (struct frame *f, int x, int y, int menuflags,
|
|||
pane = selidx = 0;
|
||||
|
||||
#ifndef MSDOS
|
||||
DEFER_SELECTIONS;
|
||||
|
||||
XMenuActivateSetWaitFunction (x_menu_wait_for_event, FRAME_X_DISPLAY (f));
|
||||
#ifdef HAVE_XINPUT2
|
||||
XMenuActivateSetTranslateFunction (x_menu_translate_generic_event);
|
||||
|
|
|
@ -1252,7 +1252,11 @@ x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type,
|
|||
else
|
||||
x_wait_for_cell_change (reading_selection_reply,
|
||||
make_timespec (secs, nsecs));
|
||||
TRACE1 (" Got event = %d", !NILP (XCAR (reading_selection_reply)));
|
||||
TRACE1 (" Got event = %s", (!NILP (XCAR (reading_selection_reply))
|
||||
? (SYMBOLP (XCAR (reading_selection_reply))
|
||||
? SSDATA (SYMBOL_NAME (XCAR (reading_selection_reply)))
|
||||
: "YES")
|
||||
: "NO"));
|
||||
|
||||
if (NILP (XCAR (reading_selection_reply)))
|
||||
error ("Timed out waiting for reply from selection owner");
|
||||
|
@ -1947,7 +1951,7 @@ x_handle_selection_notify (const XSelectionEvent *event)
|
|||
if (event->selection != reading_which_selection)
|
||||
return;
|
||||
|
||||
TRACE0 ("Received SelectionNotify");
|
||||
TRACE1 ("Received SelectionNotify: %d", (int) event->property);
|
||||
XSETCAR (reading_selection_reply,
|
||||
(event->property != 0 ? Qt : Qlambda));
|
||||
}
|
||||
|
|
63
src/xterm.c
63
src/xterm.c
|
@ -793,10 +793,43 @@ static struct input_event *current_hold_quit;
|
|||
than 0. */
|
||||
static int x_use_pending_selection_requests;
|
||||
|
||||
static void
|
||||
static void x_push_selection_request (struct selection_input_event *);
|
||||
|
||||
/* Defer selection requests. Any selection requests generated after
|
||||
this can then be processed by calling
|
||||
`x_handle_pending_selection_requests'.
|
||||
|
||||
Also run through and queue all the selection events already in the
|
||||
keyboard buffer. */
|
||||
void
|
||||
x_defer_selection_requests (void)
|
||||
{
|
||||
union buffered_input_event *event;
|
||||
|
||||
block_input ();
|
||||
x_use_pending_selection_requests++;
|
||||
|
||||
if (!x_use_pending_selection_requests)
|
||||
{
|
||||
event = kbd_fetch_ptr;
|
||||
|
||||
while (event != kbd_store_ptr)
|
||||
{
|
||||
if (event->ie.kind == SELECTION_REQUEST_EVENT
|
||||
|| event->ie.kind == SELECTION_CLEAR_EVENT)
|
||||
{
|
||||
x_push_selection_request (&event->sie);
|
||||
|
||||
/* Mark this selection event as invalid. */
|
||||
SELECTION_EVENT_DPYINFO (&event->sie) = NULL;
|
||||
}
|
||||
|
||||
event = (event == kbd_buffer + KBD_BUFFER_SIZE - 1
|
||||
? kbd_buffer : event + 1);
|
||||
}
|
||||
}
|
||||
|
||||
unblock_input ();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -805,6 +838,15 @@ x_release_selection_requests (void)
|
|||
x_use_pending_selection_requests--;
|
||||
}
|
||||
|
||||
void
|
||||
x_release_selection_requests_and_flush (void)
|
||||
{
|
||||
x_release_selection_requests ();
|
||||
|
||||
if (!x_use_pending_selection_requests)
|
||||
x_handle_pending_selection_requests ();
|
||||
}
|
||||
|
||||
struct x_selection_request_event
|
||||
{
|
||||
/* The selection request event. */
|
||||
|
@ -10764,8 +10806,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
|
|||
if (x_dnd_in_progress || x_dnd_waiting_for_finish)
|
||||
error ("A drag-and-drop session is already in progress");
|
||||
|
||||
x_defer_selection_requests ();
|
||||
record_unwind_protect_void (x_release_selection_requests);
|
||||
DEFER_SELECTIONS;
|
||||
|
||||
/* If local_value is nil, then we lost ownership of XdndSelection.
|
||||
Signal a more informative error than args-out-of-range. */
|
||||
|
@ -10781,8 +10822,8 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
|
|||
if (popup_activated ())
|
||||
error ("Trying to drag-and-drop from within a menu-entry");
|
||||
|
||||
record_unwind_protect_void (x_free_dnd_targets);
|
||||
x_set_dnd_targets (target_atoms, ntargets);
|
||||
record_unwind_protect_void (x_free_dnd_targets);
|
||||
|
||||
ltimestamp = x_timestamp_for_selection (FRAME_DISPLAY_INFO (f),
|
||||
QXdndSelection);
|
||||
|
@ -15306,7 +15347,7 @@ x_wait_for_cell_change (Lisp_Object cell, struct timespec timeout)
|
|||
|
||||
#ifndef USE_GTK
|
||||
FD_ZERO (&rfds);
|
||||
rc = 0;
|
||||
rc = -1;
|
||||
#endif
|
||||
|
||||
while (true)
|
||||
|
@ -15892,18 +15933,18 @@ handle_one_xevent (struct x_display_info *dpyinfo,
|
|||
break;
|
||||
|
||||
case SelectionNotify:
|
||||
#ifdef USE_X_TOOLKIT
|
||||
if (! x_window_to_frame (dpyinfo, event->xselection.requestor))
|
||||
#if defined USE_X_TOOLKIT || defined USE_GTK
|
||||
if (!x_window_to_frame (dpyinfo, event->xselection.requestor))
|
||||
goto OTHER;
|
||||
#endif /* not USE_X_TOOLKIT */
|
||||
#endif /* not USE_X_TOOLKIT and not USE_GTK */
|
||||
x_handle_selection_notify (&event->xselection);
|
||||
break;
|
||||
|
||||
case SelectionClear: /* Someone has grabbed ownership. */
|
||||
#ifdef USE_X_TOOLKIT
|
||||
if (! x_window_to_frame (dpyinfo, event->xselectionclear.window))
|
||||
#if defined USE_X_TOOLKIT || defined USE_GTK
|
||||
if (!x_window_to_frame (dpyinfo, event->xselectionclear.window))
|
||||
goto OTHER;
|
||||
#endif /* USE_X_TOOLKIT */
|
||||
#endif /* not USE_X_TOOLKIT and not USE_GTK */
|
||||
{
|
||||
const XSelectionClearEvent *eventp = &event->xselectionclear;
|
||||
|
||||
|
|
|
@ -1456,6 +1456,12 @@ extern void x_xr_reset_ext_clip (struct frame *f);
|
|||
extern void x_scroll_bar_configure (GdkEvent *);
|
||||
#endif
|
||||
|
||||
#define DEFER_SELECTIONS \
|
||||
x_defer_selection_requests (); \
|
||||
record_unwind_protect_void (x_release_selection_requests_and_flush)
|
||||
|
||||
extern void x_defer_selection_requests (void);
|
||||
extern void x_release_selection_requests_and_flush (void);
|
||||
extern void x_handle_pending_selection_requests (void);
|
||||
extern bool x_detect_pending_selection_requests (void);
|
||||
extern Lisp_Object x_dnd_begin_drag_and_drop (struct frame *, Time, Atom,
|
||||
|
|
Loading…
Add table
Reference in a new issue