]> git.eshelyaron.com Git - emacs.git/commitdiff
Enable scrolling optimization for xwidgets
authorPo Lu <luangruo@yahoo.com>
Fri, 29 Oct 2021 03:33:06 +0000 (11:33 +0800)
committerLars Ingebrigtsen <larsi@gnus.org>
Sun, 7 Nov 2021 01:59:39 +0000 (02:59 +0100)
* 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
src/dispnew.c
src/xdisp.c
src/xterm.c
src/xwidget.c
src/xwidget.h

index 5b28fe76664141f35f37a35b173e74a6081b5925..f17f095e0d344734bc8d78c82ac893cd3abc3f8f 100644 (file)
@@ -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.  */
index 4a73244c8966614deaa466a0be7dca37c285924f..632eec2f031a01733691a0eb9512bc7a30037c35 100644 (file)
@@ -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.  */
index 86c4e704d526401ccad2b9d6c9a86aa92f0c08de..d7ad5489171f7e252890dad561b75b58bf822a4d 100644 (file)
@@ -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)
            {
index 54bfb65bd0e750b550ffdb39fcceeac890bd312a..b12c15cb7a3b3f21b720cc8d79598302f26c1294 100644 (file)
@@ -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))
     {
index 62b30a07ab0bc374c6605e7cde0f019f8df0fa79..68188eba08ccf30915f18ff5164c1334e7d53a2e 100644 (file)
@@ -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)
           {
index fc68b52cdb54c658c805a97d19a77f64f3ecdf93..28098c0b09f930453ee8b708690bb904a88640a1 100644 (file)
@@ -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) {}