]> git.eshelyaron.com Git - emacs.git/commitdiff
Make the WebKit inspector available
authorPo Lu <luangruo@yahoo.com>
Fri, 5 Nov 2021 13:01:12 +0000 (21:01 +0800)
committerLars Ingebrigtsen <larsi@gnus.org>
Sun, 7 Nov 2021 01:59:41 +0000 (02:59 +0100)
* etc/NEWS: Document changes.
* src/xwidget.c (find_widget_at_pos)
(find_widget)
(find_widget_cb): New functions.
(struct widget_search_data): New structure.
(Fmake_xwidget): Enable web inspector for WebKit widgets.
(Fxwidget_perform_lispy_event): Use current focus instead of
hard-coded widget.
(xwidget_button_1, xwidget_button, xwidget_motion_or_crossing):
Use window at event position instead of the default widget.

etc/NEWS
src/xwidget.c

index 6654e54552fac5cf2d60f2c438811a3a0b2a1d39..a64312f7fa321bef6448aa33cd3c9d7719084a83 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -497,11 +497,17 @@ This is a convenience function to extract the field data from
 
 ** 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.
 
+---
+*** On X11, the WebKit inspector is now available inside xwidgets.
+To access the inspector, right click on the widget and select "Inspect
+Element".
+
 \f
 * New Modes and Packages in Emacs 29.1
 
index 41e4accb1a71ef8bab02d3559efaa63786e05fd8..49645b8b6fd3a99677e5042aef6dfa127352fd04 100644 (file)
@@ -82,6 +82,18 @@ 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 *);
 #endif
 
 
@@ -130,6 +142,7 @@ Returns the newly constructed xwidget, or nil if construction fails.  */)
   if (EQ (xw->type, Qwebkit))
     {
       block_input ();
+      WebKitSettings *settings;
       WebKitWebContext *webkit_context = webkit_web_context_get_default ();
 
 # if WEBKIT_CHECK_VERSION (2, 26, 0)
@@ -145,6 +158,10 @@ Returns the newly constructed xwidget, or nil if construction fails.  */)
         {
           xw->widget_osr = webkit_web_view_new ();
 
+         /* 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);
+
           /* 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
@@ -251,9 +268,12 @@ X-Windows frame.  */)
   else if (FRAME_X_P (SELECTED_FRAME ()))
     f = SELECTED_FRAME ();
 
-  widget = xw->widget_osr;
-
 #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);
@@ -324,7 +344,7 @@ X-Windows frame.  */)
   if (keycode > -1)
     {
       /* WebKitGTK internals abuse follows.  */
-      if (EQ (xw->type, Qwebkit))
+      if (WEBKIT_IS_WEB_VIEW (widget))
        {
          /* WebKitGTK relies on an internal GtkTextView object to
             "translate" keys such as backspace.  We must find that
@@ -427,6 +447,131 @@ find_suitable_keyboard (struct frame *f)
   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 void
 xwidget_button_1 (struct xwidget_view *view,
                  bool down_p, int x, int y, int button,
@@ -434,12 +579,18 @@ xwidget_button_1 (struct xwidget_view *view,
 {
   GdkEvent *xg_event = gdk_event_new (down_p ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE);
   struct xwidget *model = XXWIDGET (view->model);
+  GtkWidget *target;
 
   /* X and Y should be relative to the origin of view->wdesc.  */
   x += view->clip_left;
   y += view->clip_top;
 
-  xg_event->any.window = gtk_widget_get_window (model->widget_osr);
+  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. */
 
@@ -467,8 +618,17 @@ xwidget_button (struct xwidget_view *view,
     {
       GdkEvent *xg_event = gdk_event_new (GDK_SCROLL);
       struct xwidget *model = XXWIDGET (view->model);
+      GtkWidget *target;
+
+      x += view->clip_left;
+      y += view->clip_top;
 
-      xg_event->any.window = gtk_widget_get_window (model->widget_osr);
+      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)
@@ -504,15 +664,28 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
                                      (event->type == LeaveNotify ? GDK_LEAVE_NOTIFY :
                                       GDK_ENTER_NOTIFY));
   struct xwidget *model = XXWIDGET (view->model);
-
-  xg_event->any.window = gtk_widget_get_window (model->widget_osr);
+  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 = event->xmotion.x + view->clip_left;
-      xg_event->motion.y = event->xmotion.y + view->clip_top;
+      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;
@@ -523,8 +696,8 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
     {
       xg_event->crossing.detail = min (5, event->xcrossing.detail);
       xg_event->crossing.time = event->xcrossing.time;
-      xg_event->crossing.x = event->xcrossing.x + view->clip_left;
-      xg_event->crossing.y = event->xcrossing.y + view->clip_top;
+      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));