commit f3f20a37fb3b7e02fc52b3787968e2a332f52119 (HEAD, refs/remotes/origin/master) Author: Po Lu Date: Sat Apr 9 13:30:32 2022 +0800 Handle hierarchy events for updating scroll valuators correctly * src/keyboard.c (gen_help_event, kbd_buffer_store_help_event): Make sure to initialize the event buffer correctly. * src/xterm.c (xi_populate_device_from_info): New function. (x_init_master_valuators): Factor out most of the valuator tracking code to that function. (handle_one_xevent): Handle device enable and disable events in a more detailed fashion. diff --git a/src/keyboard.c b/src/keyboard.c index 98eebaf7f5..e569f8f34c 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -3766,6 +3766,7 @@ gen_help_event (Lisp_Object help, Lisp_Object frame, Lisp_Object window, Lisp_Object object, ptrdiff_t pos) { struct input_event event; + EVENT_INIT (event); event.kind = HELP_EVENT; event.frame_or_window = frame; @@ -3783,6 +3784,7 @@ void kbd_buffer_store_help_event (Lisp_Object frame, Lisp_Object help) { struct input_event event; + EVENT_INIT (event); event.kind = HELP_EVENT; event.frame_or_window = frame; diff --git a/src/xterm.c b/src/xterm.c index 509403fbf2..f6138d5214 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -3842,6 +3842,77 @@ x_free_xi_devices (struct x_display_info *dpyinfo) unblock_input (); } +static void +xi_populate_device_from_info (struct xi_device_t *xi_device, + XIDeviceInfo *device) +{ +#ifdef HAVE_XINPUT2_1 + struct xi_scroll_valuator_t *valuator; + int actual_valuator_count; + XIScrollClassInfo *info; +#endif +#ifdef HAVE_XINPUT2_2 + XITouchClassInfo *touch_info; +#endif + int c; + + xi_device->device_id = device->deviceid; + xi_device->grab = 0; + +#ifdef HAVE_XINPUT2_1 + actual_valuator_count = 0; + xi_device->valuators = + xmalloc (sizeof *xi_device->valuators * device->num_classes); +#endif +#ifdef HAVE_XINPUT2_2 + xi_device->touchpoints = NULL; +#endif + + xi_device->master_p = (device->use == XIMasterKeyboard + || device->use == XIMasterPointer); +#ifdef HAVE_XINPUT2_2 + xi_device->direct_p = false; +#endif + xi_device->name = build_string (device->name); + + for (c = 0; c < device->num_classes; ++c) + { + switch (device->classes[c]->type) + { +#ifdef HAVE_XINPUT2_1 + case XIScrollClass: + { + info = (XIScrollClassInfo *) device->classes[c]; + + valuator = &xi_device->valuators[actual_valuator_count++]; + valuator->horizontal + = (info->scroll_type == XIScrollTypeHorizontal); + valuator->invalid_p = true; + valuator->emacs_value = DBL_MIN; + valuator->increment = info->increment; + valuator->number = info->number; + valuator->pending_enter_reset = false; + + break; + } +#endif +#ifdef HAVE_XINPUT2_2 + case XITouchClass: + { + touch_info = (XITouchClassInfo *) device->classes[c]; + xi_device->direct_p = touch_info->mode == XIDirectTouch; + } +#endif + default: + break; + } + } + +#ifdef HAVE_XINPUT2_1 + xi_device->scroll_valuator_count = actual_valuator_count; +#endif +} + /* The code below handles the tracking of scroll valuators on XInput 2, in order to support scroll wheels that report information more granular than a screen line. @@ -3876,9 +3947,10 @@ x_free_xi_devices (struct x_display_info *dpyinfo) static void x_init_master_valuators (struct x_display_info *dpyinfo) { - int ndevices; + int ndevices, actual_devices; XIDeviceInfo *infos; + actual_devices = 0; block_input (); x_free_xi_devices (dpyinfo); infos = XIQueryDevice (dpyinfo->display, @@ -3892,79 +3964,13 @@ x_init_master_valuators (struct x_display_info *dpyinfo) return; } - int actual_devices = 0; dpyinfo->devices = xmalloc (sizeof *dpyinfo->devices * ndevices); for (int i = 0; i < ndevices; ++i) { - XIDeviceInfo *device = &infos[i]; - - if (device->enabled) - { -#ifdef HAVE_XINPUT2_1 - int actual_valuator_count = 0; -#endif - - struct xi_device_t *xi_device = &dpyinfo->devices[actual_devices++]; - xi_device->device_id = device->deviceid; - xi_device->grab = 0; - -#ifdef HAVE_XINPUT2_1 - xi_device->valuators = - xmalloc (sizeof *xi_device->valuators * device->num_classes); -#endif -#ifdef HAVE_XINPUT2_2 - xi_device->touchpoints = NULL; -#endif - - xi_device->master_p = (device->use == XIMasterKeyboard - || device->use == XIMasterPointer); -#ifdef HAVE_XINPUT2_2 - xi_device->direct_p = false; -#endif - xi_device->name = build_string (device->name); - - for (int c = 0; c < device->num_classes; ++c) - { - switch (device->classes[c]->type) - { -#ifdef HAVE_XINPUT2_1 - case XIScrollClass: - { - XIScrollClassInfo *info = - (XIScrollClassInfo *) device->classes[c]; - struct xi_scroll_valuator_t *valuator; - - valuator = &xi_device->valuators[actual_valuator_count++]; - valuator->horizontal - = (info->scroll_type == XIScrollTypeHorizontal); - valuator->invalid_p = true; - valuator->emacs_value = DBL_MIN; - valuator->increment = info->increment; - valuator->number = info->number; - valuator->pending_enter_reset = false; - - break; - } -#endif -#ifdef HAVE_XINPUT2_2 - case XITouchClass: - { - XITouchClassInfo *info; - - info = (XITouchClassInfo *) device->classes[c]; - xi_device->direct_p = info->mode == XIDirectTouch; - } -#endif - default: - break; - } - } - -#ifdef HAVE_XINPUT2_1 - xi_device->scroll_valuator_count = actual_valuator_count; -#endif - } + if (infos[i].enabled) + xi_populate_device_from_info (&dpyinfo->devices[actual_devices++], + &infos[i]); } dpyinfo->num_devices = actual_devices; @@ -17692,8 +17698,83 @@ handle_one_xevent (struct x_display_info *dpyinfo, goto XI_OTHER; case XI_HierarchyChanged: - x_init_master_valuators (dpyinfo); - goto XI_OTHER; + { + XIHierarchyEvent *hev = (XIHierarchyEvent *) xi_event; + XIDeviceInfo *info; + int i, j, ndevices, n_disabled, *disabled; + struct xi_device_t *device, *devices; +#ifdef HAVE_XINPUT2_2 + struct xi_touch_point_t *tem, *last; +#endif + + disabled = alloca (sizeof *disabled * hev->num_info); + n_disabled = 0; + + for (i = 0; i < hev->num_info; ++i) + { + if (hev->info[i].flags & XIDeviceEnabled) + { + x_catch_errors (dpyinfo->display); + info = XIQueryDevice (dpyinfo->display, hev->info[i].deviceid, + &ndevices); + x_uncatch_errors (); + + if (info && info->enabled) + { + dpyinfo->devices + = xrealloc (dpyinfo->devices, (sizeof *dpyinfo->devices + * ++dpyinfo->num_devices)); + device = &dpyinfo->devices[dpyinfo->num_devices - 1]; + xi_populate_device_from_info (device, info); + } + + if (info) + XIFreeDeviceInfo (info); + } + else if (hev->info[i].flags & XIDeviceDisabled) + disabled[n_disabled++] = hev->info[i].deviceid; + } + + if (n_disabled) + { + ndevices = 0; + devices = xmalloc (sizeof *devices * dpyinfo->num_devices); + + for (i = 0; i < dpyinfo->num_devices; ++i) + { + for (j = 0; j < n_disabled; ++j) + { + if (disabled[j] == dpyinfo->devices[i].device_id) + { +#ifdef HAVE_XINPUT2_1 + xfree (dpyinfo->devices[i].valuators); +#endif +#ifdef HAVE_XINPUT2_2 + tem = dpyinfo->devices[i].touchpoints; + while (tem) + { + last = tem; + tem = tem->next; + xfree (last); + } +#endif + goto continue_detachment; + } + } + + devices[ndevices++] = dpyinfo->devices[i]; + + continue_detachment: + continue; + } + + xfree (dpyinfo->devices); + dpyinfo->devices = devices; + dpyinfo->num_devices = ndevices; + } + + goto XI_OTHER; + } case XI_DeviceChanged: { commit 378b4ccd4bb0d68afc498a0fc9a600bd1337cabb Author: Po Lu Date: Sat Apr 9 11:43:23 2022 +0800 Fix DND leave events not being sent to toplevel after returning frame * src/xterm.c (x_dnd_update_state, handle_one_xevent): Make sure to send leave events to the previous toplevel when cancelling to return a frame. diff --git a/src/xterm.c b/src/xterm.c index d94a3cf91a..509403fbf2 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -13303,6 +13303,29 @@ x_dnd_update_state (struct x_display_info *dpyinfo, Time timestamp) if (x_dnd_return_frame == 2 && x_any_window_to_frame (dpyinfo, toplevel)) { + if (x_dnd_last_seen_window != None + && x_dnd_last_protocol_version != -1 + && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame)) + x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window); + else if (x_dnd_last_seen_window != None + && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) + && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame)) + { + if (!x_dnd_motif_setup_p) + xm_setup_drag_info (dpyinfo, x_dnd_frame); + + lmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR, + XM_DRAG_REASON_TOP_LEVEL_LEAVE); + lmsg.byteorder = XM_TARGETS_TABLE_CUR; + lmsg.zero = 0; + lmsg.timestamp = timestamp; + lmsg.source_window = FRAME_X_WINDOW (x_dnd_frame); + + if (x_dnd_motif_setup_p) + xm_send_top_level_leave_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame), + x_dnd_last_seen_window, &lmsg); + } + x_dnd_end_window = x_dnd_last_seen_window; x_dnd_last_seen_window = None; x_dnd_last_seen_toplevel = None; @@ -14949,6 +14972,29 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (x_dnd_return_frame == 2 && x_any_window_to_frame (dpyinfo, toplevel)) { + if (x_dnd_last_seen_window != None + && x_dnd_last_protocol_version != -1 + && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame)) + x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window); + else if (x_dnd_last_seen_window != None + && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) + && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame)) + { + if (!x_dnd_motif_setup_p) + xm_setup_drag_info (dpyinfo, x_dnd_frame); + + lmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR, + XM_DRAG_REASON_TOP_LEVEL_LEAVE); + lmsg.byteorder = XM_TARGETS_TABLE_CUR; + lmsg.zero = 0; + lmsg.timestamp = event->xmotion.time; + lmsg.source_window = FRAME_X_WINDOW (x_dnd_frame); + + if (x_dnd_motif_setup_p) + xm_send_top_level_leave_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame), + x_dnd_last_seen_window, &lmsg); + } + x_dnd_end_window = x_dnd_last_seen_window; x_dnd_last_seen_window = None; x_dnd_last_seen_toplevel = None; @@ -16451,6 +16497,29 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (x_dnd_return_frame == 2 && x_any_window_to_frame (dpyinfo, toplevel)) { + if (x_dnd_last_seen_window != None + && x_dnd_last_protocol_version != -1 + && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame)) + x_dnd_send_leave (x_dnd_frame, x_dnd_last_seen_window); + else if (x_dnd_last_seen_window != None + && XM_DRAG_STYLE_IS_DYNAMIC (x_dnd_last_motif_style) + && x_dnd_last_seen_window != FRAME_OUTER_WINDOW (x_dnd_frame)) + { + if (!x_dnd_motif_setup_p) + xm_setup_drag_info (dpyinfo, x_dnd_frame); + + lmsg.reason = XM_DRAG_REASON (XM_DRAG_ORIGINATOR_INITIATOR, + XM_DRAG_REASON_TOP_LEVEL_LEAVE); + lmsg.byteorder = XM_TARGETS_TABLE_CUR; + lmsg.zero = 0; + lmsg.timestamp = event->xmotion.time; + lmsg.source_window = FRAME_X_WINDOW (x_dnd_frame); + + if (x_dnd_motif_setup_p) + xm_send_top_level_leave_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame), + x_dnd_last_seen_window, &lmsg); + } + x_dnd_end_window = x_dnd_last_seen_window; x_dnd_last_seen_window = None; x_dnd_last_seen_toplevel = None; commit 72782ca182993dac6bd805bb3b54b21b7e7efa7d Author: Po Lu Date: Sat Apr 9 11:37:56 2022 +0800 Use right frame when computing mouse movement device * src/keyboard.c (kbd_buffer_get_event): Use the frame on which the mouse actually moved to compute the last mouse device. diff --git a/src/keyboard.c b/src/keyboard.c index 642ae7d7e0..98eebaf7f5 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -4275,12 +4275,13 @@ kbd_buffer_get_event (KBOARD **kbp, /* Try generating a mouse motion event. */ else if (some_mouse_moved ()) { - struct frame *f = some_mouse_moved (); + struct frame *f, *movement_frame = some_mouse_moved (); Lisp_Object bar_window; enum scroll_bar_part part; Lisp_Object x, y; Time t; + f = movement_frame; *kbp = current_kboard; /* Note that this uses F to determine which terminal to look at. If there is no valid info, it does not store anything @@ -4317,8 +4318,8 @@ kbd_buffer_get_event (KBOARD **kbp, obj = make_lispy_movement (f, bar_window, part, x, y, t); if (!NILP (obj)) - Vlast_event_device = (f && STRINGP (f->last_mouse_device) - ? f->last_mouse_device + Vlast_event_device = (STRINGP (movement_frame->last_mouse_device) + ? movement_frame->last_mouse_device : virtual_core_pointer_name); } else commit cb45fff0cb01d7a2e428676e0406bcc7ebc1e63a Author: Po Lu Date: Sat Apr 9 11:35:08 2022 +0800 Minor cleanups in X Windows drag-and-drop code * src/keyboard.c (kbd_buffer_get_event): Don't dereference f if nil when generating mouse motion event. * src/xterm.c (x_dnd_send_enter, x_dnd_send_position) (x_dnd_send_leave, x_dnd_send_drop, x_send_scroll_bar_event): Use NoEventMask instead of 0. diff --git a/src/keyboard.c b/src/keyboard.c index 588ee75ee0..642ae7d7e0 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -4317,7 +4317,7 @@ kbd_buffer_get_event (KBOARD **kbp, obj = make_lispy_movement (f, bar_window, part, x, y, t); if (!NILP (obj)) - Vlast_event_device = (STRINGP (f->last_mouse_device) + Vlast_event_device = (f && STRINGP (f->last_mouse_device) ? f->last_mouse_device : virtual_core_pointer_name); } diff --git a/src/xterm.c b/src/xterm.c index 329376cab2..d94a3cf91a 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -3331,7 +3331,7 @@ x_dnd_send_enter (struct frame *f, Window target, int supported) x_dnd_n_targets); x_catch_errors (dpyinfo->display); - XSendEvent (FRAME_X_DISPLAY (f), target, False, 0, &msg); + XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); x_uncatch_errors (); } @@ -3390,7 +3390,7 @@ x_dnd_send_position (struct frame *f, Window target, int supported, msg.xclient.data.l[4] = action; x_catch_errors (dpyinfo->display); - XSendEvent (FRAME_X_DISPLAY (f), target, False, 0, &msg); + XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); x_uncatch_errors (); } @@ -3414,7 +3414,7 @@ x_dnd_send_leave (struct frame *f, Window target) msg.xclient.data.l[4] = 0; x_catch_errors (dpyinfo->display); - XSendEvent (FRAME_X_DISPLAY (f), target, False, 0, &msg); + XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); x_uncatch_errors (); } @@ -3504,7 +3504,7 @@ x_dnd_send_drop (struct frame *f, Window target, Time timestamp, msg.xclient.data.l[2] = timestamp; x_catch_errors (dpyinfo->display); - XSendEvent (FRAME_X_DISPLAY (f), target, False, 0, &msg); + XSendEvent (FRAME_X_DISPLAY (f), target, False, NoEventMask, &msg); x_uncatch_errors (); return true; } @@ -10735,7 +10735,8 @@ x_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part, /* Setting the event mask to zero means that the message will be sent to the client that created the window, and if that window no longer exists, no event will be sent. */ - XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, 0, &event); + XSendEvent (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), False, + NoEventMask, &event); unblock_input (); } commit f1bf1a069853315c0fa116ef4716ba38c9a67417 Author: Po Lu Date: Sat Apr 9 09:12:24 2022 +0800 Fix source reporting for focus in and focus out events * src/xterm.c (handle_one_xevent): Report source name for FocusIn and FocusOut events. diff --git a/src/xterm.c b/src/xterm.c index 038dbcfe87..329376cab2 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -15866,8 +15866,10 @@ handle_one_xevent (struct x_display_info *dpyinfo, case XI_FocusIn: { XIFocusInEvent *focusin = (XIFocusInEvent *) xi_event; + struct xi_device_t *source; any = x_any_window_to_frame (dpyinfo, focusin->event); + source = xi_device_from_id (dpyinfo, focusin->sourceid); #ifdef USE_GTK /* Some WMs (e.g. Mutter in Gnome Shell), don't unmap minimized/iconified windows; thus, for those WMs we won't get @@ -15895,16 +15897,25 @@ handle_one_xevent (struct x_display_info *dpyinfo, XSETFRAME (inev.ie.frame_or_window, f); } } + x_detect_focus_change (dpyinfo, any, event, &inev.ie); + + if (inev.ie.kind != NO_EVENT && source) + inev.ie.device = source->name; goto XI_OTHER; } case XI_FocusOut: { XIFocusOutEvent *focusout = (XIFocusOutEvent *) xi_event; + struct xi_device_t *source; any = x_any_window_to_frame (dpyinfo, focusout->event); + source = xi_device_from_id (dpyinfo, focusout->sourceid); x_detect_focus_change (dpyinfo, any, event, &inev.ie); + + if (inev.ie.kind != NO_EVENT && source) + inev.ie.device = source->name; goto XI_OTHER; } commit 33d68da534ef4d6f7c4a6db3eaada8508c29f961 Author: Po Lu Date: Sat Apr 9 09:02:24 2022 +0800 Clean up XI2 scroll valuator tracking code * src/xterm.c (x_get_scroll_valuator_delta): Accept a pointer to a device instead of the device id. (handle_one_xevent): Pass the previously found device. diff --git a/src/xterm.c b/src/xterm.c index da67173186..038dbcfe87 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -3974,58 +3974,49 @@ x_init_master_valuators (struct x_display_info *dpyinfo) #ifdef HAVE_XINPUT2_1 /* Return the delta of the scroll valuator VALUATOR_NUMBER under - DEVICE_ID in the display DPYINFO with VALUE. The valuator's - valuator will be set to VALUE afterwards. In case no scroll - valuator is found, or if the valuator state is invalid (see the - comment under XI_Enter in handle_one_xevent), or if device_id is - not known to Emacs, DBL_MAX is returned. Otherwise, the valuator - is returned in VALUATOR_RETURN. */ + DEVICE in the display DPYINFO with VALUE. The valuator's valuator + will be set to VALUE afterwards. In case no scroll valuator is + found, or if the valuator state is invalid (see the comment under + XI_Enter in handle_one_xevent). Otherwise, the valuator is + returned in VALUATOR_RETURN. */ static double -x_get_scroll_valuator_delta (struct x_display_info *dpyinfo, int device_id, +x_get_scroll_valuator_delta (struct x_display_info *dpyinfo, + struct xi_device_t *device, int valuator_number, double value, struct xi_scroll_valuator_t **valuator_return) { - block_input (); + struct xi_scroll_valuator_t *sv; + double delta; + int i; - for (int i = 0; i < dpyinfo->num_devices; ++i) + for (i = 0; i < device->scroll_valuator_count; ++i) { - struct xi_device_t *device = &dpyinfo->devices[i]; + sv = &device->valuators[i]; - if (device->device_id == device_id) + if (sv->number == valuator_number) { - for (int j = 0; j < device->scroll_valuator_count; ++j) - { - struct xi_scroll_valuator_t *sv = &device->valuators[j]; + *valuator_return = sv; - if (sv->number == valuator_number) - { - if (sv->invalid_p) - { - sv->current_value = value; - sv->invalid_p = false; - *valuator_return = sv; + if (sv->increment == 0) + return DBL_MAX; - unblock_input (); - return DBL_MAX; - } - else - { - double delta = (sv->current_value - value) / sv->increment; - sv->current_value = value; - *valuator_return = sv; + if (sv->invalid_p) + { + sv->current_value = value; + sv->invalid_p = false; - unblock_input (); - return delta; - } - } + return DBL_MAX; } + else + { + delta = (sv->current_value - value) / sv->increment; + sv->current_value = value; - unblock_input (); - return DBL_MAX; + return delta; + } } } - unblock_input (); return DBL_MAX; } @@ -16186,7 +16177,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, /* See the comment on top of x_init_master_valuators for more details on how scroll wheel movement is reported on XInput 2. */ - delta = x_get_scroll_valuator_delta (dpyinfo, xev->deviceid, + delta = x_get_scroll_valuator_delta (dpyinfo, device, i, *values, &val); values++; commit 6449179822543b794ed3b1d0b06087c1fe33ee15 Author: Po Lu Date: Sat Apr 9 08:48:45 2022 +0800 * src/pgtkterm.c (pgtk_set_cr_source_with_color): Fix default operator. diff --git a/src/pgtkterm.c b/src/pgtkterm.c index fb62f5978d..8b60064c42 100644 --- a/src/pgtkterm.c +++ b/src/pgtkterm.c @@ -7206,8 +7206,11 @@ pgtk_set_cr_source_with_color (struct frame *f, unsigned long color, pgtk_query_color (f, &col); if (!respects_alpha_background) - cairo_set_source_rgb (FRAME_CR_CONTEXT (f), col.red / 65535.0, - col.green / 65535.0, col.blue / 65535.0); + { + cairo_set_source_rgb (FRAME_CR_CONTEXT (f), col.red / 65535.0, + col.green / 65535.0, col.blue / 65535.0); + cairo_set_operator (FRAME_CR_CONTEXT (f), CAIRO_OPERATOR_OVER); + } else { cairo_set_source_rgba (FRAME_CR_CONTEXT (f), col.red / 65535.0, commit bb7623b9bee14bf428accc5b8cc88fa34fd9c9a2 Author: Po Lu Date: Sat Apr 9 08:41:00 2022 +0800 Fix subpixel AA with alpha-background on Cairo on X * xterm.c (x_set_cr_source_with_gc_foreground) (x_set_cr_source_with_gc_background): Set operator back to OVER if alpha-background isn't to be respected. diff --git a/src/xterm.c b/src/xterm.c index dc06df246c..da67173186 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -4240,8 +4240,11 @@ x_set_cr_source_with_gc_foreground (struct frame *f, GC gc, cairo_set_operator (FRAME_CR_CONTEXT (f), CAIRO_OPERATOR_SOURCE); } else - cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0, - color.green / 65535.0, color.blue / 65535.0); + { + cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0, + color.green / 65535.0, color.blue / 65535.0); + cairo_set_operator (FRAME_CR_CONTEXT (f), CAIRO_OPERATOR_OVER); + } } void @@ -4269,8 +4272,11 @@ x_set_cr_source_with_gc_background (struct frame *f, GC gc, cairo_set_operator (FRAME_CR_CONTEXT (f), CAIRO_OPERATOR_SOURCE); } else - cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0, - color.green / 65535.0, color.blue / 65535.0); + { + cairo_set_source_rgb (FRAME_CR_CONTEXT (f), color.red / 65535.0, + color.green / 65535.0, color.blue / 65535.0); + cairo_set_operator (FRAME_CR_CONTEXT (f), CAIRO_OPERATOR_OVER); + } } static const cairo_user_data_key_t xlib_surface_key, saved_drawable_key; commit 0b16e4e1f1b9e6de16aa613b1b363d76b1023766 Author: Paul Eggert Date: Fri Apr 8 17:02:21 2022 -0700 Update from Gnulib by running admin/merge-gnulib diff --git a/lib/fcntl.in.h b/lib/fcntl.in.h index 3e0c302af3..9270ced897 100644 --- a/lib/fcntl.in.h +++ b/lib/fcntl.in.h @@ -435,6 +435,10 @@ _GL_WARN_ON_USE (openat, "openat is not portable - " # define AT_EACCESS 4 #endif +/* Ignore this flag if not supported. */ +#ifndef AT_NO_AUTOMOUNT +# define AT_NO_AUTOMOUNT 0 +#endif #endif /* _@GUARD_PREFIX@_FCNTL_H */ #endif /* _@GUARD_PREFIX@_FCNTL_H */ diff --git a/lib/gnulib.mk.in b/lib/gnulib.mk.in index 3deeca98be..bbb05fdba5 100644 --- a/lib/gnulib.mk.in +++ b/lib/gnulib.mk.in @@ -931,6 +931,7 @@ LIB_EXECINFO = @LIB_EXECINFO@ LIB_GETRANDOM = @LIB_GETRANDOM@ LIB_HAS_ACL = @LIB_HAS_ACL@ LIB_MATH = @LIB_MATH@ +LIB_NANOSLEEP = @LIB_NANOSLEEP@ LIB_PTHREAD = @LIB_PTHREAD@ LIB_PTHREAD_SIGMASK = @LIB_PTHREAD_SIGMASK@ LIB_TIMER_TIME = @LIB_TIMER_TIME@ @@ -1238,6 +1239,8 @@ WINDRES = @WINDRES@ WINT_T_SUFFIX = @WINT_T_SUFFIX@ XARGS_LIMIT = @XARGS_LIMIT@ XCB_LIBS = @XCB_LIBS@ +XCOMPOSITE_CFLAGS = @XCOMPOSITE_CFLAGS@ +XCOMPOSITE_LIBS = @XCOMPOSITE_LIBS@ XCRUN = @XCRUN@ XDBE_CFLAGS = @XDBE_CFLAGS@ XDBE_LIBS = @XDBE_LIBS@ @@ -1256,6 +1259,8 @@ XOBJ = @XOBJ@ XRANDR_CFLAGS = @XRANDR_CFLAGS@ XRANDR_LIBS = @XRANDR_LIBS@ XRENDER_LIBS = @XRENDER_LIBS@ +XSHAPE_CFLAGS = @XSHAPE_CFLAGS@ +XSHAPE_LIBS = @XSHAPE_LIBS@ XSYNC_CFLAGS = @XSYNC_CFLAGS@ XSYNC_LIBS = @XSYNC_LIBS@ XWIDGETS_OBJ = @XWIDGETS_OBJ@ diff --git a/lib/mini-gmp-gnulib.c b/lib/mini-gmp-gnulib.c index a18ee8f6ab..7d09c80e9e 100644 --- a/lib/mini-gmp-gnulib.c +++ b/lib/mini-gmp-gnulib.c @@ -40,7 +40,8 @@ #endif /* Pacify GCC -Wunused-variable for variables used only in 'assert' calls. */ -#if defined NDEBUG && 4 < __GNUC__ + (6 <= __GNUC_MINOR__) +#if (defined NDEBUG \ + && (4 < __GNUC__ + (6 <= __GNUC_MINOR__) || defined __clang__)) # pragma GCC diagnostic ignored "-Wunused-variable" #endif diff --git a/lib/mini-gmp.c b/lib/mini-gmp.c index e7a320a642..2b1ddee079 100644 --- a/lib/mini-gmp.c +++ b/lib/mini-gmp.c @@ -10,7 +10,7 @@ The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of either: * the GNU Lesser General Public License as published by the Free - Software Foundation, either version 3 of the License, or (at your + Software Foundation; either version 3 of the License, or (at your option) any later version. or @@ -1937,9 +1937,8 @@ mpz_neg (mpz_t r, const mpz_t u) void mpz_swap (mpz_t u, mpz_t v) { - MP_SIZE_T_SWAP (u->_mp_size, v->_mp_size); MP_SIZE_T_SWAP (u->_mp_alloc, v->_mp_alloc); - MP_PTR_SWAP (u->_mp_d, v->_mp_d); + MPN_PTR_SWAP (u->_mp_d, u->_mp_size, v->_mp_d, v->_mp_size); } diff --git a/lib/openat.h b/lib/openat.h index 5c8ff90b80..56919ef8dc 100644 --- a/lib/openat.h +++ b/lib/openat.h @@ -98,12 +98,14 @@ lchmodat (int fd, char const *file, mode_t mode) # define STATAT_INLINE _GL_INLINE # endif +_GL_ATTRIBUTE_DEPRECATED STATAT_INLINE int statat (int fd, char const *name, struct stat *st) { return fstatat (fd, name, st, 0); } +_GL_ATTRIBUTE_DEPRECATED STATAT_INLINE int lstatat (int fd, char const *name, struct stat *st) { diff --git a/lib/regex_internal.c b/lib/regex_internal.c index 3945ee7ecb..0e6919f340 100644 --- a/lib/regex_internal.c +++ b/lib/regex_internal.c @@ -1396,24 +1396,22 @@ re_dfa_add_node (re_dfa_t *dfa, re_token_t token) if (__glibc_unlikely (new_nodes == NULL)) return -1; dfa->nodes = new_nodes; + dfa->nodes_alloc = new_nodes_alloc; new_nexts = re_realloc (dfa->nexts, Idx, new_nodes_alloc); + if (new_nexts != NULL) + dfa->nexts = new_nexts; new_indices = re_realloc (dfa->org_indices, Idx, new_nodes_alloc); + if (new_indices != NULL) + dfa->org_indices = new_indices; new_edests = re_realloc (dfa->edests, re_node_set, new_nodes_alloc); + if (new_edests != NULL) + dfa->edests = new_edests; new_eclosures = re_realloc (dfa->eclosures, re_node_set, new_nodes_alloc); + if (new_eclosures != NULL) + dfa->eclosures = new_eclosures; if (__glibc_unlikely (new_nexts == NULL || new_indices == NULL || new_edests == NULL || new_eclosures == NULL)) - { - re_free (new_nexts); - re_free (new_indices); - re_free (new_edests); - re_free (new_eclosures); - return -1; - } - dfa->nexts = new_nexts; - dfa->org_indices = new_indices; - dfa->edests = new_edests; - dfa->eclosures = new_eclosures; - dfa->nodes_alloc = new_nodes_alloc; + return -1; } dfa->nodes[dfa->nodes_len] = token; dfa->nodes[dfa->nodes_len].constraint = 0; diff --git a/lib/regexec.c b/lib/regexec.c index aea1e7da52..521cb02841 100644 --- a/lib/regexec.c +++ b/lib/regexec.c @@ -1308,8 +1308,8 @@ push_fail_stack (struct re_fail_stack_t *fs, Idx str_idx, Idx dest_node, re_node_set *eps_via_nodes) { reg_errcode_t err; - Idx num = fs->num++; - if (fs->num == fs->alloc) + Idx num = fs->num; + if (num == fs->alloc) { struct re_fail_stack_ent_t *new_array; new_array = re_realloc (fs->stack, struct re_fail_stack_ent_t, @@ -1324,6 +1324,7 @@ push_fail_stack (struct re_fail_stack_t *fs, Idx str_idx, Idx dest_node, fs->stack[num].regs = re_malloc (regmatch_t, 2 * nregs); if (fs->stack[num].regs == NULL) return REG_ESPACE; + fs->num = num + 1; memcpy (fs->stack[num].regs, regs, sizeof (regmatch_t) * nregs); memcpy (fs->stack[num].regs + nregs, prevregs, sizeof (regmatch_t) * nregs); err = re_node_set_init_copy (&fs->stack[num].eps_via_nodes, eps_via_nodes); commit 68bc1446855c86b96d5bc22f819e63358ab250ac Author: Paul Eggert Date: Fri Apr 8 17:00:20 2022 -0700 Pacify clang -Wunused-variable * src/coding.c (detect_coding_utf_8): * src/process.c (Finternal_default_process_filter): Remove unused local vars. diff --git a/src/coding.c b/src/coding.c index c16598d275..2bed293d57 100644 --- a/src/coding.c +++ b/src/coding.c @@ -1131,7 +1131,6 @@ detect_coding_utf_8 (struct coding_system *coding, ptrdiff_t consumed_chars = 0; bool bom_found = 0; ptrdiff_t nchars = coding->head_ascii; - int eol_seen = coding->eol_seen; detect_info->checked |= CATEGORY_MASK_UTF_8; /* A coding system of this category is always ASCII compatible. */ @@ -1161,15 +1160,10 @@ detect_coding_utf_8 (struct coding_system *coding, { if (src < src_end && *src == '\n') { - eol_seen |= EOL_SEEN_CRLF; src++; nchars++; } - else - eol_seen |= EOL_SEEN_CR; } - else if (c == '\n') - eol_seen |= EOL_SEEN_LF; continue; } ONE_MORE_BYTE (c1); diff --git a/src/process.c b/src/process.c index d4a78521ab..08a02ad942 100644 --- a/src/process.c +++ b/src/process.c @@ -6239,7 +6239,6 @@ Otherwise it discards the output. */) { Lisp_Object old_read_only; ptrdiff_t old_begv, old_zv; - ptrdiff_t old_begv_byte, old_zv_byte; ptrdiff_t before, before_byte; ptrdiff_t opoint_byte; struct buffer *b; @@ -6250,8 +6249,6 @@ Otherwise it discards the output. */) old_read_only = BVAR (current_buffer, read_only); old_begv = BEGV; old_zv = ZV; - old_begv_byte = BEGV_BYTE; - old_zv_byte = ZV_BYTE; bset_read_only (current_buffer, Qnil); @@ -6299,15 +6296,9 @@ Otherwise it discards the output. */) opoint_byte += PT_BYTE - before_byte; } if (old_begv > before) - { - old_begv += PT - before; - old_begv_byte += PT_BYTE - before_byte; - } + old_begv += PT - before; if (old_zv >= before) - { - old_zv += PT - before; - old_zv_byte += PT_BYTE - before_byte; - } + old_zv += PT - before; /* If the restriction isn't what it should be, set it. */ if (old_begv != BEGV || old_zv != ZV) commit d9bffa1f3b121085fd8f954eb9446a4a5241c062 Author: Paul Eggert Date: Fri Apr 8 16:41:26 2022 -0700 ebrowse dumping need not return int * lib-src/ebrowse.c (dump_members, dump_tree): Return void, not int, since callers never actually use returned value. All uses changed. diff --git a/lib-src/ebrowse.c b/lib-src/ebrowse.c index b77572734f..641570da02 100644 --- a/lib-src/ebrowse.c +++ b/lib-src/ebrowse.c @@ -1209,17 +1209,14 @@ sym_scope (struct sym *p) } -/* Dump the list of members M to file FP. Value is the length of the - list. */ +/* Dump the list of members M to file FP. */ -static int +static void dump_members (FILE *fp, struct member *m) { - int n; - putc ('(', fp); - for (n = 0; m; m = m->next, ++n) + for (; m; m = m->next) { fputs (MEMBER_STRUCT, fp); putstr (m->name, fp); @@ -1239,7 +1236,6 @@ dump_members (FILE *fp, struct member *m) putc (')', fp); putc ('\n', fp); - return n; } @@ -1268,15 +1264,11 @@ dump_sym (FILE *fp, struct sym *root) } -/* Dump class ROOT and its subclasses to file FP. Value is the - number of classes written. */ +/* Dump class ROOT and its subclasses to file FP. */ -static int +static void dump_tree (FILE *fp, struct sym *root) { - struct link *lk; - unsigned n = 0; - dump_sym (fp, root); if (f_verbose) @@ -1287,20 +1279,20 @@ dump_tree (FILE *fp, struct sym *root) putc ('(', fp); - for (lk = root->subs; lk; lk = lk->next) + for (struct link *lk = root->subs; lk; lk = lk->next) { fputs (TREE_STRUCT, fp); - n += dump_tree (fp, lk->sym); + dump_tree (fp, lk->sym); putc (']', fp); } putc (')', fp); dump_members (fp, root->vars); - n += dump_members (fp, root->fns); + dump_members (fp, root->fns); dump_members (fp, root->static_vars); - n += dump_members (fp, root->static_fns); - n += dump_members (fp, root->friends); + dump_members (fp, root->static_fns); + dump_members (fp, root->friends); dump_members (fp, root->types); /* Superclasses. */ @@ -1312,7 +1304,6 @@ dump_tree (FILE *fp, struct sym *root) putc (')', fp); putc ('\n', fp); - return n; } @@ -1321,9 +1312,6 @@ dump_tree (FILE *fp, struct sym *root) static void dump_roots (FILE *fp) { - int i, n = 0; - struct sym *r; - /* Output file header containing version string, command line options etc. */ if (!f_append) @@ -1347,12 +1335,12 @@ dump_roots (FILE *fp) mark_inherited_virtual (); /* Dump the roots of the graph. */ - for (i = 0; i < TABLE_SIZE; ++i) - for (r = class_table[i]; r; r = r->next) + for (int i = 0; i < TABLE_SIZE; ++i) + for (struct sym *r = class_table[i]; r; r = r->next) if (!r->supers) { fputs (TREE_STRUCT, fp); - n += dump_tree (fp, r); + dump_tree (fp, r); putc (']', fp); } commit 9d20b47ad34ff8b409e83198406883f70782c295 Author: Alan Third Date: Wed Mar 30 22:40:03 2022 +0100 Fix scrollbars on macOS 10.13 and below (bug#54623) Make any build on macOS 10.13 and below follow the same drawing path as the GNUstep port. macOS 10.14 and above will use EmacsLayer. * src/nsterm.h (EmacsLayer): * src/nsterm.m ([EmacsView makeBackingLayer]): ([EmacsView unlockFocus]): ([EmacsView windowDidChangeBackingProperties:]): ([EmacsView copyRect:to:]): Remove any code required for macOS 10.13 and below, and fix the #if's to enforce strict separation of the drawing paths. (ns_update_end): (ns_unfocus): Fix #ifs so that flushWindow is called on old macOS versions as well as GNUstep. diff --git a/src/nsterm.h b/src/nsterm.h index f027646123..4cba5c0be8 100644 --- a/src/nsterm.h +++ b/src/nsterm.h @@ -487,7 +487,7 @@ typedef id instancetype; #endif - (int)fullscreenState; -#ifdef NS_IMPL_COCOA +#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 - (void)lockFocus; - (void)unlockFocus; #endif @@ -698,7 +698,7 @@ typedef id instancetype; + (CGFloat)scrollerWidth; @end -#ifdef NS_IMPL_COCOA +#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 @interface EmacsLayer : CALayer { NSMutableArray *cache; diff --git a/src/nsterm.m b/src/nsterm.m index 36e2ff55ac..550f29212e 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -1060,7 +1060,7 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen) block_input (); [view unlockFocus]; -#if defined (NS_IMPL_GNUSTEP) +#if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400 [[view window] flushWindow]; #endif @@ -1127,7 +1127,7 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen) { EmacsView *view = FRAME_NS_VIEW (f); [view unlockFocus]; -#if defined (NS_IMPL_GNUSTEP) +#if defined (NS_IMPL_GNUSTEP) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400 [[view window] flushWindow]; #endif } @@ -7208,7 +7208,7 @@ - (instancetype) initFrameFromEmacs: (struct frame *)f [[EmacsWindow alloc] initWithEmacsFrame:f]; -#ifdef NS_IMPL_COCOA +#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 /* These settings mean AppKit will retain the contents of the frame on resize. Unfortunately it also means the frame will not be automatically marked for display, but we can do that ourselves in @@ -7872,7 +7872,7 @@ - (instancetype)toggleToolbar: (id)sender } -#ifdef NS_IMPL_COCOA +#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 - (CALayer *)makeBackingLayer { EmacsLayer *l = [[EmacsLayer alloc] @@ -7888,19 +7888,12 @@ - (void)lockFocus { NSTRACE ("[EmacsView lockFocus]"); - if ([self wantsLayer]) - { - CGContextRef context = [(EmacsLayer*)[self layer] getContext]; + CGContextRef context = [(EmacsLayer*)[self layer] getContext]; - [NSGraphicsContext + [NSGraphicsContext setCurrentContext:[NSGraphicsContext graphicsContextWithCGContext:context flipped:YES]]; - } -#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400 - else - [super lockFocus]; -#endif } @@ -7908,18 +7901,8 @@ - (void)unlockFocus { NSTRACE ("[EmacsView unlockFocus]"); - if ([self wantsLayer]) - { - [NSGraphicsContext setCurrentContext:nil]; - [self setNeedsDisplay:YES]; - } -#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400 - else - { - [super unlockFocus]; - [super flushWindow]; - } -#endif + [NSGraphicsContext setCurrentContext:nil]; + [self setNeedsDisplay:YES]; } @@ -7928,19 +7911,16 @@ - (void)windowDidChangeBackingProperties:(NSNotification *)notification { NSTRACE ("EmacsView windowDidChangeBackingProperties:]"); - if ([self wantsLayer]) - { - NSRect frame = [self frame]; - EmacsLayer *layer = (EmacsLayer *)[self layer]; + NSRect frame = [self frame]; + EmacsLayer *layer = (EmacsLayer *)[self layer]; - [layer setContentsScale:[[notification object] backingScaleFactor]]; - [layer setColorSpace:[[[notification object] colorSpace] CGColorSpace]]; + [layer setContentsScale:[[notification object] backingScaleFactor]]; + [layer setColorSpace:[[[notification object] colorSpace] CGColorSpace]]; - ns_clear_frame (emacsframe); - expose_frame (emacsframe, 0, 0, NSWidth (frame), NSHeight (frame)); - } + ns_clear_frame (emacsframe); + expose_frame (emacsframe, 0, 0, NSWidth (frame), NSHeight (frame)); } -#endif /* NS_IMPL_COCOA */ +#endif - (void)copyRect:(NSRect)srcRect to:(NSPoint)dest @@ -7952,57 +7932,45 @@ - (void)copyRect:(NSRect)srcRect to:(NSPoint)dest NSRect dstRect = NSMakeRect (dest.x, dest.y, NSWidth (srcRect), NSHeight (srcRect)); -#ifdef NS_IMPL_COCOA - if ([self wantsLayer]) - { - double scale = [[self window] backingScaleFactor]; - CGContextRef context = [(EmacsLayer *)[self layer] getContext]; - int bpp = CGBitmapContextGetBitsPerPixel (context) / 8; - void *pixels = CGBitmapContextGetData (context); - int rowSize = CGBitmapContextGetBytesPerRow (context); - int srcRowSize = NSWidth (srcRect) * scale * bpp; - void *srcPixels = (char *) pixels - + (int) (NSMinY (srcRect) * scale * rowSize - + NSMinX (srcRect) * scale * bpp); - void *dstPixels = (char *) pixels - + (int) (dest.y * scale * rowSize - + dest.x * scale * bpp); - - if (NSIntersectsRect (srcRect, dstRect) - && NSMinY (srcRect) < NSMinY (dstRect)) - for (int y = NSHeight (srcRect) * scale - 1 ; y >= 0 ; y--) - memmove ((char *) dstPixels + y * rowSize, - (char *) srcPixels + y * rowSize, - srcRowSize); - else - for (int y = 0 ; y < NSHeight (srcRect) * scale ; y++) - memmove ((char *) dstPixels + y * rowSize, - (char *) srcPixels + y * rowSize, - srcRowSize); - - } -#if MAC_OS_X_VERSION_MIN_REQUIRED < 101400 +#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 + double scale = [[self window] backingScaleFactor]; + CGContextRef context = [(EmacsLayer *)[self layer] getContext]; + int bpp = CGBitmapContextGetBitsPerPixel (context) / 8; + void *pixels = CGBitmapContextGetData (context); + int rowSize = CGBitmapContextGetBytesPerRow (context); + int srcRowSize = NSWidth (srcRect) * scale * bpp; + void *srcPixels = (char *) pixels + + (int) (NSMinY (srcRect) * scale * rowSize + + NSMinX (srcRect) * scale * bpp); + void *dstPixels = (char *) pixels + + (int) (dest.y * scale * rowSize + + dest.x * scale * bpp); + + if (NSIntersectsRect (srcRect, dstRect) + && NSMinY (srcRect) < NSMinY (dstRect)) + for (int y = NSHeight (srcRect) * scale - 1 ; y >= 0 ; y--) + memmove ((char *) dstPixels + y * rowSize, + (char *) srcPixels + y * rowSize, + srcRowSize); else - { -#endif -#endif /* NS_IMPL_COCOA */ + for (int y = 0 ; y < NSHeight (srcRect) * scale ; y++) + memmove ((char *) dstPixels + y * rowSize, + (char *) srcPixels + y * rowSize, + srcRowSize); -#if !defined (NS_IMPL_COCOA) || MAC_OS_X_VERSION_MIN_REQUIRED < 101400 - hide_bell(); // Ensure the bell image isn't scrolled. +#else + hide_bell(); // Ensure the bell image isn't scrolled. - ns_focus (emacsframe, &dstRect, 1); - [self scrollRect: srcRect - by: NSMakeSize (dstRect.origin.x - srcRect.origin.x, - dstRect.origin.y - srcRect.origin.y)]; - ns_unfocus (emacsframe); -#endif -#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED < 101400 - } + ns_focus (emacsframe, &dstRect, 1); + [self scrollRect: srcRect + by: NSMakeSize (dstRect.origin.x - srcRect.origin.x, + dstRect.origin.y - srcRect.origin.y)]; + ns_unfocus (emacsframe); #endif } -#ifdef NS_IMPL_COCOA +#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 /* If the frame has been garbaged but the toolkit wants to draw, for example when resizing the frame, we end up with a blank screen. Sometimes this results in an unpleasant flicker, so try to @@ -9477,7 +9445,7 @@ - (void) scrollWheel: (NSEvent *)theEvent @end /* EmacsScroller */ -#ifdef NS_IMPL_COCOA +#if defined (NS_IMPL_COCOA) && MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 /* ========================================================================== commit 022a1f48a4e2005be7aa66b67eb2f17f8386c853 Author: Paul Eggert Date: Fri Apr 8 10:18:53 2022 -0700 Fix pacifying gcc -Wanalyzer-null-dereference * src/xterm.c (handle_one_xevent): Use eassume not eassert. eassert (X)’s suppress_checking does not let GCC assume X. diff --git a/src/xterm.c b/src/xterm.c index 9b0fe6f3f7..dc06df246c 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -13930,7 +13930,7 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (x_dnd_in_progress || x_dnd_waiting_for_finish) { - eassert (hold_quit); + eassume (hold_quit); *hold_quit = inev.ie; EVENT_INIT (inev.ie); commit c2d78d09c1eca4df0836d0fb41562ac0ae1071d6 Author: Mattias Engdegård Date: Fri Apr 8 15:34:57 2022 +0200 Rename mark_stack to mark_c_stack This is the function that marks the C stack. Avoid confusion with the new mark stack, a stack used in the GC mark phase. * src/alloc.c (SETJMP_WILL_LIKELY_WORK, SETJMP_WILL_NOT_WORK) (mark_stack, mark_c_stack): * src/lisp.h: * src/thread.c (mark_one_thread): Rename mark_stack to mark_c_stack. diff --git a/src/alloc.c b/src/alloc.c index 733f7733fa..8fd981a51f 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -4982,7 +4982,7 @@ marking. Emacs has determined that the method it uses to do the\n\ marking will likely work on your system, but this isn't sure.\n\ \n\ If you are a system-programmer, or can get the help of a local wizard\n\ -who is, please take a look at the function mark_stack in alloc.c, and\n\ +who is, please take a look at the function mark_c_stack in alloc.c, and\n\ verify that the methods used are appropriate for your system.\n\ \n\ Please mail the result to .\n\ @@ -4995,7 +4995,7 @@ marking. Emacs has determined that the default method it uses to do the\n\ marking will not work on your system. We will need a system-dependent\n\ solution for your system.\n\ \n\ -Please take a look at the function mark_stack in alloc.c, and\n\ +Please take a look at the function mark_c_stack in alloc.c, and\n\ try to find a way to make it work on your system.\n\ \n\ Note that you may get false negatives, depending on the compiler.\n\ @@ -5137,7 +5137,7 @@ typedef union from the stack start. */ void -mark_stack (char const *bottom, char const *end) +mark_c_stack (char const *bottom, char const *end) { /* This assumes that the stack is a contiguous region in memory. If that's not the case, something has to be done here to iterate diff --git a/src/lisp.h b/src/lisp.h index 9c7dc3bc6f..f723876634 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -4159,7 +4159,7 @@ extern void refill_memory_reserve (void); #endif extern void alloc_unexec_pre (void); extern void alloc_unexec_post (void); -extern void mark_stack (char const *, char const *); +extern void mark_c_stack (char const *, char const *); extern void flush_stack_call_func1 (void (*func) (void *arg), void *arg); extern void mark_memory (void const *start, void const *end); diff --git a/src/thread.c b/src/thread.c index c6742341fb..626d14aad0 100644 --- a/src/thread.c +++ b/src/thread.c @@ -655,7 +655,7 @@ mark_one_thread (struct thread_state *thread) mark_specpdl (thread->m_specpdl, thread->m_specpdl_ptr); - mark_stack (thread->m_stack_bottom, stack_top); + mark_c_stack (thread->m_stack_bottom, stack_top); for (struct handler *handler = thread->m_handlerlist; handler; handler = handler->next) commit 13c8cc58bbd829ca4616dea09cb050dc977db9ae Author: Mattias Engdegård Date: Fri Apr 8 14:57:17 2022 +0200 Enable warnings when building as a developer with Clang The configure-script logic that automatically enables warnings when building in a development tree didn't work for Clang because it was identified as an old GCC version. * configure.ac: Don't test Clang version as if it were GCC. diff --git a/configure.ac b/configure.ac index cda2a04be9..6b834a2f65 100644 --- a/configure.ac +++ b/configure.ac @@ -965,6 +965,17 @@ AC_DEFUN([gl_GCC_VERSION_IFELSE], ] ) +# clang is unduly picky about some things. +AC_CACHE_CHECK([whether the compiler is clang], [emacs_cv_clang], + [AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM([[ + #ifndef __clang__ + error "not clang"; + #endif + ]])], + [emacs_cv_clang=yes], + [emacs_cv_clang=no])]) + AC_ARG_ENABLE([gcc-warnings], [AS_HELP_STRING([--enable-gcc-warnings@<:@=TYPE@:>@], [control generation of GCC warnings. The TYPE 'yes' @@ -984,7 +995,11 @@ AC_ARG_ENABLE([gcc-warnings], # just a release imported into Git for patch management. gl_gcc_warnings=no if test -e "$srcdir"/.git && test ! -f "$srcdir"/.tarball-version; then - gl_GCC_VERSION_IFELSE([5], [3], [gl_gcc_warnings=warn-only]) + # Clang typically identifies itself as GCC 4.2 or something similar + # even if it is recent enough to accept the warnings we enable. + AS_IF([test "$emacs_cv_clang" = yes], + [gl_gcc_warnings=warn-only], + [gl_GCC_VERSION_IFELSE([5], [3], [gl_gcc_warnings=warn-only])]) fi]) AC_ARG_ENABLE([check-lisp-object-type], @@ -996,17 +1011,6 @@ if test "$enable_check_lisp_object_type" = yes; then [Define to enable compile-time checks for the Lisp_Object data type.]) fi -# clang is unduly picky about some things. -AC_CACHE_CHECK([whether the compiler is clang], [emacs_cv_clang], - [AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM([[ - #ifndef __clang__ - error "not clang"; - #endif - ]])], - [emacs_cv_clang=yes], - [emacs_cv_clang=no])]) - WERROR_CFLAGS= # When compiling with GCC, prefer -isystem to -I when including system # include files, to avoid generating useless diagnostics for the files. commit e2f3b0f16eb34ac6f4941ddcf5b8ee24642656fc Author: Lars Ingebrigtsen Date: Fri Apr 8 14:46:14 2022 +0200 Improve package.el error messages on too-old Emacsen * lisp/emacs-lisp/package.el (package-compute-transaction): Give a better error message on too-old Emacs versions (bug#54747). diff --git a/lisp/emacs-lisp/package.el b/lisp/emacs-lisp/package.el index 6aa82e576d..4f1ac5a5da 100644 --- a/lisp/emacs-lisp/package.el +++ b/lisp/emacs-lisp/package.el @@ -1854,8 +1854,12 @@ SEEN is used internally to detect infinite recursion." (error "Need package `%s-%s', but only %s is available" next-pkg (package-version-join next-version) found-something)) - (t (error "Package `%s-%s' is unavailable" - next-pkg (package-version-join next-version))))) + (t + (if (eq next-pkg 'emacs) + (error "This package requires Emacs version %s" + (package-version-join next-version)) + (error "Package `%s-%s' is unavailable" + next-pkg (package-version-join next-version)))))) (setq packages (package-compute-transaction (cons found packages) (package-desc-reqs found) commit 5c532fe30305393079674557256dbb96253fd517 Author: Po Lu Date: Fri Apr 8 19:36:03 2022 +0800 Recommend that the user turn off memory overcommit * doc/emacs/trouble.texi (Memory Full): Tell the user that Emacs behaves best with overcommit off, and how to turn it off. diff --git a/doc/emacs/trouble.texi b/doc/emacs/trouble.texi index 93f9c779db..f524a82022 100644 --- a/doc/emacs/trouble.texi +++ b/doc/emacs/trouble.texi @@ -296,6 +296,20 @@ editing in the same Emacs session. out of memory, because the Buffer Menu needs a fair amount of memory itself, and the reserve supply may not be enough. +@cindex memory trouble, GNU/Linux + On GNU/Linux systems, the system does not normally report running +out of memory to Emacs, and can instead randomly kill processes when +they run out of memory. We recommend that you turn this behavior off, +so that Emacs can respond correctly when it runs out of memory, by +becoming the super user, editing the file @code{/etc/sysctl.conf} to +contain the following lines, and then running the command @code{sysctl +-p}: + +@example +vm.overcommit_memory=2 +vm.overcommit_ratio=0 +@end example + @node Crashing @subsection When Emacs Crashes commit deb40b226764a0eb93a9fc2cafbbeeb9aeb31682 Author: Mattias Engdegård Date: Fri Apr 8 13:12:40 2022 +0200 ; * src/nsterm.m: Remove stray semicolon diff --git a/src/nsterm.m b/src/nsterm.m index 15127d53fb..36e2ff55ac 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -7873,7 +7873,7 @@ - (instancetype)toggleToolbar: (id)sender #ifdef NS_IMPL_COCOA -- (CALayer *)makeBackingLayer; +- (CALayer *)makeBackingLayer { EmacsLayer *l = [[EmacsLayer alloc] initWithColorSpace:[[[self window] colorSpace] CGColorSpace]]; commit 410690085e011d9c474d1e2a1bf3e4d713d04174 Author: Po Lu Date: Fri Apr 8 18:50:48 2022 +0800 Interpolate scrolls coming from mice by default * lisp/pixel-scroll.el (pixel-scroll-precision-interpolate-mice): New user option. (pixel-scroll-precision): If the class of the last event device is `mouse', interpolate the next scroll. diff --git a/lisp/pixel-scroll.el b/lisp/pixel-scroll.el index 688a054896..b0fe2f56c0 100644 --- a/lisp/pixel-scroll.el +++ b/lisp/pixel-scroll.el @@ -214,6 +214,14 @@ This is only effective when `pixel-scroll-precision-mode' is enabled." :type 'boolean :version "29.1") +(defcustom pixel-scroll-precision-interpolate-mice t + "Whether or not to interpolate scrolling from a mouse. +If non-nil, scrolling from the mouse wheel of an actual mouse (as +opposed to a touchpad) will cause Emacs to interpolate the scroll." + :group 'scrolling + :type 'boolean + :version "29.1") + (defun pixel-scroll-in-rush-p () "Return non-nil if next scroll should be non-smooth. When scrolling request is delivered soon after the previous one, @@ -681,16 +689,20 @@ wheel." (if (> (abs delta) (window-text-height window t)) (mwheel-scroll event nil) (with-selected-window window - (if (and pixel-scroll-precision-large-scroll-height - (> (abs delta) - pixel-scroll-precision-large-scroll-height) - (let* ((kin-state (pixel-scroll-kinetic-state)) - (ring (aref kin-state 0)) - (time (aref kin-state 1))) - (or (null time) - (> (- (float-time) time) 1.0) - (and (consp ring) - (ring-empty-p ring))))) + (if (or (and pixel-scroll-precision-interpolate-mice + (eq (device-class last-event-frame + last-event-device) + 'mouse)) + (and pixel-scroll-precision-large-scroll-height + (> (abs delta) + pixel-scroll-precision-large-scroll-height) + (let* ((kin-state (pixel-scroll-kinetic-state)) + (ring (aref kin-state 0)) + (time (aref kin-state 1))) + (or (null time) + (> (- (float-time) time) 1.0) + (and (consp ring) + (ring-empty-p ring)))))) (progn (let ((kin-state (pixel-scroll-kinetic-state))) (aset kin-state 0 (make-ring 30)) commit d9851c6df2d5b5e950329968ac268a06ef4adfbf Author: Michael Albinus Date: Fri Apr 8 12:47:53 2022 +0200 Ensure local `default-directory' when calling `process-attributes'. * lisp/server.el (server-running-p): * lisp/subr.el (memory-limit): Ensure local `default-directory' when calling `process-attributes'. diff --git a/lisp/server.el b/lisp/server.el index da60f1cda7..763cf27f7a 100644 --- a/lisp/server.el +++ b/lisp/server.el @@ -779,7 +779,8 @@ by the current Emacs process, use the `server-process' variable." (condition-case nil (if server-use-tcp (with-temp-buffer - (insert-file-contents-literally (expand-file-name name server-auth-dir)) + (setq default-directory server-auth-dir) + (insert-file-contents-literally (expand-file-name name)) (or (and (looking-at "127\\.0\\.0\\.1:[0-9]+ \\([0-9]+\\)") (assq 'comm (process-attributes diff --git a/lisp/subr.el b/lisp/subr.el index 34f7bb6888..e7d5d36461 100644 --- a/lisp/subr.el +++ b/lisp/subr.el @@ -2719,7 +2719,8 @@ It can be retrieved with `(process-get PROCESS PROPNAME)'." (defun memory-limit () "Return an estimate of Emacs virtual memory usage, divided by 1024." - (or (cdr (assq 'vsize (process-attributes (emacs-pid)))) 0)) + (let ((default-directory temporary-file-directory)) + (or (cdr (assq 'vsize (process-attributes (emacs-pid)))) 0))) ;;;; Input and display facilities. commit c4921d1157a2e3e15b1d779a6bdf768e307275dd Author: Po Lu Date: Fri Apr 8 17:00:37 2022 +0800 Fix GC marking of input events with devices * src/keyboard.c (mark_kboards): * src/pgtkterm.c (mark_pgtkterm): Mark `device' as well. diff --git a/src/keyboard.c b/src/keyboard.c index 01274b4d4a..588ee75ee0 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -13088,6 +13088,12 @@ mark_kboards (void) mark_object (event->ie.y); mark_object (event->ie.frame_or_window); mark_object (event->ie.arg); + + /* This should never be allocated for a single event, but + mark it anyway in the situation where the list of devices + changed but an event with an old device is still present + in the queue. */ + mark_object (event->ie.device); } } } diff --git a/src/pgtkterm.c b/src/pgtkterm.c index d8c6dad2f9..fb62f5978d 100644 --- a/src/pgtkterm.c +++ b/src/pgtkterm.c @@ -347,6 +347,7 @@ mark_pgtkterm (void) mark_object (ev->ie.y); mark_object (ev->ie.frame_or_window); mark_object (ev->ie.arg); + mark_object (ev->ie.device); } for (dpyinfo = x_display_list; dpyinfo;