commit 7b621c40f39c49232d96e446892ee2f553cf733d (HEAD, refs/remotes/origin/master) Author: Po Lu Date: Wed Dec 29 14:59:41 2021 +0800 Queue xwidget views for allocation in more places * src/xwidget.c (Fmake_xwidget) [HAVE_PGTK]: (Fxwidget_resize) [HAVE_PGTK]: Queue xwidgets and views for allocation. diff --git a/src/xwidget.c b/src/xwidget.c index c05cefde4b..71a1a46d10 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -327,6 +327,7 @@ fails. */) gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height); + gtk_widget_queue_allocate (GTK_WIDGET (xw->widget_osr)); if (EQ (xw->type, Qwebkit)) { @@ -2195,6 +2196,7 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) clip_bottom - clip_top); gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (xv->frame)), xv->widget, x + clip_left, y + clip_top); + gtk_widget_queue_allocate (xv->widget); #endif #elif defined NS_IMPL_COCOA nsxwidget_resize_view (xv, clip_right - clip_left, commit 2b7d33e30b4b66bca405fed5b5483e864db6b1e5 Author: Po Lu Date: Wed Dec 29 14:37:49 2021 +0800 Improve xwidget event handling on XI2 * src/xterm.c (handle_one_xevent): Pass XI2 entry and leave events to xwidgets and fix scroll valuator reset logic for xwidgets. * src/xwidget.c (xwidget_button_1): Stop ungrabbing all devices XI2 builds. (xwidget_motion_or_crossing): Learn to pass through XI2 crossing events. (x_draw_xwidget_glyph_string): Add crossing events to the XI2 event mask. diff --git a/src/xterm.c b/src/xterm.c index a986681ab7..e3079727d5 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -9928,9 +9928,6 @@ handle_one_xevent (struct x_display_info *dpyinfo, XIValuatorState *states; double *values; bool found_valuator = false; -#ifdef HAVE_XWIDGETS - bool any_stop_p = false; -#endif /* HAVE_XWIDGETS */ /* A fake XMotionEvent for x_note_mouse_movement. */ XMotionEvent ev; @@ -9981,28 +9978,46 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_display_set_last_user_time (dpyinfo, xi_event->time); x_detect_focus_change (dpyinfo, any, event, &inev.ie); + { +#ifdef HAVE_XWIDGETS + struct xwidget_view *xwidget_view = xwidget_view_from_window (enter->event); +#else + bool xwidget_view = false; +#endif + + /* One problem behind the design of XInput 2 scrolling is + that valuators are not unique to each window, but only + the window that has grabbed the valuator's device or + the window that the device's pointer is on top of can + receive motion events. There is also no way to + retrieve the value of a valuator outside of each motion + event. + + As such, to prevent wildly inaccurate results when the + valuators have changed outside Emacs, we reset our + records of each valuator's value whenever the pointer + re-enters a frame after its valuators have potentially + been changed elsewhere. */ + if (enter->detail != XINotifyInferior + && enter->mode != XINotifyPassiveUngrab + /* See the comment under FocusIn in + `x_detect_focus_change'. The main relevant culprit + these days seems to be XFCE. */ + && enter->mode != XINotifyUngrab + && (xwidget_view + || (any && enter->event == FRAME_X_WINDOW (any)))) + xi_reset_scroll_valuators_for_device_id (dpyinfo, enter->deviceid); - /* One problem behind the design of XInput 2 scrolling is - that valuators are not unique to each window, but only - the window that has grabbed the valuator's device or - the window that the device's pointer is on top of can - receive motion events. There is also no way to - retrieve the value of a valuator outside of each motion - event. - - As such, to prevent wildly inaccurate results when the - valuators have changed outside Emacs, we reset our - records of each valuator's value whenever the pointer - re-enters a frame after its valuators have potentially - been changed elsewhere. */ - if (enter->detail != XINotifyInferior - && enter->mode != XINotifyPassiveUngrab - /* See the comment under FocusIn in - `x_detect_focus_change'. The main relevant culprit - these days seems to be XFCE. */ - && enter->mode != XINotifyUngrab - && any && enter->event == FRAME_X_WINDOW (any)) - xi_reset_scroll_valuators_for_device_id (dpyinfo, enter->deviceid); +#ifdef HAVE_XWIDGETS + if (xwidget_view) + { + *finish = X_EVENT_DROP; + xwidget_motion_or_crossing (xwidget_view, event); + + goto XI_OTHER; + } +#endif + } f = any; @@ -10026,6 +10041,21 @@ handle_one_xevent (struct x_display_info *dpyinfo, ev.window = leave->event; any = x_any_window_to_frame (dpyinfo, leave->event); +#ifdef HAVE_XWIDGETS + { + struct xwidget_view *xvw + = xwidget_view_from_window (leave->event); + + if (xvw) + { + *finish = X_EVENT_DROP; + xwidget_motion_or_crossing (xvw, event); + + goto XI_OTHER; + } + } +#endif + x_display_set_last_user_time (dpyinfo, xi_event->time); x_detect_focus_change (dpyinfo, any, event, &inev.ie); @@ -10105,16 +10135,19 @@ handle_one_xevent (struct x_display_info *dpyinfo, #ifdef HAVE_XWIDGETS if (xv) { + /* FIXME: figure out what in GTK is + causing interval values to jump by + >100 at the end of a touch sequence + when an xwidget gets a scroll event + where is_stop is TRUE. */ + if (fabs (delta) > 100) + continue; if (val->horizontal) xv_total_x += delta; else xv_total_y += delta; found_valuator = true; - - if (delta == 0.0) - any_stop_p = true; - continue; } #endif @@ -10224,8 +10257,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, if (found_valuator) xwidget_scroll (xv, xev->event_x, xev->event_y, - xv_total_x, xv_total_y, state, - xev->time, any_stop_p); + -xv_total_x, -xv_total_y, state, + xev->time, (xv_total_x == 0.0 + && xv_total_y == 0.0)); else xwidget_motion_notify (xv, xev->event_x, xev->event_y, state, xev->time); diff --git a/src/xwidget.c b/src/xwidget.c index 22c42382bb..c05cefde4b 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -1052,12 +1052,6 @@ xwidget_button_1 (struct xwidget_view *view, GdkEvent *xg_event = gdk_event_new (down_p ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE); struct xwidget *model = XXWIDGET (view->model); GtkWidget *target; -#ifdef HAVE_XINPUT2 - struct x_display_info *dpyinfo; - struct xi_device_t *xi_device; - GdkSeat *seat; - GdkDevice *device; -#endif /* X and Y should be relative to the origin of view->wdesc. */ x += view->clip_left; @@ -1081,24 +1075,6 @@ xwidget_button_1 (struct xwidget_view *view, xg_event->button.time = time; xg_event->button.device = find_suitable_pointer (view->frame); -#ifdef HAVE_XINPUT2 - dpyinfo = FRAME_DISPLAY_INFO (view->frame); - device = xg_event->button.device; - - for (int idx = 0; idx < dpyinfo->num_devices; ++idx) - { - xi_device = &dpyinfo->devices[idx]; - - XIUngrabDevice (view->dpy, xi_device->device_id, CurrentTime); - } - - if (device) - { - seat = gdk_device_get_seat (device); - gdk_seat_ungrab (seat); - } -#endif - gtk_main_do_event (xg_event); gdk_event_free (xg_event); } @@ -1260,24 +1236,47 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event) int x; int y; GtkWidget *target; +#ifdef HAVE_XINPUT2 + XIEnterEvent *xev = NULL; +#endif if (NILP (model->buffer)) return; - xg_event = gdk_event_new (event->type == MotionNotify - ? GDK_MOTION_NOTIFY - : (event->type == LeaveNotify - ? GDK_LEAVE_NOTIFY - : GDK_ENTER_NOTIFY)); +#ifdef HAVE_XINPUT2 + if (event->type != GenericEvent) +#endif + { + xg_event = gdk_event_new (event->type == MotionNotify + ? GDK_MOTION_NOTIFY + : (event->type == LeaveNotify + ? GDK_LEAVE_NOTIFY + : GDK_ENTER_NOTIFY)); + target = find_widget_at_pos (model->widgetwindow_osr, + (event->type == MotionNotify + ? event->xmotion.x + view->clip_left + : event->xcrossing.x + view->clip_left), + (event->type == MotionNotify + ? event->xmotion.y + view->clip_top + : event->xcrossing.y + view->clip_top), + &x, &y); + } +#ifdef HAVE_XINPUT2 + else + { + eassert (event->xcookie.evtype == XI_Enter + || event->xcookie.evtype == XI_Leave); - target = find_widget_at_pos (model->widgetwindow_osr, - (event->type == MotionNotify - ? event->xmotion.x + view->clip_left - : event->xcrossing.x + view->clip_left), - (event->type == MotionNotify - ? event->xmotion.y + view->clip_top - : event->xcrossing.y + view->clip_top), - &x, &y); + xev = (XIEnterEvent *) event->xcookie.data; + xg_event = gdk_event_new (event->type == XI_Enter + ? GDK_ENTER_NOTIFY + : GDK_LEAVE_NOTIFY); + target = find_widget_at_pos (model->widgetwindow_osr, + lrint (xev->event_x + view->clip_left), + lrint (xev->event_y + view->clip_top), + &x, &y); + } +#endif if (!target) target = model->widget_osr; @@ -1297,6 +1296,18 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event) xg_event->motion.state = event->xmotion.state; xg_event->motion.device = find_suitable_pointer (view->frame); } +#ifdef HAVE_XINPUT2 + else if (event->type == GenericEvent) + { + xg_event->crossing.x = (gdouble) xev->event_x; + xg_event->crossing.y = (gdouble) xev->event_y; + xg_event->crossing.x_root = (gdouble) xev->root_x; + xg_event->crossing.y_root = (gdouble) xev->root_y; + xg_event->crossing.time = xev->time; + xg_event->crossing.focus = xev->focus; + gdk_event_set_device (xg_event, find_suitable_pointer (view->frame)); + } +#endif else { xg_event->crossing.detail = min (5, event->xcrossing.detail); @@ -1305,6 +1316,7 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event) xg_event->crossing.y = y; xg_event->crossing.x_root = event->xcrossing.x_root; xg_event->crossing.y_root = event->xcrossing.y_root; + xg_event->crossing.focus = event->xcrossing.focus; gdk_event_set_device (xg_event, find_suitable_pointer (view->frame)); } @@ -2108,6 +2120,8 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) XISetMask (m, XI_Motion); XISetMask (m, XI_ButtonPress); XISetMask (m, XI_ButtonRelease); + XISetMask (m, XI_Enter); + XISetMask (m, XI_Leave); XISelectEvents (xv->dpy, xv->wdesc, &mask, 1); } #endif commit 22a9a205137f404863451c7dc43c15d2ef396325 Merge: 8419011ceb 06dcd2be5d Author: Stefan Kangas Date: Wed Dec 29 06:51:46 2021 +0100 Merge from origin/emacs-28 06dcd2be5d Improve rectangle-mark-mode documentation regarding mark a... commit 8419011cebc25efda0e130e9734bf4f5106e651e Author: Po Lu Date: Wed Dec 29 13:30:46 2021 +0800 Translate buttons when sending XI2 motion events to xwidgets * src/xterm.c (handle_one_xevent): Translate all three buttons when passing XI2 motion events to xwidgets. diff --git a/src/xterm.c b/src/xterm.c index 3200e44a87..a986681ab7 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -10210,13 +10210,25 @@ handle_one_xevent (struct x_display_info *dpyinfo, #ifdef HAVE_XWIDGETS if (xv) { + uint state = xev->mods.effective; + + if (xev->buttons.mask_len) + { + if (XIMaskIsSet (xev->buttons.mask, 1)) + state |= Button1Mask; + if (XIMaskIsSet (xev->buttons.mask, 2)) + state |= Button2Mask; + if (XIMaskIsSet (xev->buttons.mask, 3)) + state |= Button3Mask; + } + if (found_valuator) xwidget_scroll (xv, xev->event_x, xev->event_y, - xv_total_x, xv_total_y, xev->mods.effective, + xv_total_x, xv_total_y, state, xev->time, any_stop_p); else xwidget_motion_notify (xv, xev->event_x, xev->event_y, - xev->mods.effective, xev->time); + state, xev->time); goto XI_OTHER; } commit 42ede97016e82c86460b2a20cadeb4e8e6ebea7a Author: Po Lu Date: Wed Dec 29 13:13:15 2021 +0800 Use XI2 to handle xwidget button events * src/xterm.c (handle_one_xevent): Handle xwidget views when handling XI_ButtonPress or XI_ButtonRelease events. * src/xwidget.c (x_draw_xwidget_glyph_string): Add appropriate values to the XI2 event mask. diff --git a/src/xterm.c b/src/xterm.c index 3fdf214c3d..3200e44a87 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -10325,6 +10325,9 @@ handle_one_xevent (struct x_display_info *dpyinfo, bool tab_bar_p = false; bool tool_bar_p = false; struct xi_device_t *device; +#ifdef HAVE_XWIDGETS + struct xwidget_view *xvw; +#endif #ifdef XIPointerEmulated /* Ignore emulated scroll events when XI2 native @@ -10340,6 +10343,25 @@ handle_one_xevent (struct x_display_info *dpyinfo, } #endif +#ifdef HAVE_XWIDGETS + xvw = xwidget_view_from_window (xev->event); + if (xvw) + { + xwidget_button (xvw, xev->evtype == XI_ButtonPress, + lrint (xev->event_x), lrint (xev->event_y), + xev->detail, xev->mods.effective, xev->time); + + if (!EQ (selected_window, xvw->w) && (xev->detail < 4)) + { + inev.ie.kind = SELECT_WINDOW_EVENT; + inev.ie.frame_or_window = xvw->w; + } + + *finish = X_EVENT_DROP; + goto XI_OTHER; + } +#endif + device = xi_device_from_id (dpyinfo, xev->deviceid); if (!device || !device->master_p) diff --git a/src/xwidget.c b/src/xwidget.c index 5745153548..22c42382bb 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -2106,6 +2106,8 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) mask.deviceid = XIAllMasterDevices; XISetMask (m, XI_Motion); + XISetMask (m, XI_ButtonPress); + XISetMask (m, XI_ButtonRelease); XISelectEvents (xv->dpy, xv->wdesc, &mask, 1); } #endif commit 0b5d9e9d8e914b060e6fdc868169259080f9d7a0 Author: Po Lu Date: Wed Dec 29 12:59:46 2021 +0800 Fix embedder calculation for xwidgets on PGTK * src/xwidget.c (Fmake_xwidget): (x_draw_xwidget_glyph_string): Defer focus event synthesis on PGTK as well. (record_osr_embedder): Use view window on PGTK. (to_embedder): (from_embedder): Rectify accordingly. diff --git a/src/xwidget.c b/src/xwidget.c index b6f1780927..5745153548 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -341,7 +341,7 @@ fails. */) gtk_widget_show (xw->widget_osr); gtk_widget_show (xw->widgetwindow_osr); -#ifndef HAVE_XINPUT2 +#if !defined HAVE_XINPUT2 && !defined HAVE_PGTK synthesize_focus_in_event (xw->widgetwindow_osr); #endif @@ -667,8 +667,11 @@ record_osr_embedder (struct xwidget_view *view) xw = XXWIDGET (view->model); window = gtk_widget_get_window (xw->widgetwindow_osr); +#ifndef HAVE_PGTK embedder = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (view->frame)); - +#else + embedder = gtk_widget_get_window (view->widget); +#endif gdk_offscreen_window_set_embedder (window, embedder); xw->embedder = view->frame; xw->embedder_view = view; @@ -703,6 +706,7 @@ from_embedder (GdkWindow *window, double x, double y, { double *xout = x_out_ptr; double *yout = y_out_ptr; +#ifndef HAVE_PGTK struct xwidget *xw = find_xwidget_for_offscreen_window (window); struct xwidget_view *xvw; gint xoff, yoff; @@ -726,6 +730,10 @@ from_embedder (GdkWindow *window, double x, double y, *xout = x - xvw->x - xoff; *yout = y - xvw->y - yoff; } +#else + *xout = x; + *yout = y; +#endif } static void @@ -735,6 +743,7 @@ to_embedder (GdkWindow *window, double x, double y, { double *xout = x_out_ptr; double *yout = y_out_ptr; +#ifndef HAVE_PGTK struct xwidget *xw = find_xwidget_for_offscreen_window (window); struct xwidget_view *xvw; gint xoff, yoff; @@ -758,6 +767,10 @@ to_embedder (GdkWindow *window, double x, double y, *xout = x + xvw->x + xoff; *yout = y + xvw->y + yoff; } +#else + *xout = x; + *yout = y; +#endif } static GdkDevice * @@ -2203,7 +2216,7 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) } #endif -#ifdef HAVE_XINPUT2 +#if defined HAVE_XINPUT2 || defined HAVE_PGTK record_osr_embedder (xv); synthesize_focus_in_event (xww->widget_osr); #endif commit 8be5b08bb576fbf20feae6417b4069de2cf69781 Author: Po Lu Date: Wed Dec 29 10:06:37 2021 +0800 Fix NS xwidget build * src/xwidget.c (kill_frame_xwidget_views): * src/xwidget.h (kill_frame_xwidget_views): Disable on NS. diff --git a/src/xwidget.c b/src/xwidget.c index a53d43016a..b6f1780927 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -3354,6 +3354,7 @@ lower_frame_xwidget_views (struct frame *f) } #endif +#ifndef NS_IMPL_COCOA void kill_frame_xwidget_views (struct frame *f) { @@ -3370,6 +3371,7 @@ kill_frame_xwidget_views (struct frame *f) for (; CONSP (rem); rem = XCDR (rem)) Fdelete_xwidget_view (XCAR (rem)); } +#endif static void kill_xwidget (struct xwidget *xw) diff --git a/src/xwidget.h b/src/xwidget.h index ef56dfa7c5..ab60b9ed34 100644 --- a/src/xwidget.h +++ b/src/xwidget.h @@ -200,7 +200,9 @@ struct xwidget_view *xwidget_view_from_window (Window wdesc); void xwidget_expose (struct xwidget_view *xv); extern void lower_frame_xwidget_views (struct frame *f); #endif +#ifndef NS_IMPL_COCOA extern void kill_frame_xwidget_views (struct frame *f); +#endif #ifdef HAVE_X_WINDOWS extern void xwidget_button (struct xwidget_view *, bool, int, int, int, int, Time); commit 512e7c368565994c95300323ae5454a40c06649f Author: Po Lu Date: Wed Dec 29 10:01:49 2021 +0800 * src/xwidget.c (syms_of_xwidget): Fix typo. diff --git a/src/xwidget.c b/src/xwidget.c index ffd61ebfa8..a53d43016a 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -3149,7 +3149,7 @@ syms_of_xwidget (void) staticpro (&internal_xwidget_view_list); #ifdef HAVE_X_WINDOWS - x_window_to_xwv_map = CALLN (Fmake_hash_table, QCtest,); Qeq + x_window_to_xwv_map = CALLN (Fmake_hash_table, QCtest, Qeq); staticpro (&x_window_to_xwv_map); #endif commit 9249365837c33e18f8504dcbf12b8c3d217f0d43 Author: Po Lu Date: Wed Dec 29 09:53:42 2021 +0800 Add support for xwidgets to the PGTK port * src/emacsgtkfixed.c (EMACS_FIXED_GET_CLASS): New function. (struct GtkFixedPrivateL): New struct. (emacs_fixed_gtk_widget_size_allocate): (emacs_fixed_class_init): New functions. * src/keyboard.h: Declare lispy_function_keys also when HAVE_PGTK. * src/pgtkterm.c (x_free_frame_resources): Destroy all xwidget views. (pgtk_scroll_run): Move xwidget views that overlap with the scrolled area. (pgtk_emacs_to_gtk_modifiers): Expose function. * src/pgtkterm.h: Wrap in include guard. (pgtk_emacs_to_gtk_modifiers): New prototype. * src/xwidget.c (xw_forward_event_translate): (xw_forward_event_from_view): New functions. (Fmake_xwidget): Remove obsolete PGTK specific code. (Fxwidget_perform_lispy_event): Convert modifiers correctly on PGTK. (define_cursors): Use GDK functions to define cursors on PGTK. (xwidget_view_from_window): Disable on non-PGTK builds. (xwidget_show_view): (xwidget_hide_view): Implement on PGTK. (xv_do_draw): Disable on non-PGTK builds. (offscreen_damage_event): Queue xwidget views for draw. (xwidget_expose): Disable on non-PGTK builds. (xwidget_init_view): (x_draw_xwidget_glyph_string): (Fdelete_xwidget_view): Implement for PGTK. (syms_of_xwidget): Don't initialize XID to widget table on PGTK. (lower_frame_xwidget_views): Disable on PGTK. * src/xwidget.h (struct xwidget_view): New fields for PGTK builds. (kill_frame_xwidget_views): Enable on PGTK. diff --git a/src/emacsgtkfixed.c b/src/emacsgtkfixed.c index 78c952f805..7130e3535a 100644 --- a/src/emacsgtkfixed.c +++ b/src/emacsgtkfixed.c @@ -63,6 +63,92 @@ EMACS_FIXED (GtkWidget *widget) EmacsFixed); } +#if defined HAVE_XWIDGETS && defined HAVE_PGTK + +static EmacsFixedClass * +EMACS_FIXED_GET_CLASS (GtkWidget *widget) +{ + return G_TYPE_INSTANCE_GET_CLASS (widget, emacs_fixed_get_type (), + EmacsFixedClass); +} + +struct GtkFixedPrivateL +{ + GList *children; +}; + +static void +emacs_fixed_gtk_widget_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + /* For xwidgets. + + This basically re-implements the base class method and adds an + additional case for an xwidget view. + + It would be nicer if the bse class method could be called first, + and the xview modification only would remain here. It wasn't + possible to solve it that way yet. */ + EmacsFixedClass *klass; + GtkWidgetClass *parent_class; + struct GtkFixedPrivateL *priv; + + klass = EMACS_FIXED_GET_CLASS (widget); + parent_class = g_type_class_peek_parent (klass); + parent_class->size_allocate (widget, allocation); + + priv = G_TYPE_INSTANCE_GET_PRIVATE (widget, GTK_TYPE_FIXED, + struct GtkFixedPrivateL); + + gtk_widget_set_allocation (widget, allocation); + + if (gtk_widget_get_has_window (widget)) + { + if (gtk_widget_get_realized (widget)) + gdk_window_move_resize (gtk_widget_get_window (widget), + allocation->x, + allocation->y, + allocation->width, + allocation->height); + } + + for (GList *children = priv->children; children; children = children->next) + { + GtkFixedChild *child = children->data; + + if (!gtk_widget_get_visible (child->widget)) + continue; + + GtkRequisition child_requisition; + gtk_widget_get_preferred_size (child->widget, &child_requisition, NULL); + + GtkAllocation child_allocation; + child_allocation.x = child->x; + child_allocation.y = child->y; + + if (!gtk_widget_get_has_window (widget)) + { + child_allocation.x += allocation->x; + child_allocation.y += allocation->y; + } + + child_allocation.width = child_requisition.width; + child_allocation.height = child_requisition.height; + + struct xwidget_view *xv + = g_object_get_data (G_OBJECT (child->widget), XG_XWIDGET_VIEW); + if (xv) + { + child_allocation.width = xv->clip_right; + child_allocation.height = xv->clip_bottom - xv->clip_top; + } + + gtk_widget_size_allocate (child->widget, &child_allocation); + } +} + +#endif /* HAVE_XWIDGETS && HAVE_PGTK */ + static void emacs_fixed_class_init (EmacsFixedClass *klass) { @@ -72,6 +158,9 @@ emacs_fixed_class_init (EmacsFixedClass *klass) widget_class->get_preferred_width = emacs_fixed_get_preferred_width; widget_class->get_preferred_height = emacs_fixed_get_preferred_height; +#if defined HAVE_XWIDGETS && defined HAVE_PGTK + widget_class->size_allocate = emacs_fixed_gtk_widget_size_allocate; +#endif g_type_class_add_private (klass, sizeof (EmacsFixedPrivate)); } diff --git a/src/keyboard.h b/src/keyboard.h index 21c51ec386..26b910ba7e 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -491,7 +491,7 @@ extern void process_pending_signals (void); extern struct timespec timer_check (void); extern void mark_kboards (void); -#if defined HAVE_NTGUI || defined HAVE_X_WINDOWS +#if defined HAVE_NTGUI || defined HAVE_X_WINDOWS || defined HAVE_PGTK extern const char *const lispy_function_keys[]; #endif diff --git a/src/pgtkterm.c b/src/pgtkterm.c index c75dab5130..0814fb0df8 100644 --- a/src/pgtkterm.c +++ b/src/pgtkterm.c @@ -245,6 +245,9 @@ x_free_frame_resources (struct frame *f) block_input (); +#ifdef HAVE_XWIDGETS + kill_frame_xwidget_views (f); +#endif free_frame_faces (f); if (FRAME_X_OUTPUT (f)->scale_factor_atimer != NULL) @@ -2999,6 +3002,91 @@ pgtk_scroll_run (struct window *w, struct run *run) block_input (); +#ifdef HAVE_XWIDGETS + /* "Copy" xwidget views in the area that will be scrolled. */ + GtkWidget *tem, *parent = FRAME_GTK_WIDGET (f); + GList *children = gtk_container_get_children (GTK_CONTAINER (parent)); + GList *iter; + struct xwidget_view *view; + + for (iter = children; iter; iter = iter->next) + { + tem = iter->data; + view = g_object_get_data (G_OBJECT (tem), XG_XWIDGET_VIEW); + + if (view && !view->hidden) + { + int window_y = view->y + view->clip_top; + int window_height = view->clip_bottom - view->clip_top; + + Emacs_Rectangle r1, r2, result; + r1.x = w->pixel_left; + r1.y = from_y; + r1.width = w->pixel_width; + r1.height = height; + r2 = r1; + r2.y = window_y; + r2.height = window_height; + + /* The window is offscreen, just unmap it. */ + if (window_height == 0) + { + view->hidden = true; + gtk_widget_hide (tem); + continue; + } + + bool intersects_p = + gui_intersect_rectangles (&r1, &r2, &result); + + if (XWINDOW (view->w) == w && intersects_p) + { + int y = view->y + (to_y - from_y); + int text_area_x, text_area_y, text_area_width, text_area_height; + int clip_top, clip_bottom; + + window_box (w, view->area, &text_area_x, &text_area_y, + &text_area_width, &text_area_height); + + view->y = y; + + clip_top = 0; + clip_bottom = XXWIDGET (view->model)->height; + + if (y < text_area_y) + clip_top = text_area_y - y; + + if ((y + clip_bottom) > (text_area_y + text_area_height)) + { + clip_bottom -= (y + clip_bottom) - (text_area_y + text_area_height); + } + + view->clip_top = clip_top; + view->clip_bottom = clip_bottom; + + /* This means the view has moved offscreen. Unmap + it and hide it here. */ + if ((view->clip_bottom - view->clip_top) <= 0) + { + view->hidden = true; + gtk_widget_hide (tem); + } + else + { + gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (f)), + tem, view->x + view->clip_left, + view->y + view->clip_top); + gtk_widget_set_size_request (tem, view->clip_right - view->clip_left, + view->clip_bottom - view->clip_top); + gtk_widget_queue_allocate (tem); + } + } + } + } + + g_list_free (children); +#endif + /* Cursor off. Will be switched on again in x_update_window_end. */ gui_clear_cursor (w); @@ -5099,7 +5187,7 @@ pgtk_gtk_to_emacs_modifiers (struct pgtk_display_info *dpyinfo, int state) return mod; } -static int +int pgtk_emacs_to_gtk_modifiers (struct pgtk_display_info *dpyinfo, int state) { int mod_ctrl; diff --git a/src/pgtkterm.h b/src/pgtkterm.h index e76411cf02..034e4f3c83 100644 --- a/src/pgtkterm.h +++ b/src/pgtkterm.h @@ -17,6 +17,8 @@ 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 . */ +#ifndef _PGTKTERM_H_ +#define _PGTKTERM_H_ #include "dispextern.h" #include "frame.h" @@ -660,5 +662,7 @@ extern bool xg_set_icon_from_xpm_data (struct frame *f, const char **data); extern bool pgtk_text_icon (struct frame *f, const char *icon_name); extern double pgtk_frame_scale_factor (struct frame *); +extern int pgtk_emacs_to_gtk_modifiers (struct pgtk_display_info *, int); #endif /* HAVE_PGTK */ +#endif /* _PGTKTERM_H_ */ diff --git a/src/xwidget.c b/src/xwidget.c index 63ac0555db..ffd61ebfa8 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -39,7 +39,11 @@ along with GNU Emacs. If not, see . */ #include #include #include +#ifndef HAVE_PGTK #include +#else +#include +#endif #ifdef HAVE_XINPUT2 #include #endif @@ -55,7 +59,9 @@ static Lisp_Object internal_xwidget_list; static uint32_t xwidget_counter = 0; #ifdef USE_GTK +#ifdef HAVE_X_WINDOWS static Lisp_Object x_window_to_xwv_map; +#endif static gboolean offscreen_damage_event (GtkWidget *, GdkEvent *, gpointer); static void synthesize_focus_in_event (GtkWidget *); static GdkDevice *find_suitable_keyboard (struct frame *); @@ -119,6 +125,102 @@ static void mouse_target_changed (WebKitWebView *, WebKitHitTestResult *, guint, gpointer); #endif +#ifdef HAVE_PGTK +static int +xw_forward_event_translate (GdkEvent *event, struct xwidget_view *xv, + struct xwidget *xw) +{ + GtkWidget *widget; + int new_x, new_y; + + switch (event->type) + { + case GDK_BUTTON_PRESS: + case GDK_BUTTON_RELEASE: + case GDK_2BUTTON_PRESS: + case GDK_3BUTTON_PRESS: + widget = find_widget_at_pos (xw->widgetwindow_osr, + lrint (event->button.x - xv->clip_left), + lrint (event->button.y - xv->clip_top), + &new_x, &new_y); + if (widget) + { + event->any.window = gtk_widget_get_window (widget); + event->button.x = new_x; + event->button.y = new_y; + return 1; + } + return 0; + case GDK_SCROLL: + widget = find_widget_at_pos (xw->widgetwindow_osr, + lrint (event->scroll.x - xv->clip_left), + lrint (event->scroll.y - xv->clip_top), + &new_x, &new_y); + if (widget) + { + event->any.window = gtk_widget_get_window (widget); + event->scroll.x = new_x; + event->scroll.y = new_y; + return 1; + } + return 0; + case GDK_MOTION_NOTIFY: + widget = find_widget_at_pos (xw->widgetwindow_osr, + lrint (event->motion.x - xv->clip_left), + lrint (event->motion.y - xv->clip_top), + &new_x, &new_y); + if (widget) + { + event->any.window = gtk_widget_get_window (widget); + event->motion.x = new_x; + event->motion.y = new_y; + return 1; + } + return 0; + case GDK_ENTER_NOTIFY: + case GDK_LEAVE_NOTIFY: + widget = find_widget_at_pos (xw->widgetwindow_osr, + lrint (event->crossing.x - xv->clip_left), + lrint (event->crossing.y - xv->clip_top), + &new_x, &new_y); + if (widget) + { + event->any.window = gtk_widget_get_window (widget); + event->crossing.x = new_x; + event->crossing.y = new_y; + return 1; + } + return 0; + default: + return 0; + } +} + +static gboolean +xw_forward_event_from_view (GtkWidget *widget, GdkEvent *event, + gpointer user_data) +{ + struct xwidget_view *xv = user_data; + struct xwidget *xw = XXWIDGET (xv->model); + GdkEvent *eventcopy; + bool translated_p; + + if (NILP (xw->buffer)) + return TRUE; + + eventcopy = gdk_event_copy (event); + translated_p = xw_forward_event_translate (eventcopy, xv, xw); + record_osr_embedder (xv); + + g_object_ref (eventcopy->any.window); + if (translated_p) + gtk_main_do_event (eventcopy); + gdk_event_free (eventcopy); + + /* Don't propagate this event further. */ + return TRUE; +} +#endif DEFUN ("make-xwidget", Fmake_xwidget, Smake_xwidget, @@ -185,12 +287,9 @@ fails. */) # endif xw->widgetwindow_osr = gtk_offscreen_window_new (); -#ifndef HAVE_PGTK gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width, xw->height); -#else gtk_container_check_resize (GTK_CONTAINER (xw->widgetwindow_osr)); -#endif if (EQ (xw->type, Qwebkit)) { @@ -389,10 +488,17 @@ selected frame is not an X-Windows frame. */) if (character < 32) character += '_'; +#ifndef HAVE_PGTK if (f) modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f), modifiers); else modifiers = 0; +#else + if (f) + modifiers = pgtk_emacs_to_gtk_modifiers (FRAME_DISPLAY_INFO (f), modifiers); + else + modifiers = 0; +#endif } else if (SYMBOLP (event)) { @@ -414,11 +520,19 @@ selected frame is not an X-Windows frame. */) ++off; } +#ifndef HAVE_PGTK if (f) modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f), XFIXNUM (XCAR (XCDR (decoded)))); else modifiers = 0; +#else + if (f) + modifiers = pgtk_emacs_to_gtk_modifiers (FRAME_DISPLAY_INFO (f), + XFIXNUM (XCAR (XCDR (decoded)))); + else + modifiers = 0; +#endif if (found) keycode = off + 0xff00; @@ -816,6 +930,9 @@ static void define_cursors (struct xwidget *xw, WebKitHitTestResult *res) { struct xwidget_view *xvw; +#ifdef HAVE_PGTK + GdkWindow *wdesc; +#endif xw->hit_result = webkit_hit_test_result_get_context (res); @@ -829,8 +946,16 @@ define_cursors (struct xwidget *xw, WebKitHitTestResult *res) if (XXWIDGET (xvw->model) == xw) { xvw->cursor = cursor_for_hit (xw->hit_result, xvw->frame); +#ifdef HAVE_X_WINDOWS if (xvw->wdesc != None) XDefineCursor (xvw->dpy, xvw->wdesc, xvw->cursor); +#else + if (gtk_widget_get_realized (xvw->widget)) + { + wdesc = gtk_widget_get_window (xvw->widget); + gdk_window_set_cursor (wdesc, xvw->cursor); + } +#endif } } } @@ -904,6 +1029,7 @@ run_file_chooser_cb (WebKitWebView *webview, return TRUE; } +#ifdef HAVE_X_WINDOWS static void xwidget_button_1 (struct xwidget_view *view, @@ -1173,6 +1299,8 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event) gdk_event_free (xg_event); } +#endif /* HAVE_X_WINDOWS */ + static void synthesize_focus_in_event (GtkWidget *offscreen_window) { @@ -1198,6 +1326,7 @@ synthesize_focus_in_event (GtkWidget *offscreen_window) gdk_event_free (focus_event); } +#ifdef HAVE_X_WINDOWS struct xwidget_view * xwidget_view_from_window (Window wdesc) { @@ -1209,16 +1338,24 @@ xwidget_view_from_window (Window wdesc) return XXWIDGET_VIEW (xwv); } +#endif static void xwidget_show_view (struct xwidget_view *xv) { xv->hidden = false; +#ifdef HAVE_X_WINDOWS XMoveWindow (xv->dpy, xv->wdesc, xv->x + xv->clip_left, xv->y + xv->clip_top); XMapWindow (xv->dpy, xv->wdesc); XFlush (xv->dpy); +#else + gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (xv->frame)), + xv->widget, xv->x + xv->clip_left, + xv->y + xv->clip_top); + gtk_widget_show_all (xv->widget); +#endif } /* Hide an xwidget view. */ @@ -1226,10 +1363,15 @@ static void xwidget_hide_view (struct xwidget_view *xv) { xv->hidden = true; +#ifdef HAVE_X_WINDOWS XUnmapWindow (xv->dpy, xv->wdesc); XFlush (xv->dpy); +#else + gtk_widget_hide (xv->widget); +#endif } +#ifndef HAVE_PGTK static void xv_do_draw (struct xwidget_view *xw, struct xwidget *w) { @@ -1261,6 +1403,37 @@ xv_do_draw (struct xwidget_view *xw, struct xwidget *w) unblock_input (); } +#else +static void +xwidget_view_draw_cb (GtkWidget *widget, cairo_t *cr, + gpointer data) +{ + struct xwidget_view *view = data; + struct xwidget *w = XXWIDGET (view->model); + GtkOffscreenWindow *wnd; + cairo_surface_t *surface; + + if (NILP (w->buffer)) + return; + + block_input (); + wnd = GTK_OFFSCREEN_WINDOW (w->widgetwindow_osr); + surface = gtk_offscreen_window_get_surface (wnd); + + cairo_save (cr); + if (surface) + { + cairo_translate (cr, -view->clip_left, + -view->clip_top); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + } + cairo_restore (cr); + + unblock_input (); +} +#endif /* When the off-screen webkit master view changes this signal is called. It copies the bitmap from the off-screen instance. */ @@ -1276,9 +1449,12 @@ offscreen_damage_event (GtkWidget *widget, GdkEvent *event, if (XWIDGET_VIEW_P (XCAR (tail))) { struct xwidget_view *view = XXWIDGET_VIEW (XCAR (tail)); - +#ifdef HAVE_X_WINDOWS if (view->wdesc && XXWIDGET (view->model) == xwidget) xv_do_draw (view, XXWIDGET (view->model)); +#else + gtk_widget_queue_draw (view->widget); +#endif } } @@ -1287,6 +1463,7 @@ offscreen_damage_event (GtkWidget *widget, GdkEvent *event, return FALSE; } +#ifdef HAVE_X_WINDOWS void xwidget_expose (struct xwidget_view *xv) { @@ -1294,6 +1471,7 @@ xwidget_expose (struct xwidget_view *xv) xv_do_draw (xv, xw); } +#endif #endif /* USE_GTK */ void @@ -1754,7 +1932,7 @@ xwidget_init_view (struct xwidget *xww, XSETWINDOW (xv->w, s->w); XSETXWIDGET (xv->model, xww); -#ifdef USE_GTK +#ifdef HAVE_X_WINDOWS xv->dpy = FRAME_X_DISPLAY (s->f); xv->x = x; @@ -1766,6 +1944,32 @@ xwidget_init_view (struct xwidget *xww, xv->clip_bottom = xww->height; xv->wdesc = None; + xv->frame = s->f; + xv->cursor = cursor_for_hit (xww->hit_result, s->f); + xv->just_resized = false; +#elif defined HAVE_PGTK + xv->dpyinfo = FRAME_DISPLAY_INFO (s->f); + xv->widget = gtk_drawing_area_new (); + gtk_widget_set_app_paintable (xv->widget, TRUE); + gtk_widget_add_events (xv->widget, GDK_ALL_EVENTS_MASK); + gtk_container_add (GTK_CONTAINER (FRAME_GTK_WIDGET (s->f)), + xv->widget); + + g_signal_connect (xv->widget, "draw", + G_CALLBACK (xwidget_view_draw_cb), xv); + g_signal_connect (xv->widget, "event", + G_CALLBACK (xw_forward_event_from_view), xv); + + g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET_VIEW, xv); + + xv->x = x; + xv->y = y; + + xv->clip_left = 0; + xv->clip_right = xww->width; + xv->clip_top = 0; + xv->clip_bottom = xww->height; + xv->frame = s->f; xv->cursor = cursor_for_hit (xww->hit_result, s->f); xv->just_resized = false; @@ -1847,13 +2051,13 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) bool moved = (xv->x + xv->clip_left != x + clip_left || xv->y + xv->clip_top != y + clip_top); -#ifdef USE_GTK +#ifdef HAVE_X_WINDOWS bool wdesc_was_none = xv->wdesc == None; #endif xv->x = x; xv->y = y; -#ifdef USE_GTK +#ifdef HAVE_X_WINDOWS block_input (); if (xv->wdesc == None) { @@ -1905,16 +2109,25 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) moved = false; } #endif +#ifdef HAVE_PGTK + block_input (); +#endif /* Has it moved? */ if (moved) { -#ifdef USE_GTK +#ifdef HAVE_X_WINDOWS XMoveResizeWindow (xv->dpy, xv->wdesc, x + clip_left, y + clip_top, clip_right - clip_left, clip_bottom - clip_top); XFlush (xv->dpy); cairo_xlib_surface_set_size (xv->cr_surface, clip_right - clip_left, clip_bottom - clip_top); +#elif defined HAVE_PGTK + gtk_widget_set_size_request (xv->widget, clip_right - clip_left, + clip_bottom - clip_top); + gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (xv->frame)), + xv->widget, x + clip_left, y + clip_top); + gtk_widget_queue_allocate (xv->widget); #elif defined NS_IMPL_COCOA nsxwidget_move_view (xv, x + clip_left, y + clip_top); #endif @@ -1930,6 +2143,7 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) || xv->clip_top != clip_top || xv->clip_left != clip_left) { #ifdef USE_GTK +#ifdef HAVE_X_WINDOWS if (!wdesc_was_none && !moved) { if (clip_right - clip_left <= 0 @@ -1947,6 +2161,12 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) cairo_xlib_surface_set_size (xv->cr_surface, clip_right - clip_left, clip_bottom - clip_top); } +#else + gtk_widget_set_size_request (xv->widget, clip_right - clip_left, + clip_bottom - clip_top); + gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (xv->frame)), + xv->widget, x + clip_left, y + clip_top); +#endif #elif defined NS_IMPL_COCOA nsxwidget_resize_view (xv, clip_right - clip_left, clip_bottom - clip_top); @@ -1975,7 +2195,7 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) #endif } } -#ifdef USE_GTK +#ifdef HAVE_X_WINDOWS else { XSetWindowBackground (xv->dpy, xv->wdesc, @@ -2324,7 +2544,7 @@ DEFUN ("delete-xwidget-view", #ifdef USE_GTK struct xwidget *xw = XXWIDGET (xv->model); GdkWindow *w; - +#ifdef HAVE_X_WINDOWS if (xv->wdesc != None) { block_input (); @@ -2334,6 +2554,9 @@ DEFUN ("delete-xwidget-view", Fremhash (make_fixnum (xv->wdesc), x_window_to_xwv_map); unblock_input (); } +#else + gtk_widget_destroy (xv->widget); +#endif if (xw->embedder_view == xv && !NILP (xw->buffer)) { @@ -2925,8 +3148,8 @@ syms_of_xwidget (void) internal_xwidget_view_list = Qnil; staticpro (&internal_xwidget_view_list); -#ifdef USE_GTK - x_window_to_xwv_map = CALLN (Fmake_hash_table, QCtest, Qeq); +#ifdef HAVE_X_WINDOWS + x_window_to_xwv_map = CALLN (Fmake_hash_table, QCtest,); Qeq staticpro (&x_window_to_xwv_map); #endif @@ -3115,7 +3338,7 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix) } } -#ifdef USE_GTK +#ifdef HAVE_X_WINDOWS void lower_frame_xwidget_views (struct frame *f) { @@ -3129,6 +3352,7 @@ lower_frame_xwidget_views (struct frame *f) XLowerWindow (xv->dpy, xv->wdesc); } } +#endif void kill_frame_xwidget_views (struct frame *f) @@ -3146,7 +3370,6 @@ kill_frame_xwidget_views (struct frame *f) for (; CONSP (rem); rem = XCDR (rem)) Fdelete_xwidget_view (XCAR (rem)); } -#endif static void kill_xwidget (struct xwidget *xw) diff --git a/src/xwidget.h b/src/xwidget.h index a03006fde9..ef56dfa7c5 100644 --- a/src/xwidget.h +++ b/src/xwidget.h @@ -32,8 +32,12 @@ struct window; #if defined (USE_GTK) #include +#ifndef HAVE_PGTK #include #include "xterm.h" +#else +#include "pgtkterm.h" +#endif #elif defined (NS_IMPL_COCOA) && defined (__OBJC__) #import #import "nsxwidget.h" @@ -107,8 +111,13 @@ struct xwidget_view enum glyph_row_area area; #if defined (USE_GTK) +#ifndef HAVE_PGTK Display *dpy; Window wdesc; +#else + struct pgtk_display_info *dpyinfo; + GtkWidget *widget; +#endif Emacs_Cursor cursor; struct frame *frame; @@ -190,7 +199,9 @@ extern struct xwidget *xwidget_from_id (uint32_t id); struct xwidget_view *xwidget_view_from_window (Window wdesc); void xwidget_expose (struct xwidget_view *xv); extern void lower_frame_xwidget_views (struct frame *f); +#endif extern void kill_frame_xwidget_views (struct frame *f); +#ifdef HAVE_X_WINDOWS extern void xwidget_button (struct xwidget_view *, bool, int, int, int, int, Time); extern void xwidget_motion_or_crossing (struct xwidget_view *, commit 1e6c7cfd0beed5937dfb1ba4ad805666b19ea23e Author: Stefan Kangas Date: Wed Dec 29 01:21:34 2021 +0100 ; * doc/misc/gnus.texi (Server Commands): Fix typo. diff --git a/doc/misc/gnus.texi b/doc/misc/gnus.texi index 49b6ab515f..98b296c376 100644 --- a/doc/misc/gnus.texi +++ b/doc/misc/gnus.texi @@ -13477,7 +13477,7 @@ Also @pxref{Formatting Variables}. @subsection Server Commands @cindex server commands -The following key binding are available in the server buffer. Be aware +The following key bindings are available in the server buffer. Be aware that some of the commands will only work on servers that you've added through this interface (with @kbd{a}), not with servers you've defined in your init files. commit 18b680cfd177e877991be2bd70ead628bbdc0aa0 Author: Sam Steingold Date: Tue Dec 28 17:27:41 2021 -0500 Fix bug#52467 by adding a new custom variable 'display-comint-buffer-action' * lisp/window.el (display-comint-buffer-action): New `defcustom`, defaults to 'display-buffer-same-window' for backward compatibility. * lisp/cmuscheme.el (run-scheme, switch-to-scheme): Pass 'display-comint-buffer-action' to 'pop-to-buffer' instead of using 'pop-to-buffer-same-window'. * lisp/eshell/eshell.el (eshell): Likewise. * lisp/shell.el (shell): Likewise. * lisp/org/ol-eshell.el (org-eshell-open): Likewise. * lisp/progmodes/inf-lisp.el (inferior-lisp): Likewise. * lisp/progmodes/project.el (project-shell, project-eshell): Likewise. * lisp/textmodes/tex-mode.el (tex-display-shell, tex-compile-default) (tex-recenter-output-buffer): Pass 'display-comint-buffer-action' to 'pop-to-buffer'. diff --git a/lisp/cmuscheme.el b/lisp/cmuscheme.el index 47113ad8c2..acc0888907 100644 --- a/lisp/cmuscheme.el +++ b/lisp/cmuscheme.el @@ -237,7 +237,7 @@ is run). (inferior-scheme-mode))) (setq scheme-program-name cmd) (setq scheme-buffer "*scheme*") - (pop-to-buffer-same-window "*scheme*")) + (pop-to-buffer "*scheme*" display-comint-buffer-action)) (defun scheme-start-file (prog) "Return the name of the start file corresponding to PROG. @@ -357,7 +357,7 @@ With argument, position cursor at end of buffer." (interactive "P") (if (or (and scheme-buffer (get-buffer scheme-buffer)) (scheme-interactively-start-process)) - (pop-to-buffer-same-window scheme-buffer) + (pop-to-buffer scheme-buffer display-comint-buffer-action) (error "No current process buffer. See variable `scheme-buffer'")) (when eob-p (push-mark) diff --git a/lisp/eshell/eshell.el b/lisp/eshell/eshell.el index c66ad00072..47fdfa095f 100644 --- a/lisp/eshell/eshell.el +++ b/lisp/eshell/eshell.el @@ -260,7 +260,7 @@ information on Eshell, see Info node `(eshell)Top'." (t (get-buffer-create eshell-buffer-name))))) (cl-assert (and buf (buffer-live-p buf))) - (pop-to-buffer-same-window buf) + (pop-to-buffer buf display-comint-buffer-action) (unless (derived-mode-p 'eshell-mode) (eshell-mode)) buf)) diff --git a/lisp/org/ol-eshell.el b/lisp/org/ol-eshell.el index a7550e3769..b13f659b22 100644 --- a/lisp/org/ol-eshell.el +++ b/lisp/org/ol-eshell.el @@ -46,7 +46,7 @@ followed by a colon." (eshell-buffer-name (car buffer-and-command)) (command (cadr buffer-and-command))) (if (get-buffer eshell-buffer-name) - (pop-to-buffer-same-window eshell-buffer-name) + (pop-to-buffer eshell-buffer-name display-comint-buffer-action) (eshell)) (goto-char (point-max)) (eshell-kill-input) diff --git a/lisp/progmodes/inf-lisp.el b/lisp/progmodes/inf-lisp.el index e69a9ff394..2d2061e7cf 100644 --- a/lisp/progmodes/inf-lisp.el +++ b/lisp/progmodes/inf-lisp.el @@ -308,7 +308,7 @@ quoted using shell quote syntax. "inferior-lisp" (car cmdlist) nil (cdr cmdlist))) (inferior-lisp-mode))) (setq inferior-lisp-buffer "*inferior-lisp*") - (pop-to-buffer-same-window "*inferior-lisp*")) + (pop-to-buffer "*inferior-lisp*" display-comint-buffer-action)) ;;;###autoload (defalias 'run-lisp 'inferior-lisp) diff --git a/lisp/progmodes/project.el b/lisp/progmodes/project.el index 3b634471ac..62dba7b393 100644 --- a/lisp/progmodes/project.el +++ b/lisp/progmodes/project.el @@ -1015,7 +1015,7 @@ if one already exists." (default-project-shell-name (project-prefixed-buffer-name "shell")) (shell-buffer (get-buffer default-project-shell-name))) (if (and shell-buffer (not current-prefix-arg)) - (pop-to-buffer-same-window shell-buffer) + (pop-to-buffer shell-buffer display-comint-buffer-action) (shell (generate-new-buffer-name default-project-shell-name))))) ;;;###autoload @@ -1031,7 +1031,7 @@ if one already exists." (eshell-buffer-name (project-prefixed-buffer-name "eshell")) (eshell-buffer (get-buffer eshell-buffer-name))) (if (and eshell-buffer (not current-prefix-arg)) - (pop-to-buffer-same-window eshell-buffer) + (pop-to-buffer eshell-buffer display-comint-buffer-action) (eshell t)))) ;;;###autoload diff --git a/lisp/shell.el b/lisp/shell.el index 370532ea46..1860e4691d 100644 --- a/lisp/shell.el +++ b/lisp/shell.el @@ -758,7 +758,7 @@ Make the shell buffer the current buffer, and return it. (current-buffer))) ;; The buffer's window must be correctly set when we call comint ;; (so that comint sets the COLUMNS env var properly). - (pop-to-buffer-same-window buffer) + (pop-to-buffer buffer) (with-connection-local-variables ;; On remote hosts, the local `shell-file-name' might be useless. diff --git a/lisp/textmodes/tex-mode.el b/lisp/textmodes/tex-mode.el index 5fba93c76e..0c112b2ecf 100644 --- a/lisp/textmodes/tex-mode.el +++ b/lisp/textmodes/tex-mode.el @@ -2037,7 +2037,7 @@ In the tex shell buffer this command behaves like `comint-send-input'." (defun tex-display-shell () "Make the TeX shell buffer visible in a window." - (display-buffer (tex-shell-buf)) + (display-buffer (tex-shell-buf) display-comint-buffer-action) (tex-recenter-output-buffer nil)) (defun tex-shell-sentinel (proc _msg) @@ -2441,7 +2441,7 @@ Only applies the FSPEC to the args part of FORMAT." (if cmds (tex-format-cmd (caar cmds) fspec)))))) (defun tex-cmd-doc-view (file) - (pop-to-buffer (find-file-noselect file))) + (pop-to-buffer (find-file-noselect file) display-comint-buffer-action)) (defun tex-compile (dir cmd) "Run a command CMD on current TeX buffer's file in DIR." @@ -2698,7 +2698,7 @@ line LINE of the window, or centered if LINE is nil." (window)) (if (null tex-shell) (message "No TeX output buffer") - (setq window (display-buffer tex-shell)) + (setq window (display-buffer tex-shell display-comint-buffer-action)) (with-selected-window window (bury-buffer tex-shell) (goto-char (point-max)) diff --git a/lisp/window.el b/lisp/window.el index aff99d36c5..d75dd9931b 100644 --- a/lisp/window.el +++ b/lisp/window.el @@ -7474,6 +7474,14 @@ ALIST. See `display-buffer' for details." :version "24.1" :group 'windows) +(defcustom display-comint-buffer-action 'display-buffer-same-window + "The action to display a comint buffer." + :type 'display-buffer--action-function-custom-type + :risky t + :version "29.1" + :group 'windows + :group 'comint) + (defconst display-buffer-fallback-action '((display-buffer--maybe-same-window ;FIXME: why isn't this redundant? display-buffer-reuse-window commit 6e52becfbe2a33c025b8c4838b3c8f06ba5a6fb8 Author: Philipp Stephani Date: Tue Dec 28 21:05:23 2021 +0100 Fix test lisp/cedet/semantic/bovine/gcc-tests on macOS (Bug#52431) * test/lisp/cedet/semantic/bovine/gcc-tests.el (semantic-gcc-test-output-parser-this-machine): Also detect Apple clang on macOS Monterey. diff --git a/test/lisp/cedet/semantic/bovine/gcc-tests.el b/test/lisp/cedet/semantic/bovine/gcc-tests.el index ba84ce4d81..04a02ec03b 100644 --- a/test/lisp/cedet/semantic/bovine/gcc-tests.el +++ b/test/lisp/cedet/semantic/bovine/gcc-tests.el @@ -128,7 +128,7 @@ gcc version 2.95.2 19991024 (release)" ;; We can't even check if it's a symlink; it's a binary placed in ;; "/usr/bin/gcc". So check the output and just skip this test if ;; it looks like that's the case. - (unless (string-match "Apple LLVM\\|Xcode.app" + (unless (string-match "Apple \\(LLVM\\|clang\\)\\|Xcode\\.app" (car semantic-gcc-test-strings)) (semantic-gcc-test-output-parser)))) commit 2033f950fa37e9177c07eee0f5cab8a0eda37c4b Author: Juri Linkov Date: Tue Dec 28 21:51:54 2021 +0200 * lisp/textmodes/paragraphs.el (repunctuate-sentences): Region for NO-QUERY. Use region boundaries also for the case when NO-QUERY arg is non-nil (bug#52769). diff --git a/lisp/textmodes/paragraphs.el b/lisp/textmodes/paragraphs.el index 98362b8579..acb26fd1c1 100644 --- a/lisp/textmodes/paragraphs.el +++ b/lisp/textmodes/paragraphs.el @@ -492,8 +492,10 @@ asking for confirmation." (let ((regexp "\\([]\"')]?\\)\\([.?!]\\)\\([]\"')]?\\) +") (to-string "\\1\\2\\3 ")) (if no-query - (while (re-search-forward regexp nil t) - (replace-match to-string)) + (progn + (when start (goto-char start)) + (while (re-search-forward regexp end t) + (replace-match to-string))) (query-replace-regexp regexp to-string nil start end)))) commit af92c526699daba6246420a396c086085417c4d3 Author: Juri Linkov Date: Tue Dec 28 21:19:25 2021 +0200 * lisp/textmodes/paragraphs.el (repunctuate-sentences): Support region. Add optional args 'start' and 'end', and pass them as region boundaries to query-replace-regexp (bug#52769). diff --git a/lisp/textmodes/paragraphs.el b/lisp/textmodes/paragraphs.el index 59b15e82a8..98362b8579 100644 --- a/lisp/textmodes/paragraphs.el +++ b/lisp/textmodes/paragraphs.el @@ -479,18 +479,22 @@ sentences. Also, every paragraph boundary terminates sentences as well." (setq arg (1- arg))) (constrain-to-field nil opoint t))) -(defun repunctuate-sentences (&optional no-query) +(defun repunctuate-sentences (&optional no-query start end) "Put two spaces at the end of sentences from point to the end of buffer. -It works using `query-replace-regexp'. +It works using `query-replace-regexp'. In Transient Mark mode, +if the mark is active, operate on the contents of the region. +Second and third arg START and END specify the region to operate on. If optional argument NO-QUERY is non-nil, make changes without asking for confirmation." - (interactive) + (interactive (list nil + (if (use-region-p) (region-beginning)) + (if (use-region-p) (region-end)))) (let ((regexp "\\([]\"')]?\\)\\([.?!]\\)\\([]\"')]?\\) +") (to-string "\\1\\2\\3 ")) (if no-query (while (re-search-forward regexp nil t) (replace-match to-string)) - (query-replace-regexp regexp to-string)))) + (query-replace-regexp regexp to-string nil start end)))) (defun backward-sentence (&optional arg) commit e066db238139670c6a2cfb2436fabbdeddf211e9 Author: Juri Linkov Date: Tue Dec 28 21:14:55 2021 +0200 * lisp/replace.el (replace-regexp-function): New function (bug#52558). (replace-search, replace-highlight): Use it. diff --git a/lisp/replace.el b/lisp/replace.el index 0e81b15a09..2e877305c0 100644 --- a/lisp/replace.el +++ b/lisp/replace.el @@ -2621,6 +2621,11 @@ It is used by `query-replace-regexp', `replace-regexp', It is called with three arguments, as if it were `re-search-forward'.") +(defvar replace-regexp-function nil + "Function to convert a search string to a regexp to replace. +It's bound to `isearch-regexp-function' when searching +for a string to replace.") + (defun replace-search (search-string limit regexp-flag delimited-flag case-fold &optional backward) "Search for the next occurrence of SEARCH-STRING to replace." @@ -2633,7 +2638,8 @@ It is called with three arguments, as if it were ;; outside of this function because then another I-search ;; used after `recursive-edit' might override them. (let* ((isearch-regexp regexp-flag) - (isearch-regexp-function (or delimited-flag + (isearch-regexp-function (or replace-regexp-function + delimited-flag (and replace-char-fold (not regexp-flag) #'char-fold-to-regexp))) @@ -2690,7 +2696,8 @@ It is called with three arguments, as if it were (if query-replace-lazy-highlight (let ((isearch-string search-string) (isearch-regexp regexp-flag) - (isearch-regexp-function (or delimited-flag + (isearch-regexp-function (or replace-regexp-function + delimited-flag (and replace-char-fold (not regexp-flag) #'char-fold-to-regexp))) commit d3bc520513131b53d4f82dde295837a33dca200a Author: Eli Zaretskii Date: Tue Dec 28 20:09:42 2021 +0200 ; * lisp/term.el (term-goto-process-mark-maybe): Fix typo in doc string. diff --git a/lisp/term.el b/lisp/term.el index 5961350ff9..cb13f60c1d 100644 --- a/lisp/term.el +++ b/lisp/term.el @@ -3301,7 +3301,7 @@ Called as a buffer-local `post-command-hook' function in an inconsistent state by unexpectedly moving point. Mouse and wheel events are ignored so that mouse selection and -mouse wheel scrolling is unimpeded. +mouse wheel scrolling are unimpeded. Only acts when the pre-command position of point was equal to the process mark, and the `term-char-mode-point-at-process-mark' commit 8276605efb09abf8f86dad56f5c43fa57e5c1bd7 Author: Eli Zaretskii Date: Tue Dec 28 20:07:54 2021 +0200 ; * lisp/keymap.el (key-valid-p): Fix wording of doc string. diff --git a/lisp/keymap.el b/lisp/keymap.el index 734cbe89cd..25288013cf 100644 --- a/lisp/keymap.el +++ b/lisp/keymap.el @@ -297,7 +297,7 @@ See `kbd' for a descripion of KEYS." (defun key-valid-p (keys) "Say whether KEYS is a valid key. A key is a string consisting of one or more key strokes. -The key strokes are separated by a space character. +The key strokes are separated by space characters. Each key stroke is either a single character, or the name of an event, surrounded by angle brackets. In addition, any key stroke commit 498787e5119b4ad0f316b5f8cd426bedc40dad7c Author: Eli Zaretskii Date: Tue Dec 28 20:02:07 2021 +0200 ; * doc/emacs/search.texi (Lax Search): Fix wording. diff --git a/doc/emacs/search.texi b/doc/emacs/search.texi index c3b3d9a0b1..fae016531f 100644 --- a/doc/emacs/search.texi +++ b/doc/emacs/search.texi @@ -1451,10 +1451,10 @@ letter @code{a} as well as all the other variants like @code{@'a}. @vindex char-fold-override You can add new foldings using the customizable variable @code{char-fold-include}, or remove the existing ones using the -customizable variable @code{char-fold-exclude}. Also you can -customize @code{char-fold-override} to @code{t} to disable default -character equivalences, so you can add only your own equivalences -using @code{char-fold-include}. +customizable variable @code{char-fold-exclude}. You can also +customize @code{char-fold-override} to @code{t} to disable all the +character equivalences except those you add yourself using +@code{char-fold-include}. @node Replace @section Replacement Commands commit 5403dcf699688475bb64d093fd6320c1e28ec6e0 Author: Eli Zaretskii Date: Tue Dec 28 19:53:42 2021 +0200 ; * etc/NEWS: Fix punctuation. diff --git a/etc/NEWS b/etc/NEWS index 3f2bae2d9a..96e95967ef 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -88,7 +88,7 @@ time. * Incompatible changes in Emacs 29.1 --- -** Support for old EIEIO functions is not autoloaded any more +** Support for old EIEIO functions is not autoloaded any more. You need an explicit (require 'eieio-compat) to use 'defmethod' and 'defgeneric' (which have been made obsolete in Emacs-25 with 'cl-defmethod' and 'cl-defgeneric'). commit 06dcd2be5d42362757e923bc5d1952a2bce509b9 (refs/remotes/origin/emacs-28) Author: Sean Whitton Date: Mon Dec 27 12:58:25 2021 -0700 Improve rectangle-mark-mode documentation regarding mark activation * doc/emacs/killing.texi: Describe how rectangle-mark-mode works when Transient Mark mode is off. Qualify discussion of rectangle-exchange-point-and-mark to say that it cycles the four corners only when the region is active. * lisp/rect.el (rectangle-mark-mode): State that rectangle-mark-mode does not activate the mark when Transient Mark mode is off. Reword sentence about how long the mode lasts to account for when Transient Mark mode is off. (Bug#42663) diff --git a/doc/emacs/killing.texi b/doc/emacs/killing.texi index 6e4fd77e8b..37243b6cd2 100644 --- a/doc/emacs/killing.texi +++ b/doc/emacs/killing.texi @@ -921,6 +921,11 @@ so in a rectangular fashion, and killing and yanking operate on the rectangle. @xref{Killing}. The mode persists only as long as the region is active. +The region-rectangle works only when the mark is active. In +particular, when Transient Mark mode is off (@pxref{Disabled Transient +Mark}), in addition to typing @kbd{C-x @key{SPC}} you will need to +activate the mark. + Unlike the standard region, the region-rectangle can have its corners extended past the end of buffer, or inside stretches of white space that point normally cannot enter, like in the middle of a TAB @@ -929,11 +934,12 @@ character. @findex rectangle-exchange-point-and-mark @findex exchange-point-and-mark@r{, in rectangle-mark-mode} @kindex C-x C-x@r{, in rectangle-mark-mode} -When the region is in rectangle-mark-mode, @kbd{C-x C-x} runs the -command @code{rectangle-exchange-point-and-mark}, which cycles between -the four corners of the region-rectangle. This comes in handy if you -want to modify the dimensions of the region-rectangle before invoking -an operation on the marked text. +When the region is active (@pxref{Mark}) and in rectangle-mark-mode, +@kbd{C-x C-x} runs the command +@code{rectangle-exchange-point-and-mark}, which cycles between the +four corners of the region-rectangle. This comes in handy if you want +to modify the dimensions of the region-rectangle before invoking an +operation on the marked text. @node CUA Bindings @section CUA Bindings diff --git a/lisp/rect.el b/lisp/rect.el index d288adfbaf..80f992e182 100644 --- a/lisp/rect.el +++ b/lisp/rect.el @@ -651,7 +651,8 @@ with a prefix argument, prompt for START-AT and FORMAT." (define-minor-mode rectangle-mark-mode "Toggle the region as rectangular. -Activates the region if needed. Only lasts until the region is deactivated." +Activates the region if it's inactive and Transient Mark mode is +on. Only lasts until the region is next deactivated." :lighter nil (rectangle--reset-crutches) (when rectangle-mark-mode commit e7699bf290926936a3357ada280d3a843f00af23 Author: Andrea Corallo Date: Tue Dec 28 12:12:16 2021 +0100 * Fix native comp for non trivial function names (bug#52833) * lisp/emacs-lisp/comp.el (comp-c-func-name): Fix native compilation for functions with function names containing non trivial characters (bug#52833). diff --git a/lisp/emacs-lisp/comp.el b/lisp/emacs-lisp/comp.el index b51224088f..ea52aba5d3 100644 --- a/lisp/emacs-lisp/comp.el +++ b/lisp/emacs-lisp/comp.el @@ -1181,7 +1181,9 @@ clashes." for i across orig-name for byte = (format "%x" i) do (aset str j (aref byte 0)) - (aset str (1+ j) (aref byte 1)) + (aset str (1+ j) (if (length> byte 1) + (aref byte 1) + ?\_)) finally return str)) (human-readable (string-replace "-" "_" orig-name)) commit e31facd84a125d6481c7bb6fd001429d513e6915 Author: Stefan Monnier Date: Tue Dec 28 09:44:05 2021 -0500 * etc/NEWS (eieio-compat): Rewrite diff --git a/etc/NEWS b/etc/NEWS index 01e1a8e940..3f2bae2d9a 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -88,12 +88,12 @@ time. * Incompatible changes in Emacs 29.1 --- -** Support for old EIEIO functions not is autoloaded any more -You need to explicitly (require 'eieio-compat) if you need to use -the functions `defmethod` and `defgeneric` (which have been made -obsolete in Emacs-25 with `cl-defmethod` and `cl-defgeneric`). -Similarly files that were compiled with an old EIEIO (Emacs<25), -will usually need (require 'eieio-compat). +** Support for old EIEIO functions is not autoloaded any more +You need an explicit (require 'eieio-compat) to use 'defmethod' +and 'defgeneric' (which have been made obsolete in Emacs-25 with +'cl-defmethod' and 'cl-defgeneric'). +Similarly you might need to (require 'eieio-compat) before loading +files that were compiled with an old EIEIO (Emacs<25). --- ** 'C-x 8 .' has been moved to 'C-x 8 . .'. commit d257d92d17c5bfe5317973c5fadd8b5295174a1b Author: Po Lu Date: Tue Dec 28 17:53:20 2021 +0800 * lwlib/xlwmenu.c (fit_to_screen): Adjust correctly for child menus. diff --git a/lwlib/xlwmenu.c b/lwlib/xlwmenu.c index a065c53310..68b0a2f5fe 100644 --- a/lwlib/xlwmenu.c +++ b/lwlib/xlwmenu.c @@ -1392,23 +1392,28 @@ fit_to_screen (XlwMenuWidget mw, { int screen_width, screen_height; int screen_x, screen_y; + int prev_screen_x, prev_screen_y; #ifdef emacs + xlw_monitor_dimensions_at_pos (XtDisplay (mw), XtScreen (mw), + previous_ws->x, previous_ws->y, + &prev_screen_x, &prev_screen_y, + &screen_width, &screen_height); xlw_monitor_dimensions_at_pos (XtDisplay (mw), XtScreen (mw), ws->x, ws->y, &screen_x, &screen_y, &screen_width, &screen_height); #else screen_width = WidthOfScreen (XtScreen (mw)); screen_height = HeightOfScreen (XtScreen (mw)); - screen_x = 0; - screen_y = 0; + prev_screen_x = screen_x = 0; + prev_screen_y = screen_y = 0; #endif /* 1 if we are unable to avoid an overlap between this menu and the parent menu in the X dimension. */ int horizontal_overlap = 0; if (ws->x < screen_x) - ws->x = 0; + ws->x = screen_x; else if (ws->x + ws->width > screen_x + screen_width) { if (!horizontal_p) @@ -1417,6 +1422,7 @@ fit_to_screen (XlwMenuWidget mw, the right of the invoking menu-item; it makes the sub-menu look more `attached' to the menu-item. */ ws->x = screen_x + (previous_ws->x + - prev_screen_x - ws->width + mw->menu.shadow_thickness); else @@ -1445,7 +1451,9 @@ fit_to_screen (XlwMenuWidget mw, else if (ws->y + ws->height > screen_y + screen_height) { if (horizontal_p) - ws->y = screen_y + (previous_ws->y - ws->height); + ws->y = screen_y + (previous_ws->y + - prev_screen_y + - ws->height); else ws->y = screen_y + (screen_height - ws->height); if (ws->y < screen_y) commit a17a11df04fcc5e48330e92d6f33f0a40655e5af Author: Juri Linkov Date: Tue Dec 28 10:45:27 2021 +0200 * lisp/vc/vc.el (vc-revert): Use generate-new-buffer, not just new buffer name diff --git a/lisp/vc/vc.el b/lisp/vc/vc.el index 64f752f248..ba94d908d1 100644 --- a/lisp/vc/vc.el +++ b/lisp/vc/vc.el @@ -2755,7 +2755,7 @@ to the working revision (except for keyword expansion)." (unwind-protect (when (if vc-revert-show-diff (progn - (setq diff-buffer (generate-new-buffer-name "*vc-diff*")) + (setq diff-buffer (generate-new-buffer "*vc-diff*")) (vc-diff-internal vc-allow-async-revert vc-fileset nil nil nil diff-buffer)) ;; Avoid querying the user again.