From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 29 Oct 2021 04:32:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: report 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 51473@debbugs.gnu.org X-Debbugs-Original-To: bug-gnu-emacs@gnu.org Received: via spool by submit@debbugs.gnu.org id=B.163548187028227 (code B ref -1); Fri, 29 Oct 2021 04:32:01 +0000 Received: (at submit) by debbugs.gnu.org; 29 Oct 2021 04:31:10 +0000 Received: from localhost ([127.0.0.1]:53747 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mgJXn-0007L9-2i for submit@debbugs.gnu.org; Fri, 29 Oct 2021 00:31:10 -0400 Received: from lists.gnu.org ([209.51.188.17]:44470) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mgJXi-0007Ks-99 for submit@debbugs.gnu.org; Fri, 29 Oct 2021 00:31:06 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:50540) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mgJXh-00033a-NS for bug-gnu-emacs@gnu.org; Fri, 29 Oct 2021 00:31:02 -0400 Received: from sonic304-20.consmr.mail.ne1.yahoo.com ([66.163.191.146]:41391) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1mgJXe-0007Up-DQ for bug-gnu-emacs@gnu.org; Fri, 29 Oct 2021 00:31:01 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635481856; bh=M9jlSGiQ5ttmM+YxY7RZ2yN8grjviVnlQzAmygiOIq0=; h=From:To:Subject:Date:References:From:Subject:Reply-To; b=TttAfSZ77R59Kq2bwXvaro3AngbFV6QnToHDrvDAAsQDY1I2ZjHcMiVAdnsQhLJh2MlOyDdX5jkU/4AZwmhXH1WiDJ2RT6i3O2ktWK5w4xO7ixqxrEQ6e5G0LeHgYVqnebqgQC7e8Ju3XZD2JnaOo6xepFFDKFP5Bi0pJ76rramUyAByM0w3bkV2MhTCqlhLcAkpc+aI/OIMmccS3RTxIQY02OBqDbEXQxPRayKh5PH9RolEACZ3gKZsluWPnmjdU31GKPw+Ch7NTs8QyALyopUwMes69kegn6wAtVx6V+69ssvUdX7k/wPeLo845ekZPZ0KiENndJnlXuWUou7FAw== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635481856; bh=0GRlMDuenKVN6CM2pK/rbADigqzF6NqeEQ/AYYgLoft=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=o53XY3VmopfxYdD4nFlI6ZyuCvUtQSAbg63ohyvt8Ivqm6HymcsX6321Lpu0a+BdzIEMZg8wXKxRMdXFvx4osTPyJ6FwXdLFjh8yBxMiIbUAVy5RS63Fsmy+fuYW0wJlMEAXZc9NoTqLlBdLezKgRYNc/25DzHIg4kgzYYuJLF5v4bqD8usaYGj7TMLyuccIv3HaFHbRvoKadk9InQ8DfyhXLrShYHMcBls9BlQuzn46pxBc8htCe63Axjby55YNOce5B6SzcTW/eDml65Fw85FseBIxfrErzIwSaYennHdpWoY4cXNO5Ls15WL5JIBV2QLafSI2wN6beX910I4orw== X-YMail-OSG: o0lGEyAVM1lT6MrSvIvNlIYuheM4ifCTJUcpfCZnrseKAJfiX1v0WF6PNIx0LR8 ZevTjn4VqFPJCX6YbOsprJcc60yTFbXB1aDi0Zc3bTH23YJmB.XmTZEJDIXo.LLw4Fxfz6T3EVX6 uW5U3QJ51B5_OnvyH9geGEL_DeMfcdCDDE6N.AEXtR7.VdbJc04Kha.J1EDdYwfboOikqUwQVh12 rAzfQpucMlGBqlzO5fzVSHfOyBWJMC5P5HQiKJHxWVxchM4rZSW6zbbtV_utqmFjFBqVMQ8t05cz pjo_miOiuCIQ8kHsrYUedtBnVCzRZv.71Cy_JB7xaMWchkMOIO2qzaos1mhyKotpB7gq2DpMbIgn YrEfDqZxFr_AbrA85LIuzC9XupSP9_WDsPpwyBa3WHbjMRg.GMVfwEid8CrjXxaQo7ZR0BU0nyW6 Plhah7PJprUPshSDEu7NKXuiFWJLJ8RQBq.akiLgkW.eiVkP1o9mEIvF9TVNobBPHa9QU1A6TOrN zkuuwLFSLebUpvPBQxoeN3lsskOutpA892rCQJoduWvRlJkM1eEtwFqhNupet.WByC_ZqENdyx1m u34eCDmyryt6MEdAcaZnTHtwv9ipHIrn8A_.Q49G5Img92PAnoCVpidTtTGJ1_aR6EHxfJtFkNUE 34fLJxmbx8swqX.hK25T5YAkC4Zmqfi3VPebeKOIJL6mEBdmoSVgbGANPxfTksb1sJEJFRPfndoH CbYXCkHkEZo9PfB7F8g8qvl1ouMxStsX8PuiUYbJZyGVVUCySW21j6RdJ3TzaD8lDSEWb8JWP0z2 vTMfCRg1pZR3_PRnAboh1KS1u7mxSE.BT5voXuNHmGZxePO1fcQoQ6dycG2aIrCHQHL0KHhGj_8l 8qfC177eRp3RJO0vmSayICjrozDp1ZVyjpx57hrpwJ4thzccC_HfmycGqK4MOiJxqrsaeCRueTvZ TpZAa.r50vuz_BPO.pBOP9_dgYkFKTKutQYaAUzwGjIxraWL06.iSukofua9c51LaiuucCjXmb97 AYDR27Al5IMXHTJ1lxLssGSLjhktH2e6AUip3UkYNFY_atnEpX3S3DfML70YiXR1S503hAZUSSSc 2yxgg97AxYDcEsNNmmBdQPNgikqPq2jpDk875ls7BKyvMG6N45oY3yinzFog09Dk7cuAAEm99uiE 3Npx4QvTV3zoQQK41F3ztamQ1r7XvMfIMOXolAntmWMInKLSF_pZNvpjh4nLnOuk3Oicx2zDjnGa dQ8klY4iPOR5HD3Hr9E2Op7bEDAfPuVwyvAkA3MWVDh8Bs5JgCjsRbB7pz5gwfzk3f959U.VSMR8 0hZtAVrzsc43nAJGuJi0R6clPszG4BidDkgaMbd3p7KJK6qzIB4uIR0K7Fe3Dww99pEeHWM0xavY 3fEKfDpqiZDA9_bbWKsiUAgHRfdWnuCu4kJBlBB4MguymD2ffn0gzV26vGNAbAHFl0tDih2VOhqC m_u2WpOxWoFhSAyVs8nf3I0OfEpXjz0XfR8.UfhjJX4bKUVkBQGaHz2JMTmuGAE6Hv5vYSW2wypn ZC2JxCrFedTD0Z_vStQHwV4.HsP8Yi15fxtbk6hvtbGd7hFEkRLhLRJYc6xQvZB7YLfOHz3UsYnD jLdMXK183pijHNIw.8ET05GaKcXYLRcSAoeZrcOsNzgBBnsSEn6YDICbkKFsjXyItYOwtAU.9bNF 621CFJOpj62kjTtLQ6ChfN5LYiGgIaDaPY3EvGtPr531hhCXxZtKnAJ9wzoHnbS3.Ry_BJR0NRUs CXwYwgmsL7bJE.rzpW.OzTQnYCHTfwpkhDSRWU_KbFfRZzrXmQ000qnxy6XUihGAwhYegcvZx17H R1TR.SW715kh1NZhlAHts8HnM96scix2YSZ1OgzXl1Y1yCxBamuu.33I0SKGrigYU4gO5fL_rV4p aPvJw5wa4NBEB4gOtKaIR5UtgjOKmXIg1X8oSWsIVoNJKh0iloMG74M1LqZkw5FY5W21HgM85IOS nPKq7YszwNxkvxWE9QdU0yq0J6jogjF1Woh3duc4jnv.D2y3suT0j_ZnIG7aMDOWeQKYnkUjrtlz GdBFEoFLDTJ6oJgUZpMDssFsnZ7UFdJNjQuusFzTEnBU_tGPKhAxbyzlVshnCCtvkjNkbKz1bDp9 WRNPPPTFDDpkgSDZ4yET.YjqJHbj6CqQfp5LbbokkFYJFGSFO4nzbgV4E0ieg5fQIo0gmyZL8pzy 4kZkmK16x.pQBB9fjsWlD3JU- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic304.consmr.mail.ne1.yahoo.com with HTTP; Fri, 29 Oct 2021 04:30:56 +0000 Received: by kubenode514.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID febf8a47ece21e54376e4adf1664236f; Fri, 29 Oct 2021 04:30:48 +0000 (UTC) From: Po Lu Date: Fri, 29 Oct 2021 12:30:45 +0800 Message-ID: <87zgqslafe.fsf@yahoo.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" References: <87zgqslafe.fsf.ref@yahoo.com> X-Mailer: WebService/1.1.19198 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 27041 Received-SPF: pass client-ip=66.163.191.146; envelope-from=luangruo@yahoo.com; helo=sonic304-20.consmr.mail.ne1.yahoo.com X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Spam-Score: -0.6 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.6 (-) --=-=-= Content-Type: text/plain The attached changes fix flickering xwidgets by moving xwidget display into a separate X window, and also enable the scrolling optimization for xwidgets. Someone with access to a Mac will have to do the changes necessary for xwidget scrolling to work correctly on macOS, as they don't work on GNUstep in the first place. However, event passthrough doesn't work yet, and will require some thought. But that would be a fantastic opportunity to clean up the current xwidget event handling mess (and perhaps even define a mechanism for Lisp code to send events into xwidgets, which would make integrating them into the existing Emacs event model much easier.) Any thoughts? Thanks. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Use-an-X-window-to-display-xwidgets-on-X11.patch >From 09f3697b2904dac7616697ba252d93e4748f7418 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Thu, 28 Oct 2021 21:46:01 +0800 Subject: [PATCH 1/2] Use an X window to display xwidgets on X11 Since Emacs draws using X11 primitives, Emacs drawing operations can erase the GtkDrawingArea used to draw the offscreen widget, which leads to unpleasant flickering effects, all of which can be prevented by creating a native X window and drawing to that instead. * src/xterm.c (x_window_to_frame): Return xwidget window if appropriate. (handle_one_xevent): Handle xwidget expose events. * src/xwidget.c (x_window_to_xvw_map): New variable. (xwidget_view_from_window): New function. (xwidget_show_view, xwidget_hide_view) (offscreen_damage_event): Move to drawing xwidgets with X windows. (xv_do_draw) (xwidget_expose): New function. (xwidget_osr_draw_cb, xwidget_osr_event_forward) (xwidget_osr_event_set_embedder): Removed. (xwidget_init_view): Replace use of GtkDrawingArea with that of an X window. (x_draw_xwidget_glyph_string): Prevent xwidget views from constantly generating expose events, and use an X window instead of a GtkDrawingArea. (syms_of_xwidget): Initialize x_window_to_xwv_map. src/xwidget.h (struct xwidget_view): Replace GTK widgets with X-related fields. (xwidget_view_from_window, xwidget_expose): New functions. --- src/xterm.c | 24 ++++- src/xwidget.c | 277 ++++++++++++++++++++++++++------------------------ src/xwidget.h | 12 ++- 3 files changed, 175 insertions(+), 138 deletions(-) diff --git a/src/xterm.c b/src/xterm.c index aa1a1a5eed..54bfb65bd0 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -4563,8 +4563,9 @@ x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct fra } } -/* Return the Emacs frame-object corresponding to an X window. - It could be the frame's main window or an icon window. */ +/* Return the Emacs frame-object corresponding to an X window. It + could be the frame's main window, an icon window, or an xwidget + window. */ static struct frame * x_window_to_frame (struct x_display_info *dpyinfo, int wdesc) @@ -4575,6 +4576,13 @@ x_window_to_frame (struct x_display_info *dpyinfo, int wdesc) if (wdesc == None) return NULL; +#ifdef HAVE_XWIDGETS + struct xwidget_view *xvw = xwidget_view_from_window (wdesc); + + if (xvw && xvw->frame) + return xvw->frame; +#endif + FOR_EACH_FRAME (tail, frame) { f = XFRAME (frame); @@ -8211,6 +8219,18 @@ handle_one_xevent (struct x_display_info *dpyinfo, case Expose: f = x_window_to_frame (dpyinfo, event->xexpose.window); +#ifdef HAVE_XWIDGETS + { + struct xwidget_view *xv = + xwidget_view_from_window (event->xexpose.window); + + if (xv) + { + xwidget_expose (xv); + goto OTHER; + } + } +#endif if (f) { if (!FRAME_VISIBLE_P (f)) diff --git a/src/xwidget.c b/src/xwidget.c index e4b42e6e0c..62b30a07ab 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -35,10 +35,16 @@ Copyright (C) 2011-2021 Free Software Foundation, Inc. #ifdef USE_GTK #include #include +#include +#include #elif defined NS_IMPL_COCOA #include "nsxwidget.h" #endif +#ifdef USE_GTK +static Lisp_Object x_window_to_xwv_map; +#endif + static struct xwidget * allocate_xwidget (void) { @@ -222,15 +228,28 @@ xwidget_hidden (struct xwidget_view *xv) } #ifdef USE_GTK + +struct xwidget_view * +xwidget_view_from_window (Window wdesc) +{ + Lisp_Object key = make_fixnum (wdesc); + Lisp_Object xwv = Fgethash (key, x_window_to_xwv_map, Qnil); + + if (NILP (xwv)) + return NULL; + + return XXWIDGET_VIEW (xwv); +} + static void xwidget_show_view (struct xwidget_view *xv) { xv->hidden = false; - gtk_widget_show (xv->widgetwindow); - gtk_fixed_move (GTK_FIXED (xv->emacswindow), - xv->widgetwindow, - xv->x + xv->clip_left, - xv->y + xv->clip_top); + XMoveWindow (xv->dpy, xv->wdesc, + xv->x + xv->clip_left, + xv->y + xv->clip_top); + XMapWindow (xv->dpy, xv->wdesc); + XFlush (xv->dpy); } /* Hide an xwidget view. */ @@ -238,28 +257,48 @@ xwidget_show_view (struct xwidget_view *xv) xwidget_hide_view (struct xwidget_view *xv) { xv->hidden = true; - gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow, - 10000, 10000); + XUnmapWindow (xv->dpy, xv->wdesc); + XFlush (xv->dpy); +} + +static void +xv_do_draw (struct xwidget_view *xw, struct xwidget *w) +{ + block_input (); + + cairo_save (xw->cr_context); + cairo_translate (xw->cr_context, -xw->clip_left, + -xw->clip_top); + gtk_widget_draw (w->widget_osr, xw->cr_context); + cairo_restore (xw->cr_context); + + unblock_input (); } /* When the off-screen webkit master view changes this signal is called. It copies the bitmap from the off-screen instance. */ static gboolean offscreen_damage_event (GtkWidget *widget, GdkEvent *event, - gpointer xv_widget) + gpointer xwidget_view) { - /* Queue a redraw of onscreen widget. - There is a guard against receiving an invalid widget, - which should only happen if we failed to remove the - specific signal handler for the damage event. */ - if (GTK_IS_WIDGET (xv_widget)) - gtk_widget_queue_draw (GTK_WIDGET (xv_widget)); - else - message ("Warning, offscreen_damage_event received invalid xv pointer:%p\n", - xv_widget); + struct xwidget_view *xw = xwidget_view; + struct xwidget *w = XXWIDGET (xw->model); + + if (xw->wdesc == None) + return FALSE; + + xv_do_draw (xw, w); return FALSE; } + +void +xwidget_expose (struct xwidget_view *xv) +{ + struct xwidget *xw = XXWIDGET (xv->model); + + xv_do_draw (xv, xw); +} #endif /* USE_GTK */ void @@ -498,51 +537,6 @@ webkit_decide_policy_cb (WebKitWebView *webView, return FALSE; } } - - -/* For gtk3 offscreen rendered widgets. */ -static gboolean -xwidget_osr_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data) -{ - struct xwidget *xw = g_object_get_data (G_OBJECT (widget), XG_XWIDGET); - struct xwidget_view *xv = g_object_get_data (G_OBJECT (widget), - XG_XWIDGET_VIEW); - - cairo_rectangle (cr, 0, 0, xv->clip_right, xv->clip_bottom); - cairo_clip (cr); - - gtk_widget_draw (xw->widget_osr, cr); - return FALSE; -} - -static gboolean -xwidget_osr_event_forward (GtkWidget *widget, GdkEvent *event, - gpointer user_data) -{ - /* Copy events that arrive at the outer widget to the offscreen widget. */ - struct xwidget *xw = g_object_get_data (G_OBJECT (widget), XG_XWIDGET); - GdkEvent *eventcopy = gdk_event_copy (event); - eventcopy->any.window = gtk_widget_get_window (xw->widget_osr); - - /* TODO: This might leak events. They should be deallocated later, - perhaps in xwgir_event_cb. */ - gtk_main_do_event (eventcopy); - - /* Don't propagate this event further. */ - return TRUE; -} - -static gboolean -xwidget_osr_event_set_embedder (GtkWidget *widget, GdkEvent *event, - gpointer data) -{ - struct xwidget_view *xv = data; - struct xwidget *xww = XXWIDGET (xv->model); - gdk_offscreen_window_set_embedder (gtk_widget_get_window - (xww->widgetwindow_osr), - gtk_widget_get_window (xv->widget)); - return FALSE; -} #endif /* USE_GTK */ @@ -568,63 +562,21 @@ xwidget_init_view (struct xwidget *xww, XSETXWIDGET (xv->model, xww); #ifdef USE_GTK - if (EQ (xww->type, Qwebkit)) - { - xv->widget = gtk_drawing_area_new (); - /* Expose event handling. */ - gtk_widget_set_app_paintable (xv->widget, TRUE); - gtk_widget_add_events (xv->widget, GDK_ALL_EVENTS_MASK); - - /* Draw the view on damage-event. */ - g_signal_connect (G_OBJECT (xww->widgetwindow_osr), "damage-event", - G_CALLBACK (offscreen_damage_event), xv->widget); - - if (EQ (xww->type, Qwebkit)) - { - g_signal_connect (G_OBJECT (xv->widget), "button-press-event", - G_CALLBACK (xwidget_osr_event_forward), NULL); - g_signal_connect (G_OBJECT (xv->widget), "button-release-event", - G_CALLBACK (xwidget_osr_event_forward), NULL); - g_signal_connect (G_OBJECT (xv->widget), "motion-notify-event", - G_CALLBACK (xwidget_osr_event_forward), NULL); - } - else - { - /* xwgir debug, orthogonal to forwarding. */ - g_signal_connect (G_OBJECT (xv->widget), "enter-notify-event", - G_CALLBACK (xwidget_osr_event_set_embedder), xv); - } - g_signal_connect (G_OBJECT (xv->widget), "draw", - G_CALLBACK (xwidget_osr_draw_cb), NULL); - } + xv->dpy = FRAME_X_DISPLAY (s->f); - /* Widget realization. - - Make container widget first, and put the actual widget inside the - container later. Drawing should crop container window if necessary - to handle case where xwidget is partially obscured by other Emacs - windows. Other containers than gtk_fixed where explored, but - gtk_fixed had the most predictable behavior so far. */ - - xv->emacswindow = FRAME_GTK_WIDGET (s->f); - xv->widgetwindow = gtk_fixed_new (); - gtk_widget_set_has_window (xv->widgetwindow, TRUE); - gtk_container_add (GTK_CONTAINER (xv->widgetwindow), xv->widget); - - /* Store some xwidget data in the gtk widgets. */ - g_object_set_data (G_OBJECT (xv->widget), XG_FRAME_DATA, s->f); - g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET, xww); - g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET_VIEW, xv); - g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET, xww); - g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET_VIEW, xv); - - gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xww->width, - xww->height); - gtk_widget_set_size_request (xv->widgetwindow, xww->width, xww->height); - gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), xv->widgetwindow, x, y); xv->x = x; xv->y = y; - gtk_widget_show_all (xv->widgetwindow); + + xv->clip_left = 0; + xv->clip_right = xww->width; + xv->clip_top = 0; + xv->clip_bottom = xww->height; + + xv->wdesc = None; + xv->frame = s->f; + + g_signal_connect (G_OBJECT (xww->widgetwindow_osr), "damage-event", + G_CALLBACK (offscreen_damage_event), xv); #elif defined NS_IMPL_COCOA nsxwidget_init_view (xv, xww, s, x, y); nsxwidget_resize_view(xv, xww->width, xww->height); @@ -681,6 +633,8 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) window_box (s->w, TEXT_AREA, &text_area_x, &text_area_y, &text_area_width, &text_area_height); + /* On X11, this keeps generating expose events. */ +#ifndef USE_GTK /* Resize xwidget webkit if its container window size is changed in some ways, for example, a buffer became hidden in small split window, then it can appear front in merged whole window. */ @@ -693,6 +647,7 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) make_int (text_area_width), make_int (text_area_height)); } +#endif clip_left = max (0, text_area_x - x); clip_right = max (clip_left, @@ -711,15 +666,45 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) later. */ bool moved = (xv->x + xv->clip_left != x + clip_left || xv->y + xv->clip_top != y + clip_top); + +#ifdef USE_GTK + bool wdesc_was_none = xv->wdesc == None; +#endif xv->x = x; xv->y = y; +#ifdef USE_GTK + block_input (); + if (xv->wdesc == None) + { + Lisp_Object xvw; + XSETXWIDGET_VIEW (xvw, xv); + XSetWindowAttributes a; + a.event_mask = ExposureMask; + + xv->wdesc = XCreateWindow (xv->dpy, FRAME_X_WINDOW (s->f), + x + clip_left, y + clip_top, + clip_right - clip_left, + clip_bottom - clip_top, 0, + CopyFromParent, CopyFromParent, + CopyFromParent, CWEventMask, &a); + xv->cr_surface = cairo_xlib_surface_create (xv->dpy, + xv->wdesc, + FRAME_DISPLAY_INFO (s->f)->visual, + clip_right - clip_left, + clip_bottom - clip_top); + xv->cr_context = cairo_create (xv->cr_surface); + Fputhash (make_fixnum (xv->wdesc), xvw, x_window_to_xwv_map); + + moved = false; + } +#endif + /* Has it moved? */ if (moved) { #ifdef USE_GTK - gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), - xv->widgetwindow, x + clip_left, y + clip_top); + XMoveWindow (xv->dpy, xv->wdesc, x + clip_left, y + clip_top); #elif defined NS_IMPL_COCOA nsxwidget_move_view (xv, x + clip_left, y + clip_top); #endif @@ -735,10 +720,14 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) || xv->clip_top != clip_top || xv->clip_left != clip_left) { #ifdef USE_GTK - gtk_widget_set_size_request (xv->widgetwindow, clip_right - clip_left, - clip_bottom - clip_top); - gtk_fixed_move (GTK_FIXED (xv->widgetwindow), xv->widget, -clip_left, - -clip_top); + if (!wdesc_was_none) + { + XResizeWindow (xv->dpy, xv->wdesc, 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 NS_IMPL_COCOA nsxwidget_resize_view (xv, clip_right - clip_left, clip_bottom - clip_top); @@ -758,12 +747,15 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) if (!xwidget_hidden (xv)) { #ifdef USE_GTK - gtk_widget_queue_draw (xv->widgetwindow); - gtk_widget_queue_draw (xv->widget); + xv_do_draw (xv, xww); #elif defined NS_IMPL_COCOA nsxwidget_set_needsdisplay (xv); #endif } + +#ifdef USE_GTK + unblock_input (); +#endif } static bool @@ -976,8 +968,13 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0, if (XXWIDGET (xv->model) == xw) { #ifdef USE_GTK - gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width, - xw->height); + if (xv->wdesc != None) + { + XResizeWindow (xv->dpy, xv->wdesc, xw->width, xw->height); + XFlush (xv->dpy); + cairo_xlib_surface_set_size (xv->cr_surface, + xw->width, xw->height); + } #elif defined NS_IMPL_COCOA nsxwidget_resize_view(xv, xw->width, xw->height); #endif @@ -1084,13 +1081,21 @@ DEFUN ("delete-xwidget-view", CHECK_XWIDGET_VIEW (xwidget_view); struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view); #ifdef USE_GTK - gtk_widget_destroy (xv->widgetwindow); - /* xv->model still has signals pointing to the view. There can be - several views. Find the matching signals and delete them all. */ - g_signal_handlers_disconnect_matched (XXWIDGET (xv->model)->widgetwindow_osr, - G_SIGNAL_MATCH_DATA, - 0, 0, 0, 0, - xv->widget); + if (xv->wdesc != None) + { + block_input (); + XDestroyWindow (xv->dpy, xv->wdesc); + /* xv->model still has signals pointing to the view. There can be + several views. Find the matching signals and delete them all. */ + g_signal_handlers_disconnect_matched (XXWIDGET (xv->model)->widgetwindow_osr, + G_SIGNAL_MATCH_DATA, + 0, 0, 0, 0, xv); + + cairo_destroy (xv->cr_context); + cairo_surface_destroy (xv->cr_surface); + Fremhash (make_fixnum (xv->wdesc), x_window_to_xwv_map); + unblock_input (); + } #elif defined NS_IMPL_COCOA nsxwidget_delete_view (xv); #endif @@ -1236,6 +1241,12 @@ syms_of_xwidget (void) Vxwidget_view_list = Qnil; Fprovide (intern ("xwidget-internal"), Qnil); + +#ifdef USE_GTK + x_window_to_xwv_map = CALLN (Fmake_hash_table, QCtest, Qeq); + + staticpro (&x_window_to_xwv_map); +#endif } diff --git a/src/xwidget.h b/src/xwidget.h index 591f23489d..fc68b52cdb 100644 --- a/src/xwidget.h +++ b/src/xwidget.h @@ -32,6 +32,7 @@ #define XWIDGET_H_INCLUDED #if defined (USE_GTK) #include +#include #elif defined (NS_IMPL_COCOA) && defined (__OBJC__) #import #import "nsxwidget.h" @@ -98,9 +99,12 @@ #define XWIDGET_H_INCLUDED bool hidden; #if defined (USE_GTK) - GtkWidget *widget; - GtkWidget *widgetwindow; - GtkWidget *emacswindow; + Display *dpy; + Window wdesc; + struct frame *frame; + + cairo_surface_t *cr_surface; + cairo_t *cr_context; #elif defined (NS_IMPL_COCOA) # ifdef __OBJC__ XvWindow *xvWindow; @@ -162,6 +166,8 @@ #define XG_XWIDGET_VIEW "emacs_xwidget_view" void store_xwidget_js_callback_event (struct xwidget *xw, Lisp_Object proc, Lisp_Object argument); +struct xwidget_view *xwidget_view_from_window (Window wdesc); +void xwidget_expose (struct xwidget_view *xv); #else INLINE_HEADER_BEGIN INLINE void syms_of_xwidget (void) {} -- 2.31.1 --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0002-Enable-scrolling-optimization-for-xwidgets.patch >From fda1685eb81d0a8b7fe19966572913b504606d9d Mon Sep 17 00:00:00 2001 From: Po Lu Date: Fri, 29 Oct 2021 11:33:06 +0800 Subject: [PATCH 2/2] Enable scrolling optimization for xwidgets * src/dispextern.h (struct glyph): Store xwidget ID instead of a reference. * src/dispnew.c (scrolling_window): Enable scrolling optimization on xwidget builds. * src/xdisp.c (fill_xwidget_glyph_string, produce_xwidget_glyph): Obtain xwidget from ID. * src/xterm.c (x_scroll_run): Scroll xwidget windows. * src/xwidget.c (id_to_xwidget_map, xwidget_counter): New xwidget variables. (Fmake_xwidget): Assign each xwidget a unique ID, and keep track of that ID. (xwidget_from_id): New function. (syms_of_xwidget): Initialize id_to_xwidget_map. (xwidget_end_redisplay): Lookup xwidgets via ID. * src/xwidget.h (struct xwidget): Add ID field. (xwidget_from_id): New function. --- src/dispextern.h | 4 +-- src/dispnew.c | 10 ------ src/xdisp.c | 4 +-- src/xterm.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++ src/xwidget.c | 24 +++++++++++++- src/xwidget.h | 3 ++ 6 files changed, 112 insertions(+), 15 deletions(-) diff --git a/src/dispextern.h b/src/dispextern.h index 08dac5d455..218675b021 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -536,8 +536,8 @@ #define FACE_ID_BITS 20 int img_id; #ifdef HAVE_XWIDGETS - /* Xwidget reference (type == XWIDGET_GLYPH). */ - struct xwidget *xwidget; + /* Xwidget ID. */ + uint32_t xwidget; #endif /* Sub-structure for type == STRETCH_GLYPH. */ diff --git a/src/dispnew.c b/src/dispnew.c index c3f6d0bfef..2e0b4801da 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -4447,16 +4447,6 @@ scrolling_window (struct window *w, int tab_line_p) break; } -#ifdef HAVE_XWIDGETS - /* Currently this seems needed to detect xwidget movement reliably. - This is most probably because an xwidget glyph is represented in - struct glyph's 'union u' by a pointer to a struct, which takes 8 - bytes in 64-bit builds, and thus the comparison of u.val values - done by GLYPH_EQUAL_P doesn't work reliably, since it assumes the - size of the union is 4 bytes. FIXME. */ - return 0; -#endif - /* Can't scroll the display of w32 GUI frames when position of point is indicated by the system caret, because scrolling the display will then "copy" the pixels used by the caret. */ diff --git a/src/xdisp.c b/src/xdisp.c index aa01db210b..198bfc06a4 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -28425,7 +28425,7 @@ fill_xwidget_glyph_string (struct glyph_string *s) } s->width = s->first_glyph->pixel_width; s->ybase += s->first_glyph->voffset; - s->xwidget = s->first_glyph->u.xwidget; + s->xwidget = xwidget_from_id (s->first_glyph->u.xwidget); } #endif /* Fill glyph string S from a sequence of stretch glyphs. @@ -29830,7 +29830,7 @@ produce_xwidget_glyph (struct it *it) glyph->padding_p = 0; glyph->glyph_not_available_p = 0; glyph->face_id = it->face_id; - glyph->u.xwidget = it->xwidget; + glyph->u.xwidget = it->xwidget->xwidget_id; glyph->font_type = FONT_TYPE_UNKNOWN; if (it->bidi_p) { diff --git a/src/xterm.c b/src/xterm.c index 54bfb65bd0..b12c15cb7a 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -4390,6 +4390,88 @@ x_scroll_run (struct window *w, struct run *run) /* Cursor off. Will be switched on again in gui_update_window_end. */ gui_clear_cursor (w); +#ifdef HAVE_XWIDGETS + /* "Copy" xwidget windows in the area that will be scrolled. */ + Display *dpy = FRAME_X_DISPLAY (f); + Window window = FRAME_X_WINDOW (f); + + Window root, parent, *children; + unsigned int nchildren; + + if (XQueryTree (dpy, window, &root, &parent, &children, &nchildren)) + { + /* Now find xwidget views situated between from_y and to_y, and + attached to w. */ + for (unsigned int i = 0; i < nchildren; ++i) + { + Window child = children[i]; + struct xwidget_view *view = xwidget_view_from_window (child); + + if (view) + { + int window_y = view->y + view->clip_top; + int window_height = view->clip_bottom - view->clip_top; + int min_y = min (from_y, to_y); + int max_y = max (from_y, to_y); + + Emacs_Rectangle r1, r2, result; + r1.x = w->pixel_left; + r1.y = min_y; + r1.width = w->pixel_width; + r1.height = max_y - min_y; + r2 = r1; + r2.y = window_y; + r2.height = window_height; + + /* The window is offscreen, just unmap it. */ + if (window_height == 0) + { + view->hidden = true; + XUnmapWindow (dpy, child); + 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, TEXT_AREA, &text_area_x, &text_area_y, + &text_area_width, &text_area_height); + + clip_top = max (0, text_area_y - y); + clip_bottom = max (clip_top, + min (XXWIDGET (view->model)->height, + text_area_y + text_area_height - y)); + + view->y = y; + 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_top - view->clip_bottom) <= 0) + { + view->hidden = true; + XUnmapWindow (dpy, child); + } + else + XMoveResizeWindow (dpy, child, view->x + view->clip_left, + view->y + view->clip_top, + view->clip_right - view->clip_left, + view->clip_top - view->clip_bottom); + XFlush (dpy); + } + } + } + XFree (children); + } +#endif + #ifdef USE_CAIRO if (FRAME_CR_CONTEXT (f)) { diff --git a/src/xwidget.c b/src/xwidget.c index 62b30a07ab..68188eba08 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -41,6 +41,9 @@ Copyright (C) 2011-2021 Free Software Foundation, Inc. #include "nsxwidget.h" #endif +static Lisp_Object id_to_xwidget_map; +static uint32_t xwidget_counter = 0; + #ifdef USE_GTK static Lisp_Object x_window_to_xwv_map; #endif @@ -114,6 +117,9 @@ DEFUN ("make-xwidget", XSETXWIDGET (val, xw); Vxwidget_list = Fcons (val, Vxwidget_list); xw->plist = Qnil; + xw->xwidget_id = ++xwidget_counter; + + Fputhash (make_fixnum (xw->xwidget_id), val, id_to_xwidget_map); #ifdef USE_GTK xw->widgetwindow_osr = NULL; @@ -227,6 +233,18 @@ xwidget_hidden (struct xwidget_view *xv) return xv->hidden; } +struct xwidget * +xwidget_from_id (uint32_t id) +{ + Lisp_Object key = make_fixnum (id); + Lisp_Object xwidget = Fgethash (key, id_to_xwidget_map, Qnil); + + if (NILP (xwidget)) + emacs_abort (); + + return XXWIDGET (xwidget); +} + #ifdef USE_GTK struct xwidget_view * @@ -1242,6 +1260,9 @@ syms_of_xwidget (void) Fprovide (intern ("xwidget-internal"), Qnil); + id_to_xwidget_map = CALLN (Fmake_hash_table, QCtest, Qeq); + staticpro (&id_to_xwidget_map); + #ifdef USE_GTK x_window_to_xwv_map = CALLN (Fmake_hash_table, QCtest, Qeq); @@ -1385,7 +1406,7 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix) /* The only call to xwidget_end_redisplay is in dispnew. xwidget_end_redisplay (w->current_matrix); */ struct xwidget_view *xv - = xwidget_view_lookup (glyph->u.xwidget, w); + = xwidget_view_lookup (xwidget_from_id (glyph->u.xwidget), w); #ifdef USE_GTK /* FIXME: Is it safe to assume xwidget_view_lookup always succeeds here? If so, this comment can be removed. @@ -1448,6 +1469,7 @@ kill_buffer_xwidgets (Lisp_Object buffer) { CHECK_XWIDGET (xwidget); struct xwidget *xw = XXWIDGET (xwidget); + Fremhash (make_fixnum (xw->xwidget_id), id_to_xwidget_map); #ifdef USE_GTK if (xw->widget_osr && xw->widgetwindow_osr) { diff --git a/src/xwidget.h b/src/xwidget.h index fc68b52cdb..28098c0b09 100644 --- a/src/xwidget.h +++ b/src/xwidget.h @@ -60,6 +60,7 @@ #define XWIDGET_H_INCLUDED int height; int width; + uint32_t xwidget_id; #if defined (USE_GTK) /* For offscreen widgets, unused if not osr. */ @@ -168,6 +169,8 @@ #define XG_XWIDGET_VIEW "emacs_xwidget_view" Lisp_Object argument); struct xwidget_view *xwidget_view_from_window (Window wdesc); void xwidget_expose (struct xwidget_view *xv); + +extern struct xwidget *xwidget_from_id (uint32_t id); #else INLINE_HEADER_BEGIN INLINE void syms_of_xwidget (void) {} -- 2.31.1 --=-=-=-- From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 29 Oct 2021 13:19:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.16355135152561 (code B ref 51473); Fri, 29 Oct 2021 13:19:02 +0000 Received: (at 51473) by debbugs.gnu.org; 29 Oct 2021 13:18:35 +0000 Received: from localhost ([127.0.0.1]:54162 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mgRmF-0000fE-Eu for submit@debbugs.gnu.org; Fri, 29 Oct 2021 09:18:35 -0400 Received: from sonic316-20.consmr.mail.ne1.yahoo.com ([66.163.187.146]:39614) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mgRmA-0000ep-Ni for 51473@debbugs.gnu.org; Fri, 29 Oct 2021 09:18:34 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635513504; bh=Wrrt4fjk5D8Tu771Oat5sYZ/d9qTFxrk5D6/e5Wua1Q=; h=From:To:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=MRNxkB6KKOJrTGQqiFKqe1h6x33gJaRURgw3jT6Q/kO88QatkR85uwN6LnR6VkG3vCFdBSIKkJG9z1YYOy1Tza3yGyeMpsu4Is9IeyA5oda2lu9GDjUaiNpDAifHLkxmlZbBEiVtmYSaj/fiOmcWPgp7Nz796f7iTiDskmLq+2iwwCmQJ/IBDlxJ3VkJ3p6yaZwzy/QZTn4QFKzGeTh2Nxp5oxN2uXfnuMxDNE8Y4DoKor/vbVEm1EBurc8S5D8I7ezTfsYS/CSshnFirz++WXx6qTBJIcQGbf6XmYFTBDn3xUaUH046fCmW9OvLkRuzGAMYxWtMCxIbecEQlXbw5w== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1635513504; bh=ASRDHXbVOZ/oVTlc68YpYjrbClh1pTtMrYyguXmXETg=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=I1yoh02Zj8F6aHeBuxAS6caG2gF9Ei0iSHJa7NyNS/btlZ8k8lbbz38jREDb4xhSBSI/syVipiaMeOtxILH+jOtymSThtDPtXc75orvs45JYYRvPuVgvGOyQIb3JUuCp907YKkLp9/KSjPjJCY+6Z0LHms1xqgJ6nyWjCRYmqD8dj+4ifvMbXeyHjYX9gMytqeDHpVTmfzqUsGGWTCUqUNDjawvEFdS3oh6CSnfwawz27uSredO4SkL04yzjMaRthkCjqa91mBXv9UK+UpGhj2+QkfoRNN5XWp9yCetLgUsuoYcF7UzmC6yh3pnKZiiUwpkinQWG5fi3Ii4bYpEAyg== X-YMail-OSG: 64JZ5FoVM1ndd7LaFzQyzVeSNS0NvkVSCafFZN4cbf_7uXthuTHR4eXHYSN_l28 hJpPYmE27KkeWsOXfFgKEF.ic1.Y0GAyu6c4tqwDQuQuta9h3GoMaI_YewlO_G44WRkRAFPz6gdY ZtHkQW.WiiaasZp2Wga67vwJfX3a354EckHkMb6vG4BYcmhqH_JXFvewJNx8ayKJlK9oxc0GCn4Y 4QLypA9iIO8Aa7dfcR5K0Id3iS0bhzk55eebrWReyGFlOwqZEq1p2CsAf9qr3OV6wbhoi_ewZYHk MB9cuUbV3SioHjpo1cABkWtj9xR2PrZcwclI5TIIFfcS7TG8K8wSLxfbS0U.B_0Yxe1l4PA7cJKc b1rFxab.MXuWjxU.6eZAOnFbwafRVmJQDKyjfOmzAI3SMOLuBCvNv6sPtzUKWWS99BqNeSFjZM2t gUdPaS1KRRybxZnhnj3LV.kbB1WzX3bAcUgtjNMF0IhWlmq6tCWPWCNABx2lH12ZcKtgybYAzTVL gkk4OP0b_ZfHnkYkx0si3.qE5o3tnWswNurwI_KKYn9zafiFB7ak5iopDkLHr4VZFHHnkhs.RGEV RDehgyHTFFAUCjaiMECH9DcGj2lGy54z_HFpHz0TJFBhqYdnYUULPDxg27cPCTZaElqXZjYB5oL0 13d2CebYjdJXYjxR3_LjYD5eGgcdl_dhiryfT8CUOBYdEcW0YnLiRmttq9vujE9vUt_8rJ19cEw4 d7byUTme4a8VdN5.2LnwGmek5Ospdt07voddHa_cSsKXdT2YjaobNja0xg.Q8AuR_95agvNci18w ttdEjfcaNDX.33A6OkdUtsftrUzgMPysBkr.U.bkjVAbQlATRGhEw.63cGnrH3.U77iAlFAoNqpP FjxDthzKm7ViTHBF6rgmbf5STOwg8Ms8xECxSGvoKbKfbR.kMiNQPC7b2VyYVLvvoapjuSjXpY87 ayixI4djcYNDOGh8z9ZVlTb9YwHQqldyZWqt8aKw88KVYJx2XUgjaA_QdaENrl2EUMS_OBgIfafJ cG.o8oiU3HaJdvds4VYmiy2hkT5zx8a95Zt9g2QwP1dwqNjTG7dr9uBDw97j5qsSzw9EDLH9Z95p 5KnmMNr1Q.rl9V3XkR6m9B3oEJc6_AfuNLrn_fzc7dLLUYpvx8DLAPG7MKXRhjcVpaCQyBv8I24c 3nZyWfGofPZlghohfVFPchfE2qEXPOcr2A_cLWteuk.2pcSv9NB.9poMPu.ICCPzJB0cOTUBR48k 48CFYSvCJiXBW4GuLZx_ahSjcTm3BzghCPL5jzYANNkFderAOpi948NiBq8iix8ZJRTB8qxKuX3P 2Ro1YXmlS3RV6UCapPq.WRfXHkoILvF9zq3ByGeAp0Ns7cx318ltmTOrEvhfffQHBPFhqNxIEICv lsTJvx7o21849gHD3sx3C1Zjz9QoJ1k0umPGvw4qTUss9UCpi0qNdJOIpowu8Z1FbaE2djkXFNlg y97YRwxYwoyGaMqsQfyDZChiMIVhdTXP_PHXT.pnhIS0E5cpY0uP05l4VGtv_yGnuBUNZXVKg1.3 _TKXgWMwBdeCtda3ToYZQ2XXuGVE09i77vb7LMiKhaQd4PTC4uZTtsc0AALaEp.49QES6Fy30L26 ZOeFv0tQmcfupLm3zCB4cD_dOEEi.sHRkU.jykm9ta1i7X8SyFoU5aZOEfF9YxW85bxlExP7EUGE KiAvUAJMqYglCR13YYfmaHV6_PU0BViY0DeBfnomXfECkhgm3.v27WlMIaw2kENFIUg6YWB2E7TH I3GE1r7U6OkKFB8tbuTgUc6neAPh5QiPbkKUwvahu_ZfxECIH_SSSsilh8JPyh8JOaEUFMeuS_7e oX5lGMKkGzauJet3EQUdsD9es3tY7bnOwUl6Ce8w6bRFdjZsC8vP2qfxXasEBeva0imDKlQq54ss hJF8vMR20WX1aW9Nbo2Tqse6H_HPaXjH9em8lO3RXJ_21WMtzMr8Z5qe9q5dsmjmmHfW8tuQAKEE _gKsm09keye_PmHQ0rUVYq2I5IEzYRAc2j5q99JY3s7iVJecgeUbZWhPziN3EGdC0UfLZnhKe31E nm.jGDdl3se6MXgsfYSiTKZOWahpGOixaSQUjtVgDsJdNKaeucC6eUFwRsI.OCXRY91Zq1CgmYOi alpwhZUydpze6h7pTnLtPhcuZrATnbC18awOCkOIbod.IA55_gnIbAPiFy2bDFL7W8zV1xerW_1. 9sottqzsrNPSldXxi4wdVTcOdo6LtiBVr45PVl3H5 X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic316.consmr.mail.ne1.yahoo.com with HTTP; Fri, 29 Oct 2021 13:18:24 +0000 Received: by kubenode503.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 991ae618a639404a3a67302e7a924f91; Fri, 29 Oct 2021 13:18:18 +0000 (UTC) From: Po Lu References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> Date: Fri, 29 Oct 2021 21:18:14 +0800 In-Reply-To: <87zgqslafe.fsf@yahoo.com> (Po Lu's message of "Fri, 29 Oct 2021 12:30:45 +0800") Message-ID: <87mtmskm09.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Mailer: WebService/1.1.19198 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 5717 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Po Lu writes: > The attached changes fix flickering xwidgets by moving xwidget display > into a separate X window, and also enable the scrolling optimization for > xwidgets. > > Someone with access to a Mac will have to do the changes necessary for > xwidget scrolling to work correctly on macOS, as they don't work on > GNUstep in the first place. > > However, event passthrough doesn't work yet, and will require some > thought. But that would be a fantastic opportunity to clean up the > current xwidget event handling mess (and perhaps even define a mechanism > for Lisp code to send events into xwidgets, which would make integrating > them into the existing Emacs event model much easier.) Any thoughts? > > Thanks. And I missed something, you will also need the following patch for everything to function correctly: --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0003-Destroy-xwidgets-when-destroying-frames.patch >From b490315aad58c704589fbb753de3238ce0d08819 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Fri, 29 Oct 2021 19:26:49 +0800 Subject: [PATCH 3/3] Destroy xwidgets when destroying frames * src/xterm.c (x_free_frame_resources): Make sure to kill xwidget views. * src/xwidget.c (Fmake_xwidget): Attach damage event signal. (offscreen_damage_event): Operate on xwidgets and not individual views. (xwidget_init_view): Don't attach damage event signal here. (Fdelete_xwidget_view): Destroy window correctly and stop removing damage event signal. (kill_frame_xwidget_views): New function. * src/xwidget.c (kill_frame_xwidget_views): New function. --- src/xterm.c | 4 ++++ src/xwidget.c | 52 +++++++++++++++++++++++++++++++++++---------------- src/xwidget.h | 1 + 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/src/xterm.c b/src/xterm.c index b12c15cb7a..3e8cfb8b29 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -12210,6 +12210,10 @@ x_free_frame_resources (struct frame *f) xfree (f->shell_position); #else /* !USE_X_TOOLKIT */ +#ifdef HAVE_XWIDGETS + kill_frame_xwidget_views (f); +#endif + #ifdef USE_GTK xg_free_frame_widgets (f); #endif /* USE_GTK */ diff --git a/src/xwidget.c b/src/xwidget.c index 68188eba08..fe6640171c 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -46,6 +46,7 @@ Copyright (C) 2011-2021 Free Software Foundation, Inc. #ifdef USE_GTK static Lisp_Object x_window_to_xwv_map; +static gboolean offscreen_damage_event (GtkWidget *, GdkEvent *, gpointer); #endif static struct xwidget * @@ -193,6 +194,9 @@ DEFUN ("make-xwidget", xw); } + g_signal_connect (G_OBJECT (xw->widgetwindow_osr), "damage-event", + G_CALLBACK (offscreen_damage_event), xw); + unblock_input (); } #elif defined NS_IMPL_COCOA @@ -297,15 +301,20 @@ xv_do_draw (struct xwidget_view *xw, struct xwidget *w) It copies the bitmap from the off-screen instance. */ static gboolean offscreen_damage_event (GtkWidget *widget, GdkEvent *event, - gpointer xwidget_view) + gpointer xwidget) { - struct xwidget_view *xw = xwidget_view; - struct xwidget *w = XXWIDGET (xw->model); + block_input (); - if (xw->wdesc == None) - return FALSE; + for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); + tail = XCDR (tail)) + { + struct xwidget_view *view = XXWIDGET_VIEW (XCAR (tail)); + + if (view->wdesc && XXWIDGET (view->model) == xwidget) + xv_do_draw (view, XXWIDGET (view->model)); + } - xv_do_draw (xw, w); + unblock_input (); return FALSE; } @@ -592,9 +601,6 @@ xwidget_init_view (struct xwidget *xww, xv->wdesc = None; xv->frame = s->f; - - g_signal_connect (G_OBJECT (xww->widgetwindow_osr), "damage-event", - G_CALLBACK (offscreen_damage_event), xv); #elif defined NS_IMPL_COCOA nsxwidget_init_view (xv, xww, s, x, y); nsxwidget_resize_view(xv, xww->width, xww->height); @@ -1102,15 +1108,9 @@ DEFUN ("delete-xwidget-view", if (xv->wdesc != None) { block_input (); - XDestroyWindow (xv->dpy, xv->wdesc); - /* xv->model still has signals pointing to the view. There can be - several views. Find the matching signals and delete them all. */ - g_signal_handlers_disconnect_matched (XXWIDGET (xv->model)->widgetwindow_osr, - G_SIGNAL_MATCH_DATA, - 0, 0, 0, 0, xv); - cairo_destroy (xv->cr_context); cairo_surface_destroy (xv->cr_surface); + XDestroyWindow (xv->dpy, xv->wdesc); Fremhash (make_fixnum (xv->wdesc), x_window_to_xwv_map); unblock_input (); } @@ -1456,6 +1456,26 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix) } } +#ifdef USE_GTK +void +kill_frame_xwidget_views (struct frame *f) +{ + Lisp_Object rem = Qnil; + + for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); + tail = XCDR (tail)) + { + if (XXWIDGET_VIEW (XCAR (tail))->frame == f) + rem = Fcons (XCAR (tail), rem); + } + + for (; CONSP (rem); rem = XCDR (rem)) + { + Fdelete_xwidget_view (XCAR (rem)); + } +} +#endif + /* Kill all xwidget in BUFFER. */ void kill_buffer_xwidgets (Lisp_Object buffer) diff --git a/src/xwidget.h b/src/xwidget.h index 28098c0b09..f51921dbef 100644 --- a/src/xwidget.h +++ b/src/xwidget.h @@ -171,6 +171,7 @@ #define XG_XWIDGET_VIEW "emacs_xwidget_view" void xwidget_expose (struct xwidget_view *xv); extern struct xwidget *xwidget_from_id (uint32_t id); +extern void kill_frame_xwidget_views (struct frame *f); #else INLINE_HEADER_BEGIN INLINE void syms_of_xwidget (void) {} -- 2.31.1 --=-=-=-- From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Lars Ingebrigtsen Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Thu, 04 Nov 2021 23:13:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Po Lu Cc: 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163606753124376 (code B ref 51473); Thu, 04 Nov 2021 23:13:01 +0000 Received: (at 51473) by debbugs.gnu.org; 4 Nov 2021 23:12:11 +0000 Received: from localhost ([127.0.0.1]:43862 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1miltz-0006L6-66 for submit@debbugs.gnu.org; Thu, 04 Nov 2021 19:12:11 -0400 Received: from quimby.gnus.org ([95.216.78.240]:60656) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1miltw-0006Kq-As for 51473@debbugs.gnu.org; Thu, 04 Nov 2021 19:12:09 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnus.org; s=20200322; h=Content-Type:MIME-Version:Message-ID:In-Reply-To:Date: References:Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=eYbh6j2791/NJsZdF/uYACN0/DRqGBOvvnoUaOaBXJ4=; b=bqqPvTxBNsSdxlN4aakqm98RPE Q/7cp0Bt+Q/FqQj5JnVV2EYEwPZo3fS9tdKQ44gXJRBHgB+Lmqc9C8JIDEFzi0jhSpE2jei1fyWgt f3U789pcm5gZIAi0vPp9HfEGUTU/bvPr5Ei+5KtwlCON9OXcktaK/CqkqSMQpfzfAGmU=; Received: from [84.212.220.105] (helo=elva) by quimby.gnus.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1miltm-0007Lx-FW; Fri, 05 Nov 2021 00:12:02 +0100 From: Lars Ingebrigtsen References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> X-Now-Playing: Chloe Thevenin & Pete Harden's _The Wire Tapper 57_: "Phantom Ride" Date: Fri, 05 Nov 2021 00:11:58 +0100 In-Reply-To: <87zgqslafe.fsf@yahoo.com> (Po Lu's message of "Fri, 29 Oct 2021 12:30:45 +0800") Message-ID: <875yt7plc1.fsf@gnus.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Report: Spam detection software, running on the system "quimby.gnus.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see @@CONTACT_ADDRESS@@ for details. Content preview: Po Lu writes: > The attached changes fix flickering xwidgets by moving xwidget display > into a separate X window, and also enable the scrolling optimization for > xwidgets. Sounds good... Content analysis details: (-2.9 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Po Lu writes: > The attached changes fix flickering xwidgets by moving xwidget display > into a separate X window, and also enable the scrolling optimization for > xwidgets. Sounds good... > Someone with access to a Mac will have to do the changes necessary for > xwidget scrolling to work correctly on macOS, as they don't work on > GNUstep in the first place. Does this mean that these patches will break the Macos build? > However, event passthrough doesn't work yet, and will require some > thought. But that would be a fantastic opportunity to clean up the > current xwidget event handling mess (and perhaps even define a mechanism > for Lisp code to send events into xwidgets, which would make integrating > them into the existing Emacs event model much easier.) Any thoughts? I'm not really that familiar with how xwidget works, so er does this mean that the events work less with your patch than before? I'm unable to test this at all, because: larsi@elva:~/src/emacs/trunk$ emake; ./src/emacs -geometry -0+0 Overriding existing handler for signal 10. Set JSC_SIGNAL_FOR_GC if you want WebKit to use a different signal ** (emacs:2173922): ERROR **: 00:09:01.997: GApplication is required for xdg-desktop-portal access in the WebKit sandbox. Fatal error 5: Trace/breakpoint trap This is on Debian/bookwork. (And without your patch, just building with xwidget and `M-x xwidget-webkit-browse-url RET fsf.org RET', and Emacs crashes.) -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Eli Zaretskii Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 05 Nov 2021 07:22:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Lars Ingebrigtsen Cc: luangruo@yahoo.com, 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.16360968702283 (code B ref 51473); Fri, 05 Nov 2021 07:22:02 +0000 Received: (at 51473) by debbugs.gnu.org; 5 Nov 2021 07:21:10 +0000 Received: from localhost ([127.0.0.1]:44538 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mitXC-0000al-FU for submit@debbugs.gnu.org; Fri, 05 Nov 2021 03:21:10 -0400 Received: from eggs.gnu.org ([209.51.188.92]:52650) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mitXA-0000aV-WC for 51473@debbugs.gnu.org; Fri, 05 Nov 2021 03:21:09 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]:43648) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mitX5-0004nX-Q9; Fri, 05 Nov 2021 03:21:03 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date: mime-version; bh=X7cavBD2fqZGBXfjXCp0voyd4e3qxxARtElFKA7xF2A=; b=e4Mj27QyZ6xh 6yqQpJOBwRyx+zNQq6m82AlN4AUTikQZJV3r6Jp/rpbO2/+JM2svRzJQoebM6H/5rEAz4nYWzp/S9 ZLeD7JOG0Mrpab3pMdH+dtg2YYs/+7/tBF49hwOJfollTbAsreEtyQjoEI2ayw5GKLh3nggFkEGAV R0Uracih/dCRu8Djk1xJp9g32IfTxchMhCUVLirzdq91Str0/j/y+fk1t82kZ5KY6xek8qzUNLh60 cyIXtdSoL4jyapWpHgyUTcqqwgB5796IVUI/GNWTl5VtchE9DmPLvtGIEQba78c0HQpJNGnoOgOT3 0JLBigqET5SK/dXLuYO6VQ==; Received: from [87.69.77.57] (port=3186 helo=home-c4e4a596f7) by fencepost.gnu.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mitWt-0006m6-8c; Fri, 05 Nov 2021 03:20:56 -0400 Date: Fri, 05 Nov 2021 09:20:32 +0200 Message-Id: <83h7crdq67.fsf@gnu.org> From: Eli Zaretskii In-Reply-To: <875yt7plc1.fsf@gnus.org> (message from Lars Ingebrigtsen on Fri, 05 Nov 2021 00:11:58 +0100) References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > From: Lars Ingebrigtsen > Date: Fri, 05 Nov 2021 00:11:58 +0100 > Cc: 51473@debbugs.gnu.org > > (And without your patch, just building with > xwidget and `M-x xwidget-webkit-browse-url RET fsf.org RET', and Emacs > crashes.) Sounds like a serious problem. Any idea why it crashes? What does the backtrace say? From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 05 Nov 2021 07:31:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Eli Zaretskii Cc: Lars Ingebrigtsen , 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.16360974493778 (code B ref 51473); Fri, 05 Nov 2021 07:31:01 +0000 Received: (at 51473) by debbugs.gnu.org; 5 Nov 2021 07:30:49 +0000 Received: from localhost ([127.0.0.1]:44713 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mitgX-0000ys-7I for submit@debbugs.gnu.org; Fri, 05 Nov 2021 03:30:49 -0400 Received: from sonic314-22.consmr.mail.ne1.yahoo.com ([66.163.189.148]:42282) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mitgV-0000ye-O0 for 51473@debbugs.gnu.org; Fri, 05 Nov 2021 03:30:48 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636097442; bh=s8y2nQJT79MPZwV7Ai6uUhFiAWNe1bJ8OsAQi8DTyaQ=; h=From:To:Cc:Subject:In-Reply-To:References:Date:From:Subject:Reply-To; b=bAxH7UyfD6fgBSESUNFd46k2mTBZy3iH4Ijp02VatscZ7wtoph6j86QjeyVOvOpSOcd33UDFSC0sssRPtyu+5RxU47/PQx/zd4YD5SVTh153AeELPSk9FJ6VnnfeeKbZ3fOak9l8LD+jUjomoKTg+qqPiIv2Vj5Fa8iYQtZMLX3wERAiho3b3quvKc3ZY9WUyxV76x6FZkcF5sNlTGFhTSXfUWLSrXDmpg143Psq7EX2tQHl6qOCxGX0m8duYvrEeX/zoetqmazjLJzMHMLNk3YYJPe/wTPJbjgGx3DS8io3/izNix/js7diRj+cvsSEhXGaHpBMt7fFfqu9L8SAwg== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636097442; bh=XFriEXHGkV4MSZzSLTSFXYJUCwzRdOKUmBRNBMr7MQg=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=tuL/iflotnmU7TRGORtaBv8gdjeIRDrNWpFmR/dGF1riLjfnFcq1f0zb1En2up9uS9NVq98COg853LXQDu3uvd6Vu2tTRRNzEmL9H7RP7Gd73+vXSgy+W+gBMJJfaSXCysxAR6YIZ+3BSDj/6QKkl6pT3Kxu/IIXGAduTdAlxtpM5sgL9ofceYHakBGf4qpyfwmF/7cq0WNThX5uNLVGe0aEuJmEaFy0x3Zo77TYfqGDBHiMSPksXpcTS/O+ywxCFoTvHAVsT01ed0LJYjg04mAFksOrhENaVYtxMofCo28JYgnu5YSY7Mtvc781a10DAyd9ozeeXAe65rl9AyGEmw== X-YMail-OSG: e_MLrfMVM1nrQdtbzvFFmezgVnkC2VRwLV9hhJGwFYNrE3mlZ862_ssXehtK7r1 72ABiP_FWRjbZ7PrM2rRgt5Yjz9kiBNY1jE.jqUubl0RRrHswncca5YS8OU3sHfVd5l8SfvrfIrR wA3DYJWJ99.bccgjSyeU4ja1mq.nX8Oeq6QAZlAH7rxCLTtBWfzTveb23cR_0KLksmyF8oOhZoDq iCvURYcq4keLyffIxMuupmZaipw_R0ROAd6bLTmSCyUau9creVKAlf9W2sidHyWYA_wZ6uA9ghb8 SQoia3HCWl0CfOZGJ4y996tAiq4KJAhETq__kbTQ3THi6ZRF1EaEF6WQYBcQTtxfiJMigQEXjPeF veH6XxqCt7VZ0cVn57AitVofu5WE38HomhXoxjfMHR5ZDimQ8sx1Er5wpbAHdcZ.buDlH857FHVP FlsnYyn5gbOasl3uMs8PoPQK9h0.HC0GSoVA2imLel4k1GnHod0Fzq4tu7PWMp5xnE_rxXbSiQaR ViPuuEsPNiETAkMVpaQ9KYS3EGZIEhyPNHW9SlGt2ylryHpscYA5XQlCcODkS.5ptlNoJ_F1JPXx gMrPPiSiOGSpouXNuoX6Ai2PQiSA8kNVxV.zhRwda7DrwlzI1ost6vNhYq6lx3e.1g9uX4.kiJXq C591kGxJBVUHd8VHSVLAhfJUzGWr.oj5ssHHFO07PQnUgnSye.r8Wl0u2w58MOgpnMsYC2aWQuiq uZBS7W7GBbbSliJ2XBLN6gVDIwqEHXqAOXiYSmuUnWGefoAgFFvbf0vhmATZ0lB7h9.9cc7BwVdX ozgKKDum3xcjHkvMI11Z4hKWzE5H10erVmarSviCdg6uZz4Kcugm4i8REPpb.3s4u2fHXFXeNARs jE4zLxixPtqLDmYWKMtSJ5AK2M_nMBzfggNU_BnGfmJv1tL1Hnmjr8Yp1S6cfjXkeuWgVXmzcFDq ywPeX9JeRQmZL74QQpfmQT0tT6oGLZJziKWym6diO4VoUISs1QkTD1ROrkbczPgxuH81PfUQuLh8 TQ1PhKLLPLJT3i1AocV59Zr8J2kfzjlQbgQOFC0yS7gjTM2Ru6EKrs2YFFXqEZmL6n0o_UKm_A79 0do6zlnU6m3TCbKqiEMMoxgnjMG9.AJ5KwsrjggK3oWwl1jsTniVYbu7ln_wKdh2sDvGFWkShC0c JMEqMPtHxWDVojRAYq2e9oyRBVay6g5ffRp2lNoV.cTbB.zixvKwhRKqBW_aegLAy5FaF_Ot_yGp Dtv4KpZFJ7sWK_BJei_B3ZPaZIVGcM.MqnG7xPrLM3Xj8dNbOrQPw46HLZY2nA96oRbid.bOkVzA AtfiPb5rGT06oEOGlcPQvdeZeQ6wSA6aRz7BLWzTjmlXCN_ZphdgvMAWEUghWEfABJHacHqBRfjq ms9OJY1InBM0Dw5Tz3XKshoaycFkqUpOr2fZo6Jv1rnxDd1yTK_AlXKzoPq1VGLLt7KoUYbQqXSe M6DWYt0s25p.2oUpxue2kPSAz3V9dSgpboB7dTc6NnW4jFRCpc2EV2jcIlOLtD7OEhBvBBQ5NWb3 4QwNzedrzYp3Gpe4NeI4VMRFiTP51Mmbzngqwn5C9SSDEtyEtLXqK5rGkfQg51nHKtneNGJCv7_0 NYVnzp.PfGe3E.BjltMZH2QwheU_jR7EH7eoOPJEaOA4vw5dEswXfEhiU0G2rPPjqMPKBKgwG9pj 3bFrPJrREOJPDCyQUPEsmBlp6G2bo0ZNyI87pdK.bjl7Obzq45o8QboNidki7FB1wBlHD3IQUuJt O2ZrfGg0I.3sVSQZB91P9yrDdRaQHN7bjakQbSSm4Yex1b7bSNjaY4ZuTm5ApPnlupPCA6vMmjZ6 Np8dqm2OAVoG.c9NcRjjRvakXhcOAUg9O3HR_DB5tnAAgv6SjwMX0zUwzLTr3tVeS3jrcSuhtPub 0aHIA_AmhEUXF1QJ10mMXP2GYuq01OAR7XdfuXpE0F8BWDncFLfMiC0j24tU2k0oQUKXJZQGU9np 81SadHaK1nqJ795d0CAKUAhad5OCz6Jx1XYY42E.1nAdKWVZ36RqFouF3BR.MC2uB9CoNAOWx_e8 J38OdyjUHKXIGOEGfS2pTMqhPWLbE0G3ftsdeTSIgBrcu6g0uYHlu1iEugyH.luEBjUeFdM9CP42 .WrQB0YHDTJSB1n0hLKT2vM11rQs_O93dABGgUEmwE_.sZP3vFZvLx.TuyhVl1ENHRMxvS2zIci9 y7DtjYZUPiqxqKmKRGQAmaLOtNvoZWsCTWuQIhQUFXMgWyFV4CjURVQ-- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic314.consmr.mail.ne1.yahoo.com with HTTP; Fri, 5 Nov 2021 07:30:42 +0000 Received: by kubenode517.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 2c645896a444e3c94954b25d4ba5f9c1; Fri, 05 Nov 2021 07:30:35 +0000 (UTC) From: Po Lu In-Reply-To: <83h7crdq67.fsf@gnu.org> (Eli Zaretskii's message of "Fri, 05 Nov 2021 09:20:32 +0200") References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <83h7crdq67.fsf@gnu.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) Date: Fri, 05 Nov 2021 15:29:58 +0800 Message-ID: <87wnln9i15.fsf@yahoo.com> MIME-Version: 1.0 Content-Type: text/plain X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 468 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Eli Zaretskii writes: > Sounds like a serious problem. Any idea why it crashes? What does > the backtrace say? Lars, are you using Fedora 34 by any chance? The WebKitGTK 2 package there has some kind of bug that also affects the GNOME Yelp viewer, not just Emacs. I realize that I've forgotten to update this issue with a few improvements I've made though. I'll send them soon, it would be nice if someone took a look at them afer that. Thanks. From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Lars Ingebrigtsen Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 05 Nov 2021 07:34:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Po Lu Cc: Eli Zaretskii , 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.16360976274087 (code B ref 51473); Fri, 05 Nov 2021 07:34:02 +0000 Received: (at 51473) by debbugs.gnu.org; 5 Nov 2021 07:33:47 +0000 Received: from localhost ([127.0.0.1]:44723 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mitjO-00013p-Tf for submit@debbugs.gnu.org; Fri, 05 Nov 2021 03:33:47 -0400 Received: from quimby.gnus.org ([95.216.78.240]:36384) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mitjN-00013b-Pw for 51473@debbugs.gnu.org; Fri, 05 Nov 2021 03:33:46 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnus.org; s=20200322; h=Content-Type:MIME-Version:Message-ID:In-Reply-To:Date: References:Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=pTiuqc6sdFGBzK0SQe1Rejng+c4PFwaBe7ZITipbVLc=; b=mQMUEY+m7xkjp2QyQl4zs6he9J 6D7Ygs6waU/8zubQ5Gb0NTH9meZETLNC+SR4mu4/149VVGmO441/ytZPv8Xv38Pebc0dZ9g5Dphd3 ytEilp8ArZ8QFz7mn1kXXw0hFqmyU+juG7Cz6r0QIvvkXgu962J4dB0t7jgQ47cfEp0Q=; Received: from [84.212.220.105] (helo=elva) by quimby.gnus.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mitjE-0002XH-DA; Fri, 05 Nov 2021 08:33:39 +0100 From: Lars Ingebrigtsen References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <83h7crdq67.fsf@gnu.org> <87wnln9i15.fsf@yahoo.com> X-Now-Playing: SOPHIE's _BIPP (Autechre Mx), UNISIL_: "UNISIL" Date: Fri, 05 Nov 2021 08:33:33 +0100 In-Reply-To: <87wnln9i15.fsf@yahoo.com> (Po Lu's message of "Fri, 05 Nov 2021 15:29:58 +0800") Message-ID: <87pmrfkqeq.fsf@gnus.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Report: Spam detection software, running on the system "quimby.gnus.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see @@CONTACT_ADDRESS@@ for details. Content preview: Po Lu writes: > Lars, are you using Fedora 34 by any chance? The WebKitGTK 2 package > there has some kind of bug that also affects the GNOME Yelp viewer, not > just Emacs. No, I'm using Debian/bookworm. Content analysis details: (-2.9 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Po Lu writes: > Lars, are you using Fedora 34 by any chance? The WebKitGTK 2 package > there has some kind of bug that also affects the GNOME Yelp viewer, not > just Emacs. No, I'm using Debian/bookworm. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 05 Nov 2021 07:35:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Lars Ingebrigtsen Cc: 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.16360976804190 (code B ref 51473); Fri, 05 Nov 2021 07:35:01 +0000 Received: (at 51473) by debbugs.gnu.org; 5 Nov 2021 07:34:40 +0000 Received: from localhost ([127.0.0.1]:44728 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mitkG-00015W-61 for submit@debbugs.gnu.org; Fri, 05 Nov 2021 03:34:40 -0400 Received: from sonic317-34.consmr.mail.ne1.yahoo.com ([66.163.184.45]:40053) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mitkE-00015C-L8 for 51473@debbugs.gnu.org; Fri, 05 Nov 2021 03:34:39 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636097672; bh=l6zIwFSLrefOHC+P4eU+4Rn4nf+1CDodL1DjqD6Q4B8=; h=From:To:Cc:Subject:In-Reply-To:References:Date:From:Subject:Reply-To; b=Fe/Cx9b+dbYJKhX7KMm4EG7RZdF+6AxRTTGsHOzhbjyYXBDJGpnwJqklhPONNR2fKlWjceCt2h6a8clZti4gaKQKYe4gZLYUwY9ptm5Ygtyek7qpcQ5W0qg2+J6MA0irx7HTnnvtw2is0AhaSIELNeU2j+qHJGN+vWK5HU+2AjIj9Qiud4KoVbaC0jnFFuQXT86AiogMJwGk6r2bluH8WVglChZqbM2bCcxnqQpWwU5nfM21D7PFUI0Lbh0og94VECWIVUr7Yhv1np116cp77ziTvNKeZkQ5iKhVGRlKFPfzSCL9r8/90N0QVlK+Gud1m23CHNAfrRobvjSc+lmoKA== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636097672; bh=LfP0ExUHzrTaEUJkL966nwNhkjjZnpsH4Ifxo1ejZhr=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=GReVnzct2OZ0cYcDxdKJo0a0/YNVcAHAKA/zUgKWn1JELn/UHzfWHQDRUYpu5xMBFTIEwKidQcyK4L3dDjl3iCJEoo01zxh1akDWBKkLAk5sT/DKEygK0+1JRY2P+ovfd7mSPX2ie/lkY12MbOJBWALJWVz7To5dhoaQDE7WGic5X9k9l5r/EK84/LbtX3CVym43b35bgf9bdhsH3sF3lNaL4Ma7RU4+oGcyhA/L1+XCwfClFZ8Q0GIO1S7mmB8u39cJR9UvvgBvxh0PqveIqin1HtE7S/AiKjYP0m+qefsdI6y3yLLe5XTwehFLfrVUWwIkEaa6SNEummcrcNwURA== X-YMail-OSG: Wm2uQYAVM1n4QSiPm7kvAM8SoCRWuEx3IyJf4soKaRm5vGpIfDpU6_csqpQ6qUV QAbAi171kk1.CQuWQtQUCH2PKZ95Yy3xQeD.zCBSpR1kBDcQkYPiBzef8M_SuZQL6z3q4lsFVmDt d8VBFQXISds73_wIDMGOrE9VJTSNZfaVYbXzJsHdaTkLvd5_N.AhAnG.VGrBSfwOUVs4yGor3omT QRU2Cfhoqb0ahCcV4ExMUghDHM9U0b.nRCqxMdB8l3axnJibV1zAvyMVmJXB_OMSWGHuU8qR4jk8 CPIAyI2rPv.v_5Cpom5VWPosz7UbYvfAW69eImCF4mW1wi79oYz1zBifFldN5K2jA5.Yz5RJ_Sqh ICKfEAiLXl_B6c.DQWCXkpubK0yM66tBRXF_ndt09Wvmb1byo5Wm_.qhKFaxvTm8TlhycTCsgNI5 g1q9XhPsTSFzafs60Ue9S2i9Uqe5zskxf2XVuFPnUWam3.SuOIqsQJrHkoyoUc4aZQci7ALPFk5Z is1XhraYTLLpRwlS6nGlg6IrZO5o0XTIfl8023P_gt3do.TcpkxnOVl59uEE54qCVE8pVobzo.QV dozuiuTaJo8PCZHYgar4UCwzfv6WVtXYEwiI_.sssuD70RfiOz0n9gzJy1oUFtaVOjkUUA5QwQx5 wCSY96EWFt23S0zSU.RYN2kJ0gx3BQj3oF_hTHRCg9eSrrMUBkSUl9GP7wtgL.L.QIuZc4zo.iNp l0eWAioQBquXChqXH6amQYufxubmcVqULA50X.Fp8g6hBUii.k5eNmoZLfM_qTaNRecT.pL5uBef fmEkR1HVSW54ydPAP6ZN9WjBvrDQP0qiH0Zx7f4VB1vkMy57YplC3UaxAhsjjKlmSQ3Z6I.BGiuO p9S7zVftc.ANrUeDX3WfB42w54lUmbrupEvEEdwmfj1yNHhEuuSAMNncrXFdoQ9Y2ROIiKqjpWiS QI2WNF9IKS4Myz.x4EiF9S0LylctRpEXXYrqQSJyfhf.ThduaTT4n7S8vFymSywEqdnWY6kr601B 4xiliyYm.HmZTdrOi.gts9GljUyuXObfKqcVsSDSFNLzmniTm4On5B.4GF.V.Y27osP8BGeLH4vH RFRPD3MPDQ8mZxvfgeYKbcVrYO.YoXFYoyEyDCCM4ui8YtRIcmoVKLQYGRonr7N5DtrX2lhovqBa YC_fGHRj5L3AYO6ETEc4gebkUhXQOnF8sVmGmFakRpw4vlvH3zRQy_MO3Sk_N9LZ3C.COlx9clBr EShn.pU9btvVvvdMQb.iCm0tWaxEjlbEc8EtyWv3ue4d7RGUg2PKkl9bcSLtzs9JiEgrs0YM.0SO a.EZgTd6UmCiH.wbmjMq1SNGqmYfh3T2hnW99EP.3awb0eH6mbSlasg8DzH2KnZtwALhY8gYiTCs 2NLIFyiSc9QQzcdetdjldwPbRybi5SB2va6A4gisUQskscROxURPASjn.KDBs7mrIVv7WUUkKEEg YGrPy0ZWaxrB5oQ23zqlU9KLT7IKwGPr0NqOrP8sJrK5sU3X3Gl7ACYQ1XeVLzqjH_lQCquBamgs XG6OZYjJLs0eeOpbh9DSIWuiwIPso0uYUUi2mRdq75ENN8OxF9yLJjmi.FbDO1S3W.Em82B.FvJJ inSVBfg.ZnTRTQTiNjZDS_pPuVBUiPVbbiKKu2q5dL499GjWFw5b1_XEfJe15IO1baS1ntgxXgQd 4oU01ZVbBWamDE6TY2woKyOTwfx3Tx9SfqnUAhMKK5UvfRU2T8OCYHJDCIjMz4mAy9bUC41LLvyO 2jz3s.X42DUpHCU9Du3EvIKOdqwyueyRv9CsuI.RQX9dM6C3qC3fga3oIp5HinszUFH3XTcYABFf wiv6X_ebrDjK_1kiWv2evoG_b.auCtFewqXcVFFpJzkm85VePGDIq9Ash0PdwtkDV5ds2canxZGr ecApr8Jf0PD.qnh_ZEJmpIRDENaolJBMAJiy8dMqzd6OkFYvz4nnavkrqpyQbbczqMyIGyMlolN2 Kkl7DnZTuHCbVP_Q7eyGaj1h9szzmdNH62SXeKdHJNVHjUecJG_UtH6hJyfbUuFXOYoqZKEN5H04 r4rwNBwhwcSgG3fqoWs7eLfe079NI8UeVaEclkGPz40S7TyV3xc85ISxUszcdbcaJsKaNnXS1M9W gH23m6wCjnHb2EWG4klXQd3PrUqzLLFAvk6O7AK1tOQjlKAsUGfSdxhp9gdDsaYDGuQW7Kt9sQpz FfYnYj9p0laoyvmWBEM2B96YeyVDbo48xFzUb_KmMIJ5ObS8P6BriVIJs X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic317.consmr.mail.ne1.yahoo.com with HTTP; Fri, 5 Nov 2021 07:34:32 +0000 Received: by kubenode510.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 12b1cdd9bd06f9ca7ccfff1ce6ee2fdd; Fri, 05 Nov 2021 07:34:27 +0000 (UTC) From: Po Lu In-Reply-To: <875yt7plc1.fsf@gnus.org> (Lars Ingebrigtsen's message of "Fri, 05 Nov 2021 00:11:58 +0100") References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) Date: Fri, 05 Nov 2021 15:34:23 +0800 Message-ID: <87mtmj9hts.fsf@yahoo.com> MIME-Version: 1.0 Content-Type: text/plain X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 1299 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Lars Ingebrigtsen writes: > Sounds good... > >> Someone with access to a Mac will have to do the changes necessary for >> xwidget scrolling to work correctly on macOS, as they don't work on >> GNUstep in the first place. > > Does this mean that these patches will break the Macos build? I tried my best to keep it working, but the scroll optimization will not function there. > I'm not really that familiar with how xwidget works, so er does this > mean that the events work less with your patch than before? Yes, but I fixed that, and defined a new facility for sending events to xwidgets from Lisp code in a few other changes. Should I squash them or send the new commits as individual patches? Thanks. > I'm unable to test this at all, because: > ** (emacs:2173922): ERROR **: 00:09:01.997: GApplication is required for xdg-desktop-portal access in the WebKit sandbox. > Fatal error 5: Trace/breakpoint trap > This is on Debian/bookwork. (And without your patch, just building with > xwidget and `M-x xwidget-webkit-browse-url RET fsf.org RET', and Emacs > crashes.) This is probably the same WebKitGtk bug that also happens on Fedora. Can you tell me the version of your WebKitGtk package and GLib? If you can't upgrade/downgrade, continually retrying could help. From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 05 Nov 2021 07:48:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Lars Ingebrigtsen Cc: Eli Zaretskii , 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.16360984795690 (code B ref 51473); Fri, 05 Nov 2021 07:48:01 +0000 Received: (at 51473) by debbugs.gnu.org; 5 Nov 2021 07:47:59 +0000 Received: from localhost ([127.0.0.1]:44757 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mitx9-0001Ti-Ax for submit@debbugs.gnu.org; Fri, 05 Nov 2021 03:47:59 -0400 Received: from sonic305-20.consmr.mail.ne1.yahoo.com ([66.163.185.146]:36820) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mitx8-0001TS-GY for 51473@debbugs.gnu.org; Fri, 05 Nov 2021 03:47:58 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636098473; bh=S9rBgYflu6Lrcfltw390ctqIX/qy2kHNxtTCzBY/Zh4=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=iRqVKebQTrM/qUETV2rHhXwN7BEVn8K1YOi/25+AwgFLhg+onvKoR6rHX0LipGPUJzTxkOts7FL6ikvlzDU6aIYNclSsIWle37HpOPDN+C7n3UpcvwHJ2tGDOwsJfHj5YJTxWbzbp7cWa9t1Rb0DqkB8izo/ApTD9XMY/x2tXR/5wsNRBfRD7jnkXP9zjoyzpDxfq94Ia26KfGyK55MPlREAWu0s0/+aLcHe9TOloeO+quS2L9jCPahGVVefJoBNrj+KmAIQv5k0DkvipABG6auHwUoGXNtBs4LmMWHPBcUbSj0PWsfqgbFJbptyXnk0S1pR4eSBOsegdsj6s0N8Ng== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636098473; bh=oJkq16AJODPA4HlcYHzRooicqiqe7Y30CxWhjd1G22W=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=TTqjRm4+Uh6NA1NyoA5QupevEsz37yKrr4p26BdfNrC+n65BqEa6yw138aAeIN3q0eiw2JwonPlK+xESuR4y0K6Pl6xq6UUt/NRv1D6retDqudd9GKM0Ly3ZRKgNGsrzUhJyKmFvNSXQyCb44EOafMOo914UJK1GzB10Q6MZp0XTTRFSfDdSj4moBOEdGwI5/xSRjZBnFDY0J/GiTnhm22hxX7rO91QTPZBc95OJ27hg/JkLwOyu80KSIlXTugsBkmdvk3nZe/0oTjttqf4cibPiz4DyNw4O6/Fr6yR2eWx+0sa/M3MS8SGpogA/fwL7HN2cehfrjyXHLxKi+f6bVA== X-YMail-OSG: EBQNJf0VM1lkCv1_mj4eZcNxay6NBrXS87svUZoTNw0FDGS7fW3fR40Oe4qobiQ HXD.sE2ebRlwS57MWQ8iWk_n3XcpBNOr1ilWY1zA8QPsbre1tBS3FDI7ONC1PNqEGedi0CEHtBx8 9alBFwCV7POBm_Llme6yXctG5dmfoV2aLJns9EbbqNqW8dFqSFkpKTFA__dGAm4E26j2MWsFf2lc 1G.XQzC6kYDlfHT6F7KA8_Zq6RkGHH2MOdwnLzTkRyK_JMClIGan8WXb_dlqRM5cOG5zKRR1CSCK unI9_Q6lz90hC0zlqzw46YtnFa6HI4rZQ93WV_RJM..tcJ0LUL1_v_So7ArM3NR0esRFs3U9NaLT jpEJNrQ.GNKYvoJy2SB5zIj2jsQ4g4HCk2ld.cJaJcD2PWu_SYSUiDX2VwxvWyxnJ7Bny_l26D2O id26ZkoAT5Zw111DvbL06IbRQR_GMkMtf.bv8IdnXnmpqQU.EwVnT7NxLpkXoEo3j1qymMgVd1fS 6VrMXUjwQCGxBTcYGXbjAIReLQ_RbSVwde6XswbaOvR33MeQ.4uCHB15kkjZRvP_3pH7tctVydLt IWy.Cl77_xfAvnnOXDNWwGDgy69PeiX_x7A8_e48zpOSK_.hy4Qaxi9gHzIZkw6cJW9OU9P7dL0d ATmlJj40PEGxx4uZPya5YXyCqVMjeE6rw8ylqPQB1broCfXqSg5YyMNiTHdbMyd4ADMxMmRhkCik YAnHI0RQg3zoymFPuG3phxG91e2KDp3xILinSY.QlK2B1JvcuzcEMjbGoaYnodvZQ0.oZ9KCrnYh M11jAfinD5BlHbrOnDP24pCNf4O2rzNwc2Bpkw5xFho9j0wxnWgw4Zbnhguep.qzj2koOYtaicYE 7eYJW3jKB4vENT8QFkiI3WrwydqHRlqL_JKr0HzzB37ir8h1hqDhL3V2CAkhLmTZA4W7mwXVzQuQ 6YTV7tnA5EHahnYMYrnH6hK3Z0lVDnSXla__UELjKuxnkAnpvLPcmALGEUNv3ICVo4kSrnrV42jt mIULVIo_hWMj62lOWlkCK3ROCdeR698klJR1r3OYr0T70xmtpwBaXmdIDU2H_PKFQ_9GQ62mXQZt P6RUx074I5KuwGfZ1e6IEKeXJzfJROXZs2fMeCyG8JlNkyYb3M5886sYVFqoT0WeeYXVvCnB8Kly z1Nazs_dmbGnO6I3xla263xIaSz2ivhJKLAv8fLPNfWMbJ3EWkR6bnooIVvAm6eWoClzKJEAS_fc jnsNrUMSUWLNWptP8K8Z5qKLjmwipA5kszAMyh9YyFFqPUjVYNBY5CzQ.oS.NBVFNEZ2IYeOMqo4 W2lq1RpDEAEENq0jnDHJojWn4XOHP8GvQsE.v54kDGjFOkIb7GTyJpw0C5j8AtujF27c1jvXebTU pHr.8I83KzsgSRhFY3MegUMF_h8oROCHpm3ghFSCKkxhbUcOKlyRwmiYZ_k2_lEo39YJERY.FOBz XGl1kza_irzdy5KXdtO4._BX.e1HOdcZPEIFSrnyTZbAP3o9VN5FVaY2ertj38T1zdW2anuCTBpC H6NCAS2_dFv0xrqPwh9MuOBSZS0QlzfaFlzpCrDntuzUcvVMV7vL2co0T72yDSFqIieKtR5gl3FJ 3RbpMa8fvZIWb7RWHHwYkAA2AKaqbt_D6S9FL9E45Kvc_YQL8FTKo3V1QG3YbaVjPLqSmxtS4KAC 9ysV2PZOpvs.r3KHkN3eAIlowXGhVGS0z.CpK_4D6HEId2LHiG0qbZvTbr82tMYBB9aJgK4pnt3L 1MTOvm.AfscLm3mgYgtQQQka41XijhUCGvs_RGYr2eviVygqRhP.Phz9Ag.r2OG.MZieJ0CLYeXg AdWVQYCsas0O41kOZGeOFtK2gOSoh9uBTMc2V0i56stph_73Wjnf6DEkNLZReX_Rr2z0LauFtjEh T7b.x0pje5cedD69zIHFfp9OP2i2ka3qgElnCLF8sS0fM7DTPBdXwbFZlbxBrIC60mIv8b5URcU_ l9x8s0HnbYbGgrewF14OTc89ew1hLSIR3qKQvSPCD7EHGmaFe1M4jPP_GVq9NLynW.uMjknbMulM Ay0QO8FCXE.zDB4vbg06UnfP8dVHn7U0jMegkXkH311QaUbP5hbvjd5W2wGOjfYKVhpXNYKjSH7N 7_Z1kU86NESqy.1Q9TeuRsbWsR8LGky0pGQvpC1WUsGwBQfgo2CkybeaYhpGPtufeqvQ_Jy95AN6 pPyUGYCRFMnXXVtg4LBMPxAXrdxSv0oSDcWSfQ.ILnQgBIhPXnXUI.KY- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic305.consmr.mail.ne1.yahoo.com with HTTP; Fri, 5 Nov 2021 07:47:53 +0000 Received: by kubenode517.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 66f750aac35d88b520b93104d0b7b875; Fri, 05 Nov 2021 07:47:46 +0000 (UTC) From: Po Lu References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <83h7crdq67.fsf@gnu.org> <87wnln9i15.fsf@yahoo.com> <87pmrfkqeq.fsf@gnus.org> Date: Fri, 05 Nov 2021 15:47:43 +0800 In-Reply-To: <87pmrfkqeq.fsf@gnus.org> (Lars Ingebrigtsen's message of "Fri, 05 Nov 2021 08:33:33 +0100") Message-ID: <87bl2z9h7k.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 155 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Lars Ingebrigtsen writes: > No, I'm using Debian/bookworm. Thanks, I tried to explain the situation better in my reply to your message. From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 05 Nov 2021 13:11:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Lars Ingebrigtsen Cc: 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163611783021523 (code B ref 51473); Fri, 05 Nov 2021 13:11:01 +0000 Received: (at 51473) by debbugs.gnu.org; 5 Nov 2021 13:10:30 +0000 Received: from localhost ([127.0.0.1]:45100 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1miyzG-0005b5-09 for submit@debbugs.gnu.org; Fri, 05 Nov 2021 09:10:30 -0400 Received: from sonic309-20.consmr.mail.ne1.yahoo.com ([66.163.184.146]:43820) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1miyzE-0005ar-5U for 51473@debbugs.gnu.org; Fri, 05 Nov 2021 09:10:29 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636117822; bh=hL7zGWRoYxcOP/XUA0Q4jVJs51DJT3doArX4OJviviM=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=ETcja/TwvGodG0wXhNJHq0kH6KZ5OdCGKO8FTBIYePmZ5Q1CNIa6uOG/NFTHDfK4kGI02puaHUh+5CsU5f0e1r9XZdKVwtJW4gfYw+8owQ1XX1hC5f+xMw4+YXH2uCxc+Qh8+cunOUps6zbUQrJCgCrjHqlo5DK+Pi+kCS5HD+UT5Rp8yhjyYf6+73vQEgxxmqiM9488gOfKOx5DsAzSD+eKz5dAkE1QaAdG6hBjODWCZOm0DunpRr1vpEhNOJfiScufhYJZsqCB5D6V167KYGC9/nf6lWe6CoE4DC2833ZzJU689jbMh2lis3/cUosZ7xJtyH3LLbMpsPOTb5IXFg== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636117822; bh=tLwJQBMlKIIiFE/AKyn/WPh9LvDcWOGG9B72I+ASbn7=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=ohdivxaDut1cP6sdiGBYg7V+NlQHDaAhl7sLmzIKE1SQVl1Zl9gnM6iHpP3k//9C1SNShdxs+TsngkcgKITXnKFhbMUmXh+dm4AnIsh584T9sSVgls0A3qWG2lgww1iHzj5HGgkL2AW7BOYSqzuUklw4dwMMBPW41kFCmBr+/p8ABBxs+uh20/SBtBwqcEndMMIsQZkzAY4wnq9Hao7u17QJI09A8e3RT87cFtdcYw5itX+NUfcEgRgjY/xylrNqzs6jpha+0T82Au/ezRxYo1bPpgHF9x7a6aKu6c4sfc9QIBHogDaBN3eTe4JYYEG1gGr1ppVv6IL31Mq17R49UQ== X-YMail-OSG: 4uUy5mQVM1lrOCs7ryzBuz6bEWI6FVBvDlcNQX56OPUyRhCokpkLiCWgb7Pla9t bym39Qp4i5mcquumO.0GsGeCreTy1dNH2X3MkJHcXULe0qG9kcGJSPbXin5sU3qZGNjuqyl4qj6y VBdJaLYVb0froaM.jhFQQU7axcvYfhgzYVUYUhiLgXbc5cveMM3tBVZAPv6yZJzndxd2AtMufYA1 R9F5IVLgyyff1DxWokTVUFVaIRfDGYaQvsgJYnasM5DXserr4MVkksTjm.4JNqnbRrSY4.mM1azg KGZp81wXgJ_5hAZ9usqgkOzbFLqfMLu0duczjgv0GgE_fAMaAEny6mFJZN_6Vtui6MdwEJzHZ2Dj N313UEeCIKlWdpUgPcnsmHrZj.ad6cd81oexmOWIRkkNHbaofrTcIaBKRQujsYB59b8I1dKYxWSJ .yJNAHQI6Mw.YhF9..raBj8F_GZosLVgDXY4DlV6L9mTjWbnNRyIFUfMkWr4O3GDdzcYrqEETnet OrH.GnrLh_fj74MTVdl7wYCee5R9ORIlXwEya4o4Gmg6u4tAPMhWkG1jV02pEeAdIHR6UDnJKiLO 0nMeJZWl8TMqJERNik.wTRciARwkn46viP.8FVaOYLoo2O.JYa3vMe1DXROK5BzrngdgO14Kffj2 wKHAkDcTTjPO0duaP0omVeWPEFVRDiZhQgCVf_lVjJ6_V55h_1ICm4LOhZBcHV9MR_H7wQ64J.mc gpq1XjdiBPI26ilbEfX5uosNnWubg0Xcon8d0WbKpLj6enOJ5pjkrpZBjC_HGvSHayioFFvkIq8J eFhG3CZ8xM46SgSB6mNcPwZahnBuLeBgSWBpI6EItQbVZSKIbNrPqPKam2HHdNB5QQ29Q2DIK3Ml 1EZQ5nhZWM5JqjcN5YGwzGEjW.EEY5loJE4.0d4V4lxo7FXIOPeEKnu4gXFm_x3pKG64p._stUzL M2Ut.LcJ2WSUmlHb.uclhboPwdsp86tfwlJhEzGY6vnlMqbaDaZ8kXIMV96xWVWZxF3oWMk17D1U tWVCiJiKfEFTpfEfzNSmR.o3fVTKe0506CKbAgzUAsbFqq6N4ZsRGUlpioQLNhGZhwzIcOkFdQoa xPyRrO0ir4_bc7v5xbLgHtCKdoNS9g2A5Rw4dRKgWpD46KUO2AVHzWccup5WwX7wi1qRm1H.0IKO wGmpNuew3f9hlsohGSxq0T9Ws6nL9NvsLxwq1bmXJfi7eHDzGgWl.AfKr__pAaB93eECr1Kq9363 BCK5vRe5qKA2ObfkHBUAds9.WVUiWpQbKpip3YcOqJZOK7vPxMCfk60Kw.vO9WXXfTDJoCkXghA6 ixKobi4bMIBQi8ovMCnvXNcERmW.3.sqsieIyrQChq2RvSzndQo7q_27XCGs6AHQhNiYOHQMcwhI pHmMBj7ME4zWcnMRyd8J5yceeHExURHpwi0pIT5yfBH00_iyvR65mg9M37cmNhD_ljHzS2L9rB2s geZ3UpK_erZE8grlh1.oTTgqs9JNRBXZVVzPxAeVKaak6lcUKl265uA.6_7z5rYIyye5I.dFbGMV vIH.hecwrSKNRjwxBpp76kHVyPIjqGyjsaqc6UeHegqVuuPXa6vhMv93E4xcJkaHisWQy1xgVyGZ _qazbo1pEKMOs4S4UXuLzrPHhH3ALv9cWcm8jzyuLcHurT3dt8YzRSuHM8l7.MStElSl3o6W3glY C0S0Fxu_xoM93pGz6lzKIL1fH3h6WqfVIQaavmufcDPTOkng4y45tRKOUwDnUP42E8RHQ9srnKDU 8C6FvTsnHwmOLNdrsUK2M8xQUpPH3ngj8ZzN7NL.W6R1x80iWgmKlthEVf4zZOh.ZKPMUNJ0n0Jk 8YK0HsYz1QrNoWGTWvBYrkQHTwxMPMr0JT4.PW0E0VjGdL5WoC2S9h702izJShGVDBQfj2NB2iE5 AAWzAMlig2d05CDtZ8J8ZfCG7IVnaW8DO1lknnDdf2DwBfQwsIpdARc2_5.7.qhfZruVbqOlb9ms .6YlJtJEsUTkbM7DwU2ia2H4X13O8_cZPT16GgmnhG5DEie1SuuIJWc8F.H.IcxfWRfai2Y..DfL PoB7dP._0nuF_LsB9kx_9kOswvTVbchZOCU34lKnhAi4yZaFD1QC210HULGTUP1GgdzPqYguAY0y uVpa_skJovyMOu4nGbTrLxUbSk4MpGk2TTnZikZATCs7MjsM5fjgohugiMZdvFMWqhOzNaM4hhXY 3xAguRsnSckCFHR.rA9MZByV_npB3ZDLGdNipWSlTRjvDUj5nW7T0zCGTL1SWWWs- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic309.consmr.mail.ne1.yahoo.com with HTTP; Fri, 5 Nov 2021 13:10:22 +0000 Received: by kubenode508.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID cda815e78e6c288261318be16a5dfab5; Fri, 05 Nov 2021 13:10:16 +0000 (UTC) From: Po Lu References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> Date: Fri, 05 Nov 2021 21:10:13 +0800 In-Reply-To: <87mtmj9hts.fsf@yahoo.com> (Po Lu's message of "Fri, 05 Nov 2021 15:34:23 +0800") Message-ID: <87mtmi92a2.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 34760 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Po Lu writes: > Yes, but I fixed that, and defined a new facility for sending events to > xwidgets from Lisp code in a few other changes. Should I squash them or > send the new commits as individual patches? Thanks. Also, if you want to try out the enhancements, here they are: --=-=-= Content-Type: application/gzip Content-Disposition: attachment; filename=patches.tar.gz Content-Transfer-Encoding: base64 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 --=-=-= Content-Type: text/plain I have tried to explain the user-facing changes in NEWS and in the manual. Thanks. --=-=-=-- From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Lars Ingebrigtsen Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 05 Nov 2021 13:29:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Po Lu Cc: 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163611891523184 (code B ref 51473); Fri, 05 Nov 2021 13:29:02 +0000 Received: (at 51473) by debbugs.gnu.org; 5 Nov 2021 13:28:35 +0000 Received: from localhost ([127.0.0.1]:45128 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mizGl-00061s-2N for submit@debbugs.gnu.org; Fri, 05 Nov 2021 09:28:35 -0400 Received: from quimby.gnus.org ([95.216.78.240]:39354) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mizGi-00061e-Pr for 51473@debbugs.gnu.org; Fri, 05 Nov 2021 09:28:33 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnus.org; s=20200322; h=Content-Type:MIME-Version:Message-ID:In-Reply-To:Date: References:Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=ym04Qh9054sTNMmMsQ98qnhzrsbnh3cnkEAzN0dla0c=; b=t8Co3oHdwFZauWed8qvK7CNgeI 9Bo81XF1D+vaGtqgpvOD1xnl/5jnR+x5rzkRB8ofuA1pUpQ3UkDL5UvgoNjmLRsxYcsm0Qw9yrIfo RK5iWRkk1tAkSaeUDmEsrso++RNgdconVcn/kWI0DvLnExqXzE909A0ylsbGs9PkCu3k=; Received: from [84.212.220.105] (helo=elva) by quimby.gnus.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mizGa-00054E-Br; Fri, 05 Nov 2021 14:28:27 +0100 From: Lars Ingebrigtsen References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAABGdBTUEAALGPC/xhBQAAACBj SFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAALVBMVEU8QEs3OkMoKCsb Gh0fICRUWGGcn6izucX09PbO0todHSFqcYEgHiEgHR/////UU9brAAAAAWJLR0QOb70wTwAAAAd0 SU1FB+ULBQ0WC0nBHr4AAAFvSURBVDjL7dExS8NAFAfwVKxIJxU/QD2vKOKUgwoFQY4DoXRpS4t1 FA3VyU3dXDTNWtDSTdLocHTyI2gmSaduxXwX3+XuEoTL5uh/SOB+9+69S6wCMsdC//DnsGXlQLmQ B0s5sJbTg6ybAXc3zHDs5Yx7+2gboeq5JSPsjlyHmuBkMLg8owYo9j3HXU4BI6x2lVdGd961n1Vg VVFxnNF4fJoBQzQxfON0eoN7qoBiRsEge73nSrPvZj2YiNhXdVvvBw80myoR8e5dfby0dQVFWJcs 7QxR0U6bM6Zgu3vR1DOKHinsrw5t1KpoYDoIvZ4j2nprS8AsE2iH/aMnP4MoVO1BcYcmIFYjCSy5 KwrkUawRJQnBKKOb+n/ASbD6pWvsEpafx2IhVHDOp1HYAPOxHAJZ4pTveLEAgaJ6PVBTAMzieEEI 5wBqXUJ8OCeQGsgUjtR3tWYxkalx0YoHGj4JSYVP4BEomJNfqU3ApzDeD3Ut/PmjBFl0AAAAJXRF WHRkYXRlOmNyZWF0ZQAyMDIxLTExLTA1VDEzOjIyOjExKzAwOjAwxemLVAAAACV0RVh0ZGF0ZTpt b2RpZnkAMjAyMS0xMS0wNVQxMzoyMjoxMSswMDowMLS0M+gAAAAASUVORK5CYII= X-Now-Playing: Anna B Savage's _A Common Turn_: "Two" Date: Fri, 05 Nov 2021 14:28:23 +0100 In-Reply-To: <87mtmj9hts.fsf@yahoo.com> (Po Lu's message of "Fri, 05 Nov 2021 15:34:23 +0800") Message-ID: <87cznelojs.fsf@gnus.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Report: Spam detection software, running on the system "quimby.gnus.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see @@CONTACT_ADDRESS@@ for details. Content preview: Po Lu writes: > This is probably the same WebKitGtk bug that also happens on Fedora. > Can you tell me the version of your WebKitGtk package and GLib? Let's see... it's these packages? Content analysis details: (-2.9 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Po Lu writes: > This is probably the same WebKitGtk bug that also happens on Fedora. > Can you tell me the version of your WebKitGtk package and GLib? Let's see... it's these packages? webkit2gtk-driver/testing 2.34.1-1 amd64 WebKitGTK WebDriver support libglib2.0-dev/testing,now 2.70.0-3 amd64 [installed,automatic] Development files for the GLib library > If you can't upgrade/downgrade, continually retrying could help. I've done an "apt update/upgrade" (and rebuilt Emacs), but it's still failing in the same way. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Lars Ingebrigtsen Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 05 Nov 2021 13:34:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Po Lu Cc: 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163611918923679 (code B ref 51473); Fri, 05 Nov 2021 13:34:02 +0000 Received: (at 51473) by debbugs.gnu.org; 5 Nov 2021 13:33:09 +0000 Received: from localhost ([127.0.0.1]:45136 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mizLB-00069r-LJ for submit@debbugs.gnu.org; Fri, 05 Nov 2021 09:33:09 -0400 Received: from quimby.gnus.org ([95.216.78.240]:39376) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mizL9-00069L-Cj for 51473@debbugs.gnu.org; Fri, 05 Nov 2021 09:33:07 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnus.org; s=20200322; h=Content-Type:MIME-Version:Message-ID:In-Reply-To:Date: References:Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=vD/CQkwbxdELlVzDszx3Ft8fAObFwFmLwU89kxTTcUI=; b=gqx+qNmf8ci4RngGOcfIw0wMZG p804M2zsjeIW8maEVyjBKFZO8IjlRfIq9XE7qBBPu4ky4SCMRYSlR1I6NDXsdwn2C8VkX+CDjO21j /hoGIi5Jv5318xf9g5yFmVJEzat+8EuFHdUA6Vm5r0JKl7achKrkuDwgwcCDTx8dSEUM=; Received: from [84.212.220.105] (helo=elva) by quimby.gnus.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mizL0-00057C-Ik; Fri, 05 Nov 2021 14:33:01 +0100 From: Lars Ingebrigtsen References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87mtmi92a2.fsf@yahoo.com> Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAABGdBTUEAALGPC/xhBQAAACBj SFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAALVBMVEU8QEs3OkMoKCsb Gh0fICRUWGGcn6izucX09PbO0todHSFqcYEgHiEgHR/////UU9brAAAAAWJLR0QOb70wTwAAAAd0 SU1FB+ULBQ0WC0nBHr4AAAFvSURBVDjL7dExS8NAFAfwVKxIJxU/QD2vKOKUgwoFQY4DoXRpS4t1 FA3VyU3dXDTNWtDSTdLocHTyI2gmSaduxXwX3+XuEoTL5uh/SOB+9+69S6wCMsdC//DnsGXlQLmQ B0s5sJbTg6ybAXc3zHDs5Yx7+2gboeq5JSPsjlyHmuBkMLg8owYo9j3HXU4BI6x2lVdGd961n1Vg VVFxnNF4fJoBQzQxfON0eoN7qoBiRsEge73nSrPvZj2YiNhXdVvvBw80myoR8e5dfby0dQVFWJcs 7QxR0U6bM6Zgu3vR1DOKHinsrw5t1KpoYDoIvZ4j2nprS8AsE2iH/aMnP4MoVO1BcYcmIFYjCSy5 KwrkUawRJQnBKKOb+n/ASbD6pWvsEpafx2IhVHDOp1HYAPOxHAJZ4pTveLEAgaJ6PVBTAMzieEEI 5wBqXUJ8OCeQGsgUjtR3tWYxkalx0YoHGj4JSYVP4BEomJNfqU3ApzDeD3Ut/PmjBFl0AAAAJXRF WHRkYXRlOmNyZWF0ZQAyMDIxLTExLTA1VDEzOjIyOjExKzAwOjAwxemLVAAAACV0RVh0ZGF0ZTpt b2RpZnkAMjAyMS0xMS0wNVQxMzoyMjoxMSswMDowMLS0M+gAAAAASUVORK5CYII= X-Now-Playing: Anna B Savage's _A Common Turn_: "A Common Tern" Date: Fri, 05 Nov 2021 14:32:58 +0100 In-Reply-To: <87mtmi92a2.fsf@yahoo.com> (Po Lu's message of "Fri, 05 Nov 2021 21:10:13 +0800") Message-ID: <878ry2loc5.fsf@gnus.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Report: Spam detection software, running on the system "quimby.gnus.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see @@CONTACT_ADDRESS@@ for details. Content preview: Po Lu writes: > I have tried to explain the user-facing changes in NEWS and in the > manual. Thanks; I've only skimmed the patches, but the general gist makes sense to me. But I can't really test them, so somebody else will have to do that. Content analysis details: (-2.9 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Po Lu writes: > I have tried to explain the user-facing changes in NEWS and in the > manual. Thanks; I've only skimmed the patches, but the general gist makes sense to me. But I can't really test them, so somebody else will have to do that. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Lars Ingebrigtsen Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 05 Nov 2021 13:36:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Eli Zaretskii Cc: luangruo@yahoo.com, 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163611932323889 (code B ref 51473); Fri, 05 Nov 2021 13:36:01 +0000 Received: (at 51473) by debbugs.gnu.org; 5 Nov 2021 13:35:23 +0000 Received: from localhost ([127.0.0.1]:45140 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mizNL-0006DF-0F for submit@debbugs.gnu.org; Fri, 05 Nov 2021 09:35:23 -0400 Received: from quimby.gnus.org ([95.216.78.240]:39452) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mizNJ-0006D0-0f for 51473@debbugs.gnu.org; Fri, 05 Nov 2021 09:35:21 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnus.org; s=20200322; h=Content-Type:MIME-Version:Message-ID:In-Reply-To:Date: References:Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=HlZ7NvUNTt1xmt+Vscb7Oe23bXrwZzDcnNvd7XpQD70=; b=Qz5/sGF5OKLhjzKKhzqaXk+sG+ XZ0DLV/AvF2enBxV58E7rd4WiDaIlzG/2Ql5edg96C0Avxy/D+Js3WCoJbTEkZV6/GhRNKqpT8t7A 4UB71aoQ2KvfU4Y9vCe/+Cr+2s1GcVS0oOQSP6RVvzADMRAwB5FVv2iRLsDsJRNJLfs8=; Received: from [84.212.220.105] (helo=elva) by quimby.gnus.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mizNA-00057g-He; Fri, 05 Nov 2021 14:35:15 +0100 From: Lars Ingebrigtsen References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <83h7crdq67.fsf@gnu.org> Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAABGdBTUEAALGPC/xhBQAAACBj SFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAALVBMVEU8QEs3OkMoKCsb Gh0fICRUWGGcn6izucX09PbO0todHSFqcYEgHiEgHR/////UU9brAAAAAWJLR0QOb70wTwAAAAd0 SU1FB+ULBQ0WC0nBHr4AAAFvSURBVDjL7dExS8NAFAfwVKxIJxU/QD2vKOKUgwoFQY4DoXRpS4t1 FA3VyU3dXDTNWtDSTdLocHTyI2gmSaduxXwX3+XuEoTL5uh/SOB+9+69S6wCMsdC//DnsGXlQLmQ B0s5sJbTg6ybAXc3zHDs5Yx7+2gboeq5JSPsjlyHmuBkMLg8owYo9j3HXU4BI6x2lVdGd961n1Vg VVFxnNF4fJoBQzQxfON0eoN7qoBiRsEge73nSrPvZj2YiNhXdVvvBw80myoR8e5dfby0dQVFWJcs 7QxR0U6bM6Zgu3vR1DOKHinsrw5t1KpoYDoIvZ4j2nprS8AsE2iH/aMnP4MoVO1BcYcmIFYjCSy5 KwrkUawRJQnBKKOb+n/ASbD6pWvsEpafx2IhVHDOp1HYAPOxHAJZ4pTveLEAgaJ6PVBTAMzieEEI 5wBqXUJ8OCeQGsgUjtR3tWYxkalx0YoHGj4JSYVP4BEomJNfqU3ApzDeD3Ut/PmjBFl0AAAAJXRF WHRkYXRlOmNyZWF0ZQAyMDIxLTExLTA1VDEzOjIyOjExKzAwOjAwxemLVAAAACV0RVh0ZGF0ZTpt b2RpZnkAMjAyMS0xMS0wNVQxMzoyMjoxMSswMDowMLS0M+gAAAAASUVORK5CYII= X-Now-Playing: Anna B Savage's _A Common Turn_: "A Common Tern" Date: Fri, 05 Nov 2021 14:35:10 +0100 In-Reply-To: <83h7crdq67.fsf@gnu.org> (Eli Zaretskii's message of "Fri, 05 Nov 2021 09:20:32 +0200") Message-ID: <874k8qlo8h.fsf@gnus.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Report: Spam detection software, running on the system "quimby.gnus.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see @@CONTACT_ADDRESS@@ for details. Content preview: Eli Zaretskii writes: > Sounds like a serious problem. Any idea why it crashes? What does > the backtrace say? The start of it is: Content analysis details: (-2.9 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Eli Zaretskii writes: > Sounds like a serious problem. Any idea why it crashes? What does > the backtrace say? The start of it is: Overriding existing handler for signal 10. Set JSC_SIGNAL_FOR_GC if you want WebKit to use a different signal ** (emacs:2296186): ERROR **: 14:33:31.815: GApplication is required for xdg-desktop-portal access in the WebKit sandbox. Fatal error 5: Trace/breakpoint trap Backtrace: So I guess the Webkit code is doing something here to exit, so it didn't seem worth trying to debug further on the Emacs side (for me). -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 05 Nov 2021 13:41:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Lars Ingebrigtsen Cc: 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163611963624371 (code B ref 51473); Fri, 05 Nov 2021 13:41:02 +0000 Received: (at 51473) by debbugs.gnu.org; 5 Nov 2021 13:40:36 +0000 Received: from localhost ([127.0.0.1]:45151 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mizSO-0006L0-IT for submit@debbugs.gnu.org; Fri, 05 Nov 2021 09:40:36 -0400 Received: from sonic301-31.consmr.mail.ne1.yahoo.com ([66.163.184.200]:41041) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mizSL-0006Km-MJ for 51473@debbugs.gnu.org; Fri, 05 Nov 2021 09:40:34 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636119627; bh=RwV2GLzhOXqj8B/BtjS0zyibhwDH75tMqpTO5Plf/7Y=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=mrGb0Wgj4cwrMyRMObyQk1xC/JiH5RIR8RCTpmLTh63ouHGuMTmF3TW37Wcbjq538V0scT3ZVbICPKZ5i+C9JHJ5DykimYpPET1XonhyBjt9gdzinX27HROCTs3CbyuKzSOLurs6XAYYd5tiarLN7f9QUz1qY3IDiOVFw8feLRLQ0JbyHG9brnzdcUvrSNv9gTCwwi32oQD69bBIi7j6JA8RENfY7UVuuUG6tNSPHjXfKv+vmWS0sTAQ9zMZRNNTcvaRttzlEbaIrwg/qRFlYuC37UukTpgBaSUOflFptJ1ok2ARAd5EVDM+/FOcKdX+LUt+76KHowBP5JJE567RGw== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636119627; bh=c6lPxV+TDKyet7uH60yNo7avLcQ/mtKOWMWlJaIZvll=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=cyZdORnK97+Df2B1ZYfQ8ZD7hw2vDORLj0IP4DGj7dZv9Ci1ntC8KdECmZOMfPiVrOq2EhCDlzxUEp2Fp+/cTeQ3con5r3ilQIunCBxXMoTkKwqQzOmLMRuyJC2A54LEecrY+snCaFPGctJqk/NTqMwfebyeSuMeuyOcJNLlt8342npPtfuHTjiJodQW1qoyE5N+eDZDdBIS44od3ptI+QqbtQSzG9vrbvjvECtI6Sn4u09i9kyYRe/DjnBvINmaWKPkI0sFwpxl/GLH7+Y14Rt5VHN17PxJSo0Pi99WxZSXem+wuTzGpSZrHjo9Mlrt+DVsPVGIucDb4HhUkcpvbg== X-YMail-OSG: AMu5CO8VM1mgQ_SpQ7cv50mGLFkAH3wU9oeDUOgW7dNgN8JT6LaevFKuKGKwDYf 1u.uobvcJfk9PDXN04_otQudy.OxZGNqTBJQ79HyJg6WsEIwKEkeQJtCcwK2tXun2zm4Mkap4_uh tV0uflkgdcEpuIjJARAur4wl_xtn88918hjoTp3UEUTtgUshPGHpAVKWL1gquZe.QWXu2Hne9Ey6 wgyKSFxUZS4IIV_3Pl5QO9Mq3i0vk4DZTx3KZAqW9izUA7vV_EW.FnOiZ3UaCLUKRle.JzmOFl9V wVxKuZmmjJZ.4juYfXHRKpDxEyty0aRFoU6o6qcl2tFmQ3bdH6UDjl48SvXJuWrUfrmrNbROK3df RQM7dblNbYIGin9DY6bd9GoZ8kb83cJ5xm6OW.cTJQRxyoR1j8iILCcBfk5eQdS86OFSw2P0A4ej b5f8NS_NkmBjt0mGh14Nb8J6zzR33nkn8xZOblizVK9v67xzRteOeV5JEMSlZMMj4eMkfE2ggSMk y56Qoj0JCaLfDnXShca6SKb00clW9gu0Qzq6cDCRkaP5rAxZRjuetLdFCn41wHWIsLrLnZ76ylC9 3pEiLwtakdPABjZ0DQUfAmomfbx.ywM367esT4n5fOF2bHbvJd7zl_UYDZsDEhyUcN09PFXmy5mI Fgkdiv5ljpFKbZkeNPaeqVTu49fOQHq1uUHRjazqlTEQEtZ1bGkL8H2DqptB66f5AVXp9Pv2P7ZG DR8Ums.CLU.MdHykO7ekzjDrrBUZWrl2RRHjVKpsP1TUTpG3bId3pkbSQbN1zf.lCVLiFCTtuKbc HoVQQqCUjrjUImryAkTjO_4TU6WSu.V.aYDr.CcWjCeyH1P0MsSps7q7QH3KL7AnEC2is2008DD6 YFxfBaWtbU1jg8LxvBcgnnIyUHTEL64Om3v8QeWsXHb9Qo59gxhGyo4cz.dFwmz5R3LFlY1ZeXW_ 9EHkrpZvbunGxAV7HRJBD4Hp6E1t0xvJ1wq9zd256xWjTbDQ.b_0IodQLLil2uxxz6mQMnbG3Piy S9PWnmxlgQJfA59BlAVG1ywVQsndgvPJxe7IY9gITcqaDpI8m3lvt4WPApmQbit9Np8t7WWq472B JUC4_UQoxRgb9ziKlTGxU5QXpvgs5J1042rdMvjUtrf0_NtkKUjj_T_nqSPW4Xi1wRGRCXEyRhom 1dlu.awRYDtXXpX0hFu_iPwgo9F9Xp1p.6.9K8FQXqhfUmOPxI.jguHq4r2joCBuZAH.k_pdigHx aRw5NCnx9a4RisVXqkQ4.AbBjNaI8uB1Y6X1zHW52v.vksnFTAYtJNHBuAGVbWmlvKtmsbImmQqC DxPYmFHGbJpWjTA2Qeow6Lv80xIVN_ff4rZkwQXmyn7H9v_w2Mfw97KhSNjvLrnkaU.dlqVTDGiA 4IZOS2yJuuUnwGNBh2rkSsh.QWJAemC5YIZmVGxyht8PNQ9VhTnAVFj6z8_OElBYz1B8wbCwMDtQ PVw.JxPvLv4cPxxulAfZd0dwO8l8lw_pKEG4RZOnqPhFvGVZcmhXxL66O8jRNJ32kaQVCcXVDHG6 bzCdtUwuv21riShjE.6SEMQMNq0F2nDWCKmM.CL4AEeJPCYZ4BZ77rN3o84jDSxi_MB1ftsWTAFU 4QLo7cAcJslvt.0KZnA2KE3NlZN00_ng.vJOOHM6r2K51BzC1mtMOXSRjy9mnd2molK433JHcx0_ kbkm1TUeyn_h.I9Z9rZsnaoPVvz4ZwB8GIo.wyidsVexXU4PUmiW2HRF6HYZtQ6J1r_RKIl_.YvZ ENv4twnBUkUm4qi13XO.cxf1glHQkBa8kBjSGG0r10soaXKxfzKAc5wMaHRCEKWaLPeIl4CqAMWv cloSwaLbTxYMmYshWGn08FSrQ0_D8Waiy53t4bgI0VHMPTy26f1krjfqG18JMVBeiSiG_ZF3uYtd cvyjw4Lre2EXVc5.DRTNf_xYn0jz.cxv3BJSpI_zA7XdaTNpsQHWVc7R.Hc118EXrykgI025Ww1S r2n_QDjrXGhCfbDj3F79kopOYbvu6YnVja96J.CaibGEcPeHUZRnYbpk_yAPQR03rLV3bpjarhj9 As7VCbHriZRwzKSFDn5pc5N9Wne1rRgFY7sU8RgAB5G860f6cV8EjpqDhs5M9u0RBlR_UeA6MVaA tY9g5Bx0IiHTNzExc.ygOwlJaTq9oppfDX5qoBs5pzmuZJDhTHkFdawKbS0kzNt_.ISJInVSLZKc r2AfoG6HDcBgTpmdiBuYQZ_ogmP7YLgpUNpbxSdmC7u44UwQZM8dHGRblhA-- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic301.consmr.mail.ne1.yahoo.com with HTTP; Fri, 5 Nov 2021 13:40:27 +0000 Received: by kubenode501.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 3ffb6a621dac6a6ca8c906ea07ea8c10; Fri, 05 Nov 2021 13:40:24 +0000 (UTC) From: Po Lu References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> Date: Fri, 05 Nov 2021 21:40:20 +0800 In-Reply-To: <87cznelojs.fsf@gnus.org> (Lars Ingebrigtsen's message of "Fri, 05 Nov 2021 14:28:23 +0100") Message-ID: <87fssa90vv.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 566 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Lars Ingebrigtsen writes: > Let's see... it's these packages? > > webkit2gtk-driver/testing 2.34.1-1 amd64 > WebKitGTK WebDriver support That's not the right package. You should be looking at the version of `webkit2gtk', on Debian. > libglib2.0-dev/testing,now 2.70.0-3 amd64 [installed,automatic] > Development files for the GLib library Interesting, thanks. Unfortunately, that puts an end to my theory that this bug only happens with <2.69.3. FWIW, the only systems I've seen to exhibit this bug have webkit2gtk3 2.32 with GLib 2.68. From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Lars Ingebrigtsen Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Fri, 05 Nov 2021 13:49:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Po Lu Cc: 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163612009425301 (code B ref 51473); Fri, 05 Nov 2021 13:49:02 +0000 Received: (at 51473) by debbugs.gnu.org; 5 Nov 2021 13:48:14 +0000 Received: from localhost ([127.0.0.1]:45170 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mizZm-0006a1-K7 for submit@debbugs.gnu.org; Fri, 05 Nov 2021 09:48:14 -0400 Received: from quimby.gnus.org ([95.216.78.240]:39616) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mizZl-0006Zo-4H for 51473@debbugs.gnu.org; Fri, 05 Nov 2021 09:48:14 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnus.org; s=20200322; h=Content-Type:MIME-Version:Message-ID:In-Reply-To:Date: References:Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=O3/7y236dtYMImvdlwphfMDP8I8QWSdjY5cTfYG+xjE=; b=o9+kHups+HXczKdB56luTgqmHf wMEt9cWJctvigEl/izm0wLPo9mqdhb5ok/Sj+ZWWQZjNkzG4y9YYSvL1Ksxa2RykTM1qehevE3637 +dOeTEdaYw3r3+6BJLsynfP9hiVEruXvxho8gFKwHozXNlq/CwkpObQd5zhPfNia+2IQ=; Received: from [84.212.220.105] (helo=elva) by quimby.gnus.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mizZc-0005Dd-By; Fri, 05 Nov 2021 14:48:06 +0100 From: Lars Ingebrigtsen References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAABGdBTUEAALGPC/xhBQAAACBj SFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAALVBMVEU8QEs3OkMoKCsb Gh0fICRUWGGcn6izucX09PbO0todHSFqcYEgHiEgHR/////UU9brAAAAAWJLR0QOb70wTwAAAAd0 SU1FB+ULBQ0WC0nBHr4AAAFvSURBVDjL7dExS8NAFAfwVKxIJxU/QD2vKOKUgwoFQY4DoXRpS4t1 FA3VyU3dXDTNWtDSTdLocHTyI2gmSaduxXwX3+XuEoTL5uh/SOB+9+69S6wCMsdC//DnsGXlQLmQ B0s5sJbTg6ybAXc3zHDs5Yx7+2gboeq5JSPsjlyHmuBkMLg8owYo9j3HXU4BI6x2lVdGd961n1Vg VVFxnNF4fJoBQzQxfON0eoN7qoBiRsEge73nSrPvZj2YiNhXdVvvBw80myoR8e5dfby0dQVFWJcs 7QxR0U6bM6Zgu3vR1DOKHinsrw5t1KpoYDoIvZ4j2nprS8AsE2iH/aMnP4MoVO1BcYcmIFYjCSy5 KwrkUawRJQnBKKOb+n/ASbD6pWvsEpafx2IhVHDOp1HYAPOxHAJZ4pTveLEAgaJ6PVBTAMzieEEI 5wBqXUJ8OCeQGsgUjtR3tWYxkalx0YoHGj4JSYVP4BEomJNfqU3ApzDeD3Ut/PmjBFl0AAAAJXRF WHRkYXRlOmNyZWF0ZQAyMDIxLTExLTA1VDEzOjIyOjExKzAwOjAwxemLVAAAACV0RVh0ZGF0ZTpt b2RpZnkAMjAyMS0xMS0wNVQxMzoyMjoxMSswMDowMLS0M+gAAAAASUVORK5CYII= X-Now-Playing: Anna B Savage's _A Common Turn_: "Hotel" Date: Fri, 05 Nov 2021 14:48:03 +0100 In-Reply-To: <87fssa90vv.fsf@yahoo.com> (Po Lu's message of "Fri, 05 Nov 2021 21:40:20 +0800") Message-ID: <87r1buk92k.fsf@gnus.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Report: Spam detection software, running on the system "quimby.gnus.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see @@CONTACT_ADDRESS@@ for details. Content preview: Po Lu writes: > That's not the right package. You should be looking at the version of > `webkit2gtk', on Debian. Uhm... there's no package called exactly webkit2gtk here, but there's these, perhaps? Content analysis details: (-2.9 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Po Lu writes: > That's not the right package. You should be looking at the version of > `webkit2gtk', on Debian. Uhm... there's no package called exactly webkit2gtk here, but there's these, perhaps? libwebkit2gtk-4.0-dev/testing,now 2.34.1-1 amd64 [installed] Web content engine library for GTK - development files webkit2gtk-driver/testing 2.34.1-1 amd64 WebKitGTK WebDriver support -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 06 Nov 2021 00:01:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Lars Ingebrigtsen Cc: 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.16361568287303 (code B ref 51473); Sat, 06 Nov 2021 00:01:02 +0000 Received: (at 51473) by debbugs.gnu.org; 6 Nov 2021 00:00:28 +0000 Received: from localhost ([127.0.0.1]:47665 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mj98F-0001tj-Uj for submit@debbugs.gnu.org; Fri, 05 Nov 2021 20:00:28 -0400 Received: from sonic301-30.consmr.mail.ne1.yahoo.com ([66.163.184.199]:39236) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mj98D-0001tU-L6 for 51473@debbugs.gnu.org; Fri, 05 Nov 2021 20:00:27 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636156818; bh=Z9JjTV+BgDgUH5ajOZ4jBs1FyuqNgzA/jFOSjm83Cuc=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=FTLQtp5rOg5/o2uPRbv/k4yOM3AwORgQQ6I85euUYag07vbXAbFWZ8aKCtsZQ/uLCEUaKWe30V8EMx5qb7k5ui87/VhHWUJ9exyuBdQsBzDiL53bxsQEHsrFovsTL0e/4YfOntXnXAmihIYyNAthReLNMIH3AfqbNgRt8mypBqa9Ol9Xc7f2qyRScjOu0DXnvyyjEKSGs7/XxR5tnzq/hng5W/pHQ82nbklasqioMP1Ae3fEnPqwxLaCB1WB5aOC1V1vfL8WIEejAuaytirEMe5JnSwzdkbX5inBY5EL5RjsXNziPR5jFOVQ6q7qHvwXWKjxE7yxNfFLZUpxR7Cxzg== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636156818; bh=Y2zkBbtb6wbjVDJHb76x70owBUKMCjYTlBnWEr5uh+I=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=mPhEnnX85aBY6bsBdvzEt3KJb1rSNYLq7XwjFlqB+iIVPH2EJZcojh4cyNQGG2H7V1m2zkGvxE1NNoI021bY5olrgr5Bt8NcCLOEv+8ledpv5zpTWMMSAwKg0aRCiS/SDONLE0xXv6sZCklxWU8G0+ceKxy88CSeNtYAQy69OzdS9uGgUWL5Xrtl+ft4zZRlC0EPWZ9KH3T08m7NU3AteBWygw58Q0wGFtmOxWWnfrjikG96c9qDXSG9TfMi8ovUO/ETI34rAZ/0rrF7fOYCJvRszJriKZVSt/FxqGydOjGQgn92qfn1DiD+OEzrw0Zv0/JT6lqko/nNzY7nubCtTw== X-YMail-OSG: R2_iRN0VM1mkJrpPHFb6GX3REFU20b08s8adTtOc9Via_NkQ2XYsNEEQe.b_bgr SqVyHxJYLUFfcmhHCbdoI1XvFUTK2qtEA8dPxgR9pp4jrjCXCifFJBFLu4cXtriBIqgqihDefUZz Ie9LEAWiW1E8.BX0DEj83sWlWRUruZhZImpRZBbcwTN6jdIIE5t2dL_4zFcBej2_vEugaJxXzfg6 tznovWnYMc5F9iUeVE1lFmnh..1YerG5dYZT7qIwEyPIWLsKzOzCRWqfCWuyjn3jTjoPSsRhDcnN EEcVHh.b1HoKQ.jaNn7l6ekUUBNJv0ZrlHIVP25uHuocjyT1ppyXrspPqUQbn5ambP.lVw7JC1Cm TQg3pHAXJVnK_AGchIQV35dc3eUTVEXDwjD9jbzmDwgwLx7Vb36iWhjK9kn9OUaN7KaI1yYjFB.l jY4ogQqcIQAiUHYXRtb9DXwe_ZL5OTaYqZyWG75UmJ5P5zGWfASrtkTvMZXfDLIcSxIn5ChTOZle TsWfL1DDMp853RH8PJMrhDBv86J.TTagIuy3i5Kz5ZwDp7otXRjUR2W2hxMUVG5HEQkdm5ZpVJJp sWkqj8PZRyHXMHcqVi8HSLNCeT7qDVFKI7i4IjUvSjopnT_voEBedn7QWL.LsvN.9p5VmlzebbM8 horMal.0VkEw6.oGLUQVFx70t59kRYagiLEhNbzoSlyKpcQ8ro.cBcMZV1yI.ki_u5RtWK2bTzW. jOBFh8zYB1VCrz2fDdorVyYUA76kJJ7t6DRqFm5SDEWfC2VB2WX6C.QIV4JTta6QiZItIVd_tlMS JPRYQrdXdVhkoONjNvI_9au2y5YOpkJtulmvseKO09EZTXRsDFRftC9Bx2byg1Herze7sXcOy7Zp 9tHklkXiYtk.i0bdStaM1oXUVX3rd9MfYxyJ3Qu04gX_TpSH9yOiMLYaK4W5_x6yYxXh4DQ1jxrm LJeAm6ZNJEVuKkv8deI.sjax5ytupGf2Z57n6cxFexiU9QQ0OTGvRuDr668T5.AP678GV_FVUvcC msPuM2A4rMB4P2kLVG_BG0k0_uDjgD.2_XR1ajaqQlKqokvQ4EK3IKpMPPj4aVBLFhMUdqC4wWoP xngGbpE1qVXEL0sGgsm0nakafXuKHtFa3QbH1d_2RyOiwD1GN2GFLoXETc3YvZj0SgeP2.RD2Guw bX.Z99dQoia0iYZi1Ll5xYC.9KbnevJaDeXCIC5kGmQ3LaPYfxOoV58R9Euv.lF5yoV6IZD.Z4ZM k.KE_Ps6BTpmhB4jsNmrvI0k9G9UldBPi3rSY7cHYLBzHvMoTVXeJCvNRvJXzduqGKRYKmEmx18L yXGm4bD8Z.KwKBQnqtocRElpN.fNUuYjgHiIx4.gRJiAzNj671A99rmakKa6ExbcKx9guXPDo21l tTPrynHS2DR4KG9tFYvDxPK_7Ojer1wg18Wvkx6Lj_nDPfc5dccIeQ.a2ybgmhSB7RJL2WbblzRa hUockz_gLhHV3sHydRWEjs45058H1lsZvFThmWhFPNmbGGtt7ivYq2TXOXC8BC0Aqo10OY3CZGbl bPcMZN.kusiiQgulcO1DuQLOCNr89u.y9aXnVPVTgtsbEfjSSBocU0RnIFyGLFOut6VNnc1.wbDB PqTWUDmIDYIr0l9iv_VLAZRUzltcGnQ8wOv6cTdKbeY8KiTXtgv5evQMqdl4zXAmo3phi9Q665ai ak18a76jH7GmD95Zjwr2MpfRqOrZTvh5kuF1ounvvWIFcbiyroBtYaeUrR4wfDRqDZfHd5mH_ejH P3HmnEt.LMbZzweDxWbi5X5o2ZXxHtlOdu5exL7ne7ozdoepKk_mCUDHhyhfpjz.dlUSzXUoqzMx 6w2HToZEloQSfmzzOFcI_424L7WNfEp_sHsDa5dLQlESUSwrOgJkOaQ1QbzC8XImLw0AXhnDRKYd 13KnnmcFtwavOjCmS3m6Vqi0EewARIYLvceUpouzpZ5ypz4lMwnhQS14Jf.BgHAFDa.NP.5WVaPB QiyNHf8esfPcch1EEhAEgtmDzAOs5W2Yr2irPzy78pUh0R.IlmN6suLb0DN.Fn7AjLcKsEz4kdnY r2B2ljhcIdnNC0wEYQd3NsqE1QvVov8pfKBqu0DfO5ZQqAEMnN.LeaUzeJYZ48l4VHF6TFBh.OSo MzC597KBmNZIDcwDTkFHlo.32DVH3VFMFp2xkxwTNUAJincFaVD2JgKUS5abSRuqrWUo5c2nxq4r zWku4C0PtBr3UL3z.f4VSBQUYgCPXHGf0Lw6YSZ08P.mGbf.M8w-- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic301.consmr.mail.ne1.yahoo.com with HTTP; Sat, 6 Nov 2021 00:00:18 +0000 Received: by kubenode502.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 80d9f63852bff06f148d780f87e2fbe3; Sat, 06 Nov 2021 00:00:11 +0000 (UTC) From: Po Lu References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> Date: Sat, 06 Nov 2021 08:00:07 +0800 In-Reply-To: <87r1buk92k.fsf@gnus.org> (Lars Ingebrigtsen's message of "Fri, 05 Nov 2021 14:48:03 +0100") Message-ID: <87bl2y886w.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 414 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Lars Ingebrigtsen writes: > Uhm... there's no package called exactly webkit2gtk here, but there's > these, perhaps? > libwebkit2gtk-4.0-dev/testing,now 2.34.1-1 amd64 [installed] > Web content engine library for GTK - development files That's the version of the library for GTK 4.x, not GTK 3, but the versions should be the same. Thanks for the help, I'll probably have a workaround soon. From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 06 Nov 2021 00:23:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Lars Ingebrigtsen Cc: 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163615814317732 (code B ref 51473); Sat, 06 Nov 2021 00:23:02 +0000 Received: (at 51473) by debbugs.gnu.org; 6 Nov 2021 00:22:23 +0000 Received: from localhost ([127.0.0.1]:47704 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mj9TT-0004bw-Hr for submit@debbugs.gnu.org; Fri, 05 Nov 2021 20:22:23 -0400 Received: from sonic309-22.consmr.mail.ne1.yahoo.com ([66.163.184.148]:44448) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mj9TR-0004bi-9q for 51473@debbugs.gnu.org; Fri, 05 Nov 2021 20:22:22 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636158135; bh=KqaQ4JsJaIXFNgSI8LacotiwnL6Za5WRyxDwY/VXGUA=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=rLNZ0UmI0heU0dhrqZ30QobZmSxQHTFwMxc1qxdmG6+gjIObZKizQwUy1wn3ur4l2yfmxfM+YkVw19CUdu0MjL7EGx+cU2nvABUyoUtONAZ0I99rul8GvfDvMf2IB7XdAgIqJgaNeFZYJEg2pSa92BtRqicwrDfmOfpgblejcMIuMgEHHbSELFOmBK0pWrFyL19BP+KFRJX+1ySptw9E65wkZuW9DPv8t6A9tvxpRGyrweY7gJovQ7p8EfKlRf9noN0o4Ca5FapD43BomTEllHF+gRlnxuUfKvaeIDL/hWbIKvtswLUG6+T5/AVnSgNowvPGVfF2GhhV20pboe2ymQ== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636158135; bh=k/n1uiWMo9nYZwEGywdFylzGtVCUKecuIjKzLNWZiUF=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=jZ1MSoxUr9qhYnWztHZYG4Ys8fRrEJ+9gGz0RAvFQ8vD6u12P3c+oeYdMe8O15RJFerncxDBlnJCU1RNq/beJaGwme1MqU2NSXWIQe8SI5SSesYAhmopdiX/NM3X9tEA77DORDJrnGarO+OvJfDxd0zrxAH9mTlKUBMvihO+LRG+FVd1zeNaYXa5AQ/X7PqJ4pkX0XrPIeUS85s2u4ueK6bwV2cQhnC7FR4VH0d3Z1pzGIPvel/zW8Eugvo1FQKE1MhwTtnSp4l2I7Hw61zaozCjgwBYlfwpSiKeb6oLKCQhiNLtOi64rWuoJJHZgRD8eczAcSXbh4V46BcQA4PRTQ== X-YMail-OSG: OcE4ts0VM1mizShaSq3.6vAGlbiCL3Ec_5RvYH5W7mrQbP0K2OmKWTa7_w7c60K EfL1hdMR6BI1.Djt.LYrOcYRmaXCTYvZ8JTx_tCWqK4OTdOiyrx_m9F5RRmM.x1gFX6nDsQovpXT Fd2r8yxWf8IAK8_p8dKHX0F1ASllBhv8y5PUMRfYqc5zD1OA_kpNnBbQGtd7BXtvnlyPQge0ubaK fyti9cP9jVVh_mQ67sPewKUckdT3hiB8FXrdUC776QfZ3pH.lfkSLbHYvoHK4MvwawPEL2EBi9be 8_kaNof_X0VB_fpg5CX5keLl0oRI9u3XdX2C3Olu7.q2wzpbb2x7bVAX6GlBNHJzhycXdk.GToNO QgfYINNauT773F5whSFxX27QSGnWbKP48J9mD0C8yLzUuYpQ.RD4yQ2mMw1VkYp57MWRbkN6SiHw Ii_S1QObth7WR3H1GK3BMe7rYmDja0tsvkaLW9jrr6ew6K60Jjw6FLgLWxctadaZ7w2oZOa.ixgG b5r3DvNMUJWot8IeFmMXaPVxI.Ajq7miFd_4ArrRDSs.Zwhi8qFBV8Rgjmobu.dS6SiZnp0HI.Rc o0RsHcfgk_gab8j5B7Fq93WZjhu.usb2ewPRt9GxVwaG9AriokZl7q.kJNz1.Uui53OcEd1X5ZRe AFe3kTGTdq97TCTM_RyEhrict6dXY1Ru8bO5gEucpCBqrCy9qV2A_nZAzkIj7.qhCv6weaD3sCDk J5deAcgo1LwwW5pojKzM20T6CnapqoBsY.ohObqFBu7ESuYH1SCv6Q1ctaR22Dv6keJfluLihSyI AYfUVRwkUuXE3MytwN_DMNCoFMgIekhguBKcFYzxIOQPrzM.1uiJ.1HMzDSRvrv_gZqAIhZ.whT9 ZjHIbI27ahwwOoK_AZHXQgvfnAfintRg5EB6g.ZttOgu7aaoS_qjXsaTlAttYlA5ihFsXrsYHMUh NzxBSuN8QaMO4RJ58VYlNofZ3N18jJpNqKWTj6tWweQHD6XAg_XuARpVx1Wom7yRXpJo_NCBIP.F p0VWicbdw6qjcsHjD4XU9CeXe3c9fckT0oBF88NzNZzOx.8A7PjFB15GegyUke3NuKsJjrSfuZ2J 6Pz.GCZ_A9ZdYfkOY1Ne7C49N73.CzY_NWkg10c7wNN3PDyRTAiCX_VgtNZOBRWJIHzRM8GJ8kk3 X_nf4ghAH9Tb0l0oZvWJHXQstkfcsezLUoISNnDD7fNZ64kACXEWt0Qv85KkDL2PZl.4kViGct7M MP0BY7xMAK6zvGkijNsL.oDeqyXS0zT.4Zh4d5AZO4Eua70nJGNY3r.vxQFop9GupOXUNzaJgOMc GltTh7Imp9eJbPjFoiRjinAyiXP8BrUd2Dep2vxwkqzVFgTSYmnOFQTTsiR07pOTszi4aSghYTyb mMhM6T0bAog7nBd7MX.OPwcLm1GPskaQQizM9Dgq4M.9dQ23Bz_G6hXqESlZv2jlx82mwkAs79.Z K7rjS6AKZMOjdV0ybICLVXAmcqOYbE3JFDOr3mI1N5sKLRRsImjppdmGDsnC_PLDXQe6JR_202BI cSCL3Y5YYkH1ISD28ZE27.yFCHhj48tN7Vl0ZeqxYTpl4ai.CouCC9JyPLYpORAUxUxOAga9H1pN NNYH5.mYP1betimMZwyJQCBodX.DnrUQmBQsz9kH.sZ0yzXxb.tvUU4c9y.FzV6wngdTyIKjfhKl hQIRcuAFchM2CpFqyDrmYpUf.OsxeNt9L4xa7ZVecGIV7JrVudJQjCjRaNSk008AiwhhPrFg5Aoh wbyDpm9pQekfZpyOtYBEMJ_yLWuEhl.C4CzNnpuxwYLwIYzk_kkxyaRctaNlyb020zsv42Q.eby6 RgU4TGuYWoVwFMWHTqTrwcpbPpl6Z7K7U05UDEDctUdyY44gBcNBHX8SbO3vgTAIWGzmsKJVGBNG GqMeCeu0a9g7cRtjhWYsmRO0ykw3k5LA1gjuLN96LSw3wgDm1zNzJIkKjnWv2NaNPCWC4v6Z9KMh zeIGys8FHsT6aZgoSCEGtBr2zHN.AgJGYWjrdFkSHNv7xUlwGYUkZaQJg.3Gm6Md4uIxzmYMwrc_ y3EZxTkotTnUzJXMMwK2XRJV1yFukgkFLVzX37MW6h8lFNN925hz1pQbF9rlQ9dv_S1zUbYvzJAX 8we_HXkiRkvvbdL4i._NKec_nPxT9raLYAxw2yFjcWhuCASiW_2QSib9LlFDLRhxjm3XsOclUZJU c3DXe9jMzXSOWKpih22RQnNpasZ9M2EUxUAtMzbSWTnDxaqdsUXU- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic309.consmr.mail.ne1.yahoo.com with HTTP; Sat, 6 Nov 2021 00:22:15 +0000 Received: by kubenode514.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 1fca16a3bd8eef9c46d0c192d919e217; Sat, 06 Nov 2021 00:22:08 +0000 (UTC) From: Po Lu References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> Date: Sat, 06 Nov 2021 08:22:05 +0800 In-Reply-To: <87r1buk92k.fsf@gnus.org> (Lars Ingebrigtsen's message of "Fri, 05 Nov 2021 14:48:03 +0100") Message-ID: <8735oa876a.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 301 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Lars Ingebrigtsen writes: > webkit2gtk-driver/testing 2.34.1-1 amd64 > WebKitGTK WebDriver support A temporary workaround is to disable sandboxing of the WebKit sub-processes. Would this be acceptable? Also, would it be OK to adopt such a change in the release branch? Thanks. From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Lars Ingebrigtsen Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 06 Nov 2021 00:26:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Po Lu Cc: 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163615833818108 (code B ref 51473); Sat, 06 Nov 2021 00:26:01 +0000 Received: (at 51473) by debbugs.gnu.org; 6 Nov 2021 00:25:38 +0000 Received: from localhost ([127.0.0.1]:47721 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mj9Wc-0004i0-Gc for submit@debbugs.gnu.org; Fri, 05 Nov 2021 20:25:38 -0400 Received: from quimby.gnus.org ([95.216.78.240]:45298) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mj9Wa-0004hl-PN for 51473@debbugs.gnu.org; Fri, 05 Nov 2021 20:25:37 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnus.org; s=20200322; h=Content-Type:MIME-Version:Message-ID:In-Reply-To:Date: References:Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=wQvQAz7NgQ9VSu9x/yu/8vSImdJTWbMIuNi4VPG1yBA=; b=Ev9LwxXreCxMLirPkF5dOG9GF1 /527mz0iC9Vm0VfCsPX1aCqYF23qCFxpLomkW7dHSXsdPLzVC4kzVsL0TgIYLodG1+FABjuFhdr49 RYjjE2AyPhCv4G+uXdorlKcCUi0E6mxa8g5YPkpwMtQevYNnTCtzoCF/nYy63h13rOJU=; Received: from [84.212.220.105] (helo=elva) by quimby.gnus.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mj9WS-0001AA-Ca; Sat, 06 Nov 2021 01:25:31 +0100 From: Lars Ingebrigtsen References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAABGdBTUEAALGPC/xhBQAAACBj SFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAElBMVEUaFxQvLChDPztc WVOUkYr///9D/Lt8AAAAAWJLR0QF+G/pxwAAAAd0SU1FB+ULBgAQNl2eyZQAAAGHSURBVDjLZZKL kYMwDERl0oBkGgC5gWDRQa7/mk4/m0A8mQzys3ZXBgDEQnVnETn/fH1OfRYgKkTc7Dn2/yQB0HrY ecmeTzw66C2KJrbv1RuQqKqSFZ3l/PQ4sxgI1A3kau8TKIAuk0oDqRKAqv7C3PffqwIdI9jQ6b0X FkC4QHrwsTDfgGQ43KuBJFWYEZTwtjJ/AV07wKIA9chuwAh6aIBXb8fSLymLZv1Q8bU1BQS29J8M yKHFsnTeiYaUg90KaLZPGddvjL0dOluRV+LjV2+A9RtEqt3BS9jnKC5jgnVLoLPMAe2LaC5ViuSA lJPrKU9PYnntDWbeekAzYDdicSOK3RSWw0FjGgMaUeuVzB4rJTAh/UeIuHOFt3USOyp4g1a1I/3S A8a5tk0J90g1PYs34BmfpnOnhH0ZJgOkyE9HoRlgRMwbvYPpGgYB8DZgACx4z3fZBsACj1VCB+nZ k4BuchgeDmiiy7xQDgjz6/1+OxOEsHXQA5QhRT8d+ADj64G89AH+AYM9S8q3C9arAAAAJXRFWHRk YXRlOmNyZWF0ZQAyMDIxLTExLTA2VDAwOjE2OjU0KzAwOjAwip9VOAAAACV0RVh0ZGF0ZTptb2Rp ZnkAMjAyMS0xMS0wNlQwMDoxNjo1NCswMDowMPvC7YQAAAAASUVORK5CYII= X-Now-Playing: Fire!'s _Defeat_: "Defeat (only further apart)" Date: Sat, 06 Nov 2021 01:25:27 +0100 In-Reply-To: <8735oa876a.fsf@yahoo.com> (Po Lu's message of "Sat, 06 Nov 2021 08:22:05 +0800") Message-ID: <87wnlmdtag.fsf@gnus.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Report: Spam detection software, running on the system "quimby.gnus.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see @@CONTACT_ADDRESS@@ for details. Content preview: Po Lu writes: > A temporary workaround is to disable sandboxing of the WebKit > sub-processes. Would this be acceptable? Hm... I'd rather not, if possible. But if that's the only non-invasive fix possible... Content analysis details: (-2.9 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Po Lu writes: > A temporary workaround is to disable sandboxing of the WebKit > sub-processes. Would this be acceptable? Hm... I'd rather not, if possible. But if that's the only non-invasive fix possible... > Also, would it be OK to adopt such a change in the release branch? If Emacs 28 is segfaulting (and I assume it is, but I've only tried Emacs 29) on a lot of newer systems, then I guess we should. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 06 Nov 2021 02:07:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Lars Ingebrigtsen Cc: 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163616438929191 (code B ref 51473); Sat, 06 Nov 2021 02:07:02 +0000 Received: (at 51473) by debbugs.gnu.org; 6 Nov 2021 02:06:29 +0000 Received: from localhost ([127.0.0.1]:47881 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjB6C-0007al-Nc for submit@debbugs.gnu.org; Fri, 05 Nov 2021 22:06:28 -0400 Received: from sonic311-25.consmr.mail.ne1.yahoo.com ([66.163.188.206]:38027) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjB6A-0007aU-D5 for 51473@debbugs.gnu.org; Fri, 05 Nov 2021 22:06:27 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636164379; bh=FQ59wW2CaQi+n56k1pXglHOXC2I1CKxzZbvuqq8x2fA=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=cJfnd2HwKTMyziEoOYeQfzCc5BlKDGZY7c6YrTtQsvVaqc9k4Iqv9T0iZKm4JaPbSWitUXbUXWOy6LNcoDeMBY7ICCFSy+uDBgc9T1MuDR+/RBrGkaTkt2Sd8KieCsFt2CSp8wxWoJvpslcWmyEeMCI38dbJxbMYeoLuQ27wwktmBRjDh5JmSKitXE9xmiJ7p5XmPXKea7CXhpi4YewHwKvk7NWzOx1f3Bg07QQlN8nAVKrWXGLwAl2szEVBTspGOPzfdcPN66uLBl7nSJQXGAOzloeaJjjMpKtQVDUtjrKX7ryh6ONNg58/463YXSyRmCGVUgjNdZBGcPanG7H4yg== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636164379; bh=zoAC+1Wc0btg6gb2FFZHQuktI8qGbgJ3teanmV/2oNC=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=ZbonDDFtRvaJhJXOBnfit7Q/KKvhcuxwPBXL04ttn6rjg3q3bMnhLwILWHt9VK185pjdQaFSgUZlsFl/7YrH2kWQKlH7j6LU02OAfhr0I4gfwsr9ARnQjTXfiWoYUKGS8M50i4F0NNv8HyMUovoEdWeNd4b0FXJyGXt+WoQYMyUDCpvl5n+9ghvNfmuxrCSwRIFQJ8IecvR/M0Wodvjt7F0LEuX1s1QBwgKRI36cgr8bP6sYIXQXITNZw/4sDd4e6XGOz+Y65gcN2VWnFnPerkM8nvgweCXAbzPyT1FJaD8aPQAHJXvuPmZXFAmpx8p49U1Z50lL4SlwaeaxB34WSw== X-YMail-OSG: hAcdzHoVM1lT9tQte9un3A9Cefn.zrNEvyTO9Gm3.Sv2jYW3jMqB7NZFBZDLAev 88TaV2ZX8lDHMeNeNNJ8aSeNUKQwKww5WkalfOBmXd7wDiJo35jI4QdNnwwQoVNN1.mpLlJE35Ct YybkFmJzxnNT5gvmw7ijcbArMngJoG88xTRfru12.rQUTv_Y2gVz4j8dRqRHJebEcAktG3atMccE U6dhwFSMf7ctwBjjCHsqGzZvrZXhGF8TMVlt7Fy9Ln2qVvwRoaDzo3JWSQbFW2iQbbB9DFg2SxXe 1C3JQ2QyO86fBq2bRdBBS0WdfQ8UeR.tvIU0hUYxUBMvUoLtU3XbSaBZPHSd981ERyBIROdL__nR shpQc6KmmdtDv5gtaxWJ0j4P0_MA.2FKk8AaICd2dyH9SQXN1sMMaw_luVCVhdCEVLZ7j9BmeWvC 9sbLpNsNewdALx.cp4SGmZPrEgmrW0yTBB2Y89ESeJ__GN4d_Ml60h3qeifYoihxCRURGyAhwynR Q4MonhVbyBcnxX.PhcsFeYCdOnS5T6D56pVfVEoqGLlxXSN0oZbt78sqaA1oiaMHhrKnW95QXT09 7DeoHJkBRu_vucqOYFFQZ.IlQ.dq0gLs1oM1yC4GRRsrF_nIYr6.4BIwo5fD7aykzIfPU2TnCcJd KzOoMSMLznvHduFsuGgVhL8LQLFZ1k5cUUzve03sZoqvDioEy83wOOv6D8A8KwdjcMJ6YvMXf5tc uhfN3j1ZfyLm8qBND.UdFZ7n7bA4EbcArTyx84knGC.4_ZeA8qjMmrozwe0tkg2xc13is0nkqA7H qxiVWxMAEfp0jAJH09G2siU2rSZbBXsTLCWY1PkgfBKprhHp2ti38m_GfaBz.ckDE9LVhKLDcITc HBB4ub9jhCJNJ1rCdPoHWctpV9XQeGehloGx5oJDC8nqUG9INRAuVJsomp9BmSf32MgWFzAA9Rz1 IywcGMGdvnCrf6edrbsDrYDsMoMQByU_wZDMZ8vFIMfmwdtb96bHorots9JSWaGRLEXTXQwiMKHJ xM7iCeQyscGEXlamH.ojFXPqQnu5WYsXHDcnZzRRwI2.BqOJcUtsAMDWCBoeTkMQvJtuVIynUNaY 1bCkDsZn_CZFY6QYiEebVzHckNiLDFDwrj8SCTep4AhVXocMhOVgzxIn.8DWS2SZappwzyZl5wuj NyVuo6F.bstUpVxGz1HS1H0R3DPMLvbBUAGN6xZRbHcvVCir7K0QWyu6Xqoqn3kF7tidTuKWKuNf y9_4O5yjRRVjaStvTrACoyXSTVMJe3YMPzDZj18ZxqFfB_rGYcStMShNK6_RZxQ6e0a_wzNLWcJ. UJOpUlDoG0KW32C1f6l_OgYNvRfrqTLD8ouEVdPm36S0X.1L3hf3_90_V1PNSDSukfmwZchgsyqy wdnKi7BWX7eADc7pcm98HYR0Fs9aBiBOF1sGOXVMXMzsy7fD2d1wbUoOOMJFkFbG6oeGuJnSAbe1 Y.bHakoTNQ1VFhu7uBrDqzehntGJXf57tCypJHp8HkSlwGtXikL6gZdynB_jH0JqlWuDx7ywxvDa 6EM3Z_4BuB7lB72RwaA3svhIg2bXLY3ml1pB5D3VZQ8tCT0ptSHcl1AMvrKYEyYHO5OMfy8KCp2t NEUFZVtAKXkl3JiS_HEqGXpI0Xx7VFTMxD7adOP9GBjbK7VUzogGRnx8v5lVnLrcoWlWWOiYHFxx HkFAEIIgiqfJh5J7Rv9kkZ32Jmmd.YA_SfkZ53SWDtafYW6oorthGE7ZFMxc3vTqvO45WB5LWErk 8psbLfBsACR_P1v6hFcyAYC02zJGxTnayaWMp1E1j6hb62c0b9ER1BMjW6bk3QRnciHA2Tt6WZ2l AU8Co.ZQuFZ0mkvrxMe_kyvOLsUmScq0950TITchs.UEmj1QnmWkMXkYteFXXMVPLx.FonSvaVNP nsQyPD1bovksLZDc7TxnYWKUY26h0uTKqGiG6ICPwJoskGibAfOQjpCQNWsX66L8_NKeQ4pQQmhJ DEUlMNos56FFzBBouNRZKRWlU0ryd2_gAdrqCzr7YshhtBfUIOqDdTnszmHQULb_REXD.WG9Ge.x yoY5KKTGRl6e1Hs9fvnTdFeIUBdJq5Y_p4AoDuh1jEWd_yLyj2QcW_vXvRb63Ry9vedSszy8zY67 42P_j.5FD_LU.U1PaNaZElfA1ds.uxi1nWSRJ1e2rx_vJ7SxzImXBYBq7MQDJaU4iMX8033tAMTe iGzr8IWByneU7m84JQYwe1jNJ1HPoMnuYQnGsbIhE3JliZpKTf.zHP3A- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic311.consmr.mail.ne1.yahoo.com with HTTP; Sat, 6 Nov 2021 02:06:19 +0000 Received: by kubenode510.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID f0132406cdf2bbf2d44012596c733c35; Sat, 06 Nov 2021 02:06:12 +0000 (UTC) From: Po Lu References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> Date: Sat, 06 Nov 2021 10:06:06 +0800 In-Reply-To: <87wnlmdtag.fsf@gnus.org> (Lars Ingebrigtsen's message of "Sat, 06 Nov 2021 01:25:27 +0100") Message-ID: <87r1bu6nsh.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 788 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Lars Ingebrigtsen writes: > Po Lu writes: > >> A temporary workaround is to disable sandboxing of the WebKit >> sub-processes. Would this be acceptable? > > Hm... I'd rather not, if possible. But if that's the only non-invasive > fix possible... I will try to find some other non-invasive fix. >> Also, would it be OK to adopt such a change in the release branch? > If Emacs 28 is segfaulting (and I assume it is, but I've only tried > Emacs 29) on a lot of newer systems, then I guess we should. It's not a segfault, but rather some race condition occurring in WebKitGTK+, which causes it to invoke one of the GLib logging functions incorrectly, which then raises SIGTRAP. This crash also happens in Emacs 27, and also GNOME's Yelp viewer. From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 06 Nov 2021 05:40:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Lars Ingebrigtsen Cc: 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163617719510629 (code B ref 51473); Sat, 06 Nov 2021 05:40:01 +0000 Received: (at 51473) by debbugs.gnu.org; 6 Nov 2021 05:39:55 +0000 Received: from localhost ([127.0.0.1]:48082 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjEQk-0002lM-Sl for submit@debbugs.gnu.org; Sat, 06 Nov 2021 01:39:55 -0400 Received: from sonic308-10.consmr.mail.ne1.yahoo.com ([66.163.187.33]:44396) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjEQi-0002l5-DA for 51473@debbugs.gnu.org; Sat, 06 Nov 2021 01:39:53 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636177184; bh=Lsjg9SBJL9RJPbtvqtN1rIcCiciNKeykMyUUBnnt9mw=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=juklXPTSdgh9oc8cYRvAPOQTuyV+cdOoOMKS5gBfhXsn+nUFuneXWPrAIy9Gl0xrHAwffJi66bITGy1aXE9trW/UxkArNnwfTl07SUQQ5bWZNfNF8W3gq8r3etFXsiB7BQD5d0er5ubXKYE6b032xa/iBcvs9z+DrLzKk2ZZMVRf303rbNgZfv0CJP1muML4CO9N3Jj0vN4PKatCsteUUoXv8zWuYK2sMiP+aKg5/oPxApR8okjMCIGwMxZhIWz5S8/aye5j9GToYjzQs7p9F7cj7VSdymh7tCsQKulkLxwcJLOcDMXLewfgJNFO4MmvAWffHOKMjSacQdcRzgNgPg== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636177184; bh=FYkB0VC/E3WbRi33/uAU0PKDU681OH8WYi3npqnVNkG=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=SXfb4OSXxgXZMz8gaGd2NkxLvatbrdTUD8rwpVAShGjzKyW3HGKDw1x482fVbOQvo/6TpE7KlI07NFTJNTOissBMxGnuFfKkVrxtfSiggUw+p5iUBgyOWLkBphH1t/E5d/cFLVBXgM4AMh/ejj9+aKu8QrVwOAAHK8MLkutUA05UCTbBMQUB6Byq8iY3r4bfEythgLVeuDLHs0oRMB45uhrEyvmzsR0wEZi9nvE2CQBsvkfiOlXX9KU8ni7/A8uKdF0Fqw2FucDPOelRAM5kdAQqnjY1i3yuCRDMYzxAEHR+ngfyr+e0uQBKXXO/Bj00Sq87sLrwIkVC/RGwciTn5A== X-YMail-OSG: KrTGegcVM1k.urO64DI42oFTXIMKcdfIJkYuhoq8L_ncG2S1eJxkWESqUko8V9n r7mhd9LjTcciN7nqUWhr4Wkd21kBnuCyYiJr5YBr6OTfbiZCBLiTzZu4M_NoRk5OIxR5roMS7EBP O1tZh.azTFjDAOM_GMZu1LfqjILrENwCOz6PWJd0dhWuACoWJfMMHgWmKwchxztPSirRFqo59QTf 8AGqyjUmuC20mybuP1ocChtfWILXL9bW7NCk7d8MBUruNWmxpXXBwbuBjHa4E7HdQ8PKdBRNMkfU IKPDxVzjpJ1oZRiD5TSBt7Nu6D.YW6ygRNBDuw75aotR057UA.hJvPMNL29x.DERjMrNwwe0H3p3 wvHGEon_a2Y0wSMxcQU41HbGuzDNPdDJ7c02lAainE764mYrC9t_y1jimSsXssuU2D.zZrBpHXzO .qn4SjXbELWJUf10_6L2JdvnAT8ImXuwQXqeFw.jejRnPXpqR8NScJGlf3avViSyk3bQy2RoGEkk 3nCgXH_5jplLk3w7GnjifDiqS0rdmvqao.nGuXev.WCnakYVnFMjxpD88jZX3HL.5ni95rd39YIf UvpeFAPIisLEBWHgcR_CpHaXOd8zSeigLt3uiKNg4OobAyoh9FVZxUvfs7axR0VEZpvk_akKSkaK MExx0oHj7LasEnjkFqpORCJaeGhpz9XrpRIRav1p4RiBIQqEuBjC_9Vzvc8.gChHTNBMLAuFNLRR Kay98B.8LVWeKd55qj79y3ebPI2MmxB83T9i6ZylSshMzQjvDeI29AD82sWyoV4XUePFyIdXis4C NmEOsX_x4ijygUEHJu4_7mUnOT79BiF.3CEsO_ZyxZHPfsO.J195sd1NdpC311UReU53LWFfJU6_ klWRthvHNMooeaafczntUokmxuz6gQ_g5_Tnli2O4dVu60OSlhr7ORD.yfw1d9IQt.kLJ1QaoJUd 2OHr7uPK9U85DvnJBYYsta8BZryX8tPpI1XP7x.D3y9tRS5LfWxVJWCXasHQqZQCyMROobaEwXlC gRwuaz6fhUYViZL_jwGePjWA7SO3laSn.IXyVOdP.G8.gcqsCFEw8wAaRF6kFitUgubzNglVAXkC nlXZIpZdsrjiR03U3gAf.ewXnoojxCvLQn3CFkB7n62dBiTr83CKbytBujeSwTGtXnqTruisdT4J xnYSZhhc3ZsDoB.rGRhVHS9i9eJnPW5bxm7WyXu7zwPy.BdPwwLoE6phInQNXvS512fqmvY2Qrkc BWesi6_V29EVK0kVvCZSd5yheNgYZQHXHeaxUCRgpyBb5CREObMs5oSsx4Ve5Wlgmfs7r8OAxfsL kkVGuzbDSRhRAMsrGK9FLVvhZgXF0A2104kKbBHakHIDbrHk.xiimUGxN25yxL50UAgYotWL5m7Z Ud8xSo7aG6BLOT7DuZDKhy1JEngy7n5.qAeKPdvhRh7yxOBle6N8Z9xX.RQg8UfmzJRAUvQENKQ7 wNyA3nd3Bg8x5wiyTMrziyq0VO5PqPfDW5SqG7kea.MuCai9dAEuimAPMKAtEW0o3hpV3JXaS9Bf _5vnXmtoxVR9DP0XvkUKs1rZ1O5E3qknu2knWZ.IgQf23eHUp4UmhrCdTnpnO.ecC8ww9Y91Ukt0 9tEW.muizqwZ4Wtb.9ma7IBrgryiMY7aOR_PvtYnM3KvCraLuZTMwx.GRjbNcl8.3jR0WmztZsO1 Fmh8Ga.y8dJjiFWqkkyJVaj0pDjL_e2dP8Ko7QE3Wn1aDRhjdJip5y3j57n4_fymuoCfHXs6CI7g H9xfDjHZhvKsbLqRu1DrGZvOwqXtk6zpK8JVPqZEmszVQvLQZ0rGYtzXj51tHuNDc0fhspBMNeVV VfWWFJGLaZ7h4Qded64zFQx9MXJdELDFdK.owHShGI1iHCu_pZ3ydgGRJWBAwb5baM.F86bRL6L7 wjsxlXPKyxt8c8HyY3HZupBPrVFULCRLQoZlsTPQNdd4q2vT0b5Vji6AlQhJiPGw46YI5T.Jnzbd HWI7yh85WlS0Ooa9HzkwHrUlrNb67FkfEK6galO6zuHbcXGmlo4_7NcBll5jyPvimuphLn8cm_Ch TsnGK.u75Ei1rqBVfnYrAy_8vsTFfTyQqBeMDNJdbPlHzrtf0VaXj.mKHqDYCoVCJjLREbz1DbE4 R_Twk_UhspUP3VWkGb3SgwshuKkECZL1l3xr1SYn6KtxBdlqHQrqCL7MvKWubnzuOiYphnccqGci gAx4DLuClZ6MPgIo4G3SSujotyeHtFBQztb5.uQSID_WstGqi_oqEEe64Zq8- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic308.consmr.mail.ne1.yahoo.com with HTTP; Sat, 6 Nov 2021 05:39:44 +0000 Received: by kubenode510.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 5a188c5ec3b2574acfa2ab9343902a63; Sat, 06 Nov 2021 05:39:38 +0000 (UTC) From: Po Lu References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> Date: Sat, 06 Nov 2021 13:39:34 +0800 In-Reply-To: <87wnlmdtag.fsf@gnus.org> (Lars Ingebrigtsen's message of "Sat, 06 Nov 2021 01:25:27 +0100") Message-ID: <87v9156dwp.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 1083 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Lars Ingebrigtsen writes: > Hm... I'd rather not, if possible. But if that's the only non-invasive > fix possible... Another solution is to set the environment variables `SNAP', `SNAP_NAME' and `SNAP_REVISION', so WebKitGTK thinks it is running in snap and doesn't go down the faulty Bubblewrap code path. It works, but it could potentially affect other programs running inside Emacs as well, and that variable can't be temporarily set because it's impossible to determine when WebKitGTK will actually launch a subprocess. So I think it should be documented in etc/PROBLEMS instead. Something along the lines of: ** Emacs crashes with SIGTRAP when trying to start an WebKit xwidget. The version of WebKitGTK installed on your system is buggy, and errors out trying to start a subprocess through bubblewrap. You can prevent the buggy code from being executed by setting the environment variables `SNAP', `SNAP_NAME' and `SNAP_REVISION', which tricks WebKit into thinking Emacs is running in snap and makes it use GLib to launch subprocesses instead. WDYT? From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Eli Zaretskii Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 06 Nov 2021 08:59:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Po Lu Cc: larsi@gnus.org, 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163618913114167 (code B ref 51473); Sat, 06 Nov 2021 08:59:02 +0000 Received: (at 51473) by debbugs.gnu.org; 6 Nov 2021 08:58:51 +0000 Received: from localhost ([127.0.0.1]:48373 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjHXG-0003gR-QE for submit@debbugs.gnu.org; Sat, 06 Nov 2021 04:58:50 -0400 Received: from eggs.gnu.org ([209.51.188.92]:39556) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjHXD-0003gA-IU for 51473@debbugs.gnu.org; Sat, 06 Nov 2021 04:58:50 -0400 Received: from fencepost.gnu.org ([2001:470:142:3::e]:38546) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mjHX8-0007Gz-3u; Sat, 06 Nov 2021 04:58:42 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date: mime-version; bh=xSO2j7zhiSSocAACQ3hlHTJXLdBetziWMp5X3W2gSl8=; b=PkrZQ1S1C/cP uCLcuuxYM8Vg9Tiz1N88EXXe81bqEv7HC0u80LvBrhQMjOBPICXxGV8B1+eFhq/cSTqSyvcYWe1eB 3+WDoV7qAguhZWVhNW/mnZ5pN/vQoLzuJyzdR68w61Ov2WH9l18KlZ7zhZPH7GQ4U3284U90ggQIG +PSl9MAEV8HmEZtJ5yrM3T+QTnRzcHpYcrpjJrO0qbWJLKvn8ok0zgNj8tPBU+26qAF3dz6Wwn5zo RLC/T1FAWirdrJvkwE0O9mwtxGD8OUs5aAI9mv1tH5h05hEdaxeB1El2MIuzz0S5KWe7RGXymAzHy S/sc7JWWyK1ag+suqmVqpg==; Received: from [87.69.77.57] (port=1910 helo=home-c4e4a596f7) by fencepost.gnu.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mjHX7-0006JB-M0; Sat, 06 Nov 2021 04:58:41 -0400 Date: Sat, 06 Nov 2021 10:58:25 +0200 Message-Id: <83pmrdbqz2.fsf@gnu.org> From: Eli Zaretskii In-Reply-To: <87v9156dwp.fsf@yahoo.com> (bug-gnu-emacs@gnu.org) References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > Cc: 51473@debbugs.gnu.org > Date: Sat, 06 Nov 2021 13:39:34 +0800 > From: Po Lu via "Bug reports for GNU Emacs, > the Swiss army knife of text editors" > > So I think it should be documented in etc/PROBLEMS instead. Something > along the lines of: > > ** Emacs crashes with SIGTRAP when trying to start an WebKit xwidget. > > The version of WebKitGTK installed on your system is buggy, and errors > out trying to start a subprocess through bubblewrap. You can prevent > the buggy code from being executed by setting the environment variables > `SNAP', `SNAP_NAME' and `SNAP_REVISION', which tricks WebKit into > thinking Emacs is running in snap and makes it use GLib to launch > subprocesses instead. > > WDYT? Thanks, I added an entry in PROBLEMS along those lines. From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 06 Nov 2021 10:42:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Eli Zaretskii Cc: larsi@gnus.org, 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163619530425222 (code B ref 51473); Sat, 06 Nov 2021 10:42:02 +0000 Received: (at 51473) by debbugs.gnu.org; 6 Nov 2021 10:41:44 +0000 Received: from localhost ([127.0.0.1]:48552 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjJ8q-0006Yk-LG for submit@debbugs.gnu.org; Sat, 06 Nov 2021 06:41:44 -0400 Received: from sonic310-23.consmr.mail.ne1.yahoo.com ([66.163.186.204]:45087) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjJ8o-0006YS-Pb for 51473@debbugs.gnu.org; Sat, 06 Nov 2021 06:41:43 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636195297; bh=UpTOVKNxVYxJQaYAVXUYEV/Fj1zra64bLmX+veTc1GE=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=ajcMmoSMdsbEZAATvC58zX0oOPaKIwhTnrTB7BK5tLXVN0RlACNHgGUsd608GuS8jDgypsPJuZnTjRv1oP4IDumFGfUC3l0HTFE87uEthYcVPC05Q5+Q+4V5SFY9oxHoWp4Q15w0WoGkCKKlKcx7QxYG2jjfx4q4PtZ04m9O9JfSs2jWhITs3v7msgnxBvoNHsn+Fu8TPO5PRzbEkqyowJLuHKZg8hbwwACUPCqt9vD2dHl1iHlwTBEDPSHuJSPo6bcfFjmICERHOVctZNtGtrOCiHF7BrmPVQO25P6T7uhdpkzDN50QJ44Z3zntBAYC6BUd6cPm9p7bX0XqUpUDqw== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636195297; bh=/zxwFIkakPS2JP/tB4C5j6LegKt1jDOrnpfzcYvr/Pl=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=lWH8ZA1m6v+up87KWUBQe/ZBkpLOq5uH/JLWgi+00/gxUS90K9q4gqaMDehozO0j/LT7NDaDl+YnPZdQW8E1nhqhYg30KY3WATMz1+pebZFGFc17hgebvqcXtXNffRFpeyslJzFRcbKVN3Z2flvJxt2MKp8pTqLgXIkR9YAY6NqbvXuGmph/UXb5AblDzF5LQ0ccc8a8jcAzQuCBCPHP/x98m9rc08J7+ah3wF3PG7iSpFAhzi/B4xBHC3O3CLxx8d32SCsa/mwZl661IJCRYcBq4PnP2FaHXJVq3DHiSDufbwukPX97/ZhFp8G0NNvCecowxB8bi4jxLMuzQmWCcg== X-YMail-OSG: .ab9chEVM1nYiYp1IqmuTIyQusglg1uBL3mo0a4BKO0EDZ_ey6N6ulQ2pq_30iQ LWTlfwpHv2IUx3N7rluBzy4.2BWIwsqXU4OYrwWcrFCJ0Z2eCoezSF1OxI_OvmvyHSNuR0gROm5A P82SwJSKxcwAqhwPt0PrwEFJoiNx8S40YUP.8dr7ul8NoX72PZYts8NgMsObain9PPnsBEEjRYK9 TNBtxCd56FQgM8ptbIMC_d5enxUhDcfq9CbjfGTvpKDRvA3quV3jeD0RJ5m_Uj3ii8JTfX.bNvKk HkFx5OdRsjPesSRutdED_olSkoTeSxrR9jmXxwrHCDj3tWZeDt7Mo9RmtVdCHdZ9kMXVv3cAFRXn JAL_7sLncglpZEA2JEsRgYKEsByknqQprJAmSe_3gzNbwbc.FoTq3N9UMd1qb_jaQd1Lm9ztmngo 28IyyO0Q2oDOeZzYNT8dRqaKf9kEugiiKQEEy5uKS.LDolS_Ma8BhFdlopOVTTWlGYpfnjSrGkCo SfafMHhRuW2yr_IbitrFQ.SUPXFgoo9C81T5b3KLzzixoY.98azBqkdDgY2k6GSHnOpooLE45ZlZ qQyJlGh9qA4ZwyjXkEuEUrYFTcYPp0Fwbn_3Eew5JZ.OufJsR7rELCgUwobf28yMYXR1T1HI10BP aO5wrO_1Bd3r1pPBtu1hmFAMhxJlHDaP9LC6SwMd1JIcc.yx3AKCHFBWYTQOvkpA60eHTRVtjDka ADu5qF6zQ_GAtj_pt2yJ6f6jDXtjsh2nqUr4VSxRz9etAvdVk_bmsh.J4UJNGCx8kGgbmhcIqaTo IFoQ7sqRlThoW3p37Ks4Q3RuV4ReU1O_vpyhBLyvRMSD0AzAasuIXt4Uvp0ACcKTum2e1Jm75GDM tIqZEpGn75maMmhIKbM.IwcxZEgFZfsWwuBhGjQtbXBHCHXHVq32W7.496vZiBK9BWdZVKIH2iH6 i1qYP5xdFxqK3xHJMb1g81BTSUhRO.lP5oZFgRroOkt1o4KLLvB.JXrENOh2p_YyuByK1Uv7Fq3K uqVCtFOZKI3OyuM9cJWRfCqakOsPQxSuZ_hPHxFfEfu91FzsrVLh.5h196p5gobh2kvHRJskdqET RiKab1E3GWfWptUTtaMBYfMW58JlfrjCOuuzyn3z60Cblq53A22v67Gr9KdcNDYpis6ls9SHhhay WxsiasYsrwoWIJ35YTTVoeQXE35m2mAi2MgMp4sqQeD_TM.6fqkTg2JW0F_cwPk3O4D.i_LZSywj 8dlQZouZBrr9GnwN45Z_aL0FYEvH4c__e4v1ilZS0880axarF3k8yYZfjNQhtOBD60cFbbwBavsA 59i3nbqkt1LSA8kezeED792xGS2uE5BDvfTrbhODNA7zHhj8YMkeCUSQW4rzS00u3KgHdFRppRFl PZbdGhgJ_5WTxH9i7Q1sBpi_ewKUWD9AUqwoItz5Sa.PjCakphyltwvhEDoZ1_rVy6UpFJR5Uxh. QNCW82K8LHeplVgsQ4_WFgrjohubiGgexWK0o248oMURyFMGS4eThWM3fkZvnbYwBrlrzEr4skzT Cd6256YykffXvGdFT.1.oJMTxdjB4v0Zm9W_n8Ii868WK8cEDJ3FISn2kBQ_J7cYIGXPlW2MyuNB Qr7YFugR12q5fSjrKl39xCa0wRpbBve1CjbISfNHg5GrEDvfkB54ZD6_YP8h0q3fQ_Zu3_U5_v_9 2UbM5JR7sEUIXFGRubVSLgIaC2lHxdEMK3y1d1rlrKrhPBdLr6_Fz8RXBuiCX3SOgML.NO76TIzc Bldbm8WSiTjjBWJX7gu__Zt9noy8TMOalLirE5DMJlHpd3CO1AKoQl980kOF.cnZaTC9rzgOR6v2 zwo9qW.IS7H_wLLLqVtKgf.tV21Og2pab_oZvciSrJxd8Oe.T..wbI9zzgO9poaa0t_5zcLIm7tL 59KqBNmLjVWAZLsnr4Acwrojh7vt0ga5vPLpKiB1qbu9RgHQhfPlZ6zFAFLcKoZ1WqD5yT0hUd2m GjCA3zKMf92RUpT6DLR1QC15TqmiAURQ3kzJB_Dh7uxXvrWx6GgT.LLeYgia9aty5_V8M7OKFOTX oB2ecFpiriZqJt0p3nSDp0GO.NoFO0ZqdRaojLjUoNZJUK5euFh0LZa00uET6G1kAolQtMeQ9bKX EmS1H_BWJq2My6QvZd2FSn8KPKoYYT1DFqnBwUhMnVTrgAOQMv6Rc6ytjHjT6Ki0v9FAxz3HQEbp z_PyUDj2xAXTd0lb62aqU4Uv9ha7lygz3qwldny6Ua9_ou0mOSlElbsHrbIQ- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic310.consmr.mail.ne1.yahoo.com with HTTP; Sat, 6 Nov 2021 10:41:37 +0000 Received: by kubenode510.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID db4c20d1743c99402968b7529e3e2810; Sat, 06 Nov 2021 10:41:31 +0000 (UTC) From: Po Lu References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> Date: Sat, 06 Nov 2021 18:41:27 +0800 In-Reply-To: <83pmrdbqz2.fsf@gnu.org> (Eli Zaretskii's message of "Sat, 06 Nov 2021 10:58:25 +0200") Message-ID: <87o86xzhuw.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 48963 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Eli Zaretskii writes: > Thanks, I added an entry in PROBLEMS along those lines. Thanks! Lars, could you test the latest changes below with the workaround now described in PROBLEMS? Also, could someone with a Mac verify that this still builds on macOS, and preferably implement the missing features on that platform as well? I hope all goes well, because it would be really nice to see this installed in the master branch soon. Many people have been waiting for xwidgets to be actually useful for a long time. Thanks. --=-=-= Content-Type: application/gzip Content-Disposition: attachment; filename=patches.tar.gz Content-Transfer-Encoding: base64 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 --=-=-=-- From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Lars Ingebrigtsen Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sat, 06 Nov 2021 17:43:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Po Lu Cc: Eli Zaretskii , 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163622056011397 (code B ref 51473); Sat, 06 Nov 2021 17:43:01 +0000 Received: (at 51473) by debbugs.gnu.org; 6 Nov 2021 17:42:40 +0000 Received: from localhost ([127.0.0.1]:50430 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjPiB-0002xk-TQ for submit@debbugs.gnu.org; Sat, 06 Nov 2021 13:42:40 -0400 Received: from quimby.gnus.org ([95.216.78.240]:53312) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjPiA-0002xX-Ah for 51473@debbugs.gnu.org; Sat, 06 Nov 2021 13:42:39 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnus.org; s=20200322; h=Content-Type:MIME-Version:Message-ID:In-Reply-To:Date: References:Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=T3dpKqSCRy2ESSOkb5ySBUGK2mKh4GU0kaeXYj8P80o=; b=Lq7udFP2ht0xsy3BoOkAxpFsNd Q9mYxI4st7J84DogrhbOezFgD/J7kktyVswHsIt9spvFWTzQVs2kLavRvgqO2fb26JWJURBkf3fVs KZeJCY3zixghLwVWCFlmzkK/YXc7I5J7WLVlMRUbTXIB/Ehp/6xWegyJsBV5MxdRNwv0=; Received: from [84.212.220.105] (helo=elva) by quimby.gnus.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mjPi0-00008m-U8; Sat, 06 Nov 2021 18:42:31 +0100 From: Lars Ingebrigtsen References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> <87o86xzhuw.fsf@yahoo.com> Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAABGdBTUEAALGPC/xhBQAAACBj SFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAJ1BMVEWmmXry26zjx532 47T88cHZoIW8R0ewIi/HYlu1poTWi3fks5P////UfGsyAAAAAWJLR0QMgbNRYwAAAAd0SU1FB+UL BhEgHESH//YAAAGHSURBVDjLpZTPasJAEMaVPsFk8AES8dTTZOilPfYJSimIuav4AKb0VsG49CY+ gYcWaU9WKNJ9ue6fbLJJ1lPnEML88s03M9mk108gShIAQLZB+gLc64MNl3dRgTapgSkQAEgIQCGF pwwDuASwA0g/jQFgIdYeSF594BYoKTe6wtqYfIUCVGahAZhsS9weEL12/TnMkgIruQJOY/Y6Rqbk XgO8meVrbxYebPJXBXbpZzbOn0+O0DhfyMlJKa6V22C2PJX5j3ylHKQulcbAd5sXC36We051Z70d RVLGmAo7ZHEk+U0GpPIwXWSVO52nawlGcSiKYrp3Tf3OxVw8aICRvD2IJ6f4ehOP76YU8iATq6jM R8OzGA315FtFR5MsdqWkzI5mJVu1bq42qDV2W1rRXKLbrvLg0PkxgP8HGh4YVpRpbAH11SHXx4Eq AERwwRzIKKpBHSBCNGdQ3ZEPquPhXhaBclUenTCV1XZr10qrND5odGZAEkcBkJiIL4HE/IH0++uC xgP8B+ZkrxYVE0zmAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDIxLTExLTA2VDE3OjMyOjI4KzAwOjAw 9gHIwAAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMS0xMS0wNlQxNzozMjoyOCswMDowMIdccHwAAAAA SUVORK5CYII= X-Now-Playing: Xiu Xiu's _Oh No_: "Fuzz Gong Fight" Date: Sat, 06 Nov 2021 18:42:28 +0100 In-Reply-To: <87o86xzhuw.fsf@yahoo.com> (Po Lu's message of "Sat, 06 Nov 2021 18:41:27 +0800") Message-ID: <87sfw9cha3.fsf@gnus.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Report: Spam detection software, running on the system "quimby.gnus.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see @@CONTACT_ADDRESS@@ for details. Content preview: Po Lu writes: > Thanks! Lars, could you test the latest changes below with the > workaround now described in PROBLEMS? > > Also, could someone with a Mac verify that this still builds on macOS, > and preferably imp [...] Content analysis details: (-2.9 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Po Lu writes: > Thanks! Lars, could you test the latest changes below with the > workaround now described in PROBLEMS? > > Also, could someone with a Mac verify that this still builds on macOS, > and preferably implement the missing features on that platform as well? I can test both, but it'd be easier to test if it was just one huge patch. (When applying for real, we can apply the patch series.) So can you post this series as one patch? -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 07 Nov 2021 00:42:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Lars Ingebrigtsen Cc: Eli Zaretskii , 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.16362457008289 (code B ref 51473); Sun, 07 Nov 2021 00:42:01 +0000 Received: (at 51473) by debbugs.gnu.org; 7 Nov 2021 00:41:40 +0000 Received: from localhost ([127.0.0.1]:51214 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjWFc-00029a-QR for submit@debbugs.gnu.org; Sat, 06 Nov 2021 20:41:40 -0400 Received: from sonic312-25.consmr.mail.ne1.yahoo.com ([66.163.191.206]:35584) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjWFX-00029H-BO for 51473@debbugs.gnu.org; Sat, 06 Nov 2021 20:41:35 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636245685; bh=eRcUDc9FplHcNm6Y62CeRNWt5EAj4P4hnp/vX5uOYa8=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=ffYWNiXxkBVwXm8kU+NU9hH5F52CcXT0kmH7kZxYt4n4lZ8j24l9L9Z4JhqflYYI01aophOkDBirApqKs5faCpdNhr1QIbaEZjxanwLqIRsFfvvHRAteCTu7950hnfzwgkeTf6AO6Pbzc3Oqyh9njzKuLRTxDUOMEb5wycHcuwAtAsCNtVKyNn8L2+jZk8j08kaP9C40Mts07JEyEb3h6vlx2fZwQFJCh7JkX5Y3h2cPXtCnJPE51hUu1+v3m/472/nEPN8gnpSwe2EhuNel8GJXZljSL3svUL/BQHuhEZ1UWMMpyU0sXu3ZReG74YVUjV/WxzARqCraUzlATczl1w== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636245685; bh=I3AQzYO/tsmBB5/12yMt/EAlUTmYVQQrH2qgwKe5hIC=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=QuTHOC2oho1jBMs3Npz3cKnhke7WEidI1sKfV8NSM2Xll45Q5ftMOlbRUgDUnBHyRofRwEviLGX/xt5P4EhMcjfQeAEyU6f7kYEoAYCdjS9Aa1nmOBUurP2/Cg2Ur6q/+G7FKSwEIDOTTe184HfAsBhj1slxyZWEi3G9yGITPJ0xBhpNOUVU7ekSxc0DOhdV9EUQdDo4xGjh9/NtIvrEQWjtYVirxhm2+KEYl+BubPIyQmoYuYyp7tzcIfCfYND4LRxWD0O5FmERfGEBGKTsOpDwNt3UEZGc3Kk5NcB+QcjxNKbEtpAnJeCAs7zEAqS1ttFjBzY84KYwcYk7uWSzgw== X-YMail-OSG: GrJA2rwVM1nIE68BpIvOscgpSKhzHuEZ_NB8v5Z5kHdWsieudBMdmCq.X2DrPiN xQTYh_ye_L0SHWibBkuzfrUhkCpBPTDdl65sPeLC2jytIcLF8x3ISxfqb2pUfFdp4pSePIpofAaH nos.imP8MSC2z4YheMw5_IZk_cqfrfAS07hD4KLiU97otcmkJqmY5DHS3uquOUGSqT3pp6akJsy8 Twf1UA1VhtNc8xfNmoJeoVYaxK3_QJQ5izWSEsvEjTZET1Gr7ilxLCM2P1qeVOjvsLhrCBF5O9Bk sVZJBdL_fnXQiPCn8XbV39K0cyEwGtWoY2WmSR7NauxgTBeN3xi4U2noTMcRrHGNFrBW3t0o2hBO r.oECItedk2ERwTqHLFfPfaKSJTVFNcRbmX_YICY4tZgQgEJVqsB7K.IKP6ygLKRpekW31lbxpNn RllikmPeBsd9weftiWKHL0Dci6tzZrRfZA_3X2jbkn5mR_IuNapgOaow_HTLcDKRGT3VR_5OGQjz 1.Q8salTG0aV_19S9Mx7tCp3pg2l8bQ_1yNs2v1cmwN94PsZsvhrYjQ8QQgdDQfWkzErSiyVv8AM .jyP30TMB8qGMuTE.bozRHqQFz3z6q9XpWD.KLbXUOI8VlJXTG_j94iw2c3wc.3Pdsf.6h4sxvr0 VIBzjDJA0fwItaTisdHXpc_ZypP6.A6xahbqf0gWfHjOxZ3yxjZ7k5bfWdzgqnm4WUhUvrG92hHo jmUO80_gnGp4_1xb1txeCcN4L_OZSyDtdbQ4VYCI4cQcUrnBG.xb9_iwoPAswg0dbzeT_qxObvXz RRsfDqCoGzzxVnGDbdIbZ9nq05Us6.LHZQHp0CR1LKo1QWTbn4exN_Um_aFktW5ejPUS3jKla_1g .5WqVDm7YEfJ4PC5q2VeuzzeSokN28TwzG8q9nSC.b0NqgiT7Tcz18lO_DEySTodhvg7sQvBh6aI iO0VBWRKq4hh_T7j9pOEIl5yNnqLAumotVfT_yD.xHjO384zX3RR5CLa7J5MlWeoQQkGkBziPc8B XR5MBTpEiwsWrpWLRUceRjbKjnRvxr5ImwF2vjht1w6z1hYXtr0dngSF7ly8xzUhmuZetDl.Lz5_ EYTczXVwy_N4.IG2EG5N8CMuvOcB3MBl.ScUJMmGXYNt_Z0nLXgurVoqxy7gpn_rfK51zH54Ciqj EGTsJGtGj2DNJ.1urPTO6y8Zk2EZzWqOrc5AHYP_.9sbsgDKFZtRk5m1kBxaqGEhYMnuv1BObYXp .XL6YVejoFlrf1ZNLrIDaALz.dQMAcjbpUi63B9dXEIaeZGHj7VAxBe0CDX5NKDhSGGp.2bXT7WW AlS_kcKgAdvg0_KJOdDm56uZa4UCyjen9IUMHRxsrbEOEcSTLS4imm4bOa2ON6QfUtgFQghrVlW0 fzwYfVZ5iIh6qfGwIgWGTDyy_jYw_M0EeVWSaHHhp5nFIOYVVHnNKM3phQr2Vr7w7MeZU4RI4hnT EM8Ph47Dr7YknDfQ72W528gmJ0Rw09DIrfjsPEYzkL2kETeBxxdJI0ycFmNPmjJE1P_ngF3E9UDo qf8ukMM3ME4z4WZaUz7I1srieEKLFVyEHYeIgPtjyfPlcTuVDUI7APGekI6_9bBD4IRrR3kI1nnb 8jny60Yz90jlZiPwV42wW6gjbERBZT6cE1FHppHz_2XEsGEfldgy34kYFGS6T.MwHlkvELHZa77s Eetj.c9kcr7qN0sr2OEiCmspmhFO5UfGWaaD8ej79bxr.vdr6FFYxUfi4Fb0YtLMg83aFPHFgWNS unSlkATYSMVjYqLwDiDFn5EStg2XxBVqq.fbxlhfPEcgP3bKmdMNLk.fp6skp5C4CQEbD67IWiAi SAALlkuGqXyGoEuawXM1QhGTExisx58Xcv.Oo8_U0RUFPf97ddqUBA7xtcVpLV3HLJHJG.FK2p.R DPYolSfBQ3btTszSy.hbYnFrjY82FhR8Ujob5XqupTSeicwKnb9s1aK.kTKchC23.AlziwQU0n60 fqObkv9CuDwVKaEXAgYlPaeyWBjzIzfEmUpWJt6EiN9BWb8O8ILGQUhQ5DgEIO9FUV5EsM5okrfi Y3dk1csKqiESXHQ5dcJ.iSLeuQeNOHBmvuHLdx5qzHOaZgswLTfEaRJMQdXXtmOMHfzWDZZ2_cWE 0C5HImOoT7h.T4jC0WFcKMnXbLK6mVxW0Swt_PodfPvcUio4lRxBO3FRCCeJDMOZRJivJ_uNqosb 6IWp.qeh2_9_0iQTCdU_ZPOLebKX70fYZO6dWZZZUddkoPfqDXhA1kWcDyUfn X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic312.consmr.mail.ne1.yahoo.com with HTTP; Sun, 7 Nov 2021 00:41:25 +0000 Received: by kubenode504.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 64cc54656765cf54ccadddb8eda3eade; Sun, 07 Nov 2021 00:41:18 +0000 (UTC) From: Po Lu References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> <87o86xzhuw.fsf@yahoo.com> <87sfw9cha3.fsf@gnus.org> Date: Sun, 07 Nov 2021 08:41:15 +0800 In-Reply-To: <87sfw9cha3.fsf@gnus.org> (Lars Ingebrigtsen's message of "Sat, 06 Nov 2021 18:42:28 +0100") Message-ID: <878ry0ztjo.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 92234 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Lars Ingebrigtsen writes: > I can test both, but it'd be easier to test if it was just one huge > patch. (When applying for real, we can apply the patch series.) So can > you post this series as one patch? Thanks, here you go. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=test.diff diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi index 7f91e1c188..1207ab5e9a 100644 --- a/doc/emacs/misc.texi +++ b/doc/emacs/misc.texi @@ -2953,6 +2953,34 @@ Embedded WebKit Widgets reloading it. Type @w{@kbd{C-h b}} in that buffer to see the key bindings. +@findex xwidget-webkit-edit-mode +@cindex xwidget-webkit-edit-mode + By default, typing a self-inserting character inside an xwidget +webkit buffer will do nothing, or trigger some special action. To +make those characters and other common editing keys insert themselves +when pressed, you can enable @code{xwidget-webkit-edit-mode}, which +redefines them to be passed through to the WebKit xwidget. + +You can also enable @code{xwidget-webkit-edit-mode} by typing @kbd{e} +inside the xwidget webkit buffer. + +@findex xwidget-webkit-isearch-mode +@cindex xwidget-webkit-isearch-mode +@cindex searching in webkit buffers + @code{xwidget-webkit-isearch-mode} is a minor mode that behaves +similarly to incremental search (@pxref{Incremental Search}), but +operates on the contents of a WebKit widget instead of the current +buffer. It is bound to @kbd{C-s} and @kbd{C-r} inside xwidget-webkit +buffers. When it is enabled through @kbd{C-r}, the initial search +will be performed in reverse direction. + +Typing any self-inserting character will cause the character to be +inserted into the current search query. Typing @kbd{C-s} will cause +the WebKit widget to display the next search result, while typing +@kbd{C-r} will cause it to display the last. + +To leave incremental search, you can type @kbd{C-g}. + @node Browse-URL @subsection Following URLs @cindex World Wide Web diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi index b38a83b4fe..832b570b6a 100644 --- a/doc/lispref/commands.texi +++ b/doc/lispref/commands.texi @@ -1176,6 +1176,7 @@ Input Events * Repeat Events:: Double and triple click (or drag, or down). * Motion Events:: Just moving the mouse, not pushing a button. * Focus Events:: Moving the mouse between frames. +* Xwidget Events:: Events generated by xwidgets. * Misc Events:: Other events the system can generate. * Event Examples:: Examples of the lists for mouse events. * Classifying Events:: Finding the modifier keys in an event symbol. @@ -1871,6 +1872,76 @@ Focus Events so that the focus event comes either before or after the multi-event key sequence, and not within it. +@node Xwidget Events +@subsection Xwidget events + +Xwidgets (@pxref{Xwidgets}) can send events to update Lisp programs on +their status. These events are dubbed @code{xwidget-events}, and +contain various data describing the nature of the change. + +@table @code +@cindex @code{xwidget-event} event +@item (xwidget-event @var{kind} @var{xwidget} @var{arg}) +This event is sent whenever some kind of update occurs in +@var{xwidget}. There are several types of updates, which are +identified by @var{kind}. + +@cindex @code{load-changed} xwidget events +An xwidget event with @var{kind} set to @code{load-changed} indicates +that the @var{xwidget} has reached a particular point of the +page-loading process. When these events are sent, @var{arg} will +contain a string that futher describes the status of the widget. + +@cindex @samp{"load-finished"} in xwidgets +When @var{arg} is @samp{"load-finished"}, it means the xwidget has +finished processing whatever page-loading operation that it was +previously performing. + +@cindex @samp{"load-started"} in xwidgets +Otherwise, if it is @samp{"load-started"}, then the widget has begun a +page-loading operation. + +@cindex @samp{"load-redirected"} in xwidgets +If @var{arg} is @samp{"load-redirected"}, it means the widget has +encountered and followed a redirect during the page-loading operation. + +@cindex @samp{"load-committed"} in xwidgets +If @var{arg} is @samp{"load-committed"}, then the widget has committed +to a given URL during the page-loading operation. This means that the +URL is the final URL that will be rendered by @var{xwidget} during the +current page-loading operation. + +@cindex @code{download-callback} xwidget events +An event with @var{kind} set to @code{download-callback} indicates +that a download of some kind has been completed. + +In these events, there can be arguments after @var{arg}, which itself +indicates the URL that the download file was retrieved from: the first +argument after @var{arg} indicates the MIME type of the download, as a +string, while the second such argument contains the full file path to +the downloaded file. + +@cindex @code{download-started} xwidget events +An event with @var{kind} set to @code{download-started} indicates that +a download has been started. In these events, @var{arg} contains the +URL of the file that is currently being downloaded. + +@cindex @code{javascript-callback} xwidget events +An event with @var{kind} set to @code{javascript-callback} contains +JavaScript callback data. These events are used internally by +@code{xwidget-webkit-execute-script}. + +@cindex @code{xwidget-display-event} event +@item (xwidget-display-event @var{xwidget}) +This event is sent whenever an xwidget requests that another xwidget +be displayed. @var{xwidget} is the xwidget that should be displayed. + +@var{xwidget}'s buffer will be set to a temporary buffer. When +displaying the widget, care should be taken to replace the buffer with +the buffer in which the xwidget will be displayed, using +@code{set-xwidget-buffer} (@pxref{Xwidgets}). +@end table + @node Misc Events @subsection Miscellaneous System Events diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 22528a1b0f..37f07c4f28 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -6784,7 +6784,10 @@ Xwidgets in a @code{display} text or overlay property (@pxref{Display Property}). -@defun make-xwidget type title width height arguments &optional buffer + Embedded widgets can send events notifying Lisp code about changes +occurring within them. (@pxref{Xwidget Events}). + +@defun make-xwidget type title width height arguments &optional buffer related This creates and returns an xwidget object. If @var{buffer} is omitted or @code{nil}, it defaults to the current buffer. If @var{buffer} names a buffer that doesn't exist, it will be @@ -6797,7 +6800,9 @@ Xwidgets @end table The @var{width} and @var{height} arguments specify the widget size in -pixels, and @var{title}, a string, specifies its title. +pixels, and @var{title}, a string, specifies its title. @var{related} +is used internally by the WebKit widget, and is not of interest to the +programmer. @end defun @defun xwidgetp object @@ -6818,6 +6823,10 @@ Xwidgets This function returns the buffer of @var{xwidget}. @end defun +@defun set-xwidget-buffer xwidget buffer +This function sets the buffer of @var{xwidget} to @var{buffer}. +@end defun + @defun get-buffer-xwidgets buffer This function returns a list of xwidget objects associated with the @var{buffer}, which can be specified as a buffer object or a name of @@ -6878,6 +6887,61 @@ Xwidgets query-on-exit flag, either @code{t} or @code{nil}. @end defun +@defun xwidget-perform-lispy-event xwidget event frame +Send an input event @var{event} to @var{xwidget}. The precise action +performed is platform-specific. See @ref{Input Events}. + +You can optionally pass the frame the event was generated from via +@var{frame}. On X11, modifier keys in key events will not be +considered if @var{frame} is @code{nil}, and the selected frame is not +an X-Windows frame. + +On GTK, only keyboard and function key events are implemented. Mouse, +motion, and click events are dispatched to the xwidget without going +through Lisp code, and as such shouldn't require this function to be +sent. +@end defun + +@defun xwidget-webkit-search query xwidget &optional case-insensitive backwards wrap-around +Start an incremental search on the WebKit widget @var{xwidget} with +the string @var{query} as a query. @var{case-insensitive} denotes +whether or not the search is case-insensitive, @var{backwards} +determines if the search is performed backwards towards the start of +the document, and @var{wrap-around} determines whether or not the +search terminates at the end of the document. + +If the function is called while a search query is already present, +then the query specified here will replace the existing query. + +To stop a search query, use @code{xwidget-webkit-finish-search}. +@end defun + +@defun xwidget-webkit-next-result xwidget +Display the next search result in @var{xwidget}. This function will +error unless a search query has already been started in @var{xwidget} +through @code{xwidget-webkit-search}. + +If @code{wrap-around} was non-nil when @code{xwidget-webkit-search} +was called, then the search will restart from the beginning of the +document if the end is reached. +@end defun + +@defun xwidget-webkit-previous-result xwidget +Display the previous search result in @var{xwidget}. This function +will error unless a search query has already been started in +@var{xwidget} through @code{xwidget-webkit-search}. + +If @code{wrap-around} was non-nil when @code{xwidget-webkit-search} +was called, then the search will restart from the end of the +document if the beginning is reached. +@end defun + +@defun xwidget-webkit-finish-search xwidget +Finish a search operation started with @code{xwidget-webkit-search} in +@var{xwidget}. If there is no query currently ongoing, then this +function will error. +@end defun + @node Buttons @section Buttons @cindex buttons in buffers diff --git a/etc/NEWS b/etc/NEWS index a50229916f..0e5caa4825 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -495,6 +495,31 @@ the buffer will take you to that directory. This is a convenience function to extract the field data from 'exif-parse-file' and 'exif-parse-buffer'. +** Xwidgets + ++++ +*** New minor mode `xwidget-webkit-edit-mode'. +When this mode is enabled, self-inserting characters and other common +web browser shotcut keys are redefined to send themselves to the +WebKit widget. + ++++ +*** New minor mode `xwidget-webkit-isearch-mode'. +This mode acts similarly to incremental search, and allows to search +the contents of a WebKit widget. In xwidget-webkit mode, it is bound +to `C-s' and `C-r'. + +--- +*** On X11, the WebKit inspector is now available inside xwidgets. +To access the inspector, right click on the widget and select "Inspect +Element". + +--- +*** "Open in New Window" in a WebKit widget's context menu now works. +The newly created buffer will be displayed via display-buffer, which +can be customized through the usual mechanism of display-buffer-alist +and friends. + * New Modes and Packages in Emacs 29.1 @@ -719,6 +744,33 @@ an exact match, then the lowercased '[menu-bar foo\ bar]' and finally '[menu-bar foo-bar]'. This further improves backwards-compatibility when converting menus to use 'easy-menu-define'. ++++ +** New function `xwidget-perform-lispy-event'. +This function allows you to send events to xwidgets. Usually, some +equivalent of the event will be sent, but there is no guarantee of +what the widget will actually receive. + +On GTK+, only key and function key events are implemented. + ++++ +** New functions for performing searches on WebKit xwidgets. +Some new functions, such as `xwidget-webkit-search', have been added +for performing searches on WebKit xwidgets. + ++++ +** `load-changed' xwidget events are now more detailed. +In particular, they can now have different arguments based on the +state of the WebKit widget. `load-finished' is sent when a load has +completed, `load-started' when a load first starts, `load-redirected' +after a redirect, and `load-committed' when the WebKit widget first +commits to the load. + ++++ +** New event type `xwidget-display-event'. +These events are sent whenever an xwidget requests that Emacs display +another. The only argument to this event is the xwidget that should +be displayed. + * Changes in Emacs 29.1 on Non-Free Operating Systems diff --git a/etc/images/README b/etc/images/README index 9bbe796cc9..561cfff765 100644 --- a/etc/images/README +++ b/etc/images/README @@ -68,6 +68,7 @@ Emacs images and their source in the GNOME icons stock/ directory: bookmark_add.xpm actions/bookmark_add cancel.xpm slightly modified generic/stock_stop connect.xpm net/stock_connect + connect-to-url.xpm net/stock_connect-to-url contact.xpm net/stock_contact data-save.xpm data/stock_data-save delete.xpm generic/stock_delete diff --git a/etc/images/connect-to-url.pbm b/etc/images/connect-to-url.pbm new file mode 100644 index 0000000000..f142349f4a Binary files /dev/null and b/etc/images/connect-to-url.pbm differ diff --git a/etc/images/connect-to-url.xpm b/etc/images/connect-to-url.xpm new file mode 100644 index 0000000000..38fefeaf61 --- /dev/null +++ b/etc/images/connect-to-url.xpm @@ -0,0 +1,281 @@ +/* XPM */ +static char *connect_to_url[] = { +/* columns rows colors chars-per-pixel */ +"24 24 251 2 ", +" c black", +". c #010101", +"X c #000103", +"o c #010204", +"O c #010305", +"+ c #020407", +"@ c #020609", +"# c #03070C", +"$ c #04080D", +"% c #0F0F0D", +"& c #030A10", +"* c #050B10", +"= c #060C11", +"- c #070D13", +"; c #070D14", +": c #060C15", +"> c #070E14", +", c #0B1824", +"< c #0A1B2B", +"1 c #0A1C2E", +"2 c #141A20", +"3 c #161E25", +"4 c #181E23", +"5 c #0D2032", +"6 c #142534", +"7 c #1F2830", +"8 c #1D2933", +"9 c #102438", +"0 c #272622", +"q c #21292F", +"w c #272F36", +"e c #282F33", +"r c #222F3A", +"t c #2E3337", +"y c #2D373E", +"u c #32383C", +"i c #33383C", +"p c #343A3E", +"a c #43423C", +"s c #112941", +"d c #102A44", +"f c #132D47", +"g c #192F46", +"h c #17314B", +"j c #15314F", +"k c #163351", +"l c #163554", +"z c #173554", +"x c #1F3A53", +"c c #1D3955", +"v c #1A3958", +"b c #1C3B5B", +"n c #1F3C58", +"m c #1D3C5C", +"M c #1E3E5D", +"N c #1F3F5F", +"B c #303B44", +"V c #313C44", +"C c #313D47", +"Z c #213C56", +"A c #233E57", +"S c #1F405F", +"D c #374148", +"F c #2D4050", +"G c #25405B", +"H c #25425E", +"J c #214262", +"K c #244565", +"L c #264665", +"P c #254666", +"I c #2A4967", +"U c #284969", +"Y c #2A4C6C", +"T c #2C4F6F", +"R c #33526E", +"E c #385269", +"W c #2D5070", +"Q c #2E5172", +"! c #335473", +"~ c #3F5B75", +"^ c #3D5F7D", +"/ c #41494F", +"( c #646056", +") c #6C685E", +"_ c #505F6C", +"` c #48657C", +"' c #556A7A", +"] c #5B6C78", +"[ c #5F6F7B", +"{ c #5D6F7D", +"} c #706C62", +"| c #726D63", +" . c #78756B", +".. c #7D786E", +"X. c #60727F", +"o. c #807D74", +"O. c #8A857B", +"+. c #8B877E", +"@. c #4E6A83", +"#. c #4A6A86", +"$. c #4A7090", +"%. c #587790", +"&. c #5F7E95", +"*. c #587B98", +"=. c #6F7980", +"-. c #697F8F", +";. c #66839B", +":. c #6A879F", +">. c #708391", +",. c #728A9A", +"<. c #748898", +"1. c #758A99", +"2. c #7B8F9F", +"3. c #708DA4", +"4. c #7990A1", +"5. c #7292AB", +"6. c #7691A8", +"7. c #7693AB", +"8. c #7B98AE", +"9. c #7E98AD", +"0. c #7E9DB3", +"q. c #7F9EB4", +"w. c #8C8981", +"e. c #989389", +"r. c #A6A29B", +"t. c #8093A1", +"y. c #8598A3", +"u. c #8498A7", +"i. c #809AAD", +"p. c #8F9FAA", +"a. c #899FAE", +"s. c #819FB5", +"d. c #86A2B8", +"f. c #87A5BB", +"g. c #88A3B8", +"h. c #89A5BA", +"j. c #8FABBF", +"k. c #97A7B1", +"l. c #90AABE", +"z. c #91ABBF", +"x. c #98ACB9", +"c. c #AAA7A0", +"v. c #B1ADA4", +"b. c #B3B1AA", +"n. c #B7B3AA", +"m. c #A3B1BC", +"M. c #A5B1BC", +"N. c #A9B6BF", +"B. c #BEBBB5", +"V. c #C4C2BD", +"C. c #94AEC1", +"Z. c #96AEC1", +"A. c #94AFC2", +"S. c #95AFC2", +"D. c #96B0C3", +"F. c #98B0C3", +"G. c #9FB5C3", +"H. c #99B3C6", +"J. c #98B3C7", +"K. c #9AB3C6", +"L. c #9BB4C7", +"P. c #9FB8CA", +"I. c #9FB8CB", +"U. c #A2B8C9", +"Y. c #A3B9C9", +"T. c #A0B9CB", +"R. c #A3BACB", +"E. c #A0B9CC", +"W. c #A2BACC", +"Q. c #A4BDCE", +"!. c #A6BECF", +"~. c #B8BEC2", +"^. c #B8C3CA", +"/. c #BCC5CB", +"(. c #BDC8CE", +"). c #A8C0D1", +"_. c #AAC0D0", +"`. c #ABC1D1", +"'. c #ACC2D3", +"]. c #AAC5D7", +"[. c #B4C8D6", +"{. c #BDCBD5", +"}. c #B4C9D8", +"|. c #B6CAD8", +" X c #B8CBD9", +".X c #BBCDDB", +"XX c #B7D0E0", +"oX c #BDD3E2", +"OX c #BCD5E5", +"+X c #CECAC3", +"@X c #C5D2C8", +"#X c #C0D2DE", +"$X c #C4D3DF", +"%X c #CCD7DE", +"&X c #D2D8DC", +"*X c #E1DFDB", +"=X c #E2E1DD", +"-X c #C2D3E0", +";X c #C2D4E1", +":X c #C5D5E1", +">X c #C6D6E1", +",X c #C4D6E2", +". e.o. sXwX}.R.R.`.H.1.- JXJX", +"JX4 a.9.C.h.] a n.V.BXo. p.!.T.l.4.- JXJX", +"JX2 F.d.5.7. =XAXc.BXo. @X@XZX !.C.F.@.> JXJX", +" o.=XAXc.BXo. t.U.z.3.Y $ JXJX", +"BXBXBXBXVXBXBXAXVXO.CXo. P.C.!.I.J.C.;.L * JXJX", +"o.o.o.o.o. . .B.b...*X . $.*.T.J.A.h.Y c @ JXJX", +" .w.r.| +X . 1.C.3.L h JXJX", +"JXJX6 Q ^ 1.% w.r.| +X . @X@XHX h.:.M , JXJX", +"JXJXO x T #.] 0 +.} v.) -.s.H 9 O JXJXJX", +"JXJXJX+ n ! i.X.% % e.( Q Y %.0.&.f O JXJXJX", +"JXJXJXJX& A s.8.E A % % A K J R ` g @ JXJXJXJX", +"JXJXJXJXJX@ C ~ m M J N M b v l < O JXJXJXJXJX", +"JXJXJXJXJXJX : 5 d k z k d 1 & JXJXJXJXJXJX", +"JXJXJXJXJXJXJXJX JXJXJXJXJXJXJXJX", +"JXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJX", +"JXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJX" +}; diff --git a/lisp/xwidget.el b/lisp/xwidget.el index 8c593abea8..d427e70233 100644 --- a/lisp/xwidget.el +++ b/lisp/xwidget.el @@ -37,6 +37,7 @@ (declare-function make-xwidget "xwidget.c" (type title width height arguments &optional buffer)) (declare-function xwidget-buffer "xwidget.c" (xwidget)) +(declare-function set-xwidget-buffer "xwidget.c" (xwidget buffer)) (declare-function xwidget-size-request "xwidget.c" (xwidget)) (declare-function xwidget-resize "xwidget.c" (xwidget new-width new-height)) (declare-function xwidget-webkit-execute-script "xwidget.c" @@ -88,6 +89,9 @@ xwidget-at (require 'seq) (require 'url-handlers) +(defvar-local xwidget-webkit--title "" + "The title of the WebKit widget, used for the header line.") + ;;;###autoload (defun xwidget-webkit-browse-url (url &optional new-session) "Ask xwidget-webkit to browse URL. @@ -124,6 +128,14 @@ xwidget-webkit-clone-and-split-right (with-selected-window (split-window-right) (xwidget-webkit-new-session url)))) +(declare-function xwidget-perform-lispy-event "xwidget.c") + +(defun xwidget-webkit-pass-command-event () + "Pass `last-command-event' to the current buffer's WebKit widget." + (interactive) + (xwidget-perform-lispy-event (xwidget-webkit-current-session) + last-command-event)) + ;;todo. ;; - check that the webkit support is compiled in (defvar xwidget-webkit-mode-map @@ -138,6 +150,9 @@ xwidget-webkit-mode-map (define-key map "w" 'xwidget-webkit-current-url) (define-key map "+" 'xwidget-webkit-zoom-in) (define-key map "-" 'xwidget-webkit-zoom-out) + (define-key map "e" 'xwidget-webkit-edit-mode) + (define-key map "\C-r" 'xwidget-webkit-isearch-mode) + (define-key map "\C-s" 'xwidget-webkit-isearch-mode) ;;similar to image mode bindings (define-key map (kbd "SPC") 'xwidget-webkit-scroll-up) @@ -164,6 +179,63 @@ xwidget-webkit-mode-map map) "Keymap for `xwidget-webkit-mode'.") +(easy-menu-define nil xwidget-webkit-mode-map "Xwidget WebKit menu." + (list "Xwidget WebKit" + ["Browse URL" xwidget-webkit-browse-url + :active t + :help "Prompt for a URL, then instruct WebKit to browse it"] + ["Back" xwidget-webkit-back t] + ["Forward" xwidget-webkit-forward t] + ["Reload" xwidget-webkit-reload t] + ["Insert String" xwidget-webkit-insert-string + :active t + :help "Insert a string into the currently active field"] + ["Zoom In" xwidget-webkit-zoom-in t] + ["Zoom Out" xwidget-webkit-zoom-out t] + ["Edit Mode" xwidget-webkit-edit-mode + :active t + :style toggle + :selected xwidget-webkit-edit-mode + :help "Send self inserting characters to the WebKit widget"] + ["Save Selection" xwidget-webkit-copy-selection-as-kill + :active t + :help "Save the browser's selection in the kill ring"] + ["Incremental Search" xwidget-webkit-isearch-mode + :active (not xwidget-webkit-isearch-mode) + :help "Perform incremental search inside the WebKit widget"])) + +(defvar xwidget-webkit-tool-bar-map + (let ((map (make-sparse-keymap))) + (prog1 map + (tool-bar-local-item-from-menu 'xwidget-webkit-back + "left-arrow" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-forward + "right-arrow" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-reload + "refresh" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-zoom-in + "zoom-in" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-zoom-out + "zoom-out" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-browse-url + "connect-to-url" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-isearch-mode + "search" + map + xwidget-webkit-mode-map)))) + (defun xwidget-webkit-zoom-in () "Increase webkit view zoom factor." (interactive nil xwidget-webkit-mode) @@ -276,6 +348,8 @@ xwidget-webkit-callback (with-current-buffer (xwidget-buffer xwidget) (cond ((eq xwidget-event-type 'load-changed) (let ((title (xwidget-webkit-title xwidget))) + (setq xwidget-webkit--title title) + (force-mode-line-update) (xwidget-log "webkit finished loading: %s" title) ;; Do not adjust webkit size to window here, the selected window ;; can be the mini-buffer window unwantedly. @@ -309,8 +383,10 @@ bookmark-make-record-function (define-derived-mode xwidget-webkit-mode special-mode "xwidget-webkit" "Xwidget webkit view mode." (setq buffer-read-only t) + (setq-local tool-bar-map xwidget-webkit-tool-bar-map) (setq-local bookmark-make-record-function #'xwidget-webkit-bookmark-make-record) + (setq-local header-line-format 'xwidget-webkit--title) ;; Keep track of [vh]scroll when switching buffers (image-mode-setup-winprops)) @@ -626,6 +702,29 @@ xwidget-webkit-new-session (xwidget-webkit-mode) (xwidget-webkit-goto-uri (xwidget-webkit-last-session) url))) +(defun xwidget-webkit-import-widget (xwidget) + "Create a new webkit session buffer from XWIDGET, an existing xwidget. +Return the buffer." + (let* ((bufname (generate-new-buffer-name "*xwidget-webkit*")) + (callback #'xwidget-webkit-callback) + (buffer (get-buffer-create bufname))) + (with-current-buffer buffer + (save-excursion + (erase-buffer) + (insert ".") + (put-text-property (point-min) (point-max) + 'display (list 'xwidget :xwidget xwidget))) + (xwidget-put xwidget 'callback callback) + (set-xwidget-buffer xwidget buffer) + (xwidget-webkit-mode)) + buffer)) + +(defun xwidget-webkit-display-event (event) + "Import the xwidget inside EVENT and display it." + (interactive "e") + (display-buffer (xwidget-webkit-import-widget (nth 1 event)))) + +(global-set-key [xwidget-display-event] 'xwidget-webkit-display-event) (defun xwidget-webkit-goto-url (url) "Goto URL with xwidget webkit." @@ -684,6 +783,158 @@ xwidget-put (set-xwidget-plist xwidget (plist-put (xwidget-plist xwidget) propname value))) +(defvar xwidget-webkit-edit-mode-map (make-keymap)) + +(define-key xwidget-webkit-edit-mode-map [backspace] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [tab] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [left] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [right] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [up] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [down] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [return] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-left] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-right] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-up] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-down] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-return] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-left] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-right] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-up] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-down] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-return] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-left] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-right] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-up] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-down] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-return] 'xwidget-webkit-pass-command-event) + +(define-minor-mode xwidget-webkit-edit-mode + "Minor mode for editing the content of WebKit buffers. + +This defines most self-inserting characters and some common +keyboard shortcuts to `xwidget-webkit-pass-command-event', which +will pass the key events corresponding to these characters to the +WebKit widget." + :keymap xwidget-webkit-edit-mode-map) + +(substitute-key-definition 'self-insert-command + 'xwidget-webkit-pass-command-event + xwidget-webkit-edit-mode-map + global-map) + +(declare-function xwidget-webkit-search "xwidget.c") +(declare-function xwidget-webkit-next-result "xwidget.c") +(declare-function xwidget-webkit-previous-result "xwidget.c") +(declare-function xwidget-webkit-finish-search "xwidget.c") + +(defvar-local xwidget-webkit-isearch--string "" + "The current search query.") +(defvar-local xwidget-webkit-isearch--is-reverse nil + "Whether or not the current isearch should be reverse.") + +(defun xwidget-webkit-isearch--update () + "Update the current buffer's WebKit widget's search query. +The query will be set to the contents of `xwidget-webkit-isearch--string'." + (xwidget-webkit-search xwidget-webkit-isearch--string + (xwidget-webkit-current-session) + t xwidget-webkit-isearch--is-reverse t) + (message "Search contents: %s" xwidget-webkit-isearch--string)) + +(defun xwidget-webkit-isearch-erasing-char (count) + "Erase the last COUNT characters of the current query." + (interactive (list (prefix-numeric-value current-prefix-arg))) + (when (> (length xwidget-webkit-isearch--string) 0) + (setq xwidget-webkit-isearch--string + (substring xwidget-webkit-isearch--string 0 + (- (length xwidget-webkit-isearch--string) count)))) + (xwidget-webkit-isearch--update)) + +(defun xwidget-webkit-isearch-printing-char (char &optional count) + "Add ordinary character CHAR to the search string and search. +With argument, add COUNT copies of CHAR." + (interactive (list last-command-event + (prefix-numeric-value current-prefix-arg))) + (setq xwidget-webkit-isearch--string (concat xwidget-webkit-isearch--string + (make-string (or count 1) char))) + (xwidget-webkit-isearch--update)) + +(defun xwidget-webkit-isearch-forward (count) + "Move to the next search result COUNT times." + (interactive (list (prefix-numeric-value current-prefix-arg))) + (let ((was-reverse xwidget-webkit-isearch--is-reverse)) + (setq xwidget-webkit-isearch--is-reverse nil) + (when was-reverse + (xwidget-webkit-isearch--update))) + (let ((i 0)) + (while (< i count) + (xwidget-webkit-next-result (xwidget-webkit-current-session)) + (cl-incf i)))) + +(defun xwidget-webkit-isearch-backward (count) + "Move to the previous search result COUNT times." + (interactive (list (prefix-numeric-value current-prefix-arg))) + (let ((was-reverse xwidget-webkit-isearch--is-reverse)) + (setq xwidget-webkit-isearch--is-reverse t) + (unless was-reverse + (xwidget-webkit-isearch--update))) + (let ((i 0)) + (while (< i count) + (xwidget-webkit-next-result (xwidget-webkit-current-session)) + (cl-incf i)))) + +(defun xwidget-webkit-isearch-exit () + "Exit incremental search of a WebKit buffer." + (interactive) + (xwidget-webkit-isearch-mode 0)) + +(defvar xwidget-webkit-isearch-mode-map (make-keymap) + "The keymap used inside xwidget-webkit-isearch-mode.") + +(set-char-table-range (nth 1 xwidget-webkit-isearch-mode-map) + (cons 0 (max-char)) + 'xwidget-webkit-isearch-exit) + +(substitute-key-definition 'self-insert-command + 'xwidget-webkit-isearch-printing-char + xwidget-webkit-isearch-mode-map + global-map) + +(define-key xwidget-webkit-isearch-mode-map (kbd "DEL") + 'xwidget-webkit-isearch-erasing-char) +(define-key xwidget-webkit-isearch-mode-map [return] 'xwidget-webkit-isearch-exit) +(define-key xwidget-webkit-isearch-mode-map "\r" 'xwidget-webkit-isearch-exit) +(define-key xwidget-webkit-isearch-mode-map "\C-g" 'xwidget-webkit-isearch-exit) +(define-key xwidget-webkit-isearch-mode-map "\C-r" 'xwidget-webkit-isearch-backward) +(define-key xwidget-webkit-isearch-mode-map "\C-s" 'xwidget-webkit-isearch-forward) +(define-key xwidget-webkit-isearch-mode-map "\t" 'xwidget-webkit-isearch-printing-char) + +(let ((meta-map (make-keymap))) + (set-char-table-range (nth 1 meta-map) + (cons 0 (max-char)) + 'xwidget-webkit-isearch-exit) + (define-key xwidget-webkit-isearch-mode-map (char-to-string meta-prefix-char) meta-map)) + +(define-minor-mode xwidget-webkit-isearch-mode + "Minor mode for performing incremental search inside WebKit buffers. + +An attempt was made for this to resemble regular incremental +search, but it suffers from several limitations, such as not +supporting recursive edits. + +If this mode is enabled with `C-r', then the search will default +to being performed in reverse direction. + +To navigate around the search results, type +\\[xwidget-webkit-isearch-forward] to move forward, and +\\[xwidget-webkit-isearch-backward] to move backward. + +Press \\[xwidget-webkit-isearch-exit] to exit incremental search." + :keymap xwidget-webkit-isearch-mode-map + (if xwidget-webkit-isearch-mode + (progn + (setq xwidget-webkit-isearch--string "") + (setq xwidget-webkit-isearch--is-reverse (eq last-command-event ?\C-r))) + (xwidget-webkit-finish-search (xwidget-webkit-current-session)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/src/dispextern.h b/src/dispextern.h index 5b28fe7666..f17f095e0d 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -536,8 +536,8 @@ #define FACE_ID_BITS 20 int img_id; #ifdef HAVE_XWIDGETS - /* Xwidget reference (type == XWIDGET_GLYPH). */ - struct xwidget *xwidget; + /* Xwidget ID. */ + uint32_t xwidget; #endif /* Sub-structure for type == STRETCH_GLYPH. */ diff --git a/src/dispnew.c b/src/dispnew.c index 4a73244c89..632eec2f03 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -4449,16 +4449,6 @@ scrolling_window (struct window *w, int tab_line_p) break; } -#ifdef HAVE_XWIDGETS - /* Currently this seems needed to detect xwidget movement reliably. - This is most probably because an xwidget glyph is represented in - struct glyph's 'union u' by a pointer to a struct, which takes 8 - bytes in 64-bit builds, and thus the comparison of u.val values - done by GLYPH_EQUAL_P doesn't work reliably, since it assumes the - size of the union is 4 bytes. FIXME. */ - return 0; -#endif - /* Can't scroll the display of w32 GUI frames when position of point is indicated by the system caret, because scrolling the display will then "copy" the pixels used by the caret. */ diff --git a/src/keyboard.c b/src/keyboard.c index aa6a4b9e97..c4a5671b10 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -3993,6 +3993,7 @@ kbd_buffer_get_event (KBOARD **kbp, #endif #ifdef HAVE_XWIDGETS case XWIDGET_EVENT: + case XWIDGET_DISPLAY_EVENT: #endif case SAVE_SESSION_EVENT: case NO_EVENT: @@ -4897,7 +4898,7 @@ #define FUNCTION_KEY_OFFSET 0xff00 /* You'll notice that this table is arranged to be conveniently indexed by X Windows keysym values. */ -static const char *const lispy_function_keys[] = +const char *const lispy_function_keys[] = { /* X Keysym value */ @@ -6139,6 +6140,11 @@ make_lispy_event (struct input_event *event) { return Fcons (Qxwidget_event, event->arg); } + + case XWIDGET_DISPLAY_EVENT: + { + return list2 (Qxwidget_display_event, event->arg); + } #endif #ifdef USE_FILE_NOTIFY @@ -11732,6 +11738,7 @@ syms_of_keyboard (void) #ifdef HAVE_XWIDGETS DEFSYM (Qxwidget_event, "xwidget-event"); + DEFSYM (Qxwidget_display_event, "xwidget-display-event"); #endif #ifdef USE_FILE_NOTIFY diff --git a/src/keyboard.h b/src/keyboard.h index 8bdffaa2bf..21c51ec386 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -491,7 +491,7 @@ kbd_buffer_store_event_hold (struct input_event *event, extern struct timespec timer_check (void); extern void mark_kboards (void); -#ifdef HAVE_NTGUI +#if defined HAVE_NTGUI || defined HAVE_X_WINDOWS extern const char *const lispy_function_keys[]; #endif diff --git a/src/print.c b/src/print.c index c13294c8e6..eca389158f 100644 --- a/src/print.c +++ b/src/print.c @@ -1521,8 +1521,20 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag, printchar ('>', printcharfun); break; - case PVEC_XWIDGET: case PVEC_XWIDGET_VIEW: - print_c_string ("#", + XXWIDGET (obj)->xwidget_id, + XXWIDGET (obj)->widget_osr); + strout (buf, len, len, printcharfun); + break; + } +#else + emacs_abort (); +#endif + case PVEC_XWIDGET_VIEW: + print_c_string ("#', printcharfun); break; diff --git a/src/termhooks.h b/src/termhooks.h index 1d3cdc8fe8..e7539bbce2 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -255,6 +255,8 @@ #define EMACS_TERMHOOKS_H #ifdef HAVE_XWIDGETS /* events generated by xwidgets*/ , XWIDGET_EVENT + /* Event generated when WebKit asks us to display another widget. */ + , XWIDGET_DISPLAY_EVENT #endif #ifdef USE_FILE_NOTIFY diff --git a/src/xdisp.c b/src/xdisp.c index 86c4e704d5..d7ad548917 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -28429,7 +28429,7 @@ fill_xwidget_glyph_string (struct glyph_string *s) } s->width = s->first_glyph->pixel_width; s->ybase += s->first_glyph->voffset; - s->xwidget = s->first_glyph->u.xwidget; + s->xwidget = xwidget_from_id (s->first_glyph->u.xwidget); } #endif /* Fill glyph string S from a sequence of stretch glyphs. @@ -29832,7 +29832,7 @@ produce_xwidget_glyph (struct it *it) glyph->padding_p = 0; glyph->glyph_not_available_p = 0; glyph->face_id = it->face_id; - glyph->u.xwidget = it->xwidget; + glyph->u.xwidget = it->xwidget->xwidget_id; glyph->font_type = FONT_TYPE_UNKNOWN; if (it->bidi_p) { diff --git a/src/xterm.c b/src/xterm.c index aa1a1a5eed..9b434bffcc 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -4390,6 +4390,86 @@ x_scroll_run (struct window *w, struct run *run) /* Cursor off. Will be switched on again in gui_update_window_end. */ gui_clear_cursor (w); +#ifdef HAVE_XWIDGETS + /* "Copy" xwidget windows in the area that will be scrolled. */ + Display *dpy = FRAME_X_DISPLAY (f); + Window window = FRAME_X_WINDOW (f); + + Window root, parent, *children; + unsigned int nchildren; + + if (XQueryTree (dpy, window, &root, &parent, &children, &nchildren)) + { + /* Now find xwidget views situated between from_y and to_y, and + attached to w. */ + for (unsigned int i = 0; i < nchildren; ++i) + { + Window child = children[i]; + struct xwidget_view *view = xwidget_view_from_window (child); + + if (view) + { + 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; + XUnmapWindow (dpy, child); + 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, TEXT_AREA, &text_area_x, &text_area_y, + &text_area_width, &text_area_height); + + clip_top = max (0, text_area_y - y); + clip_bottom = max (clip_top, + min (XXWIDGET (view->model)->height, + text_area_y + text_area_height - y)); + + view->y = y; + 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_top - view->clip_bottom) <= 0) + { + view->hidden = true; + XUnmapWindow (dpy, child); + } + else + XMoveResizeWindow (dpy, child, view->x + view->clip_left, + view->y + view->clip_top, + view->clip_right - view->clip_left, + view->clip_top - view->clip_bottom); + XFlush (dpy); + } + } + } + XFree (children); + } +#endif + #ifdef USE_CAIRO if (FRAME_CR_CONTEXT (f)) { @@ -4563,8 +4643,9 @@ x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct fra } } -/* Return the Emacs frame-object corresponding to an X window. - It could be the frame's main window or an icon window. */ +/* Return the Emacs frame-object corresponding to an X window. It + could be the frame's main window, an icon window, or an xwidget + window. */ static struct frame * x_window_to_frame (struct x_display_info *dpyinfo, int wdesc) @@ -4575,6 +4656,13 @@ x_window_to_frame (struct x_display_info *dpyinfo, int wdesc) if (wdesc == None) return NULL; +#ifdef HAVE_XWIDGETS + struct xwidget_view *xvw = xwidget_view_from_window (wdesc); + + if (xvw && xvw->frame) + return xvw->frame; +#endif + FOR_EACH_FRAME (tail, frame) { f = XFRAME (frame); @@ -4997,7 +5085,7 @@ x_x_to_emacs_modifiers (struct x_display_info *dpyinfo, int state) | ((state & dpyinfo->hyper_mod_mask) ? mod_hyper : 0)); } -static int +int x_emacs_to_x_modifiers (struct x_display_info *dpyinfo, intmax_t state) { EMACS_INT mod_ctrl = ctrl_modifier; @@ -8211,6 +8299,18 @@ handle_one_xevent (struct x_display_info *dpyinfo, case Expose: f = x_window_to_frame (dpyinfo, event->xexpose.window); +#ifdef HAVE_XWIDGETS + { + struct xwidget_view *xv = + xwidget_view_from_window (event->xexpose.window); + + if (xv) + { + xwidget_expose (xv); + goto OTHER; + } + } +#endif if (f) { if (!FRAME_VISIBLE_P (f)) @@ -8791,6 +8891,31 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_display_set_last_user_time (dpyinfo, event->xcrossing.time); x_detect_focus_change (dpyinfo, any, event, &inev.ie); +#ifdef HAVE_XWIDGETS + { + struct xwidget_view *xvw = xwidget_view_from_window (event->xcrossing.window); + Mouse_HLInfo *hlinfo; + + if (xvw) + { + xwidget_motion_or_crossing (xvw, event); + hlinfo = MOUSE_HL_INFO (xvw->frame); + + if (xvw->frame == hlinfo->mouse_face_mouse_frame) + { + clear_mouse_face (hlinfo); + hlinfo->mouse_face_mouse_frame = 0; + } + + if (any_help_event_p) + { + do_help = -1; + } + goto OTHER; + } + } +#endif + f = any; if (f && x_mouse_click_focus_ignore_position) @@ -8834,6 +8959,17 @@ handle_one_xevent (struct x_display_info *dpyinfo, goto OTHER; case LeaveNotify: +#ifdef HAVE_XWIDGETS + { + struct xwidget_view *xvw = xwidget_view_from_window (event->xcrossing.window); + + if (xvw) + { + xwidget_motion_or_crossing (xvw, event); + goto OTHER; + } + } +#endif x_display_set_last_user_time (dpyinfo, event->xcrossing.time); x_detect_focus_change (dpyinfo, any, event, &inev.ie); @@ -8883,6 +9019,12 @@ handle_one_xevent (struct x_display_info *dpyinfo, #ifdef USE_GTK if (f && xg_event_is_for_scrollbar (f, event)) f = 0; +#endif +#ifdef HAVE_XWIDGETS + struct xwidget_view *xvw = xwidget_view_from_window (event->xmotion.window); + + if (xvw) + xwidget_motion_or_crossing (xvw, event); #endif if (f) { @@ -9138,6 +9280,24 @@ handle_one_xevent (struct x_display_info *dpyinfo, case ButtonRelease: case ButtonPress: { +#ifdef HAVE_XWIDGETS + struct xwidget_view *xvw = xwidget_view_from_window (event->xmotion.window); + + if (xvw) + { + xwidget_button (xvw, event->type == ButtonPress, + event->xbutton.x, event->xbutton.y, + event->xbutton.button, event->xbutton.state, + event->xbutton.time); + + if (!EQ (selected_window, xvw->w)) + { + inev.ie.kind = SELECT_WINDOW_EVENT; + inev.ie.frame_or_window = xvw->w; + } + goto OTHER; + } +#endif /* If we decide we want to generate an event to be seen by the rest of Emacs, we put it here. */ Lisp_Object tab_bar_arg = Qnil; @@ -12108,6 +12268,10 @@ x_free_frame_resources (struct frame *f) xfree (f->shell_position); #else /* !USE_X_TOOLKIT */ +#ifdef HAVE_XWIDGETS + kill_frame_xwidget_views (f); +#endif + #ifdef USE_GTK xg_free_frame_widgets (f); #endif /* USE_GTK */ diff --git a/src/xterm.h b/src/xterm.h index de6ea50385..9d9534dd62 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -1108,6 +1108,7 @@ #define SELECTION_EVENT_TIME(eventp) \ extern int x_dispatch_event (XEvent *, Display *); #endif extern int x_x_to_emacs_modifiers (struct x_display_info *, int); +extern int x_emacs_to_x_modifiers (struct x_display_info *, intmax_t); #ifdef USE_CAIRO extern void x_cr_destroy_frame_context (struct frame *); extern void x_cr_update_surface_desired_size (struct frame *, int, int); diff --git a/src/xwidget.c b/src/xwidget.c index e4b42e6e0c..bf69f262fb 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -19,6 +19,7 @@ Copyright (C) 2011-2021 Free Software Foundation, Inc. #include +#include "buffer.h" #include "xwidget.h" #include "lisp.h" @@ -35,10 +36,22 @@ Copyright (C) 2011-2021 Free Software Foundation, Inc. #ifdef USE_GTK #include #include +#include +#include #elif defined NS_IMPL_COCOA #include "nsxwidget.h" #endif +static Lisp_Object id_to_xwidget_map; +static uint32_t xwidget_counter = 0; + +#ifdef USE_GTK +static Lisp_Object x_window_to_xwv_map; +static gboolean offscreen_damage_event (GtkWidget *, GdkEvent *, gpointer); +static void synthesize_focus_in_event (GtkWidget *); +static GdkDevice *find_suitable_keyboard (struct frame *); +#endif + static struct xwidget * allocate_xwidget (void) { @@ -64,18 +77,32 @@ #define XSETXWIDGET_VIEW(a, b) XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW) GAsyncResult *, gpointer); static gboolean webkit_download_cb (WebKitWebContext *, WebKitDownload *, gpointer); - +static GtkWidget *webkit_create_cb (WebKitWebView *, WebKitNavigationAction *, gpointer); static gboolean webkit_decide_policy_cb (WebKitWebView *, WebKitPolicyDecision *, WebKitPolicyDecisionType, gpointer); +static GtkWidget *find_widget_at_pos (GtkWidget *, int, int, int *, int *); + +struct widget_search_data +{ + int x; + int y; + bool foundp; + bool first; + GtkWidget *data; +}; + +static void find_widget (GtkWidget *t, struct widget_search_data *); +static void mouse_target_changed (WebKitWebView *, WebKitHitTestResult *, guint, + gpointer); #endif DEFUN ("make-xwidget", Fmake_xwidget, Smake_xwidget, - 5, 6, 0, + 5, 7, 0, doc: /* Make an xwidget of TYPE. If BUFFER is nil, use the current buffer. If BUFFER is a string and no such buffer exists, create it. @@ -83,10 +110,12 @@ DEFUN ("make-xwidget", - webkit -Returns the newly constructed xwidget, or nil if construction fails. */) +RELATED is nil, or an xwidget. This argument is used internally. +Returns the newly constructed xwidget, or nil if construction +fails. */) (Lisp_Object type, Lisp_Object title, Lisp_Object width, Lisp_Object height, - Lisp_Object arguments, Lisp_Object buffer) + Lisp_Object arguments, Lisp_Object buffer, Lisp_Object related) { #ifdef USE_GTK if (!xg_gtk_initialized) @@ -108,13 +137,19 @@ DEFUN ("make-xwidget", XSETXWIDGET (val, xw); Vxwidget_list = Fcons (val, Vxwidget_list); xw->plist = Qnil; + xw->xwidget_id = ++xwidget_counter; + + Fputhash (make_fixnum (xw->xwidget_id), val, id_to_xwidget_map); #ifdef USE_GTK xw->widgetwindow_osr = NULL; xw->widget_osr = NULL; + xw->hit_result = 0; + xw->find_text = NULL; if (EQ (xw->type, Qwebkit)) { block_input (); + WebKitSettings *settings; WebKitWebContext *webkit_context = webkit_web_context_get_default (); # if WEBKIT_CHECK_VERSION (2, 26, 0) @@ -128,18 +163,33 @@ DEFUN ("make-xwidget", if (EQ (xw->type, Qwebkit)) { - xw->widget_osr = webkit_web_view_new (); - - /* webkitgtk uses GSubprocess which sets sigaction causing - Emacs to not catch SIGCHLD with its usual handle setup in - catch_child_signal(). This resets the SIGCHLD - sigaction. */ - struct sigaction old_action; - sigaction (SIGCHLD, NULL, &old_action); - webkit_web_view_load_uri(WEBKIT_WEB_VIEW (xw->widget_osr), - "about:blank"); - sigaction (SIGCHLD, &old_action, NULL); - } + WebKitWebView *related_view; + + if (NILP (related) + || !XWIDGETP (related) + || !EQ (XXWIDGET (related)->type, Qwebkit)) + { + /* Enable the developer extras */ + settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (xw->widget_osr)); + g_object_set (G_OBJECT (settings), "enable-developer-extras", TRUE, NULL); + xw->widget_osr = webkit_web_view_new (); + + /* webkitgtk uses GSubprocess which sets sigaction causing + Emacs to not catch SIGCHLD with its usual handle setup in + catch_child_signal(). This resets the SIGCHLD + sigaction. */ + struct sigaction old_action; + sigaction (SIGCHLD, NULL, &old_action); + webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr), + "about:blank"); + sigaction (SIGCHLD, &old_action, NULL); + } + else + { + related_view = WEBKIT_WEB_VIEW (XXWIDGET (related)->widget_osr); + xw->widget_osr = webkit_web_view_new_with_related_view (related_view); + } + } gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height); @@ -157,6 +207,7 @@ DEFUN ("make-xwidget", gtk_widget_show (xw->widget_osr); gtk_widget_show (xw->widgetwindow_osr); + synthesize_focus_in_event (xw->widgetwindow_osr); /* Store some xwidget data in the gtk widgets for convenient retrieval in the event handlers. */ @@ -179,8 +230,20 @@ DEFUN ("make-xwidget", G_CALLBACK (webkit_decide_policy_cb), xw); + + g_signal_connect (G_OBJECT (xw->widget_osr), + "mouse-target-changed", + G_CALLBACK (mouse_target_changed), + xw); + g_signal_connect (G_OBJECT (xw->widget_osr), + "create", + G_CALLBACK (webkit_create_cb), + xw); } + g_signal_connect (G_OBJECT (xw->widgetwindow_osr), "damage-event", + G_CALLBACK (offscreen_damage_event), xw); + unblock_input (); } #elif defined NS_IMPL_COCOA @@ -190,6 +253,158 @@ DEFUN ("make-xwidget", return val; } +#ifdef USE_GTK +static void +set_widget_if_text_view (GtkWidget *widget, void *data) +{ + GtkWidget **pointer = data; + + if (GTK_IS_TEXT_VIEW (widget)) + { + *pointer = widget; + } +} +#endif + +DEFUN ("xwidget-perform-lispy-event", + Fxwidget_perform_lispy_event, Sxwidget_perform_lispy_event, + 2, 3, 0, doc: /* Send a lispy event to XWIDGET. +EVENT should be the event that will be sent. FRAME should be the +frame which generated the event, or nil. On X11, modifier keys will +not be processed if FRAME is nil and the selected frame is not an +X-Windows frame. */) + (Lisp_Object xwidget, Lisp_Object event, Lisp_Object frame) +{ + struct xwidget *xw; + struct frame *f = NULL; + int character = -1, keycode = -1; + int modifiers = 0; + +#ifdef USE_GTK + GdkEvent *xg_event; + GtkContainerClass *klass; + GtkWidget *widget; + GtkWidget *temp = NULL; +#endif + + CHECK_XWIDGET (xwidget); + xw = XXWIDGET (xwidget); + + if (!NILP (frame)) + f = decode_window_system_frame (frame); + else if (FRAME_X_P (SELECTED_FRAME ())) + f = SELECTED_FRAME (); + +#ifdef USE_GTK + widget = gtk_window_get_focus (GTK_WINDOW (xw->widgetwindow_osr)); + + if (!widget) + widget = xw->widget_osr; + + if (RANGED_FIXNUMP (0, event, INT_MAX)) + { + character = XFIXNUM (event); + + if (character < 32) + modifiers |= ctrl_modifier; + + modifiers |= character & meta_modifier; + modifiers |= character & hyper_modifier; + modifiers |= character & super_modifier; + modifiers |= character & shift_modifier; + modifiers |= character & ctrl_modifier; + + character = character & ~(1 << 21); + + if (character < 32) + character += '_'; + + if (f) + modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f), modifiers); + else + modifiers = 0; + } + else if (SYMBOLP (event)) + { + Lisp_Object decoded = parse_modifiers (event); + Lisp_Object decoded_name = SYMBOL_NAME (XCAR (decoded)); + + int off = 0; + bool found = false; + + while (off < 256) + { + if (lispy_function_keys[off] + && !strcmp (lispy_function_keys[off], + SSDATA (decoded_name))) + { + found = true; + break; + } + ++off; + } + + if (f) + modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f), + XFIXNUM (XCAR (XCDR (decoded)))); + else + modifiers = 0; + + if (found) + keycode = off + 0xff00; + } + + if (character == -1 && keycode == -1) + return Qnil; + + block_input (); + xg_event = gdk_event_new (GDK_KEY_PRESS); + xg_event->any.window = gtk_widget_get_window (xw->widget_osr); + g_object_ref (xg_event->any.window); + + if (character > -1) + keycode = gdk_unicode_to_keyval (character); + + xg_event->key.keyval = keycode; + xg_event->key.state = modifiers; + + if (keycode > -1) + { + /* WebKitGTK internals abuse follows. */ + if (WEBKIT_IS_WEB_VIEW (widget)) + { + /* WebKitGTK relies on an internal GtkTextView object to + "translate" keys such as backspace. We must find that + widget and activate its binding to this key if any. */ + klass = GTK_CONTAINER_CLASS (G_OBJECT_GET_CLASS (widget)); + + klass->forall (GTK_CONTAINER (xw->widget_osr), TRUE, + set_widget_if_text_view, &temp); + + if (GTK_IS_WIDGET (temp)) + { + if (!gtk_widget_get_realized (temp)) + gtk_widget_realize (temp); + + gtk_bindings_activate (G_OBJECT (temp), keycode, modifiers); + } + } + } + + if (f) + gdk_event_set_device (xg_event, + find_suitable_keyboard (SELECTED_FRAME ())); + + gtk_main_do_event (xg_event); + xg_event->type = GDK_KEY_RELEASE; + gtk_main_do_event (xg_event); + gdk_event_free (xg_event); + unblock_input (); +#endif + + return Qnil; +} + DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets, Sget_buffer_xwidgets, 1, 1, 0, doc: /* Return a list of xwidgets associated with BUFFER. @@ -221,16 +436,397 @@ xwidget_hidden (struct xwidget_view *xv) return xv->hidden; } +struct xwidget * +xwidget_from_id (uint32_t id) +{ + Lisp_Object key = make_fixnum (id); + Lisp_Object xwidget = Fgethash (key, id_to_xwidget_map, Qnil); + + if (NILP (xwidget)) + emacs_abort (); + + return XXWIDGET (xwidget); +} + #ifdef USE_GTK + +static GdkDevice * +find_suitable_pointer (struct frame *f) +{ + GdkSeat *seat = gdk_display_get_default_seat + (gtk_widget_get_display (FRAME_GTK_WIDGET (f))); + + if (!seat) + return NULL; + + return gdk_seat_get_pointer (seat); +} + +static GdkDevice * +find_suitable_keyboard (struct frame *f) +{ + GdkSeat *seat = gdk_display_get_default_seat + (gtk_widget_get_display (FRAME_GTK_WIDGET (f))); + + if (!seat) + return NULL; + + return gdk_seat_get_keyboard (seat); +} + +static void +find_widget_cb (GtkWidget *widget, void *user) +{ + find_widget (widget, user); +} + +static void +find_widget (GtkWidget *widget, + struct widget_search_data *data) +{ + GtkAllocation new_allocation; + GdkWindow *window; + int x_offset = 0; + int y_offset = 0; + + gtk_widget_get_allocation (widget, &new_allocation); + + if (gtk_widget_get_has_window (widget)) + { + new_allocation.x = 0; + new_allocation.y = 0; + } + + if (gtk_widget_get_parent (widget) && !data->first) + { + window = gtk_widget_get_window (widget); + while (window != gtk_widget_get_window (gtk_widget_get_parent (widget))) + { + gint tx, ty, twidth, theight; + + if (!window) + return; + + twidth = gdk_window_get_width (window); + theight = gdk_window_get_height (window); + + if (new_allocation.x < 0) + { + new_allocation.width += new_allocation.x; + new_allocation.x = 0; + } + + if (new_allocation.y < 0) + { + new_allocation.height += new_allocation.y; + new_allocation.y = 0; + } + + if (new_allocation.x + new_allocation.width > twidth) + new_allocation.width = twidth - new_allocation.x; + if (new_allocation.y + new_allocation.height > theight) + new_allocation.height = theight - new_allocation.y; + + gdk_window_get_position (window, &tx, &ty); + new_allocation.x += tx; + x_offset += tx; + new_allocation.y += ty; + y_offset += ty; + + window = gdk_window_get_parent (window); + } + } + + if ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) && + (data->x < new_allocation.x + new_allocation.width) && + (data->y < new_allocation.y + new_allocation.height)) + { + /* First, check if the drag is in a valid drop site in + * one of our children + */ + if (GTK_IS_CONTAINER (widget)) + { + struct widget_search_data new_data = *data; + + new_data.x -= x_offset; + new_data.y -= y_offset; + new_data.foundp = false; + new_data.first = false; + + gtk_container_forall (GTK_CONTAINER (widget), + find_widget_cb, &new_data); + + data->foundp = new_data.foundp; + if (data->foundp) + data->data = new_data.data; + } + + /* If not, and this widget is registered as a drop site, check to + * emit "drag_motion" to check if we are actually in + * a drop site. + */ + if (!data->foundp) + { + data->foundp = true; + data->data = widget; + } + } +} + +static GtkWidget * +find_widget_at_pos (GtkWidget *w, int x, int y, + int *new_x, int *new_y) +{ + struct widget_search_data data; + + data.x = x; + data.y = y; + data.foundp = false; + data.first = true; + + find_widget (w, &data); + + if (data.foundp) + { + gtk_widget_translate_coordinates (w, data.data, x, + y, new_x, new_y); + return data.data; + } + + *new_x = x; + *new_y = y; + + return NULL; +} + +static Emacs_Cursor +cursor_for_hit (guint result, struct frame *frame) +{ + Emacs_Cursor cursor = FRAME_OUTPUT_DATA (frame)->nontext_cursor; + + if ((result & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE) + || (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION) + || (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT)) + cursor = FRAME_X_OUTPUT (frame)->text_cursor; + + if (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR) + cursor = FRAME_X_OUTPUT (frame)->vertical_drag_cursor; + + if (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK) + cursor = FRAME_X_OUTPUT (frame)->hand_cursor; + + return cursor; +} + +static void +define_cursors (struct xwidget *xw, WebKitHitTestResult *res) +{ + struct xwidget_view *xvw; + + xw->hit_result = webkit_hit_test_result_get_context (res); + + for (Lisp_Object tem = Vxwidget_view_list; CONSP (tem); + tem = XCDR (tem)) + { + if (XWIDGET_VIEW_P (XCAR (tem))) + { + xvw = XXWIDGET_VIEW (XCAR (tem)); + + if (XXWIDGET (xvw->model) == xw) + { + xvw->cursor = cursor_for_hit (xw->hit_result, xvw->frame); + if (xvw->wdesc != None) + XDefineCursor (xvw->dpy, xvw->wdesc, xvw->cursor); + } + } + } +} + +static void +mouse_target_changed (WebKitWebView *webview, + WebKitHitTestResult *hitresult, + guint modifiers, gpointer xw) +{ + define_cursors (xw, hitresult); +} + + +static void +xwidget_button_1 (struct xwidget_view *view, + bool down_p, int x, int y, int button, + int modifier_state, Time time) +{ + GdkEvent *xg_event = gdk_event_new (down_p ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE); + struct xwidget *model = XXWIDGET (view->model); + GtkWidget *target; + + /* X and Y should be relative to the origin of view->wdesc. */ + x += view->clip_left; + y += view->clip_top; + + target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y); + + if (!target) + target = model->widget_osr; + + xg_event->any.window = gtk_widget_get_window (target); + g_object_ref (xg_event->any.window); /* The window will be unrefed + later by gdk_event_free. */ + + xg_event->button.x = x; + xg_event->button.x_root = x; + xg_event->button.y = y; + xg_event->button.y_root = y; + xg_event->button.button = button; + xg_event->button.state = modifier_state; + xg_event->button.time = time; + xg_event->button.device = find_suitable_pointer (view->frame); + + gtk_main_do_event (xg_event); + gdk_event_free (xg_event); +} + +void +xwidget_button (struct xwidget_view *view, + bool down_p, int x, int y, int button, + int modifier_state, Time time) +{ + if (button < 4 || button > 8) + xwidget_button_1 (view, down_p, x, y, button, modifier_state, time); + else + { + GdkEvent *xg_event = gdk_event_new (GDK_SCROLL); + struct xwidget *model = XXWIDGET (view->model); + GtkWidget *target; + + x += view->clip_left; + y += view->clip_top; + + target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y); + + if (!target) + target = model->widget_osr; + + xg_event->any.window = gtk_widget_get_window (target); + g_object_ref (xg_event->any.window); /* The window will be unrefed + later by gdk_event_free. */ + if (button == 4) + xg_event->scroll.direction = GDK_SCROLL_UP; + else if (button == 5) + xg_event->scroll.direction = GDK_SCROLL_DOWN; + else if (button == 6) + xg_event->scroll.direction = GDK_SCROLL_LEFT; + else + xg_event->scroll.direction = GDK_SCROLL_RIGHT; + + xg_event->scroll.device = find_suitable_pointer (view->frame); + + xg_event->scroll.x = x; + xg_event->scroll.x_root = x; + xg_event->scroll.y = y; + xg_event->scroll.y_root = y; + xg_event->scroll.state = modifier_state; + xg_event->scroll.time = time; + + xg_event->scroll.delta_x = 0; + xg_event->scroll.delta_y = 0; + + gtk_main_do_event (xg_event); + gdk_event_free (xg_event); + } +} + +void +xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event) +{ + GdkEvent *xg_event = gdk_event_new (event->type == MotionNotify ? GDK_MOTION_NOTIFY : + (event->type == LeaveNotify ? GDK_LEAVE_NOTIFY : + GDK_ENTER_NOTIFY)); + struct xwidget *model = XXWIDGET (view->model); + int x; + int y; + GtkWidget *target = find_widget_at_pos (model->widgetwindow_osr, + (event->type == MotionNotify + ? event->xmotion.x + view->clip_left + : event->xmotion.y + view->clip_top), + (event->type == MotionNotify + ? event->xmotion.y + view->clip_left + : event->xcrossing.y + view->clip_top), + &x, &y); + + if (!target) + target = model->widgetwindow_osr; + + xg_event->any.window = gtk_widget_get_window (target); + g_object_ref (xg_event->any.window); /* The window will be unrefed + later by gdk_event_free. */ + + if (event->type == MotionNotify) + { + xg_event->motion.x = x; + xg_event->motion.y = y; + xg_event->motion.x_root = event->xmotion.x_root; + xg_event->motion.y_root = event->xmotion.y_root; + xg_event->motion.time = event->xmotion.time; + xg_event->motion.state = event->xmotion.state; + xg_event->motion.device = find_suitable_pointer (view->frame); + } + else + { + xg_event->crossing.detail = min (5, event->xcrossing.detail); + xg_event->crossing.time = event->xcrossing.time; + xg_event->crossing.x = x; + xg_event->crossing.y = y; + xg_event->crossing.x_root = event->xcrossing.x_root; + xg_event->crossing.y_root = event->xcrossing.y_root; + gdk_event_set_device (xg_event, find_suitable_pointer (view->frame)); + } + + gtk_main_do_event (xg_event); + gdk_event_free (xg_event); +} + +static void +synthesize_focus_in_event (GtkWidget *offscreen_window) +{ + GdkWindow *wnd; + GdkEvent *focus_event; + + if (!gtk_widget_get_realized (offscreen_window)) + gtk_widget_realize (offscreen_window); + + wnd = gtk_widget_get_window (offscreen_window); + + focus_event = gdk_event_new (GDK_FOCUS_CHANGE); + focus_event->any.window = wnd; + focus_event->focus_change.in = TRUE; + g_object_ref (wnd); + + gtk_main_do_event (focus_event); + gdk_event_free (focus_event); +} + +struct xwidget_view * +xwidget_view_from_window (Window wdesc) +{ + Lisp_Object key = make_fixnum (wdesc); + Lisp_Object xwv = Fgethash (key, x_window_to_xwv_map, Qnil); + + if (NILP (xwv)) + return NULL; + + return XXWIDGET_VIEW (xwv); +} + static void xwidget_show_view (struct xwidget_view *xv) { xv->hidden = false; - gtk_widget_show (xv->widgetwindow); - gtk_fixed_move (GTK_FIXED (xv->emacswindow), - xv->widgetwindow, - xv->x + xv->clip_left, - xv->y + xv->clip_top); + XMoveWindow (xv->dpy, xv->wdesc, + xv->x + xv->clip_left, + xv->y + xv->clip_top); + XMapWindow (xv->dpy, xv->wdesc); + XFlush (xv->dpy); } /* Hide an xwidget view. */ @@ -238,28 +834,64 @@ xwidget_show_view (struct xwidget_view *xv) xwidget_hide_view (struct xwidget_view *xv) { xv->hidden = true; - gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow, - 10000, 10000); + XUnmapWindow (xv->dpy, xv->wdesc); + XFlush (xv->dpy); +} + +static void +xv_do_draw (struct xwidget_view *xw, struct xwidget *w) +{ + GtkOffscreenWindow *wnd; + cairo_surface_t *surface; + block_input (); + wnd = GTK_OFFSCREEN_WINDOW (w->widgetwindow_osr); + surface = gtk_offscreen_window_get_surface (wnd); + + cairo_save (xw->cr_context); + if (surface) + { + cairo_set_source_surface (xw->cr_context, surface, xw->clip_left, + xw->clip_top); + cairo_set_operator (xw->cr_context, CAIRO_OPERATOR_SOURCE); + cairo_paint (xw->cr_context); + } + cairo_restore (xw->cr_context); + + unblock_input (); } /* When the off-screen webkit master view changes this signal is called. It copies the bitmap from the off-screen instance. */ static gboolean offscreen_damage_event (GtkWidget *widget, GdkEvent *event, - gpointer xv_widget) -{ - /* Queue a redraw of onscreen widget. - There is a guard against receiving an invalid widget, - which should only happen if we failed to remove the - specific signal handler for the damage event. */ - if (GTK_IS_WIDGET (xv_widget)) - gtk_widget_queue_draw (GTK_WIDGET (xv_widget)); - else - message ("Warning, offscreen_damage_event received invalid xv pointer:%p\n", - xv_widget); + gpointer xwidget) +{ + block_input (); + + for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); + tail = XCDR (tail)) + { + if (XWIDGET_VIEW_P (XCAR (tail))) + { + struct xwidget_view *view = XXWIDGET_VIEW (XCAR (tail)); + + if (view->wdesc && XXWIDGET (view->model) == xwidget) + xv_do_draw (view, XXWIDGET (view->model)); + } + } + + unblock_input (); return FALSE; } + +void +xwidget_expose (struct xwidget_view *xv) +{ + struct xwidget *xw = XXWIDGET (xv->model); + + xv_do_draw (xv, xw); +} #endif /* USE_GTK */ void @@ -313,22 +945,108 @@ store_xwidget_js_callback_event (struct xwidget *xw, #ifdef USE_GTK +static void +store_xwidget_display_event (struct xwidget *xw) +{ + struct input_event evt; + Lisp_Object val; + + XSETXWIDGET (val, xw); + EVENT_INIT (evt); + evt.kind = XWIDGET_DISPLAY_EVENT; + evt.frame_or_window = Qnil; + evt.arg = val; + kbd_buffer_store_event (&evt); +} + +static void +webkit_ready_to_show (WebKitWebView *new_view, + gpointer user_data) +{ + Lisp_Object tem; + struct xwidget *xw; + + for (tem = Vxwidget_list; CONSP (tem); tem = XCDR (tem)) + { + if (XWIDGETP (XCAR (tem))) + { + xw = XXWIDGET (XCAR (tem)); + + if (EQ (xw->type, Qwebkit) + && WEBKIT_WEB_VIEW (xw->widget_osr) == new_view) + store_xwidget_display_event (xw); + } + } +} + +static GtkWidget * +webkit_create_cb_1 (WebKitWebView *webview, + struct xwidget_view *xv) +{ + Lisp_Object related; + Lisp_Object xwidget; + GtkWidget *widget; + + XSETXWIDGET (related, xv); + xwidget = Fmake_xwidget (Qwebkit, Qnil, make_fixnum (0), + make_fixnum (0), Qnil, + build_string (" *detached xwidget buffer*"), + related); + + if (NILP (xwidget)) + return NULL; + + widget = XXWIDGET (xwidget)->widget_osr; + + g_signal_connect (G_OBJECT (widget), "ready-to-show", + G_CALLBACK (webkit_ready_to_show), NULL); + + return widget; +} + +static GtkWidget * +webkit_create_cb (WebKitWebView *webview, + WebKitNavigationAction *nav_action, + gpointer user_data) +{ + switch (webkit_navigation_action_get_navigation_type (nav_action)) + { + case WEBKIT_NAVIGATION_TYPE_OTHER: + return webkit_create_cb_1 (webview, user_data); + + case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD: + case WEBKIT_NAVIGATION_TYPE_RELOAD: + case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED: + case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED: + case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED: + default: + return NULL; + } +} + void webkit_view_load_changed_cb (WebKitWebView *webkitwebview, WebKitLoadEvent load_event, gpointer data) { - switch (load_event) { - case WEBKIT_LOAD_FINISHED: + struct xwidget *xw = g_object_get_data (G_OBJECT (webkitwebview), + XG_XWIDGET); + + switch (load_event) { - struct xwidget *xw = g_object_get_data (G_OBJECT (webkitwebview), - XG_XWIDGET); - store_xwidget_event_string (xw, "load-changed", ""); + case WEBKIT_LOAD_FINISHED: + store_xwidget_event_string (xw, "load-changed", "load-finished"); + break; + case WEBKIT_LOAD_STARTED: + store_xwidget_event_string (xw, "load-changed", "load-started"); + break; + case WEBKIT_LOAD_REDIRECTED: + store_xwidget_event_string (xw, "load-changed", "load-redirected"); + break; + case WEBKIT_LOAD_COMMITTED: + store_xwidget_event_string (xw, "load-changed", "load-committed"); break; } - default: - break; - } } /* Recursively convert a JavaScript value to a Lisp value. */ @@ -498,51 +1216,6 @@ webkit_decide_policy_cb (WebKitWebView *webView, return FALSE; } } - - -/* For gtk3 offscreen rendered widgets. */ -static gboolean -xwidget_osr_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data) -{ - struct xwidget *xw = g_object_get_data (G_OBJECT (widget), XG_XWIDGET); - struct xwidget_view *xv = g_object_get_data (G_OBJECT (widget), - XG_XWIDGET_VIEW); - - cairo_rectangle (cr, 0, 0, xv->clip_right, xv->clip_bottom); - cairo_clip (cr); - - gtk_widget_draw (xw->widget_osr, cr); - return FALSE; -} - -static gboolean -xwidget_osr_event_forward (GtkWidget *widget, GdkEvent *event, - gpointer user_data) -{ - /* Copy events that arrive at the outer widget to the offscreen widget. */ - struct xwidget *xw = g_object_get_data (G_OBJECT (widget), XG_XWIDGET); - GdkEvent *eventcopy = gdk_event_copy (event); - eventcopy->any.window = gtk_widget_get_window (xw->widget_osr); - - /* TODO: This might leak events. They should be deallocated later, - perhaps in xwgir_event_cb. */ - gtk_main_do_event (eventcopy); - - /* Don't propagate this event further. */ - return TRUE; -} - -static gboolean -xwidget_osr_event_set_embedder (GtkWidget *widget, GdkEvent *event, - gpointer data) -{ - struct xwidget_view *xv = data; - struct xwidget *xww = XXWIDGET (xv->model); - gdk_offscreen_window_set_embedder (gtk_widget_get_window - (xww->widgetwindow_osr), - gtk_widget_get_window (xv->widget)); - return FALSE; -} #endif /* USE_GTK */ @@ -568,63 +1241,19 @@ xwidget_init_view (struct xwidget *xww, XSETXWIDGET (xv->model, xww); #ifdef USE_GTK - if (EQ (xww->type, Qwebkit)) - { - xv->widget = gtk_drawing_area_new (); - /* Expose event handling. */ - gtk_widget_set_app_paintable (xv->widget, TRUE); - gtk_widget_add_events (xv->widget, GDK_ALL_EVENTS_MASK); - - /* Draw the view on damage-event. */ - g_signal_connect (G_OBJECT (xww->widgetwindow_osr), "damage-event", - G_CALLBACK (offscreen_damage_event), xv->widget); - - if (EQ (xww->type, Qwebkit)) - { - g_signal_connect (G_OBJECT (xv->widget), "button-press-event", - G_CALLBACK (xwidget_osr_event_forward), NULL); - g_signal_connect (G_OBJECT (xv->widget), "button-release-event", - G_CALLBACK (xwidget_osr_event_forward), NULL); - g_signal_connect (G_OBJECT (xv->widget), "motion-notify-event", - G_CALLBACK (xwidget_osr_event_forward), NULL); - } - else - { - /* xwgir debug, orthogonal to forwarding. */ - g_signal_connect (G_OBJECT (xv->widget), "enter-notify-event", - G_CALLBACK (xwidget_osr_event_set_embedder), xv); - } - g_signal_connect (G_OBJECT (xv->widget), "draw", - G_CALLBACK (xwidget_osr_draw_cb), NULL); - } + xv->dpy = FRAME_X_DISPLAY (s->f); - /* Widget realization. - - Make container widget first, and put the actual widget inside the - container later. Drawing should crop container window if necessary - to handle case where xwidget is partially obscured by other Emacs - windows. Other containers than gtk_fixed where explored, but - gtk_fixed had the most predictable behavior so far. */ - - xv->emacswindow = FRAME_GTK_WIDGET (s->f); - xv->widgetwindow = gtk_fixed_new (); - gtk_widget_set_has_window (xv->widgetwindow, TRUE); - gtk_container_add (GTK_CONTAINER (xv->widgetwindow), xv->widget); - - /* Store some xwidget data in the gtk widgets. */ - g_object_set_data (G_OBJECT (xv->widget), XG_FRAME_DATA, s->f); - g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET, xww); - g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET_VIEW, xv); - g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET, xww); - g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET_VIEW, xv); - - gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xww->width, - xww->height); - gtk_widget_set_size_request (xv->widgetwindow, xww->width, xww->height); - gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), xv->widgetwindow, x, y); xv->x = x; xv->y = y; - gtk_widget_show_all (xv->widgetwindow); + + xv->clip_left = 0; + xv->clip_right = xww->width; + xv->clip_top = 0; + xv->clip_bottom = xww->height; + + xv->wdesc = None; + xv->frame = s->f; + xv->cursor = cursor_for_hit (xww->hit_result, s->f); #elif defined NS_IMPL_COCOA nsxwidget_init_view (xv, xww, s, x, y); nsxwidget_resize_view(xv, xww->width, xww->height); @@ -681,6 +1310,8 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) window_box (s->w, TEXT_AREA, &text_area_x, &text_area_y, &text_area_width, &text_area_height); + /* On X11, this keeps generating expose events. */ +#ifndef USE_GTK /* Resize xwidget webkit if its container window size is changed in some ways, for example, a buffer became hidden in small split window, then it can appear front in merged whole window. */ @@ -693,6 +1324,7 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) make_int (text_area_width), make_int (text_area_height)); } +#endif clip_left = max (0, text_area_x - x); clip_right = max (clip_left, @@ -711,15 +1343,51 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) later. */ bool moved = (xv->x + xv->clip_left != x + clip_left || xv->y + xv->clip_top != y + clip_top); + +#ifdef USE_GTK + bool wdesc_was_none = xv->wdesc == None; +#endif xv->x = x; xv->y = y; +#ifdef USE_GTK + block_input (); + if (xv->wdesc == None) + { + Lisp_Object xvw; + XSETXWIDGET_VIEW (xvw, xv); + XSetWindowAttributes a; + a.event_mask = (ExposureMask | ButtonPressMask | ButtonReleaseMask + | PointerMotionMask | EnterWindowMask | LeaveWindowMask); + + xv->wdesc = XCreateWindow (xv->dpy, FRAME_X_WINDOW (s->f), + x + clip_left, y + clip_top, + clip_right - clip_left, + clip_bottom - clip_top, 0, + CopyFromParent, CopyFromParent, + CopyFromParent, CWEventMask, &a); + XDefineCursor (xv->dpy, xv->wdesc, xv->cursor); + xv->cr_surface = cairo_xlib_surface_create (xv->dpy, + xv->wdesc, + FRAME_DISPLAY_INFO (s->f)->visual, + clip_right - clip_left, + clip_bottom - clip_top); + xv->cr_context = cairo_create (xv->cr_surface); + Fputhash (make_fixnum (xv->wdesc), xvw, x_window_to_xwv_map); + + moved = false; + } +#endif + /* Has it moved? */ if (moved) { #ifdef USE_GTK - gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), - xv->widgetwindow, x + clip_left, y + clip_top); + 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 NS_IMPL_COCOA nsxwidget_move_view (xv, x + clip_left, y + clip_top); #endif @@ -735,10 +1403,14 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) || xv->clip_top != clip_top || xv->clip_left != clip_left) { #ifdef USE_GTK - gtk_widget_set_size_request (xv->widgetwindow, clip_right - clip_left, - clip_bottom - clip_top); - gtk_fixed_move (GTK_FIXED (xv->widgetwindow), xv->widget, -clip_left, - -clip_top); + if (!wdesc_was_none && !moved) + { + XResizeWindow (xv->dpy, xv->wdesc, 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 NS_IMPL_COCOA nsxwidget_resize_view (xv, clip_right - clip_left, clip_bottom - clip_top); @@ -758,12 +1430,15 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) if (!xwidget_hidden (xv)) { #ifdef USE_GTK - gtk_widget_queue_draw (xv->widgetwindow); - gtk_widget_queue_draw (xv->widget); + gtk_widget_queue_draw (xww->widget_osr); #elif defined NS_IMPL_COCOA nsxwidget_set_needsdisplay (xv); #endif } + +#ifdef USE_GTK + unblock_input (); +#endif } static bool @@ -975,16 +1650,13 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0, struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail)); if (XXWIDGET (xv->model) == xw) { -#ifdef USE_GTK - gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width, - xw->height); -#elif defined NS_IMPL_COCOA - nsxwidget_resize_view(xv, xw->width, xw->height); -#endif + wset_redisplay (XWINDOW (xv->w)); } } } + redisplay (); + return Qnil; } @@ -1084,13 +1756,15 @@ DEFUN ("delete-xwidget-view", CHECK_XWIDGET_VIEW (xwidget_view); struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view); #ifdef USE_GTK - gtk_widget_destroy (xv->widgetwindow); - /* xv->model still has signals pointing to the view. There can be - several views. Find the matching signals and delete them all. */ - g_signal_handlers_disconnect_matched (XXWIDGET (xv->model)->widgetwindow_osr, - G_SIGNAL_MATCH_DATA, - 0, 0, 0, 0, - xv->widget); + if (xv->wdesc != None) + { + block_input (); + cairo_destroy (xv->cr_context); + cairo_surface_destroy (xv->cr_surface); + XDestroyWindow (xv->dpy, xv->wdesc); + Fremhash (make_fixnum (xv->wdesc), x_window_to_xwv_map); + unblock_input (); + } #elif defined NS_IMPL_COCOA nsxwidget_delete_view (xv); #endif @@ -1145,6 +1819,19 @@ DEFUN ("xwidget-buffer", return XXWIDGET (xwidget)->buffer; } +DEFUN ("set-xwidget-buffer", + Fset_xwidget_buffer, Sset_xwidget_buffer, + 2, 2, 0, + doc: /* Set XWIDGET's buffer to BUFFER. */) + (Lisp_Object xwidget, Lisp_Object buffer) +{ + CHECK_XWIDGET (xwidget); + CHECK_BUFFER (buffer); + + XXWIDGET (xwidget)->buffer = buffer; + return Qnil; +} + DEFUN ("set-xwidget-plist", Fset_xwidget_plist, Sset_xwidget_plist, 2, 2, 0, @@ -1183,6 +1870,166 @@ DEFUN ("xwidget-query-on-exit-flag", return (XXWIDGET (xwidget)->kill_without_query ? Qnil : Qt); } +DEFUN ("xwidget-webkit-search", Fxwidget_webkit_search, Sxwidget_webkit_search, + 2, 5, 0, + doc: /* Begin an incremental search operation in an xwidget. +QUERY should be a string containing the text to search for. XWIDGET +should be a WebKit xwidget where the search will take place. When the +search operation is complete, callers should also call +`xwidget-webkit-finish-search' to complete the search operation. + +CASE-INSENSITIVE, when non-nil, will cause the search to ignore the +case of characters inside QUERY. BACKWARDS, when non-nil, will cause +the search to proceed towards the beginning of the widget's contents. +WRAP-AROUND, when nil, will cause the search to stop upon hitting the +end of the widget's contents. + +It is OK to call this function even when a search is already in +progress. In that case, the previous search query will be replaced +with QUERY. */) + (Lisp_Object query, Lisp_Object xwidget, Lisp_Object case_insensitive, + Lisp_Object backwards, Lisp_Object wrap_around) +{ +#ifdef USE_GTK + WebKitWebView *webview; + WebKitFindController *controller; + WebKitFindOptions opt; + struct xwidget *xw; + gchar *g_query; +#endif + + CHECK_STRING (query); + CHECK_XWIDGET (xwidget); + +#ifdef USE_GTK + xw = XXWIDGET (xwidget); + webview = WEBKIT_WEB_VIEW (xw->widget_osr); + query = ENCODE_UTF_8 (query); + opt = WEBKIT_FIND_OPTIONS_NONE; + g_query = xstrdup (SSDATA (query)); + + if (!NILP (case_insensitive)) + opt |= WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE; + if (!NILP (backwards)) + opt |= WEBKIT_FIND_OPTIONS_BACKWARDS; + if (!NILP (wrap_around)) + opt |= WEBKIT_FIND_OPTIONS_WRAP_AROUND; + + if (xw->find_text) + xfree (xw->find_text); + xw->find_text = g_query; + + block_input (); + controller = webkit_web_view_get_find_controller (webview); + webkit_find_controller_search (controller, g_query, opt, G_MAXUINT); + unblock_input (); +#endif + + return Qnil; +} + +DEFUN ("xwidget-webkit-next-result", Fxwidget_webkit_next_result, + Sxwidget_webkit_next_result, 1, 1, 0, + doc: /* Show the next result matching the current search query. + +XWIDGET should be an xwidget that currently has a search query. +Before calling this function, you should start a search operation +using `xwidget-webkit-search'. */) + (Lisp_Object xwidget) +{ + struct xwidget *xw; +#ifdef USE_GTK + WebKitWebView *webview; + WebKitFindController *controller; +#endif + + CHECK_XWIDGET (xwidget); + xw = XXWIDGET (xwidget); + + if (!xw->find_text) + error ("Widget has no ongoing search operation"); + +#ifdef USE_GTK + block_input (); + webview = WEBKIT_WEB_VIEW (xw->widget_osr); + controller = webkit_web_view_get_find_controller (webview); + webkit_find_controller_search_next (controller); + unblock_input (); +#endif + + return Qnil; +} + +DEFUN ("xwidget-webkit-previous-result", Fxwidget_webkit_previous_result, + Sxwidget_webkit_previous_result, 1, 1, 0, + doc: /* Show the previous result matching the current search query. + +XWIDGET should be an xwidget that currently has a search query. +Before calling this function, you should start a search operation +using `xwidget-webkit-search'. */) + (Lisp_Object xwidget) +{ + struct xwidget *xw; +#ifdef USE_GTK + WebKitWebView *webview; + WebKitFindController *controller; +#endif + + CHECK_XWIDGET (xwidget); + xw = XXWIDGET (xwidget); + + if (!xw->find_text) + error ("Widget has no ongoing search operation"); + +#ifdef USE_GTK + block_input (); + webview = WEBKIT_WEB_VIEW (xw->widget_osr); + controller = webkit_web_view_get_find_controller (webview); + webkit_find_controller_search_previous (controller); + + if (xw->find_text) + { + xfree (xw->find_text); + xw->find_text = NULL; + } + unblock_input (); +#endif + + return Qnil; +} + +DEFUN ("xwidget-webkit-finish-search", Fxwidget_webkit_finish_search, + Sxwidget_webkit_finish_search, 1, 1, 0, + doc: /* Finish XWIDGET's search operation. + +XWIDGET should be an xwidget that currently has a search query. +Before calling this function, you should start a search operation +using `xwidget-webkit-search'. */) + (Lisp_Object xwidget) +{ + struct xwidget *xw; +#ifdef USE_GTK + WebKitWebView *webview; + WebKitFindController *controller; +#endif + + CHECK_XWIDGET (xwidget); + xw = XXWIDGET (xwidget); + + if (!xw->find_text) + error ("Widget has no ongoing search operation"); + +#ifdef USE_GTK + block_input (); + webview = WEBKIT_WEB_VIEW (xw->widget_osr); + controller = webkit_web_view_get_find_controller (webview); + webkit_find_controller_search_finish (controller); + unblock_input (); +#endif + + return Qnil; +} + void syms_of_xwidget (void) { @@ -1215,6 +2062,12 @@ syms_of_xwidget (void) defsubr (&Sxwidget_plist); defsubr (&Sxwidget_buffer); defsubr (&Sset_xwidget_plist); + defsubr (&Sxwidget_perform_lispy_event); + defsubr (&Sxwidget_webkit_search); + defsubr (&Sxwidget_webkit_finish_search); + defsubr (&Sxwidget_webkit_next_result); + defsubr (&Sxwidget_webkit_previous_result); + defsubr (&Sset_xwidget_buffer); DEFSYM (QCxwidget, ":xwidget"); DEFSYM (QCtitle, ":title"); @@ -1236,6 +2089,15 @@ syms_of_xwidget (void) Vxwidget_view_list = Qnil; Fprovide (intern ("xwidget-internal"), Qnil); + + id_to_xwidget_map = CALLN (Fmake_hash_table, QCtest, Qeq); + staticpro (&id_to_xwidget_map); + +#ifdef USE_GTK + x_window_to_xwv_map = CALLN (Fmake_hash_table, QCtest, Qeq); + + staticpro (&x_window_to_xwv_map); +#endif } @@ -1374,7 +2236,7 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix) /* The only call to xwidget_end_redisplay is in dispnew. xwidget_end_redisplay (w->current_matrix); */ struct xwidget_view *xv - = xwidget_view_lookup (glyph->u.xwidget, w); + = xwidget_view_lookup (xwidget_from_id (glyph->u.xwidget), w); #ifdef USE_GTK /* FIXME: Is it safe to assume xwidget_view_lookup always succeeds here? If so, this comment can be removed. @@ -1424,6 +2286,26 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix) } } +#ifdef USE_GTK +void +kill_frame_xwidget_views (struct frame *f) +{ + Lisp_Object rem = Qnil; + + for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); + tail = XCDR (tail)) + { + if (XXWIDGET_VIEW (XCAR (tail))->frame == f) + rem = Fcons (XCAR (tail), rem); + } + + for (; CONSP (rem); rem = XCDR (rem)) + { + Fdelete_xwidget_view (XCAR (rem)); + } +} +#endif + /* Kill all xwidget in BUFFER. */ void kill_buffer_xwidgets (Lisp_Object buffer) @@ -1437,12 +2319,15 @@ kill_buffer_xwidgets (Lisp_Object buffer) { CHECK_XWIDGET (xwidget); struct xwidget *xw = XXWIDGET (xwidget); + Fremhash (make_fixnum (xw->xwidget_id), id_to_xwidget_map); #ifdef USE_GTK if (xw->widget_osr && xw->widgetwindow_osr) { gtk_widget_destroy (xw->widget_osr); gtk_widget_destroy (xw->widgetwindow_osr); } + if (xw->find_text) + xfree (xw->find_text); if (!NILP (xw->script_callbacks)) for (ptrdiff_t idx = 0; idx < ASIZE (xw->script_callbacks); idx++) { diff --git a/src/xwidget.h b/src/xwidget.h index 591f23489d..3bab6d5b00 100644 --- a/src/xwidget.h +++ b/src/xwidget.h @@ -32,6 +32,8 @@ #define XWIDGET_H_INCLUDED #if defined (USE_GTK) #include +#include +#include "xterm.h" #elif defined (NS_IMPL_COCOA) && defined (__OBJC__) #import #import "nsxwidget.h" @@ -59,11 +61,14 @@ #define XWIDGET_H_INCLUDED int height; int width; + uint32_t xwidget_id; #if defined (USE_GTK) /* For offscreen widgets, unused if not osr. */ GtkWidget *widget_osr; GtkWidget *widgetwindow_osr; + guint hit_result; + gchar *find_text; #elif defined (NS_IMPL_COCOA) # ifdef __OBJC__ /* For offscreen widgets, unused if not osr. */ @@ -98,9 +103,13 @@ #define XWIDGET_H_INCLUDED bool hidden; #if defined (USE_GTK) - GtkWidget *widget; - GtkWidget *widgetwindow; - GtkWidget *emacswindow; + Display *dpy; + Window wdesc; + Emacs_Cursor cursor; + struct frame *frame; + + cairo_surface_t *cr_surface; + cairo_t *cr_context; #elif defined (NS_IMPL_COCOA) # ifdef __OBJC__ XvWindow *xvWindow; @@ -162,6 +171,15 @@ #define XG_XWIDGET_VIEW "emacs_xwidget_view" void store_xwidget_js_callback_event (struct xwidget *xw, Lisp_Object proc, Lisp_Object argument); +struct xwidget_view *xwidget_view_from_window (Window wdesc); +void xwidget_expose (struct xwidget_view *xv); + +extern struct xwidget *xwidget_from_id (uint32_t id); +extern void kill_frame_xwidget_views (struct frame *f); +extern void xwidget_button (struct xwidget_view *, bool, int, + int, int, int, Time); +extern void xwidget_motion_or_crossing (struct xwidget_view *, + const XEvent *); #else INLINE_HEADER_BEGIN INLINE void syms_of_xwidget (void) {} --=-=-=-- From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Lars Ingebrigtsen Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 07 Nov 2021 00:56:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Po Lu Cc: Eli Zaretskii , 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163624655117952 (code B ref 51473); Sun, 07 Nov 2021 00:56:01 +0000 Received: (at 51473) by debbugs.gnu.org; 7 Nov 2021 00:55:51 +0000 Received: from localhost ([127.0.0.1]:51220 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjWTO-0004fU-Nc for submit@debbugs.gnu.org; Sat, 06 Nov 2021 20:55:50 -0400 Received: from quimby.gnus.org ([95.216.78.240]:56960) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjWTM-0004fH-Uk for 51473@debbugs.gnu.org; Sat, 06 Nov 2021 20:55:49 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnus.org; s=20200322; h=Content-Type:MIME-Version:Message-ID:In-Reply-To:Date: References:Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=bLNK/ugnfxRVhi1WdXp7ErkwpqAqfOWlo4eOIEZNnIQ=; b=b3aT1IW99UeYOWMNHbaGsnCRvF 8IW9xyR/y3R75WE4EuqW4ELJF/QU3pDmXowZ/8ujIEXuz2zySLXubipoUPDNFVZzzPN78DWq3JQji 9OW0ZNTP8D8RDwCaT98jidKzyx0NGp4N4CxMZ5oOOiTrEO758AfPFTnhh+C2IHLfYAfY=; Received: from [84.212.220.105] (helo=elva) by quimby.gnus.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mjWTD-0003BN-JF; Sun, 07 Nov 2021 01:55:42 +0100 From: Lars Ingebrigtsen References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> <87o86xzhuw.fsf@yahoo.com> <87sfw9cha3.fsf@gnus.org> <878ry0ztjo.fsf@yahoo.com> Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAABGdBTUEAALGPC/xhBQAAACBj SFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAG1BMVEU1LypEOzNWUEgj HhqScErGnGZdSznXwpX////dnnslAAAAAWJLR0QIht6VegAAAAd0SU1FB+ULBwA2GhQkQTYAAAGU SURBVDjLlZK9b8IwEMVtQjPbQD0XaPdItN2Rzs7cKoaVSMGsHQj+93tn57OARJ+UD93v3vPFMWNc klao2VJ2mjPG6CleAQoNyxEgyQlZVvIK8AmgvvgVCFAKxm+BQccdcNdBln8C9ghAtxhmRcCVi5Kd JQAZipVz4JwYRGG9Am2tBTAmkDiVVA6wavfe26L18DlSR92tGoIO6QDGpIwOBQ2gKJJxhwAqBLHX +xrvuiALgtaAjjpEAeAq0dEuEbIKHBqzGmDK8D26AWW7BnakSlWCKU0AGmAwUoHW2knBdQ8MfdDR V35X0GnQCEyYCnNYaj281drQawu2ODSf1n53qj9+aJsWAFsCgkDlTxfw+VlQLA3Dads541Obe3/0 PuzTFEQEgsm0qnWxt0bSL+SYPgkOxfjzRZv889D99ADSF5Hua//9XpWHESCd6nyXe9eDdfOyKJ62 +bk/Px1gJed9/xBkyego9uCPHgFJds+RsQGa9YuPoxqwCUqyzRgkm04ZXQRW62G5VXRc18lzG6Dn DsgQ/AIpZYy6KGfBdAAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMS0xMS0wN1QwMDo1NDoyNiswMDow MA2BfyYAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjEtMTEtMDdUMDA6NTQ6MjYrMDA6MDB83MeaAAAA AElFTkSuQmCC X-Now-Playing: Nils Frahm's _Tripping with Nils Frahm_: "All Melody" Date: Sun, 07 Nov 2021 01:55:37 +0100 In-Reply-To: <878ry0ztjo.fsf@yahoo.com> (Po Lu's message of "Sun, 07 Nov 2021 08:41:15 +0800") Message-ID: <874k8oss1i.fsf@gnus.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Report: Spam detection software, running on the system "quimby.gnus.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see @@CONTACT_ADDRESS@@ for details. Content preview: Po Lu writes: > Thanks, here you go. Thanks! I've now tried on Debian/bookworm, and everything seems to be working fine. (But truth be told, I don't see much difference before/after the patches with some very cursory browsing on youtube. [...] Content analysis details: (-2.9 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Po Lu writes: > Thanks, here you go. Thanks! I've now tried on Debian/bookworm, and everything seems to be working fine. (But truth be told, I don't see much difference before/after the patches with some very cursory browsing on youtube.com and google.com.) Now for Macos... -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Lars Ingebrigtsen Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 07 Nov 2021 01:05:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Po Lu Cc: Eli Zaretskii , 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163624705318780 (code B ref 51473); Sun, 07 Nov 2021 01:05:02 +0000 Received: (at 51473) by debbugs.gnu.org; 7 Nov 2021 01:04:13 +0000 Received: from localhost ([127.0.0.1]:51232 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjWbU-0004sq-UF for submit@debbugs.gnu.org; Sat, 06 Nov 2021 21:04:13 -0400 Received: from quimby.gnus.org ([95.216.78.240]:57012) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjWbT-0004sc-4I for 51473@debbugs.gnu.org; Sat, 06 Nov 2021 21:04:11 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnus.org; s=20200322; h=Content-Type:MIME-Version:Message-ID:In-Reply-To:Date: References:Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=+Gkwjsh2hMBvDNJ82cNd4wSTrXtTWhyKRxUNqfuuM1M=; b=I1JCxAGK4ADNV7EIzikxwsVYzU QOZ7qqOY8oG8/Gnl/GlybAW2HsF3lKIOUI1gQdu2mag/Ey32G7Gp4RHmvgoeF9Cm2JWdgXHCLwsTJ DHHp/mOQPY3Us+DoEJBXTKRcTZWb2495pUAU8dMalM7YvCeePGG2cYeZzG91m0DBNyTo=; Received: from [84.212.220.105] (helo=elva) by quimby.gnus.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mjWbK-0003Fu-D3; Sun, 07 Nov 2021 02:04:05 +0100 From: Lars Ingebrigtsen References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> <87o86xzhuw.fsf@yahoo.com> <87sfw9cha3.fsf@gnus.org> <878ry0ztjo.fsf@yahoo.com> Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAABGdBTUEAALGPC/xhBQAAACBj SFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAG1BMVEU1LypEOzNWUEgj HhqScErGnGZdSznXwpX////dnnslAAAAAWJLR0QIht6VegAAAAd0SU1FB+ULBwA2GhQkQTYAAAGU SURBVDjLlZK9b8IwEMVtQjPbQD0XaPdItN2Rzs7cKoaVSMGsHQj+93tn57OARJ+UD93v3vPFMWNc klao2VJ2mjPG6CleAQoNyxEgyQlZVvIK8AmgvvgVCFAKxm+BQccdcNdBln8C9ghAtxhmRcCVi5Kd JQAZipVz4JwYRGG9Am2tBTAmkDiVVA6wavfe26L18DlSR92tGoIO6QDGpIwOBQ2gKJJxhwAqBLHX +xrvuiALgtaAjjpEAeAq0dEuEbIKHBqzGmDK8D26AWW7BnakSlWCKU0AGmAwUoHW2knBdQ8MfdDR V35X0GnQCEyYCnNYaj281drQawu2ODSf1n53qj9+aJsWAFsCgkDlTxfw+VlQLA3Dads541Obe3/0 PuzTFEQEgsm0qnWxt0bSL+SYPgkOxfjzRZv889D99ADSF5Hua//9XpWHESCd6nyXe9eDdfOyKJ62 +bk/Px1gJed9/xBkyego9uCPHgFJds+RsQGa9YuPoxqwCUqyzRgkm04ZXQRW62G5VXRc18lzG6Dn DsgQ/AIpZYy6KGfBdAAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMS0xMS0wN1QwMDo1NDoyNiswMDow MA2BfyYAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjEtMTEtMDdUMDA6NTQ6MjYrMDA6MDB83MeaAAAA AElFTkSuQmCC X-Now-Playing: Nils Frahm's _Tripping with Nils Frahm_: "All Melody" Date: Sun, 07 Nov 2021 02:04:01 +0100 In-Reply-To: <878ry0ztjo.fsf@yahoo.com> (Po Lu's message of "Sun, 07 Nov 2021 08:41:15 +0800") Message-ID: <87zgqgrd32.fsf@gnus.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Report: Spam detection software, running on the system "quimby.gnus.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see @@CONTACT_ADDRESS@@ for details. Content preview: On Macos, it fails with: CC dispnew.o In file included from dispnew.c:43: ./xwidget.h:182:12: error: unknown type name 'XEvent' const XEvent *); ^ 1 error generated. make[1]: *** [dispnew.o] Error 1 Content analysis details: (-2.9 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) On Macos, it fails with: CC dispnew.o In file included from dispnew.c:43: ./xwidget.h:182:12: error: unknown type name 'XEvent' const XEvent *); ^ 1 error generated. make[1]: *** [dispnew.o] Error 1 -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 07 Nov 2021 01:17:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Lars Ingebrigtsen Cc: Eli Zaretskii , 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163624779119871 (code B ref 51473); Sun, 07 Nov 2021 01:17:02 +0000 Received: (at 51473) by debbugs.gnu.org; 7 Nov 2021 01:16:31 +0000 Received: from localhost ([127.0.0.1]:51246 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjWnP-0005AR-45 for submit@debbugs.gnu.org; Sat, 06 Nov 2021 21:16:31 -0400 Received: from sonic309-22.consmr.mail.ne1.yahoo.com ([66.163.184.148]:38291) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjWnN-0005AE-JP for 51473@debbugs.gnu.org; Sat, 06 Nov 2021 21:16:30 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636247784; bh=RqT3E9mTZkBjR5nyJTNTZm9UenXHlIEYcMIGjscma00=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=EG7WwGxFREK/LV5qGnxeZ/6CkXeGlgv36hn5GGqi3ZIF/dR9u9X8XZvBkYlvejZo+Uk6w44wPHpDJFX/tLFfAzG9JwSm05YZMmsy5sAD8GArm2dnr8PkgBHT7bUukKZWOcBlzUIZR0s0CK2n9cpudjRlWcjye1qyYInF8jdWZgBjVwJJqwxPOBCH0II7OZMynSsNLIjBHXYpaFFri6ySSmQfr1XrHu/+ylbjNEsJ7K+Ma7el4xVeRR9RdjAQ5X9o5Ntbr1AOQndyQjJBD0mV9kdzjIuQrwCCwaGUBa/SduBQBldf21I+wUnmn6XSYahtXWMOuOrkMjgt13hzySBODQ== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636247784; bh=IDvOA9HV8v3qjZnOD4F2EurGtk+yoZtP/hyFwtK6/Qj=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=a5yy4AzDbKWkW2dZX/Wp2dncph6pFsKoWxDQRy0sstvsRPMiSnd5HviWuHKeYZsrPGG9Va79xt7bTfpnFDHvKa9x/S6vHFdskLuvJJ8bfuJjJ7TqGTaGU9J8N8+J4H8abxjDLYtBM+9tvBJEzbSHR4yaxcDsCNCdzzKGOZLlhHAVf06ur/mwwLUcOYuDtVIteExURphjn/73PknTFVIC1ny4PNLhi8cSm224oYc1VQ2BTK/9X3Gb/VYMTI85X6PFYCU6PYQWEAcMBvSjSsuxm+4YQ5ltprLmx16TApPq/V6yZMoa7EcYX55fv5PbOolDBCOPU6oCddtiO9qyjlcLag== X-YMail-OSG: YlHU6fYVM1npkgC6RtSu_oa1dwxCCDValO6zXpuuDDpM1U183tZ6itbX5KoCdHF tTo2bFaoHG88FQm4g310NfzvaLfPBl1zMJycyviEku7KRPLAxv4jutoXZYtN9xfbPAN1rLKc7V6V VHuLXgC9_smMHb8a3xDhBUutcdnSJscfoCmeNORmRiOq_K.QqQ0rcFeTEjVX3Ny6JKYoJ1h9.AdW rLaORP7wL2uz6Q9ClODrk4d1Wdq13NGkxUEf7eg6wjiPvxuIvJFvPUNo9FQpEb5kgPD5EmeTooYk 2bhn8pUOr0AWwalivxoVkZ.nCiM7uNsDKTJpZ_JaqBj3iTJ.LhG2RX7pznKSLG0GB7Tn4eit3w4b A9Z5M2QiDjsbnEwqTddwUplV.qxZm0g9.738.vjk8SkZL9xzcnysRdsljIZXAr0HlYVXWxX59yT4 Gpwphdqe06F0feUMvB1sly4nNcVFFOiXVfIHnAMlR8yAJlaYUHoeK0_DdyF0ZTTvsRw0krdCLHE5 ORWyeg_Bl_7kw3M5kwBwaqLt1hHB38d5fzsdj_DgEDj2uc5CQ1jElhSjR51b7D9v4zMSs9vO2eBD _0CFBdvI4EC4qaPEpcYwSVSVz3wd1uQSDg2mUUNeeA5Cb7zsQy.Vjf_QaX6no2.t9cqJx1U2Mw8z a5bzvYyBBtemerurZbafm7tyhM2q5LPJdHWvdOR3bsjBE49UrYezzgZ8LSbin_kQUfuNLT3iApM5 A4MCi4ExYtSXNDFmQnvIu_sjP5hr5MisKwMX4Gv0ozVRJcdzY0knR3xRFXO8tXK6ncy8luPiIfZM w560.jbYOmtJrCaV4IZCIAsLDwjlHBmU3nZ9hpaZ8n1tAnFuuBEEJT8aNMI9LphgB0xd0F4L058Q Q81un19Nhq_0yD7TmMQA2g0VAcPKFtRn2pfaV0xN9ANuqEpN.OkYC8j8LtA.Jh7rC6Ri5X9ikSbS otBYIzAfSenrC8rjz84tzyzBI2X8TJKssRJeBpChd8LijoJL607MRpLTychuMMH2o.rPrH63z5F6 1Q0lEVhm3F0p6VLrALsJFVeDYkY2RSb7JFo0H26wB5pzRqak.ypX.oW0aEQrE_IN1B4TrGnzlQri ZVlRgRhTiSssDyUBGQuqydbauaVlUgWgAHQnYGThzhOU9Y1CkGTwfphrLtgMw65yVNefQSTq55BP tg40Msa7IeBGZ6DOLsjlbWd88G34gn_2DGHdxzkdI7y0caT3TjSmEixIe6EEciC2etB7tJ2pg0z. sqLT2xPWm9ERvJ.CQu8srdxu54DkvuV6xskj11AkS22s7t7Ys0g6XNUhTJBynsuhTR7ri_ESJnRM kDFWkTNSyqK6NseCByLWzbZdhnos7Xlzg._JKC0SobBYPjkyWXGduFF.bhioVFtYCveCo4RtpVJe KlBgUN60hiA8O5iCtz3mSleDZ2llpWLwP.Dv7ttqJ2z8a4yVHk8xpC8JrEBskuSHZCGqPMG35xF1 SMl1nqdNK12PufiVPz4h0U72MhDVAvxaUcBC26v6TzSK1Tn71.LhiFrimSntDlMQ5Yt6821DfkNw _GooM4wmjV1rZUkLq4taZGO7L6YgJU4.Fg70d5QVDhipvNj_xD5ggjaXPeSrv4vA92XkK4gGxtAD YoA4fmP4ZAMIczT2huf0qbEGSsyCUB788FQ12rhBALeGeTChaRzqmdRuQDMeVnH2n0RrdWNR0CNZ R4c8m7OpK.5w1Tc8sTPXttpfXKDhOWfPD1TLqPuEz4iAKoYrSPAfFRCsFgf0BZByr0npaSZhhrHV vR7P389n4Ga34nKCC9K1PgGynBdwr9qvCyXYMtHq92zkoPpa2IkHIPMLWObOxJac5gaa.dpX68em L_WDV_NGx.yNtvriX0KbScm6wVivkJWTrvc6erEWv8XNAQe5tK_VGMv7Hqt7xSyA_4nsXTyAY9No RJO1hjS35llYjAzuEMDutR6q0fMsWURBr1gUHZ2ttNfut8TAmg9P0Ztcq0vizarhiWcnfwDmNCkS J6ql5ja8IYYc2IaoWtD5Hf3LSk1jLB9whSG.psykc7bn7DfgcX9h0vif8S6W8GDS8JGDgUS16zrI KQ985_HPT1bYnOU1XnQc5K5X8LnDSZu_qYmjRvo.DCWq2_bMdax5dFKvzhqu.GQnFa5P1Cr.b9lk Dgx6IZJHJ60dXF3kkLZvJD01HiesO_8_o.ELT0Ta9gBtYWmKyLVWW9i1Zgi0H4ANWQq7TShWdm_k M_6pael4en4ZcwtDvtMsaYEgFyprs4CZrK4mbaYZcUpXY9MwcDS3zyjk- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic309.consmr.mail.ne1.yahoo.com with HTTP; Sun, 7 Nov 2021 01:16:24 +0000 Received: by kubenode514.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 7d0ecd9b2ac42e4bb2bca4694afd76c4; Sun, 07 Nov 2021 01:16:17 +0000 (UTC) From: Po Lu References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> <87o86xzhuw.fsf@yahoo.com> <87sfw9cha3.fsf@gnus.org> <878ry0ztjo.fsf@yahoo.com> <874k8oss1i.fsf@gnus.org> Date: Sun, 07 Nov 2021 09:16:12 +0800 In-Reply-To: <874k8oss1i.fsf@gnus.org> (Lars Ingebrigtsen's message of "Sun, 07 Nov 2021 01:55:37 +0100") Message-ID: <874k8ozrxf.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 345 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) Lars Ingebrigtsen writes: > Thanks! I've now tried on Debian/bookworm, and everything seems to be > working fine. (But truth be told, I don't see much difference > before/after the patches with some very cursory browsing on > youtube.com and google.com.) Less flickering, for one, and you can also press "e" and try typing. From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 07 Nov 2021 01:19:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Lars Ingebrigtsen Cc: Eli Zaretskii , 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163624792820077 (code B ref 51473); Sun, 07 Nov 2021 01:19:01 +0000 Received: (at 51473) by debbugs.gnu.org; 7 Nov 2021 01:18:48 +0000 Received: from localhost ([127.0.0.1]:51252 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjWpY-0005Dh-FZ for submit@debbugs.gnu.org; Sat, 06 Nov 2021 21:18:48 -0400 Received: from sonic313-10.consmr.mail.ne1.yahoo.com ([66.163.185.33]:41161) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjWpT-0005DR-JB for 51473@debbugs.gnu.org; Sat, 06 Nov 2021 21:18:43 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636247914; bh=z+PeRFPgrwz2TLFUxDOUedxCYicUz06bKQ8xEFAtnys=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=Ov44nfXUT2CLlBS0hgLEaVKD3NydQvx9hpTo9B+10uj/mgbW4cKHz88Rkz8E8JzjaB5ZvIDwWaM+TNhuk6roNF646BBvC2REoE185Ma6ZtCBhtsDmWRiyOCBNi69/DV2c2f9R1QY5KddY9qbCzlwhKGmNwVsH+jDy6XVU+0VIyBxPVVz8a0rSx5rDrDkpdHEurvYwSzqz3IeRQR78Mm8o09J+pYkKxNoQFPGFo+sDTp9MvUJIzd00BbTRQcuI9hJhPkRWhr8jOxIiko1+tTR5QnQoa3tF50AvL//dc5SOnCio9Qlu7a7YFBvjLfzxjIZaoYPkDzYDFAiOaC/6MtxuQ== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636247914; bh=CgDJn+WXL+aHi3hBTthiD6ZS8KLNdTJqkpcDDo8UWW8=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=FNi6WfVkEWu5m65Hw53n0SEtVPPi3jLL7jugngGfi7oYnHnjatjp6SCPrJVuWMtwLK8zk9SO4Ni10ssxGLm6w9M8nSi0W6FSbdpkAS+1G13PJzKnDU4ofYcBvdJ46OMRjDzwIgVrrevy4sJTSDGsHWXrn79E6mM+FmBWSPlqCiF9JN9ro8Hq0PCLLkgriXPpTQyXSG4X2S1PLu8zIGpFOkt6lAUGomIzjoP+kkf0G4wFsPHXLFzLGPLS43Z7BEn4s+0obZQWvWc1+FIFyksxTjQKPYDGI5izlthyyD2j8+4cmkHDi1eOT0o4lGZ10TBIDUMccj7cUv8C5w0L83HFXg== X-YMail-OSG: KoYje0sVM1lYgPSthlWlHS7oERj9e9U9TJUIJVQWpt0f.g45KQeqeaQWrQ6KtQr KRFrpolRkGvWiQkb268iaQ9DVroEmI09YD0jhUjGe1PkbnNT9brmpPA6q.3ePgugLBB1PbxxPJ3k YkZElvX6bJ75TEZIN79ZrSkQvdEPTMsoGw4qNlJrvbeAUgA1Xp5GFR_KhcXiD6MKQQWGvnMsWiUU G.iVoddgkFvbgwpVSsYeaivP7sIFjoBu97bD9v2EdiCfy_gU86NNTw.J0CflSw5T7LRkL02lRZSU VbuLC6inJJIjFD53PtSkr79KjuH018xDocUnKIbGhqrY6sB7__2xTKotszpWpQUCCMRZC0ibVGmZ qBF15kBvFdaboS.ehkC4fQ3EoS.czMsMLgE4DRng2qJnGpKEyAKAlG4Ggm23kbueXIbgWQHLpCLx gfWLfu4s_HyW2VXvjieP973LiOf3._EMNvWJCm4RAvXFN6C_1QM.FOmmgXNVNT9jOmNu1B9U8F4R eF8xfwm9gyf.QX5iPE17mwGK0l9z31tI24c3Q3SwnvSXclL56B3gzOLOVgfQ6OMxG2XnLyGj9kog qEqb2B0UDI1OVSKHo7yihomFCmWCYfOYzyKorzAcZwBclBSMo1UWdWJR_obbPSqpip..2SBFitlT 7CgyPr52RDVypBDh4GqXyLLdPeWF6NwY53arwX18_dpmr7_2bRCH8sGdYYkWa6vwK8HEOwalPTmb Ml2NEvkSPqRvcgPYLIC8p3jHAljDTaOxGD9S5bLE5c92Jpnaj03ujNuiAph9F2vaA7AWV59Wp3QG 61I_EhRFnuLytfoiAJ6wtloUULCEaefu3rcrANXgu3.63VlpvX9f5H2ZTrr4zSdf6Ygr99RPfNvT WZXcOCR8xjhemLngO2S1K6R4aJJltq8IUzXnuUb.WkOw37SQgVlXh1KK4Evc18yxfR1XyOnrGxxS rrpct3XFLyE8yzeWji0bh2nVSjZQy9xeJQNirrxhojk71glXx94DNhSAV8BZU8JbpXwwNVRyS2GQ AjVpmf_B1.d96NUcSVNqrqB.sY0DbHW0IzR_cW7nQbw3a1o3YVyXMcFzNfHCJUuGM24.jNOQYyOr Vvxxz4PRLLPUKp8AMBAdvkgOcZ_cmjXDJ6fgPCstTqSWTvvfWzzsVCPRGEZ69DTFlPDZ_p1lgFZG N5vqlBBY0Tpc2ymo2D4QLdayNpwSL_T2GQHmj8xxGzS1hKJtsoPu9M5fQ_4HgTMYhZhzzrw2731A XXPg6ftgDcPH6z.ozeNMR5UQy0UOTa1uStsRCWgfYcwrAVYwHUSgzjdPTzOwEZLCX7GaaMRU.GeO BiAtLSjnQuzt6RxfbYCe0SkmNQGHsnBa1ts.pWJbl1apP0KCKdFu.V6jMrsW_sExrbnyX1dH5bvR oTzG9hwZHPXfCO45_G5K91R3k04tHZp6un_QFMMRJcnXkVZYk5Fe0QIosKMJo64lFEMGCsEr3L5N sn55UzYLfw4c0R2IfgdZz._J0GBpsTCJCt1ca7Rp4mWLvCQeTE3.Q0nC2Z_7NvZnc9hv5boW0mNV MSVHaJscb3BzJuuOGvwhqtfBRw2vtfgdLV7Ef1BIt_6x8rxW_LUcPVvzjhhgD5JPhLzQTrNGuEDH H3FGQ6r31N9Mu9lrnbXs0.FObfVxVavpoSFZsGMA0o3jMf0knztWQRSRNUWyd_82tKMWzxuYKQ.Z FTpR3ERZlcnIW1RUJk11f6J8ULeFzpDAGrEO6vcykRbG.ZRlWQA54dLl9pdrbwU0a26AE6JP_x09 1dwHMQwJUj8trDWzDwL.KKC4Ms.NVos0ak7ecXV3ze7F8l.pHrcdy8bKgxO5jsug6d2EBseepd0W 6YVsd5TxTUHYYY654.qhzV5YnISJlyhhI7VrE3QPAeK2EVp4kKYoZXTisLBNHJCf2kOHMb3UtVN6 4sm4t_X5Mx4QpRSPd3B4N7lZS9hBdUXXm1_yfmiURJaH6dOWBGD6xOv1GdYDAkPiAW4ZM_iIQOb7 7YjrincjDJ2HtoeBOKr30pqd7ERJl7CKpaPeWLH9H667uOtqi9ohRb_hNN_pkAKw6piD1GQW3cm3 TRi5ZVlWmW_JZB26xnLufoT5z7aHNPsQPMoT16cRdcfxbPHCvcmWfc5ywDUk21cASXvl7t3gb.Iz cI83NH9sixRHWWREsepcCVZ6GHHKIb41Stl6S30l3XhN5zo3OcWBvo_kc3csesi_LvyarYOKOQ1o jQRx8w82y7n9xg5OixbYMvY6eaquDNgZPfNYxoZ2Th1LDhqBtevqx37Ot X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic313.consmr.mail.ne1.yahoo.com with HTTP; Sun, 7 Nov 2021 01:18:34 +0000 Received: by kubenode510.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 853cedd9af73960003fb820f1f599e04; Sun, 07 Nov 2021 01:18:25 +0000 (UTC) From: Po Lu References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> <87o86xzhuw.fsf@yahoo.com> <87sfw9cha3.fsf@gnus.org> <878ry0ztjo.fsf@yahoo.com> <87zgqgrd32.fsf@gnus.org> Date: Sun, 07 Nov 2021 09:18:22 +0800 In-Reply-To: <87zgqgrd32.fsf@gnus.org> (Lars Ingebrigtsen's message of "Sun, 07 Nov 2021 02:04:01 +0100") Message-ID: <87zgqgyd9d.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 94741 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Lars Ingebrigtsen writes: > CC dispnew.o > In file included from dispnew.c:43: > ./xwidget.h:182:12: error: unknown type name 'XEvent' > const XEvent *); > ^ Does this version fix the problem? --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=test.diff diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi index 7f91e1c188..1207ab5e9a 100644 --- a/doc/emacs/misc.texi +++ b/doc/emacs/misc.texi @@ -2953,6 +2953,34 @@ Embedded WebKit Widgets reloading it. Type @w{@kbd{C-h b}} in that buffer to see the key bindings. +@findex xwidget-webkit-edit-mode +@cindex xwidget-webkit-edit-mode + By default, typing a self-inserting character inside an xwidget +webkit buffer will do nothing, or trigger some special action. To +make those characters and other common editing keys insert themselves +when pressed, you can enable @code{xwidget-webkit-edit-mode}, which +redefines them to be passed through to the WebKit xwidget. + +You can also enable @code{xwidget-webkit-edit-mode} by typing @kbd{e} +inside the xwidget webkit buffer. + +@findex xwidget-webkit-isearch-mode +@cindex xwidget-webkit-isearch-mode +@cindex searching in webkit buffers + @code{xwidget-webkit-isearch-mode} is a minor mode that behaves +similarly to incremental search (@pxref{Incremental Search}), but +operates on the contents of a WebKit widget instead of the current +buffer. It is bound to @kbd{C-s} and @kbd{C-r} inside xwidget-webkit +buffers. When it is enabled through @kbd{C-r}, the initial search +will be performed in reverse direction. + +Typing any self-inserting character will cause the character to be +inserted into the current search query. Typing @kbd{C-s} will cause +the WebKit widget to display the next search result, while typing +@kbd{C-r} will cause it to display the last. + +To leave incremental search, you can type @kbd{C-g}. + @node Browse-URL @subsection Following URLs @cindex World Wide Web diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi index b38a83b4fe..832b570b6a 100644 --- a/doc/lispref/commands.texi +++ b/doc/lispref/commands.texi @@ -1176,6 +1176,7 @@ Input Events * Repeat Events:: Double and triple click (or drag, or down). * Motion Events:: Just moving the mouse, not pushing a button. * Focus Events:: Moving the mouse between frames. +* Xwidget Events:: Events generated by xwidgets. * Misc Events:: Other events the system can generate. * Event Examples:: Examples of the lists for mouse events. * Classifying Events:: Finding the modifier keys in an event symbol. @@ -1871,6 +1872,76 @@ Focus Events so that the focus event comes either before or after the multi-event key sequence, and not within it. +@node Xwidget Events +@subsection Xwidget events + +Xwidgets (@pxref{Xwidgets}) can send events to update Lisp programs on +their status. These events are dubbed @code{xwidget-events}, and +contain various data describing the nature of the change. + +@table @code +@cindex @code{xwidget-event} event +@item (xwidget-event @var{kind} @var{xwidget} @var{arg}) +This event is sent whenever some kind of update occurs in +@var{xwidget}. There are several types of updates, which are +identified by @var{kind}. + +@cindex @code{load-changed} xwidget events +An xwidget event with @var{kind} set to @code{load-changed} indicates +that the @var{xwidget} has reached a particular point of the +page-loading process. When these events are sent, @var{arg} will +contain a string that futher describes the status of the widget. + +@cindex @samp{"load-finished"} in xwidgets +When @var{arg} is @samp{"load-finished"}, it means the xwidget has +finished processing whatever page-loading operation that it was +previously performing. + +@cindex @samp{"load-started"} in xwidgets +Otherwise, if it is @samp{"load-started"}, then the widget has begun a +page-loading operation. + +@cindex @samp{"load-redirected"} in xwidgets +If @var{arg} is @samp{"load-redirected"}, it means the widget has +encountered and followed a redirect during the page-loading operation. + +@cindex @samp{"load-committed"} in xwidgets +If @var{arg} is @samp{"load-committed"}, then the widget has committed +to a given URL during the page-loading operation. This means that the +URL is the final URL that will be rendered by @var{xwidget} during the +current page-loading operation. + +@cindex @code{download-callback} xwidget events +An event with @var{kind} set to @code{download-callback} indicates +that a download of some kind has been completed. + +In these events, there can be arguments after @var{arg}, which itself +indicates the URL that the download file was retrieved from: the first +argument after @var{arg} indicates the MIME type of the download, as a +string, while the second such argument contains the full file path to +the downloaded file. + +@cindex @code{download-started} xwidget events +An event with @var{kind} set to @code{download-started} indicates that +a download has been started. In these events, @var{arg} contains the +URL of the file that is currently being downloaded. + +@cindex @code{javascript-callback} xwidget events +An event with @var{kind} set to @code{javascript-callback} contains +JavaScript callback data. These events are used internally by +@code{xwidget-webkit-execute-script}. + +@cindex @code{xwidget-display-event} event +@item (xwidget-display-event @var{xwidget}) +This event is sent whenever an xwidget requests that another xwidget +be displayed. @var{xwidget} is the xwidget that should be displayed. + +@var{xwidget}'s buffer will be set to a temporary buffer. When +displaying the widget, care should be taken to replace the buffer with +the buffer in which the xwidget will be displayed, using +@code{set-xwidget-buffer} (@pxref{Xwidgets}). +@end table + @node Misc Events @subsection Miscellaneous System Events diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 22528a1b0f..60bca15eb2 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -6784,7 +6784,10 @@ Xwidgets in a @code{display} text or overlay property (@pxref{Display Property}). -@defun make-xwidget type title width height arguments &optional buffer + Embedded widgets can send events notifying Lisp code about changes +occurring within them. (@pxref{Xwidget Events}). + +@defun make-xwidget type title width height arguments &optional buffer related This creates and returns an xwidget object. If @var{buffer} is omitted or @code{nil}, it defaults to the current buffer. If @var{buffer} names a buffer that doesn't exist, it will be @@ -6797,7 +6800,10 @@ Xwidgets @end table The @var{width} and @var{height} arguments specify the widget size in -pixels, and @var{title}, a string, specifies its title. +pixels, and @var{title}, a string, specifies its title. @var{related} +is used internally by the WebKit widget, and specifies another WebKit +widget that the newly created widget should share settings and +subprocesses with. @end defun @defun xwidgetp object @@ -6818,6 +6824,10 @@ Xwidgets This function returns the buffer of @var{xwidget}. @end defun +@defun set-xwidget-buffer xwidget buffer +This function sets the buffer of @var{xwidget} to @var{buffer}. +@end defun + @defun get-buffer-xwidgets buffer This function returns a list of xwidget objects associated with the @var{buffer}, which can be specified as a buffer object or a name of @@ -6878,6 +6888,61 @@ Xwidgets query-on-exit flag, either @code{t} or @code{nil}. @end defun +@defun xwidget-perform-lispy-event xwidget event frame +Send an input event @var{event} to @var{xwidget}. The precise action +performed is platform-specific. See @ref{Input Events}. + +You can optionally pass the frame the event was generated from via +@var{frame}. On X11, modifier keys in key events will not be +considered if @var{frame} is @code{nil}, and the selected frame is not +an X-Windows frame. + +On GTK, only keyboard and function key events are implemented. Mouse, +motion, and click events are dispatched to the xwidget without going +through Lisp code, and as such shouldn't require this function to be +sent. +@end defun + +@defun xwidget-webkit-search query xwidget &optional case-insensitive backwards wrap-around +Start an incremental search on the WebKit widget @var{xwidget} with +the string @var{query} as a query. @var{case-insensitive} denotes +whether or not the search is case-insensitive, @var{backwards} +determines if the search is performed backwards towards the start of +the document, and @var{wrap-around} determines whether or not the +search terminates at the end of the document. + +If the function is called while a search query is already present, +then the query specified here will replace the existing query. + +To stop a search query, use @code{xwidget-webkit-finish-search}. +@end defun + +@defun xwidget-webkit-next-result xwidget +Display the next search result in @var{xwidget}. This function will +error unless a search query has already been started in @var{xwidget} +through @code{xwidget-webkit-search}. + +If @code{wrap-around} was non-nil when @code{xwidget-webkit-search} +was called, then the search will restart from the beginning of the +document if the end is reached. +@end defun + +@defun xwidget-webkit-previous-result xwidget +Display the previous search result in @var{xwidget}. This function +will error unless a search query has already been started in +@var{xwidget} through @code{xwidget-webkit-search}. + +If @code{wrap-around} was non-nil when @code{xwidget-webkit-search} +was called, then the search will restart from the end of the +document if the beginning is reached. +@end defun + +@defun xwidget-webkit-finish-search xwidget +Finish a search operation started with @code{xwidget-webkit-search} in +@var{xwidget}. If there is no query currently ongoing, then this +function will error. +@end defun + @node Buttons @section Buttons @cindex buttons in buffers diff --git a/etc/NEWS b/etc/NEWS index a50229916f..b14f9a2549 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -495,6 +495,31 @@ the buffer will take you to that directory. This is a convenience function to extract the field data from 'exif-parse-file' and 'exif-parse-buffer'. +** Xwidgets + ++++ +*** New minor mode `xwidget-webkit-edit-mode'. +When this mode is enabled, self-inserting characters and other common +web browser shotcut keys are redefined to send themselves to the +WebKit widget. + ++++ +*** New minor mode `xwidget-webkit-isearch-mode'. +This mode acts similarly to incremental search, and allows to search +the contents of a WebKit widget. In xwidget-webkit mode, it is bound +to `C-s' and `C-r'. + +--- +*** On X11, the WebKit inspector is now available inside xwidgets. +To access the inspector, right click on the widget and select "Inspect +Element". + +--- +*** "Open in New Window" in a WebKit widget's context menu now works. +The newly created buffer will be displayed via display-buffer, which +can be customized through the usual mechanism of display-buffer-alist +and friends. + * New Modes and Packages in Emacs 29.1 @@ -719,6 +744,39 @@ an exact match, then the lowercased '[menu-bar foo\ bar]' and finally '[menu-bar foo-bar]'. This further improves backwards-compatibility when converting menus to use 'easy-menu-define'. ++++ +** The function `make-xwidget' now accepts an optional RELATED argument. +This argument is used as another widget for the newly created WebKit +widget to share settings and subprocesses with. It must be another +WebKit widget. + ++++ +** New function `xwidget-perform-lispy-event'. +This function allows you to send events to xwidgets. Usually, some +equivalent of the event will be sent, but there is no guarantee of +what the widget will actually receive. + +On GTK+, only key and function key events are implemented. + ++++ +** New functions for performing searches on WebKit xwidgets. +Some new functions, such as `xwidget-webkit-search', have been added +for performing searches on WebKit xwidgets. + ++++ +** `load-changed' xwidget events are now more detailed. +In particular, they can now have different arguments based on the +state of the WebKit widget. `load-finished' is sent when a load has +completed, `load-started' when a load first starts, `load-redirected' +after a redirect, and `load-committed' when the WebKit widget first +commits to the load. + ++++ +** New event type `xwidget-display-event'. +These events are sent whenever an xwidget requests that Emacs display +another. The only argument to this event is the xwidget that should +be displayed. + * Changes in Emacs 29.1 on Non-Free Operating Systems diff --git a/etc/images/README b/etc/images/README index 9bbe796cc9..561cfff765 100644 --- a/etc/images/README +++ b/etc/images/README @@ -68,6 +68,7 @@ Emacs images and their source in the GNOME icons stock/ directory: bookmark_add.xpm actions/bookmark_add cancel.xpm slightly modified generic/stock_stop connect.xpm net/stock_connect + connect-to-url.xpm net/stock_connect-to-url contact.xpm net/stock_contact data-save.xpm data/stock_data-save delete.xpm generic/stock_delete diff --git a/etc/images/connect-to-url.pbm b/etc/images/connect-to-url.pbm new file mode 100644 index 0000000000..f142349f4a Binary files /dev/null and b/etc/images/connect-to-url.pbm differ diff --git a/etc/images/connect-to-url.xpm b/etc/images/connect-to-url.xpm new file mode 100644 index 0000000000..38fefeaf61 --- /dev/null +++ b/etc/images/connect-to-url.xpm @@ -0,0 +1,281 @@ +/* XPM */ +static char *connect_to_url[] = { +/* columns rows colors chars-per-pixel */ +"24 24 251 2 ", +" c black", +". c #010101", +"X c #000103", +"o c #010204", +"O c #010305", +"+ c #020407", +"@ c #020609", +"# c #03070C", +"$ c #04080D", +"% c #0F0F0D", +"& c #030A10", +"* c #050B10", +"= c #060C11", +"- c #070D13", +"; c #070D14", +": c #060C15", +"> c #070E14", +", c #0B1824", +"< c #0A1B2B", +"1 c #0A1C2E", +"2 c #141A20", +"3 c #161E25", +"4 c #181E23", +"5 c #0D2032", +"6 c #142534", +"7 c #1F2830", +"8 c #1D2933", +"9 c #102438", +"0 c #272622", +"q c #21292F", +"w c #272F36", +"e c #282F33", +"r c #222F3A", +"t c #2E3337", +"y c #2D373E", +"u c #32383C", +"i c #33383C", +"p c #343A3E", +"a c #43423C", +"s c #112941", +"d c #102A44", +"f c #132D47", +"g c #192F46", +"h c #17314B", +"j c #15314F", +"k c #163351", +"l c #163554", +"z c #173554", +"x c #1F3A53", +"c c #1D3955", +"v c #1A3958", +"b c #1C3B5B", +"n c #1F3C58", +"m c #1D3C5C", +"M c #1E3E5D", +"N c #1F3F5F", +"B c #303B44", +"V c #313C44", +"C c #313D47", +"Z c #213C56", +"A c #233E57", +"S c #1F405F", +"D c #374148", +"F c #2D4050", +"G c #25405B", +"H c #25425E", +"J c #214262", +"K c #244565", +"L c #264665", +"P c #254666", +"I c #2A4967", +"U c #284969", +"Y c #2A4C6C", +"T c #2C4F6F", +"R c #33526E", +"E c #385269", +"W c #2D5070", +"Q c #2E5172", +"! c #335473", +"~ c #3F5B75", +"^ c #3D5F7D", +"/ c #41494F", +"( c #646056", +") c #6C685E", +"_ c #505F6C", +"` c #48657C", +"' c #556A7A", +"] c #5B6C78", +"[ c #5F6F7B", +"{ c #5D6F7D", +"} c #706C62", +"| c #726D63", +" . c #78756B", +".. c #7D786E", +"X. c #60727F", +"o. c #807D74", +"O. c #8A857B", +"+. c #8B877E", +"@. c #4E6A83", +"#. c #4A6A86", +"$. c #4A7090", +"%. c #587790", +"&. c #5F7E95", +"*. c #587B98", +"=. c #6F7980", +"-. c #697F8F", +";. c #66839B", +":. c #6A879F", +">. c #708391", +",. c #728A9A", +"<. c #748898", +"1. c #758A99", +"2. c #7B8F9F", +"3. c #708DA4", +"4. c #7990A1", +"5. c #7292AB", +"6. c #7691A8", +"7. c #7693AB", +"8. c #7B98AE", +"9. c #7E98AD", +"0. c #7E9DB3", +"q. c #7F9EB4", +"w. c #8C8981", +"e. c #989389", +"r. c #A6A29B", +"t. c #8093A1", +"y. c #8598A3", +"u. c #8498A7", +"i. c #809AAD", +"p. c #8F9FAA", +"a. c #899FAE", +"s. c #819FB5", +"d. c #86A2B8", +"f. c #87A5BB", +"g. c #88A3B8", +"h. c #89A5BA", +"j. c #8FABBF", +"k. c #97A7B1", +"l. c #90AABE", +"z. c #91ABBF", +"x. c #98ACB9", +"c. c #AAA7A0", +"v. c #B1ADA4", +"b. c #B3B1AA", +"n. c #B7B3AA", +"m. c #A3B1BC", +"M. c #A5B1BC", +"N. c #A9B6BF", +"B. c #BEBBB5", +"V. c #C4C2BD", +"C. c #94AEC1", +"Z. c #96AEC1", +"A. c #94AFC2", +"S. c #95AFC2", +"D. c #96B0C3", +"F. c #98B0C3", +"G. c #9FB5C3", +"H. c #99B3C6", +"J. c #98B3C7", +"K. c #9AB3C6", +"L. c #9BB4C7", +"P. c #9FB8CA", +"I. c #9FB8CB", +"U. c #A2B8C9", +"Y. c #A3B9C9", +"T. c #A0B9CB", +"R. c #A3BACB", +"E. c #A0B9CC", +"W. c #A2BACC", +"Q. c #A4BDCE", +"!. c #A6BECF", +"~. c #B8BEC2", +"^. c #B8C3CA", +"/. c #BCC5CB", +"(. c #BDC8CE", +"). c #A8C0D1", +"_. c #AAC0D0", +"`. c #ABC1D1", +"'. c #ACC2D3", +"]. c #AAC5D7", +"[. c #B4C8D6", +"{. c #BDCBD5", +"}. c #B4C9D8", +"|. c #B6CAD8", +" X c #B8CBD9", +".X c #BBCDDB", +"XX c #B7D0E0", +"oX c #BDD3E2", +"OX c #BCD5E5", +"+X c #CECAC3", +"@X c #C5D2C8", +"#X c #C0D2DE", +"$X c #C4D3DF", +"%X c #CCD7DE", +"&X c #D2D8DC", +"*X c #E1DFDB", +"=X c #E2E1DD", +"-X c #C2D3E0", +";X c #C2D4E1", +":X c #C5D5E1", +">X c #C6D6E1", +",X c #C4D6E2", +". e.o. sXwX}.R.R.`.H.1.- JXJX", +"JX4 a.9.C.h.] a n.V.BXo. p.!.T.l.4.- JXJX", +"JX2 F.d.5.7. =XAXc.BXo. @X@XZX !.C.F.@.> JXJX", +" o.=XAXc.BXo. t.U.z.3.Y $ JXJX", +"BXBXBXBXVXBXBXAXVXO.CXo. P.C.!.I.J.C.;.L * JXJX", +"o.o.o.o.o. . .B.b...*X . $.*.T.J.A.h.Y c @ JXJX", +" .w.r.| +X . 1.C.3.L h JXJX", +"JXJX6 Q ^ 1.% w.r.| +X . @X@XHX h.:.M , JXJX", +"JXJXO x T #.] 0 +.} v.) -.s.H 9 O JXJXJX", +"JXJXJX+ n ! i.X.% % e.( Q Y %.0.&.f O JXJXJX", +"JXJXJXJX& A s.8.E A % % A K J R ` g @ JXJXJXJX", +"JXJXJXJXJX@ C ~ m M J N M b v l < O JXJXJXJXJX", +"JXJXJXJXJXJX : 5 d k z k d 1 & JXJXJXJXJXJX", +"JXJXJXJXJXJXJXJX JXJXJXJXJXJXJXJX", +"JXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJX", +"JXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJX" +}; diff --git a/lisp/xwidget.el b/lisp/xwidget.el index 8c593abea8..4046140895 100644 --- a/lisp/xwidget.el +++ b/lisp/xwidget.el @@ -35,8 +35,9 @@ (require 'bookmark) (declare-function make-xwidget "xwidget.c" - (type title width height arguments &optional buffer)) + (type title width height arguments &optional buffer related)) (declare-function xwidget-buffer "xwidget.c" (xwidget)) +(declare-function set-xwidget-buffer "xwidget.c" (xwidget buffer)) (declare-function xwidget-size-request "xwidget.c" (xwidget)) (declare-function xwidget-resize "xwidget.c" (xwidget new-width new-height)) (declare-function xwidget-webkit-execute-script "xwidget.c" @@ -58,14 +59,14 @@ xwidget "Displaying native widgets in Emacs buffers." :group 'widgets) -(defun xwidget-insert (pos type title width height &optional args) +(defun xwidget-insert (pos type title width height &optional args related) "Insert an xwidget at position POS. -Supply the xwidget's TYPE, TITLE, WIDTH, and HEIGHT. +Supply the xwidget's TYPE, TITLE, WIDTH, HEIGHT, and RELATED. See `make-xwidget' for the possible TYPE values. The usage of optional argument ARGS depends on the xwidget. This returns the result of `make-xwidget'." (goto-char pos) - (let ((id (make-xwidget type title width height args))) + (let ((id (make-xwidget type title width height args nil related))) (put-text-property (point) (+ 1 (point)) 'display (list 'xwidget ':xwidget id)) id)) @@ -88,6 +89,9 @@ xwidget-at (require 'seq) (require 'url-handlers) +(defvar-local xwidget-webkit--title "" + "The title of the WebKit widget, used for the header line.") + ;;;###autoload (defun xwidget-webkit-browse-url (url &optional new-session) "Ask xwidget-webkit to browse URL. @@ -124,6 +128,14 @@ xwidget-webkit-clone-and-split-right (with-selected-window (split-window-right) (xwidget-webkit-new-session url)))) +(declare-function xwidget-perform-lispy-event "xwidget.c") + +(defun xwidget-webkit-pass-command-event () + "Pass `last-command-event' to the current buffer's WebKit widget." + (interactive) + (xwidget-perform-lispy-event (xwidget-webkit-current-session) + last-command-event)) + ;;todo. ;; - check that the webkit support is compiled in (defvar xwidget-webkit-mode-map @@ -138,6 +150,9 @@ xwidget-webkit-mode-map (define-key map "w" 'xwidget-webkit-current-url) (define-key map "+" 'xwidget-webkit-zoom-in) (define-key map "-" 'xwidget-webkit-zoom-out) + (define-key map "e" 'xwidget-webkit-edit-mode) + (define-key map "\C-r" 'xwidget-webkit-isearch-mode) + (define-key map "\C-s" 'xwidget-webkit-isearch-mode) ;;similar to image mode bindings (define-key map (kbd "SPC") 'xwidget-webkit-scroll-up) @@ -164,6 +179,63 @@ xwidget-webkit-mode-map map) "Keymap for `xwidget-webkit-mode'.") +(easy-menu-define nil xwidget-webkit-mode-map "Xwidget WebKit menu." + (list "Xwidget WebKit" + ["Browse URL" xwidget-webkit-browse-url + :active t + :help "Prompt for a URL, then instruct WebKit to browse it"] + ["Back" xwidget-webkit-back t] + ["Forward" xwidget-webkit-forward t] + ["Reload" xwidget-webkit-reload t] + ["Insert String" xwidget-webkit-insert-string + :active t + :help "Insert a string into the currently active field"] + ["Zoom In" xwidget-webkit-zoom-in t] + ["Zoom Out" xwidget-webkit-zoom-out t] + ["Edit Mode" xwidget-webkit-edit-mode + :active t + :style toggle + :selected xwidget-webkit-edit-mode + :help "Send self inserting characters to the WebKit widget"] + ["Save Selection" xwidget-webkit-copy-selection-as-kill + :active t + :help "Save the browser's selection in the kill ring"] + ["Incremental Search" xwidget-webkit-isearch-mode + :active (not xwidget-webkit-isearch-mode) + :help "Perform incremental search inside the WebKit widget"])) + +(defvar xwidget-webkit-tool-bar-map + (let ((map (make-sparse-keymap))) + (prog1 map + (tool-bar-local-item-from-menu 'xwidget-webkit-back + "left-arrow" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-forward + "right-arrow" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-reload + "refresh" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-zoom-in + "zoom-in" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-zoom-out + "zoom-out" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-browse-url + "connect-to-url" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-isearch-mode + "search" + map + xwidget-webkit-mode-map)))) + (defun xwidget-webkit-zoom-in () "Increase webkit view zoom factor." (interactive nil xwidget-webkit-mode) @@ -276,6 +348,8 @@ xwidget-webkit-callback (with-current-buffer (xwidget-buffer xwidget) (cond ((eq xwidget-event-type 'load-changed) (let ((title (xwidget-webkit-title xwidget))) + (setq xwidget-webkit--title title) + (force-mode-line-update) (xwidget-log "webkit finished loading: %s" title) ;; Do not adjust webkit size to window here, the selected window ;; can be the mini-buffer window unwantedly. @@ -309,8 +383,10 @@ bookmark-make-record-function (define-derived-mode xwidget-webkit-mode special-mode "xwidget-webkit" "Xwidget webkit view mode." (setq buffer-read-only t) + (setq-local tool-bar-map xwidget-webkit-tool-bar-map) (setq-local bookmark-make-record-function #'xwidget-webkit-bookmark-make-record) + (setq-local header-line-format 'xwidget-webkit--title) ;; Keep track of [vh]scroll when switching buffers (image-mode-setup-winprops)) @@ -609,6 +685,7 @@ xwidget-webkit-new-session (let* ((bufname (generate-new-buffer-name "*xwidget-webkit*")) (callback (or callback #'xwidget-webkit-callback)) + (current-session (xwidget-webkit-current-session)) xw) (setq xwidget-webkit-last-session-buffer (switch-to-buffer (get-buffer-create bufname))) @@ -621,11 +698,35 @@ xwidget-webkit-new-session (setq xw (xwidget-insert start 'webkit bufname (xwidget-window-inside-pixel-width (selected-window)) - (xwidget-window-inside-pixel-height (selected-window))))) + (xwidget-window-inside-pixel-height (selected-window)) + nil current-session))) (xwidget-put xw 'callback callback) (xwidget-webkit-mode) (xwidget-webkit-goto-uri (xwidget-webkit-last-session) url))) +(defun xwidget-webkit-import-widget (xwidget) + "Create a new webkit session buffer from XWIDGET, an existing xwidget. +Return the buffer." + (let* ((bufname (generate-new-buffer-name "*xwidget-webkit*")) + (callback #'xwidget-webkit-callback) + (buffer (get-buffer-create bufname))) + (with-current-buffer buffer + (save-excursion + (erase-buffer) + (insert ".") + (put-text-property (point-min) (point-max) + 'display (list 'xwidget :xwidget xwidget))) + (xwidget-put xwidget 'callback callback) + (set-xwidget-buffer xwidget buffer) + (xwidget-webkit-mode)) + buffer)) + +(defun xwidget-webkit-display-event (event) + "Import the xwidget inside EVENT and display it." + (interactive "e") + (display-buffer (xwidget-webkit-import-widget (nth 1 event)))) + +(global-set-key [xwidget-display-event] 'xwidget-webkit-display-event) (defun xwidget-webkit-goto-url (url) "Goto URL with xwidget webkit." @@ -684,6 +785,165 @@ xwidget-put (set-xwidget-plist xwidget (plist-put (xwidget-plist xwidget) propname value))) +(defvar xwidget-webkit-edit-mode-map (make-keymap)) + +(define-key xwidget-webkit-edit-mode-map [backspace] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [tab] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [left] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [right] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [up] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [down] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [return] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-left] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-right] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-up] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-down] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-return] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-left] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-right] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-up] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-down] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-return] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-left] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-right] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-up] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-down] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-return] 'xwidget-webkit-pass-command-event) + +(define-minor-mode xwidget-webkit-edit-mode + "Minor mode for editing the content of WebKit buffers. + +This defines most self-inserting characters and some common +keyboard shortcuts to `xwidget-webkit-pass-command-event', which +will pass the key events corresponding to these characters to the +WebKit widget." + :keymap xwidget-webkit-edit-mode-map) + +(substitute-key-definition 'self-insert-command + 'xwidget-webkit-pass-command-event + xwidget-webkit-edit-mode-map + global-map) + +(declare-function xwidget-webkit-search "xwidget.c") +(declare-function xwidget-webkit-next-result "xwidget.c") +(declare-function xwidget-webkit-previous-result "xwidget.c") +(declare-function xwidget-webkit-finish-search "xwidget.c") + +(defvar-local xwidget-webkit-isearch--string "" + "The current search query.") +(defvar-local xwidget-webkit-isearch--is-reverse nil + "Whether or not the current isearch should be reverse.") + +(defun xwidget-webkit-isearch--update (&optional only-message) + "Update the current buffer's WebKit widget's search query. +If ONLY-MESSAGE is non-nil, the query will not be sent to the +WebKit widget. The query will be set to the contents of +`xwidget-webkit-isearch--string'." + (unless only-message + (xwidget-webkit-search xwidget-webkit-isearch--string + (xwidget-webkit-current-session) + t xwidget-webkit-isearch--is-reverse t)) + (message (concat (propertize "Search contents: " 'face 'minibuffer-prompt) + xwidget-webkit-isearch--string))) + +(defun xwidget-webkit-isearch-erasing-char (count) + "Erase the last COUNT characters of the current query." + (interactive (list (prefix-numeric-value current-prefix-arg))) + (when (> (length xwidget-webkit-isearch--string) 0) + (setq xwidget-webkit-isearch--string + (substring xwidget-webkit-isearch--string 0 + (- (length xwidget-webkit-isearch--string) count)))) + (xwidget-webkit-isearch--update)) + +(defun xwidget-webkit-isearch-printing-char (char &optional count) + "Add ordinary character CHAR to the search string and search. +With argument, add COUNT copies of CHAR." + (interactive (list last-command-event + (prefix-numeric-value current-prefix-arg))) + (setq xwidget-webkit-isearch--string (concat xwidget-webkit-isearch--string + (make-string (or count 1) char))) + (xwidget-webkit-isearch--update)) + +(defun xwidget-webkit-isearch-forward (count) + "Move to the next search result COUNT times." + (interactive (list (prefix-numeric-value current-prefix-arg))) + (let ((was-reverse xwidget-webkit-isearch--is-reverse)) + (setq xwidget-webkit-isearch--is-reverse nil) + (when was-reverse + (xwidget-webkit-isearch--update))) + (let ((i 0)) + (while (< i count) + (xwidget-webkit-next-result (xwidget-webkit-current-session)) + (cl-incf i))) + (xwidget-webkit-isearch--update t)) + +(defun xwidget-webkit-isearch-backward (count) + "Move to the previous search result COUNT times." + (interactive (list (prefix-numeric-value current-prefix-arg))) + (let ((was-reverse xwidget-webkit-isearch--is-reverse)) + (setq xwidget-webkit-isearch--is-reverse t) + (unless was-reverse + (xwidget-webkit-isearch--update))) + (let ((i 0)) + (while (< i count) + (xwidget-webkit-next-result (xwidget-webkit-current-session)) + (cl-incf i))) + (xwidget-webkit-isearch--update t)) + +(defun xwidget-webkit-isearch-exit () + "Exit incremental search of a WebKit buffer." + (interactive) + (xwidget-webkit-isearch-mode 0)) + +(defvar xwidget-webkit-isearch-mode-map (make-keymap) + "The keymap used inside xwidget-webkit-isearch-mode.") + +(set-char-table-range (nth 1 xwidget-webkit-isearch-mode-map) + (cons 0 (max-char)) + 'xwidget-webkit-isearch-exit) + +(substitute-key-definition 'self-insert-command + 'xwidget-webkit-isearch-printing-char + xwidget-webkit-isearch-mode-map + global-map) + +(define-key xwidget-webkit-isearch-mode-map (kbd "DEL") + 'xwidget-webkit-isearch-erasing-char) +(define-key xwidget-webkit-isearch-mode-map [return] 'xwidget-webkit-isearch-exit) +(define-key xwidget-webkit-isearch-mode-map "\r" 'xwidget-webkit-isearch-exit) +(define-key xwidget-webkit-isearch-mode-map "\C-g" 'xwidget-webkit-isearch-exit) +(define-key xwidget-webkit-isearch-mode-map "\C-r" 'xwidget-webkit-isearch-backward) +(define-key xwidget-webkit-isearch-mode-map "\C-s" 'xwidget-webkit-isearch-forward) +(define-key xwidget-webkit-isearch-mode-map "\t" 'xwidget-webkit-isearch-printing-char) + +(let ((meta-map (make-keymap))) + (set-char-table-range (nth 1 meta-map) + (cons 0 (max-char)) + 'xwidget-webkit-isearch-exit) + (define-key xwidget-webkit-isearch-mode-map (char-to-string meta-prefix-char) meta-map)) + +(define-minor-mode xwidget-webkit-isearch-mode + "Minor mode for performing incremental search inside WebKit buffers. + +An attempt was made for this to resemble regular incremental +search, but it suffers from several limitations, such as not +supporting recursive edits. + +If this mode is enabled with `C-r', then the search will default +to being performed in reverse direction. + +To navigate around the search results, type +\\[xwidget-webkit-isearch-forward] to move forward, and +\\[xwidget-webkit-isearch-backward] to move backward. + +Press \\[xwidget-webkit-isearch-exit] to exit incremental search." + :keymap xwidget-webkit-isearch-mode-map + (if xwidget-webkit-isearch-mode + (progn + (setq xwidget-webkit-isearch--string "") + (setq xwidget-webkit-isearch--is-reverse (eq last-command-event ?\C-r)) + (xwidget-webkit-isearch--update)) + (xwidget-webkit-finish-search (xwidget-webkit-current-session)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/src/dispextern.h b/src/dispextern.h index 5b28fe7666..f17f095e0d 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -536,8 +536,8 @@ #define FACE_ID_BITS 20 int img_id; #ifdef HAVE_XWIDGETS - /* Xwidget reference (type == XWIDGET_GLYPH). */ - struct xwidget *xwidget; + /* Xwidget ID. */ + uint32_t xwidget; #endif /* Sub-structure for type == STRETCH_GLYPH. */ diff --git a/src/dispnew.c b/src/dispnew.c index 4a73244c89..632eec2f03 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -4449,16 +4449,6 @@ scrolling_window (struct window *w, int tab_line_p) break; } -#ifdef HAVE_XWIDGETS - /* Currently this seems needed to detect xwidget movement reliably. - This is most probably because an xwidget glyph is represented in - struct glyph's 'union u' by a pointer to a struct, which takes 8 - bytes in 64-bit builds, and thus the comparison of u.val values - done by GLYPH_EQUAL_P doesn't work reliably, since it assumes the - size of the union is 4 bytes. FIXME. */ - return 0; -#endif - /* Can't scroll the display of w32 GUI frames when position of point is indicated by the system caret, because scrolling the display will then "copy" the pixels used by the caret. */ diff --git a/src/keyboard.c b/src/keyboard.c index aa6a4b9e97..c4a5671b10 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -3993,6 +3993,7 @@ kbd_buffer_get_event (KBOARD **kbp, #endif #ifdef HAVE_XWIDGETS case XWIDGET_EVENT: + case XWIDGET_DISPLAY_EVENT: #endif case SAVE_SESSION_EVENT: case NO_EVENT: @@ -4897,7 +4898,7 @@ #define FUNCTION_KEY_OFFSET 0xff00 /* You'll notice that this table is arranged to be conveniently indexed by X Windows keysym values. */ -static const char *const lispy_function_keys[] = +const char *const lispy_function_keys[] = { /* X Keysym value */ @@ -6139,6 +6140,11 @@ make_lispy_event (struct input_event *event) { return Fcons (Qxwidget_event, event->arg); } + + case XWIDGET_DISPLAY_EVENT: + { + return list2 (Qxwidget_display_event, event->arg); + } #endif #ifdef USE_FILE_NOTIFY @@ -11732,6 +11738,7 @@ syms_of_keyboard (void) #ifdef HAVE_XWIDGETS DEFSYM (Qxwidget_event, "xwidget-event"); + DEFSYM (Qxwidget_display_event, "xwidget-display-event"); #endif #ifdef USE_FILE_NOTIFY diff --git a/src/keyboard.h b/src/keyboard.h index 8bdffaa2bf..21c51ec386 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -491,7 +491,7 @@ kbd_buffer_store_event_hold (struct input_event *event, extern struct timespec timer_check (void); extern void mark_kboards (void); -#ifdef HAVE_NTGUI +#if defined HAVE_NTGUI || defined HAVE_X_WINDOWS extern const char *const lispy_function_keys[]; #endif diff --git a/src/print.c b/src/print.c index c13294c8e6..eca389158f 100644 --- a/src/print.c +++ b/src/print.c @@ -1521,8 +1521,20 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag, printchar ('>', printcharfun); break; - case PVEC_XWIDGET: case PVEC_XWIDGET_VIEW: - print_c_string ("#", + XXWIDGET (obj)->xwidget_id, + XXWIDGET (obj)->widget_osr); + strout (buf, len, len, printcharfun); + break; + } +#else + emacs_abort (); +#endif + case PVEC_XWIDGET_VIEW: + print_c_string ("#', printcharfun); break; diff --git a/src/termhooks.h b/src/termhooks.h index 1d3cdc8fe8..e7539bbce2 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -255,6 +255,8 @@ #define EMACS_TERMHOOKS_H #ifdef HAVE_XWIDGETS /* events generated by xwidgets*/ , XWIDGET_EVENT + /* Event generated when WebKit asks us to display another widget. */ + , XWIDGET_DISPLAY_EVENT #endif #ifdef USE_FILE_NOTIFY diff --git a/src/xdisp.c b/src/xdisp.c index 86c4e704d5..d7ad548917 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -28429,7 +28429,7 @@ fill_xwidget_glyph_string (struct glyph_string *s) } s->width = s->first_glyph->pixel_width; s->ybase += s->first_glyph->voffset; - s->xwidget = s->first_glyph->u.xwidget; + s->xwidget = xwidget_from_id (s->first_glyph->u.xwidget); } #endif /* Fill glyph string S from a sequence of stretch glyphs. @@ -29832,7 +29832,7 @@ produce_xwidget_glyph (struct it *it) glyph->padding_p = 0; glyph->glyph_not_available_p = 0; glyph->face_id = it->face_id; - glyph->u.xwidget = it->xwidget; + glyph->u.xwidget = it->xwidget->xwidget_id; glyph->font_type = FONT_TYPE_UNKNOWN; if (it->bidi_p) { diff --git a/src/xterm.c b/src/xterm.c index aa1a1a5eed..9b434bffcc 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -4390,6 +4390,86 @@ x_scroll_run (struct window *w, struct run *run) /* Cursor off. Will be switched on again in gui_update_window_end. */ gui_clear_cursor (w); +#ifdef HAVE_XWIDGETS + /* "Copy" xwidget windows in the area that will be scrolled. */ + Display *dpy = FRAME_X_DISPLAY (f); + Window window = FRAME_X_WINDOW (f); + + Window root, parent, *children; + unsigned int nchildren; + + if (XQueryTree (dpy, window, &root, &parent, &children, &nchildren)) + { + /* Now find xwidget views situated between from_y and to_y, and + attached to w. */ + for (unsigned int i = 0; i < nchildren; ++i) + { + Window child = children[i]; + struct xwidget_view *view = xwidget_view_from_window (child); + + if (view) + { + 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; + XUnmapWindow (dpy, child); + 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, TEXT_AREA, &text_area_x, &text_area_y, + &text_area_width, &text_area_height); + + clip_top = max (0, text_area_y - y); + clip_bottom = max (clip_top, + min (XXWIDGET (view->model)->height, + text_area_y + text_area_height - y)); + + view->y = y; + 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_top - view->clip_bottom) <= 0) + { + view->hidden = true; + XUnmapWindow (dpy, child); + } + else + XMoveResizeWindow (dpy, child, view->x + view->clip_left, + view->y + view->clip_top, + view->clip_right - view->clip_left, + view->clip_top - view->clip_bottom); + XFlush (dpy); + } + } + } + XFree (children); + } +#endif + #ifdef USE_CAIRO if (FRAME_CR_CONTEXT (f)) { @@ -4563,8 +4643,9 @@ x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct fra } } -/* Return the Emacs frame-object corresponding to an X window. - It could be the frame's main window or an icon window. */ +/* Return the Emacs frame-object corresponding to an X window. It + could be the frame's main window, an icon window, or an xwidget + window. */ static struct frame * x_window_to_frame (struct x_display_info *dpyinfo, int wdesc) @@ -4575,6 +4656,13 @@ x_window_to_frame (struct x_display_info *dpyinfo, int wdesc) if (wdesc == None) return NULL; +#ifdef HAVE_XWIDGETS + struct xwidget_view *xvw = xwidget_view_from_window (wdesc); + + if (xvw && xvw->frame) + return xvw->frame; +#endif + FOR_EACH_FRAME (tail, frame) { f = XFRAME (frame); @@ -4997,7 +5085,7 @@ x_x_to_emacs_modifiers (struct x_display_info *dpyinfo, int state) | ((state & dpyinfo->hyper_mod_mask) ? mod_hyper : 0)); } -static int +int x_emacs_to_x_modifiers (struct x_display_info *dpyinfo, intmax_t state) { EMACS_INT mod_ctrl = ctrl_modifier; @@ -8211,6 +8299,18 @@ handle_one_xevent (struct x_display_info *dpyinfo, case Expose: f = x_window_to_frame (dpyinfo, event->xexpose.window); +#ifdef HAVE_XWIDGETS + { + struct xwidget_view *xv = + xwidget_view_from_window (event->xexpose.window); + + if (xv) + { + xwidget_expose (xv); + goto OTHER; + } + } +#endif if (f) { if (!FRAME_VISIBLE_P (f)) @@ -8791,6 +8891,31 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_display_set_last_user_time (dpyinfo, event->xcrossing.time); x_detect_focus_change (dpyinfo, any, event, &inev.ie); +#ifdef HAVE_XWIDGETS + { + struct xwidget_view *xvw = xwidget_view_from_window (event->xcrossing.window); + Mouse_HLInfo *hlinfo; + + if (xvw) + { + xwidget_motion_or_crossing (xvw, event); + hlinfo = MOUSE_HL_INFO (xvw->frame); + + if (xvw->frame == hlinfo->mouse_face_mouse_frame) + { + clear_mouse_face (hlinfo); + hlinfo->mouse_face_mouse_frame = 0; + } + + if (any_help_event_p) + { + do_help = -1; + } + goto OTHER; + } + } +#endif + f = any; if (f && x_mouse_click_focus_ignore_position) @@ -8834,6 +8959,17 @@ handle_one_xevent (struct x_display_info *dpyinfo, goto OTHER; case LeaveNotify: +#ifdef HAVE_XWIDGETS + { + struct xwidget_view *xvw = xwidget_view_from_window (event->xcrossing.window); + + if (xvw) + { + xwidget_motion_or_crossing (xvw, event); + goto OTHER; + } + } +#endif x_display_set_last_user_time (dpyinfo, event->xcrossing.time); x_detect_focus_change (dpyinfo, any, event, &inev.ie); @@ -8883,6 +9019,12 @@ handle_one_xevent (struct x_display_info *dpyinfo, #ifdef USE_GTK if (f && xg_event_is_for_scrollbar (f, event)) f = 0; +#endif +#ifdef HAVE_XWIDGETS + struct xwidget_view *xvw = xwidget_view_from_window (event->xmotion.window); + + if (xvw) + xwidget_motion_or_crossing (xvw, event); #endif if (f) { @@ -9138,6 +9280,24 @@ handle_one_xevent (struct x_display_info *dpyinfo, case ButtonRelease: case ButtonPress: { +#ifdef HAVE_XWIDGETS + struct xwidget_view *xvw = xwidget_view_from_window (event->xmotion.window); + + if (xvw) + { + xwidget_button (xvw, event->type == ButtonPress, + event->xbutton.x, event->xbutton.y, + event->xbutton.button, event->xbutton.state, + event->xbutton.time); + + if (!EQ (selected_window, xvw->w)) + { + inev.ie.kind = SELECT_WINDOW_EVENT; + inev.ie.frame_or_window = xvw->w; + } + goto OTHER; + } +#endif /* If we decide we want to generate an event to be seen by the rest of Emacs, we put it here. */ Lisp_Object tab_bar_arg = Qnil; @@ -12108,6 +12268,10 @@ x_free_frame_resources (struct frame *f) xfree (f->shell_position); #else /* !USE_X_TOOLKIT */ +#ifdef HAVE_XWIDGETS + kill_frame_xwidget_views (f); +#endif + #ifdef USE_GTK xg_free_frame_widgets (f); #endif /* USE_GTK */ diff --git a/src/xterm.h b/src/xterm.h index de6ea50385..9d9534dd62 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -1108,6 +1108,7 @@ #define SELECTION_EVENT_TIME(eventp) \ extern int x_dispatch_event (XEvent *, Display *); #endif extern int x_x_to_emacs_modifiers (struct x_display_info *, int); +extern int x_emacs_to_x_modifiers (struct x_display_info *, intmax_t); #ifdef USE_CAIRO extern void x_cr_destroy_frame_context (struct frame *); extern void x_cr_update_surface_desired_size (struct frame *, int, int); diff --git a/src/xwidget.c b/src/xwidget.c index e4b42e6e0c..90aac4e092 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -19,6 +19,7 @@ Copyright (C) 2011-2021 Free Software Foundation, Inc. #include +#include "buffer.h" #include "xwidget.h" #include "lisp.h" @@ -35,10 +36,22 @@ Copyright (C) 2011-2021 Free Software Foundation, Inc. #ifdef USE_GTK #include #include +#include +#include #elif defined NS_IMPL_COCOA #include "nsxwidget.h" #endif +static Lisp_Object id_to_xwidget_map; +static uint32_t xwidget_counter = 0; + +#ifdef USE_GTK +static Lisp_Object x_window_to_xwv_map; +static gboolean offscreen_damage_event (GtkWidget *, GdkEvent *, gpointer); +static void synthesize_focus_in_event (GtkWidget *); +static GdkDevice *find_suitable_keyboard (struct frame *); +#endif + static struct xwidget * allocate_xwidget (void) { @@ -64,18 +77,32 @@ #define XSETXWIDGET_VIEW(a, b) XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW) GAsyncResult *, gpointer); static gboolean webkit_download_cb (WebKitWebContext *, WebKitDownload *, gpointer); - +static GtkWidget *webkit_create_cb (WebKitWebView *, WebKitNavigationAction *, gpointer); static gboolean webkit_decide_policy_cb (WebKitWebView *, WebKitPolicyDecision *, WebKitPolicyDecisionType, gpointer); +static GtkWidget *find_widget_at_pos (GtkWidget *, int, int, int *, int *); + +struct widget_search_data +{ + int x; + int y; + bool foundp; + bool first; + GtkWidget *data; +}; + +static void find_widget (GtkWidget *t, struct widget_search_data *); +static void mouse_target_changed (WebKitWebView *, WebKitHitTestResult *, guint, + gpointer); #endif DEFUN ("make-xwidget", Fmake_xwidget, Smake_xwidget, - 5, 6, 0, + 5, 7, 0, doc: /* Make an xwidget of TYPE. If BUFFER is nil, use the current buffer. If BUFFER is a string and no such buffer exists, create it. @@ -83,10 +110,13 @@ DEFUN ("make-xwidget", - webkit -Returns the newly constructed xwidget, or nil if construction fails. */) +RELATED is nil, or an xwidget. When constructing a WebKit widget, it +will share the same settings and internal subprocess as RELATED. +Returns the newly constructed xwidget, or nil if construction +fails. */) (Lisp_Object type, Lisp_Object title, Lisp_Object width, Lisp_Object height, - Lisp_Object arguments, Lisp_Object buffer) + Lisp_Object arguments, Lisp_Object buffer, Lisp_Object related) { #ifdef USE_GTK if (!xg_gtk_initialized) @@ -108,13 +138,19 @@ DEFUN ("make-xwidget", XSETXWIDGET (val, xw); Vxwidget_list = Fcons (val, Vxwidget_list); xw->plist = Qnil; + xw->xwidget_id = ++xwidget_counter; + + Fputhash (make_fixnum (xw->xwidget_id), val, id_to_xwidget_map); #ifdef USE_GTK xw->widgetwindow_osr = NULL; xw->widget_osr = NULL; + xw->hit_result = 0; + xw->find_text = NULL; if (EQ (xw->type, Qwebkit)) { block_input (); + WebKitSettings *settings; WebKitWebContext *webkit_context = webkit_web_context_get_default (); # if WEBKIT_CHECK_VERSION (2, 26, 0) @@ -128,18 +164,34 @@ DEFUN ("make-xwidget", if (EQ (xw->type, Qwebkit)) { - xw->widget_osr = webkit_web_view_new (); - - /* webkitgtk uses GSubprocess which sets sigaction causing - Emacs to not catch SIGCHLD with its usual handle setup in - catch_child_signal(). This resets the SIGCHLD - sigaction. */ - struct sigaction old_action; - sigaction (SIGCHLD, NULL, &old_action); - webkit_web_view_load_uri(WEBKIT_WEB_VIEW (xw->widget_osr), - "about:blank"); - sigaction (SIGCHLD, &old_action, NULL); - } + WebKitWebView *related_view; + + if (NILP (related) + || !XWIDGETP (related) + || !EQ (XXWIDGET (related)->type, Qwebkit)) + { + xw->widget_osr = webkit_web_view_new (); + + /* webkitgtk uses GSubprocess which sets sigaction causing + Emacs to not catch SIGCHLD with its usual handle setup in + catch_child_signal(). This resets the SIGCHLD + sigaction. */ + struct sigaction old_action; + sigaction (SIGCHLD, NULL, &old_action); + webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr), + "about:blank"); + sigaction (SIGCHLD, &old_action, NULL); + } + else + { + related_view = WEBKIT_WEB_VIEW (XXWIDGET (related)->widget_osr); + xw->widget_osr = webkit_web_view_new_with_related_view (related_view); + } + + /* Enable the developer extras */ + settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (xw->widget_osr)); + g_object_set (G_OBJECT (settings), "enable-developer-extras", TRUE, NULL); + } gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height); @@ -157,6 +209,7 @@ DEFUN ("make-xwidget", gtk_widget_show (xw->widget_osr); gtk_widget_show (xw->widgetwindow_osr); + synthesize_focus_in_event (xw->widgetwindow_osr); /* Store some xwidget data in the gtk widgets for convenient retrieval in the event handlers. */ @@ -179,8 +232,20 @@ DEFUN ("make-xwidget", G_CALLBACK (webkit_decide_policy_cb), xw); + + g_signal_connect (G_OBJECT (xw->widget_osr), + "mouse-target-changed", + G_CALLBACK (mouse_target_changed), + xw); + g_signal_connect (G_OBJECT (xw->widget_osr), + "create", + G_CALLBACK (webkit_create_cb), + xw); } + g_signal_connect (G_OBJECT (xw->widgetwindow_osr), "damage-event", + G_CALLBACK (offscreen_damage_event), xw); + unblock_input (); } #elif defined NS_IMPL_COCOA @@ -190,6 +255,158 @@ DEFUN ("make-xwidget", return val; } +#ifdef USE_GTK +static void +set_widget_if_text_view (GtkWidget *widget, void *data) +{ + GtkWidget **pointer = data; + + if (GTK_IS_TEXT_VIEW (widget)) + { + *pointer = widget; + } +} +#endif + +DEFUN ("xwidget-perform-lispy-event", + Fxwidget_perform_lispy_event, Sxwidget_perform_lispy_event, + 2, 3, 0, doc: /* Send a lispy event to XWIDGET. +EVENT should be the event that will be sent. FRAME should be the +frame which generated the event, or nil. On X11, modifier keys will +not be processed if FRAME is nil and the selected frame is not an +X-Windows frame. */) + (Lisp_Object xwidget, Lisp_Object event, Lisp_Object frame) +{ + struct xwidget *xw; + struct frame *f = NULL; + int character = -1, keycode = -1; + int modifiers = 0; + +#ifdef USE_GTK + GdkEvent *xg_event; + GtkContainerClass *klass; + GtkWidget *widget; + GtkWidget *temp = NULL; +#endif + + CHECK_XWIDGET (xwidget); + xw = XXWIDGET (xwidget); + + if (!NILP (frame)) + f = decode_window_system_frame (frame); + else if (FRAME_X_P (SELECTED_FRAME ())) + f = SELECTED_FRAME (); + +#ifdef USE_GTK + widget = gtk_window_get_focus (GTK_WINDOW (xw->widgetwindow_osr)); + + if (!widget) + widget = xw->widget_osr; + + if (RANGED_FIXNUMP (0, event, INT_MAX)) + { + character = XFIXNUM (event); + + if (character < 32) + modifiers |= ctrl_modifier; + + modifiers |= character & meta_modifier; + modifiers |= character & hyper_modifier; + modifiers |= character & super_modifier; + modifiers |= character & shift_modifier; + modifiers |= character & ctrl_modifier; + + character = character & ~(1 << 21); + + if (character < 32) + character += '_'; + + if (f) + modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f), modifiers); + else + modifiers = 0; + } + else if (SYMBOLP (event)) + { + Lisp_Object decoded = parse_modifiers (event); + Lisp_Object decoded_name = SYMBOL_NAME (XCAR (decoded)); + + int off = 0; + bool found = false; + + while (off < 256) + { + if (lispy_function_keys[off] + && !strcmp (lispy_function_keys[off], + SSDATA (decoded_name))) + { + found = true; + break; + } + ++off; + } + + if (f) + modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f), + XFIXNUM (XCAR (XCDR (decoded)))); + else + modifiers = 0; + + if (found) + keycode = off + 0xff00; + } + + if (character == -1 && keycode == -1) + return Qnil; + + block_input (); + xg_event = gdk_event_new (GDK_KEY_PRESS); + xg_event->any.window = gtk_widget_get_window (xw->widget_osr); + g_object_ref (xg_event->any.window); + + if (character > -1) + keycode = gdk_unicode_to_keyval (character); + + xg_event->key.keyval = keycode; + xg_event->key.state = modifiers; + + if (keycode > -1) + { + /* WebKitGTK internals abuse follows. */ + if (WEBKIT_IS_WEB_VIEW (widget)) + { + /* WebKitGTK relies on an internal GtkTextView object to + "translate" keys such as backspace. We must find that + widget and activate its binding to this key if any. */ + klass = GTK_CONTAINER_CLASS (G_OBJECT_GET_CLASS (widget)); + + klass->forall (GTK_CONTAINER (xw->widget_osr), TRUE, + set_widget_if_text_view, &temp); + + if (GTK_IS_WIDGET (temp)) + { + if (!gtk_widget_get_realized (temp)) + gtk_widget_realize (temp); + + gtk_bindings_activate (G_OBJECT (temp), keycode, modifiers); + } + } + } + + if (f) + gdk_event_set_device (xg_event, + find_suitable_keyboard (SELECTED_FRAME ())); + + gtk_main_do_event (xg_event); + xg_event->type = GDK_KEY_RELEASE; + gtk_main_do_event (xg_event); + gdk_event_free (xg_event); + unblock_input (); +#endif + + return Qnil; +} + DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets, Sget_buffer_xwidgets, 1, 1, 0, doc: /* Return a list of xwidgets associated with BUFFER. @@ -221,16 +438,397 @@ xwidget_hidden (struct xwidget_view *xv) return xv->hidden; } +struct xwidget * +xwidget_from_id (uint32_t id) +{ + Lisp_Object key = make_fixnum (id); + Lisp_Object xwidget = Fgethash (key, id_to_xwidget_map, Qnil); + + if (NILP (xwidget)) + emacs_abort (); + + return XXWIDGET (xwidget); +} + #ifdef USE_GTK + +static GdkDevice * +find_suitable_pointer (struct frame *f) +{ + GdkSeat *seat = gdk_display_get_default_seat + (gtk_widget_get_display (FRAME_GTK_WIDGET (f))); + + if (!seat) + return NULL; + + return gdk_seat_get_pointer (seat); +} + +static GdkDevice * +find_suitable_keyboard (struct frame *f) +{ + GdkSeat *seat = gdk_display_get_default_seat + (gtk_widget_get_display (FRAME_GTK_WIDGET (f))); + + if (!seat) + return NULL; + + return gdk_seat_get_keyboard (seat); +} + +static void +find_widget_cb (GtkWidget *widget, void *user) +{ + find_widget (widget, user); +} + +static void +find_widget (GtkWidget *widget, + struct widget_search_data *data) +{ + GtkAllocation new_allocation; + GdkWindow *window; + int x_offset = 0; + int y_offset = 0; + + gtk_widget_get_allocation (widget, &new_allocation); + + if (gtk_widget_get_has_window (widget)) + { + new_allocation.x = 0; + new_allocation.y = 0; + } + + if (gtk_widget_get_parent (widget) && !data->first) + { + window = gtk_widget_get_window (widget); + while (window != gtk_widget_get_window (gtk_widget_get_parent (widget))) + { + gint tx, ty, twidth, theight; + + if (!window) + return; + + twidth = gdk_window_get_width (window); + theight = gdk_window_get_height (window); + + if (new_allocation.x < 0) + { + new_allocation.width += new_allocation.x; + new_allocation.x = 0; + } + + if (new_allocation.y < 0) + { + new_allocation.height += new_allocation.y; + new_allocation.y = 0; + } + + if (new_allocation.x + new_allocation.width > twidth) + new_allocation.width = twidth - new_allocation.x; + if (new_allocation.y + new_allocation.height > theight) + new_allocation.height = theight - new_allocation.y; + + gdk_window_get_position (window, &tx, &ty); + new_allocation.x += tx; + x_offset += tx; + new_allocation.y += ty; + y_offset += ty; + + window = gdk_window_get_parent (window); + } + } + + if ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) && + (data->x < new_allocation.x + new_allocation.width) && + (data->y < new_allocation.y + new_allocation.height)) + { + /* First, check if the drag is in a valid drop site in + * one of our children + */ + if (GTK_IS_CONTAINER (widget)) + { + struct widget_search_data new_data = *data; + + new_data.x -= x_offset; + new_data.y -= y_offset; + new_data.foundp = false; + new_data.first = false; + + gtk_container_forall (GTK_CONTAINER (widget), + find_widget_cb, &new_data); + + data->foundp = new_data.foundp; + if (data->foundp) + data->data = new_data.data; + } + + /* If not, and this widget is registered as a drop site, check to + * emit "drag_motion" to check if we are actually in + * a drop site. + */ + if (!data->foundp) + { + data->foundp = true; + data->data = widget; + } + } +} + +static GtkWidget * +find_widget_at_pos (GtkWidget *w, int x, int y, + int *new_x, int *new_y) +{ + struct widget_search_data data; + + data.x = x; + data.y = y; + data.foundp = false; + data.first = true; + + find_widget (w, &data); + + if (data.foundp) + { + gtk_widget_translate_coordinates (w, data.data, x, + y, new_x, new_y); + return data.data; + } + + *new_x = x; + *new_y = y; + + return NULL; +} + +static Emacs_Cursor +cursor_for_hit (guint result, struct frame *frame) +{ + Emacs_Cursor cursor = FRAME_OUTPUT_DATA (frame)->nontext_cursor; + + if ((result & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE) + || (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION) + || (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT)) + cursor = FRAME_X_OUTPUT (frame)->text_cursor; + + if (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR) + cursor = FRAME_X_OUTPUT (frame)->vertical_drag_cursor; + + if (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK) + cursor = FRAME_X_OUTPUT (frame)->hand_cursor; + + return cursor; +} + +static void +define_cursors (struct xwidget *xw, WebKitHitTestResult *res) +{ + struct xwidget_view *xvw; + + xw->hit_result = webkit_hit_test_result_get_context (res); + + for (Lisp_Object tem = Vxwidget_view_list; CONSP (tem); + tem = XCDR (tem)) + { + if (XWIDGET_VIEW_P (XCAR (tem))) + { + xvw = XXWIDGET_VIEW (XCAR (tem)); + + if (XXWIDGET (xvw->model) == xw) + { + xvw->cursor = cursor_for_hit (xw->hit_result, xvw->frame); + if (xvw->wdesc != None) + XDefineCursor (xvw->dpy, xvw->wdesc, xvw->cursor); + } + } + } +} + +static void +mouse_target_changed (WebKitWebView *webview, + WebKitHitTestResult *hitresult, + guint modifiers, gpointer xw) +{ + define_cursors (xw, hitresult); +} + + +static void +xwidget_button_1 (struct xwidget_view *view, + bool down_p, int x, int y, int button, + int modifier_state, Time time) +{ + GdkEvent *xg_event = gdk_event_new (down_p ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE); + struct xwidget *model = XXWIDGET (view->model); + GtkWidget *target; + + /* X and Y should be relative to the origin of view->wdesc. */ + x += view->clip_left; + y += view->clip_top; + + target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y); + + if (!target) + target = model->widget_osr; + + xg_event->any.window = gtk_widget_get_window (target); + g_object_ref (xg_event->any.window); /* The window will be unrefed + later by gdk_event_free. */ + + xg_event->button.x = x; + xg_event->button.x_root = x; + xg_event->button.y = y; + xg_event->button.y_root = y; + xg_event->button.button = button; + xg_event->button.state = modifier_state; + xg_event->button.time = time; + xg_event->button.device = find_suitable_pointer (view->frame); + + gtk_main_do_event (xg_event); + gdk_event_free (xg_event); +} + +void +xwidget_button (struct xwidget_view *view, + bool down_p, int x, int y, int button, + int modifier_state, Time time) +{ + if (button < 4 || button > 8) + xwidget_button_1 (view, down_p, x, y, button, modifier_state, time); + else + { + GdkEvent *xg_event = gdk_event_new (GDK_SCROLL); + struct xwidget *model = XXWIDGET (view->model); + GtkWidget *target; + + x += view->clip_left; + y += view->clip_top; + + target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y); + + if (!target) + target = model->widget_osr; + + xg_event->any.window = gtk_widget_get_window (target); + g_object_ref (xg_event->any.window); /* The window will be unrefed + later by gdk_event_free. */ + if (button == 4) + xg_event->scroll.direction = GDK_SCROLL_UP; + else if (button == 5) + xg_event->scroll.direction = GDK_SCROLL_DOWN; + else if (button == 6) + xg_event->scroll.direction = GDK_SCROLL_LEFT; + else + xg_event->scroll.direction = GDK_SCROLL_RIGHT; + + xg_event->scroll.device = find_suitable_pointer (view->frame); + + xg_event->scroll.x = x; + xg_event->scroll.x_root = x; + xg_event->scroll.y = y; + xg_event->scroll.y_root = y; + xg_event->scroll.state = modifier_state; + xg_event->scroll.time = time; + + xg_event->scroll.delta_x = 0; + xg_event->scroll.delta_y = 0; + + gtk_main_do_event (xg_event); + gdk_event_free (xg_event); + } +} + +void +xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event) +{ + GdkEvent *xg_event = gdk_event_new (event->type == MotionNotify ? GDK_MOTION_NOTIFY : + (event->type == LeaveNotify ? GDK_LEAVE_NOTIFY : + GDK_ENTER_NOTIFY)); + struct xwidget *model = XXWIDGET (view->model); + int x; + int y; + GtkWidget *target = find_widget_at_pos (model->widgetwindow_osr, + (event->type == MotionNotify + ? event->xmotion.x + view->clip_left + : event->xmotion.y + view->clip_top), + (event->type == MotionNotify + ? event->xmotion.y + view->clip_left + : event->xcrossing.y + view->clip_top), + &x, &y); + + if (!target) + target = model->widgetwindow_osr; + + xg_event->any.window = gtk_widget_get_window (target); + g_object_ref (xg_event->any.window); /* The window will be unrefed + later by gdk_event_free. */ + + if (event->type == MotionNotify) + { + xg_event->motion.x = x; + xg_event->motion.y = y; + xg_event->motion.x_root = event->xmotion.x_root; + xg_event->motion.y_root = event->xmotion.y_root; + xg_event->motion.time = event->xmotion.time; + xg_event->motion.state = event->xmotion.state; + xg_event->motion.device = find_suitable_pointer (view->frame); + } + else + { + xg_event->crossing.detail = min (5, event->xcrossing.detail); + xg_event->crossing.time = event->xcrossing.time; + xg_event->crossing.x = x; + xg_event->crossing.y = y; + xg_event->crossing.x_root = event->xcrossing.x_root; + xg_event->crossing.y_root = event->xcrossing.y_root; + gdk_event_set_device (xg_event, find_suitable_pointer (view->frame)); + } + + gtk_main_do_event (xg_event); + gdk_event_free (xg_event); +} + +static void +synthesize_focus_in_event (GtkWidget *offscreen_window) +{ + GdkWindow *wnd; + GdkEvent *focus_event; + + if (!gtk_widget_get_realized (offscreen_window)) + gtk_widget_realize (offscreen_window); + + wnd = gtk_widget_get_window (offscreen_window); + + focus_event = gdk_event_new (GDK_FOCUS_CHANGE); + focus_event->any.window = wnd; + focus_event->focus_change.in = TRUE; + g_object_ref (wnd); + + gtk_main_do_event (focus_event); + gdk_event_free (focus_event); +} + +struct xwidget_view * +xwidget_view_from_window (Window wdesc) +{ + Lisp_Object key = make_fixnum (wdesc); + Lisp_Object xwv = Fgethash (key, x_window_to_xwv_map, Qnil); + + if (NILP (xwv)) + return NULL; + + return XXWIDGET_VIEW (xwv); +} + static void xwidget_show_view (struct xwidget_view *xv) { xv->hidden = false; - gtk_widget_show (xv->widgetwindow); - gtk_fixed_move (GTK_FIXED (xv->emacswindow), - xv->widgetwindow, - xv->x + xv->clip_left, - xv->y + xv->clip_top); + XMoveWindow (xv->dpy, xv->wdesc, + xv->x + xv->clip_left, + xv->y + xv->clip_top); + XMapWindow (xv->dpy, xv->wdesc); + XFlush (xv->dpy); } /* Hide an xwidget view. */ @@ -238,28 +836,64 @@ xwidget_show_view (struct xwidget_view *xv) xwidget_hide_view (struct xwidget_view *xv) { xv->hidden = true; - gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow, - 10000, 10000); + XUnmapWindow (xv->dpy, xv->wdesc); + XFlush (xv->dpy); +} + +static void +xv_do_draw (struct xwidget_view *xw, struct xwidget *w) +{ + GtkOffscreenWindow *wnd; + cairo_surface_t *surface; + block_input (); + wnd = GTK_OFFSCREEN_WINDOW (w->widgetwindow_osr); + surface = gtk_offscreen_window_get_surface (wnd); + + cairo_save (xw->cr_context); + if (surface) + { + cairo_set_source_surface (xw->cr_context, surface, xw->clip_left, + xw->clip_top); + cairo_set_operator (xw->cr_context, CAIRO_OPERATOR_SOURCE); + cairo_paint (xw->cr_context); + } + cairo_restore (xw->cr_context); + + unblock_input (); } /* When the off-screen webkit master view changes this signal is called. It copies the bitmap from the off-screen instance. */ static gboolean offscreen_damage_event (GtkWidget *widget, GdkEvent *event, - gpointer xv_widget) -{ - /* Queue a redraw of onscreen widget. - There is a guard against receiving an invalid widget, - which should only happen if we failed to remove the - specific signal handler for the damage event. */ - if (GTK_IS_WIDGET (xv_widget)) - gtk_widget_queue_draw (GTK_WIDGET (xv_widget)); - else - message ("Warning, offscreen_damage_event received invalid xv pointer:%p\n", - xv_widget); + gpointer xwidget) +{ + block_input (); + + for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); + tail = XCDR (tail)) + { + if (XWIDGET_VIEW_P (XCAR (tail))) + { + struct xwidget_view *view = XXWIDGET_VIEW (XCAR (tail)); + + if (view->wdesc && XXWIDGET (view->model) == xwidget) + xv_do_draw (view, XXWIDGET (view->model)); + } + } + + unblock_input (); return FALSE; } + +void +xwidget_expose (struct xwidget_view *xv) +{ + struct xwidget *xw = XXWIDGET (xv->model); + + xv_do_draw (xv, xw); +} #endif /* USE_GTK */ void @@ -313,22 +947,108 @@ store_xwidget_js_callback_event (struct xwidget *xw, #ifdef USE_GTK +static void +store_xwidget_display_event (struct xwidget *xw) +{ + struct input_event evt; + Lisp_Object val; + + XSETXWIDGET (val, xw); + EVENT_INIT (evt); + evt.kind = XWIDGET_DISPLAY_EVENT; + evt.frame_or_window = Qnil; + evt.arg = val; + kbd_buffer_store_event (&evt); +} + +static void +webkit_ready_to_show (WebKitWebView *new_view, + gpointer user_data) +{ + Lisp_Object tem; + struct xwidget *xw; + + for (tem = Vxwidget_list; CONSP (tem); tem = XCDR (tem)) + { + if (XWIDGETP (XCAR (tem))) + { + xw = XXWIDGET (XCAR (tem)); + + if (EQ (xw->type, Qwebkit) + && WEBKIT_WEB_VIEW (xw->widget_osr) == new_view) + store_xwidget_display_event (xw); + } + } +} + +static GtkWidget * +webkit_create_cb_1 (WebKitWebView *webview, + struct xwidget_view *xv) +{ + Lisp_Object related; + Lisp_Object xwidget; + GtkWidget *widget; + + XSETXWIDGET (related, xv); + xwidget = Fmake_xwidget (Qwebkit, Qnil, make_fixnum (0), + make_fixnum (0), Qnil, + build_string (" *detached xwidget buffer*"), + related); + + if (NILP (xwidget)) + return NULL; + + widget = XXWIDGET (xwidget)->widget_osr; + + g_signal_connect (G_OBJECT (widget), "ready-to-show", + G_CALLBACK (webkit_ready_to_show), NULL); + + return widget; +} + +static GtkWidget * +webkit_create_cb (WebKitWebView *webview, + WebKitNavigationAction *nav_action, + gpointer user_data) +{ + switch (webkit_navigation_action_get_navigation_type (nav_action)) + { + case WEBKIT_NAVIGATION_TYPE_OTHER: + return webkit_create_cb_1 (webview, user_data); + + case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD: + case WEBKIT_NAVIGATION_TYPE_RELOAD: + case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED: + case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED: + case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED: + default: + return NULL; + } +} + void webkit_view_load_changed_cb (WebKitWebView *webkitwebview, WebKitLoadEvent load_event, gpointer data) { - switch (load_event) { - case WEBKIT_LOAD_FINISHED: + struct xwidget *xw = g_object_get_data (G_OBJECT (webkitwebview), + XG_XWIDGET); + + switch (load_event) { - struct xwidget *xw = g_object_get_data (G_OBJECT (webkitwebview), - XG_XWIDGET); - store_xwidget_event_string (xw, "load-changed", ""); + case WEBKIT_LOAD_FINISHED: + store_xwidget_event_string (xw, "load-changed", "load-finished"); + break; + case WEBKIT_LOAD_STARTED: + store_xwidget_event_string (xw, "load-changed", "load-started"); + break; + case WEBKIT_LOAD_REDIRECTED: + store_xwidget_event_string (xw, "load-changed", "load-redirected"); + break; + case WEBKIT_LOAD_COMMITTED: + store_xwidget_event_string (xw, "load-changed", "load-committed"); break; } - default: - break; - } } /* Recursively convert a JavaScript value to a Lisp value. */ @@ -498,51 +1218,6 @@ webkit_decide_policy_cb (WebKitWebView *webView, return FALSE; } } - - -/* For gtk3 offscreen rendered widgets. */ -static gboolean -xwidget_osr_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data) -{ - struct xwidget *xw = g_object_get_data (G_OBJECT (widget), XG_XWIDGET); - struct xwidget_view *xv = g_object_get_data (G_OBJECT (widget), - XG_XWIDGET_VIEW); - - cairo_rectangle (cr, 0, 0, xv->clip_right, xv->clip_bottom); - cairo_clip (cr); - - gtk_widget_draw (xw->widget_osr, cr); - return FALSE; -} - -static gboolean -xwidget_osr_event_forward (GtkWidget *widget, GdkEvent *event, - gpointer user_data) -{ - /* Copy events that arrive at the outer widget to the offscreen widget. */ - struct xwidget *xw = g_object_get_data (G_OBJECT (widget), XG_XWIDGET); - GdkEvent *eventcopy = gdk_event_copy (event); - eventcopy->any.window = gtk_widget_get_window (xw->widget_osr); - - /* TODO: This might leak events. They should be deallocated later, - perhaps in xwgir_event_cb. */ - gtk_main_do_event (eventcopy); - - /* Don't propagate this event further. */ - return TRUE; -} - -static gboolean -xwidget_osr_event_set_embedder (GtkWidget *widget, GdkEvent *event, - gpointer data) -{ - struct xwidget_view *xv = data; - struct xwidget *xww = XXWIDGET (xv->model); - gdk_offscreen_window_set_embedder (gtk_widget_get_window - (xww->widgetwindow_osr), - gtk_widget_get_window (xv->widget)); - return FALSE; -} #endif /* USE_GTK */ @@ -568,63 +1243,19 @@ xwidget_init_view (struct xwidget *xww, XSETXWIDGET (xv->model, xww); #ifdef USE_GTK - if (EQ (xww->type, Qwebkit)) - { - xv->widget = gtk_drawing_area_new (); - /* Expose event handling. */ - gtk_widget_set_app_paintable (xv->widget, TRUE); - gtk_widget_add_events (xv->widget, GDK_ALL_EVENTS_MASK); - - /* Draw the view on damage-event. */ - g_signal_connect (G_OBJECT (xww->widgetwindow_osr), "damage-event", - G_CALLBACK (offscreen_damage_event), xv->widget); + xv->dpy = FRAME_X_DISPLAY (s->f); - if (EQ (xww->type, Qwebkit)) - { - g_signal_connect (G_OBJECT (xv->widget), "button-press-event", - G_CALLBACK (xwidget_osr_event_forward), NULL); - g_signal_connect (G_OBJECT (xv->widget), "button-release-event", - G_CALLBACK (xwidget_osr_event_forward), NULL); - g_signal_connect (G_OBJECT (xv->widget), "motion-notify-event", - G_CALLBACK (xwidget_osr_event_forward), NULL); - } - else - { - /* xwgir debug, orthogonal to forwarding. */ - g_signal_connect (G_OBJECT (xv->widget), "enter-notify-event", - G_CALLBACK (xwidget_osr_event_set_embedder), xv); - } - g_signal_connect (G_OBJECT (xv->widget), "draw", - G_CALLBACK (xwidget_osr_draw_cb), NULL); - } - - /* Widget realization. - - Make container widget first, and put the actual widget inside the - container later. Drawing should crop container window if necessary - to handle case where xwidget is partially obscured by other Emacs - windows. Other containers than gtk_fixed where explored, but - gtk_fixed had the most predictable behavior so far. */ - - xv->emacswindow = FRAME_GTK_WIDGET (s->f); - xv->widgetwindow = gtk_fixed_new (); - gtk_widget_set_has_window (xv->widgetwindow, TRUE); - gtk_container_add (GTK_CONTAINER (xv->widgetwindow), xv->widget); - - /* Store some xwidget data in the gtk widgets. */ - g_object_set_data (G_OBJECT (xv->widget), XG_FRAME_DATA, s->f); - g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET, xww); - g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET_VIEW, xv); - g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET, xww); - g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET_VIEW, xv); - - gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xww->width, - xww->height); - gtk_widget_set_size_request (xv->widgetwindow, xww->width, xww->height); - gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), xv->widgetwindow, x, y); xv->x = x; xv->y = y; - gtk_widget_show_all (xv->widgetwindow); + + xv->clip_left = 0; + xv->clip_right = xww->width; + xv->clip_top = 0; + xv->clip_bottom = xww->height; + + xv->wdesc = None; + xv->frame = s->f; + xv->cursor = cursor_for_hit (xww->hit_result, s->f); #elif defined NS_IMPL_COCOA nsxwidget_init_view (xv, xww, s, x, y); nsxwidget_resize_view(xv, xww->width, xww->height); @@ -681,6 +1312,8 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) window_box (s->w, TEXT_AREA, &text_area_x, &text_area_y, &text_area_width, &text_area_height); + /* On X11, this keeps generating expose events. */ +#ifndef USE_GTK /* Resize xwidget webkit if its container window size is changed in some ways, for example, a buffer became hidden in small split window, then it can appear front in merged whole window. */ @@ -693,6 +1326,7 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) make_int (text_area_width), make_int (text_area_height)); } +#endif clip_left = max (0, text_area_x - x); clip_right = max (clip_left, @@ -711,15 +1345,51 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) later. */ bool moved = (xv->x + xv->clip_left != x + clip_left || xv->y + xv->clip_top != y + clip_top); + +#ifdef USE_GTK + bool wdesc_was_none = xv->wdesc == None; +#endif xv->x = x; xv->y = y; +#ifdef USE_GTK + block_input (); + if (xv->wdesc == None) + { + Lisp_Object xvw; + XSETXWIDGET_VIEW (xvw, xv); + XSetWindowAttributes a; + a.event_mask = (ExposureMask | ButtonPressMask | ButtonReleaseMask + | PointerMotionMask | EnterWindowMask | LeaveWindowMask); + + xv->wdesc = XCreateWindow (xv->dpy, FRAME_X_WINDOW (s->f), + x + clip_left, y + clip_top, + clip_right - clip_left, + clip_bottom - clip_top, 0, + CopyFromParent, CopyFromParent, + CopyFromParent, CWEventMask, &a); + XDefineCursor (xv->dpy, xv->wdesc, xv->cursor); + xv->cr_surface = cairo_xlib_surface_create (xv->dpy, + xv->wdesc, + FRAME_DISPLAY_INFO (s->f)->visual, + clip_right - clip_left, + clip_bottom - clip_top); + xv->cr_context = cairo_create (xv->cr_surface); + Fputhash (make_fixnum (xv->wdesc), xvw, x_window_to_xwv_map); + + moved = false; + } +#endif + /* Has it moved? */ if (moved) { #ifdef USE_GTK - gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), - xv->widgetwindow, x + clip_left, y + clip_top); + 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 NS_IMPL_COCOA nsxwidget_move_view (xv, x + clip_left, y + clip_top); #endif @@ -735,10 +1405,14 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) || xv->clip_top != clip_top || xv->clip_left != clip_left) { #ifdef USE_GTK - gtk_widget_set_size_request (xv->widgetwindow, clip_right - clip_left, - clip_bottom - clip_top); - gtk_fixed_move (GTK_FIXED (xv->widgetwindow), xv->widget, -clip_left, - -clip_top); + if (!wdesc_was_none && !moved) + { + XResizeWindow (xv->dpy, xv->wdesc, 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 NS_IMPL_COCOA nsxwidget_resize_view (xv, clip_right - clip_left, clip_bottom - clip_top); @@ -758,12 +1432,15 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) if (!xwidget_hidden (xv)) { #ifdef USE_GTK - gtk_widget_queue_draw (xv->widgetwindow); - gtk_widget_queue_draw (xv->widget); + gtk_widget_queue_draw (xww->widget_osr); #elif defined NS_IMPL_COCOA nsxwidget_set_needsdisplay (xv); #endif } + +#ifdef USE_GTK + unblock_input (); +#endif } static bool @@ -975,16 +1652,13 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0, struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail)); if (XXWIDGET (xv->model) == xw) { -#ifdef USE_GTK - gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width, - xw->height); -#elif defined NS_IMPL_COCOA - nsxwidget_resize_view(xv, xw->width, xw->height); -#endif + wset_redisplay (XWINDOW (xv->w)); } } } + redisplay (); + return Qnil; } @@ -1084,13 +1758,15 @@ DEFUN ("delete-xwidget-view", CHECK_XWIDGET_VIEW (xwidget_view); struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view); #ifdef USE_GTK - gtk_widget_destroy (xv->widgetwindow); - /* xv->model still has signals pointing to the view. There can be - several views. Find the matching signals and delete them all. */ - g_signal_handlers_disconnect_matched (XXWIDGET (xv->model)->widgetwindow_osr, - G_SIGNAL_MATCH_DATA, - 0, 0, 0, 0, - xv->widget); + if (xv->wdesc != None) + { + block_input (); + cairo_destroy (xv->cr_context); + cairo_surface_destroy (xv->cr_surface); + XDestroyWindow (xv->dpy, xv->wdesc); + Fremhash (make_fixnum (xv->wdesc), x_window_to_xwv_map); + unblock_input (); + } #elif defined NS_IMPL_COCOA nsxwidget_delete_view (xv); #endif @@ -1145,6 +1821,19 @@ DEFUN ("xwidget-buffer", return XXWIDGET (xwidget)->buffer; } +DEFUN ("set-xwidget-buffer", + Fset_xwidget_buffer, Sset_xwidget_buffer, + 2, 2, 0, + doc: /* Set XWIDGET's buffer to BUFFER. */) + (Lisp_Object xwidget, Lisp_Object buffer) +{ + CHECK_XWIDGET (xwidget); + CHECK_BUFFER (buffer); + + XXWIDGET (xwidget)->buffer = buffer; + return Qnil; +} + DEFUN ("set-xwidget-plist", Fset_xwidget_plist, Sset_xwidget_plist, 2, 2, 0, @@ -1183,6 +1872,166 @@ DEFUN ("xwidget-query-on-exit-flag", return (XXWIDGET (xwidget)->kill_without_query ? Qnil : Qt); } +DEFUN ("xwidget-webkit-search", Fxwidget_webkit_search, Sxwidget_webkit_search, + 2, 5, 0, + doc: /* Begin an incremental search operation in an xwidget. +QUERY should be a string containing the text to search for. XWIDGET +should be a WebKit xwidget where the search will take place. When the +search operation is complete, callers should also call +`xwidget-webkit-finish-search' to complete the search operation. + +CASE-INSENSITIVE, when non-nil, will cause the search to ignore the +case of characters inside QUERY. BACKWARDS, when non-nil, will cause +the search to proceed towards the beginning of the widget's contents. +WRAP-AROUND, when nil, will cause the search to stop upon hitting the +end of the widget's contents. + +It is OK to call this function even when a search is already in +progress. In that case, the previous search query will be replaced +with QUERY. */) + (Lisp_Object query, Lisp_Object xwidget, Lisp_Object case_insensitive, + Lisp_Object backwards, Lisp_Object wrap_around) +{ +#ifdef USE_GTK + WebKitWebView *webview; + WebKitFindController *controller; + WebKitFindOptions opt; + struct xwidget *xw; + gchar *g_query; +#endif + + CHECK_STRING (query); + CHECK_XWIDGET (xwidget); + +#ifdef USE_GTK + xw = XXWIDGET (xwidget); + webview = WEBKIT_WEB_VIEW (xw->widget_osr); + query = ENCODE_UTF_8 (query); + opt = WEBKIT_FIND_OPTIONS_NONE; + g_query = xstrdup (SSDATA (query)); + + if (!NILP (case_insensitive)) + opt |= WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE; + if (!NILP (backwards)) + opt |= WEBKIT_FIND_OPTIONS_BACKWARDS; + if (!NILP (wrap_around)) + opt |= WEBKIT_FIND_OPTIONS_WRAP_AROUND; + + if (xw->find_text) + xfree (xw->find_text); + xw->find_text = g_query; + + block_input (); + controller = webkit_web_view_get_find_controller (webview); + webkit_find_controller_search (controller, g_query, opt, G_MAXUINT); + unblock_input (); +#endif + + return Qnil; +} + +DEFUN ("xwidget-webkit-next-result", Fxwidget_webkit_next_result, + Sxwidget_webkit_next_result, 1, 1, 0, + doc: /* Show the next result matching the current search query. + +XWIDGET should be an xwidget that currently has a search query. +Before calling this function, you should start a search operation +using `xwidget-webkit-search'. */) + (Lisp_Object xwidget) +{ + struct xwidget *xw; +#ifdef USE_GTK + WebKitWebView *webview; + WebKitFindController *controller; +#endif + + CHECK_XWIDGET (xwidget); + xw = XXWIDGET (xwidget); + + if (!xw->find_text) + error ("Widget has no ongoing search operation"); + +#ifdef USE_GTK + block_input (); + webview = WEBKIT_WEB_VIEW (xw->widget_osr); + controller = webkit_web_view_get_find_controller (webview); + webkit_find_controller_search_next (controller); + unblock_input (); +#endif + + return Qnil; +} + +DEFUN ("xwidget-webkit-previous-result", Fxwidget_webkit_previous_result, + Sxwidget_webkit_previous_result, 1, 1, 0, + doc: /* Show the previous result matching the current search query. + +XWIDGET should be an xwidget that currently has a search query. +Before calling this function, you should start a search operation +using `xwidget-webkit-search'. */) + (Lisp_Object xwidget) +{ + struct xwidget *xw; +#ifdef USE_GTK + WebKitWebView *webview; + WebKitFindController *controller; +#endif + + CHECK_XWIDGET (xwidget); + xw = XXWIDGET (xwidget); + + if (!xw->find_text) + error ("Widget has no ongoing search operation"); + +#ifdef USE_GTK + block_input (); + webview = WEBKIT_WEB_VIEW (xw->widget_osr); + controller = webkit_web_view_get_find_controller (webview); + webkit_find_controller_search_previous (controller); + + if (xw->find_text) + { + xfree (xw->find_text); + xw->find_text = NULL; + } + unblock_input (); +#endif + + return Qnil; +} + +DEFUN ("xwidget-webkit-finish-search", Fxwidget_webkit_finish_search, + Sxwidget_webkit_finish_search, 1, 1, 0, + doc: /* Finish XWIDGET's search operation. + +XWIDGET should be an xwidget that currently has a search query. +Before calling this function, you should start a search operation +using `xwidget-webkit-search'. */) + (Lisp_Object xwidget) +{ + struct xwidget *xw; +#ifdef USE_GTK + WebKitWebView *webview; + WebKitFindController *controller; +#endif + + CHECK_XWIDGET (xwidget); + xw = XXWIDGET (xwidget); + + if (!xw->find_text) + error ("Widget has no ongoing search operation"); + +#ifdef USE_GTK + block_input (); + webview = WEBKIT_WEB_VIEW (xw->widget_osr); + controller = webkit_web_view_get_find_controller (webview); + webkit_find_controller_search_finish (controller); + unblock_input (); +#endif + + return Qnil; +} + void syms_of_xwidget (void) { @@ -1215,6 +2064,12 @@ syms_of_xwidget (void) defsubr (&Sxwidget_plist); defsubr (&Sxwidget_buffer); defsubr (&Sset_xwidget_plist); + defsubr (&Sxwidget_perform_lispy_event); + defsubr (&Sxwidget_webkit_search); + defsubr (&Sxwidget_webkit_finish_search); + defsubr (&Sxwidget_webkit_next_result); + defsubr (&Sxwidget_webkit_previous_result); + defsubr (&Sset_xwidget_buffer); DEFSYM (QCxwidget, ":xwidget"); DEFSYM (QCtitle, ":title"); @@ -1236,6 +2091,15 @@ syms_of_xwidget (void) Vxwidget_view_list = Qnil; Fprovide (intern ("xwidget-internal"), Qnil); + + id_to_xwidget_map = CALLN (Fmake_hash_table, QCtest, Qeq); + staticpro (&id_to_xwidget_map); + +#ifdef USE_GTK + x_window_to_xwv_map = CALLN (Fmake_hash_table, QCtest, Qeq); + + staticpro (&x_window_to_xwv_map); +#endif } @@ -1374,7 +2238,7 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix) /* The only call to xwidget_end_redisplay is in dispnew. xwidget_end_redisplay (w->current_matrix); */ struct xwidget_view *xv - = xwidget_view_lookup (glyph->u.xwidget, w); + = xwidget_view_lookup (xwidget_from_id (glyph->u.xwidget), w); #ifdef USE_GTK /* FIXME: Is it safe to assume xwidget_view_lookup always succeeds here? If so, this comment can be removed. @@ -1424,6 +2288,26 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix) } } +#ifdef USE_GTK +void +kill_frame_xwidget_views (struct frame *f) +{ + Lisp_Object rem = Qnil; + + for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); + tail = XCDR (tail)) + { + if (XXWIDGET_VIEW (XCAR (tail))->frame == f) + rem = Fcons (XCAR (tail), rem); + } + + for (; CONSP (rem); rem = XCDR (rem)) + { + Fdelete_xwidget_view (XCAR (rem)); + } +} +#endif + /* Kill all xwidget in BUFFER. */ void kill_buffer_xwidgets (Lisp_Object buffer) @@ -1437,12 +2321,15 @@ kill_buffer_xwidgets (Lisp_Object buffer) { CHECK_XWIDGET (xwidget); struct xwidget *xw = XXWIDGET (xwidget); + Fremhash (make_fixnum (xw->xwidget_id), id_to_xwidget_map); #ifdef USE_GTK if (xw->widget_osr && xw->widgetwindow_osr) { gtk_widget_destroy (xw->widget_osr); gtk_widget_destroy (xw->widgetwindow_osr); } + if (xw->find_text) + xfree (xw->find_text); if (!NILP (xw->script_callbacks)) for (ptrdiff_t idx = 0; idx < ASIZE (xw->script_callbacks); idx++) { diff --git a/src/xwidget.h b/src/xwidget.h index 591f23489d..82ac74543c 100644 --- a/src/xwidget.h +++ b/src/xwidget.h @@ -32,6 +32,8 @@ #define XWIDGET_H_INCLUDED #if defined (USE_GTK) #include +#include +#include "xterm.h" #elif defined (NS_IMPL_COCOA) && defined (__OBJC__) #import #import "nsxwidget.h" @@ -59,11 +61,14 @@ #define XWIDGET_H_INCLUDED int height; int width; + uint32_t xwidget_id; #if defined (USE_GTK) /* For offscreen widgets, unused if not osr. */ GtkWidget *widget_osr; GtkWidget *widgetwindow_osr; + guint hit_result; + gchar *find_text; #elif defined (NS_IMPL_COCOA) # ifdef __OBJC__ /* For offscreen widgets, unused if not osr. */ @@ -98,9 +103,13 @@ #define XWIDGET_H_INCLUDED bool hidden; #if defined (USE_GTK) - GtkWidget *widget; - GtkWidget *widgetwindow; - GtkWidget *emacswindow; + Display *dpy; + Window wdesc; + Emacs_Cursor cursor; + struct frame *frame; + + cairo_surface_t *cr_surface; + cairo_t *cr_context; #elif defined (NS_IMPL_COCOA) # ifdef __OBJC__ XvWindow *xvWindow; @@ -162,6 +171,18 @@ #define XG_XWIDGET_VIEW "emacs_xwidget_view" void store_xwidget_js_callback_event (struct xwidget *xw, Lisp_Object proc, Lisp_Object argument); + +extern struct xwidget *xwidget_from_id (uint32_t id); + +#ifdef HAVE_X_WINDOWS +struct xwidget_view *xwidget_view_from_window (Window wdesc); +void xwidget_expose (struct xwidget_view *xv); +extern void kill_frame_xwidget_views (struct frame *f); +extern void xwidget_button (struct xwidget_view *, bool, int, + int, int, int, Time); +extern void xwidget_motion_or_crossing (struct xwidget_view *, + const XEvent *); +#endif #else INLINE_HEADER_BEGIN INLINE void syms_of_xwidget (void) {} --=-=-= Content-Type: text/plain Thanks. --=-=-=-- From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Lars Ingebrigtsen Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 07 Nov 2021 01:24:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Po Lu Cc: Eli Zaretskii , 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163624819920521 (code B ref 51473); Sun, 07 Nov 2021 01:24:01 +0000 Received: (at 51473) by debbugs.gnu.org; 7 Nov 2021 01:23:19 +0000 Received: from localhost ([127.0.0.1]:51257 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjWty-0005Kv-TL for submit@debbugs.gnu.org; Sat, 06 Nov 2021 21:23:19 -0400 Received: from quimby.gnus.org ([95.216.78.240]:57236) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjWtx-0005Kh-5R for 51473@debbugs.gnu.org; Sat, 06 Nov 2021 21:23:17 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnus.org; s=20200322; h=Content-Type:MIME-Version:Message-ID:In-Reply-To:Date: References:Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=VgYPlWRifmE3F+dGhD9bpl8Im3R1NZpVa4yh9cDL2H4=; b=r2FuHLRw6g6zINzbRgBR/lD2ib i92DC94c+UvZmn3R1zP0ACQr0JrYJmINr5L7DGumsiErHj9EAYbrwPUAz75/Gl1M0qyTpClX33XH6 eJJO7RctLnclwFyY+Z79DJJW0VxT8OWLvqjug1UfH4pQeYVgDBpwnGano3e/I2me7dOg=; Received: from [84.212.220.105] (helo=elva) by quimby.gnus.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mjWto-0003Pp-0o; Sun, 07 Nov 2021 02:23:10 +0100 From: Lars Ingebrigtsen References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> <87o86xzhuw.fsf@yahoo.com> <87sfw9cha3.fsf@gnus.org> <878ry0ztjo.fsf@yahoo.com> <87zgqgrd32.fsf@gnus.org> <87zgqgyd9d.fsf@yahoo.com> Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAABGdBTUEAALGPC/xhBQAAACBj SFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAG1BMVEU1LypEOzNWUEgj HhqScErGnGZdSznXwpX////dnnslAAAAAWJLR0QIht6VegAAAAd0SU1FB+ULBwA2GhQkQTYAAAGU SURBVDjLlZK9b8IwEMVtQjPbQD0XaPdItN2Rzs7cKoaVSMGsHQj+93tn57OARJ+UD93v3vPFMWNc klao2VJ2mjPG6CleAQoNyxEgyQlZVvIK8AmgvvgVCFAKxm+BQccdcNdBln8C9ghAtxhmRcCVi5Kd JQAZipVz4JwYRGG9Am2tBTAmkDiVVA6wavfe26L18DlSR92tGoIO6QDGpIwOBQ2gKJJxhwAqBLHX +xrvuiALgtaAjjpEAeAq0dEuEbIKHBqzGmDK8D26AWW7BnakSlWCKU0AGmAwUoHW2knBdQ8MfdDR V35X0GnQCEyYCnNYaj281drQawu2ODSf1n53qj9+aJsWAFsCgkDlTxfw+VlQLA3Dads541Obe3/0 PuzTFEQEgsm0qnWxt0bSL+SYPgkOxfjzRZv889D99ADSF5Hua//9XpWHESCd6nyXe9eDdfOyKJ62 +bk/Px1gJed9/xBkyego9uCPHgFJds+RsQGa9YuPoxqwCUqyzRgkm04ZXQRW62G5VXRc18lzG6Dn DsgQ/AIpZYy6KGfBdAAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAyMS0xMS0wN1QwMDo1NDoyNiswMDow MA2BfyYAAAAldEVYdGRhdGU6bW9kaWZ5ADIwMjEtMTEtMDdUMDA6NTQ6MjYrMDA6MDB83MeaAAAA AElFTkSuQmCC X-Now-Playing: Nils Frahm's _Tripping with Nils Frahm_: "Ode-Our Own Roof" Date: Sun, 07 Nov 2021 02:23:05 +0100 In-Reply-To: <87zgqgyd9d.fsf@yahoo.com> (Po Lu's message of "Sun, 07 Nov 2021 09:18:22 +0800") Message-ID: <87r1bsrc7a.fsf@gnus.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Report: Spam detection software, running on the system "quimby.gnus.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see @@CONTACT_ADDRESS@@ for details. Content preview: Po Lu writes: > Does this version fix the problem? It gets further: Content analysis details: (-2.9 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Po Lu writes: > Does this version fix the problem? It gets further: xwidget.c:1951:12: error: no member named 'find_text' in 'struct xwidget' if (!xw->find_text) ~~ ^ xwidget.c:1983:12: error: no member named 'find_text' in 'struct xwidget' if (!xw->find_text) ~~ ^ xwidget.c:2021:12: error: no member named 'find_text' in 'struct xwidget' if (!xw->find_text) ~~ ^ Oh, and I didn't notice this error the first time around, apparently: print.c:1529:23: error: no member named 'widget_osr' in 'struct xwidget' XXWIDGET (obj)->widget_osr); ~~~~~~~~~~~~~~ ^ -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 07 Nov 2021 01:28:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Lars Ingebrigtsen Cc: Eli Zaretskii , 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163624842720853 (code B ref 51473); Sun, 07 Nov 2021 01:28:02 +0000 Received: (at 51473) by debbugs.gnu.org; 7 Nov 2021 01:27:07 +0000 Received: from localhost ([127.0.0.1]:51262 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjWxb-0005QD-Ds for submit@debbugs.gnu.org; Sat, 06 Nov 2021 21:27:07 -0400 Received: from sonic301-30.consmr.mail.ne1.yahoo.com ([66.163.184.199]:36685) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjWxW-0005Pg-NB for 51473@debbugs.gnu.org; Sat, 06 Nov 2021 21:27:02 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636248413; bh=FRlSWFj7aqtwtDHclYkARcFPtI4ZcJFJHu5IhqaQ8+4=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=A1W9zPF9f+HkqG6hhARzENvZToOIDNaYPmh7FwN8fd1gIIL9NRF20iAkHQ8oZhF/VI3Vu46Nrx5A7TOsooi4C5MuPau3bpbEoj8K9v9En0vEqGebjDTGWXBlTI5clFWLLbbJXirD6DQoj1y0ijQKT0TOM0XAjijFLNJ3saPzy2D8iet4dJczE1lb+GsGbf9Lh3eKMbVWkxhkEWHki/EZQhZRUbu7PcS7eJMk1OchbgQBx9R+HrJuhrAEr0t8XJlTJTxunE2h5ohQG9n2f7ysLE3qG1TkOUVWiPuRPhj+aZlIgFRMT4a0F9+23nM1oV5HQdCvcOQvhkoSYVQCRdv6PQ== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636248413; bh=nR67o+pWSRpAy+w/H8ndFwx1AR5CnCzxQUOHP9SM9Fi=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=Rsku7LcYXR04qs3sg5IM8P868FFjcBmZTY4xtSPssLAFXhrUGKnHqy9Hb8UaWZBu5qi33y2lVDsuGpbf/GyADpQg+7kAcHMqaTEOirq2XqQz7GEn81bwPmVKzkI9GkR3yBaQL3QkSlwqwaFGLcDFeu6GTFVriwlX9N+BiAXWsjtCIGWwDD2X9i2CGNNV2fYoETfuJwuYAuRlzkeMuEdOWaF3XWtC3f3Nw0kZp3jnaKZEhAfSGQBum4K8PeXxB7it6C5YDvA2LDno0X/klSliwZGNhGnNYkBO31YQjJNvVWQGzDozFhg18ETZeg9/FHdCs0dkZ+TPMhVkdd2W5BT80Q== X-YMail-OSG: MbfU3bgVM1mo3xo0KIIf.kEJxaRTaVBL9s_wP.jt1S6VJdJJRpyNd.u6yhh6c5J YBOXZRF4JAj80xuxiLJWllTzq2fqvlN0KrqU3wVEb7VoOJIqdHVyI.YzWyIn32NOVcT8OQ4fK77n JS2VynPL9Yn.z2h9vGegjMcVDyRXoaXOY.WnyI5qpVTQ49p3ueLdVUOfdgpSxaftkToFkuQ4iW0H y.U0nBZfa4ke2zp_.TZonYWxejWCTRNuDcWAmbT3g2tIrGaXV2G0m9L6Yy7Kznq5WKlCjaFXRd03 A5GZrTuQSprgouZa9XudiLcYlKC93SEcnD6hH29hxGi84kavSmUUS4A3rpQEOCHS7eoG2jnkqAof TxQzF1AcdjF9TOtp0u.HyDHcNUB_eqd3fmmaWZ8HGBm24jK49hRN6JjWxeuarozeqB5uS6G3NYwt CZXgKCapL1eIOhAZ797bymf0z6y5DynQDyYmcmvaf4AV1ydAeiP7XkMuo56RzTOkX2YMKL.cdt_b dQiztjQumagl8AO_J3hLjgDNblxCgNsCqLhM8RMv8GeXI8LjTf6Hjrg21KKZe6HHYkOcNH7l0.UV yYyrwEHQAEMHjY9kQGaW9XKXx2GJxw5kt0QahkXLqAQykF.gox7H6h5ma0CKCDUZZmKbVTUgjxVw UOvGc.aBnpN3zE1.e.kDds_rolaYlkv.W7ZTsLO3mPT5qxsKbO6aC3hc2xBP3QipkCmp.OGsKy0X 0ab0RHEWm72xKsii0My3V6W_k867Sg6vjQOqB7GgFaOHg9ydPlEWO_ABmuaAyxrnLMIclUSnoC5. d5x61k3lwAYD1BHmqbheOrxg4sMtV9Y_ns86cItpQEXxpDbjNHi0XRilHC5FnaHrW2USNglyZ2r9 cTJF2HAxVQXn9zpY62rrwKJuLW69BqJfqzn2lzHDPZke2zuKBSoGDAJ_BegutpzyA65XJEonZ8bw X_sgemIya7vpxzATf3lwtfNVAok46j6z8YplVTwAyS7quVNp7K.mqbwWSiURY0gYCmEu_q0OcpIS sx_5q4Qe3D1rFEMYYuTo1ENJ_BBFW3k.Ajt4vcPZZB_Dn906N2ope0hrNuuRTM_0YFFTUdOEcgDW foTQKszKsAiBuPcKstNR5SUmrA8luHEUiPAS5YWNfEsth_MJsQavWpGr3aY8NZVcYX50mBYaMD7x LyrtJpHtm2OPRrwpf_iHwyXfmzBvjiJRlLIm3DZOaPfWrRmpU5m19eujF15.WPEuKB2bPPLy3xoX MgDkSQewp8A8EWoSA6CXcK3W51wiNAYCB3ZN4ko5Jz.R47ZhAwAprCwQAwrihbyj8Uv9yujhx00P NdaO94yPSLh_QLDWvxB9MGOGuwyP7JEmFAdlJ9StTyhsasx5fCd9YnWciQrhGS5M2Dzc9wqpZzrj gPAtYTt5YomiqWzHxh3de0AnBu0tsZIia2YWoR_bqXJ4Xpm.Z3x4thDKdeYOybZEzbexIC2g4WCe hEuEDFbYdZNg7n8a1KXc4hKaBoB4JQeswkutf0a_UFa3iX1JhkP7f5yhQKSkpkRFGQvx7bL4gsAr DJv8vG8wilQTu6bRvDM4eeSlpCg29my44dw8Y3dpnO7naSBIQvyPE8nCv2dLqaQDIv7BQ7tr3eQy iYThvf_Ka8qejXhcxoAIRsJBDga6b9IsR3ROpg7eRJ3twk0wH8wwizKWFezbuKvuqMwgcUP4ewII og9VW3Lbxd75HUI386AC_bEaDUdETyQiH.w2jNnaQfvoX1RIkU6UWRBuuZK8TVceSYuZ6plfJPAv 3UVbhPh59YNCegE506URoJ2TGd.KvPb85mxC_kIKRChrhv60Ub6qWDQC49BGeuAEQD1mxq3fNB63 y1VqlbkNJi1MgYNANO0WCUluhW5_3vbyV_69_qutf2Hz_kuKjhyyZiTwvOOrs4kNUpk1n6DUofKg mEgDWWSWuqLlTzib.qpWMb6GhwHCOl13JS2Rtqc7DjsHQZMhthOeKIBsV4EPF7cuBfmwzcWziAaG OwdkcpvaY0qRQ0KxhzJQL2dckZa.3IopoFB1XkzDa8Up3HM2xCgvIzduUgYBsI.Jj.nSbgwwsPZh CGwETxUhGnVnSIhr1mVBE2eQvueL4DJPq7icF_RNjlEffsCMk_scdI6xWH_tWAefG2ETHHK2e0oN sVPSkC7CHKKKfRd0ixbpqBq9KXbA.Wk0xtdR9f_G_kOFyQbfm72Agz.G8FswMqm3sszAdfHbNSlv 1IMIFv6NacDaVgIMo2i9pDWQeeppVRftYHtd2PwB_ZzIANbK0fKmVg3hl X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic301.consmr.mail.ne1.yahoo.com with HTTP; Sun, 7 Nov 2021 01:26:53 +0000 Received: by kubenode514.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 79918a6fae8ac30ca5b6b65ca4f1999f; Sun, 07 Nov 2021 01:26:45 +0000 (UTC) From: Po Lu References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> <87o86xzhuw.fsf@yahoo.com> <87sfw9cha3.fsf@gnus.org> <878ry0ztjo.fsf@yahoo.com> <87zgqgrd32.fsf@gnus.org> <87zgqgyd9d.fsf@yahoo.com> <87r1bsrc7a.fsf@gnus.org> Date: Sun, 07 Nov 2021 09:26:41 +0800 In-Reply-To: <87r1bsrc7a.fsf@gnus.org> (Lars Ingebrigtsen's message of "Sun, 07 Nov 2021 02:23:05 +0100") Message-ID: <87v914ycvi.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 95235 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Lars Ingebrigtsen writes: > It gets further: > > xwidget.c:1951:12: error: no member named 'find_text' in 'struct xwidget' > if (!xw->find_text) > ~~ ^ > xwidget.c:1983:12: error: no member named 'find_text' in 'struct xwidget' > if (!xw->find_text) > ~~ ^ > xwidget.c:2021:12: error: no member named 'find_text' in 'struct xwidget' > if (!xw->find_text) > ~~ ^ > > Oh, and I didn't notice this error the first time around, apparently: > > print.c:1529:23: error: no member named 'widget_osr' in 'struct xwidget' > XXWIDGET (obj)->widget_osr); > ~~~~~~~~~~~~~~ ^ Thanks, does this work instead? --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=test.diff diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi index 7f91e1c188..1207ab5e9a 100644 --- a/doc/emacs/misc.texi +++ b/doc/emacs/misc.texi @@ -2953,6 +2953,34 @@ Embedded WebKit Widgets reloading it. Type @w{@kbd{C-h b}} in that buffer to see the key bindings. +@findex xwidget-webkit-edit-mode +@cindex xwidget-webkit-edit-mode + By default, typing a self-inserting character inside an xwidget +webkit buffer will do nothing, or trigger some special action. To +make those characters and other common editing keys insert themselves +when pressed, you can enable @code{xwidget-webkit-edit-mode}, which +redefines them to be passed through to the WebKit xwidget. + +You can also enable @code{xwidget-webkit-edit-mode} by typing @kbd{e} +inside the xwidget webkit buffer. + +@findex xwidget-webkit-isearch-mode +@cindex xwidget-webkit-isearch-mode +@cindex searching in webkit buffers + @code{xwidget-webkit-isearch-mode} is a minor mode that behaves +similarly to incremental search (@pxref{Incremental Search}), but +operates on the contents of a WebKit widget instead of the current +buffer. It is bound to @kbd{C-s} and @kbd{C-r} inside xwidget-webkit +buffers. When it is enabled through @kbd{C-r}, the initial search +will be performed in reverse direction. + +Typing any self-inserting character will cause the character to be +inserted into the current search query. Typing @kbd{C-s} will cause +the WebKit widget to display the next search result, while typing +@kbd{C-r} will cause it to display the last. + +To leave incremental search, you can type @kbd{C-g}. + @node Browse-URL @subsection Following URLs @cindex World Wide Web diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi index b38a83b4fe..832b570b6a 100644 --- a/doc/lispref/commands.texi +++ b/doc/lispref/commands.texi @@ -1176,6 +1176,7 @@ Input Events * Repeat Events:: Double and triple click (or drag, or down). * Motion Events:: Just moving the mouse, not pushing a button. * Focus Events:: Moving the mouse between frames. +* Xwidget Events:: Events generated by xwidgets. * Misc Events:: Other events the system can generate. * Event Examples:: Examples of the lists for mouse events. * Classifying Events:: Finding the modifier keys in an event symbol. @@ -1871,6 +1872,76 @@ Focus Events so that the focus event comes either before or after the multi-event key sequence, and not within it. +@node Xwidget Events +@subsection Xwidget events + +Xwidgets (@pxref{Xwidgets}) can send events to update Lisp programs on +their status. These events are dubbed @code{xwidget-events}, and +contain various data describing the nature of the change. + +@table @code +@cindex @code{xwidget-event} event +@item (xwidget-event @var{kind} @var{xwidget} @var{arg}) +This event is sent whenever some kind of update occurs in +@var{xwidget}. There are several types of updates, which are +identified by @var{kind}. + +@cindex @code{load-changed} xwidget events +An xwidget event with @var{kind} set to @code{load-changed} indicates +that the @var{xwidget} has reached a particular point of the +page-loading process. When these events are sent, @var{arg} will +contain a string that futher describes the status of the widget. + +@cindex @samp{"load-finished"} in xwidgets +When @var{arg} is @samp{"load-finished"}, it means the xwidget has +finished processing whatever page-loading operation that it was +previously performing. + +@cindex @samp{"load-started"} in xwidgets +Otherwise, if it is @samp{"load-started"}, then the widget has begun a +page-loading operation. + +@cindex @samp{"load-redirected"} in xwidgets +If @var{arg} is @samp{"load-redirected"}, it means the widget has +encountered and followed a redirect during the page-loading operation. + +@cindex @samp{"load-committed"} in xwidgets +If @var{arg} is @samp{"load-committed"}, then the widget has committed +to a given URL during the page-loading operation. This means that the +URL is the final URL that will be rendered by @var{xwidget} during the +current page-loading operation. + +@cindex @code{download-callback} xwidget events +An event with @var{kind} set to @code{download-callback} indicates +that a download of some kind has been completed. + +In these events, there can be arguments after @var{arg}, which itself +indicates the URL that the download file was retrieved from: the first +argument after @var{arg} indicates the MIME type of the download, as a +string, while the second such argument contains the full file path to +the downloaded file. + +@cindex @code{download-started} xwidget events +An event with @var{kind} set to @code{download-started} indicates that +a download has been started. In these events, @var{arg} contains the +URL of the file that is currently being downloaded. + +@cindex @code{javascript-callback} xwidget events +An event with @var{kind} set to @code{javascript-callback} contains +JavaScript callback data. These events are used internally by +@code{xwidget-webkit-execute-script}. + +@cindex @code{xwidget-display-event} event +@item (xwidget-display-event @var{xwidget}) +This event is sent whenever an xwidget requests that another xwidget +be displayed. @var{xwidget} is the xwidget that should be displayed. + +@var{xwidget}'s buffer will be set to a temporary buffer. When +displaying the widget, care should be taken to replace the buffer with +the buffer in which the xwidget will be displayed, using +@code{set-xwidget-buffer} (@pxref{Xwidgets}). +@end table + @node Misc Events @subsection Miscellaneous System Events diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 22528a1b0f..60bca15eb2 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -6784,7 +6784,10 @@ Xwidgets in a @code{display} text or overlay property (@pxref{Display Property}). -@defun make-xwidget type title width height arguments &optional buffer + Embedded widgets can send events notifying Lisp code about changes +occurring within them. (@pxref{Xwidget Events}). + +@defun make-xwidget type title width height arguments &optional buffer related This creates and returns an xwidget object. If @var{buffer} is omitted or @code{nil}, it defaults to the current buffer. If @var{buffer} names a buffer that doesn't exist, it will be @@ -6797,7 +6800,10 @@ Xwidgets @end table The @var{width} and @var{height} arguments specify the widget size in -pixels, and @var{title}, a string, specifies its title. +pixels, and @var{title}, a string, specifies its title. @var{related} +is used internally by the WebKit widget, and specifies another WebKit +widget that the newly created widget should share settings and +subprocesses with. @end defun @defun xwidgetp object @@ -6818,6 +6824,10 @@ Xwidgets This function returns the buffer of @var{xwidget}. @end defun +@defun set-xwidget-buffer xwidget buffer +This function sets the buffer of @var{xwidget} to @var{buffer}. +@end defun + @defun get-buffer-xwidgets buffer This function returns a list of xwidget objects associated with the @var{buffer}, which can be specified as a buffer object or a name of @@ -6878,6 +6888,61 @@ Xwidgets query-on-exit flag, either @code{t} or @code{nil}. @end defun +@defun xwidget-perform-lispy-event xwidget event frame +Send an input event @var{event} to @var{xwidget}. The precise action +performed is platform-specific. See @ref{Input Events}. + +You can optionally pass the frame the event was generated from via +@var{frame}. On X11, modifier keys in key events will not be +considered if @var{frame} is @code{nil}, and the selected frame is not +an X-Windows frame. + +On GTK, only keyboard and function key events are implemented. Mouse, +motion, and click events are dispatched to the xwidget without going +through Lisp code, and as such shouldn't require this function to be +sent. +@end defun + +@defun xwidget-webkit-search query xwidget &optional case-insensitive backwards wrap-around +Start an incremental search on the WebKit widget @var{xwidget} with +the string @var{query} as a query. @var{case-insensitive} denotes +whether or not the search is case-insensitive, @var{backwards} +determines if the search is performed backwards towards the start of +the document, and @var{wrap-around} determines whether or not the +search terminates at the end of the document. + +If the function is called while a search query is already present, +then the query specified here will replace the existing query. + +To stop a search query, use @code{xwidget-webkit-finish-search}. +@end defun + +@defun xwidget-webkit-next-result xwidget +Display the next search result in @var{xwidget}. This function will +error unless a search query has already been started in @var{xwidget} +through @code{xwidget-webkit-search}. + +If @code{wrap-around} was non-nil when @code{xwidget-webkit-search} +was called, then the search will restart from the beginning of the +document if the end is reached. +@end defun + +@defun xwidget-webkit-previous-result xwidget +Display the previous search result in @var{xwidget}. This function +will error unless a search query has already been started in +@var{xwidget} through @code{xwidget-webkit-search}. + +If @code{wrap-around} was non-nil when @code{xwidget-webkit-search} +was called, then the search will restart from the end of the +document if the beginning is reached. +@end defun + +@defun xwidget-webkit-finish-search xwidget +Finish a search operation started with @code{xwidget-webkit-search} in +@var{xwidget}. If there is no query currently ongoing, then this +function will error. +@end defun + @node Buttons @section Buttons @cindex buttons in buffers diff --git a/etc/NEWS b/etc/NEWS index a50229916f..b14f9a2549 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -495,6 +495,31 @@ the buffer will take you to that directory. This is a convenience function to extract the field data from 'exif-parse-file' and 'exif-parse-buffer'. +** Xwidgets + ++++ +*** New minor mode `xwidget-webkit-edit-mode'. +When this mode is enabled, self-inserting characters and other common +web browser shotcut keys are redefined to send themselves to the +WebKit widget. + ++++ +*** New minor mode `xwidget-webkit-isearch-mode'. +This mode acts similarly to incremental search, and allows to search +the contents of a WebKit widget. In xwidget-webkit mode, it is bound +to `C-s' and `C-r'. + +--- +*** On X11, the WebKit inspector is now available inside xwidgets. +To access the inspector, right click on the widget and select "Inspect +Element". + +--- +*** "Open in New Window" in a WebKit widget's context menu now works. +The newly created buffer will be displayed via display-buffer, which +can be customized through the usual mechanism of display-buffer-alist +and friends. + * New Modes and Packages in Emacs 29.1 @@ -719,6 +744,39 @@ an exact match, then the lowercased '[menu-bar foo\ bar]' and finally '[menu-bar foo-bar]'. This further improves backwards-compatibility when converting menus to use 'easy-menu-define'. ++++ +** The function `make-xwidget' now accepts an optional RELATED argument. +This argument is used as another widget for the newly created WebKit +widget to share settings and subprocesses with. It must be another +WebKit widget. + ++++ +** New function `xwidget-perform-lispy-event'. +This function allows you to send events to xwidgets. Usually, some +equivalent of the event will be sent, but there is no guarantee of +what the widget will actually receive. + +On GTK+, only key and function key events are implemented. + ++++ +** New functions for performing searches on WebKit xwidgets. +Some new functions, such as `xwidget-webkit-search', have been added +for performing searches on WebKit xwidgets. + ++++ +** `load-changed' xwidget events are now more detailed. +In particular, they can now have different arguments based on the +state of the WebKit widget. `load-finished' is sent when a load has +completed, `load-started' when a load first starts, `load-redirected' +after a redirect, and `load-committed' when the WebKit widget first +commits to the load. + ++++ +** New event type `xwidget-display-event'. +These events are sent whenever an xwidget requests that Emacs display +another. The only argument to this event is the xwidget that should +be displayed. + * Changes in Emacs 29.1 on Non-Free Operating Systems diff --git a/etc/images/README b/etc/images/README index 9bbe796cc9..561cfff765 100644 --- a/etc/images/README +++ b/etc/images/README @@ -68,6 +68,7 @@ Emacs images and their source in the GNOME icons stock/ directory: bookmark_add.xpm actions/bookmark_add cancel.xpm slightly modified generic/stock_stop connect.xpm net/stock_connect + connect-to-url.xpm net/stock_connect-to-url contact.xpm net/stock_contact data-save.xpm data/stock_data-save delete.xpm generic/stock_delete diff --git a/etc/images/connect-to-url.pbm b/etc/images/connect-to-url.pbm new file mode 100644 index 0000000000..f142349f4a Binary files /dev/null and b/etc/images/connect-to-url.pbm differ diff --git a/etc/images/connect-to-url.xpm b/etc/images/connect-to-url.xpm new file mode 100644 index 0000000000..38fefeaf61 --- /dev/null +++ b/etc/images/connect-to-url.xpm @@ -0,0 +1,281 @@ +/* XPM */ +static char *connect_to_url[] = { +/* columns rows colors chars-per-pixel */ +"24 24 251 2 ", +" c black", +". c #010101", +"X c #000103", +"o c #010204", +"O c #010305", +"+ c #020407", +"@ c #020609", +"# c #03070C", +"$ c #04080D", +"% c #0F0F0D", +"& c #030A10", +"* c #050B10", +"= c #060C11", +"- c #070D13", +"; c #070D14", +": c #060C15", +"> c #070E14", +", c #0B1824", +"< c #0A1B2B", +"1 c #0A1C2E", +"2 c #141A20", +"3 c #161E25", +"4 c #181E23", +"5 c #0D2032", +"6 c #142534", +"7 c #1F2830", +"8 c #1D2933", +"9 c #102438", +"0 c #272622", +"q c #21292F", +"w c #272F36", +"e c #282F33", +"r c #222F3A", +"t c #2E3337", +"y c #2D373E", +"u c #32383C", +"i c #33383C", +"p c #343A3E", +"a c #43423C", +"s c #112941", +"d c #102A44", +"f c #132D47", +"g c #192F46", +"h c #17314B", +"j c #15314F", +"k c #163351", +"l c #163554", +"z c #173554", +"x c #1F3A53", +"c c #1D3955", +"v c #1A3958", +"b c #1C3B5B", +"n c #1F3C58", +"m c #1D3C5C", +"M c #1E3E5D", +"N c #1F3F5F", +"B c #303B44", +"V c #313C44", +"C c #313D47", +"Z c #213C56", +"A c #233E57", +"S c #1F405F", +"D c #374148", +"F c #2D4050", +"G c #25405B", +"H c #25425E", +"J c #214262", +"K c #244565", +"L c #264665", +"P c #254666", +"I c #2A4967", +"U c #284969", +"Y c #2A4C6C", +"T c #2C4F6F", +"R c #33526E", +"E c #385269", +"W c #2D5070", +"Q c #2E5172", +"! c #335473", +"~ c #3F5B75", +"^ c #3D5F7D", +"/ c #41494F", +"( c #646056", +") c #6C685E", +"_ c #505F6C", +"` c #48657C", +"' c #556A7A", +"] c #5B6C78", +"[ c #5F6F7B", +"{ c #5D6F7D", +"} c #706C62", +"| c #726D63", +" . c #78756B", +".. c #7D786E", +"X. c #60727F", +"o. c #807D74", +"O. c #8A857B", +"+. c #8B877E", +"@. c #4E6A83", +"#. c #4A6A86", +"$. c #4A7090", +"%. c #587790", +"&. c #5F7E95", +"*. c #587B98", +"=. c #6F7980", +"-. c #697F8F", +";. c #66839B", +":. c #6A879F", +">. c #708391", +",. c #728A9A", +"<. c #748898", +"1. c #758A99", +"2. c #7B8F9F", +"3. c #708DA4", +"4. c #7990A1", +"5. c #7292AB", +"6. c #7691A8", +"7. c #7693AB", +"8. c #7B98AE", +"9. c #7E98AD", +"0. c #7E9DB3", +"q. c #7F9EB4", +"w. c #8C8981", +"e. c #989389", +"r. c #A6A29B", +"t. c #8093A1", +"y. c #8598A3", +"u. c #8498A7", +"i. c #809AAD", +"p. c #8F9FAA", +"a. c #899FAE", +"s. c #819FB5", +"d. c #86A2B8", +"f. c #87A5BB", +"g. c #88A3B8", +"h. c #89A5BA", +"j. c #8FABBF", +"k. c #97A7B1", +"l. c #90AABE", +"z. c #91ABBF", +"x. c #98ACB9", +"c. c #AAA7A0", +"v. c #B1ADA4", +"b. c #B3B1AA", +"n. c #B7B3AA", +"m. c #A3B1BC", +"M. c #A5B1BC", +"N. c #A9B6BF", +"B. c #BEBBB5", +"V. c #C4C2BD", +"C. c #94AEC1", +"Z. c #96AEC1", +"A. c #94AFC2", +"S. c #95AFC2", +"D. c #96B0C3", +"F. c #98B0C3", +"G. c #9FB5C3", +"H. c #99B3C6", +"J. c #98B3C7", +"K. c #9AB3C6", +"L. c #9BB4C7", +"P. c #9FB8CA", +"I. c #9FB8CB", +"U. c #A2B8C9", +"Y. c #A3B9C9", +"T. c #A0B9CB", +"R. c #A3BACB", +"E. c #A0B9CC", +"W. c #A2BACC", +"Q. c #A4BDCE", +"!. c #A6BECF", +"~. c #B8BEC2", +"^. c #B8C3CA", +"/. c #BCC5CB", +"(. c #BDC8CE", +"). c #A8C0D1", +"_. c #AAC0D0", +"`. c #ABC1D1", +"'. c #ACC2D3", +"]. c #AAC5D7", +"[. c #B4C8D6", +"{. c #BDCBD5", +"}. c #B4C9D8", +"|. c #B6CAD8", +" X c #B8CBD9", +".X c #BBCDDB", +"XX c #B7D0E0", +"oX c #BDD3E2", +"OX c #BCD5E5", +"+X c #CECAC3", +"@X c #C5D2C8", +"#X c #C0D2DE", +"$X c #C4D3DF", +"%X c #CCD7DE", +"&X c #D2D8DC", +"*X c #E1DFDB", +"=X c #E2E1DD", +"-X c #C2D3E0", +";X c #C2D4E1", +":X c #C5D5E1", +">X c #C6D6E1", +",X c #C4D6E2", +". e.o. sXwX}.R.R.`.H.1.- JXJX", +"JX4 a.9.C.h.] a n.V.BXo. p.!.T.l.4.- JXJX", +"JX2 F.d.5.7. =XAXc.BXo. @X@XZX !.C.F.@.> JXJX", +" o.=XAXc.BXo. t.U.z.3.Y $ JXJX", +"BXBXBXBXVXBXBXAXVXO.CXo. P.C.!.I.J.C.;.L * JXJX", +"o.o.o.o.o. . .B.b...*X . $.*.T.J.A.h.Y c @ JXJX", +" .w.r.| +X . 1.C.3.L h JXJX", +"JXJX6 Q ^ 1.% w.r.| +X . @X@XHX h.:.M , JXJX", +"JXJXO x T #.] 0 +.} v.) -.s.H 9 O JXJXJX", +"JXJXJX+ n ! i.X.% % e.( Q Y %.0.&.f O JXJXJX", +"JXJXJXJX& A s.8.E A % % A K J R ` g @ JXJXJXJX", +"JXJXJXJXJX@ C ~ m M J N M b v l < O JXJXJXJXJX", +"JXJXJXJXJXJX : 5 d k z k d 1 & JXJXJXJXJXJX", +"JXJXJXJXJXJXJXJX JXJXJXJXJXJXJXJX", +"JXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJX", +"JXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJX" +}; diff --git a/lisp/xwidget.el b/lisp/xwidget.el index 8c593abea8..4046140895 100644 --- a/lisp/xwidget.el +++ b/lisp/xwidget.el @@ -35,8 +35,9 @@ (require 'bookmark) (declare-function make-xwidget "xwidget.c" - (type title width height arguments &optional buffer)) + (type title width height arguments &optional buffer related)) (declare-function xwidget-buffer "xwidget.c" (xwidget)) +(declare-function set-xwidget-buffer "xwidget.c" (xwidget buffer)) (declare-function xwidget-size-request "xwidget.c" (xwidget)) (declare-function xwidget-resize "xwidget.c" (xwidget new-width new-height)) (declare-function xwidget-webkit-execute-script "xwidget.c" @@ -58,14 +59,14 @@ xwidget "Displaying native widgets in Emacs buffers." :group 'widgets) -(defun xwidget-insert (pos type title width height &optional args) +(defun xwidget-insert (pos type title width height &optional args related) "Insert an xwidget at position POS. -Supply the xwidget's TYPE, TITLE, WIDTH, and HEIGHT. +Supply the xwidget's TYPE, TITLE, WIDTH, HEIGHT, and RELATED. See `make-xwidget' for the possible TYPE values. The usage of optional argument ARGS depends on the xwidget. This returns the result of `make-xwidget'." (goto-char pos) - (let ((id (make-xwidget type title width height args))) + (let ((id (make-xwidget type title width height args nil related))) (put-text-property (point) (+ 1 (point)) 'display (list 'xwidget ':xwidget id)) id)) @@ -88,6 +89,9 @@ xwidget-at (require 'seq) (require 'url-handlers) +(defvar-local xwidget-webkit--title "" + "The title of the WebKit widget, used for the header line.") + ;;;###autoload (defun xwidget-webkit-browse-url (url &optional new-session) "Ask xwidget-webkit to browse URL. @@ -124,6 +128,14 @@ xwidget-webkit-clone-and-split-right (with-selected-window (split-window-right) (xwidget-webkit-new-session url)))) +(declare-function xwidget-perform-lispy-event "xwidget.c") + +(defun xwidget-webkit-pass-command-event () + "Pass `last-command-event' to the current buffer's WebKit widget." + (interactive) + (xwidget-perform-lispy-event (xwidget-webkit-current-session) + last-command-event)) + ;;todo. ;; - check that the webkit support is compiled in (defvar xwidget-webkit-mode-map @@ -138,6 +150,9 @@ xwidget-webkit-mode-map (define-key map "w" 'xwidget-webkit-current-url) (define-key map "+" 'xwidget-webkit-zoom-in) (define-key map "-" 'xwidget-webkit-zoom-out) + (define-key map "e" 'xwidget-webkit-edit-mode) + (define-key map "\C-r" 'xwidget-webkit-isearch-mode) + (define-key map "\C-s" 'xwidget-webkit-isearch-mode) ;;similar to image mode bindings (define-key map (kbd "SPC") 'xwidget-webkit-scroll-up) @@ -164,6 +179,63 @@ xwidget-webkit-mode-map map) "Keymap for `xwidget-webkit-mode'.") +(easy-menu-define nil xwidget-webkit-mode-map "Xwidget WebKit menu." + (list "Xwidget WebKit" + ["Browse URL" xwidget-webkit-browse-url + :active t + :help "Prompt for a URL, then instruct WebKit to browse it"] + ["Back" xwidget-webkit-back t] + ["Forward" xwidget-webkit-forward t] + ["Reload" xwidget-webkit-reload t] + ["Insert String" xwidget-webkit-insert-string + :active t + :help "Insert a string into the currently active field"] + ["Zoom In" xwidget-webkit-zoom-in t] + ["Zoom Out" xwidget-webkit-zoom-out t] + ["Edit Mode" xwidget-webkit-edit-mode + :active t + :style toggle + :selected xwidget-webkit-edit-mode + :help "Send self inserting characters to the WebKit widget"] + ["Save Selection" xwidget-webkit-copy-selection-as-kill + :active t + :help "Save the browser's selection in the kill ring"] + ["Incremental Search" xwidget-webkit-isearch-mode + :active (not xwidget-webkit-isearch-mode) + :help "Perform incremental search inside the WebKit widget"])) + +(defvar xwidget-webkit-tool-bar-map + (let ((map (make-sparse-keymap))) + (prog1 map + (tool-bar-local-item-from-menu 'xwidget-webkit-back + "left-arrow" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-forward + "right-arrow" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-reload + "refresh" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-zoom-in + "zoom-in" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-zoom-out + "zoom-out" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-browse-url + "connect-to-url" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-isearch-mode + "search" + map + xwidget-webkit-mode-map)))) + (defun xwidget-webkit-zoom-in () "Increase webkit view zoom factor." (interactive nil xwidget-webkit-mode) @@ -276,6 +348,8 @@ xwidget-webkit-callback (with-current-buffer (xwidget-buffer xwidget) (cond ((eq xwidget-event-type 'load-changed) (let ((title (xwidget-webkit-title xwidget))) + (setq xwidget-webkit--title title) + (force-mode-line-update) (xwidget-log "webkit finished loading: %s" title) ;; Do not adjust webkit size to window here, the selected window ;; can be the mini-buffer window unwantedly. @@ -309,8 +383,10 @@ bookmark-make-record-function (define-derived-mode xwidget-webkit-mode special-mode "xwidget-webkit" "Xwidget webkit view mode." (setq buffer-read-only t) + (setq-local tool-bar-map xwidget-webkit-tool-bar-map) (setq-local bookmark-make-record-function #'xwidget-webkit-bookmark-make-record) + (setq-local header-line-format 'xwidget-webkit--title) ;; Keep track of [vh]scroll when switching buffers (image-mode-setup-winprops)) @@ -609,6 +685,7 @@ xwidget-webkit-new-session (let* ((bufname (generate-new-buffer-name "*xwidget-webkit*")) (callback (or callback #'xwidget-webkit-callback)) + (current-session (xwidget-webkit-current-session)) xw) (setq xwidget-webkit-last-session-buffer (switch-to-buffer (get-buffer-create bufname))) @@ -621,11 +698,35 @@ xwidget-webkit-new-session (setq xw (xwidget-insert start 'webkit bufname (xwidget-window-inside-pixel-width (selected-window)) - (xwidget-window-inside-pixel-height (selected-window))))) + (xwidget-window-inside-pixel-height (selected-window)) + nil current-session))) (xwidget-put xw 'callback callback) (xwidget-webkit-mode) (xwidget-webkit-goto-uri (xwidget-webkit-last-session) url))) +(defun xwidget-webkit-import-widget (xwidget) + "Create a new webkit session buffer from XWIDGET, an existing xwidget. +Return the buffer." + (let* ((bufname (generate-new-buffer-name "*xwidget-webkit*")) + (callback #'xwidget-webkit-callback) + (buffer (get-buffer-create bufname))) + (with-current-buffer buffer + (save-excursion + (erase-buffer) + (insert ".") + (put-text-property (point-min) (point-max) + 'display (list 'xwidget :xwidget xwidget))) + (xwidget-put xwidget 'callback callback) + (set-xwidget-buffer xwidget buffer) + (xwidget-webkit-mode)) + buffer)) + +(defun xwidget-webkit-display-event (event) + "Import the xwidget inside EVENT and display it." + (interactive "e") + (display-buffer (xwidget-webkit-import-widget (nth 1 event)))) + +(global-set-key [xwidget-display-event] 'xwidget-webkit-display-event) (defun xwidget-webkit-goto-url (url) "Goto URL with xwidget webkit." @@ -684,6 +785,165 @@ xwidget-put (set-xwidget-plist xwidget (plist-put (xwidget-plist xwidget) propname value))) +(defvar xwidget-webkit-edit-mode-map (make-keymap)) + +(define-key xwidget-webkit-edit-mode-map [backspace] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [tab] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [left] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [right] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [up] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [down] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [return] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-left] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-right] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-up] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-down] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-return] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-left] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-right] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-up] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-down] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-return] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-left] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-right] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-up] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-down] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-return] 'xwidget-webkit-pass-command-event) + +(define-minor-mode xwidget-webkit-edit-mode + "Minor mode for editing the content of WebKit buffers. + +This defines most self-inserting characters and some common +keyboard shortcuts to `xwidget-webkit-pass-command-event', which +will pass the key events corresponding to these characters to the +WebKit widget." + :keymap xwidget-webkit-edit-mode-map) + +(substitute-key-definition 'self-insert-command + 'xwidget-webkit-pass-command-event + xwidget-webkit-edit-mode-map + global-map) + +(declare-function xwidget-webkit-search "xwidget.c") +(declare-function xwidget-webkit-next-result "xwidget.c") +(declare-function xwidget-webkit-previous-result "xwidget.c") +(declare-function xwidget-webkit-finish-search "xwidget.c") + +(defvar-local xwidget-webkit-isearch--string "" + "The current search query.") +(defvar-local xwidget-webkit-isearch--is-reverse nil + "Whether or not the current isearch should be reverse.") + +(defun xwidget-webkit-isearch--update (&optional only-message) + "Update the current buffer's WebKit widget's search query. +If ONLY-MESSAGE is non-nil, the query will not be sent to the +WebKit widget. The query will be set to the contents of +`xwidget-webkit-isearch--string'." + (unless only-message + (xwidget-webkit-search xwidget-webkit-isearch--string + (xwidget-webkit-current-session) + t xwidget-webkit-isearch--is-reverse t)) + (message (concat (propertize "Search contents: " 'face 'minibuffer-prompt) + xwidget-webkit-isearch--string))) + +(defun xwidget-webkit-isearch-erasing-char (count) + "Erase the last COUNT characters of the current query." + (interactive (list (prefix-numeric-value current-prefix-arg))) + (when (> (length xwidget-webkit-isearch--string) 0) + (setq xwidget-webkit-isearch--string + (substring xwidget-webkit-isearch--string 0 + (- (length xwidget-webkit-isearch--string) count)))) + (xwidget-webkit-isearch--update)) + +(defun xwidget-webkit-isearch-printing-char (char &optional count) + "Add ordinary character CHAR to the search string and search. +With argument, add COUNT copies of CHAR." + (interactive (list last-command-event + (prefix-numeric-value current-prefix-arg))) + (setq xwidget-webkit-isearch--string (concat xwidget-webkit-isearch--string + (make-string (or count 1) char))) + (xwidget-webkit-isearch--update)) + +(defun xwidget-webkit-isearch-forward (count) + "Move to the next search result COUNT times." + (interactive (list (prefix-numeric-value current-prefix-arg))) + (let ((was-reverse xwidget-webkit-isearch--is-reverse)) + (setq xwidget-webkit-isearch--is-reverse nil) + (when was-reverse + (xwidget-webkit-isearch--update))) + (let ((i 0)) + (while (< i count) + (xwidget-webkit-next-result (xwidget-webkit-current-session)) + (cl-incf i))) + (xwidget-webkit-isearch--update t)) + +(defun xwidget-webkit-isearch-backward (count) + "Move to the previous search result COUNT times." + (interactive (list (prefix-numeric-value current-prefix-arg))) + (let ((was-reverse xwidget-webkit-isearch--is-reverse)) + (setq xwidget-webkit-isearch--is-reverse t) + (unless was-reverse + (xwidget-webkit-isearch--update))) + (let ((i 0)) + (while (< i count) + (xwidget-webkit-next-result (xwidget-webkit-current-session)) + (cl-incf i))) + (xwidget-webkit-isearch--update t)) + +(defun xwidget-webkit-isearch-exit () + "Exit incremental search of a WebKit buffer." + (interactive) + (xwidget-webkit-isearch-mode 0)) + +(defvar xwidget-webkit-isearch-mode-map (make-keymap) + "The keymap used inside xwidget-webkit-isearch-mode.") + +(set-char-table-range (nth 1 xwidget-webkit-isearch-mode-map) + (cons 0 (max-char)) + 'xwidget-webkit-isearch-exit) + +(substitute-key-definition 'self-insert-command + 'xwidget-webkit-isearch-printing-char + xwidget-webkit-isearch-mode-map + global-map) + +(define-key xwidget-webkit-isearch-mode-map (kbd "DEL") + 'xwidget-webkit-isearch-erasing-char) +(define-key xwidget-webkit-isearch-mode-map [return] 'xwidget-webkit-isearch-exit) +(define-key xwidget-webkit-isearch-mode-map "\r" 'xwidget-webkit-isearch-exit) +(define-key xwidget-webkit-isearch-mode-map "\C-g" 'xwidget-webkit-isearch-exit) +(define-key xwidget-webkit-isearch-mode-map "\C-r" 'xwidget-webkit-isearch-backward) +(define-key xwidget-webkit-isearch-mode-map "\C-s" 'xwidget-webkit-isearch-forward) +(define-key xwidget-webkit-isearch-mode-map "\t" 'xwidget-webkit-isearch-printing-char) + +(let ((meta-map (make-keymap))) + (set-char-table-range (nth 1 meta-map) + (cons 0 (max-char)) + 'xwidget-webkit-isearch-exit) + (define-key xwidget-webkit-isearch-mode-map (char-to-string meta-prefix-char) meta-map)) + +(define-minor-mode xwidget-webkit-isearch-mode + "Minor mode for performing incremental search inside WebKit buffers. + +An attempt was made for this to resemble regular incremental +search, but it suffers from several limitations, such as not +supporting recursive edits. + +If this mode is enabled with `C-r', then the search will default +to being performed in reverse direction. + +To navigate around the search results, type +\\[xwidget-webkit-isearch-forward] to move forward, and +\\[xwidget-webkit-isearch-backward] to move backward. + +Press \\[xwidget-webkit-isearch-exit] to exit incremental search." + :keymap xwidget-webkit-isearch-mode-map + (if xwidget-webkit-isearch-mode + (progn + (setq xwidget-webkit-isearch--string "") + (setq xwidget-webkit-isearch--is-reverse (eq last-command-event ?\C-r)) + (xwidget-webkit-isearch--update)) + (xwidget-webkit-finish-search (xwidget-webkit-current-session)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/src/dispextern.h b/src/dispextern.h index 5b28fe7666..f17f095e0d 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -536,8 +536,8 @@ #define FACE_ID_BITS 20 int img_id; #ifdef HAVE_XWIDGETS - /* Xwidget reference (type == XWIDGET_GLYPH). */ - struct xwidget *xwidget; + /* Xwidget ID. */ + uint32_t xwidget; #endif /* Sub-structure for type == STRETCH_GLYPH. */ diff --git a/src/dispnew.c b/src/dispnew.c index 4a73244c89..632eec2f03 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -4449,16 +4449,6 @@ scrolling_window (struct window *w, int tab_line_p) break; } -#ifdef HAVE_XWIDGETS - /* Currently this seems needed to detect xwidget movement reliably. - This is most probably because an xwidget glyph is represented in - struct glyph's 'union u' by a pointer to a struct, which takes 8 - bytes in 64-bit builds, and thus the comparison of u.val values - done by GLYPH_EQUAL_P doesn't work reliably, since it assumes the - size of the union is 4 bytes. FIXME. */ - return 0; -#endif - /* Can't scroll the display of w32 GUI frames when position of point is indicated by the system caret, because scrolling the display will then "copy" the pixels used by the caret. */ diff --git a/src/keyboard.c b/src/keyboard.c index aa6a4b9e97..c4a5671b10 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -3993,6 +3993,7 @@ kbd_buffer_get_event (KBOARD **kbp, #endif #ifdef HAVE_XWIDGETS case XWIDGET_EVENT: + case XWIDGET_DISPLAY_EVENT: #endif case SAVE_SESSION_EVENT: case NO_EVENT: @@ -4897,7 +4898,7 @@ #define FUNCTION_KEY_OFFSET 0xff00 /* You'll notice that this table is arranged to be conveniently indexed by X Windows keysym values. */ -static const char *const lispy_function_keys[] = +const char *const lispy_function_keys[] = { /* X Keysym value */ @@ -6139,6 +6140,11 @@ make_lispy_event (struct input_event *event) { return Fcons (Qxwidget_event, event->arg); } + + case XWIDGET_DISPLAY_EVENT: + { + return list2 (Qxwidget_display_event, event->arg); + } #endif #ifdef USE_FILE_NOTIFY @@ -11732,6 +11738,7 @@ syms_of_keyboard (void) #ifdef HAVE_XWIDGETS DEFSYM (Qxwidget_event, "xwidget-event"); + DEFSYM (Qxwidget_display_event, "xwidget-display-event"); #endif #ifdef USE_FILE_NOTIFY diff --git a/src/keyboard.h b/src/keyboard.h index 8bdffaa2bf..21c51ec386 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -491,7 +491,7 @@ kbd_buffer_store_event_hold (struct input_event *event, extern struct timespec timer_check (void); extern void mark_kboards (void); -#ifdef HAVE_NTGUI +#if defined HAVE_NTGUI || defined HAVE_X_WINDOWS extern const char *const lispy_function_keys[]; #endif diff --git a/src/print.c b/src/print.c index c13294c8e6..adadb289de 100644 --- a/src/print.c +++ b/src/print.c @@ -1521,8 +1521,26 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag, printchar ('>', printcharfun); break; - case PVEC_XWIDGET: case PVEC_XWIDGET_VIEW: - print_c_string ("#", + XXWIDGET (obj)->xwidget_id, + XXWIDGET (obj)->widget_osr); +#else + int len = sprintf (buf, "#", + XXWIDGET (obj)->xwidget_id, + XXWIDGET (obj)->xwWidget); +#endif + strout (buf, len, len, printcharfun); + break; + } +#else + emacs_abort (); +#endif + case PVEC_XWIDGET_VIEW: + print_c_string ("#', printcharfun); break; diff --git a/src/termhooks.h b/src/termhooks.h index 1d3cdc8fe8..e7539bbce2 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -255,6 +255,8 @@ #define EMACS_TERMHOOKS_H #ifdef HAVE_XWIDGETS /* events generated by xwidgets*/ , XWIDGET_EVENT + /* Event generated when WebKit asks us to display another widget. */ + , XWIDGET_DISPLAY_EVENT #endif #ifdef USE_FILE_NOTIFY diff --git a/src/xdisp.c b/src/xdisp.c index 86c4e704d5..d7ad548917 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -28429,7 +28429,7 @@ fill_xwidget_glyph_string (struct glyph_string *s) } s->width = s->first_glyph->pixel_width; s->ybase += s->first_glyph->voffset; - s->xwidget = s->first_glyph->u.xwidget; + s->xwidget = xwidget_from_id (s->first_glyph->u.xwidget); } #endif /* Fill glyph string S from a sequence of stretch glyphs. @@ -29832,7 +29832,7 @@ produce_xwidget_glyph (struct it *it) glyph->padding_p = 0; glyph->glyph_not_available_p = 0; glyph->face_id = it->face_id; - glyph->u.xwidget = it->xwidget; + glyph->u.xwidget = it->xwidget->xwidget_id; glyph->font_type = FONT_TYPE_UNKNOWN; if (it->bidi_p) { diff --git a/src/xterm.c b/src/xterm.c index aa1a1a5eed..9b434bffcc 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -4390,6 +4390,86 @@ x_scroll_run (struct window *w, struct run *run) /* Cursor off. Will be switched on again in gui_update_window_end. */ gui_clear_cursor (w); +#ifdef HAVE_XWIDGETS + /* "Copy" xwidget windows in the area that will be scrolled. */ + Display *dpy = FRAME_X_DISPLAY (f); + Window window = FRAME_X_WINDOW (f); + + Window root, parent, *children; + unsigned int nchildren; + + if (XQueryTree (dpy, window, &root, &parent, &children, &nchildren)) + { + /* Now find xwidget views situated between from_y and to_y, and + attached to w. */ + for (unsigned int i = 0; i < nchildren; ++i) + { + Window child = children[i]; + struct xwidget_view *view = xwidget_view_from_window (child); + + if (view) + { + 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; + XUnmapWindow (dpy, child); + 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, TEXT_AREA, &text_area_x, &text_area_y, + &text_area_width, &text_area_height); + + clip_top = max (0, text_area_y - y); + clip_bottom = max (clip_top, + min (XXWIDGET (view->model)->height, + text_area_y + text_area_height - y)); + + view->y = y; + 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_top - view->clip_bottom) <= 0) + { + view->hidden = true; + XUnmapWindow (dpy, child); + } + else + XMoveResizeWindow (dpy, child, view->x + view->clip_left, + view->y + view->clip_top, + view->clip_right - view->clip_left, + view->clip_top - view->clip_bottom); + XFlush (dpy); + } + } + } + XFree (children); + } +#endif + #ifdef USE_CAIRO if (FRAME_CR_CONTEXT (f)) { @@ -4563,8 +4643,9 @@ x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct fra } } -/* Return the Emacs frame-object corresponding to an X window. - It could be the frame's main window or an icon window. */ +/* Return the Emacs frame-object corresponding to an X window. It + could be the frame's main window, an icon window, or an xwidget + window. */ static struct frame * x_window_to_frame (struct x_display_info *dpyinfo, int wdesc) @@ -4575,6 +4656,13 @@ x_window_to_frame (struct x_display_info *dpyinfo, int wdesc) if (wdesc == None) return NULL; +#ifdef HAVE_XWIDGETS + struct xwidget_view *xvw = xwidget_view_from_window (wdesc); + + if (xvw && xvw->frame) + return xvw->frame; +#endif + FOR_EACH_FRAME (tail, frame) { f = XFRAME (frame); @@ -4997,7 +5085,7 @@ x_x_to_emacs_modifiers (struct x_display_info *dpyinfo, int state) | ((state & dpyinfo->hyper_mod_mask) ? mod_hyper : 0)); } -static int +int x_emacs_to_x_modifiers (struct x_display_info *dpyinfo, intmax_t state) { EMACS_INT mod_ctrl = ctrl_modifier; @@ -8211,6 +8299,18 @@ handle_one_xevent (struct x_display_info *dpyinfo, case Expose: f = x_window_to_frame (dpyinfo, event->xexpose.window); +#ifdef HAVE_XWIDGETS + { + struct xwidget_view *xv = + xwidget_view_from_window (event->xexpose.window); + + if (xv) + { + xwidget_expose (xv); + goto OTHER; + } + } +#endif if (f) { if (!FRAME_VISIBLE_P (f)) @@ -8791,6 +8891,31 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_display_set_last_user_time (dpyinfo, event->xcrossing.time); x_detect_focus_change (dpyinfo, any, event, &inev.ie); +#ifdef HAVE_XWIDGETS + { + struct xwidget_view *xvw = xwidget_view_from_window (event->xcrossing.window); + Mouse_HLInfo *hlinfo; + + if (xvw) + { + xwidget_motion_or_crossing (xvw, event); + hlinfo = MOUSE_HL_INFO (xvw->frame); + + if (xvw->frame == hlinfo->mouse_face_mouse_frame) + { + clear_mouse_face (hlinfo); + hlinfo->mouse_face_mouse_frame = 0; + } + + if (any_help_event_p) + { + do_help = -1; + } + goto OTHER; + } + } +#endif + f = any; if (f && x_mouse_click_focus_ignore_position) @@ -8834,6 +8959,17 @@ handle_one_xevent (struct x_display_info *dpyinfo, goto OTHER; case LeaveNotify: +#ifdef HAVE_XWIDGETS + { + struct xwidget_view *xvw = xwidget_view_from_window (event->xcrossing.window); + + if (xvw) + { + xwidget_motion_or_crossing (xvw, event); + goto OTHER; + } + } +#endif x_display_set_last_user_time (dpyinfo, event->xcrossing.time); x_detect_focus_change (dpyinfo, any, event, &inev.ie); @@ -8883,6 +9019,12 @@ handle_one_xevent (struct x_display_info *dpyinfo, #ifdef USE_GTK if (f && xg_event_is_for_scrollbar (f, event)) f = 0; +#endif +#ifdef HAVE_XWIDGETS + struct xwidget_view *xvw = xwidget_view_from_window (event->xmotion.window); + + if (xvw) + xwidget_motion_or_crossing (xvw, event); #endif if (f) { @@ -9138,6 +9280,24 @@ handle_one_xevent (struct x_display_info *dpyinfo, case ButtonRelease: case ButtonPress: { +#ifdef HAVE_XWIDGETS + struct xwidget_view *xvw = xwidget_view_from_window (event->xmotion.window); + + if (xvw) + { + xwidget_button (xvw, event->type == ButtonPress, + event->xbutton.x, event->xbutton.y, + event->xbutton.button, event->xbutton.state, + event->xbutton.time); + + if (!EQ (selected_window, xvw->w)) + { + inev.ie.kind = SELECT_WINDOW_EVENT; + inev.ie.frame_or_window = xvw->w; + } + goto OTHER; + } +#endif /* If we decide we want to generate an event to be seen by the rest of Emacs, we put it here. */ Lisp_Object tab_bar_arg = Qnil; @@ -12108,6 +12268,10 @@ x_free_frame_resources (struct frame *f) xfree (f->shell_position); #else /* !USE_X_TOOLKIT */ +#ifdef HAVE_XWIDGETS + kill_frame_xwidget_views (f); +#endif + #ifdef USE_GTK xg_free_frame_widgets (f); #endif /* USE_GTK */ diff --git a/src/xterm.h b/src/xterm.h index de6ea50385..9d9534dd62 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -1108,6 +1108,7 @@ #define SELECTION_EVENT_TIME(eventp) \ extern int x_dispatch_event (XEvent *, Display *); #endif extern int x_x_to_emacs_modifiers (struct x_display_info *, int); +extern int x_emacs_to_x_modifiers (struct x_display_info *, intmax_t); #ifdef USE_CAIRO extern void x_cr_destroy_frame_context (struct frame *); extern void x_cr_update_surface_desired_size (struct frame *, int, int); diff --git a/src/xwidget.c b/src/xwidget.c index e4b42e6e0c..78a3860490 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -19,6 +19,7 @@ Copyright (C) 2011-2021 Free Software Foundation, Inc. #include +#include "buffer.h" #include "xwidget.h" #include "lisp.h" @@ -35,10 +36,22 @@ Copyright (C) 2011-2021 Free Software Foundation, Inc. #ifdef USE_GTK #include #include +#include +#include #elif defined NS_IMPL_COCOA #include "nsxwidget.h" #endif +static Lisp_Object id_to_xwidget_map; +static uint32_t xwidget_counter = 0; + +#ifdef USE_GTK +static Lisp_Object x_window_to_xwv_map; +static gboolean offscreen_damage_event (GtkWidget *, GdkEvent *, gpointer); +static void synthesize_focus_in_event (GtkWidget *); +static GdkDevice *find_suitable_keyboard (struct frame *); +#endif + static struct xwidget * allocate_xwidget (void) { @@ -64,18 +77,32 @@ #define XSETXWIDGET_VIEW(a, b) XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW) GAsyncResult *, gpointer); static gboolean webkit_download_cb (WebKitWebContext *, WebKitDownload *, gpointer); - +static GtkWidget *webkit_create_cb (WebKitWebView *, WebKitNavigationAction *, gpointer); static gboolean webkit_decide_policy_cb (WebKitWebView *, WebKitPolicyDecision *, WebKitPolicyDecisionType, gpointer); +static GtkWidget *find_widget_at_pos (GtkWidget *, int, int, int *, int *); + +struct widget_search_data +{ + int x; + int y; + bool foundp; + bool first; + GtkWidget *data; +}; + +static void find_widget (GtkWidget *t, struct widget_search_data *); +static void mouse_target_changed (WebKitWebView *, WebKitHitTestResult *, guint, + gpointer); #endif DEFUN ("make-xwidget", Fmake_xwidget, Smake_xwidget, - 5, 6, 0, + 5, 7, 0, doc: /* Make an xwidget of TYPE. If BUFFER is nil, use the current buffer. If BUFFER is a string and no such buffer exists, create it. @@ -83,10 +110,13 @@ DEFUN ("make-xwidget", - webkit -Returns the newly constructed xwidget, or nil if construction fails. */) +RELATED is nil, or an xwidget. When constructing a WebKit widget, it +will share the same settings and internal subprocess as RELATED. +Returns the newly constructed xwidget, or nil if construction +fails. */) (Lisp_Object type, Lisp_Object title, Lisp_Object width, Lisp_Object height, - Lisp_Object arguments, Lisp_Object buffer) + Lisp_Object arguments, Lisp_Object buffer, Lisp_Object related) { #ifdef USE_GTK if (!xg_gtk_initialized) @@ -108,13 +138,19 @@ DEFUN ("make-xwidget", XSETXWIDGET (val, xw); Vxwidget_list = Fcons (val, Vxwidget_list); xw->plist = Qnil; + xw->xwidget_id = ++xwidget_counter; + xw->find_text = NULL; + + Fputhash (make_fixnum (xw->xwidget_id), val, id_to_xwidget_map); #ifdef USE_GTK xw->widgetwindow_osr = NULL; xw->widget_osr = NULL; + xw->hit_result = 0; if (EQ (xw->type, Qwebkit)) { block_input (); + WebKitSettings *settings; WebKitWebContext *webkit_context = webkit_web_context_get_default (); # if WEBKIT_CHECK_VERSION (2, 26, 0) @@ -128,18 +164,34 @@ DEFUN ("make-xwidget", if (EQ (xw->type, Qwebkit)) { - xw->widget_osr = webkit_web_view_new (); - - /* webkitgtk uses GSubprocess which sets sigaction causing - Emacs to not catch SIGCHLD with its usual handle setup in - catch_child_signal(). This resets the SIGCHLD - sigaction. */ - struct sigaction old_action; - sigaction (SIGCHLD, NULL, &old_action); - webkit_web_view_load_uri(WEBKIT_WEB_VIEW (xw->widget_osr), - "about:blank"); - sigaction (SIGCHLD, &old_action, NULL); - } + WebKitWebView *related_view; + + if (NILP (related) + || !XWIDGETP (related) + || !EQ (XXWIDGET (related)->type, Qwebkit)) + { + xw->widget_osr = webkit_web_view_new (); + + /* webkitgtk uses GSubprocess which sets sigaction causing + Emacs to not catch SIGCHLD with its usual handle setup in + catch_child_signal(). This resets the SIGCHLD + sigaction. */ + struct sigaction old_action; + sigaction (SIGCHLD, NULL, &old_action); + webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr), + "about:blank"); + sigaction (SIGCHLD, &old_action, NULL); + } + else + { + related_view = WEBKIT_WEB_VIEW (XXWIDGET (related)->widget_osr); + xw->widget_osr = webkit_web_view_new_with_related_view (related_view); + } + + /* Enable the developer extras */ + settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (xw->widget_osr)); + g_object_set (G_OBJECT (settings), "enable-developer-extras", TRUE, NULL); + } gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height); @@ -157,6 +209,7 @@ DEFUN ("make-xwidget", gtk_widget_show (xw->widget_osr); gtk_widget_show (xw->widgetwindow_osr); + synthesize_focus_in_event (xw->widgetwindow_osr); /* Store some xwidget data in the gtk widgets for convenient retrieval in the event handlers. */ @@ -179,8 +232,20 @@ DEFUN ("make-xwidget", G_CALLBACK (webkit_decide_policy_cb), xw); + + g_signal_connect (G_OBJECT (xw->widget_osr), + "mouse-target-changed", + G_CALLBACK (mouse_target_changed), + xw); + g_signal_connect (G_OBJECT (xw->widget_osr), + "create", + G_CALLBACK (webkit_create_cb), + xw); } + g_signal_connect (G_OBJECT (xw->widgetwindow_osr), "damage-event", + G_CALLBACK (offscreen_damage_event), xw); + unblock_input (); } #elif defined NS_IMPL_COCOA @@ -190,6 +255,158 @@ DEFUN ("make-xwidget", return val; } +#ifdef USE_GTK +static void +set_widget_if_text_view (GtkWidget *widget, void *data) +{ + GtkWidget **pointer = data; + + if (GTK_IS_TEXT_VIEW (widget)) + { + *pointer = widget; + } +} +#endif + +DEFUN ("xwidget-perform-lispy-event", + Fxwidget_perform_lispy_event, Sxwidget_perform_lispy_event, + 2, 3, 0, doc: /* Send a lispy event to XWIDGET. +EVENT should be the event that will be sent. FRAME should be the +frame which generated the event, or nil. On X11, modifier keys will +not be processed if FRAME is nil and the selected frame is not an +X-Windows frame. */) + (Lisp_Object xwidget, Lisp_Object event, Lisp_Object frame) +{ + struct xwidget *xw; + struct frame *f = NULL; + int character = -1, keycode = -1; + int modifiers = 0; + +#ifdef USE_GTK + GdkEvent *xg_event; + GtkContainerClass *klass; + GtkWidget *widget; + GtkWidget *temp = NULL; +#endif + + CHECK_XWIDGET (xwidget); + xw = XXWIDGET (xwidget); + + if (!NILP (frame)) + f = decode_window_system_frame (frame); + else if (FRAME_X_P (SELECTED_FRAME ())) + f = SELECTED_FRAME (); + +#ifdef USE_GTK + widget = gtk_window_get_focus (GTK_WINDOW (xw->widgetwindow_osr)); + + if (!widget) + widget = xw->widget_osr; + + if (RANGED_FIXNUMP (0, event, INT_MAX)) + { + character = XFIXNUM (event); + + if (character < 32) + modifiers |= ctrl_modifier; + + modifiers |= character & meta_modifier; + modifiers |= character & hyper_modifier; + modifiers |= character & super_modifier; + modifiers |= character & shift_modifier; + modifiers |= character & ctrl_modifier; + + character = character & ~(1 << 21); + + if (character < 32) + character += '_'; + + if (f) + modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f), modifiers); + else + modifiers = 0; + } + else if (SYMBOLP (event)) + { + Lisp_Object decoded = parse_modifiers (event); + Lisp_Object decoded_name = SYMBOL_NAME (XCAR (decoded)); + + int off = 0; + bool found = false; + + while (off < 256) + { + if (lispy_function_keys[off] + && !strcmp (lispy_function_keys[off], + SSDATA (decoded_name))) + { + found = true; + break; + } + ++off; + } + + if (f) + modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f), + XFIXNUM (XCAR (XCDR (decoded)))); + else + modifiers = 0; + + if (found) + keycode = off + 0xff00; + } + + if (character == -1 && keycode == -1) + return Qnil; + + block_input (); + xg_event = gdk_event_new (GDK_KEY_PRESS); + xg_event->any.window = gtk_widget_get_window (xw->widget_osr); + g_object_ref (xg_event->any.window); + + if (character > -1) + keycode = gdk_unicode_to_keyval (character); + + xg_event->key.keyval = keycode; + xg_event->key.state = modifiers; + + if (keycode > -1) + { + /* WebKitGTK internals abuse follows. */ + if (WEBKIT_IS_WEB_VIEW (widget)) + { + /* WebKitGTK relies on an internal GtkTextView object to + "translate" keys such as backspace. We must find that + widget and activate its binding to this key if any. */ + klass = GTK_CONTAINER_CLASS (G_OBJECT_GET_CLASS (widget)); + + klass->forall (GTK_CONTAINER (xw->widget_osr), TRUE, + set_widget_if_text_view, &temp); + + if (GTK_IS_WIDGET (temp)) + { + if (!gtk_widget_get_realized (temp)) + gtk_widget_realize (temp); + + gtk_bindings_activate (G_OBJECT (temp), keycode, modifiers); + } + } + } + + if (f) + gdk_event_set_device (xg_event, + find_suitable_keyboard (SELECTED_FRAME ())); + + gtk_main_do_event (xg_event); + xg_event->type = GDK_KEY_RELEASE; + gtk_main_do_event (xg_event); + gdk_event_free (xg_event); + unblock_input (); +#endif + + return Qnil; +} + DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets, Sget_buffer_xwidgets, 1, 1, 0, doc: /* Return a list of xwidgets associated with BUFFER. @@ -221,16 +438,397 @@ xwidget_hidden (struct xwidget_view *xv) return xv->hidden; } +struct xwidget * +xwidget_from_id (uint32_t id) +{ + Lisp_Object key = make_fixnum (id); + Lisp_Object xwidget = Fgethash (key, id_to_xwidget_map, Qnil); + + if (NILP (xwidget)) + emacs_abort (); + + return XXWIDGET (xwidget); +} + #ifdef USE_GTK + +static GdkDevice * +find_suitable_pointer (struct frame *f) +{ + GdkSeat *seat = gdk_display_get_default_seat + (gtk_widget_get_display (FRAME_GTK_WIDGET (f))); + + if (!seat) + return NULL; + + return gdk_seat_get_pointer (seat); +} + +static GdkDevice * +find_suitable_keyboard (struct frame *f) +{ + GdkSeat *seat = gdk_display_get_default_seat + (gtk_widget_get_display (FRAME_GTK_WIDGET (f))); + + if (!seat) + return NULL; + + return gdk_seat_get_keyboard (seat); +} + +static void +find_widget_cb (GtkWidget *widget, void *user) +{ + find_widget (widget, user); +} + +static void +find_widget (GtkWidget *widget, + struct widget_search_data *data) +{ + GtkAllocation new_allocation; + GdkWindow *window; + int x_offset = 0; + int y_offset = 0; + + gtk_widget_get_allocation (widget, &new_allocation); + + if (gtk_widget_get_has_window (widget)) + { + new_allocation.x = 0; + new_allocation.y = 0; + } + + if (gtk_widget_get_parent (widget) && !data->first) + { + window = gtk_widget_get_window (widget); + while (window != gtk_widget_get_window (gtk_widget_get_parent (widget))) + { + gint tx, ty, twidth, theight; + + if (!window) + return; + + twidth = gdk_window_get_width (window); + theight = gdk_window_get_height (window); + + if (new_allocation.x < 0) + { + new_allocation.width += new_allocation.x; + new_allocation.x = 0; + } + + if (new_allocation.y < 0) + { + new_allocation.height += new_allocation.y; + new_allocation.y = 0; + } + + if (new_allocation.x + new_allocation.width > twidth) + new_allocation.width = twidth - new_allocation.x; + if (new_allocation.y + new_allocation.height > theight) + new_allocation.height = theight - new_allocation.y; + + gdk_window_get_position (window, &tx, &ty); + new_allocation.x += tx; + x_offset += tx; + new_allocation.y += ty; + y_offset += ty; + + window = gdk_window_get_parent (window); + } + } + + if ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) && + (data->x < new_allocation.x + new_allocation.width) && + (data->y < new_allocation.y + new_allocation.height)) + { + /* First, check if the drag is in a valid drop site in + * one of our children + */ + if (GTK_IS_CONTAINER (widget)) + { + struct widget_search_data new_data = *data; + + new_data.x -= x_offset; + new_data.y -= y_offset; + new_data.foundp = false; + new_data.first = false; + + gtk_container_forall (GTK_CONTAINER (widget), + find_widget_cb, &new_data); + + data->foundp = new_data.foundp; + if (data->foundp) + data->data = new_data.data; + } + + /* If not, and this widget is registered as a drop site, check to + * emit "drag_motion" to check if we are actually in + * a drop site. + */ + if (!data->foundp) + { + data->foundp = true; + data->data = widget; + } + } +} + +static GtkWidget * +find_widget_at_pos (GtkWidget *w, int x, int y, + int *new_x, int *new_y) +{ + struct widget_search_data data; + + data.x = x; + data.y = y; + data.foundp = false; + data.first = true; + + find_widget (w, &data); + + if (data.foundp) + { + gtk_widget_translate_coordinates (w, data.data, x, + y, new_x, new_y); + return data.data; + } + + *new_x = x; + *new_y = y; + + return NULL; +} + +static Emacs_Cursor +cursor_for_hit (guint result, struct frame *frame) +{ + Emacs_Cursor cursor = FRAME_OUTPUT_DATA (frame)->nontext_cursor; + + if ((result & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE) + || (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION) + || (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT)) + cursor = FRAME_X_OUTPUT (frame)->text_cursor; + + if (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR) + cursor = FRAME_X_OUTPUT (frame)->vertical_drag_cursor; + + if (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK) + cursor = FRAME_X_OUTPUT (frame)->hand_cursor; + + return cursor; +} + +static void +define_cursors (struct xwidget *xw, WebKitHitTestResult *res) +{ + struct xwidget_view *xvw; + + xw->hit_result = webkit_hit_test_result_get_context (res); + + for (Lisp_Object tem = Vxwidget_view_list; CONSP (tem); + tem = XCDR (tem)) + { + if (XWIDGET_VIEW_P (XCAR (tem))) + { + xvw = XXWIDGET_VIEW (XCAR (tem)); + + if (XXWIDGET (xvw->model) == xw) + { + xvw->cursor = cursor_for_hit (xw->hit_result, xvw->frame); + if (xvw->wdesc != None) + XDefineCursor (xvw->dpy, xvw->wdesc, xvw->cursor); + } + } + } +} + +static void +mouse_target_changed (WebKitWebView *webview, + WebKitHitTestResult *hitresult, + guint modifiers, gpointer xw) +{ + define_cursors (xw, hitresult); +} + + +static void +xwidget_button_1 (struct xwidget_view *view, + bool down_p, int x, int y, int button, + int modifier_state, Time time) +{ + GdkEvent *xg_event = gdk_event_new (down_p ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE); + struct xwidget *model = XXWIDGET (view->model); + GtkWidget *target; + + /* X and Y should be relative to the origin of view->wdesc. */ + x += view->clip_left; + y += view->clip_top; + + target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y); + + if (!target) + target = model->widget_osr; + + xg_event->any.window = gtk_widget_get_window (target); + g_object_ref (xg_event->any.window); /* The window will be unrefed + later by gdk_event_free. */ + + xg_event->button.x = x; + xg_event->button.x_root = x; + xg_event->button.y = y; + xg_event->button.y_root = y; + xg_event->button.button = button; + xg_event->button.state = modifier_state; + xg_event->button.time = time; + xg_event->button.device = find_suitable_pointer (view->frame); + + gtk_main_do_event (xg_event); + gdk_event_free (xg_event); +} + +void +xwidget_button (struct xwidget_view *view, + bool down_p, int x, int y, int button, + int modifier_state, Time time) +{ + if (button < 4 || button > 8) + xwidget_button_1 (view, down_p, x, y, button, modifier_state, time); + else + { + GdkEvent *xg_event = gdk_event_new (GDK_SCROLL); + struct xwidget *model = XXWIDGET (view->model); + GtkWidget *target; + + x += view->clip_left; + y += view->clip_top; + + target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y); + + if (!target) + target = model->widget_osr; + + xg_event->any.window = gtk_widget_get_window (target); + g_object_ref (xg_event->any.window); /* The window will be unrefed + later by gdk_event_free. */ + if (button == 4) + xg_event->scroll.direction = GDK_SCROLL_UP; + else if (button == 5) + xg_event->scroll.direction = GDK_SCROLL_DOWN; + else if (button == 6) + xg_event->scroll.direction = GDK_SCROLL_LEFT; + else + xg_event->scroll.direction = GDK_SCROLL_RIGHT; + + xg_event->scroll.device = find_suitable_pointer (view->frame); + + xg_event->scroll.x = x; + xg_event->scroll.x_root = x; + xg_event->scroll.y = y; + xg_event->scroll.y_root = y; + xg_event->scroll.state = modifier_state; + xg_event->scroll.time = time; + + xg_event->scroll.delta_x = 0; + xg_event->scroll.delta_y = 0; + + gtk_main_do_event (xg_event); + gdk_event_free (xg_event); + } +} + +void +xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event) +{ + GdkEvent *xg_event = gdk_event_new (event->type == MotionNotify ? GDK_MOTION_NOTIFY : + (event->type == LeaveNotify ? GDK_LEAVE_NOTIFY : + GDK_ENTER_NOTIFY)); + struct xwidget *model = XXWIDGET (view->model); + int x; + int y; + GtkWidget *target = find_widget_at_pos (model->widgetwindow_osr, + (event->type == MotionNotify + ? event->xmotion.x + view->clip_left + : event->xmotion.y + view->clip_top), + (event->type == MotionNotify + ? event->xmotion.y + view->clip_left + : event->xcrossing.y + view->clip_top), + &x, &y); + + if (!target) + target = model->widgetwindow_osr; + + xg_event->any.window = gtk_widget_get_window (target); + g_object_ref (xg_event->any.window); /* The window will be unrefed + later by gdk_event_free. */ + + if (event->type == MotionNotify) + { + xg_event->motion.x = x; + xg_event->motion.y = y; + xg_event->motion.x_root = event->xmotion.x_root; + xg_event->motion.y_root = event->xmotion.y_root; + xg_event->motion.time = event->xmotion.time; + xg_event->motion.state = event->xmotion.state; + xg_event->motion.device = find_suitable_pointer (view->frame); + } + else + { + xg_event->crossing.detail = min (5, event->xcrossing.detail); + xg_event->crossing.time = event->xcrossing.time; + xg_event->crossing.x = x; + xg_event->crossing.y = y; + xg_event->crossing.x_root = event->xcrossing.x_root; + xg_event->crossing.y_root = event->xcrossing.y_root; + gdk_event_set_device (xg_event, find_suitable_pointer (view->frame)); + } + + gtk_main_do_event (xg_event); + gdk_event_free (xg_event); +} + +static void +synthesize_focus_in_event (GtkWidget *offscreen_window) +{ + GdkWindow *wnd; + GdkEvent *focus_event; + + if (!gtk_widget_get_realized (offscreen_window)) + gtk_widget_realize (offscreen_window); + + wnd = gtk_widget_get_window (offscreen_window); + + focus_event = gdk_event_new (GDK_FOCUS_CHANGE); + focus_event->any.window = wnd; + focus_event->focus_change.in = TRUE; + g_object_ref (wnd); + + gtk_main_do_event (focus_event); + gdk_event_free (focus_event); +} + +struct xwidget_view * +xwidget_view_from_window (Window wdesc) +{ + Lisp_Object key = make_fixnum (wdesc); + Lisp_Object xwv = Fgethash (key, x_window_to_xwv_map, Qnil); + + if (NILP (xwv)) + return NULL; + + return XXWIDGET_VIEW (xwv); +} + static void xwidget_show_view (struct xwidget_view *xv) { xv->hidden = false; - gtk_widget_show (xv->widgetwindow); - gtk_fixed_move (GTK_FIXED (xv->emacswindow), - xv->widgetwindow, - xv->x + xv->clip_left, - xv->y + xv->clip_top); + XMoveWindow (xv->dpy, xv->wdesc, + xv->x + xv->clip_left, + xv->y + xv->clip_top); + XMapWindow (xv->dpy, xv->wdesc); + XFlush (xv->dpy); } /* Hide an xwidget view. */ @@ -238,28 +836,64 @@ xwidget_show_view (struct xwidget_view *xv) xwidget_hide_view (struct xwidget_view *xv) { xv->hidden = true; - gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow, - 10000, 10000); + XUnmapWindow (xv->dpy, xv->wdesc); + XFlush (xv->dpy); +} + +static void +xv_do_draw (struct xwidget_view *xw, struct xwidget *w) +{ + GtkOffscreenWindow *wnd; + cairo_surface_t *surface; + block_input (); + wnd = GTK_OFFSCREEN_WINDOW (w->widgetwindow_osr); + surface = gtk_offscreen_window_get_surface (wnd); + + cairo_save (xw->cr_context); + if (surface) + { + cairo_set_source_surface (xw->cr_context, surface, xw->clip_left, + xw->clip_top); + cairo_set_operator (xw->cr_context, CAIRO_OPERATOR_SOURCE); + cairo_paint (xw->cr_context); + } + cairo_restore (xw->cr_context); + + unblock_input (); } /* When the off-screen webkit master view changes this signal is called. It copies the bitmap from the off-screen instance. */ static gboolean offscreen_damage_event (GtkWidget *widget, GdkEvent *event, - gpointer xv_widget) -{ - /* Queue a redraw of onscreen widget. - There is a guard against receiving an invalid widget, - which should only happen if we failed to remove the - specific signal handler for the damage event. */ - if (GTK_IS_WIDGET (xv_widget)) - gtk_widget_queue_draw (GTK_WIDGET (xv_widget)); - else - message ("Warning, offscreen_damage_event received invalid xv pointer:%p\n", - xv_widget); + gpointer xwidget) +{ + block_input (); + + for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); + tail = XCDR (tail)) + { + if (XWIDGET_VIEW_P (XCAR (tail))) + { + struct xwidget_view *view = XXWIDGET_VIEW (XCAR (tail)); + + if (view->wdesc && XXWIDGET (view->model) == xwidget) + xv_do_draw (view, XXWIDGET (view->model)); + } + } + + unblock_input (); return FALSE; } + +void +xwidget_expose (struct xwidget_view *xv) +{ + struct xwidget *xw = XXWIDGET (xv->model); + + xv_do_draw (xv, xw); +} #endif /* USE_GTK */ void @@ -313,22 +947,108 @@ store_xwidget_js_callback_event (struct xwidget *xw, #ifdef USE_GTK +static void +store_xwidget_display_event (struct xwidget *xw) +{ + struct input_event evt; + Lisp_Object val; + + XSETXWIDGET (val, xw); + EVENT_INIT (evt); + evt.kind = XWIDGET_DISPLAY_EVENT; + evt.frame_or_window = Qnil; + evt.arg = val; + kbd_buffer_store_event (&evt); +} + +static void +webkit_ready_to_show (WebKitWebView *new_view, + gpointer user_data) +{ + Lisp_Object tem; + struct xwidget *xw; + + for (tem = Vxwidget_list; CONSP (tem); tem = XCDR (tem)) + { + if (XWIDGETP (XCAR (tem))) + { + xw = XXWIDGET (XCAR (tem)); + + if (EQ (xw->type, Qwebkit) + && WEBKIT_WEB_VIEW (xw->widget_osr) == new_view) + store_xwidget_display_event (xw); + } + } +} + +static GtkWidget * +webkit_create_cb_1 (WebKitWebView *webview, + struct xwidget_view *xv) +{ + Lisp_Object related; + Lisp_Object xwidget; + GtkWidget *widget; + + XSETXWIDGET (related, xv); + xwidget = Fmake_xwidget (Qwebkit, Qnil, make_fixnum (0), + make_fixnum (0), Qnil, + build_string (" *detached xwidget buffer*"), + related); + + if (NILP (xwidget)) + return NULL; + + widget = XXWIDGET (xwidget)->widget_osr; + + g_signal_connect (G_OBJECT (widget), "ready-to-show", + G_CALLBACK (webkit_ready_to_show), NULL); + + return widget; +} + +static GtkWidget * +webkit_create_cb (WebKitWebView *webview, + WebKitNavigationAction *nav_action, + gpointer user_data) +{ + switch (webkit_navigation_action_get_navigation_type (nav_action)) + { + case WEBKIT_NAVIGATION_TYPE_OTHER: + return webkit_create_cb_1 (webview, user_data); + + case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD: + case WEBKIT_NAVIGATION_TYPE_RELOAD: + case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED: + case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED: + case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED: + default: + return NULL; + } +} + void webkit_view_load_changed_cb (WebKitWebView *webkitwebview, WebKitLoadEvent load_event, gpointer data) { - switch (load_event) { - case WEBKIT_LOAD_FINISHED: + struct xwidget *xw = g_object_get_data (G_OBJECT (webkitwebview), + XG_XWIDGET); + + switch (load_event) { - struct xwidget *xw = g_object_get_data (G_OBJECT (webkitwebview), - XG_XWIDGET); - store_xwidget_event_string (xw, "load-changed", ""); + case WEBKIT_LOAD_FINISHED: + store_xwidget_event_string (xw, "load-changed", "load-finished"); + break; + case WEBKIT_LOAD_STARTED: + store_xwidget_event_string (xw, "load-changed", "load-started"); + break; + case WEBKIT_LOAD_REDIRECTED: + store_xwidget_event_string (xw, "load-changed", "load-redirected"); + break; + case WEBKIT_LOAD_COMMITTED: + store_xwidget_event_string (xw, "load-changed", "load-committed"); break; } - default: - break; - } } /* Recursively convert a JavaScript value to a Lisp value. */ @@ -498,51 +1218,6 @@ webkit_decide_policy_cb (WebKitWebView *webView, return FALSE; } } - - -/* For gtk3 offscreen rendered widgets. */ -static gboolean -xwidget_osr_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data) -{ - struct xwidget *xw = g_object_get_data (G_OBJECT (widget), XG_XWIDGET); - struct xwidget_view *xv = g_object_get_data (G_OBJECT (widget), - XG_XWIDGET_VIEW); - - cairo_rectangle (cr, 0, 0, xv->clip_right, xv->clip_bottom); - cairo_clip (cr); - - gtk_widget_draw (xw->widget_osr, cr); - return FALSE; -} - -static gboolean -xwidget_osr_event_forward (GtkWidget *widget, GdkEvent *event, - gpointer user_data) -{ - /* Copy events that arrive at the outer widget to the offscreen widget. */ - struct xwidget *xw = g_object_get_data (G_OBJECT (widget), XG_XWIDGET); - GdkEvent *eventcopy = gdk_event_copy (event); - eventcopy->any.window = gtk_widget_get_window (xw->widget_osr); - - /* TODO: This might leak events. They should be deallocated later, - perhaps in xwgir_event_cb. */ - gtk_main_do_event (eventcopy); - - /* Don't propagate this event further. */ - return TRUE; -} - -static gboolean -xwidget_osr_event_set_embedder (GtkWidget *widget, GdkEvent *event, - gpointer data) -{ - struct xwidget_view *xv = data; - struct xwidget *xww = XXWIDGET (xv->model); - gdk_offscreen_window_set_embedder (gtk_widget_get_window - (xww->widgetwindow_osr), - gtk_widget_get_window (xv->widget)); - return FALSE; -} #endif /* USE_GTK */ @@ -568,63 +1243,19 @@ xwidget_init_view (struct xwidget *xww, XSETXWIDGET (xv->model, xww); #ifdef USE_GTK - if (EQ (xww->type, Qwebkit)) - { - xv->widget = gtk_drawing_area_new (); - /* Expose event handling. */ - gtk_widget_set_app_paintable (xv->widget, TRUE); - gtk_widget_add_events (xv->widget, GDK_ALL_EVENTS_MASK); - - /* Draw the view on damage-event. */ - g_signal_connect (G_OBJECT (xww->widgetwindow_osr), "damage-event", - G_CALLBACK (offscreen_damage_event), xv->widget); + xv->dpy = FRAME_X_DISPLAY (s->f); - if (EQ (xww->type, Qwebkit)) - { - g_signal_connect (G_OBJECT (xv->widget), "button-press-event", - G_CALLBACK (xwidget_osr_event_forward), NULL); - g_signal_connect (G_OBJECT (xv->widget), "button-release-event", - G_CALLBACK (xwidget_osr_event_forward), NULL); - g_signal_connect (G_OBJECT (xv->widget), "motion-notify-event", - G_CALLBACK (xwidget_osr_event_forward), NULL); - } - else - { - /* xwgir debug, orthogonal to forwarding. */ - g_signal_connect (G_OBJECT (xv->widget), "enter-notify-event", - G_CALLBACK (xwidget_osr_event_set_embedder), xv); - } - g_signal_connect (G_OBJECT (xv->widget), "draw", - G_CALLBACK (xwidget_osr_draw_cb), NULL); - } - - /* Widget realization. - - Make container widget first, and put the actual widget inside the - container later. Drawing should crop container window if necessary - to handle case where xwidget is partially obscured by other Emacs - windows. Other containers than gtk_fixed where explored, but - gtk_fixed had the most predictable behavior so far. */ - - xv->emacswindow = FRAME_GTK_WIDGET (s->f); - xv->widgetwindow = gtk_fixed_new (); - gtk_widget_set_has_window (xv->widgetwindow, TRUE); - gtk_container_add (GTK_CONTAINER (xv->widgetwindow), xv->widget); - - /* Store some xwidget data in the gtk widgets. */ - g_object_set_data (G_OBJECT (xv->widget), XG_FRAME_DATA, s->f); - g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET, xww); - g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET_VIEW, xv); - g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET, xww); - g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET_VIEW, xv); - - gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xww->width, - xww->height); - gtk_widget_set_size_request (xv->widgetwindow, xww->width, xww->height); - gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), xv->widgetwindow, x, y); xv->x = x; xv->y = y; - gtk_widget_show_all (xv->widgetwindow); + + xv->clip_left = 0; + xv->clip_right = xww->width; + xv->clip_top = 0; + xv->clip_bottom = xww->height; + + xv->wdesc = None; + xv->frame = s->f; + xv->cursor = cursor_for_hit (xww->hit_result, s->f); #elif defined NS_IMPL_COCOA nsxwidget_init_view (xv, xww, s, x, y); nsxwidget_resize_view(xv, xww->width, xww->height); @@ -681,6 +1312,8 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) window_box (s->w, TEXT_AREA, &text_area_x, &text_area_y, &text_area_width, &text_area_height); + /* On X11, this keeps generating expose events. */ +#ifndef USE_GTK /* Resize xwidget webkit if its container window size is changed in some ways, for example, a buffer became hidden in small split window, then it can appear front in merged whole window. */ @@ -693,6 +1326,7 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) make_int (text_area_width), make_int (text_area_height)); } +#endif clip_left = max (0, text_area_x - x); clip_right = max (clip_left, @@ -711,15 +1345,51 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) later. */ bool moved = (xv->x + xv->clip_left != x + clip_left || xv->y + xv->clip_top != y + clip_top); + +#ifdef USE_GTK + bool wdesc_was_none = xv->wdesc == None; +#endif xv->x = x; xv->y = y; +#ifdef USE_GTK + block_input (); + if (xv->wdesc == None) + { + Lisp_Object xvw; + XSETXWIDGET_VIEW (xvw, xv); + XSetWindowAttributes a; + a.event_mask = (ExposureMask | ButtonPressMask | ButtonReleaseMask + | PointerMotionMask | EnterWindowMask | LeaveWindowMask); + + xv->wdesc = XCreateWindow (xv->dpy, FRAME_X_WINDOW (s->f), + x + clip_left, y + clip_top, + clip_right - clip_left, + clip_bottom - clip_top, 0, + CopyFromParent, CopyFromParent, + CopyFromParent, CWEventMask, &a); + XDefineCursor (xv->dpy, xv->wdesc, xv->cursor); + xv->cr_surface = cairo_xlib_surface_create (xv->dpy, + xv->wdesc, + FRAME_DISPLAY_INFO (s->f)->visual, + clip_right - clip_left, + clip_bottom - clip_top); + xv->cr_context = cairo_create (xv->cr_surface); + Fputhash (make_fixnum (xv->wdesc), xvw, x_window_to_xwv_map); + + moved = false; + } +#endif + /* Has it moved? */ if (moved) { #ifdef USE_GTK - gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), - xv->widgetwindow, x + clip_left, y + clip_top); + 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 NS_IMPL_COCOA nsxwidget_move_view (xv, x + clip_left, y + clip_top); #endif @@ -735,10 +1405,14 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) || xv->clip_top != clip_top || xv->clip_left != clip_left) { #ifdef USE_GTK - gtk_widget_set_size_request (xv->widgetwindow, clip_right - clip_left, - clip_bottom - clip_top); - gtk_fixed_move (GTK_FIXED (xv->widgetwindow), xv->widget, -clip_left, - -clip_top); + if (!wdesc_was_none && !moved) + { + XResizeWindow (xv->dpy, xv->wdesc, 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 NS_IMPL_COCOA nsxwidget_resize_view (xv, clip_right - clip_left, clip_bottom - clip_top); @@ -758,12 +1432,15 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) if (!xwidget_hidden (xv)) { #ifdef USE_GTK - gtk_widget_queue_draw (xv->widgetwindow); - gtk_widget_queue_draw (xv->widget); + gtk_widget_queue_draw (xww->widget_osr); #elif defined NS_IMPL_COCOA nsxwidget_set_needsdisplay (xv); #endif } + +#ifdef USE_GTK + unblock_input (); +#endif } static bool @@ -975,16 +1652,13 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0, struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail)); if (XXWIDGET (xv->model) == xw) { -#ifdef USE_GTK - gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width, - xw->height); -#elif defined NS_IMPL_COCOA - nsxwidget_resize_view(xv, xw->width, xw->height); -#endif + wset_redisplay (XWINDOW (xv->w)); } } } + redisplay (); + return Qnil; } @@ -1084,13 +1758,15 @@ DEFUN ("delete-xwidget-view", CHECK_XWIDGET_VIEW (xwidget_view); struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view); #ifdef USE_GTK - gtk_widget_destroy (xv->widgetwindow); - /* xv->model still has signals pointing to the view. There can be - several views. Find the matching signals and delete them all. */ - g_signal_handlers_disconnect_matched (XXWIDGET (xv->model)->widgetwindow_osr, - G_SIGNAL_MATCH_DATA, - 0, 0, 0, 0, - xv->widget); + if (xv->wdesc != None) + { + block_input (); + cairo_destroy (xv->cr_context); + cairo_surface_destroy (xv->cr_surface); + XDestroyWindow (xv->dpy, xv->wdesc); + Fremhash (make_fixnum (xv->wdesc), x_window_to_xwv_map); + unblock_input (); + } #elif defined NS_IMPL_COCOA nsxwidget_delete_view (xv); #endif @@ -1145,6 +1821,19 @@ DEFUN ("xwidget-buffer", return XXWIDGET (xwidget)->buffer; } +DEFUN ("set-xwidget-buffer", + Fset_xwidget_buffer, Sset_xwidget_buffer, + 2, 2, 0, + doc: /* Set XWIDGET's buffer to BUFFER. */) + (Lisp_Object xwidget, Lisp_Object buffer) +{ + CHECK_XWIDGET (xwidget); + CHECK_BUFFER (buffer); + + XXWIDGET (xwidget)->buffer = buffer; + return Qnil; +} + DEFUN ("set-xwidget-plist", Fset_xwidget_plist, Sset_xwidget_plist, 2, 2, 0, @@ -1183,6 +1872,166 @@ DEFUN ("xwidget-query-on-exit-flag", return (XXWIDGET (xwidget)->kill_without_query ? Qnil : Qt); } +DEFUN ("xwidget-webkit-search", Fxwidget_webkit_search, Sxwidget_webkit_search, + 2, 5, 0, + doc: /* Begin an incremental search operation in an xwidget. +QUERY should be a string containing the text to search for. XWIDGET +should be a WebKit xwidget where the search will take place. When the +search operation is complete, callers should also call +`xwidget-webkit-finish-search' to complete the search operation. + +CASE-INSENSITIVE, when non-nil, will cause the search to ignore the +case of characters inside QUERY. BACKWARDS, when non-nil, will cause +the search to proceed towards the beginning of the widget's contents. +WRAP-AROUND, when nil, will cause the search to stop upon hitting the +end of the widget's contents. + +It is OK to call this function even when a search is already in +progress. In that case, the previous search query will be replaced +with QUERY. */) + (Lisp_Object query, Lisp_Object xwidget, Lisp_Object case_insensitive, + Lisp_Object backwards, Lisp_Object wrap_around) +{ +#ifdef USE_GTK + WebKitWebView *webview; + WebKitFindController *controller; + WebKitFindOptions opt; + struct xwidget *xw; + gchar *g_query; +#endif + + CHECK_STRING (query); + CHECK_XWIDGET (xwidget); + +#ifdef USE_GTK + xw = XXWIDGET (xwidget); + webview = WEBKIT_WEB_VIEW (xw->widget_osr); + query = ENCODE_UTF_8 (query); + opt = WEBKIT_FIND_OPTIONS_NONE; + g_query = xstrdup (SSDATA (query)); + + if (!NILP (case_insensitive)) + opt |= WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE; + if (!NILP (backwards)) + opt |= WEBKIT_FIND_OPTIONS_BACKWARDS; + if (!NILP (wrap_around)) + opt |= WEBKIT_FIND_OPTIONS_WRAP_AROUND; + + if (xw->find_text) + xfree (xw->find_text); + xw->find_text = g_query; + + block_input (); + controller = webkit_web_view_get_find_controller (webview); + webkit_find_controller_search (controller, g_query, opt, G_MAXUINT); + unblock_input (); +#endif + + return Qnil; +} + +DEFUN ("xwidget-webkit-next-result", Fxwidget_webkit_next_result, + Sxwidget_webkit_next_result, 1, 1, 0, + doc: /* Show the next result matching the current search query. + +XWIDGET should be an xwidget that currently has a search query. +Before calling this function, you should start a search operation +using `xwidget-webkit-search'. */) + (Lisp_Object xwidget) +{ + struct xwidget *xw; +#ifdef USE_GTK + WebKitWebView *webview; + WebKitFindController *controller; +#endif + + CHECK_XWIDGET (xwidget); + xw = XXWIDGET (xwidget); + + if (!xw->find_text) + error ("Widget has no ongoing search operation"); + +#ifdef USE_GTK + block_input (); + webview = WEBKIT_WEB_VIEW (xw->widget_osr); + controller = webkit_web_view_get_find_controller (webview); + webkit_find_controller_search_next (controller); + unblock_input (); +#endif + + return Qnil; +} + +DEFUN ("xwidget-webkit-previous-result", Fxwidget_webkit_previous_result, + Sxwidget_webkit_previous_result, 1, 1, 0, + doc: /* Show the previous result matching the current search query. + +XWIDGET should be an xwidget that currently has a search query. +Before calling this function, you should start a search operation +using `xwidget-webkit-search'. */) + (Lisp_Object xwidget) +{ + struct xwidget *xw; +#ifdef USE_GTK + WebKitWebView *webview; + WebKitFindController *controller; +#endif + + CHECK_XWIDGET (xwidget); + xw = XXWIDGET (xwidget); + + if (!xw->find_text) + error ("Widget has no ongoing search operation"); + +#ifdef USE_GTK + block_input (); + webview = WEBKIT_WEB_VIEW (xw->widget_osr); + controller = webkit_web_view_get_find_controller (webview); + webkit_find_controller_search_previous (controller); + + if (xw->find_text) + { + xfree (xw->find_text); + xw->find_text = NULL; + } + unblock_input (); +#endif + + return Qnil; +} + +DEFUN ("xwidget-webkit-finish-search", Fxwidget_webkit_finish_search, + Sxwidget_webkit_finish_search, 1, 1, 0, + doc: /* Finish XWIDGET's search operation. + +XWIDGET should be an xwidget that currently has a search query. +Before calling this function, you should start a search operation +using `xwidget-webkit-search'. */) + (Lisp_Object xwidget) +{ + struct xwidget *xw; +#ifdef USE_GTK + WebKitWebView *webview; + WebKitFindController *controller; +#endif + + CHECK_XWIDGET (xwidget); + xw = XXWIDGET (xwidget); + + if (!xw->find_text) + error ("Widget has no ongoing search operation"); + +#ifdef USE_GTK + block_input (); + webview = WEBKIT_WEB_VIEW (xw->widget_osr); + controller = webkit_web_view_get_find_controller (webview); + webkit_find_controller_search_finish (controller); + unblock_input (); +#endif + + return Qnil; +} + void syms_of_xwidget (void) { @@ -1215,6 +2064,12 @@ syms_of_xwidget (void) defsubr (&Sxwidget_plist); defsubr (&Sxwidget_buffer); defsubr (&Sset_xwidget_plist); + defsubr (&Sxwidget_perform_lispy_event); + defsubr (&Sxwidget_webkit_search); + defsubr (&Sxwidget_webkit_finish_search); + defsubr (&Sxwidget_webkit_next_result); + defsubr (&Sxwidget_webkit_previous_result); + defsubr (&Sset_xwidget_buffer); DEFSYM (QCxwidget, ":xwidget"); DEFSYM (QCtitle, ":title"); @@ -1236,6 +2091,15 @@ syms_of_xwidget (void) Vxwidget_view_list = Qnil; Fprovide (intern ("xwidget-internal"), Qnil); + + id_to_xwidget_map = CALLN (Fmake_hash_table, QCtest, Qeq); + staticpro (&id_to_xwidget_map); + +#ifdef USE_GTK + x_window_to_xwv_map = CALLN (Fmake_hash_table, QCtest, Qeq); + + staticpro (&x_window_to_xwv_map); +#endif } @@ -1374,7 +2238,7 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix) /* The only call to xwidget_end_redisplay is in dispnew. xwidget_end_redisplay (w->current_matrix); */ struct xwidget_view *xv - = xwidget_view_lookup (glyph->u.xwidget, w); + = xwidget_view_lookup (xwidget_from_id (glyph->u.xwidget), w); #ifdef USE_GTK /* FIXME: Is it safe to assume xwidget_view_lookup always succeeds here? If so, this comment can be removed. @@ -1424,6 +2288,26 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix) } } +#ifdef USE_GTK +void +kill_frame_xwidget_views (struct frame *f) +{ + Lisp_Object rem = Qnil; + + for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); + tail = XCDR (tail)) + { + if (XXWIDGET_VIEW (XCAR (tail))->frame == f) + rem = Fcons (XCAR (tail), rem); + } + + for (; CONSP (rem); rem = XCDR (rem)) + { + Fdelete_xwidget_view (XCAR (rem)); + } +} +#endif + /* Kill all xwidget in BUFFER. */ void kill_buffer_xwidgets (Lisp_Object buffer) @@ -1437,12 +2321,15 @@ kill_buffer_xwidgets (Lisp_Object buffer) { CHECK_XWIDGET (xwidget); struct xwidget *xw = XXWIDGET (xwidget); + Fremhash (make_fixnum (xw->xwidget_id), id_to_xwidget_map); #ifdef USE_GTK if (xw->widget_osr && xw->widgetwindow_osr) { gtk_widget_destroy (xw->widget_osr); gtk_widget_destroy (xw->widgetwindow_osr); } + if (xw->find_text) + xfree (xw->find_text); if (!NILP (xw->script_callbacks)) for (ptrdiff_t idx = 0; idx < ASIZE (xw->script_callbacks); idx++) { diff --git a/src/xwidget.h b/src/xwidget.h index 591f23489d..35b9e8b493 100644 --- a/src/xwidget.h +++ b/src/xwidget.h @@ -32,6 +32,8 @@ #define XWIDGET_H_INCLUDED #if defined (USE_GTK) #include +#include +#include "xterm.h" #elif defined (NS_IMPL_COCOA) && defined (__OBJC__) #import #import "nsxwidget.h" @@ -59,11 +61,14 @@ #define XWIDGET_H_INCLUDED int height; int width; + uint32_t xwidget_id; + gchar *find_text; #if defined (USE_GTK) /* For offscreen widgets, unused if not osr. */ GtkWidget *widget_osr; GtkWidget *widgetwindow_osr; + guint hit_result; #elif defined (NS_IMPL_COCOA) # ifdef __OBJC__ /* For offscreen widgets, unused if not osr. */ @@ -98,9 +103,13 @@ #define XWIDGET_H_INCLUDED bool hidden; #if defined (USE_GTK) - GtkWidget *widget; - GtkWidget *widgetwindow; - GtkWidget *emacswindow; + Display *dpy; + Window wdesc; + Emacs_Cursor cursor; + struct frame *frame; + + cairo_surface_t *cr_surface; + cairo_t *cr_context; #elif defined (NS_IMPL_COCOA) # ifdef __OBJC__ XvWindow *xvWindow; @@ -162,6 +171,18 @@ #define XG_XWIDGET_VIEW "emacs_xwidget_view" void store_xwidget_js_callback_event (struct xwidget *xw, Lisp_Object proc, Lisp_Object argument); + +extern struct xwidget *xwidget_from_id (uint32_t id); + +#ifdef HAVE_X_WINDOWS +struct xwidget_view *xwidget_view_from_window (Window wdesc); +void xwidget_expose (struct xwidget_view *xv); +extern void kill_frame_xwidget_views (struct frame *f); +extern void xwidget_button (struct xwidget_view *, bool, int, + int, int, int, Time); +extern void xwidget_motion_or_crossing (struct xwidget_view *, + const XEvent *); +#endif #else INLINE_HEADER_BEGIN INLINE void syms_of_xwidget (void) {} --=-=-=-- From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Lars Ingebrigtsen Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 07 Nov 2021 01:30:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Po Lu Cc: Eli Zaretskii , 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163624858521083 (code B ref 51473); Sun, 07 Nov 2021 01:30:02 +0000 Received: (at 51473) by debbugs.gnu.org; 7 Nov 2021 01:29:45 +0000 Received: from localhost ([127.0.0.1]:51266 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjX0D-0005Tz-Je for submit@debbugs.gnu.org; Sat, 06 Nov 2021 21:29:45 -0400 Received: from quimby.gnus.org ([95.216.78.240]:57336) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjX0B-0005Tl-TC for 51473@debbugs.gnu.org; Sat, 06 Nov 2021 21:29:44 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnus.org; s=20200322; h=Content-Type:MIME-Version:Message-ID:In-Reply-To:Date: References:Subject:Cc:To:From:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=3Lnau+1aBE65tA/6gOfwbkTE+B8FN3RrqEB2rDF/dJc=; b=PoJsikBfOuaMNU3tQtRm6ZHN2d Rt4QPRBNwYM5RFy69jKnb5Zwy9yhj/joRyPVJrxGk7OlOtvjDy9kesmEMmpaIfrMYfeaJHAYv6P+0 b6rdTUrBzPIqfrEnLjNXylWytrHp0wWDgyIQVObGq3zsc0H5bH/KvX755BqwNAQFbvuE=; Received: from [84.212.220.105] (helo=elva) by quimby.gnus.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mjX02-0003UD-UA; Sun, 07 Nov 2021 02:29:37 +0100 From: Lars Ingebrigtsen References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> <87o86xzhuw.fsf@yahoo.com> <87sfw9cha3.fsf@gnus.org> <878ry0ztjo.fsf@yahoo.com> <87zgqgrd32.fsf@gnus.org> <87zgqgyd9d.fsf@yahoo.com> <87r1bsrc7a.fsf@gnus.org> <87v914ycvi.fsf@yahoo.com> Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAABGdBTUEAALGPC/xhBQAAACBj SFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAElBMVEXR0OD09/uknaqD eIBcUVX///9uGm+PAAAAAWJLR0QF+G/pxwAAAAd0SU1FB+ULBwEcIyWIbyEAAAG9SURBVDjLnVOB kdswDKOUBaSfgKY8QE/UBBX3n+kByfG16bf9f50viQmQAClGUv34yDeAUvBIkZrwFJGL+pJRPquR j5KOYuntkBuoTyAVxfMCiJaDGeXteCmVKuioVo//i9evAWj0L/x/AkX0DwsEpLl3099dAsgjpolY uqk4HDLiimCx2w5YBiriK73cKWZOZD6Vn1dRDJIATPKvlsHKxiOalWqYekIZzVudGWb7BcQWQUmw YMJahwVugbUBIH6gBNoSQ3PQR4bsjKkPzV1lCQkRs5MZw2zmZuIwrQvJHgvoejYj4PRMJ0siTgLe OUJ8stTWjuGG2GSG05fmR+xDYMQC3DVDasen9wsY+GloL587wTtjBPDSkW5KlTYR7xEbCJr26PIA p01HVbELcPQKmLnm54w9B/KYZG1/+XShEpzEdfXC6wM6aBe1UKDhvVGqGxsQJo/ZEQZzzEb3IDgz MOrVZeyqzrod68NK9OPWB1mL81NybBqap4DPmBjL2pLKqSvvfsA0osMn5n0elYsomJY3+l5d4SZy XxufsnFPBmeAWr3hfnDxFX/lbHotEEV3cax6Vqwmmlu3OEfYO54ehuy9s6onAAAAJXRFWHRkYXRl OmNyZWF0ZQAyMDIxLTExLTA3VDAxOjI4OjM1KzAwOjAwHlJJrQAAACV0RVh0ZGF0ZTptb2RpZnkA MjAyMS0xMS0wN1QwMToyODozNSswMDowMG8P8REAAAAASUVORK5CYII= X-Now-Playing: Lisa Gerrard's _Burn_: "Heleali (The Sea Will Rose)" Date: Sun, 07 Nov 2021 02:29:34 +0100 In-Reply-To: <87v914ycvi.fsf@yahoo.com> (Po Lu's message of "Sun, 07 Nov 2021 09:26:41 +0800") Message-ID: <87mtmgrbwh.fsf@gnus.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain X-Spam-Report: Spam detection software, running on the system "quimby.gnus.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see @@CONTACT_ADDRESS@@ for details. Content preview: Po Lu writes: > Thanks, does this work instead? Now it's: Content analysis details: (-2.9 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Po Lu writes: > Thanks, does this work instead? Now it's: In file included from window.c:41: ./xwidget.h:65:3: error: unknown type name 'gchar'; did you mean 'char'? gchar *find_text; ^~~~~ char In file included from xdisp.c:465: ./xwidget.h:65:3: error: unknown type name 'gchar'; did you mean 'char'? gchar *find_text; ^~~~~ char In file included from dispnew.c:43: ./xwidget.h:65:3: error: unknown type name 'gchar'; did you mean 'char'? gchar *find_text; repeated a whole bunch more times, but it's just that error, I think. -- (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 07 Nov 2021 01:35:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Lars Ingebrigtsen Cc: Eli Zaretskii , 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163624889121605 (code B ref 51473); Sun, 07 Nov 2021 01:35:02 +0000 Received: (at 51473) by debbugs.gnu.org; 7 Nov 2021 01:34:51 +0000 Received: from localhost ([127.0.0.1]:51272 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjX55-0005cL-6B for submit@debbugs.gnu.org; Sat, 06 Nov 2021 21:34:51 -0400 Received: from sonic310-25.consmr.mail.ne1.yahoo.com ([66.163.186.206]:43260) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjX4z-0005c4-5m for 51473@debbugs.gnu.org; Sat, 06 Nov 2021 21:34:45 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636248875; bh=JZyBZnVnznZ5oMpQUuvOrTIZdsIuOdMLwpexXOxBHPM=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=nu1pN+ppqGEvRiuXAZipeTo0xkHfWPlybwu92zA3rSj+gQeLNH1NHe5H+Ej18xVdIgkzCv4JJQxQR2aihNYAfw2/Vnhf58I66RI6tANzSlL6w1CeRqX7V5nbHSuhtfLj5sNGVN1M+PutkN3PY2hJD8NK8Nz87gCjKPyp9DUsfGlbibulbJNTWLXxcod6wmmr9GSKYcYuNtbWjmtZtI4E9baVhDgrqXUlKPKXyCe0gBVJVTz/HqwVloUVk11Xx0cziUIoX8shq+CkSZz1cahRzm+9h4sAoATrWZ0U1NiB6pf3/DKbKBwN/RbuYujkGARM0r1ET+DCAVmu6+/4zGuHSg== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636248875; bh=hILqXLZSEoSvJheYd+oeihe0FRUebhDObVM9yw3v68j=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=iNaB/qCjm8Ai656g4owj/1jqIyeYMMS83GlVBuuvSm5VApzHNuyAyavpWwWDA3rF6wDF9RoGaeioNq2q10EROcKoJcVSvjeeuzNzrVr+1PazqJ/HOWX/jG5w63wpGPWF2Tmx4PfBABqIrKO0zX+dwzUaatMycRAZNcjUzjboycpZtVqzgmL66nVetxAh16kVz+TXNq52+Ah9QKYcXdz1PbqOKzOVjT+KcWCE0M1CLFa+2K9ZyfBlmtSF3aV7wDOTzhyR/yu2tX9HziMnAJ3yV11wOmYL7AszkwSttoD+yfU6ZFDr3lZ7JJOwvUgFIA67ZKF/hhU5xjbpSDFCIxvi+A== X-YMail-OSG: IDx2UfMVM1mFIwSvvtQeZl_pEsKmB2nmuIQfXbavBrBi_TcAqtHjUejXwjXYa_I 8VW.jjF1V7p7VMQeSDJrAml14ri_h0IKbbTcj6Xp8xfU7Bus9X4mpAY7IFiI6hZS0h5wfwxC2LLp iEqrRsvj2MxWZjsxMTDso0AJu74ucNbDZD_UnnxmDxWFWOS3NB2BhJcPNr6Vd21tVhvBkHQP4j49 kwPUXy3Ejvn8_.HP2rvknsQJ1qwmcmKIf.wf1Kc0W.H4G9WDF_kql5xbvHwTmUljhLeZ_ced9Qx1 r0KXHeNYIdYwtUSywPfVYInPe3IENkF9Sbz8zfdmrTRabHPdx7nsTRceuRVMJkOTnCOxFWmAFFBy P39xLsdrKFYPMcqf7pMb7LQnNQd_TTKwzmr0CSO5uKPsiJtylkTgzOWF_o4cxAJb5wq4Bdm03sCk k7omBwfaiaWzrsetgBxSHox9Lz6C4hsTBtlt_idbQ9fO.JlQ2HOpwXo_8mI67y_pSiHAvJYtRU2e W2brLPt0YH1SaOXbR9X9jb4vFBUsM7ZsL7dx_MK7k9XC5BwpdO5xdyGv9E7Nd38qAOxDdKkHFI5K OUvyF.AJDotSlcUftuZ6j2_090sI2b1ZnoyCYjtcyYurr2.suaNpTTVkRvVGdZIPVYFcBmiV.Anj hv6z6l2StR3rLVA1QyornmeEGlG_i4ypkbj0GJV6XgyT5YzKsfBALFmN5COhSumSP4j0m6KH.ZpG kVUS5eQ5tFH2EbojB8ESvcAM5nP4n9R_GU5K5VtCyTmFdLDKxdHljODJSeA461i3wGB8P3j9ewNz 7i947n_dd2ExmQ8vmLt30FOCRMdV7hgyus2LAA5GeRvJMbeBN6Fqz2l2_9w4G9BCFZsAw4C3ZpeW QH9Cgn8o9QD_K1x1lpZx1ZVb3rUvnXS2nXNvHbGEMy1jS9I5bQkxsjymNHTYjVFXujdX992ZDJSs cQda0yUmq7c_YuNrE01iYiW12W5rm7xlDSDlvC1h4mQR819n22_JmrYqNOTvjJXOvoHZ4CpR9r7_ Egn3zxUscLGZLY5hSHjhFw_TZROymGlD5Zu.nd.kasp5rcAJEfa_FYKUOgULlE65wR8ZFcNO_aiw GMA8TQimHdnRr_PWuQwnhI.L5ntt.Zu6oe_OH5LqlelsjPxJ11_tLk.WEiTZ3spsiSyUj1ww_msP pFteCSl39FtDROHVM3kX64RuavOAlRzZRGcNFt8VsrDecaDkPAEygbq9XmwPPw3GkCuz0uUojbay auIiy2Hkf.0EvEq1GHPel9Auh5vEKN940h5HvZNDY._T4hQF4Y1nvV17iGNMWfI6FM9sOSHk3elW tQSh4QSXoPAjWeHk4y6G3.MxPLUZVc8_0P8Dd3bsoH3ujWwswBfn1LT4eznqMRwqhddIm3K4BRKd YZZuEfQlgdqC05RiHspQhZx__tWdJ8eYbGCcoYLILzqEX5bJows9SFIgSEXCn_RTw0U_I0nvZG75 6LNJUApA1IpdGi1VYovNofG4KYNZ_x_hAWhy8ASxdJ9JIzV2gZDWa.floVW3.gC1G.QvTcr6Q0V5 s7ke0_AW7zeR19FicklHpICTh9Am4KzwxXgivLgkAtVmEMJKEZLQgp9jd51K66DtlJINf9SU1KA3 KerxKL61pBrNFSjYqpHOzndmZYvezn12dUUpBrM2rLq6HY4lZhIFBpQ.Q25QhxURolt5.w5JcV8P kbNPBRwGEbIPT105EVhJk3MekTO6OYxHZuRmKOYbwfeRvAwdnrX4herTlDPKZY8hOTWskgFrgSbS uQhBGwxXFMYJmRNe6ZGOk5nPWYaowIxW589.cQIxWw6rs0W6mSaEO0SZji.8Cto8IHKupkKUZ73u 3zd70VMj_NuVeMx1Yb2r.yQiRiiHU7EUBseDss4pOBGJyxx1Acyx6_j9vFUZBX9QVCaWWKwRj4T_ A7E7WsVFAgtH6vyC90ho1mxxrpkV1nFIlgSuXWmMWuSI8L9xVS5VIDtu8IHdM7V2MbvSy0aqmuPI CcJa2SrDgWR31BPTci_c7xOvNJO47gaorX7fY03k.pHt_MsA.5XQyZCLdwfgpV2FeNNLuUfpkS1. .HW8PuZVFgrml6ufmDycwCjbJY4G60ei5G8RhOreRBRNW.gKVf_RJA.bvoGSv_BvCB1zvlHfVaxF diCGQ4tJnzHGAgUuFUQ.814F5.TNLQbDrtyoQ7C78tLQYJiTuN9Od0StUnbcbaJCgp_OwzgR_Dtp L0gbLPyO0xYXnenHxNorMk8O6bvh5HzxJQwyIYWUJcZRAkUkK8d1b9JQXBXc- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic310.consmr.mail.ne1.yahoo.com with HTTP; Sun, 7 Nov 2021 01:34:35 +0000 Received: by kubenode501.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 9bffb6967ba22449bc75d0eb425977dd; Sun, 07 Nov 2021 01:34:28 +0000 (UTC) From: Po Lu References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> <87o86xzhuw.fsf@yahoo.com> <87sfw9cha3.fsf@gnus.org> <878ry0ztjo.fsf@yahoo.com> <87zgqgrd32.fsf@gnus.org> <87zgqgyd9d.fsf@yahoo.com> <87r1bsrc7a.fsf@gnus.org> <87v914ycvi.fsf@yahoo.com> <87mtmgrbwh.fsf@gnus.org> Date: Sun, 07 Nov 2021 09:34:23 +0800 In-Reply-To: <87mtmgrbwh.fsf@gnus.org> (Lars Ingebrigtsen's message of "Sun, 07 Nov 2021 02:29:34 +0100") Message-ID: <87pmrcycio.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 95147 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Lars Ingebrigtsen writes: > Now it's: > > In file included from window.c:41: > ./xwidget.h:65:3: error: unknown type name 'gchar'; did you mean 'char'? > gchar *find_text; > ^~~~~ > char > In file included from xdisp.c:465: > ./xwidget.h:65:3: error: unknown type name 'gchar'; did you mean 'char'? > gchar *find_text; > ^~~~~ > char > In file included from dispnew.c:43: > ./xwidget.h:65:3: error: unknown type name 'gchar'; did you mean 'char'? > gchar *find_text; > > repeated a whole bunch more times, but it's just that error, I think. Good catch, thanks! Does this work? --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=test.diff diff --git a/doc/emacs/misc.texi b/doc/emacs/misc.texi index 7f91e1c188..1207ab5e9a 100644 --- a/doc/emacs/misc.texi +++ b/doc/emacs/misc.texi @@ -2953,6 +2953,34 @@ Embedded WebKit Widgets reloading it. Type @w{@kbd{C-h b}} in that buffer to see the key bindings. +@findex xwidget-webkit-edit-mode +@cindex xwidget-webkit-edit-mode + By default, typing a self-inserting character inside an xwidget +webkit buffer will do nothing, or trigger some special action. To +make those characters and other common editing keys insert themselves +when pressed, you can enable @code{xwidget-webkit-edit-mode}, which +redefines them to be passed through to the WebKit xwidget. + +You can also enable @code{xwidget-webkit-edit-mode} by typing @kbd{e} +inside the xwidget webkit buffer. + +@findex xwidget-webkit-isearch-mode +@cindex xwidget-webkit-isearch-mode +@cindex searching in webkit buffers + @code{xwidget-webkit-isearch-mode} is a minor mode that behaves +similarly to incremental search (@pxref{Incremental Search}), but +operates on the contents of a WebKit widget instead of the current +buffer. It is bound to @kbd{C-s} and @kbd{C-r} inside xwidget-webkit +buffers. When it is enabled through @kbd{C-r}, the initial search +will be performed in reverse direction. + +Typing any self-inserting character will cause the character to be +inserted into the current search query. Typing @kbd{C-s} will cause +the WebKit widget to display the next search result, while typing +@kbd{C-r} will cause it to display the last. + +To leave incremental search, you can type @kbd{C-g}. + @node Browse-URL @subsection Following URLs @cindex World Wide Web diff --git a/doc/lispref/commands.texi b/doc/lispref/commands.texi index b38a83b4fe..832b570b6a 100644 --- a/doc/lispref/commands.texi +++ b/doc/lispref/commands.texi @@ -1176,6 +1176,7 @@ Input Events * Repeat Events:: Double and triple click (or drag, or down). * Motion Events:: Just moving the mouse, not pushing a button. * Focus Events:: Moving the mouse between frames. +* Xwidget Events:: Events generated by xwidgets. * Misc Events:: Other events the system can generate. * Event Examples:: Examples of the lists for mouse events. * Classifying Events:: Finding the modifier keys in an event symbol. @@ -1871,6 +1872,76 @@ Focus Events so that the focus event comes either before or after the multi-event key sequence, and not within it. +@node Xwidget Events +@subsection Xwidget events + +Xwidgets (@pxref{Xwidgets}) can send events to update Lisp programs on +their status. These events are dubbed @code{xwidget-events}, and +contain various data describing the nature of the change. + +@table @code +@cindex @code{xwidget-event} event +@item (xwidget-event @var{kind} @var{xwidget} @var{arg}) +This event is sent whenever some kind of update occurs in +@var{xwidget}. There are several types of updates, which are +identified by @var{kind}. + +@cindex @code{load-changed} xwidget events +An xwidget event with @var{kind} set to @code{load-changed} indicates +that the @var{xwidget} has reached a particular point of the +page-loading process. When these events are sent, @var{arg} will +contain a string that futher describes the status of the widget. + +@cindex @samp{"load-finished"} in xwidgets +When @var{arg} is @samp{"load-finished"}, it means the xwidget has +finished processing whatever page-loading operation that it was +previously performing. + +@cindex @samp{"load-started"} in xwidgets +Otherwise, if it is @samp{"load-started"}, then the widget has begun a +page-loading operation. + +@cindex @samp{"load-redirected"} in xwidgets +If @var{arg} is @samp{"load-redirected"}, it means the widget has +encountered and followed a redirect during the page-loading operation. + +@cindex @samp{"load-committed"} in xwidgets +If @var{arg} is @samp{"load-committed"}, then the widget has committed +to a given URL during the page-loading operation. This means that the +URL is the final URL that will be rendered by @var{xwidget} during the +current page-loading operation. + +@cindex @code{download-callback} xwidget events +An event with @var{kind} set to @code{download-callback} indicates +that a download of some kind has been completed. + +In these events, there can be arguments after @var{arg}, which itself +indicates the URL that the download file was retrieved from: the first +argument after @var{arg} indicates the MIME type of the download, as a +string, while the second such argument contains the full file path to +the downloaded file. + +@cindex @code{download-started} xwidget events +An event with @var{kind} set to @code{download-started} indicates that +a download has been started. In these events, @var{arg} contains the +URL of the file that is currently being downloaded. + +@cindex @code{javascript-callback} xwidget events +An event with @var{kind} set to @code{javascript-callback} contains +JavaScript callback data. These events are used internally by +@code{xwidget-webkit-execute-script}. + +@cindex @code{xwidget-display-event} event +@item (xwidget-display-event @var{xwidget}) +This event is sent whenever an xwidget requests that another xwidget +be displayed. @var{xwidget} is the xwidget that should be displayed. + +@var{xwidget}'s buffer will be set to a temporary buffer. When +displaying the widget, care should be taken to replace the buffer with +the buffer in which the xwidget will be displayed, using +@code{set-xwidget-buffer} (@pxref{Xwidgets}). +@end table + @node Misc Events @subsection Miscellaneous System Events diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 22528a1b0f..60bca15eb2 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -6784,7 +6784,10 @@ Xwidgets in a @code{display} text or overlay property (@pxref{Display Property}). -@defun make-xwidget type title width height arguments &optional buffer + Embedded widgets can send events notifying Lisp code about changes +occurring within them. (@pxref{Xwidget Events}). + +@defun make-xwidget type title width height arguments &optional buffer related This creates and returns an xwidget object. If @var{buffer} is omitted or @code{nil}, it defaults to the current buffer. If @var{buffer} names a buffer that doesn't exist, it will be @@ -6797,7 +6800,10 @@ Xwidgets @end table The @var{width} and @var{height} arguments specify the widget size in -pixels, and @var{title}, a string, specifies its title. +pixels, and @var{title}, a string, specifies its title. @var{related} +is used internally by the WebKit widget, and specifies another WebKit +widget that the newly created widget should share settings and +subprocesses with. @end defun @defun xwidgetp object @@ -6818,6 +6824,10 @@ Xwidgets This function returns the buffer of @var{xwidget}. @end defun +@defun set-xwidget-buffer xwidget buffer +This function sets the buffer of @var{xwidget} to @var{buffer}. +@end defun + @defun get-buffer-xwidgets buffer This function returns a list of xwidget objects associated with the @var{buffer}, which can be specified as a buffer object or a name of @@ -6878,6 +6888,61 @@ Xwidgets query-on-exit flag, either @code{t} or @code{nil}. @end defun +@defun xwidget-perform-lispy-event xwidget event frame +Send an input event @var{event} to @var{xwidget}. The precise action +performed is platform-specific. See @ref{Input Events}. + +You can optionally pass the frame the event was generated from via +@var{frame}. On X11, modifier keys in key events will not be +considered if @var{frame} is @code{nil}, and the selected frame is not +an X-Windows frame. + +On GTK, only keyboard and function key events are implemented. Mouse, +motion, and click events are dispatched to the xwidget without going +through Lisp code, and as such shouldn't require this function to be +sent. +@end defun + +@defun xwidget-webkit-search query xwidget &optional case-insensitive backwards wrap-around +Start an incremental search on the WebKit widget @var{xwidget} with +the string @var{query} as a query. @var{case-insensitive} denotes +whether or not the search is case-insensitive, @var{backwards} +determines if the search is performed backwards towards the start of +the document, and @var{wrap-around} determines whether or not the +search terminates at the end of the document. + +If the function is called while a search query is already present, +then the query specified here will replace the existing query. + +To stop a search query, use @code{xwidget-webkit-finish-search}. +@end defun + +@defun xwidget-webkit-next-result xwidget +Display the next search result in @var{xwidget}. This function will +error unless a search query has already been started in @var{xwidget} +through @code{xwidget-webkit-search}. + +If @code{wrap-around} was non-nil when @code{xwidget-webkit-search} +was called, then the search will restart from the beginning of the +document if the end is reached. +@end defun + +@defun xwidget-webkit-previous-result xwidget +Display the previous search result in @var{xwidget}. This function +will error unless a search query has already been started in +@var{xwidget} through @code{xwidget-webkit-search}. + +If @code{wrap-around} was non-nil when @code{xwidget-webkit-search} +was called, then the search will restart from the end of the +document if the beginning is reached. +@end defun + +@defun xwidget-webkit-finish-search xwidget +Finish a search operation started with @code{xwidget-webkit-search} in +@var{xwidget}. If there is no query currently ongoing, then this +function will error. +@end defun + @node Buttons @section Buttons @cindex buttons in buffers diff --git a/etc/NEWS b/etc/NEWS index a50229916f..b14f9a2549 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -495,6 +495,31 @@ the buffer will take you to that directory. This is a convenience function to extract the field data from 'exif-parse-file' and 'exif-parse-buffer'. +** Xwidgets + ++++ +*** New minor mode `xwidget-webkit-edit-mode'. +When this mode is enabled, self-inserting characters and other common +web browser shotcut keys are redefined to send themselves to the +WebKit widget. + ++++ +*** New minor mode `xwidget-webkit-isearch-mode'. +This mode acts similarly to incremental search, and allows to search +the contents of a WebKit widget. In xwidget-webkit mode, it is bound +to `C-s' and `C-r'. + +--- +*** On X11, the WebKit inspector is now available inside xwidgets. +To access the inspector, right click on the widget and select "Inspect +Element". + +--- +*** "Open in New Window" in a WebKit widget's context menu now works. +The newly created buffer will be displayed via display-buffer, which +can be customized through the usual mechanism of display-buffer-alist +and friends. + * New Modes and Packages in Emacs 29.1 @@ -719,6 +744,39 @@ an exact match, then the lowercased '[menu-bar foo\ bar]' and finally '[menu-bar foo-bar]'. This further improves backwards-compatibility when converting menus to use 'easy-menu-define'. ++++ +** The function `make-xwidget' now accepts an optional RELATED argument. +This argument is used as another widget for the newly created WebKit +widget to share settings and subprocesses with. It must be another +WebKit widget. + ++++ +** New function `xwidget-perform-lispy-event'. +This function allows you to send events to xwidgets. Usually, some +equivalent of the event will be sent, but there is no guarantee of +what the widget will actually receive. + +On GTK+, only key and function key events are implemented. + ++++ +** New functions for performing searches on WebKit xwidgets. +Some new functions, such as `xwidget-webkit-search', have been added +for performing searches on WebKit xwidgets. + ++++ +** `load-changed' xwidget events are now more detailed. +In particular, they can now have different arguments based on the +state of the WebKit widget. `load-finished' is sent when a load has +completed, `load-started' when a load first starts, `load-redirected' +after a redirect, and `load-committed' when the WebKit widget first +commits to the load. + ++++ +** New event type `xwidget-display-event'. +These events are sent whenever an xwidget requests that Emacs display +another. The only argument to this event is the xwidget that should +be displayed. + * Changes in Emacs 29.1 on Non-Free Operating Systems diff --git a/etc/images/README b/etc/images/README index 9bbe796cc9..561cfff765 100644 --- a/etc/images/README +++ b/etc/images/README @@ -68,6 +68,7 @@ Emacs images and their source in the GNOME icons stock/ directory: bookmark_add.xpm actions/bookmark_add cancel.xpm slightly modified generic/stock_stop connect.xpm net/stock_connect + connect-to-url.xpm net/stock_connect-to-url contact.xpm net/stock_contact data-save.xpm data/stock_data-save delete.xpm generic/stock_delete diff --git a/etc/images/connect-to-url.pbm b/etc/images/connect-to-url.pbm new file mode 100644 index 0000000000..f142349f4a Binary files /dev/null and b/etc/images/connect-to-url.pbm differ diff --git a/etc/images/connect-to-url.xpm b/etc/images/connect-to-url.xpm new file mode 100644 index 0000000000..38fefeaf61 --- /dev/null +++ b/etc/images/connect-to-url.xpm @@ -0,0 +1,281 @@ +/* XPM */ +static char *connect_to_url[] = { +/* columns rows colors chars-per-pixel */ +"24 24 251 2 ", +" c black", +". c #010101", +"X c #000103", +"o c #010204", +"O c #010305", +"+ c #020407", +"@ c #020609", +"# c #03070C", +"$ c #04080D", +"% c #0F0F0D", +"& c #030A10", +"* c #050B10", +"= c #060C11", +"- c #070D13", +"; c #070D14", +": c #060C15", +"> c #070E14", +", c #0B1824", +"< c #0A1B2B", +"1 c #0A1C2E", +"2 c #141A20", +"3 c #161E25", +"4 c #181E23", +"5 c #0D2032", +"6 c #142534", +"7 c #1F2830", +"8 c #1D2933", +"9 c #102438", +"0 c #272622", +"q c #21292F", +"w c #272F36", +"e c #282F33", +"r c #222F3A", +"t c #2E3337", +"y c #2D373E", +"u c #32383C", +"i c #33383C", +"p c #343A3E", +"a c #43423C", +"s c #112941", +"d c #102A44", +"f c #132D47", +"g c #192F46", +"h c #17314B", +"j c #15314F", +"k c #163351", +"l c #163554", +"z c #173554", +"x c #1F3A53", +"c c #1D3955", +"v c #1A3958", +"b c #1C3B5B", +"n c #1F3C58", +"m c #1D3C5C", +"M c #1E3E5D", +"N c #1F3F5F", +"B c #303B44", +"V c #313C44", +"C c #313D47", +"Z c #213C56", +"A c #233E57", +"S c #1F405F", +"D c #374148", +"F c #2D4050", +"G c #25405B", +"H c #25425E", +"J c #214262", +"K c #244565", +"L c #264665", +"P c #254666", +"I c #2A4967", +"U c #284969", +"Y c #2A4C6C", +"T c #2C4F6F", +"R c #33526E", +"E c #385269", +"W c #2D5070", +"Q c #2E5172", +"! c #335473", +"~ c #3F5B75", +"^ c #3D5F7D", +"/ c #41494F", +"( c #646056", +") c #6C685E", +"_ c #505F6C", +"` c #48657C", +"' c #556A7A", +"] c #5B6C78", +"[ c #5F6F7B", +"{ c #5D6F7D", +"} c #706C62", +"| c #726D63", +" . c #78756B", +".. c #7D786E", +"X. c #60727F", +"o. c #807D74", +"O. c #8A857B", +"+. c #8B877E", +"@. c #4E6A83", +"#. c #4A6A86", +"$. c #4A7090", +"%. c #587790", +"&. c #5F7E95", +"*. c #587B98", +"=. c #6F7980", +"-. c #697F8F", +";. c #66839B", +":. c #6A879F", +">. c #708391", +",. c #728A9A", +"<. c #748898", +"1. c #758A99", +"2. c #7B8F9F", +"3. c #708DA4", +"4. c #7990A1", +"5. c #7292AB", +"6. c #7691A8", +"7. c #7693AB", +"8. c #7B98AE", +"9. c #7E98AD", +"0. c #7E9DB3", +"q. c #7F9EB4", +"w. c #8C8981", +"e. c #989389", +"r. c #A6A29B", +"t. c #8093A1", +"y. c #8598A3", +"u. c #8498A7", +"i. c #809AAD", +"p. c #8F9FAA", +"a. c #899FAE", +"s. c #819FB5", +"d. c #86A2B8", +"f. c #87A5BB", +"g. c #88A3B8", +"h. c #89A5BA", +"j. c #8FABBF", +"k. c #97A7B1", +"l. c #90AABE", +"z. c #91ABBF", +"x. c #98ACB9", +"c. c #AAA7A0", +"v. c #B1ADA4", +"b. c #B3B1AA", +"n. c #B7B3AA", +"m. c #A3B1BC", +"M. c #A5B1BC", +"N. c #A9B6BF", +"B. c #BEBBB5", +"V. c #C4C2BD", +"C. c #94AEC1", +"Z. c #96AEC1", +"A. c #94AFC2", +"S. c #95AFC2", +"D. c #96B0C3", +"F. c #98B0C3", +"G. c #9FB5C3", +"H. c #99B3C6", +"J. c #98B3C7", +"K. c #9AB3C6", +"L. c #9BB4C7", +"P. c #9FB8CA", +"I. c #9FB8CB", +"U. c #A2B8C9", +"Y. c #A3B9C9", +"T. c #A0B9CB", +"R. c #A3BACB", +"E. c #A0B9CC", +"W. c #A2BACC", +"Q. c #A4BDCE", +"!. c #A6BECF", +"~. c #B8BEC2", +"^. c #B8C3CA", +"/. c #BCC5CB", +"(. c #BDC8CE", +"). c #A8C0D1", +"_. c #AAC0D0", +"`. c #ABC1D1", +"'. c #ACC2D3", +"]. c #AAC5D7", +"[. c #B4C8D6", +"{. c #BDCBD5", +"}. c #B4C9D8", +"|. c #B6CAD8", +" X c #B8CBD9", +".X c #BBCDDB", +"XX c #B7D0E0", +"oX c #BDD3E2", +"OX c #BCD5E5", +"+X c #CECAC3", +"@X c #C5D2C8", +"#X c #C0D2DE", +"$X c #C4D3DF", +"%X c #CCD7DE", +"&X c #D2D8DC", +"*X c #E1DFDB", +"=X c #E2E1DD", +"-X c #C2D3E0", +";X c #C2D4E1", +":X c #C5D5E1", +">X c #C6D6E1", +",X c #C4D6E2", +". e.o. sXwX}.R.R.`.H.1.- JXJX", +"JX4 a.9.C.h.] a n.V.BXo. p.!.T.l.4.- JXJX", +"JX2 F.d.5.7. =XAXc.BXo. @X@XZX !.C.F.@.> JXJX", +" o.=XAXc.BXo. t.U.z.3.Y $ JXJX", +"BXBXBXBXVXBXBXAXVXO.CXo. P.C.!.I.J.C.;.L * JXJX", +"o.o.o.o.o. . .B.b...*X . $.*.T.J.A.h.Y c @ JXJX", +" .w.r.| +X . 1.C.3.L h JXJX", +"JXJX6 Q ^ 1.% w.r.| +X . @X@XHX h.:.M , JXJX", +"JXJXO x T #.] 0 +.} v.) -.s.H 9 O JXJXJX", +"JXJXJX+ n ! i.X.% % e.( Q Y %.0.&.f O JXJXJX", +"JXJXJXJX& A s.8.E A % % A K J R ` g @ JXJXJXJX", +"JXJXJXJXJX@ C ~ m M J N M b v l < O JXJXJXJXJX", +"JXJXJXJXJXJX : 5 d k z k d 1 & JXJXJXJXJXJX", +"JXJXJXJXJXJXJXJX JXJXJXJXJXJXJXJX", +"JXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJX", +"JXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJXJX" +}; diff --git a/lisp/xwidget.el b/lisp/xwidget.el index 8c593abea8..4046140895 100644 --- a/lisp/xwidget.el +++ b/lisp/xwidget.el @@ -35,8 +35,9 @@ (require 'bookmark) (declare-function make-xwidget "xwidget.c" - (type title width height arguments &optional buffer)) + (type title width height arguments &optional buffer related)) (declare-function xwidget-buffer "xwidget.c" (xwidget)) +(declare-function set-xwidget-buffer "xwidget.c" (xwidget buffer)) (declare-function xwidget-size-request "xwidget.c" (xwidget)) (declare-function xwidget-resize "xwidget.c" (xwidget new-width new-height)) (declare-function xwidget-webkit-execute-script "xwidget.c" @@ -58,14 +59,14 @@ xwidget "Displaying native widgets in Emacs buffers." :group 'widgets) -(defun xwidget-insert (pos type title width height &optional args) +(defun xwidget-insert (pos type title width height &optional args related) "Insert an xwidget at position POS. -Supply the xwidget's TYPE, TITLE, WIDTH, and HEIGHT. +Supply the xwidget's TYPE, TITLE, WIDTH, HEIGHT, and RELATED. See `make-xwidget' for the possible TYPE values. The usage of optional argument ARGS depends on the xwidget. This returns the result of `make-xwidget'." (goto-char pos) - (let ((id (make-xwidget type title width height args))) + (let ((id (make-xwidget type title width height args nil related))) (put-text-property (point) (+ 1 (point)) 'display (list 'xwidget ':xwidget id)) id)) @@ -88,6 +89,9 @@ xwidget-at (require 'seq) (require 'url-handlers) +(defvar-local xwidget-webkit--title "" + "The title of the WebKit widget, used for the header line.") + ;;;###autoload (defun xwidget-webkit-browse-url (url &optional new-session) "Ask xwidget-webkit to browse URL. @@ -124,6 +128,14 @@ xwidget-webkit-clone-and-split-right (with-selected-window (split-window-right) (xwidget-webkit-new-session url)))) +(declare-function xwidget-perform-lispy-event "xwidget.c") + +(defun xwidget-webkit-pass-command-event () + "Pass `last-command-event' to the current buffer's WebKit widget." + (interactive) + (xwidget-perform-lispy-event (xwidget-webkit-current-session) + last-command-event)) + ;;todo. ;; - check that the webkit support is compiled in (defvar xwidget-webkit-mode-map @@ -138,6 +150,9 @@ xwidget-webkit-mode-map (define-key map "w" 'xwidget-webkit-current-url) (define-key map "+" 'xwidget-webkit-zoom-in) (define-key map "-" 'xwidget-webkit-zoom-out) + (define-key map "e" 'xwidget-webkit-edit-mode) + (define-key map "\C-r" 'xwidget-webkit-isearch-mode) + (define-key map "\C-s" 'xwidget-webkit-isearch-mode) ;;similar to image mode bindings (define-key map (kbd "SPC") 'xwidget-webkit-scroll-up) @@ -164,6 +179,63 @@ xwidget-webkit-mode-map map) "Keymap for `xwidget-webkit-mode'.") +(easy-menu-define nil xwidget-webkit-mode-map "Xwidget WebKit menu." + (list "Xwidget WebKit" + ["Browse URL" xwidget-webkit-browse-url + :active t + :help "Prompt for a URL, then instruct WebKit to browse it"] + ["Back" xwidget-webkit-back t] + ["Forward" xwidget-webkit-forward t] + ["Reload" xwidget-webkit-reload t] + ["Insert String" xwidget-webkit-insert-string + :active t + :help "Insert a string into the currently active field"] + ["Zoom In" xwidget-webkit-zoom-in t] + ["Zoom Out" xwidget-webkit-zoom-out t] + ["Edit Mode" xwidget-webkit-edit-mode + :active t + :style toggle + :selected xwidget-webkit-edit-mode + :help "Send self inserting characters to the WebKit widget"] + ["Save Selection" xwidget-webkit-copy-selection-as-kill + :active t + :help "Save the browser's selection in the kill ring"] + ["Incremental Search" xwidget-webkit-isearch-mode + :active (not xwidget-webkit-isearch-mode) + :help "Perform incremental search inside the WebKit widget"])) + +(defvar xwidget-webkit-tool-bar-map + (let ((map (make-sparse-keymap))) + (prog1 map + (tool-bar-local-item-from-menu 'xwidget-webkit-back + "left-arrow" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-forward + "right-arrow" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-reload + "refresh" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-zoom-in + "zoom-in" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-zoom-out + "zoom-out" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-browse-url + "connect-to-url" + map + xwidget-webkit-mode-map) + (tool-bar-local-item-from-menu 'xwidget-webkit-isearch-mode + "search" + map + xwidget-webkit-mode-map)))) + (defun xwidget-webkit-zoom-in () "Increase webkit view zoom factor." (interactive nil xwidget-webkit-mode) @@ -276,6 +348,8 @@ xwidget-webkit-callback (with-current-buffer (xwidget-buffer xwidget) (cond ((eq xwidget-event-type 'load-changed) (let ((title (xwidget-webkit-title xwidget))) + (setq xwidget-webkit--title title) + (force-mode-line-update) (xwidget-log "webkit finished loading: %s" title) ;; Do not adjust webkit size to window here, the selected window ;; can be the mini-buffer window unwantedly. @@ -309,8 +383,10 @@ bookmark-make-record-function (define-derived-mode xwidget-webkit-mode special-mode "xwidget-webkit" "Xwidget webkit view mode." (setq buffer-read-only t) + (setq-local tool-bar-map xwidget-webkit-tool-bar-map) (setq-local bookmark-make-record-function #'xwidget-webkit-bookmark-make-record) + (setq-local header-line-format 'xwidget-webkit--title) ;; Keep track of [vh]scroll when switching buffers (image-mode-setup-winprops)) @@ -609,6 +685,7 @@ xwidget-webkit-new-session (let* ((bufname (generate-new-buffer-name "*xwidget-webkit*")) (callback (or callback #'xwidget-webkit-callback)) + (current-session (xwidget-webkit-current-session)) xw) (setq xwidget-webkit-last-session-buffer (switch-to-buffer (get-buffer-create bufname))) @@ -621,11 +698,35 @@ xwidget-webkit-new-session (setq xw (xwidget-insert start 'webkit bufname (xwidget-window-inside-pixel-width (selected-window)) - (xwidget-window-inside-pixel-height (selected-window))))) + (xwidget-window-inside-pixel-height (selected-window)) + nil current-session))) (xwidget-put xw 'callback callback) (xwidget-webkit-mode) (xwidget-webkit-goto-uri (xwidget-webkit-last-session) url))) +(defun xwidget-webkit-import-widget (xwidget) + "Create a new webkit session buffer from XWIDGET, an existing xwidget. +Return the buffer." + (let* ((bufname (generate-new-buffer-name "*xwidget-webkit*")) + (callback #'xwidget-webkit-callback) + (buffer (get-buffer-create bufname))) + (with-current-buffer buffer + (save-excursion + (erase-buffer) + (insert ".") + (put-text-property (point-min) (point-max) + 'display (list 'xwidget :xwidget xwidget))) + (xwidget-put xwidget 'callback callback) + (set-xwidget-buffer xwidget buffer) + (xwidget-webkit-mode)) + buffer)) + +(defun xwidget-webkit-display-event (event) + "Import the xwidget inside EVENT and display it." + (interactive "e") + (display-buffer (xwidget-webkit-import-widget (nth 1 event)))) + +(global-set-key [xwidget-display-event] 'xwidget-webkit-display-event) (defun xwidget-webkit-goto-url (url) "Goto URL with xwidget webkit." @@ -684,6 +785,165 @@ xwidget-put (set-xwidget-plist xwidget (plist-put (xwidget-plist xwidget) propname value))) +(defvar xwidget-webkit-edit-mode-map (make-keymap)) + +(define-key xwidget-webkit-edit-mode-map [backspace] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [tab] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [left] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [right] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [up] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [down] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [return] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-left] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-right] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-up] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-down] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [C-return] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-left] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-right] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-up] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-down] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [S-return] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-left] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-right] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-up] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-down] 'xwidget-webkit-pass-command-event) +(define-key xwidget-webkit-edit-mode-map [M-return] 'xwidget-webkit-pass-command-event) + +(define-minor-mode xwidget-webkit-edit-mode + "Minor mode for editing the content of WebKit buffers. + +This defines most self-inserting characters and some common +keyboard shortcuts to `xwidget-webkit-pass-command-event', which +will pass the key events corresponding to these characters to the +WebKit widget." + :keymap xwidget-webkit-edit-mode-map) + +(substitute-key-definition 'self-insert-command + 'xwidget-webkit-pass-command-event + xwidget-webkit-edit-mode-map + global-map) + +(declare-function xwidget-webkit-search "xwidget.c") +(declare-function xwidget-webkit-next-result "xwidget.c") +(declare-function xwidget-webkit-previous-result "xwidget.c") +(declare-function xwidget-webkit-finish-search "xwidget.c") + +(defvar-local xwidget-webkit-isearch--string "" + "The current search query.") +(defvar-local xwidget-webkit-isearch--is-reverse nil + "Whether or not the current isearch should be reverse.") + +(defun xwidget-webkit-isearch--update (&optional only-message) + "Update the current buffer's WebKit widget's search query. +If ONLY-MESSAGE is non-nil, the query will not be sent to the +WebKit widget. The query will be set to the contents of +`xwidget-webkit-isearch--string'." + (unless only-message + (xwidget-webkit-search xwidget-webkit-isearch--string + (xwidget-webkit-current-session) + t xwidget-webkit-isearch--is-reverse t)) + (message (concat (propertize "Search contents: " 'face 'minibuffer-prompt) + xwidget-webkit-isearch--string))) + +(defun xwidget-webkit-isearch-erasing-char (count) + "Erase the last COUNT characters of the current query." + (interactive (list (prefix-numeric-value current-prefix-arg))) + (when (> (length xwidget-webkit-isearch--string) 0) + (setq xwidget-webkit-isearch--string + (substring xwidget-webkit-isearch--string 0 + (- (length xwidget-webkit-isearch--string) count)))) + (xwidget-webkit-isearch--update)) + +(defun xwidget-webkit-isearch-printing-char (char &optional count) + "Add ordinary character CHAR to the search string and search. +With argument, add COUNT copies of CHAR." + (interactive (list last-command-event + (prefix-numeric-value current-prefix-arg))) + (setq xwidget-webkit-isearch--string (concat xwidget-webkit-isearch--string + (make-string (or count 1) char))) + (xwidget-webkit-isearch--update)) + +(defun xwidget-webkit-isearch-forward (count) + "Move to the next search result COUNT times." + (interactive (list (prefix-numeric-value current-prefix-arg))) + (let ((was-reverse xwidget-webkit-isearch--is-reverse)) + (setq xwidget-webkit-isearch--is-reverse nil) + (when was-reverse + (xwidget-webkit-isearch--update))) + (let ((i 0)) + (while (< i count) + (xwidget-webkit-next-result (xwidget-webkit-current-session)) + (cl-incf i))) + (xwidget-webkit-isearch--update t)) + +(defun xwidget-webkit-isearch-backward (count) + "Move to the previous search result COUNT times." + (interactive (list (prefix-numeric-value current-prefix-arg))) + (let ((was-reverse xwidget-webkit-isearch--is-reverse)) + (setq xwidget-webkit-isearch--is-reverse t) + (unless was-reverse + (xwidget-webkit-isearch--update))) + (let ((i 0)) + (while (< i count) + (xwidget-webkit-next-result (xwidget-webkit-current-session)) + (cl-incf i))) + (xwidget-webkit-isearch--update t)) + +(defun xwidget-webkit-isearch-exit () + "Exit incremental search of a WebKit buffer." + (interactive) + (xwidget-webkit-isearch-mode 0)) + +(defvar xwidget-webkit-isearch-mode-map (make-keymap) + "The keymap used inside xwidget-webkit-isearch-mode.") + +(set-char-table-range (nth 1 xwidget-webkit-isearch-mode-map) + (cons 0 (max-char)) + 'xwidget-webkit-isearch-exit) + +(substitute-key-definition 'self-insert-command + 'xwidget-webkit-isearch-printing-char + xwidget-webkit-isearch-mode-map + global-map) + +(define-key xwidget-webkit-isearch-mode-map (kbd "DEL") + 'xwidget-webkit-isearch-erasing-char) +(define-key xwidget-webkit-isearch-mode-map [return] 'xwidget-webkit-isearch-exit) +(define-key xwidget-webkit-isearch-mode-map "\r" 'xwidget-webkit-isearch-exit) +(define-key xwidget-webkit-isearch-mode-map "\C-g" 'xwidget-webkit-isearch-exit) +(define-key xwidget-webkit-isearch-mode-map "\C-r" 'xwidget-webkit-isearch-backward) +(define-key xwidget-webkit-isearch-mode-map "\C-s" 'xwidget-webkit-isearch-forward) +(define-key xwidget-webkit-isearch-mode-map "\t" 'xwidget-webkit-isearch-printing-char) + +(let ((meta-map (make-keymap))) + (set-char-table-range (nth 1 meta-map) + (cons 0 (max-char)) + 'xwidget-webkit-isearch-exit) + (define-key xwidget-webkit-isearch-mode-map (char-to-string meta-prefix-char) meta-map)) + +(define-minor-mode xwidget-webkit-isearch-mode + "Minor mode for performing incremental search inside WebKit buffers. + +An attempt was made for this to resemble regular incremental +search, but it suffers from several limitations, such as not +supporting recursive edits. + +If this mode is enabled with `C-r', then the search will default +to being performed in reverse direction. + +To navigate around the search results, type +\\[xwidget-webkit-isearch-forward] to move forward, and +\\[xwidget-webkit-isearch-backward] to move backward. + +Press \\[xwidget-webkit-isearch-exit] to exit incremental search." + :keymap xwidget-webkit-isearch-mode-map + (if xwidget-webkit-isearch-mode + (progn + (setq xwidget-webkit-isearch--string "") + (setq xwidget-webkit-isearch--is-reverse (eq last-command-event ?\C-r)) + (xwidget-webkit-isearch--update)) + (xwidget-webkit-finish-search (xwidget-webkit-current-session)))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/src/dispextern.h b/src/dispextern.h index 5b28fe7666..f17f095e0d 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -536,8 +536,8 @@ #define FACE_ID_BITS 20 int img_id; #ifdef HAVE_XWIDGETS - /* Xwidget reference (type == XWIDGET_GLYPH). */ - struct xwidget *xwidget; + /* Xwidget ID. */ + uint32_t xwidget; #endif /* Sub-structure for type == STRETCH_GLYPH. */ diff --git a/src/dispnew.c b/src/dispnew.c index 4a73244c89..632eec2f03 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -4449,16 +4449,6 @@ scrolling_window (struct window *w, int tab_line_p) break; } -#ifdef HAVE_XWIDGETS - /* Currently this seems needed to detect xwidget movement reliably. - This is most probably because an xwidget glyph is represented in - struct glyph's 'union u' by a pointer to a struct, which takes 8 - bytes in 64-bit builds, and thus the comparison of u.val values - done by GLYPH_EQUAL_P doesn't work reliably, since it assumes the - size of the union is 4 bytes. FIXME. */ - return 0; -#endif - /* Can't scroll the display of w32 GUI frames when position of point is indicated by the system caret, because scrolling the display will then "copy" the pixels used by the caret. */ diff --git a/src/keyboard.c b/src/keyboard.c index aa6a4b9e97..c4a5671b10 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -3993,6 +3993,7 @@ kbd_buffer_get_event (KBOARD **kbp, #endif #ifdef HAVE_XWIDGETS case XWIDGET_EVENT: + case XWIDGET_DISPLAY_EVENT: #endif case SAVE_SESSION_EVENT: case NO_EVENT: @@ -4897,7 +4898,7 @@ #define FUNCTION_KEY_OFFSET 0xff00 /* You'll notice that this table is arranged to be conveniently indexed by X Windows keysym values. */ -static const char *const lispy_function_keys[] = +const char *const lispy_function_keys[] = { /* X Keysym value */ @@ -6139,6 +6140,11 @@ make_lispy_event (struct input_event *event) { return Fcons (Qxwidget_event, event->arg); } + + case XWIDGET_DISPLAY_EVENT: + { + return list2 (Qxwidget_display_event, event->arg); + } #endif #ifdef USE_FILE_NOTIFY @@ -11732,6 +11738,7 @@ syms_of_keyboard (void) #ifdef HAVE_XWIDGETS DEFSYM (Qxwidget_event, "xwidget-event"); + DEFSYM (Qxwidget_display_event, "xwidget-display-event"); #endif #ifdef USE_FILE_NOTIFY diff --git a/src/keyboard.h b/src/keyboard.h index 8bdffaa2bf..21c51ec386 100644 --- a/src/keyboard.h +++ b/src/keyboard.h @@ -491,7 +491,7 @@ kbd_buffer_store_event_hold (struct input_event *event, extern struct timespec timer_check (void); extern void mark_kboards (void); -#ifdef HAVE_NTGUI +#if defined HAVE_NTGUI || defined HAVE_X_WINDOWS extern const char *const lispy_function_keys[]; #endif diff --git a/src/print.c b/src/print.c index c13294c8e6..adadb289de 100644 --- a/src/print.c +++ b/src/print.c @@ -1521,8 +1521,26 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag, printchar ('>', printcharfun); break; - case PVEC_XWIDGET: case PVEC_XWIDGET_VIEW: - print_c_string ("#", + XXWIDGET (obj)->xwidget_id, + XXWIDGET (obj)->widget_osr); +#else + int len = sprintf (buf, "#", + XXWIDGET (obj)->xwidget_id, + XXWIDGET (obj)->xwWidget); +#endif + strout (buf, len, len, printcharfun); + break; + } +#else + emacs_abort (); +#endif + case PVEC_XWIDGET_VIEW: + print_c_string ("#', printcharfun); break; diff --git a/src/termhooks.h b/src/termhooks.h index 1d3cdc8fe8..e7539bbce2 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -255,6 +255,8 @@ #define EMACS_TERMHOOKS_H #ifdef HAVE_XWIDGETS /* events generated by xwidgets*/ , XWIDGET_EVENT + /* Event generated when WebKit asks us to display another widget. */ + , XWIDGET_DISPLAY_EVENT #endif #ifdef USE_FILE_NOTIFY diff --git a/src/xdisp.c b/src/xdisp.c index 86c4e704d5..d7ad548917 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -28429,7 +28429,7 @@ fill_xwidget_glyph_string (struct glyph_string *s) } s->width = s->first_glyph->pixel_width; s->ybase += s->first_glyph->voffset; - s->xwidget = s->first_glyph->u.xwidget; + s->xwidget = xwidget_from_id (s->first_glyph->u.xwidget); } #endif /* Fill glyph string S from a sequence of stretch glyphs. @@ -29832,7 +29832,7 @@ produce_xwidget_glyph (struct it *it) glyph->padding_p = 0; glyph->glyph_not_available_p = 0; glyph->face_id = it->face_id; - glyph->u.xwidget = it->xwidget; + glyph->u.xwidget = it->xwidget->xwidget_id; glyph->font_type = FONT_TYPE_UNKNOWN; if (it->bidi_p) { diff --git a/src/xterm.c b/src/xterm.c index aa1a1a5eed..9b434bffcc 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -4390,6 +4390,86 @@ x_scroll_run (struct window *w, struct run *run) /* Cursor off. Will be switched on again in gui_update_window_end. */ gui_clear_cursor (w); +#ifdef HAVE_XWIDGETS + /* "Copy" xwidget windows in the area that will be scrolled. */ + Display *dpy = FRAME_X_DISPLAY (f); + Window window = FRAME_X_WINDOW (f); + + Window root, parent, *children; + unsigned int nchildren; + + if (XQueryTree (dpy, window, &root, &parent, &children, &nchildren)) + { + /* Now find xwidget views situated between from_y and to_y, and + attached to w. */ + for (unsigned int i = 0; i < nchildren; ++i) + { + Window child = children[i]; + struct xwidget_view *view = xwidget_view_from_window (child); + + if (view) + { + 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; + XUnmapWindow (dpy, child); + 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, TEXT_AREA, &text_area_x, &text_area_y, + &text_area_width, &text_area_height); + + clip_top = max (0, text_area_y - y); + clip_bottom = max (clip_top, + min (XXWIDGET (view->model)->height, + text_area_y + text_area_height - y)); + + view->y = y; + 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_top - view->clip_bottom) <= 0) + { + view->hidden = true; + XUnmapWindow (dpy, child); + } + else + XMoveResizeWindow (dpy, child, view->x + view->clip_left, + view->y + view->clip_top, + view->clip_right - view->clip_left, + view->clip_top - view->clip_bottom); + XFlush (dpy); + } + } + } + XFree (children); + } +#endif + #ifdef USE_CAIRO if (FRAME_CR_CONTEXT (f)) { @@ -4563,8 +4643,9 @@ x_focus_changed (int type, int state, struct x_display_info *dpyinfo, struct fra } } -/* Return the Emacs frame-object corresponding to an X window. - It could be the frame's main window or an icon window. */ +/* Return the Emacs frame-object corresponding to an X window. It + could be the frame's main window, an icon window, or an xwidget + window. */ static struct frame * x_window_to_frame (struct x_display_info *dpyinfo, int wdesc) @@ -4575,6 +4656,13 @@ x_window_to_frame (struct x_display_info *dpyinfo, int wdesc) if (wdesc == None) return NULL; +#ifdef HAVE_XWIDGETS + struct xwidget_view *xvw = xwidget_view_from_window (wdesc); + + if (xvw && xvw->frame) + return xvw->frame; +#endif + FOR_EACH_FRAME (tail, frame) { f = XFRAME (frame); @@ -4997,7 +5085,7 @@ x_x_to_emacs_modifiers (struct x_display_info *dpyinfo, int state) | ((state & dpyinfo->hyper_mod_mask) ? mod_hyper : 0)); } -static int +int x_emacs_to_x_modifiers (struct x_display_info *dpyinfo, intmax_t state) { EMACS_INT mod_ctrl = ctrl_modifier; @@ -8211,6 +8299,18 @@ handle_one_xevent (struct x_display_info *dpyinfo, case Expose: f = x_window_to_frame (dpyinfo, event->xexpose.window); +#ifdef HAVE_XWIDGETS + { + struct xwidget_view *xv = + xwidget_view_from_window (event->xexpose.window); + + if (xv) + { + xwidget_expose (xv); + goto OTHER; + } + } +#endif if (f) { if (!FRAME_VISIBLE_P (f)) @@ -8791,6 +8891,31 @@ handle_one_xevent (struct x_display_info *dpyinfo, x_display_set_last_user_time (dpyinfo, event->xcrossing.time); x_detect_focus_change (dpyinfo, any, event, &inev.ie); +#ifdef HAVE_XWIDGETS + { + struct xwidget_view *xvw = xwidget_view_from_window (event->xcrossing.window); + Mouse_HLInfo *hlinfo; + + if (xvw) + { + xwidget_motion_or_crossing (xvw, event); + hlinfo = MOUSE_HL_INFO (xvw->frame); + + if (xvw->frame == hlinfo->mouse_face_mouse_frame) + { + clear_mouse_face (hlinfo); + hlinfo->mouse_face_mouse_frame = 0; + } + + if (any_help_event_p) + { + do_help = -1; + } + goto OTHER; + } + } +#endif + f = any; if (f && x_mouse_click_focus_ignore_position) @@ -8834,6 +8959,17 @@ handle_one_xevent (struct x_display_info *dpyinfo, goto OTHER; case LeaveNotify: +#ifdef HAVE_XWIDGETS + { + struct xwidget_view *xvw = xwidget_view_from_window (event->xcrossing.window); + + if (xvw) + { + xwidget_motion_or_crossing (xvw, event); + goto OTHER; + } + } +#endif x_display_set_last_user_time (dpyinfo, event->xcrossing.time); x_detect_focus_change (dpyinfo, any, event, &inev.ie); @@ -8883,6 +9019,12 @@ handle_one_xevent (struct x_display_info *dpyinfo, #ifdef USE_GTK if (f && xg_event_is_for_scrollbar (f, event)) f = 0; +#endif +#ifdef HAVE_XWIDGETS + struct xwidget_view *xvw = xwidget_view_from_window (event->xmotion.window); + + if (xvw) + xwidget_motion_or_crossing (xvw, event); #endif if (f) { @@ -9138,6 +9280,24 @@ handle_one_xevent (struct x_display_info *dpyinfo, case ButtonRelease: case ButtonPress: { +#ifdef HAVE_XWIDGETS + struct xwidget_view *xvw = xwidget_view_from_window (event->xmotion.window); + + if (xvw) + { + xwidget_button (xvw, event->type == ButtonPress, + event->xbutton.x, event->xbutton.y, + event->xbutton.button, event->xbutton.state, + event->xbutton.time); + + if (!EQ (selected_window, xvw->w)) + { + inev.ie.kind = SELECT_WINDOW_EVENT; + inev.ie.frame_or_window = xvw->w; + } + goto OTHER; + } +#endif /* If we decide we want to generate an event to be seen by the rest of Emacs, we put it here. */ Lisp_Object tab_bar_arg = Qnil; @@ -12108,6 +12268,10 @@ x_free_frame_resources (struct frame *f) xfree (f->shell_position); #else /* !USE_X_TOOLKIT */ +#ifdef HAVE_XWIDGETS + kill_frame_xwidget_views (f); +#endif + #ifdef USE_GTK xg_free_frame_widgets (f); #endif /* USE_GTK */ diff --git a/src/xterm.h b/src/xterm.h index de6ea50385..9d9534dd62 100644 --- a/src/xterm.h +++ b/src/xterm.h @@ -1108,6 +1108,7 @@ #define SELECTION_EVENT_TIME(eventp) \ extern int x_dispatch_event (XEvent *, Display *); #endif extern int x_x_to_emacs_modifiers (struct x_display_info *, int); +extern int x_emacs_to_x_modifiers (struct x_display_info *, intmax_t); #ifdef USE_CAIRO extern void x_cr_destroy_frame_context (struct frame *); extern void x_cr_update_surface_desired_size (struct frame *, int, int); diff --git a/src/xwidget.c b/src/xwidget.c index e4b42e6e0c..78a3860490 100644 --- a/src/xwidget.c +++ b/src/xwidget.c @@ -19,6 +19,7 @@ Copyright (C) 2011-2021 Free Software Foundation, Inc. #include +#include "buffer.h" #include "xwidget.h" #include "lisp.h" @@ -35,10 +36,22 @@ Copyright (C) 2011-2021 Free Software Foundation, Inc. #ifdef USE_GTK #include #include +#include +#include #elif defined NS_IMPL_COCOA #include "nsxwidget.h" #endif +static Lisp_Object id_to_xwidget_map; +static uint32_t xwidget_counter = 0; + +#ifdef USE_GTK +static Lisp_Object x_window_to_xwv_map; +static gboolean offscreen_damage_event (GtkWidget *, GdkEvent *, gpointer); +static void synthesize_focus_in_event (GtkWidget *); +static GdkDevice *find_suitable_keyboard (struct frame *); +#endif + static struct xwidget * allocate_xwidget (void) { @@ -64,18 +77,32 @@ #define XSETXWIDGET_VIEW(a, b) XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW) GAsyncResult *, gpointer); static gboolean webkit_download_cb (WebKitWebContext *, WebKitDownload *, gpointer); - +static GtkWidget *webkit_create_cb (WebKitWebView *, WebKitNavigationAction *, gpointer); static gboolean webkit_decide_policy_cb (WebKitWebView *, WebKitPolicyDecision *, WebKitPolicyDecisionType, gpointer); +static GtkWidget *find_widget_at_pos (GtkWidget *, int, int, int *, int *); + +struct widget_search_data +{ + int x; + int y; + bool foundp; + bool first; + GtkWidget *data; +}; + +static void find_widget (GtkWidget *t, struct widget_search_data *); +static void mouse_target_changed (WebKitWebView *, WebKitHitTestResult *, guint, + gpointer); #endif DEFUN ("make-xwidget", Fmake_xwidget, Smake_xwidget, - 5, 6, 0, + 5, 7, 0, doc: /* Make an xwidget of TYPE. If BUFFER is nil, use the current buffer. If BUFFER is a string and no such buffer exists, create it. @@ -83,10 +110,13 @@ DEFUN ("make-xwidget", - webkit -Returns the newly constructed xwidget, or nil if construction fails. */) +RELATED is nil, or an xwidget. When constructing a WebKit widget, it +will share the same settings and internal subprocess as RELATED. +Returns the newly constructed xwidget, or nil if construction +fails. */) (Lisp_Object type, Lisp_Object title, Lisp_Object width, Lisp_Object height, - Lisp_Object arguments, Lisp_Object buffer) + Lisp_Object arguments, Lisp_Object buffer, Lisp_Object related) { #ifdef USE_GTK if (!xg_gtk_initialized) @@ -108,13 +138,19 @@ DEFUN ("make-xwidget", XSETXWIDGET (val, xw); Vxwidget_list = Fcons (val, Vxwidget_list); xw->plist = Qnil; + xw->xwidget_id = ++xwidget_counter; + xw->find_text = NULL; + + Fputhash (make_fixnum (xw->xwidget_id), val, id_to_xwidget_map); #ifdef USE_GTK xw->widgetwindow_osr = NULL; xw->widget_osr = NULL; + xw->hit_result = 0; if (EQ (xw->type, Qwebkit)) { block_input (); + WebKitSettings *settings; WebKitWebContext *webkit_context = webkit_web_context_get_default (); # if WEBKIT_CHECK_VERSION (2, 26, 0) @@ -128,18 +164,34 @@ DEFUN ("make-xwidget", if (EQ (xw->type, Qwebkit)) { - xw->widget_osr = webkit_web_view_new (); - - /* webkitgtk uses GSubprocess which sets sigaction causing - Emacs to not catch SIGCHLD with its usual handle setup in - catch_child_signal(). This resets the SIGCHLD - sigaction. */ - struct sigaction old_action; - sigaction (SIGCHLD, NULL, &old_action); - webkit_web_view_load_uri(WEBKIT_WEB_VIEW (xw->widget_osr), - "about:blank"); - sigaction (SIGCHLD, &old_action, NULL); - } + WebKitWebView *related_view; + + if (NILP (related) + || !XWIDGETP (related) + || !EQ (XXWIDGET (related)->type, Qwebkit)) + { + xw->widget_osr = webkit_web_view_new (); + + /* webkitgtk uses GSubprocess which sets sigaction causing + Emacs to not catch SIGCHLD with its usual handle setup in + catch_child_signal(). This resets the SIGCHLD + sigaction. */ + struct sigaction old_action; + sigaction (SIGCHLD, NULL, &old_action); + webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr), + "about:blank"); + sigaction (SIGCHLD, &old_action, NULL); + } + else + { + related_view = WEBKIT_WEB_VIEW (XXWIDGET (related)->widget_osr); + xw->widget_osr = webkit_web_view_new_with_related_view (related_view); + } + + /* Enable the developer extras */ + settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (xw->widget_osr)); + g_object_set (G_OBJECT (settings), "enable-developer-extras", TRUE, NULL); + } gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height); @@ -157,6 +209,7 @@ DEFUN ("make-xwidget", gtk_widget_show (xw->widget_osr); gtk_widget_show (xw->widgetwindow_osr); + synthesize_focus_in_event (xw->widgetwindow_osr); /* Store some xwidget data in the gtk widgets for convenient retrieval in the event handlers. */ @@ -179,8 +232,20 @@ DEFUN ("make-xwidget", G_CALLBACK (webkit_decide_policy_cb), xw); + + g_signal_connect (G_OBJECT (xw->widget_osr), + "mouse-target-changed", + G_CALLBACK (mouse_target_changed), + xw); + g_signal_connect (G_OBJECT (xw->widget_osr), + "create", + G_CALLBACK (webkit_create_cb), + xw); } + g_signal_connect (G_OBJECT (xw->widgetwindow_osr), "damage-event", + G_CALLBACK (offscreen_damage_event), xw); + unblock_input (); } #elif defined NS_IMPL_COCOA @@ -190,6 +255,158 @@ DEFUN ("make-xwidget", return val; } +#ifdef USE_GTK +static void +set_widget_if_text_view (GtkWidget *widget, void *data) +{ + GtkWidget **pointer = data; + + if (GTK_IS_TEXT_VIEW (widget)) + { + *pointer = widget; + } +} +#endif + +DEFUN ("xwidget-perform-lispy-event", + Fxwidget_perform_lispy_event, Sxwidget_perform_lispy_event, + 2, 3, 0, doc: /* Send a lispy event to XWIDGET. +EVENT should be the event that will be sent. FRAME should be the +frame which generated the event, or nil. On X11, modifier keys will +not be processed if FRAME is nil and the selected frame is not an +X-Windows frame. */) + (Lisp_Object xwidget, Lisp_Object event, Lisp_Object frame) +{ + struct xwidget *xw; + struct frame *f = NULL; + int character = -1, keycode = -1; + int modifiers = 0; + +#ifdef USE_GTK + GdkEvent *xg_event; + GtkContainerClass *klass; + GtkWidget *widget; + GtkWidget *temp = NULL; +#endif + + CHECK_XWIDGET (xwidget); + xw = XXWIDGET (xwidget); + + if (!NILP (frame)) + f = decode_window_system_frame (frame); + else if (FRAME_X_P (SELECTED_FRAME ())) + f = SELECTED_FRAME (); + +#ifdef USE_GTK + widget = gtk_window_get_focus (GTK_WINDOW (xw->widgetwindow_osr)); + + if (!widget) + widget = xw->widget_osr; + + if (RANGED_FIXNUMP (0, event, INT_MAX)) + { + character = XFIXNUM (event); + + if (character < 32) + modifiers |= ctrl_modifier; + + modifiers |= character & meta_modifier; + modifiers |= character & hyper_modifier; + modifiers |= character & super_modifier; + modifiers |= character & shift_modifier; + modifiers |= character & ctrl_modifier; + + character = character & ~(1 << 21); + + if (character < 32) + character += '_'; + + if (f) + modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f), modifiers); + else + modifiers = 0; + } + else if (SYMBOLP (event)) + { + Lisp_Object decoded = parse_modifiers (event); + Lisp_Object decoded_name = SYMBOL_NAME (XCAR (decoded)); + + int off = 0; + bool found = false; + + while (off < 256) + { + if (lispy_function_keys[off] + && !strcmp (lispy_function_keys[off], + SSDATA (decoded_name))) + { + found = true; + break; + } + ++off; + } + + if (f) + modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f), + XFIXNUM (XCAR (XCDR (decoded)))); + else + modifiers = 0; + + if (found) + keycode = off + 0xff00; + } + + if (character == -1 && keycode == -1) + return Qnil; + + block_input (); + xg_event = gdk_event_new (GDK_KEY_PRESS); + xg_event->any.window = gtk_widget_get_window (xw->widget_osr); + g_object_ref (xg_event->any.window); + + if (character > -1) + keycode = gdk_unicode_to_keyval (character); + + xg_event->key.keyval = keycode; + xg_event->key.state = modifiers; + + if (keycode > -1) + { + /* WebKitGTK internals abuse follows. */ + if (WEBKIT_IS_WEB_VIEW (widget)) + { + /* WebKitGTK relies on an internal GtkTextView object to + "translate" keys such as backspace. We must find that + widget and activate its binding to this key if any. */ + klass = GTK_CONTAINER_CLASS (G_OBJECT_GET_CLASS (widget)); + + klass->forall (GTK_CONTAINER (xw->widget_osr), TRUE, + set_widget_if_text_view, &temp); + + if (GTK_IS_WIDGET (temp)) + { + if (!gtk_widget_get_realized (temp)) + gtk_widget_realize (temp); + + gtk_bindings_activate (G_OBJECT (temp), keycode, modifiers); + } + } + } + + if (f) + gdk_event_set_device (xg_event, + find_suitable_keyboard (SELECTED_FRAME ())); + + gtk_main_do_event (xg_event); + xg_event->type = GDK_KEY_RELEASE; + gtk_main_do_event (xg_event); + gdk_event_free (xg_event); + unblock_input (); +#endif + + return Qnil; +} + DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets, Sget_buffer_xwidgets, 1, 1, 0, doc: /* Return a list of xwidgets associated with BUFFER. @@ -221,16 +438,397 @@ xwidget_hidden (struct xwidget_view *xv) return xv->hidden; } +struct xwidget * +xwidget_from_id (uint32_t id) +{ + Lisp_Object key = make_fixnum (id); + Lisp_Object xwidget = Fgethash (key, id_to_xwidget_map, Qnil); + + if (NILP (xwidget)) + emacs_abort (); + + return XXWIDGET (xwidget); +} + #ifdef USE_GTK + +static GdkDevice * +find_suitable_pointer (struct frame *f) +{ + GdkSeat *seat = gdk_display_get_default_seat + (gtk_widget_get_display (FRAME_GTK_WIDGET (f))); + + if (!seat) + return NULL; + + return gdk_seat_get_pointer (seat); +} + +static GdkDevice * +find_suitable_keyboard (struct frame *f) +{ + GdkSeat *seat = gdk_display_get_default_seat + (gtk_widget_get_display (FRAME_GTK_WIDGET (f))); + + if (!seat) + return NULL; + + return gdk_seat_get_keyboard (seat); +} + +static void +find_widget_cb (GtkWidget *widget, void *user) +{ + find_widget (widget, user); +} + +static void +find_widget (GtkWidget *widget, + struct widget_search_data *data) +{ + GtkAllocation new_allocation; + GdkWindow *window; + int x_offset = 0; + int y_offset = 0; + + gtk_widget_get_allocation (widget, &new_allocation); + + if (gtk_widget_get_has_window (widget)) + { + new_allocation.x = 0; + new_allocation.y = 0; + } + + if (gtk_widget_get_parent (widget) && !data->first) + { + window = gtk_widget_get_window (widget); + while (window != gtk_widget_get_window (gtk_widget_get_parent (widget))) + { + gint tx, ty, twidth, theight; + + if (!window) + return; + + twidth = gdk_window_get_width (window); + theight = gdk_window_get_height (window); + + if (new_allocation.x < 0) + { + new_allocation.width += new_allocation.x; + new_allocation.x = 0; + } + + if (new_allocation.y < 0) + { + new_allocation.height += new_allocation.y; + new_allocation.y = 0; + } + + if (new_allocation.x + new_allocation.width > twidth) + new_allocation.width = twidth - new_allocation.x; + if (new_allocation.y + new_allocation.height > theight) + new_allocation.height = theight - new_allocation.y; + + gdk_window_get_position (window, &tx, &ty); + new_allocation.x += tx; + x_offset += tx; + new_allocation.y += ty; + y_offset += ty; + + window = gdk_window_get_parent (window); + } + } + + if ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) && + (data->x < new_allocation.x + new_allocation.width) && + (data->y < new_allocation.y + new_allocation.height)) + { + /* First, check if the drag is in a valid drop site in + * one of our children + */ + if (GTK_IS_CONTAINER (widget)) + { + struct widget_search_data new_data = *data; + + new_data.x -= x_offset; + new_data.y -= y_offset; + new_data.foundp = false; + new_data.first = false; + + gtk_container_forall (GTK_CONTAINER (widget), + find_widget_cb, &new_data); + + data->foundp = new_data.foundp; + if (data->foundp) + data->data = new_data.data; + } + + /* If not, and this widget is registered as a drop site, check to + * emit "drag_motion" to check if we are actually in + * a drop site. + */ + if (!data->foundp) + { + data->foundp = true; + data->data = widget; + } + } +} + +static GtkWidget * +find_widget_at_pos (GtkWidget *w, int x, int y, + int *new_x, int *new_y) +{ + struct widget_search_data data; + + data.x = x; + data.y = y; + data.foundp = false; + data.first = true; + + find_widget (w, &data); + + if (data.foundp) + { + gtk_widget_translate_coordinates (w, data.data, x, + y, new_x, new_y); + return data.data; + } + + *new_x = x; + *new_y = y; + + return NULL; +} + +static Emacs_Cursor +cursor_for_hit (guint result, struct frame *frame) +{ + Emacs_Cursor cursor = FRAME_OUTPUT_DATA (frame)->nontext_cursor; + + if ((result & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE) + || (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION) + || (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT)) + cursor = FRAME_X_OUTPUT (frame)->text_cursor; + + if (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR) + cursor = FRAME_X_OUTPUT (frame)->vertical_drag_cursor; + + if (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK) + cursor = FRAME_X_OUTPUT (frame)->hand_cursor; + + return cursor; +} + +static void +define_cursors (struct xwidget *xw, WebKitHitTestResult *res) +{ + struct xwidget_view *xvw; + + xw->hit_result = webkit_hit_test_result_get_context (res); + + for (Lisp_Object tem = Vxwidget_view_list; CONSP (tem); + tem = XCDR (tem)) + { + if (XWIDGET_VIEW_P (XCAR (tem))) + { + xvw = XXWIDGET_VIEW (XCAR (tem)); + + if (XXWIDGET (xvw->model) == xw) + { + xvw->cursor = cursor_for_hit (xw->hit_result, xvw->frame); + if (xvw->wdesc != None) + XDefineCursor (xvw->dpy, xvw->wdesc, xvw->cursor); + } + } + } +} + +static void +mouse_target_changed (WebKitWebView *webview, + WebKitHitTestResult *hitresult, + guint modifiers, gpointer xw) +{ + define_cursors (xw, hitresult); +} + + +static void +xwidget_button_1 (struct xwidget_view *view, + bool down_p, int x, int y, int button, + int modifier_state, Time time) +{ + GdkEvent *xg_event = gdk_event_new (down_p ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE); + struct xwidget *model = XXWIDGET (view->model); + GtkWidget *target; + + /* X and Y should be relative to the origin of view->wdesc. */ + x += view->clip_left; + y += view->clip_top; + + target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y); + + if (!target) + target = model->widget_osr; + + xg_event->any.window = gtk_widget_get_window (target); + g_object_ref (xg_event->any.window); /* The window will be unrefed + later by gdk_event_free. */ + + xg_event->button.x = x; + xg_event->button.x_root = x; + xg_event->button.y = y; + xg_event->button.y_root = y; + xg_event->button.button = button; + xg_event->button.state = modifier_state; + xg_event->button.time = time; + xg_event->button.device = find_suitable_pointer (view->frame); + + gtk_main_do_event (xg_event); + gdk_event_free (xg_event); +} + +void +xwidget_button (struct xwidget_view *view, + bool down_p, int x, int y, int button, + int modifier_state, Time time) +{ + if (button < 4 || button > 8) + xwidget_button_1 (view, down_p, x, y, button, modifier_state, time); + else + { + GdkEvent *xg_event = gdk_event_new (GDK_SCROLL); + struct xwidget *model = XXWIDGET (view->model); + GtkWidget *target; + + x += view->clip_left; + y += view->clip_top; + + target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y); + + if (!target) + target = model->widget_osr; + + xg_event->any.window = gtk_widget_get_window (target); + g_object_ref (xg_event->any.window); /* The window will be unrefed + later by gdk_event_free. */ + if (button == 4) + xg_event->scroll.direction = GDK_SCROLL_UP; + else if (button == 5) + xg_event->scroll.direction = GDK_SCROLL_DOWN; + else if (button == 6) + xg_event->scroll.direction = GDK_SCROLL_LEFT; + else + xg_event->scroll.direction = GDK_SCROLL_RIGHT; + + xg_event->scroll.device = find_suitable_pointer (view->frame); + + xg_event->scroll.x = x; + xg_event->scroll.x_root = x; + xg_event->scroll.y = y; + xg_event->scroll.y_root = y; + xg_event->scroll.state = modifier_state; + xg_event->scroll.time = time; + + xg_event->scroll.delta_x = 0; + xg_event->scroll.delta_y = 0; + + gtk_main_do_event (xg_event); + gdk_event_free (xg_event); + } +} + +void +xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event) +{ + GdkEvent *xg_event = gdk_event_new (event->type == MotionNotify ? GDK_MOTION_NOTIFY : + (event->type == LeaveNotify ? GDK_LEAVE_NOTIFY : + GDK_ENTER_NOTIFY)); + struct xwidget *model = XXWIDGET (view->model); + int x; + int y; + GtkWidget *target = find_widget_at_pos (model->widgetwindow_osr, + (event->type == MotionNotify + ? event->xmotion.x + view->clip_left + : event->xmotion.y + view->clip_top), + (event->type == MotionNotify + ? event->xmotion.y + view->clip_left + : event->xcrossing.y + view->clip_top), + &x, &y); + + if (!target) + target = model->widgetwindow_osr; + + xg_event->any.window = gtk_widget_get_window (target); + g_object_ref (xg_event->any.window); /* The window will be unrefed + later by gdk_event_free. */ + + if (event->type == MotionNotify) + { + xg_event->motion.x = x; + xg_event->motion.y = y; + xg_event->motion.x_root = event->xmotion.x_root; + xg_event->motion.y_root = event->xmotion.y_root; + xg_event->motion.time = event->xmotion.time; + xg_event->motion.state = event->xmotion.state; + xg_event->motion.device = find_suitable_pointer (view->frame); + } + else + { + xg_event->crossing.detail = min (5, event->xcrossing.detail); + xg_event->crossing.time = event->xcrossing.time; + xg_event->crossing.x = x; + xg_event->crossing.y = y; + xg_event->crossing.x_root = event->xcrossing.x_root; + xg_event->crossing.y_root = event->xcrossing.y_root; + gdk_event_set_device (xg_event, find_suitable_pointer (view->frame)); + } + + gtk_main_do_event (xg_event); + gdk_event_free (xg_event); +} + +static void +synthesize_focus_in_event (GtkWidget *offscreen_window) +{ + GdkWindow *wnd; + GdkEvent *focus_event; + + if (!gtk_widget_get_realized (offscreen_window)) + gtk_widget_realize (offscreen_window); + + wnd = gtk_widget_get_window (offscreen_window); + + focus_event = gdk_event_new (GDK_FOCUS_CHANGE); + focus_event->any.window = wnd; + focus_event->focus_change.in = TRUE; + g_object_ref (wnd); + + gtk_main_do_event (focus_event); + gdk_event_free (focus_event); +} + +struct xwidget_view * +xwidget_view_from_window (Window wdesc) +{ + Lisp_Object key = make_fixnum (wdesc); + Lisp_Object xwv = Fgethash (key, x_window_to_xwv_map, Qnil); + + if (NILP (xwv)) + return NULL; + + return XXWIDGET_VIEW (xwv); +} + static void xwidget_show_view (struct xwidget_view *xv) { xv->hidden = false; - gtk_widget_show (xv->widgetwindow); - gtk_fixed_move (GTK_FIXED (xv->emacswindow), - xv->widgetwindow, - xv->x + xv->clip_left, - xv->y + xv->clip_top); + XMoveWindow (xv->dpy, xv->wdesc, + xv->x + xv->clip_left, + xv->y + xv->clip_top); + XMapWindow (xv->dpy, xv->wdesc); + XFlush (xv->dpy); } /* Hide an xwidget view. */ @@ -238,28 +836,64 @@ xwidget_show_view (struct xwidget_view *xv) xwidget_hide_view (struct xwidget_view *xv) { xv->hidden = true; - gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow, - 10000, 10000); + XUnmapWindow (xv->dpy, xv->wdesc); + XFlush (xv->dpy); +} + +static void +xv_do_draw (struct xwidget_view *xw, struct xwidget *w) +{ + GtkOffscreenWindow *wnd; + cairo_surface_t *surface; + block_input (); + wnd = GTK_OFFSCREEN_WINDOW (w->widgetwindow_osr); + surface = gtk_offscreen_window_get_surface (wnd); + + cairo_save (xw->cr_context); + if (surface) + { + cairo_set_source_surface (xw->cr_context, surface, xw->clip_left, + xw->clip_top); + cairo_set_operator (xw->cr_context, CAIRO_OPERATOR_SOURCE); + cairo_paint (xw->cr_context); + } + cairo_restore (xw->cr_context); + + unblock_input (); } /* When the off-screen webkit master view changes this signal is called. It copies the bitmap from the off-screen instance. */ static gboolean offscreen_damage_event (GtkWidget *widget, GdkEvent *event, - gpointer xv_widget) -{ - /* Queue a redraw of onscreen widget. - There is a guard against receiving an invalid widget, - which should only happen if we failed to remove the - specific signal handler for the damage event. */ - if (GTK_IS_WIDGET (xv_widget)) - gtk_widget_queue_draw (GTK_WIDGET (xv_widget)); - else - message ("Warning, offscreen_damage_event received invalid xv pointer:%p\n", - xv_widget); + gpointer xwidget) +{ + block_input (); + + for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); + tail = XCDR (tail)) + { + if (XWIDGET_VIEW_P (XCAR (tail))) + { + struct xwidget_view *view = XXWIDGET_VIEW (XCAR (tail)); + + if (view->wdesc && XXWIDGET (view->model) == xwidget) + xv_do_draw (view, XXWIDGET (view->model)); + } + } + + unblock_input (); return FALSE; } + +void +xwidget_expose (struct xwidget_view *xv) +{ + struct xwidget *xw = XXWIDGET (xv->model); + + xv_do_draw (xv, xw); +} #endif /* USE_GTK */ void @@ -313,22 +947,108 @@ store_xwidget_js_callback_event (struct xwidget *xw, #ifdef USE_GTK +static void +store_xwidget_display_event (struct xwidget *xw) +{ + struct input_event evt; + Lisp_Object val; + + XSETXWIDGET (val, xw); + EVENT_INIT (evt); + evt.kind = XWIDGET_DISPLAY_EVENT; + evt.frame_or_window = Qnil; + evt.arg = val; + kbd_buffer_store_event (&evt); +} + +static void +webkit_ready_to_show (WebKitWebView *new_view, + gpointer user_data) +{ + Lisp_Object tem; + struct xwidget *xw; + + for (tem = Vxwidget_list; CONSP (tem); tem = XCDR (tem)) + { + if (XWIDGETP (XCAR (tem))) + { + xw = XXWIDGET (XCAR (tem)); + + if (EQ (xw->type, Qwebkit) + && WEBKIT_WEB_VIEW (xw->widget_osr) == new_view) + store_xwidget_display_event (xw); + } + } +} + +static GtkWidget * +webkit_create_cb_1 (WebKitWebView *webview, + struct xwidget_view *xv) +{ + Lisp_Object related; + Lisp_Object xwidget; + GtkWidget *widget; + + XSETXWIDGET (related, xv); + xwidget = Fmake_xwidget (Qwebkit, Qnil, make_fixnum (0), + make_fixnum (0), Qnil, + build_string (" *detached xwidget buffer*"), + related); + + if (NILP (xwidget)) + return NULL; + + widget = XXWIDGET (xwidget)->widget_osr; + + g_signal_connect (G_OBJECT (widget), "ready-to-show", + G_CALLBACK (webkit_ready_to_show), NULL); + + return widget; +} + +static GtkWidget * +webkit_create_cb (WebKitWebView *webview, + WebKitNavigationAction *nav_action, + gpointer user_data) +{ + switch (webkit_navigation_action_get_navigation_type (nav_action)) + { + case WEBKIT_NAVIGATION_TYPE_OTHER: + return webkit_create_cb_1 (webview, user_data); + + case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD: + case WEBKIT_NAVIGATION_TYPE_RELOAD: + case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED: + case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED: + case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED: + default: + return NULL; + } +} + void webkit_view_load_changed_cb (WebKitWebView *webkitwebview, WebKitLoadEvent load_event, gpointer data) { - switch (load_event) { - case WEBKIT_LOAD_FINISHED: + struct xwidget *xw = g_object_get_data (G_OBJECT (webkitwebview), + XG_XWIDGET); + + switch (load_event) { - struct xwidget *xw = g_object_get_data (G_OBJECT (webkitwebview), - XG_XWIDGET); - store_xwidget_event_string (xw, "load-changed", ""); + case WEBKIT_LOAD_FINISHED: + store_xwidget_event_string (xw, "load-changed", "load-finished"); + break; + case WEBKIT_LOAD_STARTED: + store_xwidget_event_string (xw, "load-changed", "load-started"); + break; + case WEBKIT_LOAD_REDIRECTED: + store_xwidget_event_string (xw, "load-changed", "load-redirected"); + break; + case WEBKIT_LOAD_COMMITTED: + store_xwidget_event_string (xw, "load-changed", "load-committed"); break; } - default: - break; - } } /* Recursively convert a JavaScript value to a Lisp value. */ @@ -498,51 +1218,6 @@ webkit_decide_policy_cb (WebKitWebView *webView, return FALSE; } } - - -/* For gtk3 offscreen rendered widgets. */ -static gboolean -xwidget_osr_draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data) -{ - struct xwidget *xw = g_object_get_data (G_OBJECT (widget), XG_XWIDGET); - struct xwidget_view *xv = g_object_get_data (G_OBJECT (widget), - XG_XWIDGET_VIEW); - - cairo_rectangle (cr, 0, 0, xv->clip_right, xv->clip_bottom); - cairo_clip (cr); - - gtk_widget_draw (xw->widget_osr, cr); - return FALSE; -} - -static gboolean -xwidget_osr_event_forward (GtkWidget *widget, GdkEvent *event, - gpointer user_data) -{ - /* Copy events that arrive at the outer widget to the offscreen widget. */ - struct xwidget *xw = g_object_get_data (G_OBJECT (widget), XG_XWIDGET); - GdkEvent *eventcopy = gdk_event_copy (event); - eventcopy->any.window = gtk_widget_get_window (xw->widget_osr); - - /* TODO: This might leak events. They should be deallocated later, - perhaps in xwgir_event_cb. */ - gtk_main_do_event (eventcopy); - - /* Don't propagate this event further. */ - return TRUE; -} - -static gboolean -xwidget_osr_event_set_embedder (GtkWidget *widget, GdkEvent *event, - gpointer data) -{ - struct xwidget_view *xv = data; - struct xwidget *xww = XXWIDGET (xv->model); - gdk_offscreen_window_set_embedder (gtk_widget_get_window - (xww->widgetwindow_osr), - gtk_widget_get_window (xv->widget)); - return FALSE; -} #endif /* USE_GTK */ @@ -568,63 +1243,19 @@ xwidget_init_view (struct xwidget *xww, XSETXWIDGET (xv->model, xww); #ifdef USE_GTK - if (EQ (xww->type, Qwebkit)) - { - xv->widget = gtk_drawing_area_new (); - /* Expose event handling. */ - gtk_widget_set_app_paintable (xv->widget, TRUE); - gtk_widget_add_events (xv->widget, GDK_ALL_EVENTS_MASK); - - /* Draw the view on damage-event. */ - g_signal_connect (G_OBJECT (xww->widgetwindow_osr), "damage-event", - G_CALLBACK (offscreen_damage_event), xv->widget); + xv->dpy = FRAME_X_DISPLAY (s->f); - if (EQ (xww->type, Qwebkit)) - { - g_signal_connect (G_OBJECT (xv->widget), "button-press-event", - G_CALLBACK (xwidget_osr_event_forward), NULL); - g_signal_connect (G_OBJECT (xv->widget), "button-release-event", - G_CALLBACK (xwidget_osr_event_forward), NULL); - g_signal_connect (G_OBJECT (xv->widget), "motion-notify-event", - G_CALLBACK (xwidget_osr_event_forward), NULL); - } - else - { - /* xwgir debug, orthogonal to forwarding. */ - g_signal_connect (G_OBJECT (xv->widget), "enter-notify-event", - G_CALLBACK (xwidget_osr_event_set_embedder), xv); - } - g_signal_connect (G_OBJECT (xv->widget), "draw", - G_CALLBACK (xwidget_osr_draw_cb), NULL); - } - - /* Widget realization. - - Make container widget first, and put the actual widget inside the - container later. Drawing should crop container window if necessary - to handle case where xwidget is partially obscured by other Emacs - windows. Other containers than gtk_fixed where explored, but - gtk_fixed had the most predictable behavior so far. */ - - xv->emacswindow = FRAME_GTK_WIDGET (s->f); - xv->widgetwindow = gtk_fixed_new (); - gtk_widget_set_has_window (xv->widgetwindow, TRUE); - gtk_container_add (GTK_CONTAINER (xv->widgetwindow), xv->widget); - - /* Store some xwidget data in the gtk widgets. */ - g_object_set_data (G_OBJECT (xv->widget), XG_FRAME_DATA, s->f); - g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET, xww); - g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET_VIEW, xv); - g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET, xww); - g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET_VIEW, xv); - - gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xww->width, - xww->height); - gtk_widget_set_size_request (xv->widgetwindow, xww->width, xww->height); - gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), xv->widgetwindow, x, y); xv->x = x; xv->y = y; - gtk_widget_show_all (xv->widgetwindow); + + xv->clip_left = 0; + xv->clip_right = xww->width; + xv->clip_top = 0; + xv->clip_bottom = xww->height; + + xv->wdesc = None; + xv->frame = s->f; + xv->cursor = cursor_for_hit (xww->hit_result, s->f); #elif defined NS_IMPL_COCOA nsxwidget_init_view (xv, xww, s, x, y); nsxwidget_resize_view(xv, xww->width, xww->height); @@ -681,6 +1312,8 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) window_box (s->w, TEXT_AREA, &text_area_x, &text_area_y, &text_area_width, &text_area_height); + /* On X11, this keeps generating expose events. */ +#ifndef USE_GTK /* Resize xwidget webkit if its container window size is changed in some ways, for example, a buffer became hidden in small split window, then it can appear front in merged whole window. */ @@ -693,6 +1326,7 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) make_int (text_area_width), make_int (text_area_height)); } +#endif clip_left = max (0, text_area_x - x); clip_right = max (clip_left, @@ -711,15 +1345,51 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) later. */ bool moved = (xv->x + xv->clip_left != x + clip_left || xv->y + xv->clip_top != y + clip_top); + +#ifdef USE_GTK + bool wdesc_was_none = xv->wdesc == None; +#endif xv->x = x; xv->y = y; +#ifdef USE_GTK + block_input (); + if (xv->wdesc == None) + { + Lisp_Object xvw; + XSETXWIDGET_VIEW (xvw, xv); + XSetWindowAttributes a; + a.event_mask = (ExposureMask | ButtonPressMask | ButtonReleaseMask + | PointerMotionMask | EnterWindowMask | LeaveWindowMask); + + xv->wdesc = XCreateWindow (xv->dpy, FRAME_X_WINDOW (s->f), + x + clip_left, y + clip_top, + clip_right - clip_left, + clip_bottom - clip_top, 0, + CopyFromParent, CopyFromParent, + CopyFromParent, CWEventMask, &a); + XDefineCursor (xv->dpy, xv->wdesc, xv->cursor); + xv->cr_surface = cairo_xlib_surface_create (xv->dpy, + xv->wdesc, + FRAME_DISPLAY_INFO (s->f)->visual, + clip_right - clip_left, + clip_bottom - clip_top); + xv->cr_context = cairo_create (xv->cr_surface); + Fputhash (make_fixnum (xv->wdesc), xvw, x_window_to_xwv_map); + + moved = false; + } +#endif + /* Has it moved? */ if (moved) { #ifdef USE_GTK - gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), - xv->widgetwindow, x + clip_left, y + clip_top); + 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 NS_IMPL_COCOA nsxwidget_move_view (xv, x + clip_left, y + clip_top); #endif @@ -735,10 +1405,14 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) || xv->clip_top != clip_top || xv->clip_left != clip_left) { #ifdef USE_GTK - gtk_widget_set_size_request (xv->widgetwindow, clip_right - clip_left, - clip_bottom - clip_top); - gtk_fixed_move (GTK_FIXED (xv->widgetwindow), xv->widget, -clip_left, - -clip_top); + if (!wdesc_was_none && !moved) + { + XResizeWindow (xv->dpy, xv->wdesc, 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 NS_IMPL_COCOA nsxwidget_resize_view (xv, clip_right - clip_left, clip_bottom - clip_top); @@ -758,12 +1432,15 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) if (!xwidget_hidden (xv)) { #ifdef USE_GTK - gtk_widget_queue_draw (xv->widgetwindow); - gtk_widget_queue_draw (xv->widget); + gtk_widget_queue_draw (xww->widget_osr); #elif defined NS_IMPL_COCOA nsxwidget_set_needsdisplay (xv); #endif } + +#ifdef USE_GTK + unblock_input (); +#endif } static bool @@ -975,16 +1652,13 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0, struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail)); if (XXWIDGET (xv->model) == xw) { -#ifdef USE_GTK - gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width, - xw->height); -#elif defined NS_IMPL_COCOA - nsxwidget_resize_view(xv, xw->width, xw->height); -#endif + wset_redisplay (XWINDOW (xv->w)); } } } + redisplay (); + return Qnil; } @@ -1084,13 +1758,15 @@ DEFUN ("delete-xwidget-view", CHECK_XWIDGET_VIEW (xwidget_view); struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view); #ifdef USE_GTK - gtk_widget_destroy (xv->widgetwindow); - /* xv->model still has signals pointing to the view. There can be - several views. Find the matching signals and delete them all. */ - g_signal_handlers_disconnect_matched (XXWIDGET (xv->model)->widgetwindow_osr, - G_SIGNAL_MATCH_DATA, - 0, 0, 0, 0, - xv->widget); + if (xv->wdesc != None) + { + block_input (); + cairo_destroy (xv->cr_context); + cairo_surface_destroy (xv->cr_surface); + XDestroyWindow (xv->dpy, xv->wdesc); + Fremhash (make_fixnum (xv->wdesc), x_window_to_xwv_map); + unblock_input (); + } #elif defined NS_IMPL_COCOA nsxwidget_delete_view (xv); #endif @@ -1145,6 +1821,19 @@ DEFUN ("xwidget-buffer", return XXWIDGET (xwidget)->buffer; } +DEFUN ("set-xwidget-buffer", + Fset_xwidget_buffer, Sset_xwidget_buffer, + 2, 2, 0, + doc: /* Set XWIDGET's buffer to BUFFER. */) + (Lisp_Object xwidget, Lisp_Object buffer) +{ + CHECK_XWIDGET (xwidget); + CHECK_BUFFER (buffer); + + XXWIDGET (xwidget)->buffer = buffer; + return Qnil; +} + DEFUN ("set-xwidget-plist", Fset_xwidget_plist, Sset_xwidget_plist, 2, 2, 0, @@ -1183,6 +1872,166 @@ DEFUN ("xwidget-query-on-exit-flag", return (XXWIDGET (xwidget)->kill_without_query ? Qnil : Qt); } +DEFUN ("xwidget-webkit-search", Fxwidget_webkit_search, Sxwidget_webkit_search, + 2, 5, 0, + doc: /* Begin an incremental search operation in an xwidget. +QUERY should be a string containing the text to search for. XWIDGET +should be a WebKit xwidget where the search will take place. When the +search operation is complete, callers should also call +`xwidget-webkit-finish-search' to complete the search operation. + +CASE-INSENSITIVE, when non-nil, will cause the search to ignore the +case of characters inside QUERY. BACKWARDS, when non-nil, will cause +the search to proceed towards the beginning of the widget's contents. +WRAP-AROUND, when nil, will cause the search to stop upon hitting the +end of the widget's contents. + +It is OK to call this function even when a search is already in +progress. In that case, the previous search query will be replaced +with QUERY. */) + (Lisp_Object query, Lisp_Object xwidget, Lisp_Object case_insensitive, + Lisp_Object backwards, Lisp_Object wrap_around) +{ +#ifdef USE_GTK + WebKitWebView *webview; + WebKitFindController *controller; + WebKitFindOptions opt; + struct xwidget *xw; + gchar *g_query; +#endif + + CHECK_STRING (query); + CHECK_XWIDGET (xwidget); + +#ifdef USE_GTK + xw = XXWIDGET (xwidget); + webview = WEBKIT_WEB_VIEW (xw->widget_osr); + query = ENCODE_UTF_8 (query); + opt = WEBKIT_FIND_OPTIONS_NONE; + g_query = xstrdup (SSDATA (query)); + + if (!NILP (case_insensitive)) + opt |= WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE; + if (!NILP (backwards)) + opt |= WEBKIT_FIND_OPTIONS_BACKWARDS; + if (!NILP (wrap_around)) + opt |= WEBKIT_FIND_OPTIONS_WRAP_AROUND; + + if (xw->find_text) + xfree (xw->find_text); + xw->find_text = g_query; + + block_input (); + controller = webkit_web_view_get_find_controller (webview); + webkit_find_controller_search (controller, g_query, opt, G_MAXUINT); + unblock_input (); +#endif + + return Qnil; +} + +DEFUN ("xwidget-webkit-next-result", Fxwidget_webkit_next_result, + Sxwidget_webkit_next_result, 1, 1, 0, + doc: /* Show the next result matching the current search query. + +XWIDGET should be an xwidget that currently has a search query. +Before calling this function, you should start a search operation +using `xwidget-webkit-search'. */) + (Lisp_Object xwidget) +{ + struct xwidget *xw; +#ifdef USE_GTK + WebKitWebView *webview; + WebKitFindController *controller; +#endif + + CHECK_XWIDGET (xwidget); + xw = XXWIDGET (xwidget); + + if (!xw->find_text) + error ("Widget has no ongoing search operation"); + +#ifdef USE_GTK + block_input (); + webview = WEBKIT_WEB_VIEW (xw->widget_osr); + controller = webkit_web_view_get_find_controller (webview); + webkit_find_controller_search_next (controller); + unblock_input (); +#endif + + return Qnil; +} + +DEFUN ("xwidget-webkit-previous-result", Fxwidget_webkit_previous_result, + Sxwidget_webkit_previous_result, 1, 1, 0, + doc: /* Show the previous result matching the current search query. + +XWIDGET should be an xwidget that currently has a search query. +Before calling this function, you should start a search operation +using `xwidget-webkit-search'. */) + (Lisp_Object xwidget) +{ + struct xwidget *xw; +#ifdef USE_GTK + WebKitWebView *webview; + WebKitFindController *controller; +#endif + + CHECK_XWIDGET (xwidget); + xw = XXWIDGET (xwidget); + + if (!xw->find_text) + error ("Widget has no ongoing search operation"); + +#ifdef USE_GTK + block_input (); + webview = WEBKIT_WEB_VIEW (xw->widget_osr); + controller = webkit_web_view_get_find_controller (webview); + webkit_find_controller_search_previous (controller); + + if (xw->find_text) + { + xfree (xw->find_text); + xw->find_text = NULL; + } + unblock_input (); +#endif + + return Qnil; +} + +DEFUN ("xwidget-webkit-finish-search", Fxwidget_webkit_finish_search, + Sxwidget_webkit_finish_search, 1, 1, 0, + doc: /* Finish XWIDGET's search operation. + +XWIDGET should be an xwidget that currently has a search query. +Before calling this function, you should start a search operation +using `xwidget-webkit-search'. */) + (Lisp_Object xwidget) +{ + struct xwidget *xw; +#ifdef USE_GTK + WebKitWebView *webview; + WebKitFindController *controller; +#endif + + CHECK_XWIDGET (xwidget); + xw = XXWIDGET (xwidget); + + if (!xw->find_text) + error ("Widget has no ongoing search operation"); + +#ifdef USE_GTK + block_input (); + webview = WEBKIT_WEB_VIEW (xw->widget_osr); + controller = webkit_web_view_get_find_controller (webview); + webkit_find_controller_search_finish (controller); + unblock_input (); +#endif + + return Qnil; +} + void syms_of_xwidget (void) { @@ -1215,6 +2064,12 @@ syms_of_xwidget (void) defsubr (&Sxwidget_plist); defsubr (&Sxwidget_buffer); defsubr (&Sset_xwidget_plist); + defsubr (&Sxwidget_perform_lispy_event); + defsubr (&Sxwidget_webkit_search); + defsubr (&Sxwidget_webkit_finish_search); + defsubr (&Sxwidget_webkit_next_result); + defsubr (&Sxwidget_webkit_previous_result); + defsubr (&Sset_xwidget_buffer); DEFSYM (QCxwidget, ":xwidget"); DEFSYM (QCtitle, ":title"); @@ -1236,6 +2091,15 @@ syms_of_xwidget (void) Vxwidget_view_list = Qnil; Fprovide (intern ("xwidget-internal"), Qnil); + + id_to_xwidget_map = CALLN (Fmake_hash_table, QCtest, Qeq); + staticpro (&id_to_xwidget_map); + +#ifdef USE_GTK + x_window_to_xwv_map = CALLN (Fmake_hash_table, QCtest, Qeq); + + staticpro (&x_window_to_xwv_map); +#endif } @@ -1374,7 +2238,7 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix) /* The only call to xwidget_end_redisplay is in dispnew. xwidget_end_redisplay (w->current_matrix); */ struct xwidget_view *xv - = xwidget_view_lookup (glyph->u.xwidget, w); + = xwidget_view_lookup (xwidget_from_id (glyph->u.xwidget), w); #ifdef USE_GTK /* FIXME: Is it safe to assume xwidget_view_lookup always succeeds here? If so, this comment can be removed. @@ -1424,6 +2288,26 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix) } } +#ifdef USE_GTK +void +kill_frame_xwidget_views (struct frame *f) +{ + Lisp_Object rem = Qnil; + + for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); + tail = XCDR (tail)) + { + if (XXWIDGET_VIEW (XCAR (tail))->frame == f) + rem = Fcons (XCAR (tail), rem); + } + + for (; CONSP (rem); rem = XCDR (rem)) + { + Fdelete_xwidget_view (XCAR (rem)); + } +} +#endif + /* Kill all xwidget in BUFFER. */ void kill_buffer_xwidgets (Lisp_Object buffer) @@ -1437,12 +2321,15 @@ kill_buffer_xwidgets (Lisp_Object buffer) { CHECK_XWIDGET (xwidget); struct xwidget *xw = XXWIDGET (xwidget); + Fremhash (make_fixnum (xw->xwidget_id), id_to_xwidget_map); #ifdef USE_GTK if (xw->widget_osr && xw->widgetwindow_osr) { gtk_widget_destroy (xw->widget_osr); gtk_widget_destroy (xw->widgetwindow_osr); } + if (xw->find_text) + xfree (xw->find_text); if (!NILP (xw->script_callbacks)) for (ptrdiff_t idx = 0; idx < ASIZE (xw->script_callbacks); idx++) { diff --git a/src/xwidget.h b/src/xwidget.h index 591f23489d..ad8b7c039c 100644 --- a/src/xwidget.h +++ b/src/xwidget.h @@ -32,6 +32,8 @@ #define XWIDGET_H_INCLUDED #if defined (USE_GTK) #include +#include +#include "xterm.h" #elif defined (NS_IMPL_COCOA) && defined (__OBJC__) #import #import "nsxwidget.h" @@ -59,11 +61,14 @@ #define XWIDGET_H_INCLUDED int height; int width; + uint32_t xwidget_id; + char *find_text; #if defined (USE_GTK) /* For offscreen widgets, unused if not osr. */ GtkWidget *widget_osr; GtkWidget *widgetwindow_osr; + guint hit_result; #elif defined (NS_IMPL_COCOA) # ifdef __OBJC__ /* For offscreen widgets, unused if not osr. */ @@ -98,9 +103,13 @@ #define XWIDGET_H_INCLUDED bool hidden; #if defined (USE_GTK) - GtkWidget *widget; - GtkWidget *widgetwindow; - GtkWidget *emacswindow; + Display *dpy; + Window wdesc; + Emacs_Cursor cursor; + struct frame *frame; + + cairo_surface_t *cr_surface; + cairo_t *cr_context; #elif defined (NS_IMPL_COCOA) # ifdef __OBJC__ XvWindow *xvWindow; @@ -162,6 +171,18 @@ #define XG_XWIDGET_VIEW "emacs_xwidget_view" void store_xwidget_js_callback_event (struct xwidget *xw, Lisp_Object proc, Lisp_Object argument); + +extern struct xwidget *xwidget_from_id (uint32_t id); + +#ifdef HAVE_X_WINDOWS +struct xwidget_view *xwidget_view_from_window (Window wdesc); +void xwidget_expose (struct xwidget_view *xv); +extern void kill_frame_xwidget_views (struct frame *f); +extern void xwidget_button (struct xwidget_view *, bool, int, + int, int, int, Time); +extern void xwidget_motion_or_crossing (struct xwidget_view *, + const XEvent *); +#endif #else INLINE_HEADER_BEGIN INLINE void syms_of_xwidget (void) {} --=-=-=-- From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Lars Ingebrigtsen Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 07 Nov 2021 01:40:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Po Lu Cc: Eli Zaretskii , 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163624918322044 (code B ref 51473); Sun, 07 Nov 2021 01:40:01 +0000 Received: (at 51473) by debbugs.gnu.org; 7 Nov 2021 01:39:43 +0000 Received: from localhost ([127.0.0.1]:51277 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjX9q-0005jU-G3 for submit@debbugs.gnu.org; Sat, 06 Nov 2021 21:39:42 -0400 Received: from quimby.gnus.org ([95.216.78.240]:57460) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjX9j-0005jA-Qk for 51473@debbugs.gnu.org; Sat, 06 Nov 2021 21:39:41 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnus.org; s=20200322; h=Content-Transfer-Encoding:Content-Type:MIME-Version:Message-ID :In-Reply-To:Date:References:Subject:Cc:To:From:Sender:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=JkKE7Jr2SfHYzhZyKYyRNuQOfTC2ZZz0ds6/pqNbJVQ=; b=kH5RUcmY9rdS/x1CSY88tVmLYE nLbx8l7x4J0VcN/SftSZrjnyXCG2dRPC58YrYTFJut8eRGFbvVnuuK6SNKOlWy1VMJiLNcZNuL8fh PtO2tYsDC72znhrr0UmbdxOpGRFEf34aj22rmvOwdjXJEJsB73/BvW7qnRJx+lT5HCbM=; Received: from [84.212.220.105] (helo=elva) by quimby.gnus.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mjX9b-0003a0-3K; Sun, 07 Nov 2021 02:39:29 +0100 From: Lars Ingebrigtsen References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> <87o86xzhuw.fsf@yahoo.com> <87sfw9cha3.fsf@gnus.org> <878ry0ztjo.fsf@yahoo.com> <87zgqgrd32.fsf@gnus.org> <87zgqgyd9d.fsf@yahoo.com> <87r1bsrc7a.fsf@gnus.org> <87v914ycvi.fsf@yahoo.com> <87mtmgrbwh.fsf@gnus.org> <87pmrcycio.fsf@yahoo.com> Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAABGdBTUEAALGPC/xhBQAAACBj SFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAElBMVEXR0OD09/uknaqD eIBcUVX///9uGm+PAAAAAWJLR0QF+G/pxwAAAAd0SU1FB+ULBwEcIyWIbyEAAAG9SURBVDjLnVOB kdswDKOUBaSfgKY8QE/UBBX3n+kByfG16bf9f50viQmQAClGUv34yDeAUvBIkZrwFJGL+pJRPquR j5KOYuntkBuoTyAVxfMCiJaDGeXteCmVKuioVo//i9evAWj0L/x/AkX0DwsEpLl3099dAsgjpolY uqk4HDLiimCx2w5YBiriK73cKWZOZD6Vn1dRDJIATPKvlsHKxiOalWqYekIZzVudGWb7BcQWQUmw YMJahwVugbUBIH6gBNoSQ3PQR4bsjKkPzV1lCQkRs5MZw2zmZuIwrQvJHgvoejYj4PRMJ0siTgLe OUJ8stTWjuGG2GSG05fmR+xDYMQC3DVDasen9wsY+GloL587wTtjBPDSkW5KlTYR7xEbCJr26PIA p01HVbELcPQKmLnm54w9B/KYZG1/+XShEpzEdfXC6wM6aBe1UKDhvVGqGxsQJo/ZEQZzzEb3IDgz MOrVZeyqzrod68NK9OPWB1mL81NybBqap4DPmBjL2pLKqSvvfsA0osMn5n0elYsomJY3+l5d4SZy XxufsnFPBmeAWr3hfnDxFX/lbHotEEV3cax6Vqwmmlu3OEfYO54ehuy9s6onAAAAJXRFWHRkYXRl OmNyZWF0ZQAyMDIxLTExLTA3VDAxOjI4OjM1KzAwOjAwHlJJrQAAACV0RVh0ZGF0ZTptb2RpZnkA MjAyMS0xMS0wN1QwMToyODozNSswMDowMG8P8REAAAAASUVORK5CYII= X-Now-Playing: Lisa Gerrard, Jules Maxwell's _Burn_: "Deshta (Forever)" Date: Sun, 07 Nov 2021 02:39:26 +0100 In-Reply-To: <87pmrcycio.fsf@yahoo.com> (Po Lu's message of "Sun, 07 Nov 2021 09:34:23 +0800") Message-ID: <87ilx4rbg1.fsf@gnus.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Report: Spam detection software, running on the system "quimby.gnus.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see @@CONTACT_ADDRESS@@ for details. Content preview: Po Lu writes: > Good catch, thanks! Does this work? It builds! =?UTF-8?Q?=E2=9C=A8?= Content analysis details: (-2.9 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Po Lu writes: > Good catch, thanks! Does this work? It builds! =E2=9C=A8 And it seems to work fine, too after doing some cursory browsing to a handful of sites. So if you send me a new tar ball of patches to apply, I'll get them pushed. (They're to be applied in the sequence they're numbered?) --=20 (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 07 Nov 2021 01:56:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Lars Ingebrigtsen Cc: Eli Zaretskii , 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163625014123744 (code B ref 51473); Sun, 07 Nov 2021 01:56:02 +0000 Received: (at 51473) by debbugs.gnu.org; 7 Nov 2021 01:55:41 +0000 Received: from localhost ([127.0.0.1]:51304 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjXPJ-0006Au-70 for submit@debbugs.gnu.org; Sat, 06 Nov 2021 21:55:41 -0400 Received: from sonic308-10.consmr.mail.ne1.yahoo.com ([66.163.187.33]:39822) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjXPE-0006Ad-W4 for 51473@debbugs.gnu.org; Sat, 06 Nov 2021 21:55:39 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636250129; bh=sTSbpK708Zb0gNXBc9jsO3imzBBdUe15f20riIVFHrs=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=BzNsbbUsKnyOCPamg9OQmsf/B7Jm6OkbFJsyxcAwblLPkUxAKi0KGLlslKj8cKIEAk4/KdQoIyy9ra4ZRALmpyqBfHCifk8a0km6WByqjQ5+p2YEnflekuzPr4B8BzIktKICjMQkz7hB8TviyzKuQ2PnjDSED4mE2niplv+BTfwbDFFnAo5DoKlzECH1iPadvz2xXF7C7mJqkVSWTtLryC151oI0lLSNWRechlqFNZ6XTsu18sjP7utOAeGQRsyjzNGNUHWzzzBcpNgMwE2TXI2xbzLtkvvfqOvksn1HpSYAen4ywB82eiO64PwO0LArN+mMReQuRw3N2cBKOPAlEg== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636250129; bh=3hEhssRQxxOgFeq1o8H8hMNShexhkmvW4zNDnv4m2pB=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=Swmixno6FBuQ0K3KTL2kjzoEi3Qlx2ix0BOBCi4/+jIJ82LHF+y82pBIpENsqkDm+vXo3bJH05L2wSHBhe5HlNol9QOch07qe3AMHRkMjVh6y1DhqPIM48pM8QnvH8r7WtjaN/u/FAhKWRS5e+H0sdgMkxaInESMP31XEntxVeJS+oFJHVWllTHGaTtJjjqbNiwq1ODKHaB5UL+M/uygZalkJQJ2bJH1w1+n/cZkgVsT98ikHIiRGyOxia6oNKi/oTmtKzVNY/9JmZORiocubbsl828lsiUziCTaBohRKJ7xRpYs6nqFLD3ImtlpuVtacwNOKQF27dejiYAbcz8a1Q== X-YMail-OSG: 1rrN8SIVM1kI0JhPmQO0nRlpJd5ukHHm9gOWHujNgtxjJigPRwSIhC21ubGiUgg iRnMkC19Q5F.56UpZTo0vjmVDQ_xm1xTLewLHBzf6pFeMJZLtfwskmDSN_nM6KZkkf4hw8gy4T3e oKHG1Akv6SL0YCRPNCOK8za28Q_F0ODQ8uUtMrjrfG0A7H49IhzBnQYRIF9sIVp80fnLMFE7PPpB 8V0GMHF_Jhkhgej.pW_qTYXHmbAnz0BsOqgiZi0hF.FlRZw.9nejb3zzjAtFoMneHxSDUGhzEslM ROX5IDlJhYKU.J151vpeExkX2XD7ffno6r_teAsAXhP0m4DbSwCD5SqU2pOhYXI5..Om9Elr.vDr hkMOHLqlewqzlvO68aIXQlIM7ET.L_CeiFJ4G.qNJaXkvWc23Fm.lN19STDlgkyi9EChcnRl8OU_ DAkNZJoaZkuV4Ur6STCfANK1YZ8Qml.4yB5RTMkv0kwKz3ZH1R2aupZLn00qphVReXPY2kT2b101 .KlAys.sd2wRWavqVqUnR1hM1xvzsaz2cnjWdk3xlN5vserwe4RWLY00RbD2ZGkxlS2jfRfWlm63 IOkhGyFwM1vEooQRsNEEeJDIZdNuioMV2rJjzWxPQ6ofHTsDc2fToO94XByL2n5LWWbkSFijvJO0 Y5HinuK3MRpNVLnDcpWvHvySyQtrFc0owpW7v.McCHno7JlFwXCI.a5bG5OqjukHkg029myxh4WO Om1dwzC7oO4xTEtNcvM3cfKGyhcAgqoyEgXBl4Q0DUbmW1O4yi9md9I2R7smppaZhZ7AD5gpPSX7 Nh6r5kzlEjtgFLEZyCCXXlHijKnBY6ec5FI9.Jvotx9BJIPzKfsNjH4WdGjJjqx5Z2lEvQEFuzSV 3sTuzKrFAGWIpFBsbrDXT5cK4.vwDfvRy9JcS2IP7A.bKvSBqE73h8VxcmXgk_2QFF8QFvcC70m7 DAna7IOCEGFKQ_5d3azpCRCBI0FOCAONmpDw7QmXNNOAdSCKMZ0HTYgYTBVn7llqz_xrllsFhwS9 ._74KM17C4gf7EZu8KNSGMaMPCggzpiTlxDhqZ.GZ03CQnrrL7dMKO7F3xKqjgZQ_OzbHYJ.XN8H tUZEn1URANF5J3_EM..m8oDqnwpBSedOUJrCSVUO4TBBPZWnO1.X.M0ATjzgOJk2pa9GbKbeuimQ V84A1mKqnJ3Y06Tq5hWhXUPOxELcaqpZvIXMbmV1KPPXsPjOZHCvhO1KlbJmYtGlM5XLL.4I7ksn SV3DIABHGh8GMSEdswq94gavU2COSufS15NG64jfXRbhuhgTlZCM.ZBudizAT0B7B7kxgTpqvL9F zPQNB4B14qBkX9WxllfBufpZV80Kyj7hXFzbIMgSejhOY_ouLRznEZwLCHvC4qoerftu72keKk1M 2ukt.EOcnjQTLse0ePZgvja0Jt_Q8EGKQCYnLCtNDv1BsmvEtjnfl4Q0ImvXwTVr7JFp8ehcK0JZ 5heLavBCFGN25ZadGXbRWKXvQ_N5SWtKnQvP9_snuXNyfVYURIcyRbaNQ9IkFkPmcrcnKExK4UeL aquxyDoEf1yS_EDAPBuoORUsuBynpYLahWgDcoyMMDg2ijigYmx..8xYSNjabwm2sc60Kv2SZHjT wLxzVFHib8.XrWYIajAsvOlnIRdVxXby47AmaasWhKB0zTQsbZG0x92oZyT1juRqt5F6r2iAp9b0 EatD64r9gns1IQ6yXu_wlvqFtlHyjGrj7UOXM0PlmhRu6FyPxUt7CovugZ5Sx2ZLBEYU5s5GHtDA zae8oA2_xprEjOxNyVSxEkc4DdOatIH3pA2e9C7sIf4jDqyka6QXH.BG4Mchr.VhtBpJhEzJqB0z AVaCW7eo5u77oJdJeFelIZf82QHGNpfzOQxznVmgWihULOCwwAnfN_82TfsOoIY9K0uNHlwks.fm qyAzoBrklxuUVeiOcNeusFHIZt62OeYrR5hDGSs__R5RyLEaoFPinOL_pznNG5ZkvSTaWHH.Yqs. mjwssknGCzu4dvpDHl5fVVDGZ60HSlDtKlJWe2ZR2Oy1PtyTvFZdDQrYQZJLajXXLmdcK2OvnFBY 5EpNshl9GV4.S9HHlA5rTwm0YxEUY7_igTQgE.6U3ncklPDJDiM7lN3ToiFb85ydeRJG5pIiMj3J gCZPb5o7OeqNIiOrragllSBXmc33Q.2hkUDlyfbnN21ntoeCeaLL0vjzNyvDrpBwyTtGbRwnz5Q1 TOzzCfOeZreMzsoCUM90HBI0p1hH5G3CoF3.L83a_55cGj44Ag7O4U7Wx9ww- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic308.consmr.mail.ne1.yahoo.com with HTTP; Sun, 7 Nov 2021 01:55:29 +0000 Received: by kubenode510.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID a89192a491bfa9fefb483dbda1f78e4a; Sun, 07 Nov 2021 01:55:25 +0000 (UTC) From: Po Lu References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> <87o86xzhuw.fsf@yahoo.com> <87sfw9cha3.fsf@gnus.org> <878ry0ztjo.fsf@yahoo.com> <87zgqgrd32.fsf@gnus.org> <87zgqgyd9d.fsf@yahoo.com> <87r1bsrc7a.fsf@gnus.org> <87v914ycvi.fsf@yahoo.com> <87mtmgrbwh.fsf@gnus.org> <87pmrcycio.fsf@yahoo.com> <87ilx4rbg1.fsf@gnus.org> Date: Sun, 07 Nov 2021 09:55:20 +0800 In-Reply-To: <87ilx4rbg1.fsf@gnus.org> (Lars Ingebrigtsen's message of "Sun, 07 Nov 2021 02:39:26 +0100") Message-ID: <87lf20ybjr.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Mailer: WebService/1.1.19306 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 59571 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Lars Ingebrigtsen writes: > It builds! =E2=9C=A8 > > And it seems to work fine, too after doing some cursory browsing to a > handful of sites. So if you send me a new tar ball of patches to apply, > I'll get them pushed. Thanks :) > (They're to be applied in the sequence they're numbered?) Yes, I created them with git format-patch. --=-=-= Content-Type: application/gzip Content-Disposition: attachment; filename=patches.tar.gz Content-Transfer-Encoding: base64 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 --=-=-=-- From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Lars Ingebrigtsen Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 07 Nov 2021 02:05:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Po Lu Cc: Eli Zaretskii , 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163625066124635 (code B ref 51473); Sun, 07 Nov 2021 02:05:02 +0000 Received: (at 51473) by debbugs.gnu.org; 7 Nov 2021 02:04:21 +0000 Received: from localhost ([127.0.0.1]:51309 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjXXh-0006PG-6Q for submit@debbugs.gnu.org; Sat, 06 Nov 2021 22:04:21 -0400 Received: from quimby.gnus.org ([95.216.78.240]:57594) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjXXb-0006Ow-Ic for 51473@debbugs.gnu.org; Sat, 06 Nov 2021 22:04:19 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnus.org; s=20200322; h=Content-Transfer-Encoding:Content-Type:MIME-Version:Message-ID :In-Reply-To:Date:References:Subject:Cc:To:From:Sender:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=ez0t4T+eJ+xD4f89SLRmHP/hV/E3lzaSmhPzaxR0RcY=; b=SXDs0SnFtDOo6M40COqeVxgB5M YDE1MGKrZ0HgB8YfhGEyVK95VnDvsnVq/E3PRhhAqYQKaEWIBs/BiyaHq8pXlJJZ/+cC3F3kpgHZO raOBvRGUonORb5xw0hPBGqt4McTd2wETCm0w/SSY3id7XXx2PnA4LTbu4OjMrSYcc8Zk=; Received: from [84.212.220.105] (helo=elva) by quimby.gnus.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mjXXS-0003nE-Ev; Sun, 07 Nov 2021 03:04:09 +0100 From: Lars Ingebrigtsen References: <87zgqslafe.fsf.ref@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> <87o86xzhuw.fsf@yahoo.com> <87sfw9cha3.fsf@gnus.org> <878ry0ztjo.fsf@yahoo.com> <87zgqgrd32.fsf@gnus.org> <87zgqgyd9d.fsf@yahoo.com> <87r1bsrc7a.fsf@gnus.org> <87v914ycvi.fsf@yahoo.com> <87mtmgrbwh.fsf@gnus.org> <87pmrcycio.fsf@yahoo.com> <87ilx4rbg1.fsf@gnus.org> <87lf20ybjr.fsf@yahoo.com> Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAABGdBTUEAALGPC/xhBQAAACBj SFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAIVBMVEX8+e7z6tfo1sy9 goHOopzVr6vFkY+4d3fd1sbfybn////YsK2pAAAAAWJLR0QKaND0VgAAAAd0SU1FB+ULBwICL/o5 oowAAAEzSURBVDjLtZLBTsMwDIbjPYH/SEg7bkWAuMGRG6AyruugElekqYX7HgAegTcmSZPGbtoL EpaqVPls5/+dGDMfZP4CeAkg/hcJFHdsUTYpgeonwKKg/wgsnYlCZspMMnk6AcT/wgfpMS0CGbxy M+TxFFF5/tAc76vtycoRe5lX3e1z//LY77p9rnI9zPrsu326bN4Ohy/RauMOdw0r9xHyQRR8tNW2 AVErJkBB7k19d+wvTt179jGA18NnXeNjt/ejIWU0rFZsiXGrnFFFmWD11AXfDIudVNJ4tyzzBrnq 6mypKlVmwAUgBWhomEDe1WD64DjsBBB9IF9orI/vKvngiOd9kARxXc3IZSU3gtzQA4Q0sPaBBJRB GIDg78A9OP+ugg9f7hgCwI9xKcA1QlhXwlj/AuYLGRMxt9yIAAAAJXRFWHRkYXRlOmNyZWF0ZQAy MDIxLTExLTA3VDAyOjAyOjQ3KzAwOjAwcYwUWwAAACV0RVh0ZGF0ZTptb2RpZnkAMjAyMS0xMS0w N1QwMjowMjo0NyswMDowMADRrOcAAAAASUVORK5CYII= X-Now-Playing: Pet Shop Boys's _Cricket Wife_: "Cricket Wife" Date: Sun, 07 Nov 2021 03:04:05 +0100 In-Reply-To: <87lf20ybjr.fsf@yahoo.com> (Po Lu's message of "Sun, 07 Nov 2021 09:55:20 +0800") Message-ID: <87a6igraay.fsf@gnus.org> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/29.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Report: Spam detection software, running on the system "quimby.gnus.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see @@CONTACT_ADDRESS@@ for details. Content preview: Po Lu writes: >> (They're to be applied in the sequence they're numbered?) > > Yes, I created them with git format-patch. Great! Now applied and pushed to trunk. =?UTF-8?Q?=F0=9F=98=80?= Content analysis details: (-2.9 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) Po Lu writes: >> (They're to be applied in the sequence they're numbered?) > > Yes, I created them with git format-patch. Great! Now applied and pushed to trunk. =F0=9F=98=80 (So I'm closing this bug report.) --=20 (domestic pets only, the antidote for overdose, milk.) bloggy blog: http://lars.ingebrigtsen.no From debbugs-submit-bounces@debbugs.gnu.org Sat Nov 06 22:04:27 2021 Received: (at control) by debbugs.gnu.org; 7 Nov 2021 02:04:27 +0000 Received: from localhost ([127.0.0.1]:51312 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjXXm-0006PX-RN for submit@debbugs.gnu.org; Sat, 06 Nov 2021 22:04:26 -0400 Received: from quimby.gnus.org ([95.216.78.240]:57610) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjXXl-0006PE-7Y for control@debbugs.gnu.org; Sat, 06 Nov 2021 22:04:25 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnus.org; s=20200322; h=Subject:From:To:Message-Id:Date:Sender:Reply-To:Cc: MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=SCetwRKThW32MRbMxO9ReKxlHgHiqjbLYiXP6lQG7Wo=; b=BxNgwi0KiXIhjybkoIcMniCeMq g+hXXs4yH3OkiN8WKEsd29MlMX6EJvRAWo1jCGeMwFfesXTRl9jIPDxxrhxUR/VqRIPuaPHYLMNcJ uSyhtn4W8X+Kt06H8D/kSyjbXcIihTzoKzGArLD2coZ17jMsF4XyzmiT9+qJ5qPIDWJ0=; Received: from [84.212.220.105] (helo=elva) by quimby.gnus.org with esmtpsa (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mjXXd-0003nR-Nl for control@debbugs.gnu.org; Sun, 07 Nov 2021 03:04:19 +0100 Date: Sun, 07 Nov 2021 03:04:17 +0100 Message-Id: <878ry0raam.fsf@gnus.org> To: control@debbugs.gnu.org From: Lars Ingebrigtsen Subject: control message for bug #51473 X-Spam-Report: Spam detection software, running on the system "quimby.gnus.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see @@CONTACT_ADDRESS@@ for details. Content preview: close 51473 29.1 quit Content analysis details: (-2.9 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -1.0 ALL_TRUSTED Passed through trusted hosts only via SMTP -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] X-Spam-Score: -2.3 (--) X-Debbugs-Envelope-To: control X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) close 51473 29.1 quit From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Eli Zaretskii Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 07 Nov 2021 10:10:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Po Lu Cc: larsi@gnus.org, 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.16362797628185 (code B ref 51473); Sun, 07 Nov 2021 10:10:01 +0000 Received: (at 51473) by debbugs.gnu.org; 7 Nov 2021 10:09:22 +0000 Received: from localhost ([127.0.0.1]:51799 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjf74-00027x-LA for submit@debbugs.gnu.org; Sun, 07 Nov 2021 05:09:22 -0500 Received: from eggs.gnu.org ([209.51.188.92]:46482) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjf70-00027Y-Tv for 51473@debbugs.gnu.org; Sun, 07 Nov 2021 05:09:21 -0500 Received: from fencepost.gnu.org ([2001:470:142:3::e]:40728) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mjf6v-0008GI-Mx; Sun, 07 Nov 2021 05:09:13 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date: mime-version; bh=GvDgzrTM+ENEeJzQxu5dI795InDOINvgabaxvQsxQrI=; b=SL8dkh0hkws1 6fhWL4RkHAfIbhCknnizOjT/ryZbN0O7Y8axPWZEHaFNgyQCapIROTXdo5b2uraS8wMsdeEi2Ayna EUtnrNklfxvX4Drq0GRon6uDfEgpyMIaxteyJ6vkcd6yojRPtWiZb1NCSGM3WMuKqdT+8jI7rqTyp eKD5A7c2pB8TMkoN5Tzd+dOtw2X7O9Dt+wUMYSZiJf2FOm45uIarxccsFXJCGI6u+CGOVDibPpWD+ VvQNMuyjLfQiR2B5gIozVFo5HvliusnoPflYxVJShytK3SlNcjAA4ojEV7oRKsLLhJkvJCrsxvfE8 pvAp5SwTG0XJcPPkpv9MVA==; Received: from [87.69.77.57] (port=3603 helo=home-c4e4a596f7) by fencepost.gnu.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mjf6u-0003cf-Sn; Sun, 07 Nov 2021 05:09:13 -0500 Date: Sun, 07 Nov 2021 12:09:00 +0200 Message-Id: <835yt49t1f.fsf@gnu.org> From: Eli Zaretskii In-Reply-To: <878ry0ztjo.fsf@yahoo.com> (message from Po Lu on Sun, 07 Nov 2021 08:41:15 +0800) References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> <87o86xzhuw.fsf@yahoo.com> <87sfw9cha3.fsf@gnus.org> <878ry0ztjo.fsf@yahoo.com> X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > From: Po Lu > Cc: Eli Zaretskii , 51473@debbugs.gnu.org > Date: Sun, 07 Nov 2021 08:41:15 +0800 > > Lars Ingebrigtsen writes: > > > I can test both, but it'd be easier to test if it was just one huge > > patch. (When applying for real, we can apply the patch series.) So can > > you post this series as one patch? > > Thanks, here you go. > --- a/src/print.c > +++ b/src/print.c > @@ -1521,8 +1521,20 @@ print_vectorlike (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag, > printchar ('>', printcharfun); > break; > > - case PVEC_XWIDGET: case PVEC_XWIDGET_VIEW: > - print_c_string ("# + case PVEC_XWIDGET: > +#ifdef HAVE_XWIDGETS > + { > + int len = sprintf (buf, "#", > + XXWIDGET (obj)->xwidget_id, > + XXWIDGET (obj)->widget_osr); > + strout (buf, len, len, printcharfun); > + break; > + } The printed representation of xwidget objects should be documented in the ELisp manual, under the "Editing Types" section. In fact, we lack a subsection there for xwidgets; it should be added. Thanks. From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 07 Nov 2021 12:04:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Eli Zaretskii Cc: larsi@gnus.org, 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163628660020204 (code B ref 51473); Sun, 07 Nov 2021 12:04:02 +0000 Received: (at 51473) by debbugs.gnu.org; 7 Nov 2021 12:03:20 +0000 Received: from localhost ([127.0.0.1]:51962 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjgtL-0005Fo-TA for submit@debbugs.gnu.org; Sun, 07 Nov 2021 07:03:20 -0500 Received: from sonic308-56.consmr.mail.ne1.yahoo.com ([66.163.187.31]:34648) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjgtI-0005FZ-PX for 51473@debbugs.gnu.org; Sun, 07 Nov 2021 07:03:18 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636286589; bh=QWc3YtcTH+0a2oOZxPrsPcjTpXnc1y9sme1Fu55L8zY=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=q6vzb3QBxDYyEA3oqdpTj+dPUCNieR/1TJjYu4elO9pv2Yv9x80azqUCDv5paXBxs8gfnry03ZjIHs+BIpZf9L4SA4MBApyy2DE5SHy7lIY//6vNhNd0Y6dEFR3cTZqBuPL0n5Q1gEpSNezitEosiIzdq3vrhs+XW3p6jyU6qZM7q2MoUtAXwVtY0BTlH1Y6XiT0eobRKnGbY2hQHFdnYT9nf6OMkz07e+PZKDoSqruvfE81UeOrn8WicptoXZKRD46dbMy0npa4zuxyKG0/QtctU/vKejXf78hfGfID/d2oTsHbQinOu/Bj7+j83lAqNNs6xyESZZYcFU6XgahzxQ== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636286589; bh=7QQ3On4V9RQIP1dmtUMy41koeV5HCosuEUHWOk4ZIXd=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=o9uwlOU9L47tvnKAfnk4N7uvgC7oEocoxNAJ4fICB7vklV0+iXOiTmLiGNYf7g2MXK+hf8Zypxl4nwZJiPSKbBq+jUXjU51np3xp7n41/g8K3Plqlsula2lSfFAU9u6A30WIVUUyIQ4VqzlvhUNp/Iw3N8ELed8hTWycEiAnWxBF0w6K9/4vzZ2JkARVnyRIF6tmJxsB0xaS9ng763ui7tJ/UqK2HUSlGN4g4P/elfjagr1AcBKhXAYQtsMKEul+1u40VtIXMyx8f+bGU6ZADHfxI3b4YZLlD0iCnpGd7mvMLLqN2dFQlp9uGMP2BxM12Ca4FFUfeJqaMSEPUeoznA== X-YMail-OSG: b6fxj_AVM1kSebMMJ0GzIaEC.DSJ.Yc2LuWwJYmXaOxld91Nbc1jdlDf8P.O_cE d2M3HCuw26jGzao.gXKDwg694XEzzoSmpucMUV9tkUtw1UywcTNMN_VIzIoGNqbZ7izhFemkLa.9 Y495RZgmJ3zpCDPQ5C.BkNcKhJheScl4FSUB5K8OqH1ebvMtWdZlGNFSpf5wTx2in4ASaRM44z3U VXqPjVd7fMxXB6hzwr9duxlQfMvVm3dGce2dKK2pDNjFMefvLvvBHHFiNccnj9g4tf4Swqpbpwpb tNWBFpGJuWCEFKVlcuUG_JjFTN07W.iI7UA_L44i_JFZEbiI4fKbLSzI4x.F4NHvCHQOUpFlQF_S ltSFCsu8H9U3eKrSJxvUjs2D9GoTZRVM0b1enxJG8LVfv4COB29aBQQEumelrI6m0JVZ.BCQk_ve mf4auUCadv8qAHp3FqOqRG6m8f9WmlZbgSBgpAJW4Zv1lQJEvB5MLG5q667rfuMPqHgDhZT41NAl c3r51.88vBUsCxMEmGyc8Phr60ClL0G.fAc.m5n1v2SRj9q46Le0NcnV8wlABxAM1CVZMacmnVta 9KE2MF1ktyT0oilVAIynECZaM57mASLtd7t0bh0rCHa5H5gvC9PmEr2bbfHisMGEPqo_siE3Ctez zm025YHtmq9S_hEty6gy8Q.YZA_Z.eWXj1U4R7QFmQ.09auvxYsTWqu1LxuetI2jsz9bl7NRPWpW fbwuMR7GxSX7En6dZZF53Tz8MXt9PpmswjCu6cBdHrfOHvaxHJsdYc3jEQrjmHyiq5nyyVMen1ha I.CNUnSoU4m4PnL4U4ymyBuKubNLPFb4u_NlNSyPq9GZaiiOfkuT7NuziQmwAusvqVCbOGBjvuNv VcOiE4mw_LexM0iPtP2RXfuv2.wEp3__tGmUQjlkRqMr8e6IKwfNI6l6On0skhcrCrq50I1jqBkN kd0F5KG83KWY1PRU9ufmLs.BejgjEgJG5wTE4TuHfoPPqnCCKXkfCxVhyeVLgpvuz.jsLRrd9Cc. DjcY3R9bFkN.MdxKFiPyJUebwCrp.pKOREAZHGGMW1y.5CnSGt1lLql3KvNlU_eofGqxUn4HSQV7 WD7U5UL3sPgx1iNaeMmnWqSBS12up8iClKecWnBcHKXHkoDkncyfSEgxdnJow77rb5dIXwOKU.82 igVtpEY_vIOmUNAcR0B.QrWxQgnSithb6KZRs5TOXKMj5qDsOhpQ6ck940T7HSX1b8I6omIT77qz 86smTuPwhjWSaEUmPaaDTArj.EHMThFKuEz389hqDD937H9ebZDJTKqJffq96F5XRPdkJVVGIzY2 4aNMYR.Q_L05LPxlmgpoCqNq8bU9Nd4R4ZXgTdMgwz2jvLb5RX3EqIZWHLnmBlpClDNlONtAkGCG 3738DK8RrxtLgHxJUXm0LpiC2jgcESpwGXE7ULdelywjn1zz3nSuSv3.kZCuxk2ulpJ5aCZ6BHou twp54rKMFBQt4wOqWFSSXdX_FM_olGXItwfyW4rbmyrqmGObOt8ZoL2uJ1iA_TCHKL2Cjy0jLVCY bU0nUvJNFQViSlVab7XbUBOPuwoeOG0EAYgi4ourHwNkWDz4293Hw9OlVnBhFr.ztC1on6HCslh7 IRZYgJjcWcVDjZpsgWzx7xr6Z3w1_UAdvx2huELMr9BJVJ78bo2gkzGLGWhAikwoHQTM0cz25_Sr h_zBo8oM1BmbBWvryts7CJJ2cuzDBVhbs4vvcQxPAEpLGV0BdMdZqZLqVCou13sHmAUCnavuJ0bV Bda5lrKg74aGDXbBpg9KNO3s8f2WQ8Sr3qSAWUnDRTaDRRdJFqb2Mw_cBowpSYoyvC74PqPb5F.1 i0PTve52Ykecc3LXIGMxskVBkaSLCBRxN_mx8tt2QEKw2iwQTAuZGwdPnxlgL0eCztiLi22hHl_y bptZA2xFGdlC1UZXO6O2zwEXBKjpMYZXv_lC2zt4jaZvwlNXNJuqLnr7TpiUjTIdhMAEUYc0LA_A Ujm03ax8jDvQpA2U9r0j4pdvSCq06RafzIYlxtYxjHsGtDrVfA4.FfIyYV4csBw0vqMNX56aNyvK qvfQ195sgCAEciaAd6q9Jqpil5jbXTrxmpFK7OFm8t8N3RaCMHu3VYYU6iA438f8xlIbWkvUKIHO 2nVFg8fGRdMFLZVmLAzUluuNBaIhHj6wwc1pxfFnco3pVTdtAQ0nA63DOsvjPbzNZGPZqh20DpLI qIdUVALPkTWKFRyh07KevOOVI0fKHzsma2PO.Ze1UcgMUA81gSlBUjLu5VeiOdA-- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic308.consmr.mail.ne1.yahoo.com with HTTP; Sun, 7 Nov 2021 12:03:09 +0000 Received: by kubenode508.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 7765b3aecc96f0fa06c891a2daf6564d; Sun, 07 Nov 2021 12:03:08 +0000 (UTC) From: Po Lu References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> <87o86xzhuw.fsf@yahoo.com> <87sfw9cha3.fsf@gnus.org> <878ry0ztjo.fsf@yahoo.com> <835yt49t1f.fsf@gnu.org> Date: Sun, 07 Nov 2021 20:03:04 +0800 In-Reply-To: <835yt49t1f.fsf@gnu.org> (Eli Zaretskii's message of "Sun, 07 Nov 2021 12:09:00 +0200") Message-ID: <87y260tbpj.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 2618 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Eli Zaretskii writes: > The printed representation of xwidget objects should be documented in > the ELisp manual, under the "Editing Types" section. In fact, we lack > a subsection there for xwidgets; it should be added. > > Thanks. Will this work? --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Document-the-xwidget-type.patch >From e90ed4c7d3e92ce6a3fd8d89b450c9b660ff2e08 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sun, 7 Nov 2021 20:02:06 +0800 Subject: [PATCH] Document the xwidget type * doc/lispref/elisp.texi: Add Xwidget Type to the menu. * doc/lispref/objects.texi (Editing Types): Add Xwidget Type to the menu. (Xwidget Type): New node. --- doc/lispref/elisp.texi | 1 + doc/lispref/objects.texi | 14 ++++++++++++++ 2 files changed, 15 insertions(+) diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi index d0bfd8c901..1c0b0fa1b5 100644 --- a/doc/lispref/elisp.texi +++ b/doc/lispref/elisp.texi @@ -365,6 +365,7 @@ Top * Keymap Type:: What function a keystroke invokes. * Overlay Type:: How an overlay is represented. * Font Type:: Fonts for displaying text. +* Xwidget Type:: Embeddable widgets. Numbers diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi index 0551bb5673..1c1f463af2 100644 --- a/doc/lispref/objects.texi +++ b/doc/lispref/objects.texi @@ -1535,6 +1535,7 @@ Editing Types * Keymap Type:: What function a keystroke invokes. * Overlay Type:: How an overlay is represented. * Font Type:: Fonts for displaying text. +* Xwidget Type:: Embeddable widgets. @end menu @node Buffer Type @@ -1860,6 +1861,19 @@ Font Type @samp{#} respectively. @xref{Low-Level Font}, for a description of these Lisp objects. +@node Xwidget Type +@subsection Xwidget Type + + An @dfn{xwidget} is a special display element, such as a web +browser, that can be embedded inside a buffer. Each window such an +xwidget is be displayed in will also have an xwidget view, which on +X-Windows corresponds to a single X window used to display the widget. + +Neither of these objects are readable; their print syntaxes look like +@samp{#} and @samp{#}, respectively. Lisp +programmers should not be interested in the functionality of xwidget +views. @xref{Xwidgets}, for a more detailed description of xwidgets. + @node Circular Objects @section Read Syntax for Circular Objects @cindex circular structure, read syntax -- 2.31.1 --=-=-=-- From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Eli Zaretskii Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 07 Nov 2021 12:34:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Po Lu Cc: larsi@gnus.org, 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163628842531384 (code B ref 51473); Sun, 07 Nov 2021 12:34:02 +0000 Received: (at 51473) by debbugs.gnu.org; 7 Nov 2021 12:33:45 +0000 Received: from localhost ([127.0.0.1]:51998 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjhMn-0008A8-2j for submit@debbugs.gnu.org; Sun, 07 Nov 2021 07:33:45 -0500 Received: from eggs.gnu.org ([209.51.188.92]:40946) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjhMi-00089r-EH for 51473@debbugs.gnu.org; Sun, 07 Nov 2021 07:33:43 -0500 Received: from fencepost.gnu.org ([2001:470:142:3::e]:43136) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mjhMc-0001zX-UH; Sun, 07 Nov 2021 07:33:34 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date: mime-version; bh=MU3iLU9VmlTe93AHlXKcbnNFPOmePdEimLPn7S8gR54=; b=E+b2IpW/v1M4 FlOuKtaUnr/RlSW0lmtE4zENyyqHcC9tF9QZ6fjh6W9AxCSC0UhCcONA+v6IGNPs33dbEvsx2F3Ft 18h6YqioqPoD7x+xQD7YlBPyqmVoaT9GcLASF+X3V4BAwineMFyIwSRHg19e5qvj/tioWf0OyW27Y zHN3SZWRv6dM6tiwlgmbUgpq917H6cAwmKtfB0uA1n6K3YXJVCkXg10kQb/nKDKVPFOGD3PuT6v77 p2opCripen6ohn9586cP44Nh2JorwHtvjdVrJsOgwKrNRNhIca+2eBp0TRrUv6oCBah38JGd76Qyn OV5ZKYKYy7raxO8TZWtjPg==; Received: from [87.69.77.57] (port=4756 helo=home-c4e4a596f7) by fencepost.gnu.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mjhMc-0007oY-BP; Sun, 07 Nov 2021 07:33:34 -0500 Date: Sun, 07 Nov 2021 14:33:21 +0200 Message-Id: <83y26087se.fsf@gnu.org> From: Eli Zaretskii In-Reply-To: <87y260tbpj.fsf@yahoo.com> (message from Po Lu on Sun, 07 Nov 2021 20:03:04 +0800) References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> <87o86xzhuw.fsf@yahoo.com> <87sfw9cha3.fsf@gnus.org> <878ry0ztjo.fsf@yahoo.com> <835yt49t1f.fsf@gnu.org> <87y260tbpj.fsf@yahoo.com> X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > From: Po Lu > Cc: larsi@gnus.org, 51473@debbugs.gnu.org > Date: Sun, 07 Nov 2021 20:03:04 +0800 > > > The printed representation of xwidget objects should be documented in > > the ELisp manual, under the "Editing Types" section. In fact, we lack > > a subsection there for xwidgets; it should be added. > > > > Thanks. > > Will this work? With some minor changes, yes. > +@node Xwidget Type > +@subsection Xwidget Type It is generally a good idea to have a @cindex entry with the name of the section (but with lower-case letters), so that the section could be easily found via Info-index. > + Each window such an > +xwidget is be displayed in This style is better avoided: it produces long sentences that are hard to grasp for non-native speakers, because the important part ("in") is at the end. It is better to say it simply: Each window that displays an xwidget will also have a @dfn{xwidget view}, ... And add a @cindex for "xwidget-view", again generally a good practice of indexing each place that introduces new terminology (indicated by @dfn). > , which on > +X-Windows corresponds to a single X window used to display the widget. What about NS? And what about Wayland? > +Neither of these objects are readable; their print syntaxes look like > +@samp{#} and @samp{#}, respectively. Lisp > +programmers should not be interested in the functionality of xwidget > +views. I'd drop the second of these sentences. It doesn't add anything to the description. Thanks. From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Po Lu Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 07 Nov 2021 12:42:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Eli Zaretskii Cc: larsi@gnus.org, 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.163628887132062 (code B ref 51473); Sun, 07 Nov 2021 12:42:02 +0000 Received: (at 51473) by debbugs.gnu.org; 7 Nov 2021 12:41:11 +0000 Received: from localhost ([127.0.0.1]:52003 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjhTx-0008L3-Tu for submit@debbugs.gnu.org; Sun, 07 Nov 2021 07:41:10 -0500 Received: from sonic309-20.consmr.mail.ne1.yahoo.com ([66.163.184.146]:43982) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjhTs-0008KP-S9 for 51473@debbugs.gnu.org; Sun, 07 Nov 2021 07:41:08 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636288859; bh=DS5auoJMubsT71d1Qvczv19QvYK95z2IQ8AV14P42Sc=; h=From:To:Cc:Subject:References:Date:In-Reply-To:From:Subject:Reply-To; b=or3YFOS6ykGRX43lBt9Ogsh+WMfdw+7DE2OwWhKSrE5IDZk9wKZ5XS6/hLTB8X0y2sEAtt99/apwAmQ+AU+/ReWlQhyAwpfPFZhS1j9YavqIq9PVNpTrnMoJjjtqm1FHLuiSn8Wh+t1Kubx17+flYVklTtruVAmSHQree7zEROghCh0Fx6xaVxqTiFlb44PLmFZvVEFvPMIIeHFx/XqJzih2JmzIJ0G5lW98EeZ3/B7yoYuk9XnnPPIhKPgyDkg1I/wvGwuIBi2T3XUzsCAaxfZdY0w1mLkFAPdvWvge17XCIsK8kNKUOOeD5n3Y6GrE3lUZ8Aar94rKHI84UpMWLQ== X-SONIC-DKIM-SIGN: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1636288859; bh=0IMCtmRcpPJVx5snYhxkFUoAwSfAGTw683Lo/tTzo3R=; h=X-Sonic-MF:From:To:Subject:Date:From:Subject; b=WxonXENryVkMFJg9OgXjznrQlhVYhvrg4UpPZRbT9zpMW9GrGFZlr1XGNjCk0lhLpWA5+BEJ/TrnoJQT5Z64Q26lec+Zrt8eIGPoQlqRJLkf8yOaUgzcdMYv6k8+C1cUgU1bDADlpWj3Gl+uvzPiyrG7DEXkYfjO+hnan942HlQIl1lq9v+D40Jp9qUaxR1GXBNLMsdCUbqCxWQNEKuVqhU5MdD20x0GxwGCJMlgd4d8otFGU4SdbCzgBQG16KlVYkrTxzrzt9aWo8t4ZDDNuElb72K+j6BamcFklPLcYnyQwSgBhCtNC0fcgii5n8wNAAIa06AXUdbsi1WWd1Ml9g== X-YMail-OSG: h9dfRScVM1meEIzRGdYA6U_o5PtqJaii.NmBTGQnV4drNqejkHIk4Vp3.TmYwKG pmrHzZYMo8qvilmxJ75cuoG6wbH38CEmJjb.g5Qn.RoUvErNqaSyccUwcv8Uv8TezN1MCY272pwO u_FjnLzlCT34t_YojJOA2P4THrJob5oTYV3tYl7z7NAWXTrxxKlXa6_pjpzlhweAFvSRTM.4ERXN ir4ZOV8uAbqChHrV6BG6JySM_WKA.cCkutpAILH.iwI.KH2qCgsVOYaqphrNMFLZb2BorukIhCp8 7DaWW_beiKS1JWlOw0u_LdCKaNXIslOmoTxbRx1uCmELxSlYbsx.elGBwcA0PvxeKUggDw0Yleyy Cv9MqDlPS3mT95dyB6.tgGRt9MTzdBiZcmxInNMdSsSXFNDhgZ28PxFQXcgs8FmyjiSCYFe8lVjd 9jtUz.dxcvb777Ba7z8yxRIj8dpTo82tzfnd3HODcrMXPQJRFg511fOT7COG0L36QXxfCnNZydXt pYDETAOlIMtpAoC5xoCy4pvS2XKl2deSKOX4cTd9qe4xzbYAmoYRFl0q.aO2INiFODxeLPAeAp9t v9crMczWVtaBySGtnMoaivK0NROPaQc6N5sre6EpQ3Mks5ygs294t5gK0Nf05WoqQcRIo.bBcnf1 9cLsMUheys37XdH2eQPXsVoUk4kLf5ugZZzRGh5nf61nR5agm7rVLnnuf9ocGOYDIAoM9Di6y3D8 hy77K6fC7OXafp1axZVHtIylh4FYd12nymQhcF9vZfSA4uidZR1WjZLkZgVq9BN9_aZ2zXL6Yg3O AwwoR2wqnHSCVIF2lL5n9HwiuSo3zLa_gkTeTJIwp4Di.Hpx13JgHGUPi5UimZkex.VzmObk378b RpUAtijK53etKXEK.iqt6Md9xPLDTOLmCUPSlOZi4t3U1lRXt1p8LqqCeEe4csIUXO.QIocAv7fm HhOZJimZEDINU2.TQ6RGisWnhAZhRludXHeinPAiWFX5VF1N1k2JLn_mC1q27JpWrdIOysb03Pti uFIRHrYGxUjHmXCx.E_7FMBu6GgyWHR7GFTUAxwMN_kKXMba6G9eQVg0htUS3cQW33TTmid4v1w5 RUe76HFvay2_NeelY87PtvXisDKjkLuClbLb2khc4UtnqFiqH7n6m9u1eqwu1PW78BPAVIez8xch HVcZduugHMtF7Zzw.NYBPCFu2_4zY7X_MYxtNowX8wnKBheKDqTUEX294UZCOfTGXJCTg8b.6A.7 DUH2PBFWFHUTcZ3g8vHo2WTDMLqb2JjV8yqExmz9sHMV8DYE4VPpywGGV0WjKZ4b42Seu0qssvr5 8PSQQ51wzT9hTDcIHckfI33iLNoNUCEqN4YnStxj5NoPN.ITYMq64Fr9B5DsDv3thTZXrLkK9b1g bGPTHKLVJTrUnnC6rAAhFxc_57RjcnpOpElCBORRhQgMjEF6tJwTbb3UL1dEZYuaaurbNX7IqQ.T CedfXQa1MF_ocsdFfZ5PLG9GLvJF5lhN8hGSwkYgy.cvcjvQQWy6jeGYqeV34Bp8XFBI1R.brZjb VpZzFHcfKBjy.12laW97GuQawQqJeUAGryrHUu9LfK3wnY9MAqmMCSYbdqko2hyoQSuMN0Mcq._z GbTYsExRvb2DhUKzRDwDzEDV0Wwn.QmPVUXWk45LLqKkquH3jigsc7a5sPEzw7w8c3Ts0lEydQYw Z5R1m1d9e1vQOUYUmp1DfQnlBpVCc0uKWVJe7dby6FDmlFn_g_HBqlOpz_G9.w1lNJYJx3VeEhH4 B2.qHn1_x1AlAH0NxTccu85omQ9Exg11sqhMJfzxAwa.j_T6TCA646MOZd0d9Bmw8tnQ_K6r3Qc_ 2M5VhyLgxQVzYXG8McgmrSxFV8.zrOV.mPPnjHiJDqZO7UY6evddasHbB5LXp3xAXMs8GNW77XpZ 96IC8EwcFgsbUfyjo4ulCA3hqs1ZF45HWo_Gh52igRIEfNc8Mz61CHV_sg4xtqAan6P8vgrxhwnE cg32As0_cujj_.qNrShpK7IeYB.lQWb2J7FEeoYD.bNRoGfKN_0vap4kJs1Qtvc68kIQhkSZM9yc .jMDEG45haQ4ndaj0gUV__jz3J.2B8wgI0z2PGBfAPURNC_lL1_3wAVzhH9XVdZxBGoXFwKxRZ7k dzffN9D7QaiP5duqMIlqm9.ne.Y3NMsQ4TKUe0fmE0pYg4jrNDDBZQIRWaXWcfSVnBaNpfT0n.pS XHcVmKFqLB4VL.oOZ7GA7jPhO3KOaSCerSVXl0DyNTAn3yxL_qBXkTOamVRKDRg-- X-Sonic-MF: Received: from sonic.gate.mail.ne1.yahoo.com by sonic309.consmr.mail.ne1.yahoo.com with HTTP; Sun, 7 Nov 2021 12:40:59 +0000 Received: by kubenode514.mail-prod1.omega.sg3.yahoo.com (VZM Hermes SMTP Server) with ESMTPA ID 48040b70dc320e48237610dca4865fb4; Sun, 07 Nov 2021 12:40:55 +0000 (UTC) From: Po Lu References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> <87o86xzhuw.fsf@yahoo.com> <87sfw9cha3.fsf@gnus.org> <878ry0ztjo.fsf@yahoo.com> <835yt49t1f.fsf@gnu.org> <87y260tbpj.fsf@yahoo.com> <83y26087se.fsf@gnu.org> Date: Sun, 07 Nov 2021 20:40:49 +0800 In-Reply-To: <83y26087se.fsf@gnu.org> (Eli Zaretskii's message of "Sun, 07 Nov 2021 14:33:21 +0200") Message-ID: <87lf20t9ym.fsf@yahoo.com> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-Mailer: WebService/1.1.19266 mail.backend.jedi.jws.acl:role.jedi.acl.token.atz.jws.hermes.yahoo Content-Length: 3359 X-Spam-Score: 0.0 (/) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -1.0 (-) --=-=-= Content-Type: text/plain Eli Zaretskii writes: > It is generally a good idea to have a @cindex entry with the name of > the section (but with lower-case letters), so that the section could > be easily found via Info-index. Thanks, done. > This style is better avoided: it produces long sentences that are hard > to grasp for non-native speakers, because the important part ("in") is > at the end. It is better to say it simply: > > Each window that displays an xwidget will also have a @dfn{xwidget > view}, ... > > And add a @cindex for "xwidget-view", again generally a good practice > of indexing each place that introduces new terminology (indicated by > @dfn). Likewise. > What about NS? And what about Wayland? I don't know exactly how it is handled on NS. On Wayland, it's still an X window that runs through Wayland's compatibility layer for X applications. (Like the rest of Emacs, at present.) > I'd drop the second of these sentences. It doesn't add anything to > the description. Done as well, please check the attached patch. --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=0001-Document-the-xwidget-type.patch >From 728f07e20bfb8e16182ef7dae816e3512665d64b Mon Sep 17 00:00:00 2001 From: Po Lu Date: Sun, 7 Nov 2021 20:02:06 +0800 Subject: [PATCH] Document the xwidget type * doc/lispref/elisp.texi: Add Xwidget Type to the menu. * doc/lispref/objects.texi (Editing Types): Add Xwidget Type to the menu. (Xwidget Type): New node. --- doc/lispref/elisp.texi | 1 + doc/lispref/objects.texi | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi index d0bfd8c901..1c0b0fa1b5 100644 --- a/doc/lispref/elisp.texi +++ b/doc/lispref/elisp.texi @@ -365,6 +365,7 @@ Top * Keymap Type:: What function a keystroke invokes. * Overlay Type:: How an overlay is represented. * Font Type:: Fonts for displaying text. +* Xwidget Type:: Embeddable widgets. Numbers diff --git a/doc/lispref/objects.texi b/doc/lispref/objects.texi index 0551bb5673..bbd3973f61 100644 --- a/doc/lispref/objects.texi +++ b/doc/lispref/objects.texi @@ -1535,6 +1535,7 @@ Editing Types * Keymap Type:: What function a keystroke invokes. * Overlay Type:: How an overlay is represented. * Font Type:: Fonts for displaying text. +* Xwidget Type:: Embeddable widgets. @end menu @node Buffer Type @@ -1860,6 +1861,20 @@ Font Type @samp{#} respectively. @xref{Low-Level Font}, for a description of these Lisp objects. +@node Xwidget Type +@subsection Xwidget Type +@cindex xwidget type +@cindex xwidget-view type + + An @dfn{xwidget} is a special display element, such as a web +browser, that can be embedded inside a buffer. Each window that +displays an xwidget will also have an @dfn{xwidget view}, which on +X-Windows corresponds to a single X window used to display the widget. + +Neither of these objects are readable; their print syntaxes look like +@samp{#} and @samp{#}, respectively. +@xref{Xwidgets}, for a more detailed description of xwidgets. + @node Circular Objects @section Read Syntax for Circular Objects @cindex circular structure, read syntax -- 2.31.1 --=-=-=-- From unknown Sun Aug 10 16:48:25 2025 X-Loop: help-debbugs@gnu.org Subject: bug#51473: [PATCH] Enable xwidget scrolling optimizations, and other xwidgets improvements Resent-From: Eli Zaretskii Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 07 Nov 2021 12:54:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 51473 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: patch To: Po Lu Cc: larsi@gnus.org, 51473@debbugs.gnu.org Received: via spool by 51473-submit@debbugs.gnu.org id=B51473.1636289585921 (code B ref 51473); Sun, 07 Nov 2021 12:54:01 +0000 Received: (at 51473) by debbugs.gnu.org; 7 Nov 2021 12:53:05 +0000 Received: from localhost ([127.0.0.1]:52019 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjhfV-0000En-EF for submit@debbugs.gnu.org; Sun, 07 Nov 2021 07:53:05 -0500 Received: from eggs.gnu.org ([209.51.188.92]:44182) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1mjhfS-0000EG-3j for 51473@debbugs.gnu.org; Sun, 07 Nov 2021 07:53:03 -0500 Received: from fencepost.gnu.org ([2001:470:142:3::e]:43454) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mjhfM-0002o6-Fp; Sun, 07 Nov 2021 07:52:56 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=gnu.org; s=fencepost-gnu-org; h=References:Subject:In-Reply-To:To:From:Date: mime-version; bh=Dp956w1taep/1E5ErMdk9nZDnvnTubtIcWnRlGbgTUQ=; b=U0tl+hoJ4g1q +XgrkfoTdOKvFYCadPdSG7m9qQl6Py1bleNrazASmKK1C0fIKrdP9f9omoCEsC82TWRVFXkrlc0R4 z738GVuQneDZ+8ECzF6Q+gcfk2ejHlHtLgiBhgFbaM56vqXRj9ZWhgck/yeQx3yec8YQk7tIDhLZp Jc37dIULLdAdvh2HzWa/itnykmeF+/JJ2Y8Q8aQTKazl5bgcm6PSY6A3FKKPdEEQh4/TYSc4GG4Jx Fxbe+CzeO3mZXYLiUbnb46EROjLt7q4yl5OLe0XuDR/dIZMi/YLap3WLLY979GnOWBIvc680oCqDn 4keLJXEktz+fJtWDXauR6Q==; Received: from [87.69.77.57] (port=1966 helo=home-c4e4a596f7) by fencepost.gnu.org with esmtpsa (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mjhfL-0007jM-Vi; Sun, 07 Nov 2021 07:52:56 -0500 Date: Sun, 07 Nov 2021 14:52:43 +0200 Message-Id: <83v91486w4.fsf@gnu.org> From: Eli Zaretskii In-Reply-To: <87lf20t9ym.fsf@yahoo.com> (message from Po Lu on Sun, 07 Nov 2021 20:40:49 +0800) References: <87zgqslafe.fsf.ref@yahoo.com> <87zgqslafe.fsf@yahoo.com> <875yt7plc1.fsf@gnus.org> <87mtmj9hts.fsf@yahoo.com> <87cznelojs.fsf@gnus.org> <87fssa90vv.fsf@yahoo.com> <87r1buk92k.fsf@gnus.org> <8735oa876a.fsf@yahoo.com> <87wnlmdtag.fsf@gnus.org> <87v9156dwp.fsf@yahoo.com> <83pmrdbqz2.fsf@gnu.org> <87o86xzhuw.fsf@yahoo.com> <87sfw9cha3.fsf@gnus.org> <878ry0ztjo.fsf@yahoo.com> <835yt49t1f.fsf@gnu.org> <87y260tbpj.fsf@yahoo.com> <83y26087se.fsf@gnu.org> <87lf20t9ym.fsf@yahoo.com> X-Spam-Score: -2.3 (--) X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: debbugs-submit-bounces@debbugs.gnu.org Sender: "Debbugs-submit" X-Spam-Score: -3.3 (---) > From: Po Lu > Cc: larsi@gnus.org, 51473@debbugs.gnu.org > Date: Sun, 07 Nov 2021 20:40:49 +0800 > > Done as well, please check the attached patch. Thanks, installed.