diff options
| author | Po Lu | 2022-09-24 16:27:42 +0800 |
|---|---|---|
| committer | Po Lu | 2022-09-24 16:30:37 +0800 |
| commit | 54876bf498f5e6b4f7a66a051b105c3ddd308945 (patch) | |
| tree | 48de4eac951b7cb9866d37011faeb55ee260ff0d /src | |
| parent | 767a10cc63de8ce9f85ac688be33555278b4f3fb (diff) | |
| download | emacs-54876bf498f5e6b4f7a66a051b105c3ddd308945.tar.gz emacs-54876bf498f5e6b4f7a66a051b105c3ddd308945.zip | |
Reduce complexity of scroll bar window protection code
It turns out my previous theories of why ClientMessages were
generated were wrong, and they are just generated so we can set
finish to X_EVENT_GOTO_OUT to have them delivered immediately.
This allows for the code to be simplified greatly, by not
unpacking pointers to the raw window into the client messages.
* src/xterm.c (x_unprotect_window_for_callback): Return the
window removed from the queue, or nil if none.
(x_scroll_bar_to_input_event)
(x_horizontal_scroll_bar_to_input_event): Use window provided by
x_unprotect_window_for_callback.
(handle_one_xevent): Pass dpyinfo to functions that need it.
(x_free_frame_resources): Remove "first scroll bar request"
code.
* src/xterm.h (struct x_display_info): Likewise.
Diffstat (limited to 'src')
| -rw-r--r-- | src/xterm.c | 104 | ||||
| -rw-r--r-- | src/xterm.h | 9 |
2 files changed, 54 insertions, 59 deletions
diff --git a/src/xterm.c b/src/xterm.c index 2d366e5511f..527c26f0da3 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -14385,17 +14385,23 @@ x_protect_window_for_callback (struct x_display_info *dpyinfo, | |||
| 14385 | return true; | 14385 | return true; |
| 14386 | } | 14386 | } |
| 14387 | 14387 | ||
| 14388 | static void | 14388 | static Lisp_Object |
| 14389 | x_unprotect_window_for_callback (struct x_display_info *dpyinfo) | 14389 | x_unprotect_window_for_callback (struct x_display_info *dpyinfo) |
| 14390 | { | 14390 | { |
| 14391 | Lisp_Object window; | ||
| 14392 | |||
| 14391 | if (!dpyinfo->n_protected_windows) | 14393 | if (!dpyinfo->n_protected_windows) |
| 14392 | emacs_abort (); | 14394 | return Qnil; |
| 14395 | |||
| 14396 | window = dpyinfo->protected_windows[0]; | ||
| 14393 | 14397 | ||
| 14394 | dpyinfo->n_protected_windows--; | 14398 | dpyinfo->n_protected_windows--; |
| 14395 | 14399 | ||
| 14396 | if (dpyinfo->n_protected_windows) | 14400 | if (dpyinfo->n_protected_windows) |
| 14397 | memmove (dpyinfo->protected_windows, &dpyinfo->protected_windows[1], | 14401 | memmove (dpyinfo->protected_windows, &dpyinfo->protected_windows[1], |
| 14398 | sizeof (Lisp_Object) * dpyinfo->n_protected_windows); | 14402 | sizeof (Lisp_Object) * dpyinfo->n_protected_windows); |
| 14403 | |||
| 14404 | return window; | ||
| 14399 | } | 14405 | } |
| 14400 | 14406 | ||
| 14401 | /* Send a client message with message type Xatom_Scrollbar for a | 14407 | /* Send a client message with message type Xatom_Scrollbar for a |
| @@ -14462,30 +14468,34 @@ x_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part, | |||
| 14462 | in *IEVENT. */ | 14468 | in *IEVENT. */ |
| 14463 | 14469 | ||
| 14464 | static void | 14470 | static void |
| 14465 | x_scroll_bar_to_input_event (const XEvent *event, | 14471 | x_scroll_bar_to_input_event (struct x_display_info *dpyinfo, |
| 14472 | const XEvent *event, | ||
| 14466 | struct input_event *ievent) | 14473 | struct input_event *ievent) |
| 14467 | { | 14474 | { |
| 14468 | const XClientMessageEvent *ev = &event->xclient; | ||
| 14469 | Lisp_Object window; | 14475 | Lisp_Object window; |
| 14470 | struct window *w; | ||
| 14471 | 14476 | ||
| 14472 | /* See the comment in the function above. */ | 14477 | /* Every time a scroll bar ClientMessage event is sent, the window |
| 14473 | intptr_t iw0 = ev->data.l[0]; | 14478 | is pushed onto a queue that is traced for garbage collection. |
| 14474 | intptr_t iw1 = ev->data.l[1]; | 14479 | Every time we need a window for a read scroll bar event, we |
| 14475 | intptr_t iw = (iw0 << 31 << 1) + (iw1 & 0xffffffffu); | 14480 | simply read from the other side of the queue. */ |
| 14476 | w = (struct window *) iw; | 14481 | window = x_unprotect_window_for_callback (dpyinfo); |
| 14477 | 14482 | ||
| 14478 | XSETWINDOW (window, w); | 14483 | if (NILP (window)) |
| 14484 | { | ||
| 14485 | /* This means we are getting extra scroll bar events for some | ||
| 14486 | reason, and shouldn't be possible in practice. */ | ||
| 14487 | EVENT_INIT (*ievent); | ||
| 14488 | return; | ||
| 14489 | } | ||
| 14479 | 14490 | ||
| 14480 | ievent->kind = SCROLL_BAR_CLICK_EVENT; | 14491 | ievent->kind = SCROLL_BAR_CLICK_EVENT; |
| 14481 | ievent->frame_or_window = window; | 14492 | ievent->frame_or_window = window; |
| 14482 | ievent->arg = Qnil; | 14493 | ievent->arg = Qnil; |
| 14483 | ievent->timestamp | 14494 | ievent->timestamp = x_get_last_toolkit_time (dpyinfo); |
| 14484 | = x_get_last_toolkit_time (FRAME_DISPLAY_INFO (XFRAME (w->frame))); | ||
| 14485 | ievent->code = 0; | 14495 | ievent->code = 0; |
| 14486 | ievent->part = ev->data.l[2]; | 14496 | ievent->part = event->xclient.data.l[2]; |
| 14487 | ievent->x = make_fixnum (ev->data.l[3]); | 14497 | ievent->x = make_fixnum (event->xclient.data.l[3]); |
| 14488 | ievent->y = make_fixnum (ev->data.l[4]); | 14498 | ievent->y = make_fixnum (event->xclient.data.l[4]); |
| 14489 | ievent->modifiers = 0; | 14499 | ievent->modifiers = 0; |
| 14490 | } | 14500 | } |
| 14491 | 14501 | ||
| @@ -14493,30 +14503,34 @@ x_scroll_bar_to_input_event (const XEvent *event, | |||
| 14493 | input event in *IEVENT. */ | 14503 | input event in *IEVENT. */ |
| 14494 | 14504 | ||
| 14495 | static void | 14505 | static void |
| 14496 | x_horizontal_scroll_bar_to_input_event (const XEvent *event, | 14506 | x_horizontal_scroll_bar_to_input_event (struct x_display_info *dpyinfo, |
| 14507 | const XEvent *event, | ||
| 14497 | struct input_event *ievent) | 14508 | struct input_event *ievent) |
| 14498 | { | 14509 | { |
| 14499 | const XClientMessageEvent *ev = &event->xclient; | ||
| 14500 | Lisp_Object window; | 14510 | Lisp_Object window; |
| 14501 | struct window *w; | ||
| 14502 | 14511 | ||
| 14503 | /* See the comment in the function above. */ | 14512 | /* Every time a scroll bar ClientMessage event is sent, the window |
| 14504 | intptr_t iw0 = ev->data.l[0]; | 14513 | is pushed onto a queue that is traced for garbage collection. |
| 14505 | intptr_t iw1 = ev->data.l[1]; | 14514 | Every time we need a window for a read scroll bar event, we |
| 14506 | intptr_t iw = (iw0 << 31 << 1) + (iw1 & 0xffffffffu); | 14515 | simply read from the other side of the queue. */ |
| 14507 | w = (struct window *) iw; | 14516 | window = x_unprotect_window_for_callback (dpyinfo); |
| 14508 | 14517 | ||
| 14509 | XSETWINDOW (window, w); | 14518 | if (NILP (window)) |
| 14519 | { | ||
| 14520 | /* This means we are getting extra scroll bar events for some | ||
| 14521 | reason, and shouldn't be possible in practice. */ | ||
| 14522 | EVENT_INIT (*ievent); | ||
| 14523 | return; | ||
| 14524 | } | ||
| 14510 | 14525 | ||
| 14511 | ievent->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT; | 14526 | ievent->kind = HORIZONTAL_SCROLL_BAR_CLICK_EVENT; |
| 14512 | ievent->frame_or_window = window; | 14527 | ievent->frame_or_window = window; |
| 14513 | ievent->arg = Qnil; | 14528 | ievent->arg = Qnil; |
| 14514 | ievent->timestamp | 14529 | ievent->timestamp = x_get_last_toolkit_time (dpyinfo); |
| 14515 | = x_get_last_toolkit_time (FRAME_DISPLAY_INFO (XFRAME (w->frame))); | ||
| 14516 | ievent->code = 0; | 14530 | ievent->code = 0; |
| 14517 | ievent->part = ev->data.l[2]; | 14531 | ievent->part = event->xclient.data.l[2]; |
| 14518 | ievent->x = make_fixnum (ev->data.l[3]); | 14532 | ievent->x = make_fixnum (event->xclient.data.l[3]); |
| 14519 | ievent->y = make_fixnum (ev->data.l[4]); | 14533 | ievent->y = make_fixnum (event->xclient.data.l[4]); |
| 14520 | ievent->modifiers = 0; | 14534 | ievent->modifiers = 0; |
| 14521 | } | 14535 | } |
| 14522 | 14536 | ||
| @@ -18104,28 +18118,21 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 18104 | we construct an input_event. */ | 18118 | we construct an input_event. */ |
| 18105 | if (event->xclient.message_type == dpyinfo->Xatom_Scrollbar) | 18119 | if (event->xclient.message_type == dpyinfo->Xatom_Scrollbar) |
| 18106 | { | 18120 | { |
| 18107 | x_scroll_bar_to_input_event (event, &inev.ie); | 18121 | /* Convert the scroll bar event to an input event using |
| 18108 | 18122 | the first window entered into the scroll bar event | |
| 18109 | /* Unprotect the first window to be sent in a | 18123 | queue. */ |
| 18110 | ClientMessage event, since it is now on the stack and | 18124 | x_scroll_bar_to_input_event (dpyinfo, event, &inev.ie); |
| 18111 | thereby subject to garbage collection. */ | ||
| 18112 | if (event->xclient.serial | ||
| 18113 | >= dpyinfo->first_valid_scroll_bar_req) | ||
| 18114 | x_unprotect_window_for_callback (dpyinfo); | ||
| 18115 | 18125 | ||
| 18116 | *finish = X_EVENT_GOTO_OUT; | 18126 | *finish = X_EVENT_GOTO_OUT; |
| 18117 | goto done; | 18127 | goto done; |
| 18118 | } | 18128 | } |
| 18119 | else if (event->xclient.message_type == dpyinfo->Xatom_Horizontal_Scrollbar) | 18129 | else if (event->xclient.message_type == dpyinfo->Xatom_Horizontal_Scrollbar) |
| 18120 | { | 18130 | { |
| 18121 | x_horizontal_scroll_bar_to_input_event (event, &inev.ie); | 18131 | /* Convert the horizontal scroll bar event to an input |
| 18122 | 18132 | event using the first window entered into the scroll | |
| 18123 | /* Unprotect the first window to be sent in a | 18133 | bar event queue. */ |
| 18124 | ClientMessage event, since it is now on the stack and | 18134 | x_horizontal_scroll_bar_to_input_event (dpyinfo, event, |
| 18125 | thereby subject to garbage collection. */ | 18135 | &inev.ie); |
| 18126 | if (event->xclient.serial | ||
| 18127 | >= dpyinfo->first_valid_scroll_bar_req) | ||
| 18128 | x_unprotect_window_for_callback (dpyinfo); | ||
| 18129 | 18136 | ||
| 18130 | *finish = X_EVENT_GOTO_OUT; | 18137 | *finish = X_EVENT_GOTO_OUT; |
| 18131 | goto done; | 18138 | goto done; |
| @@ -27347,11 +27354,8 @@ x_free_frame_resources (struct frame *f) | |||
| 27347 | #ifdef USE_TOOLKIT_SCROLL_BARS | 27354 | #ifdef USE_TOOLKIT_SCROLL_BARS |
| 27348 | /* Since the frame was destroyed, we can no longer guarantee | 27355 | /* Since the frame was destroyed, we can no longer guarantee |
| 27349 | that scroll bar events will be received. Clear | 27356 | that scroll bar events will be received. Clear |
| 27350 | protected_windows, and ignore any preceding scroll bar events | 27357 | protected_windows. */ |
| 27351 | that happen to still be deliverable. */ | ||
| 27352 | dpyinfo->n_protected_windows = 0; | 27358 | dpyinfo->n_protected_windows = 0; |
| 27353 | dpyinfo->first_valid_scroll_bar_req | ||
| 27354 | = XNextRequest (dpyinfo->display); | ||
| 27355 | #endif | 27359 | #endif |
| 27356 | } | 27360 | } |
| 27357 | 27361 | ||
diff --git a/src/xterm.h b/src/xterm.h index d1671621c78..d6ff15e40f7 100644 --- a/src/xterm.h +++ b/src/xterm.h | |||
| @@ -839,15 +839,6 @@ struct x_display_info | |||
| 839 | server_time_monotonic_p will be true). */ | 839 | server_time_monotonic_p will be true). */ |
| 840 | int_fast64_t server_time_offset; | 840 | int_fast64_t server_time_offset; |
| 841 | #endif | 841 | #endif |
| 842 | |||
| 843 | #if defined USE_TOOLKIT_SCROLL_BARS | ||
| 844 | /* Serial number of the first scroll bar event to start listening | ||
| 845 | to. This is necessary because protected_windows is display | ||
| 846 | local, but the destruction of a frame's edit window may cause | ||
| 847 | event windows to vanish before they are delivered, leading to | ||
| 848 | windows remaining protected indefinitely. */ | ||
| 849 | unsigned long first_valid_scroll_bar_req; | ||
| 850 | #endif | ||
| 851 | }; | 842 | }; |
| 852 | 843 | ||
| 853 | #ifdef HAVE_X_I18N | 844 | #ifdef HAVE_X_I18N |