emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 5c387ad 02/35: Enable scrolling optimization for xwidgets


From: Lars Ingebrigtsen
Subject: master 5c387ad 02/35: Enable scrolling optimization for xwidgets
Date: Sat, 6 Nov 2021 22:01:54 -0400 (EDT)

branch: master
commit 5c387ad437872c6e95599710ba5dcdfaa470c5ea
Author: Po Lu <luangruo@yahoo.com>
Commit: Lars Ingebrigtsen <larsi@gnus.org>

    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 5b28fe7..f17f095 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -536,8 +536,8 @@ struct glyph
     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 4a73244..632eec2 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/xdisp.c b/src/xdisp.c
index 86c4e70..d7ad548 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 54bfb65..b12c15c 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 62b30a0..68188eb 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -41,6 +41,9 @@ along with GNU Emacs.  If not, see 
<https://www.gnu.org/licenses/>.  */
 #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 @@ Returns the newly constructed xwidget, or nil if 
construction fails.  */)
   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 fc68b52..28098c0 100644
--- a/src/xwidget.h
+++ b/src/xwidget.h
@@ -60,6 +60,7 @@ struct xwidget
 
   int height;
   int width;
+  uint32_t xwidget_id;
 
 #if defined (USE_GTK)
   /* For offscreen widgets, unused if not osr.  */
@@ -168,6 +169,8 @@ void store_xwidget_js_callback_event (struct xwidget *xw,
                                       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) {}



reply via email to

[Prev in Thread] Current Thread [Next in Thread]