root/src/xwidget.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. allocate_xwidget
  2. allocate_xwidget_view
  3. xw_forward_event_translate
  4. xw_forward_event_from_view
  5. xw_translate_x_modifiers
  6. DEFUN
  7. set_widget_if_text_view
  8. DEFUN
  9. xwidget_hidden
  10. xwidget_from_id
  11. pick_embedded_child
  12. record_osr_embedder
  13. find_xwidget_for_offscreen_window
  14. from_embedder
  15. to_embedder
  16. find_suitable_pointer
  17. find_suitable_keyboard
  18. find_widget_cb
  19. find_widget
  20. find_widget_at_pos
  21. cursor_for_hit
  22. define_cursors
  23. mouse_target_changed
  24. run_file_chooser_cb
  25. xv_drag_begin_cb
  26. xwidget_button_1
  27. xwidget_button
  28. xwidget_motion_notify
  29. xwidget_scroll
  30. xwidget_pinch
  31. xi_translate_notify_detail
  32. window_coords_from_toplevel
  33. xw_find_common_ancestor
  34. xw_notify_virtual_upwards_until
  35. xw_notify_virtual_downwards_until
  36. xw_update_cursor_for_view
  37. xw_last_crossing_cursor_cb
  38. xw_maybe_synthesize_crossing
  39. xwidget_motion_or_crossing
  40. synthesize_focus_in_event
  41. xwidget_view_from_window
  42. xwidget_show_view
  43. xwidget_hide_view
  44. xv_do_draw
  45. xwidget_view_draw_cb
  46. offscreen_damage_event
  47. xwidget_expose
  48. store_xwidget_event_string
  49. store_xwidget_download_callback_event
  50. store_xwidget_js_callback_event
  51. store_xwidget_display_event
  52. webkit_ready_to_show
  53. webkit_create_cb_1
  54. webkit_create_cb
  55. webkit_view_load_changed_cb
  56. webkit_js_to_lisp
  57. webkit_javascript_finished_cb
  58. webkit_download_cb
  59. webkit_decide_policy_cb
  60. webkit_script_dialog_cb
  61. xwidget_init_view
  62. x_draw_xwidget_glyph_string
  63. DEFUN
  64. DEFUN
  65. DEFUN
  66. save_script_callback
  67. DEFUN
  68. DEFUN
  69. DEFUN
  70. DEFUN
  71. DEFUN
  72. DEFUN
  73. DEFUN
  74. DEFUN
  75. DEFUN
  76. DEFUN
  77. DEFUN
  78. DEFUN
  79. DEFUN
  80. DEFUN
  81. DEFUN
  82. DEFUN
  83. syms_of_xwidget
  84. valid_xwidget_spec_p
  85. xwidget_spec_value
  86. xwidget_view_delete_all_in_window
  87. xwidget_view_lookup
  88. lookup_xwidget
  89. xwidget_start_redisplay
  90. xwidget_touch
  91. xwidget_touched
  92. xwidget_end_redisplay
  93. lower_frame_xwidget_views
  94. kill_frame_xwidget_views
  95. kill_xwidget
  96. kill_buffer_xwidgets

     1 /* Support for embedding graphical components in a buffer.
     2 
     3 Copyright (C) 2011-2023 Free Software Foundation, Inc.
     4 
     5 This file is part of GNU Emacs.
     6 
     7 GNU Emacs is free software: you can redistribute it and/or modify
     8 it under the terms of the GNU General Public License as published by
     9 the Free Software Foundation, either version 3 of the License, or (at
    10 your option) any later version.
    11 
    12 GNU Emacs is distributed in the hope that it will be useful,
    13 but WITHOUT ANY WARRANTY; without even the implied warranty of
    14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15 GNU General Public License for more details.
    16 
    17 You should have received a copy of the GNU General Public License
    18 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    19 
    20 #include <config.h>
    21 
    22 #include "buffer.h"
    23 #include "coding.h"
    24 #include "xwidget.h"
    25 
    26 #include "lisp.h"
    27 #include "blockinput.h"
    28 #include "dispextern.h"
    29 #include "frame.h"
    30 #include "keyboard.h"
    31 #include "gtkutil.h"
    32 #include "sysstdio.h"
    33 #include "termhooks.h"
    34 #include "window.h"
    35 #include "process.h"
    36 
    37 /* Include xwidget bottom end headers.  */
    38 #ifdef USE_GTK
    39 #include <webkit2/webkit2.h>
    40 #include <JavaScriptCore/JavaScript.h>
    41 #include <cairo.h>
    42 #ifndef HAVE_PGTK
    43 #include <cairo-xlib.h>
    44 #include <X11/Xlib.h>
    45 #else
    46 #include <gtk/gtk.h>
    47 #endif
    48 #ifdef HAVE_XINPUT2
    49 #include <X11/extensions/XInput2.h>
    50 #endif
    51 #elif defined NS_IMPL_COCOA
    52 #include "nsxwidget.h"
    53 #endif
    54 
    55 #include <math.h>
    56 
    57 static Lisp_Object id_to_xwidget_map;
    58 static Lisp_Object internal_xwidget_view_list;
    59 static Lisp_Object internal_xwidget_list;
    60 static uint32_t xwidget_counter = 0;
    61 
    62 #ifdef USE_GTK
    63 #ifdef HAVE_X_WINDOWS
    64 static Lisp_Object x_window_to_xwv_map;
    65 #if WEBKIT_CHECK_VERSION (2, 34, 0)
    66 static Lisp_Object dummy_tooltip_string;
    67 #endif
    68 #endif
    69 static gboolean offscreen_damage_event (GtkWidget *, GdkEvent *, gpointer);
    70 static void synthesize_focus_in_event (GtkWidget *);
    71 static GdkDevice *find_suitable_keyboard (struct frame *);
    72 static gboolean webkit_script_dialog_cb (WebKitWebView *, WebKitScriptDialog *,
    73                                          gpointer);
    74 static void record_osr_embedder (struct xwidget_view *);
    75 static void from_embedder (GdkWindow *, double, double, gpointer, gpointer, gpointer);
    76 static void to_embedder (GdkWindow *, double, double, gpointer, gpointer, gpointer);
    77 static GdkWindow *pick_embedded_child (GdkWindow *, double, double, gpointer);
    78 #endif
    79 
    80 static struct xwidget *
    81 allocate_xwidget (void)
    82 {
    83   return ALLOCATE_PSEUDOVECTOR (struct xwidget, script_callbacks, PVEC_XWIDGET);
    84 }
    85 
    86 static struct xwidget_view *
    87 allocate_xwidget_view (void)
    88 {
    89   return ALLOCATE_PSEUDOVECTOR (struct xwidget_view, w, PVEC_XWIDGET_VIEW);
    90 }
    91 
    92 #define XSETXWIDGET(a, b) XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET)
    93 #define XSETXWIDGET_VIEW(a, b) XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW)
    94 
    95 static struct xwidget_view *xwidget_view_lookup (struct xwidget *,
    96                                                  struct window *);
    97 static void kill_xwidget (struct xwidget *);
    98 
    99 #ifdef USE_GTK
   100 static void webkit_view_load_changed_cb (WebKitWebView *,
   101                                          WebKitLoadEvent,
   102                                          gpointer);
   103 static void webkit_javascript_finished_cb (GObject *,
   104                                            GAsyncResult *,
   105                                            gpointer);
   106 static gboolean webkit_download_cb (WebKitWebContext *, WebKitDownload *, gpointer);
   107 static GtkWidget *webkit_create_cb (WebKitWebView *, WebKitNavigationAction *, gpointer);
   108 static gboolean
   109 webkit_decide_policy_cb (WebKitWebView *,
   110                          WebKitPolicyDecision *,
   111                          WebKitPolicyDecisionType,
   112                          gpointer);
   113 static GtkWidget *find_widget_at_pos (GtkWidget *, int, int, int *, int *, bool,
   114                                       struct xwidget_view *);
   115 static gboolean run_file_chooser_cb (WebKitWebView *,
   116                                      WebKitFileChooserRequest *,
   117                                      gpointer);
   118 
   119 struct widget_search_data
   120 {
   121   int x;
   122   int y;
   123   bool foundp;
   124   bool first;
   125   GtkWidget *data;
   126 };
   127 
   128 static void find_widget (GtkWidget *t, struct widget_search_data *);
   129 #endif
   130 
   131 #ifdef HAVE_PGTK
   132 static void mouse_target_changed (WebKitWebView *, WebKitHitTestResult *, guint,
   133                                   gpointer);
   134 
   135 static int
   136 xw_forward_event_translate (GdkEvent *event, struct xwidget_view *xv,
   137                             struct xwidget *xw)
   138 {
   139   GtkWidget *widget;
   140   int new_x, new_y;
   141 
   142   switch (event->type)
   143     {
   144     case GDK_BUTTON_PRESS:
   145     case GDK_BUTTON_RELEASE:
   146     case GDK_2BUTTON_PRESS:
   147     case GDK_3BUTTON_PRESS:
   148       widget = find_widget_at_pos (xw->widgetwindow_osr,
   149                                    lrint (event->button.x - xv->clip_left),
   150                                    lrint (event->button.y - xv->clip_top),
   151                                    &new_x, &new_y, false, NULL);
   152       if (widget)
   153         {
   154           event->any.window = gtk_widget_get_window (widget);
   155           event->button.x = new_x;
   156           event->button.y = new_y;
   157           return 1;
   158         }
   159       return 0;
   160     case GDK_SCROLL:
   161       widget = find_widget_at_pos (xw->widgetwindow_osr,
   162                                    lrint (event->scroll.x - xv->clip_left),
   163                                    lrint (event->scroll.y - xv->clip_top),
   164                                    &new_x, &new_y, false, NULL);
   165       if (widget)
   166         {
   167           event->any.window = gtk_widget_get_window (widget);
   168           event->scroll.x = new_x;
   169           event->scroll.y = new_y;
   170           return 1;
   171         }
   172       return 0;
   173     case GDK_MOTION_NOTIFY:
   174       widget = find_widget_at_pos (xw->widgetwindow_osr,
   175                                    lrint (event->motion.x - xv->clip_left),
   176                                    lrint (event->motion.y - xv->clip_top),
   177                                    &new_x, &new_y, false, NULL);
   178       if (widget)
   179         {
   180           event->any.window = gtk_widget_get_window (widget);
   181           event->motion.x = new_x;
   182           event->motion.y = new_y;
   183           return 1;
   184         }
   185       return 0;
   186     case GDK_ENTER_NOTIFY:
   187     case GDK_LEAVE_NOTIFY:
   188       widget = find_widget_at_pos (xw->widgetwindow_osr,
   189                                    lrint (event->crossing.x - xv->clip_left),
   190                                    lrint (event->crossing.y - xv->clip_top),
   191                                    &new_x, &new_y, false, NULL);
   192       if (widget)
   193         {
   194           event->any.window = gtk_widget_get_window (widget);
   195           event->crossing.x = new_x;
   196           event->crossing.y = new_y;
   197           return 1;
   198         }
   199       return 0;
   200     default:
   201       return 0;
   202     }
   203 }
   204 
   205 static gboolean
   206 xw_forward_event_from_view (GtkWidget *widget, GdkEvent *event,
   207                             gpointer user_data)
   208 {
   209   struct xwidget_view *xv = user_data;
   210   struct xwidget *xw = XXWIDGET (xv->model);
   211   GdkEvent *eventcopy;
   212   bool translated_p;
   213 
   214   if (NILP (xw->buffer))
   215     return TRUE;
   216 
   217   eventcopy = gdk_event_copy (event);
   218   translated_p = xw_forward_event_translate (eventcopy, xv, xw);
   219   record_osr_embedder (xv);
   220 
   221   g_object_ref (eventcopy->any.window);
   222   if (translated_p)
   223     gtk_main_do_event (eventcopy);
   224   gdk_event_free (eventcopy);
   225 
   226   /* Don't propagate this event further.  */
   227   return TRUE;
   228 }
   229 #endif
   230 
   231 #ifdef HAVE_X_WINDOWS
   232 enum xw_crossing_mode
   233   {
   234     XW_CROSSING_LEFT,
   235     XW_CROSSING_ENTERED,
   236     XW_CROSSING_NONE
   237   };
   238 
   239 static guint
   240 xw_translate_x_modifiers (struct x_display_info *dpyinfo,
   241                           unsigned int modifiers)
   242 {
   243   guint mods = 0;
   244 
   245   if (modifiers & dpyinfo->meta_mod_mask)
   246     {
   247       /* GDK always assumes Mod1 is alt, but that's no reason for
   248          us to make that mistake as well.  */
   249       if (!dpyinfo->alt_mod_mask)
   250         mods |= GDK_MOD1_MASK;
   251       else
   252         mods |= GDK_META_MASK;
   253     }
   254 
   255   if (modifiers & dpyinfo->alt_mod_mask)
   256     mods |= GDK_MOD1_MASK;
   257   if (modifiers & dpyinfo->super_mod_mask)
   258     mods |= GDK_SUPER_MASK;
   259   if (modifiers & dpyinfo->hyper_mod_mask)
   260     mods |= GDK_HYPER_MASK;
   261   if (modifiers & ControlMask)
   262     mods |= GDK_CONTROL_MASK;
   263   if (modifiers & ShiftMask)
   264     mods |= GDK_SHIFT_MASK;
   265 
   266   return mods;
   267 }
   268 
   269 static bool xw_maybe_synthesize_crossing (struct xwidget_view *,
   270                                           GdkWindow *, int, int, int,
   271                                           Time, unsigned int,
   272                                           GdkCrossingMode, GdkCrossingMode);
   273 static void xw_notify_virtual_upwards_until (struct xwidget_view *, GdkWindow *,
   274                                              GdkWindow *, GdkWindow *, unsigned int,
   275                                              int, int, Time, GdkEventType, bool,
   276                                              GdkCrossingMode);
   277 static void window_coords_from_toplevel (GdkWindow *, GdkWindow *, int,
   278                                          int, int *, int *);
   279 #endif
   280 
   281 DEFUN ("make-xwidget",
   282        Fmake_xwidget, Smake_xwidget,
   283        4, 7, 0,
   284        doc: /* Make an xwidget of TYPE.
   285 If BUFFER is nil, use the current buffer.
   286 If BUFFER is a string and no such buffer exists, create it.
   287 TYPE is a symbol which can take one of the following values:
   288 
   289 - webkit
   290 
   291 RELATED is nil, or an xwidget.  When constructing a WebKit widget, it
   292 will share the same settings and internal subprocess as RELATED.
   293 Returns the newly constructed xwidget, or nil if construction
   294 fails.  */)
   295   (Lisp_Object type,
   296    Lisp_Object title, Lisp_Object width, Lisp_Object height,
   297    Lisp_Object arguments, Lisp_Object buffer, Lisp_Object related)
   298 {
   299 #ifdef USE_GTK
   300   if (!xg_gtk_initialized)
   301     error ("make-xwidget: GTK has not been initialized");
   302 #endif
   303   CHECK_SYMBOL (type);
   304   CHECK_FIXNAT (width);
   305   CHECK_FIXNAT (height);
   306 
   307   if (!EQ (type, Qwebkit))
   308     error ("Bad xwidget type");
   309 
   310   Frequire (Qxwidget, Qnil, Qnil);
   311 
   312   struct xwidget *xw = allocate_xwidget ();
   313   Lisp_Object val;
   314   xw->type = type;
   315   xw->title = title;
   316   xw->buffer = (NILP (buffer) ? Fcurrent_buffer ()
   317                 : Fget_buffer_create (buffer, Qnil));
   318   xw->height = XFIXNAT (height);
   319   xw->width = XFIXNAT (width);
   320   xw->kill_without_query = false;
   321   XSETXWIDGET (val, xw);
   322   internal_xwidget_list = Fcons (val, internal_xwidget_list);
   323   Vxwidget_list = Fcopy_sequence (internal_xwidget_list);
   324   xw->plist = Qnil;
   325   xw->xwidget_id = ++xwidget_counter;
   326   xw->find_text = NULL;
   327 
   328   Fputhash (make_fixnum (xw->xwidget_id), val, id_to_xwidget_map);
   329 
   330 #ifdef USE_GTK
   331   xw->widgetwindow_osr = NULL;
   332   xw->widget_osr = NULL;
   333   xw->hit_result = 0;
   334   if (EQ (xw->type, Qwebkit))
   335     {
   336       block_input ();
   337       WebKitSettings *settings;
   338       WebKitWebContext *webkit_context = webkit_web_context_get_default ();
   339 
   340 # if WEBKIT_CHECK_VERSION (2, 26, 0)
   341       if (!webkit_web_context_get_sandbox_enabled (webkit_context))
   342         webkit_web_context_set_sandbox_enabled (webkit_context, TRUE);
   343 # endif
   344 
   345       xw->widgetwindow_osr = gtk_offscreen_window_new ();
   346       gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
   347                          xw->height);
   348       gtk_container_check_resize (GTK_CONTAINER (xw->widgetwindow_osr));
   349 
   350       if (EQ (xw->type, Qwebkit))
   351         {
   352           WebKitWebView *related_view;
   353 
   354           if (NILP (related)
   355               || !XWIDGETP (related)
   356               || !EQ (XXWIDGET (related)->type, Qwebkit))
   357             {
   358               WebKitWebContext *ctx = webkit_web_context_new ();
   359               xw->widget_osr = webkit_web_view_new_with_context (ctx);
   360               g_object_unref (ctx);
   361 
   362               g_signal_connect (G_OBJECT (ctx),
   363                                 "download-started",
   364                                 G_CALLBACK (webkit_download_cb), xw);
   365 
   366               webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr),
   367                                         "about:blank");
   368               /* webkitgtk uses GSubprocess which sets sigaction causing
   369                  Emacs to not catch SIGCHLD with its usual handle setup in
   370                  'catch_child_signal'.  This resets the SIGCHLD sigaction.  */
   371               catch_child_signal ();
   372             }
   373           else
   374             {
   375               related_view = WEBKIT_WEB_VIEW (XXWIDGET (related)->widget_osr);
   376               xw->widget_osr = webkit_web_view_new_with_related_view (related_view);
   377             }
   378 
   379           /* Enable the developer extras.  */
   380           settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (xw->widget_osr));
   381           g_object_set (G_OBJECT (settings), "enable-developer-extras", TRUE, NULL);
   382         }
   383 
   384       gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
   385                                    xw->height);
   386       gtk_widget_queue_allocate (GTK_WIDGET (xw->widget_osr));
   387 
   388       if (EQ (xw->type, Qwebkit))
   389         {
   390           gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
   391                              GTK_WIDGET (WEBKIT_WEB_VIEW (xw->widget_osr)));
   392         }
   393       else
   394         {
   395           gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
   396                              xw->widget_osr);
   397         }
   398 
   399       gtk_widget_show (xw->widget_osr);
   400       gtk_widget_show (xw->widgetwindow_osr);
   401 #if !defined HAVE_XINPUT2 && !defined HAVE_PGTK
   402       synthesize_focus_in_event (xw->widgetwindow_osr);
   403 #endif
   404 
   405       g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
   406                         "from-embedder", G_CALLBACK (from_embedder), NULL);
   407       g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
   408                         "to-embedder", G_CALLBACK (to_embedder), NULL);
   409       g_signal_connect (G_OBJECT (gtk_widget_get_window (xw->widgetwindow_osr)),
   410                         "pick-embedded-child", G_CALLBACK (pick_embedded_child), NULL);
   411 
   412       /* Store some xwidget data in the gtk widgets for convenient
   413          retrieval in the event handlers.  */
   414       g_object_set_data (G_OBJECT (xw->widget_osr), XG_XWIDGET, xw);
   415       g_object_set_data (G_OBJECT (xw->widgetwindow_osr), XG_XWIDGET, xw);
   416 
   417       /* signals */
   418       if (EQ (xw->type, Qwebkit))
   419         {
   420           g_signal_connect (G_OBJECT (xw->widget_osr),
   421                             "load-changed",
   422                             G_CALLBACK (webkit_view_load_changed_cb), xw);
   423 
   424           g_signal_connect (G_OBJECT (xw->widget_osr),
   425                             "decide-policy",
   426                             G_CALLBACK
   427                             (webkit_decide_policy_cb),
   428                             xw);
   429 #ifdef HAVE_PGTK
   430           g_signal_connect (G_OBJECT (xw->widget_osr),
   431                             "mouse-target-changed",
   432                             G_CALLBACK (mouse_target_changed),
   433                             xw);
   434 #endif
   435           g_signal_connect (G_OBJECT (xw->widget_osr),
   436                             "create",
   437                             G_CALLBACK (webkit_create_cb),
   438                             xw);
   439           g_signal_connect (G_OBJECT (xw->widget_osr),
   440                             "script-dialog",
   441                             G_CALLBACK (webkit_script_dialog_cb),
   442                             NULL);
   443           g_signal_connect (G_OBJECT (xw->widget_osr),
   444                             "run-file-chooser",
   445                             G_CALLBACK (run_file_chooser_cb),
   446                             NULL);
   447         }
   448 
   449       g_signal_connect (G_OBJECT (xw->widgetwindow_osr), "damage-event",
   450                         G_CALLBACK (offscreen_damage_event), xw);
   451 
   452       unblock_input ();
   453     }
   454 #elif defined NS_IMPL_COCOA
   455   nsxwidget_init (xw);
   456 #endif
   457 
   458   return val;
   459 }
   460 
   461 DEFUN ("xwidget-live-p", Fxwidget_live_p, Sxwidget_live_p,
   462        1, 1, 0, doc: /* Return t if OBJECT is an xwidget that has not been killed.
   463 Value is nil if OBJECT is not an xwidget or if it has been killed.  */)
   464   (Lisp_Object object)
   465 {
   466   return ((XWIDGETP (object)
   467            && !NILP (XXWIDGET (object)->buffer))
   468           ? Qt : Qnil);
   469 }
   470 
   471 #ifdef USE_GTK
   472 static void
   473 set_widget_if_text_view (GtkWidget *widget, void *data)
   474 {
   475   GtkWidget **pointer = data;
   476 
   477   if (GTK_IS_TEXT_VIEW (widget))
   478     *pointer = widget;
   479 }
   480 #endif
   481 
   482 DEFUN ("xwidget-perform-lispy-event",
   483        Fxwidget_perform_lispy_event, Sxwidget_perform_lispy_event,
   484        2, 3, 0, doc: /* Send a lispy event to XWIDGET.
   485 EVENT should be the event that will be sent.  FRAME should be the
   486 frame which generated the event, and defaults to the selected frame.
   487 On X11, modifier keys will not be processed if FRAME is nil and the
   488 selected frame is not an X-Windows frame.  */)
   489   (Lisp_Object xwidget, Lisp_Object event, Lisp_Object frame)
   490 {
   491   struct xwidget *xw;
   492   struct frame *f = NULL;
   493   int character = -1, keycode = -1;
   494   int modifiers = 0;
   495 
   496 #ifdef USE_GTK
   497   GdkEvent *xg_event;
   498   GtkContainerClass *klass;
   499   GtkWidget *widget;
   500   GtkWidget *temp = NULL;
   501 #ifdef HAVE_XINPUT2
   502   GdkWindow *embedder;
   503   GdkWindow *osw;
   504 #endif
   505 #endif
   506 
   507   CHECK_LIVE_XWIDGET (xwidget);
   508   xw = XXWIDGET (xwidget);
   509 
   510   if (!NILP (frame))
   511     f = decode_window_system_frame (frame);
   512   else if (FRAME_WINDOW_P (SELECTED_FRAME ()))
   513     f = SELECTED_FRAME ();
   514 
   515 #ifdef USE_GTK
   516 #ifdef HAVE_XINPUT2
   517   /* XI2 GDK devices crash if we try this without an embedder set.  */
   518   if (!f)
   519     return Qnil;
   520 
   521   block_input ();
   522   osw = gtk_widget_get_window (xw->widgetwindow_osr);
   523   embedder = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));
   524 
   525   gdk_offscreen_window_set_embedder (osw, embedder);
   526   unblock_input ();
   527 #endif
   528   widget = gtk_window_get_focus (GTK_WINDOW (xw->widgetwindow_osr));
   529 
   530   if (!widget)
   531     widget = xw->widget_osr;
   532 
   533   if (RANGED_FIXNUMP (0, event, INT_MAX))
   534     {
   535       character = XFIXNUM (event);
   536 
   537       if (character < 32)
   538         modifiers |= ctrl_modifier;
   539 
   540       modifiers |= character & meta_modifier;
   541       modifiers |= character & hyper_modifier;
   542       modifiers |= character & super_modifier;
   543       modifiers |= character & shift_modifier;
   544       modifiers |= character & ctrl_modifier;
   545 
   546       character = character & ~(1 << 21);
   547 
   548       if (character < 32)
   549         character += '_';
   550 
   551 #ifndef HAVE_PGTK
   552       if (f)
   553         modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f), modifiers);
   554       else
   555         modifiers = 0;
   556 #else
   557       if (f)
   558         modifiers = pgtk_emacs_to_gtk_modifiers (FRAME_DISPLAY_INFO (f), modifiers);
   559       else
   560         modifiers = 0;
   561 #endif
   562     }
   563   else if (SYMBOLP (event))
   564     {
   565       Lisp_Object decoded = parse_modifiers (event);
   566       Lisp_Object decoded_name = SYMBOL_NAME (XCAR (decoded));
   567 
   568       int off = 0;
   569       bool found = false;
   570 
   571       while (off < 256)
   572         {
   573           if (lispy_function_keys[off]
   574               && !strcmp (lispy_function_keys[off],
   575                           SSDATA (decoded_name)))
   576             {
   577               found = true;
   578               break;
   579             }
   580           ++off;
   581         }
   582 
   583 #ifndef HAVE_PGTK
   584       if (f)
   585         modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f),
   586                                             XFIXNUM (XCAR (XCDR (decoded))));
   587       else
   588         modifiers = 0;
   589 #else
   590       if (f)
   591         modifiers = pgtk_emacs_to_gtk_modifiers (FRAME_DISPLAY_INFO (f),
   592                                                  XFIXNUM (XCAR (XCDR (decoded))));
   593       else
   594         modifiers = 0;
   595 #endif
   596 
   597       if (found)
   598         keycode = off + 0xff00;
   599     }
   600 
   601   if (character == -1 && keycode == -1)
   602     {
   603 #ifdef HAVE_XINPUT2
   604       block_input ();
   605       if (xw->embedder_view)
   606         record_osr_embedder (xw->embedder_view);
   607       else
   608         gdk_offscreen_window_set_embedder (osw, NULL);
   609       unblock_input ();
   610 #endif
   611       return Qnil;
   612     }
   613 
   614   block_input ();
   615   xg_event = gdk_event_new (GDK_KEY_PRESS);
   616   xg_event->any.window = gtk_widget_get_window (xw->widget_osr);
   617   g_object_ref (xg_event->any.window);
   618 
   619   if (character > -1)
   620     keycode = gdk_unicode_to_keyval (character);
   621 
   622   xg_event->key.keyval = keycode;
   623 #ifndef HAVE_X_WINDOWS
   624   xg_event->key.state = modifiers;
   625 #else
   626   if (f)
   627     xg_event->key.state = xw_translate_x_modifiers (FRAME_DISPLAY_INFO (f),
   628                                                     modifiers);
   629 #endif
   630 
   631   if (keycode > -1)
   632     {
   633       /* WebKitGTK internals abuse follows.  */
   634       if (WEBKIT_IS_WEB_VIEW (widget))
   635         {
   636           /* WebKitGTK relies on an internal GtkTextView object to
   637              "translate" keys such as backspace.  We must find that
   638              widget and activate its binding to this key if any.  */
   639           klass = GTK_CONTAINER_CLASS (G_OBJECT_GET_CLASS (widget));
   640 
   641           klass->forall (GTK_CONTAINER (xw->widget_osr), TRUE,
   642                          set_widget_if_text_view, &temp);
   643 
   644           if (GTK_IS_WIDGET (temp))
   645             {
   646               if (!gtk_widget_get_realized (temp))
   647                 gtk_widget_realize (temp);
   648 
   649               gtk_bindings_activate (G_OBJECT (temp), keycode, modifiers);
   650             }
   651         }
   652     }
   653 
   654   if (f)
   655     gdk_event_set_device (xg_event,
   656                           find_suitable_keyboard (SELECTED_FRAME ()));
   657 
   658   gtk_main_do_event (xg_event);
   659   xg_event->type = GDK_KEY_RELEASE;
   660   gtk_main_do_event (xg_event);
   661   gdk_event_free (xg_event);
   662 
   663 #ifdef HAVE_XINPUT2
   664   if (xw->embedder_view)
   665     record_osr_embedder (xw->embedder_view);
   666   else
   667     gdk_offscreen_window_set_embedder (osw, NULL);
   668 #endif
   669   unblock_input ();
   670 #endif
   671 
   672   return Qnil;
   673 }
   674 
   675 DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets, Sget_buffer_xwidgets,
   676        1, 1, 0,
   677        doc: /* Return a list of xwidgets associated with BUFFER.
   678 BUFFER may be a buffer or the name of one.  */)
   679   (Lisp_Object buffer)
   680 {
   681   Lisp_Object xw, tail, xw_list;
   682 
   683   if (NILP (buffer))
   684     return Qnil;
   685   buffer = Fget_buffer (buffer);
   686   if (NILP (buffer))
   687     return Qnil;
   688 
   689   xw_list = Qnil;
   690 
   691   for (tail = internal_xwidget_list; CONSP (tail); tail = XCDR (tail))
   692     {
   693       xw = XCAR (tail);
   694       if (XWIDGETP (xw) && EQ (Fxwidget_buffer (xw), buffer))
   695         xw_list = Fcons (xw, xw_list);
   696     }
   697   return xw_list;
   698 }
   699 
   700 static bool
   701 xwidget_hidden (struct xwidget_view *xv)
   702 {
   703   return xv->hidden;
   704 }
   705 
   706 struct xwidget *
   707 xwidget_from_id (uint32_t id)
   708 {
   709   Lisp_Object key = make_fixnum (id);
   710   Lisp_Object xwidget = Fgethash (key, id_to_xwidget_map, Qnil);
   711 
   712   if (NILP (xwidget))
   713     emacs_abort ();
   714 
   715   return XXWIDGET (xwidget);
   716 }
   717 
   718 #ifdef USE_GTK
   719 static GdkWindow *
   720 pick_embedded_child (GdkWindow *window, double x, double y,
   721                      gpointer user_data)
   722 {
   723   GtkWidget *widget;
   724   GtkWidget *child;
   725   GdkEvent event;
   726   int xout, yout;
   727 
   728   event.any.window = window;
   729   event.any.type = GDK_NOTHING;
   730 
   731   widget = gtk_get_event_widget (&event);
   732 
   733   if (!widget)
   734     return NULL;
   735 
   736   child = find_widget_at_pos (widget, lrint (x), lrint (y),
   737                               &xout, &yout, false, NULL);
   738 
   739   if (!child)
   740     return NULL;
   741 
   742   return gtk_widget_get_window (child);
   743 }
   744 
   745 static void
   746 record_osr_embedder (struct xwidget_view *view)
   747 {
   748   struct xwidget *xw;
   749   GdkWindow *window, *embedder;
   750 
   751   xw = XXWIDGET (view->model);
   752   window = gtk_widget_get_window (xw->widgetwindow_osr);
   753 #ifndef HAVE_PGTK
   754   embedder = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (view->frame));
   755 #else
   756   embedder = gtk_widget_get_window (view->widget);
   757 #endif
   758   gdk_offscreen_window_set_embedder (window, embedder);
   759   xw->embedder = view->frame;
   760   xw->embedder_view = view;
   761 }
   762 
   763 static struct xwidget *
   764 find_xwidget_for_offscreen_window (GdkWindow *window)
   765 {
   766   Lisp_Object tem;
   767   struct xwidget *xw;
   768   GdkWindow *w;
   769 
   770   for (tem = internal_xwidget_list; CONSP (tem); tem = XCDR (tem))
   771     {
   772       if (XWIDGETP (XCAR (tem)))
   773         {
   774           xw = XXWIDGET (XCAR (tem));
   775           w = gtk_widget_get_window (xw->widgetwindow_osr);
   776 
   777           if (w == window)
   778             return xw;
   779         }
   780     }
   781 
   782   return NULL;
   783 }
   784 
   785 static void
   786 from_embedder (GdkWindow *window, double x, double y,
   787                gpointer x_out_ptr, gpointer y_out_ptr,
   788                gpointer user_data)
   789 {
   790   double *xout = x_out_ptr;
   791   double *yout = y_out_ptr;
   792 #ifndef HAVE_PGTK
   793   struct xwidget *xw = find_xwidget_for_offscreen_window (window);
   794   struct xwidget_view *xvw;
   795   gint xoff, yoff;
   796 
   797   if (!xw)
   798     emacs_abort ();
   799 
   800   xvw = xw->embedder_view;
   801 
   802   if (!xvw)
   803     {
   804       *xout = x;
   805       *yout = y;
   806     }
   807   else
   808     {
   809       gtk_widget_translate_coordinates (FRAME_GTK_WIDGET (xvw->frame),
   810                                         FRAME_GTK_OUTER_WIDGET (xvw->frame),
   811                                         0, 0, &xoff, &yoff);
   812 
   813       *xout = x - xvw->x - xoff;
   814       *yout = y - xvw->y - yoff;
   815     }
   816 #else
   817   *xout = x;
   818   *yout = y;
   819 #endif
   820 }
   821 
   822 static void
   823 to_embedder (GdkWindow *window, double x, double y,
   824              gpointer x_out_ptr, gpointer y_out_ptr,
   825              gpointer user_data)
   826 {
   827   double *xout = x_out_ptr;
   828   double *yout = y_out_ptr;
   829 #ifndef HAVE_PGTK
   830   struct xwidget *xw = find_xwidget_for_offscreen_window (window);
   831   struct xwidget_view *xvw;
   832   gint xoff, yoff;
   833 
   834   if (!xw)
   835     emacs_abort ();
   836 
   837   xvw = xw->embedder_view;
   838 
   839   if (!xvw)
   840     {
   841       *xout = x;
   842       *yout = y;
   843     }
   844   else
   845     {
   846       gtk_widget_translate_coordinates (FRAME_GTK_WIDGET (xvw->frame),
   847                                         FRAME_GTK_OUTER_WIDGET (xvw->frame),
   848                                         0, 0, &xoff, &yoff);
   849 
   850       *xout = x + xvw->x + xoff;
   851       *yout = y + xvw->y + yoff;
   852     }
   853 #else
   854   *xout = x;
   855   *yout = y;
   856 #endif
   857 }
   858 
   859 static GdkDevice *
   860 find_suitable_pointer (struct frame *f, bool need_smooth)
   861 {
   862   GdkSeat *seat = gdk_display_get_default_seat
   863     (gtk_widget_get_display (FRAME_GTK_WIDGET (f)));
   864   GList *devices, *tem;
   865   GdkDevice *device;
   866 
   867   if (!seat)
   868     return NULL;
   869 
   870   devices = gdk_seat_get_slaves (seat, GDK_SEAT_CAPABILITY_ALL_POINTING);
   871   device = NULL;
   872   tem = NULL;
   873 
   874   if (need_smooth)
   875     {
   876       for (tem = devices; tem; tem = tem->next)
   877         {
   878           device = GDK_DEVICE (tem->data);
   879 
   880           if (gdk_device_get_source (device) == GDK_SOURCE_TOUCHPAD)
   881             break;
   882         }
   883     }
   884 
   885   g_list_free (devices);
   886 
   887   return !tem ? gdk_seat_get_pointer (seat) : device;
   888 }
   889 
   890 static GdkDevice *
   891 find_suitable_keyboard (struct frame *f)
   892 {
   893   GdkSeat *seat = gdk_display_get_default_seat
   894     (gtk_widget_get_display (FRAME_GTK_WIDGET (f)));
   895 
   896   if (!seat)
   897     return NULL;
   898 
   899   return gdk_seat_get_keyboard (seat);
   900 }
   901 
   902 static void
   903 find_widget_cb (GtkWidget *widget, void *user)
   904 {
   905   find_widget (widget, user);
   906 }
   907 
   908 static void
   909 find_widget (GtkWidget *widget,
   910              struct widget_search_data *data)
   911 {
   912   GtkAllocation new_allocation;
   913   GdkWindow *window;
   914   int x_offset = 0;
   915   int y_offset = 0;
   916 
   917   gtk_widget_get_allocation (widget, &new_allocation);
   918 
   919   if (gtk_widget_get_has_window (widget))
   920     {
   921       new_allocation.x = 0;
   922       new_allocation.y = 0;
   923     }
   924 
   925   if (gtk_widget_get_parent (widget) && !data->first)
   926     {
   927       window = gtk_widget_get_window (widget);
   928       while (window != gtk_widget_get_window (gtk_widget_get_parent (widget)))
   929         {
   930           gint tx, ty, twidth, theight;
   931 
   932           if (!window)
   933             return;
   934 
   935           twidth = gdk_window_get_width (window);
   936           theight = gdk_window_get_height (window);
   937 
   938           if (new_allocation.x < 0)
   939             {
   940               new_allocation.width += new_allocation.x;
   941               new_allocation.x = 0;
   942             }
   943 
   944           if (new_allocation.y < 0)
   945             {
   946               new_allocation.height += new_allocation.y;
   947               new_allocation.y = 0;
   948             }
   949 
   950           if (new_allocation.x + new_allocation.width > twidth)
   951             new_allocation.width = twidth - new_allocation.x;
   952           if (new_allocation.y + new_allocation.height > theight)
   953             new_allocation.height = theight - new_allocation.y;
   954 
   955           gdk_window_get_position (window, &tx, &ty);
   956           new_allocation.x += tx;
   957           x_offset += tx;
   958           new_allocation.y += ty;
   959           y_offset += ty;
   960 
   961           window = gdk_window_get_parent (window);
   962         }
   963     }
   964 
   965   if ((data->x >= new_allocation.x) && (data->y >= new_allocation.y)
   966       && (data->x < new_allocation.x + new_allocation.width)
   967       && (data->y < new_allocation.y + new_allocation.height))
   968     {
   969       /* First, check if the drag is in a valid drop site in one of
   970          our children.  */
   971       if (GTK_IS_CONTAINER (widget))
   972         {
   973           struct widget_search_data new_data = *data;
   974 
   975           new_data.x -= x_offset;
   976           new_data.y -= y_offset;
   977           new_data.foundp = false;
   978           new_data.first = false;
   979 
   980           gtk_container_forall (GTK_CONTAINER (widget),
   981                                 find_widget_cb, &new_data);
   982 
   983           data->foundp = new_data.foundp;
   984           if (data->foundp)
   985             data->data = new_data.data;
   986         }
   987 
   988       /* If not, and this widget is registered as a drop site, check
   989          to emit "drag_motion" to check if we are actually in a drop
   990          site.  */
   991       if (!data->foundp)
   992         {
   993           data->foundp = true;
   994           data->data = widget;
   995         }
   996     }
   997 }
   998 
   999 static GtkWidget *
  1000 find_widget_at_pos (GtkWidget *w, int x, int y,
  1001                     int *new_x, int *new_y,
  1002                     bool pointer_grabs,
  1003                     struct xwidget_view *vw)
  1004 {
  1005   struct widget_search_data data;
  1006 #ifdef HAVE_X_WINDOWS
  1007   GtkWidget *grab = NULL;
  1008 
  1009   if (pointer_grabs)
  1010     {
  1011       grab = vw->passive_grab;
  1012 
  1013       if (grab && gtk_widget_get_window (grab))
  1014         {
  1015           gtk_widget_translate_coordinates (w, grab, x,
  1016                                             y, new_x, new_y);
  1017 
  1018           return grab;
  1019         }
  1020     }
  1021 #endif
  1022 
  1023   data.x = x;
  1024   data.y = y;
  1025   data.foundp = false;
  1026   data.first = true;
  1027 
  1028   find_widget (w, &data);
  1029 
  1030   if (data.foundp)
  1031     {
  1032       gtk_widget_translate_coordinates (w, data.data, x,
  1033                                         y, new_x, new_y);
  1034       return data.data;
  1035     }
  1036 
  1037   *new_x = x;
  1038   *new_y = y;
  1039 
  1040   return NULL;
  1041 }
  1042 
  1043 #ifdef HAVE_PGTK
  1044 static Emacs_Cursor
  1045 cursor_for_hit (guint result, struct frame *frame)
  1046 {
  1047   Emacs_Cursor cursor = FRAME_OUTPUT_DATA (frame)->nontext_cursor;
  1048 
  1049   if ((result & WEBKIT_HIT_TEST_RESULT_CONTEXT_EDITABLE)
  1050       || (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_SELECTION)
  1051       || (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_DOCUMENT))
  1052     cursor = FRAME_X_OUTPUT (frame)->text_cursor;
  1053 
  1054   if (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_SCROLLBAR)
  1055     cursor = FRAME_X_OUTPUT (frame)->vertical_drag_cursor;
  1056 
  1057   if (result & WEBKIT_HIT_TEST_RESULT_CONTEXT_LINK)
  1058     cursor = FRAME_X_OUTPUT (frame)->hand_cursor;
  1059 
  1060   return cursor;
  1061 }
  1062 
  1063 static void
  1064 define_cursors (struct xwidget *xw, WebKitHitTestResult *res)
  1065 {
  1066   struct xwidget_view *xvw;
  1067   GdkWindow *wdesc;
  1068 
  1069   xw->hit_result = webkit_hit_test_result_get_context (res);
  1070 
  1071   for (Lisp_Object tem = internal_xwidget_view_list; CONSP (tem);
  1072        tem = XCDR (tem))
  1073     {
  1074       if (XWIDGET_VIEW_P (XCAR (tem)))
  1075         {
  1076           xvw = XXWIDGET_VIEW (XCAR (tem));
  1077 
  1078           if (XXWIDGET (xvw->model) == xw)
  1079             {
  1080               xvw->cursor = cursor_for_hit (xw->hit_result, xvw->frame);
  1081 
  1082               if (gtk_widget_get_realized (xvw->widget))
  1083                 {
  1084                   wdesc = gtk_widget_get_window (xvw->widget);
  1085                   gdk_window_set_cursor (wdesc, xvw->cursor);
  1086                 }
  1087             }
  1088         }
  1089     }
  1090 }
  1091 
  1092 static void
  1093 mouse_target_changed (WebKitWebView *webview,
  1094                       WebKitHitTestResult *hitresult,
  1095                       guint modifiers, gpointer xw)
  1096 {
  1097   define_cursors (xw, hitresult);
  1098 }
  1099 #endif
  1100 
  1101 static gboolean
  1102 run_file_chooser_cb (WebKitWebView *webview,
  1103                      WebKitFileChooserRequest *request,
  1104                      gpointer user_data)
  1105 {
  1106   struct frame *f = SELECTED_FRAME ();
  1107   GtkFileChooserNative *chooser;
  1108   GtkFileFilter *filter;
  1109   bool select_multiple_p;
  1110   guint response;
  1111   GSList *filenames;
  1112   GSList *tem;
  1113   int i, len;
  1114   gchar **files;
  1115 
  1116   /* Return TRUE to prevent WebKit from showing the default script
  1117      dialog in the offscreen window, which runs a nested main loop
  1118      Emacs can't respond to, and as such can't pass X events to.  */
  1119   if (!FRAME_WINDOW_P (f))
  1120     return TRUE;
  1121 
  1122   chooser = gtk_file_chooser_native_new ("Select file",
  1123                                          GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
  1124                                          GTK_FILE_CHOOSER_ACTION_OPEN, "Select",
  1125                                          "Cancel");
  1126   filter = webkit_file_chooser_request_get_mime_types_filter (request);
  1127   select_multiple_p = webkit_file_chooser_request_get_select_multiple (request);
  1128 
  1129   gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (chooser),
  1130                                         select_multiple_p);
  1131   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (chooser), filter);
  1132   response = gtk_native_dialog_run (GTK_NATIVE_DIALOG (chooser));
  1133 
  1134   if (response != GTK_RESPONSE_ACCEPT)
  1135     {
  1136       gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (chooser));
  1137       webkit_file_chooser_request_cancel (request);
  1138 
  1139       return TRUE;
  1140     }
  1141 
  1142   filenames = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (chooser));
  1143   len = g_slist_length (filenames);
  1144   files = alloca (sizeof *files * (len + 1));
  1145 
  1146   for (tem = filenames, i = 0; tem; tem = tem->next, ++i)
  1147     files[i] = tem->data;
  1148   files[len] = NULL;
  1149 
  1150   g_slist_free (filenames);
  1151   webkit_file_chooser_request_select_files (request, (const gchar **) files);
  1152 
  1153   for (i = 0; i < len; ++i)
  1154     g_free (files[i]);
  1155 
  1156   gtk_native_dialog_destroy (GTK_NATIVE_DIALOG (chooser));
  1157 
  1158   return TRUE;
  1159 }
  1160 
  1161 #ifdef HAVE_X_WINDOWS
  1162 
  1163 static void
  1164 xv_drag_begin_cb (GtkWidget *widget,
  1165                   GdkDragContext *context,
  1166                   gpointer user_data)
  1167 {
  1168   struct xwidget_view *view = user_data;
  1169 
  1170   if (view->passive_grab)
  1171     {
  1172       g_signal_handler_disconnect (view->passive_grab,
  1173                                    view->passive_grab_destruction_signal);
  1174       g_signal_handler_disconnect (view->passive_grab,
  1175                                    view->passive_grab_drag_signal);
  1176       view->passive_grab = NULL;
  1177     }
  1178 }
  1179 
  1180 static void
  1181 xwidget_button_1 (struct xwidget_view *view,
  1182                   bool down_p, int x, int y, int button,
  1183                   int modifier_state, Time time)
  1184 {
  1185   GdkEvent *xg_event;
  1186   struct xwidget *model = XXWIDGET (view->model);
  1187   GtkWidget *target;
  1188   GtkWidget *ungrab_target;
  1189   GdkWindow *toplevel, *target_window;
  1190   int view_x, view_y;
  1191 
  1192   /* X and Y should be relative to the origin of view->wdesc.  */
  1193   x += view->clip_left;
  1194   y += view->clip_top;
  1195 
  1196   view_x = x;
  1197   view_y = y;
  1198 
  1199   target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y,
  1200                                true, view);
  1201 
  1202   if (!target)
  1203     target = model->widget_osr;
  1204 
  1205   xg_event = gdk_event_new (down_p ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE);
  1206 
  1207   xg_event->any.window = gtk_widget_get_window (target);
  1208   g_object_ref (xg_event->any.window); /* The window will be unrefed
  1209                                           later by gdk_event_free.  */
  1210 
  1211   xg_event->button.x = x;
  1212   xg_event->button.x_root = x;
  1213   xg_event->button.y = y;
  1214   xg_event->button.y_root = y;
  1215   xg_event->button.button = button;
  1216   xg_event->button.state = modifier_state;
  1217   xg_event->button.time = time;
  1218   xg_event->button.device = find_suitable_pointer (view->frame, false);
  1219 
  1220   gtk_main_do_event (xg_event);
  1221   gdk_event_free (xg_event);
  1222 
  1223 
  1224   if (down_p && !view->passive_grab)
  1225     {
  1226       view->passive_grab = target;
  1227       view->passive_grab_destruction_signal
  1228         = g_signal_connect (G_OBJECT (view->passive_grab),
  1229                             "destroy", G_CALLBACK (gtk_widget_destroyed),
  1230                             &view->passive_grab);
  1231       view->passive_grab_drag_signal
  1232         = g_signal_connect (G_OBJECT (view->passive_grab),
  1233                             "drag-begin", G_CALLBACK (xv_drag_begin_cb),
  1234                             view);
  1235     }
  1236   else
  1237     {
  1238       ungrab_target = find_widget_at_pos (model->widgetwindow_osr,
  1239                                           view_x, view_y, &x, &y,
  1240                                           false, NULL);
  1241 
  1242       if (view->last_crossing_window && ungrab_target)
  1243         {
  1244           xw_maybe_synthesize_crossing (view, gtk_widget_get_window (ungrab_target),
  1245                                         view_x, view_y, XW_CROSSING_NONE,
  1246                                         time, modifier_state, GDK_CROSSING_UNGRAB,
  1247                                         GDK_CROSSING_UNGRAB);
  1248         }
  1249       else
  1250         {
  1251           toplevel = gtk_widget_get_window (model->widgetwindow_osr);
  1252           xg_event = gdk_event_new (GDK_LEAVE_NOTIFY);
  1253           target_window = gtk_widget_get_window (target);
  1254           window_coords_from_toplevel (target_window, toplevel, view_x,
  1255                                        view_y, &x, &y);
  1256 
  1257           xg_event->crossing.x = x;
  1258           xg_event->crossing.y = y;
  1259           xg_event->crossing.time = time;
  1260           xg_event->crossing.focus = FALSE;
  1261           xg_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
  1262           xg_event->crossing.mode = GDK_CROSSING_UNGRAB;
  1263           xg_event->crossing.window = g_object_ref (target_window);
  1264           gdk_event_set_device (xg_event,
  1265                                 find_suitable_pointer (view->frame, false));
  1266 
  1267           gtk_main_do_event (xg_event);
  1268           gdk_event_free (xg_event);
  1269 
  1270           xw_notify_virtual_upwards_until (view, target_window, toplevel, toplevel,
  1271                                            modifier_state, view_x, view_y, time,
  1272                                            GDK_LEAVE_NOTIFY, false,
  1273                                            GDK_CROSSING_UNGRAB);
  1274 
  1275           if (target_window != toplevel)
  1276             {
  1277               xg_event = gdk_event_new (GDK_LEAVE_NOTIFY);
  1278 
  1279               xg_event->crossing.x = view_y;
  1280               xg_event->crossing.y = view_y;
  1281               xg_event->crossing.time = time;
  1282               xg_event->crossing.focus = FALSE;
  1283               xg_event->crossing.detail = GDK_NOTIFY_VIRTUAL;
  1284               xg_event->crossing.mode = GDK_CROSSING_UNGRAB;
  1285               xg_event->crossing.window = g_object_ref (toplevel);
  1286 
  1287               gdk_event_set_device (xg_event,
  1288                                     find_suitable_pointer (view->frame, false));
  1289               gtk_main_do_event (xg_event);
  1290               gdk_event_free (xg_event);
  1291             }
  1292 
  1293         }
  1294 
  1295       if (view->passive_grab)
  1296         {
  1297           g_signal_handler_disconnect (view->passive_grab,
  1298                                        view->passive_grab_destruction_signal);
  1299           g_signal_handler_disconnect (view->passive_grab,
  1300                                        view->passive_grab_drag_signal);
  1301           view->passive_grab = NULL;
  1302         }
  1303     }
  1304 }
  1305 
  1306 void
  1307 xwidget_button (struct xwidget_view *view,
  1308                 bool down_p, int x, int y, int button,
  1309                 int modifier_state, Time time)
  1310 {
  1311   if (NILP (XXWIDGET (view->model)->buffer))
  1312     return;
  1313 
  1314   record_osr_embedder (view);
  1315 
  1316   if (button < 4 || button > 8)
  1317     xwidget_button_1 (view, down_p, x, y, button, modifier_state, time);
  1318   else
  1319     {
  1320       if (!down_p)
  1321         {
  1322           GdkEvent *xg_event = gdk_event_new (GDK_SCROLL);
  1323           struct xwidget *model = XXWIDGET (view->model);
  1324           GtkWidget *target;
  1325 
  1326           x += view->clip_left;
  1327           y += view->clip_top;
  1328 
  1329           target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y,
  1330                                        true, view);
  1331 
  1332           if (!target)
  1333             target = model->widget_osr;
  1334 
  1335           xg_event->any.window = gtk_widget_get_window (target);
  1336           g_object_ref (xg_event->any.window); /* The window will be unrefed
  1337                                                   later by gdk_event_free.  */
  1338           if (button == 4)
  1339             xg_event->scroll.direction = GDK_SCROLL_UP;
  1340           else if (button == 5)
  1341             xg_event->scroll.direction = GDK_SCROLL_DOWN;
  1342           else if (button == 6)
  1343             xg_event->scroll.direction = GDK_SCROLL_LEFT;
  1344           else
  1345             xg_event->scroll.direction = GDK_SCROLL_RIGHT;
  1346 
  1347           xg_event->scroll.device = find_suitable_pointer (view->frame,
  1348                                                            false);
  1349 
  1350           xg_event->scroll.x = x;
  1351           xg_event->scroll.x_root = x;
  1352           xg_event->scroll.y = y;
  1353           xg_event->scroll.y_root = y;
  1354           xg_event->scroll.state = modifier_state;
  1355           xg_event->scroll.time = time;
  1356 
  1357           xg_event->scroll.delta_x = 0;
  1358           xg_event->scroll.delta_y = 0;
  1359 
  1360           gtk_main_do_event (xg_event);
  1361           gdk_event_free (xg_event);
  1362         }
  1363     }
  1364 }
  1365 
  1366 #ifdef HAVE_XINPUT2
  1367 void
  1368 xwidget_motion_notify (struct xwidget_view *view,
  1369                        double x, double y,
  1370                        double root_x, double root_y,
  1371                        uint state, Time time)
  1372 {
  1373   GdkEvent *xg_event;
  1374   GtkWidget *target;
  1375   struct xwidget *model = XXWIDGET (view->model);
  1376   int target_x, target_y;
  1377 
  1378   if (NILP (model->buffer))
  1379     return;
  1380 
  1381   record_osr_embedder (view);
  1382 
  1383   target = find_widget_at_pos (model->widgetwindow_osr,
  1384                                lrint (x + view->clip_left),
  1385                                lrint (y + view->clip_top),
  1386                                &target_x, &target_y,
  1387                                true, view);
  1388 
  1389   if (!target)
  1390     {
  1391       target_x = lrint (x + view->clip_left);
  1392       target_y = lrint (y + view->clip_top);
  1393       target = model->widget_osr;
  1394     }
  1395   else if (xw_maybe_synthesize_crossing (view, gtk_widget_get_window (target),
  1396                                          x + view->clip_left, y + view->clip_top,
  1397                                          XW_CROSSING_NONE, time, state,
  1398                                          (view->passive_grab
  1399                                           ? GDK_CROSSING_GRAB
  1400                                           : GDK_CROSSING_NORMAL),
  1401                                          GDK_CROSSING_NORMAL))
  1402     return;
  1403 
  1404   xg_event = gdk_event_new (GDK_MOTION_NOTIFY);
  1405   xg_event->any.window = gtk_widget_get_window (target);
  1406   xg_event->motion.x = target_x;
  1407   xg_event->motion.y = target_y;
  1408   xg_event->motion.x_root = root_x;
  1409   xg_event->motion.y_root = root_y;
  1410   xg_event->motion.time = time;
  1411   xg_event->motion.state = state;
  1412   xg_event->motion.device = find_suitable_pointer (view->frame, false);
  1413 
  1414   g_object_ref (xg_event->any.window);
  1415 
  1416   gtk_main_do_event (xg_event);
  1417   gdk_event_free (xg_event);
  1418 }
  1419 
  1420 void
  1421 xwidget_scroll (struct xwidget_view *view, double x, double y,
  1422                 double dx, double dy, uint state, Time time,
  1423                 bool stop_p)
  1424 {
  1425   GdkEvent *xg_event;
  1426   GtkWidget *target;
  1427   struct xwidget *model = XXWIDGET (view->model);
  1428   int target_x, target_y;
  1429 
  1430   if (NILP (model->buffer))
  1431     return;
  1432 
  1433   record_osr_embedder (view);
  1434 
  1435   target = find_widget_at_pos (model->widgetwindow_osr,
  1436                                lrint (x + view->clip_left),
  1437                                lrint (y + view->clip_top),
  1438                                &target_x, &target_y,
  1439                                true, view);
  1440 
  1441   if (!target)
  1442     {
  1443       target_x = lrint (x);
  1444       target_y = lrint (y);
  1445       target = model->widget_osr;
  1446     }
  1447 
  1448   xg_event = gdk_event_new (GDK_SCROLL);
  1449   xg_event->any.window = gtk_widget_get_window (target);
  1450   xg_event->scroll.direction = GDK_SCROLL_SMOOTH;
  1451   xg_event->scroll.x = target_x;
  1452   xg_event->scroll.y = target_y;
  1453   xg_event->scroll.x_root = lrint (x);
  1454   xg_event->scroll.y_root = lrint (y);
  1455   xg_event->scroll.time = time;
  1456   xg_event->scroll.state = state;
  1457   xg_event->scroll.delta_x = dx;
  1458   xg_event->scroll.delta_y = dy;
  1459   xg_event->scroll.device = find_suitable_pointer (view->frame, true);
  1460   xg_event->scroll.is_stop = stop_p;
  1461 
  1462   g_object_ref (xg_event->any.window);
  1463 
  1464   gtk_main_do_event (xg_event);
  1465   gdk_event_free (xg_event);
  1466 }
  1467 
  1468 #ifdef HAVE_XINPUT2_4
  1469 void
  1470 xwidget_pinch (struct xwidget_view *view, XIGesturePinchEvent *xev)
  1471 {
  1472 #if GTK_CHECK_VERSION (3, 18, 0)
  1473   GdkEvent *xg_event;
  1474   GtkWidget *target;
  1475   struct xwidget *model = XXWIDGET (view->model);
  1476   int target_x, target_y;
  1477   double x = xev->event_x;
  1478   double y = xev->event_y;
  1479 
  1480   if (NILP (model->buffer))
  1481     return;
  1482 
  1483   record_osr_embedder (view);
  1484 
  1485   target = find_widget_at_pos (model->widgetwindow_osr,
  1486                                lrint (x + view->clip_left),
  1487                                lrint (y + view->clip_top),
  1488                                &target_x, &target_y,
  1489                                true, view);
  1490 
  1491   if (!target)
  1492     {
  1493       target_x = lrint (x);
  1494       target_y = lrint (y);
  1495       target = model->widget_osr;
  1496     }
  1497 
  1498   xg_event = gdk_event_new (GDK_TOUCHPAD_PINCH);
  1499   xg_event->any.window = gtk_widget_get_window (target);
  1500   xg_event->touchpad_pinch.x = target_x;
  1501   xg_event->touchpad_pinch.y = target_y;
  1502   xg_event->touchpad_pinch.dx = xev->delta_x;
  1503   xg_event->touchpad_pinch.dy = xev->delta_y;
  1504   xg_event->touchpad_pinch.angle_delta = xev->delta_angle;
  1505   xg_event->touchpad_pinch.scale = xev->scale;
  1506   xg_event->touchpad_pinch.x_root = xev->root_x;
  1507   xg_event->touchpad_pinch.y_root = xev->root_y;
  1508   xg_event->touchpad_pinch.state = xev->mods.effective;
  1509   xg_event->touchpad_pinch.n_fingers = 2;
  1510 
  1511   switch (xev->evtype)
  1512     {
  1513     case XI_GesturePinchBegin:
  1514       xg_event->touchpad_pinch.phase = GDK_TOUCHPAD_GESTURE_PHASE_BEGIN;
  1515       break;
  1516     case XI_GesturePinchUpdate:
  1517       xg_event->touchpad_pinch.phase = GDK_TOUCHPAD_GESTURE_PHASE_UPDATE;
  1518       break;
  1519     case XI_GesturePinchEnd:
  1520       xg_event->touchpad_pinch.phase = GDK_TOUCHPAD_GESTURE_PHASE_END;
  1521       break;
  1522     }
  1523 
  1524   gdk_event_set_device (xg_event, find_suitable_pointer (view->frame, false));
  1525 
  1526   g_object_ref (xg_event->any.window);
  1527   gtk_main_do_event (xg_event);
  1528   gdk_event_free (xg_event);
  1529 #endif
  1530 }
  1531 #endif
  1532 #endif
  1533 
  1534 #ifdef HAVE_XINPUT2
  1535 static GdkNotifyType
  1536 xi_translate_notify_detail (int detail)
  1537 {
  1538   switch (detail)
  1539     {
  1540     case XINotifyInferior:
  1541       return GDK_NOTIFY_INFERIOR;
  1542     case XINotifyAncestor:
  1543       return GDK_NOTIFY_ANCESTOR;
  1544     case XINotifyVirtual:
  1545       return GDK_NOTIFY_VIRTUAL;
  1546     case XINotifyNonlinear:
  1547       return GDK_NOTIFY_NONLINEAR;
  1548     case XINotifyNonlinearVirtual:
  1549       return GDK_NOTIFY_NONLINEAR_VIRTUAL;
  1550     default:
  1551       emacs_abort ();
  1552     }
  1553 }
  1554 #endif
  1555 
  1556 static void
  1557 window_coords_from_toplevel (GdkWindow *window, GdkWindow *toplevel,
  1558                              int x, int y, int *out_x, int *out_y)
  1559 {
  1560   GdkWindow *parent;
  1561   GList *children, *l;
  1562   gdouble x_out, y_out;
  1563 
  1564   if (window == toplevel)
  1565     {
  1566       *out_x = x;
  1567       *out_y = y;
  1568       return;
  1569     }
  1570 
  1571   children = NULL;
  1572   while ((parent = gdk_window_get_parent (window)) != toplevel)
  1573     {
  1574       children = g_list_prepend (children, window);
  1575       window = parent;
  1576     }
  1577 
  1578   for (l = children; l != NULL; l = l->next)
  1579     gdk_window_coords_from_parent (l->data, x, y, &x_out, &y_out);
  1580 
  1581   g_list_free (children);
  1582 
  1583   *out_x = x_out;
  1584   *out_y = y_out;
  1585 }
  1586 
  1587 static GdkWindow *
  1588 xw_find_common_ancestor (GdkWindow *window,
  1589                          GdkWindow *other,
  1590                          GdkWindow *toplevel)
  1591 {
  1592   GdkWindow *tem;
  1593   GList *l1 = NULL;
  1594   GList *l2 = NULL;
  1595   GList *i1, *i2;
  1596 
  1597   tem = window;
  1598   while (tem && tem != toplevel)
  1599     {
  1600       l1 = g_list_prepend (l1, tem);
  1601       tem = gdk_window_get_parent (tem);
  1602     }
  1603 
  1604   tem = other;
  1605   while (tem && tem != toplevel)
  1606     {
  1607       l2 = g_list_prepend (l2, tem);
  1608       tem = gdk_window_get_parent (tem);
  1609     }
  1610 
  1611   tem = NULL;
  1612   i1 = l1;
  1613   i2 = l2;
  1614 
  1615   while (i1 && i2 && (i1->data == i2->data))
  1616     {
  1617       tem = i1->data;
  1618       i1 = i1->next;
  1619       i2 = i2->next;
  1620     }
  1621 
  1622   g_list_free (l1);
  1623   g_list_free (l2);
  1624 
  1625   return tem;
  1626 }
  1627 
  1628 static void
  1629 xw_notify_virtual_upwards_until (struct xwidget_view *xv,
  1630                                  GdkWindow *window,
  1631                                  GdkWindow *until,
  1632                                  GdkWindow *toplevel,
  1633                                  unsigned int state,
  1634                                  int x, int y, Time time,
  1635                                  GdkEventType type,
  1636                                  bool nonlinear_p,
  1637                                  GdkCrossingMode crossing)
  1638 {
  1639   GdkEvent *xg_event;
  1640   GdkWindow *tem;
  1641   int cx, cy;
  1642 
  1643   for (tem = gdk_window_get_parent (window);
  1644        tem && (tem != until);
  1645        tem = gdk_window_get_parent (tem))
  1646     {
  1647       xg_event = gdk_event_new (type);
  1648 
  1649       gdk_event_set_device (xg_event,
  1650                             find_suitable_pointer (xv->frame, false));
  1651       window_coords_from_toplevel (tem, toplevel, x, y, &cx, &cy);
  1652       xg_event->crossing.x = cx;
  1653       xg_event->crossing.y = cy;
  1654       xg_event->crossing.time = time;
  1655       xg_event->crossing.focus = FALSE;
  1656       xg_event->crossing.detail = (nonlinear_p
  1657                                    ? GDK_NOTIFY_NONLINEAR_VIRTUAL
  1658                                    : GDK_NOTIFY_VIRTUAL);
  1659       xg_event->crossing.mode = crossing;
  1660       xg_event->crossing.window = g_object_ref (tem);
  1661 
  1662       gtk_main_do_event (xg_event);
  1663       gdk_event_free (xg_event);
  1664     }
  1665 }
  1666 
  1667 static void
  1668 xw_notify_virtual_downwards_until (struct xwidget_view *xv,
  1669                                    GdkWindow *window,
  1670                                    GdkWindow *until,
  1671                                    GdkWindow *toplevel,
  1672                                    unsigned int state,
  1673                                    int x, int y, Time time,
  1674                                    GdkEventType type,
  1675                                    bool nonlinear_p,
  1676                                    GdkCrossingMode crossing)
  1677 {
  1678   GdkEvent *xg_event;
  1679   GdkWindow *tem;
  1680   int cx, cy;
  1681   GList *path = NULL, *it;
  1682 
  1683   tem = gdk_window_get_parent (window);
  1684 
  1685   while (tem && tem != until)
  1686     {
  1687       path = g_list_prepend (path, tem);
  1688       tem = gdk_window_get_parent (tem);
  1689     }
  1690 
  1691   for (it = path; it; it = it->next)
  1692     {
  1693       tem = it->data;
  1694       xg_event = gdk_event_new (type);
  1695 
  1696       gdk_event_set_device (xg_event,
  1697                             find_suitable_pointer (xv->frame, false));
  1698       window_coords_from_toplevel (tem, toplevel, x, y, &cx, &cy);
  1699       xg_event->crossing.x = cx;
  1700       xg_event->crossing.y = cy;
  1701       xg_event->crossing.time = time;
  1702       xg_event->crossing.focus = FALSE;
  1703       xg_event->crossing.detail = (nonlinear_p
  1704                                    ? GDK_NOTIFY_NONLINEAR_VIRTUAL
  1705                                    : GDK_NOTIFY_VIRTUAL);
  1706       xg_event->crossing.mode = crossing;
  1707       xg_event->crossing.window = g_object_ref (tem);
  1708 
  1709       gtk_main_do_event (xg_event);
  1710       gdk_event_free (xg_event);
  1711     }
  1712 
  1713   g_list_free (path);
  1714 }
  1715 
  1716 static void
  1717 xw_update_cursor_for_view (struct xwidget_view *xv,
  1718                            GdkWindow *crossing_window)
  1719 {
  1720   GdkCursor *xg_cursor;
  1721   Cursor cursor;
  1722 
  1723   xg_cursor = gdk_window_get_cursor (crossing_window);
  1724 
  1725   if (xg_cursor)
  1726     {
  1727       cursor = gdk_x11_cursor_get_xcursor (xg_cursor);
  1728 
  1729       if (gdk_x11_cursor_get_xdisplay (xg_cursor) == xv->dpy)
  1730         xv->cursor = cursor;
  1731     }
  1732   else
  1733     xv->cursor = FRAME_OUTPUT_DATA (xv->frame)->nontext_cursor;
  1734 
  1735   if (xv->wdesc != None)
  1736     XDefineCursor (xv->dpy, xv->wdesc, xv->cursor);
  1737 }
  1738 
  1739 static void
  1740 xw_last_crossing_cursor_cb (GdkWindow *window,
  1741                             GParamSpec *spec,
  1742                             gpointer user_data)
  1743 {
  1744   xw_update_cursor_for_view (user_data, window);
  1745 }
  1746 
  1747 static bool
  1748 xw_maybe_synthesize_crossing (struct xwidget_view *view,
  1749                               GdkWindow *current_window,
  1750                               int x, int y, int crossing,
  1751                               Time time, unsigned int state,
  1752                               GdkCrossingMode entry_crossing,
  1753                               GdkCrossingMode exit_crossing)
  1754 {
  1755   GdkWindow *last_crossing, *toplevel, *ancestor;
  1756   GdkEvent *xg_event;
  1757   int cx, cy;
  1758   bool nonlinear_p;
  1759   bool retention_flag;
  1760 
  1761 #if WEBKIT_CHECK_VERSION (2, 34, 0)
  1762   /* Work around a silly bug in WebKitGTK+ that tries to make tooltip
  1763      windows transient for our offscreen window.  */
  1764   int tooltip_width, tooltip_height;
  1765 
  1766   xg_prepare_tooltip (view->frame, dummy_tooltip_string,
  1767                       &tooltip_width, &tooltip_height);
  1768 #endif
  1769 
  1770   toplevel = gtk_widget_get_window (XXWIDGET (view->model)->widgetwindow_osr);
  1771   retention_flag = false;
  1772 
  1773   if (crossing == XW_CROSSING_LEFT
  1774       && (view->last_crossing_window
  1775           && !gdk_window_is_destroyed (view->last_crossing_window)))
  1776     {
  1777       xw_notify_virtual_upwards_until (view, view->last_crossing_window,
  1778                                        toplevel, toplevel,
  1779                                        state, x, y, time,
  1780                                        GDK_LEAVE_NOTIFY, false,
  1781                                        exit_crossing);
  1782     }
  1783 
  1784   if (view->last_crossing_window
  1785       && (gdk_window_is_destroyed (view->last_crossing_window)
  1786           || crossing == XW_CROSSING_LEFT))
  1787     {
  1788       if (!gdk_window_is_destroyed (view->last_crossing_window)
  1789           && view->last_crossing_window != toplevel)
  1790         {
  1791           xg_event = gdk_event_new (GDK_LEAVE_NOTIFY);
  1792           window_coords_from_toplevel (view->last_crossing_window,
  1793                                        toplevel, x, y, &cx, &cy);
  1794 
  1795           xg_event->crossing.x = cx;
  1796           xg_event->crossing.y = cy;
  1797           xg_event->crossing.time = time;
  1798           xg_event->crossing.focus = FALSE;
  1799           xg_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
  1800           xg_event->crossing.mode = exit_crossing;
  1801           xg_event->crossing.window = g_object_ref (view->last_crossing_window);
  1802           gdk_event_set_device (xg_event,
  1803                                 find_suitable_pointer (view->frame, false));
  1804 
  1805           gtk_main_do_event (xg_event);
  1806           gdk_event_free (xg_event);
  1807 
  1808           xw_notify_virtual_upwards_until (view, view->last_crossing_window,
  1809                                            gdk_window_get_parent (toplevel),
  1810                                            toplevel, state, x, y, time,
  1811                                            GDK_LEAVE_NOTIFY, false, exit_crossing);
  1812           retention_flag = true;
  1813         }
  1814 
  1815       g_signal_handler_disconnect (view->last_crossing_window,
  1816                                    view->last_crossing_cursor_signal);
  1817       g_clear_pointer (&view->last_crossing_window,
  1818                        g_object_unref);
  1819     }
  1820   last_crossing = view->last_crossing_window;
  1821 
  1822   if (!last_crossing)
  1823     {
  1824       if (current_window)
  1825         {
  1826           view->last_crossing_window = g_object_ref (current_window);
  1827           xw_update_cursor_for_view (view, current_window);
  1828           view->last_crossing_cursor_signal
  1829             = g_signal_connect (G_OBJECT (current_window), "notify::cursor",
  1830                                 G_CALLBACK (xw_last_crossing_cursor_cb), view);
  1831 
  1832           xw_notify_virtual_downwards_until (view, current_window,
  1833                                              toplevel, toplevel,
  1834                                              state, x, y, time,
  1835                                              GDK_ENTER_NOTIFY,
  1836                                              false, entry_crossing);
  1837         }
  1838       return retention_flag;
  1839     }
  1840 
  1841   if (last_crossing != current_window)
  1842     {
  1843       view->last_crossing_window = g_object_ref (current_window);
  1844       g_signal_handler_disconnect (last_crossing, view->last_crossing_cursor_signal);
  1845 
  1846       xw_update_cursor_for_view (view, current_window);
  1847       view->last_crossing_cursor_signal
  1848         = g_signal_connect (G_OBJECT (current_window), "notify::cursor",
  1849                             G_CALLBACK (xw_last_crossing_cursor_cb), view);
  1850 
  1851       ancestor = xw_find_common_ancestor (last_crossing, current_window, toplevel);
  1852 
  1853       if (!ancestor)
  1854         emacs_abort ();
  1855 
  1856       nonlinear_p = (last_crossing != ancestor) && (current_window != ancestor);
  1857 
  1858       if (nonlinear_p || (last_crossing != ancestor))
  1859         xw_notify_virtual_upwards_until (view, last_crossing,
  1860                                          ancestor, toplevel,
  1861                                          state, x, y, time,
  1862                                          GDK_LEAVE_NOTIFY,
  1863                                          nonlinear_p,
  1864                                          exit_crossing);
  1865 
  1866       xg_event = gdk_event_new (GDK_LEAVE_NOTIFY);
  1867       gdk_event_set_device (xg_event,
  1868                             find_suitable_pointer (view->frame, false));
  1869       window_coords_from_toplevel (last_crossing, toplevel,
  1870                                    x, y, &cx, &cy);
  1871       xg_event->crossing.x = cx;
  1872       xg_event->crossing.y = cy;
  1873       xg_event->crossing.time = time;
  1874       xg_event->crossing.focus = FALSE;
  1875       xg_event->crossing.state = state;
  1876       xg_event->crossing.detail = (nonlinear_p
  1877                                    ? GDK_NOTIFY_NONLINEAR
  1878                                    : (last_crossing == ancestor
  1879                                       ? GDK_NOTIFY_INFERIOR
  1880                                       : GDK_NOTIFY_ANCESTOR));
  1881       xg_event->crossing.mode = exit_crossing;
  1882       xg_event->crossing.window = g_object_ref (last_crossing);
  1883 
  1884       gtk_main_do_event (xg_event);
  1885       gdk_event_free (xg_event);
  1886 
  1887       if (nonlinear_p || (current_window != ancestor))
  1888         xw_notify_virtual_downwards_until (view, current_window,
  1889                                            ancestor, toplevel,
  1890                                            state, x, y, time,
  1891                                            GDK_ENTER_NOTIFY,
  1892                                            nonlinear_p,
  1893                                            entry_crossing);
  1894 
  1895       xg_event = gdk_event_new (GDK_ENTER_NOTIFY);
  1896       gdk_event_set_device (xg_event,
  1897                             find_suitable_pointer (view->frame, false));
  1898       window_coords_from_toplevel (current_window, toplevel,
  1899                                    x, y, &cx, &cy);
  1900       xg_event->crossing.x = cx;
  1901       xg_event->crossing.y = cy;
  1902       xg_event->crossing.time = time;
  1903       xg_event->crossing.focus = FALSE;
  1904       xg_event->crossing.state = state;
  1905       xg_event->crossing.detail = (nonlinear_p
  1906                                    ? GDK_NOTIFY_NONLINEAR
  1907                                    : (current_window == ancestor
  1908                                       ? GDK_NOTIFY_INFERIOR
  1909                                       : GDK_NOTIFY_ANCESTOR));
  1910       xg_event->crossing.mode = entry_crossing;
  1911       xg_event->crossing.window = g_object_ref (current_window);
  1912 
  1913       gtk_main_do_event (xg_event);
  1914       gdk_event_free (xg_event);
  1915       g_object_unref (last_crossing);
  1916 
  1917       return true;
  1918     }
  1919 
  1920   return false;
  1921 }
  1922 
  1923 void
  1924 xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
  1925 {
  1926   GdkEvent *xg_event;
  1927   struct xwidget *model = XXWIDGET (view->model);
  1928   int x, y, toplevel_x, toplevel_y;
  1929   GtkWidget *target;
  1930 #ifdef HAVE_XINPUT2
  1931   XIEnterEvent *xev = NULL;
  1932 #endif
  1933 
  1934   if (NILP (model->buffer))
  1935     return;
  1936 
  1937 #ifdef HAVE_XINPUT2
  1938   if (event->type != GenericEvent)
  1939 #endif
  1940     {
  1941       xg_event = gdk_event_new (event->type == MotionNotify
  1942                                 ? GDK_MOTION_NOTIFY
  1943                                 : (event->type == LeaveNotify
  1944                                    ? GDK_LEAVE_NOTIFY
  1945                                    : GDK_ENTER_NOTIFY));
  1946       toplevel_x = (event->type == MotionNotify
  1947                     ? event->xmotion.x + view->clip_left
  1948                     : event->xcrossing.x + view->clip_left);
  1949       toplevel_y = (event->type == MotionNotify
  1950                     ? event->xmotion.y + view->clip_top
  1951                     : event->xcrossing.y + view->clip_top);
  1952       target = find_widget_at_pos (model->widgetwindow_osr,
  1953                                    toplevel_x, toplevel_y, &x, &y,
  1954                                    true, view);
  1955     }
  1956 #ifdef HAVE_XINPUT2
  1957   else
  1958     {
  1959       eassert (event->xcookie.evtype == XI_Enter
  1960                || event->xcookie.evtype == XI_Leave);
  1961 
  1962       xev = (XIEnterEvent *) event->xcookie.data;
  1963       xg_event = gdk_event_new (event->type == XI_Enter
  1964                                 ? GDK_ENTER_NOTIFY
  1965                                 : GDK_LEAVE_NOTIFY);
  1966       target = find_widget_at_pos (model->widgetwindow_osr,
  1967                                    (toplevel_x
  1968                                     = lrint (xev->event_x + view->clip_left)),
  1969                                    (toplevel_y
  1970                                     = lrint (xev->event_y + view->clip_top)),
  1971                                    &x, &y, true, view);
  1972     }
  1973 #endif
  1974 
  1975   if (!target)
  1976     target = model->widget_osr;
  1977 
  1978   record_osr_embedder (view);
  1979   xg_event->any.window = gtk_widget_get_window (target);
  1980   g_object_ref (xg_event->any.window); /* The window will be unrefed
  1981                                           later by gdk_event_free.  */
  1982 
  1983   if (event->type == MotionNotify)
  1984     {
  1985       if (!xw_maybe_synthesize_crossing (view, xg_event->any.window,
  1986                                          toplevel_x, toplevel_y,
  1987                                          XW_CROSSING_NONE, event->xmotion.time,
  1988                                          event->xmotion.state,
  1989                                          (view->passive_grab
  1990                                           ? GDK_CROSSING_GRAB
  1991                                           : GDK_CROSSING_NORMAL),
  1992                                          GDK_CROSSING_NORMAL))
  1993         {
  1994           xg_event->motion.x = x;
  1995           xg_event->motion.y = y;
  1996           xg_event->motion.x_root = event->xmotion.x_root;
  1997           xg_event->motion.y_root = event->xmotion.y_root;
  1998           xg_event->motion.time = event->xmotion.time;
  1999           xg_event->motion.state = event->xmotion.state;
  2000           xg_event->motion.device
  2001             = find_suitable_pointer (view->frame, false);
  2002         }
  2003       else
  2004         {
  2005           gdk_event_free (xg_event);
  2006           return;
  2007         }
  2008     }
  2009 #ifdef HAVE_XINPUT2
  2010   else if (event->type == GenericEvent)
  2011     {
  2012       xg_event->crossing.x = x;
  2013       xg_event->crossing.y = y;
  2014       xg_event->crossing.x_root = (gdouble) xev->root_x;
  2015       xg_event->crossing.y_root = (gdouble) xev->root_y;
  2016       xg_event->crossing.time = xev->time;
  2017       xg_event->crossing.focus = xev->focus;
  2018       xg_event->crossing.mode = xev->mode;
  2019       xg_event->crossing.detail = xi_translate_notify_detail (xev->detail);
  2020       xg_event->crossing.state = xev->mods.effective;
  2021 
  2022       if (xev->buttons.mask_len)
  2023         {
  2024           if (XIMaskIsSet (xev->buttons.mask, 1))
  2025             xg_event->crossing.state |= GDK_BUTTON1_MASK;
  2026           if (XIMaskIsSet (xev->buttons.mask, 2))
  2027             xg_event->crossing.state |= GDK_BUTTON2_MASK;
  2028           if (XIMaskIsSet (xev->buttons.mask, 3))
  2029             xg_event->crossing.state |= GDK_BUTTON3_MASK;
  2030         }
  2031 
  2032       if (view->passive_grab
  2033           || xw_maybe_synthesize_crossing (view, xg_event->any.window,
  2034                                            toplevel_x, toplevel_y,
  2035                                            (xev->type == XI_Enter
  2036                                             ? XW_CROSSING_ENTERED
  2037                                             : XW_CROSSING_LEFT),
  2038                                            xev->time, xg_event->crossing.state,
  2039                                            (view->passive_grab
  2040                                             ? GDK_CROSSING_GRAB
  2041                                             : GDK_CROSSING_NORMAL),
  2042                                            GDK_CROSSING_NORMAL))
  2043         {
  2044           gdk_event_free (xg_event);
  2045           return;
  2046         }
  2047 
  2048       gdk_event_set_device (xg_event,
  2049                             find_suitable_pointer (view->frame, false));
  2050     }
  2051 #endif
  2052   else
  2053     {
  2054       if (view->passive_grab
  2055           || xw_maybe_synthesize_crossing (view, xg_event->any.window,
  2056                                            toplevel_x, toplevel_y,
  2057                                            (event->type == EnterNotify
  2058                                             ? XW_CROSSING_ENTERED
  2059                                             : XW_CROSSING_LEFT),
  2060                                            event->xcrossing.time,
  2061                                            event->xcrossing.state,
  2062                                            (view->passive_grab
  2063                                             ? GDK_CROSSING_GRAB
  2064                                             : GDK_CROSSING_NORMAL),
  2065                                            GDK_CROSSING_NORMAL))
  2066         {
  2067           gdk_event_free (xg_event);
  2068           return;
  2069         }
  2070 
  2071       xg_event->crossing.detail = min (5, event->xcrossing.detail);
  2072       xg_event->crossing.time = event->xcrossing.time;
  2073       xg_event->crossing.x = x;
  2074       xg_event->crossing.y = y;
  2075       xg_event->crossing.x_root = event->xcrossing.x_root;
  2076       xg_event->crossing.y_root = event->xcrossing.y_root;
  2077       xg_event->crossing.focus = event->xcrossing.focus;
  2078       gdk_event_set_device (xg_event,
  2079                             find_suitable_pointer (view->frame, false));
  2080     }
  2081 
  2082   gtk_main_do_event (xg_event);
  2083   gdk_event_free (xg_event);
  2084 }
  2085 
  2086 #endif /* HAVE_X_WINDOWS */
  2087 
  2088 static void
  2089 synthesize_focus_in_event (GtkWidget *offscreen_window)
  2090 {
  2091   GdkWindow *wnd;
  2092   GdkEvent *focus_event;
  2093 
  2094   if (!gtk_widget_get_realized (offscreen_window))
  2095     gtk_widget_realize (offscreen_window);
  2096 
  2097   wnd = gtk_widget_get_window (offscreen_window);
  2098 
  2099   focus_event = gdk_event_new (GDK_FOCUS_CHANGE);
  2100   focus_event->focus_change.window = wnd;
  2101   focus_event->focus_change.in = TRUE;
  2102 
  2103   if (FRAME_WINDOW_P (SELECTED_FRAME ()))
  2104     gdk_event_set_device (focus_event,
  2105                           find_suitable_pointer (SELECTED_FRAME (),
  2106                                                  false));
  2107 
  2108   g_object_ref (wnd);
  2109 
  2110   gtk_main_do_event (focus_event);
  2111   gdk_event_free (focus_event);
  2112 }
  2113 
  2114 #ifdef HAVE_X_WINDOWS
  2115 struct xwidget_view *
  2116 xwidget_view_from_window (Window wdesc)
  2117 {
  2118   Lisp_Object key = make_fixnum (wdesc);
  2119   Lisp_Object xwv = Fgethash (key, x_window_to_xwv_map, Qnil);
  2120 
  2121   if (NILP (xwv))
  2122     return NULL;
  2123 
  2124   return XXWIDGET_VIEW (xwv);
  2125 }
  2126 #endif
  2127 
  2128 static void
  2129 xwidget_show_view (struct xwidget_view *xv)
  2130 {
  2131   xv->hidden = false;
  2132 #ifdef HAVE_X_WINDOWS
  2133   XMoveWindow (xv->dpy, xv->wdesc,
  2134                xv->x + xv->clip_left,
  2135                xv->y + xv->clip_top);
  2136   XMapWindow (xv->dpy, xv->wdesc);
  2137   XFlush (xv->dpy);
  2138 #else
  2139   gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (xv->frame)),
  2140                   xv->widget, xv->x + xv->clip_left,
  2141                   xv->y + xv->clip_top);
  2142   gtk_widget_show_all (xv->widget);
  2143 #endif
  2144 }
  2145 
  2146 /* Hide an xwidget view.  */
  2147 static void
  2148 xwidget_hide_view (struct xwidget_view *xv)
  2149 {
  2150   xv->hidden = true;
  2151 #ifdef HAVE_X_WINDOWS
  2152   XUnmapWindow (xv->dpy, xv->wdesc);
  2153   XFlush (xv->dpy);
  2154 #else
  2155   gtk_widget_hide (xv->widget);
  2156 #endif
  2157 }
  2158 
  2159 #ifndef HAVE_PGTK
  2160 static void
  2161 xv_do_draw (struct xwidget_view *xw, struct xwidget *w)
  2162 {
  2163   GtkOffscreenWindow *wnd;
  2164   cairo_surface_t *surface;
  2165 
  2166   if (xw->just_resized)
  2167     return;
  2168 
  2169   if (NILP (w->buffer))
  2170     {
  2171       XClearWindow (xw->dpy, xw->wdesc);
  2172       return;
  2173     }
  2174 
  2175   block_input ();
  2176   wnd = GTK_OFFSCREEN_WINDOW (w->widgetwindow_osr);
  2177   surface = gtk_offscreen_window_get_surface (wnd);
  2178 
  2179   cairo_save (xw->cr_context);
  2180   if (surface)
  2181     {
  2182       cairo_translate (xw->cr_context, -xw->clip_left, -xw->clip_top);
  2183       cairo_set_source_surface (xw->cr_context, surface, 0, 0);
  2184       cairo_set_operator (xw->cr_context, CAIRO_OPERATOR_SOURCE);
  2185       cairo_paint (xw->cr_context);
  2186     }
  2187   cairo_restore (xw->cr_context);
  2188 
  2189   unblock_input ();
  2190 }
  2191 #else
  2192 static void
  2193 xwidget_view_draw_cb (GtkWidget *widget, cairo_t *cr,
  2194                       gpointer data)
  2195 {
  2196   struct xwidget_view *view = data;
  2197   struct xwidget *w = XXWIDGET (view->model);
  2198   GtkOffscreenWindow *wnd;
  2199   cairo_surface_t *surface;
  2200 
  2201   if (NILP (w->buffer))
  2202     return;
  2203 
  2204   block_input ();
  2205   wnd = GTK_OFFSCREEN_WINDOW (w->widgetwindow_osr);
  2206   surface = gtk_offscreen_window_get_surface (wnd);
  2207 
  2208   cairo_save (cr);
  2209   if (surface)
  2210     {
  2211       cairo_translate (cr, -view->clip_left,
  2212                        -view->clip_top);
  2213       cairo_set_source_surface (cr, surface, 0, 0);
  2214       cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
  2215       cairo_paint (cr);
  2216     }
  2217   cairo_restore (cr);
  2218 
  2219   unblock_input ();
  2220 }
  2221 #endif
  2222 
  2223 /* When the off-screen webkit master view changes this signal is called.
  2224    It copies the bitmap from the off-screen instance.  */
  2225 static gboolean
  2226 offscreen_damage_event (GtkWidget *widget, GdkEvent *event,
  2227                         gpointer xwidget)
  2228 {
  2229   block_input ();
  2230 
  2231   for (Lisp_Object tail = internal_xwidget_view_list; CONSP (tail);
  2232        tail = XCDR (tail))
  2233     {
  2234       if (XWIDGET_VIEW_P (XCAR (tail)))
  2235         {
  2236           struct xwidget_view *view = XXWIDGET_VIEW (XCAR (tail));
  2237 #ifdef HAVE_X_WINDOWS
  2238           if (view->wdesc && XXWIDGET (view->model) == xwidget)
  2239             xv_do_draw (view, XXWIDGET (view->model));
  2240 #else
  2241           gtk_widget_queue_draw (view->widget);
  2242 #endif
  2243         }
  2244     }
  2245 
  2246   unblock_input ();
  2247 
  2248   return FALSE;
  2249 }
  2250 
  2251 #ifdef HAVE_X_WINDOWS
  2252 void
  2253 xwidget_expose (struct xwidget_view *xv)
  2254 {
  2255   struct xwidget *xw = XXWIDGET (xv->model);
  2256 
  2257   xv_do_draw (xv, xw);
  2258 }
  2259 #endif
  2260 #endif /* USE_GTK */
  2261 
  2262 void
  2263 store_xwidget_event_string (struct xwidget *xw, const char *eventname,
  2264                             const char *eventstr)
  2265 {
  2266   struct input_event event;
  2267   Lisp_Object xwl;
  2268   XSETXWIDGET (xwl, xw);
  2269   EVENT_INIT (event);
  2270   event.kind = XWIDGET_EVENT;
  2271   event.frame_or_window = Qnil;
  2272   event.arg = list3 (intern (eventname), xwl, build_string (eventstr));
  2273   kbd_buffer_store_event (&event);
  2274 }
  2275 
  2276 void
  2277 store_xwidget_download_callback_event (struct xwidget *xw,
  2278                                        const char *url,
  2279                                        const char *mimetype,
  2280                                        const char *filename)
  2281 {
  2282   struct input_event event;
  2283   Lisp_Object xwl;
  2284   XSETXWIDGET (xwl, xw);
  2285   EVENT_INIT (event);
  2286   event.kind = XWIDGET_EVENT;
  2287   event.frame_or_window = Qnil;
  2288   event.arg = list5 (intern ("download-callback"),
  2289                      xwl,
  2290                      build_string (url),
  2291                      build_string (mimetype),
  2292                      build_string (filename));
  2293   kbd_buffer_store_event (&event);
  2294 }
  2295 
  2296 void
  2297 store_xwidget_js_callback_event (struct xwidget *xw,
  2298                                  Lisp_Object proc,
  2299                                  Lisp_Object argument)
  2300 {
  2301   struct input_event event;
  2302   Lisp_Object xwl;
  2303   XSETXWIDGET (xwl, xw);
  2304   EVENT_INIT (event);
  2305   event.kind = XWIDGET_EVENT;
  2306   event.frame_or_window = Qnil;
  2307   event.arg = list4 (intern ("javascript-callback"), xwl, proc, argument);
  2308   kbd_buffer_store_event (&event);
  2309 }
  2310 
  2311 
  2312 #ifdef USE_GTK
  2313 static void
  2314 store_xwidget_display_event (struct xwidget *xw,
  2315                              struct xwidget *src)
  2316 {
  2317   struct input_event evt;
  2318   Lisp_Object val, src_val;
  2319 
  2320   XSETXWIDGET (val, xw);
  2321   XSETXWIDGET (src_val, src);
  2322   EVENT_INIT (evt);
  2323   evt.kind = XWIDGET_DISPLAY_EVENT;
  2324   evt.frame_or_window = Qnil;
  2325   evt.arg = list2 (val, src_val);
  2326   kbd_buffer_store_event (&evt);
  2327 }
  2328 
  2329 static void
  2330 webkit_ready_to_show (WebKitWebView *new_view,
  2331                       gpointer user_data)
  2332 {
  2333   Lisp_Object tem;
  2334   struct xwidget *xw;
  2335   struct xwidget *src;
  2336 
  2337   src = find_xwidget_for_offscreen_window (GDK_WINDOW (user_data));
  2338 
  2339   for (tem = internal_xwidget_list; CONSP (tem); tem = XCDR (tem))
  2340     {
  2341       if (XWIDGETP (XCAR (tem)))
  2342         {
  2343           xw = XXWIDGET (XCAR (tem));
  2344 
  2345           if (EQ (xw->type, Qwebkit)
  2346               && WEBKIT_WEB_VIEW (xw->widget_osr) == new_view)
  2347             {
  2348               /* The source widget was destroyed before we had a
  2349                  chance to display the new widget.  */
  2350               if (!src)
  2351                 kill_xwidget (xw);
  2352               else
  2353                 store_xwidget_display_event (xw, src);
  2354             }
  2355         }
  2356     }
  2357 }
  2358 
  2359 static GtkWidget *
  2360 webkit_create_cb_1 (WebKitWebView *webview,
  2361                     struct xwidget *xv)
  2362 {
  2363   Lisp_Object related;
  2364   Lisp_Object xwidget;
  2365   GtkWidget *widget;
  2366 
  2367   XSETXWIDGET (related, xv);
  2368   xwidget = Fmake_xwidget (Qwebkit, Qnil, make_fixnum (0),
  2369                            make_fixnum (0), Qnil,
  2370                            build_string (" *detached xwidget buffer*"),
  2371                            related);
  2372 
  2373   if (NILP (xwidget))
  2374     return NULL;
  2375 
  2376   widget = XXWIDGET (xwidget)->widget_osr;
  2377 
  2378   g_signal_connect (G_OBJECT (widget), "ready-to-show",
  2379                     G_CALLBACK (webkit_ready_to_show),
  2380                     gtk_widget_get_window (xv->widgetwindow_osr));
  2381 
  2382   return widget;
  2383 }
  2384 
  2385 static GtkWidget *
  2386 webkit_create_cb (WebKitWebView *webview,
  2387                   WebKitNavigationAction *nav_action,
  2388                   gpointer user_data)
  2389 {
  2390   switch (webkit_navigation_action_get_navigation_type (nav_action))
  2391     {
  2392     case WEBKIT_NAVIGATION_TYPE_OTHER:
  2393       return webkit_create_cb_1 (webview, user_data);
  2394 
  2395     case WEBKIT_NAVIGATION_TYPE_BACK_FORWARD:
  2396     case WEBKIT_NAVIGATION_TYPE_RELOAD:
  2397     case WEBKIT_NAVIGATION_TYPE_FORM_SUBMITTED:
  2398     case WEBKIT_NAVIGATION_TYPE_FORM_RESUBMITTED:
  2399     case WEBKIT_NAVIGATION_TYPE_LINK_CLICKED:
  2400     default:
  2401       return NULL;
  2402     }
  2403 }
  2404 
  2405 void
  2406 webkit_view_load_changed_cb (WebKitWebView *webkitwebview,
  2407                              WebKitLoadEvent load_event,
  2408                              gpointer data)
  2409 {
  2410   struct xwidget *xw = g_object_get_data (G_OBJECT (webkitwebview),
  2411                                           XG_XWIDGET);
  2412 
  2413   switch (load_event)
  2414     {
  2415     case WEBKIT_LOAD_FINISHED:
  2416       store_xwidget_event_string (xw, "load-changed", "load-finished");
  2417       break;
  2418     case WEBKIT_LOAD_STARTED:
  2419       store_xwidget_event_string (xw, "load-changed", "load-started");
  2420       break;
  2421     case WEBKIT_LOAD_REDIRECTED:
  2422       store_xwidget_event_string (xw, "load-changed", "load-redirected");
  2423       break;
  2424     case WEBKIT_LOAD_COMMITTED:
  2425       store_xwidget_event_string (xw, "load-changed", "load-committed");
  2426       break;
  2427     }
  2428 }
  2429 
  2430 /* Recursively convert a JavaScript value to a Lisp value. */
  2431 static Lisp_Object
  2432 webkit_js_to_lisp (JSCValue *value)
  2433 {
  2434   if (jsc_value_is_string (value))
  2435     {
  2436       gchar *str_value = jsc_value_to_string (value);
  2437       Lisp_Object ret = build_string (str_value);
  2438       g_free (str_value);
  2439 
  2440       return ret;
  2441     }
  2442   else if (jsc_value_is_boolean (value))
  2443     {
  2444       return (jsc_value_to_boolean (value)) ? Qt : Qnil;
  2445     }
  2446   else if (jsc_value_is_number (value))
  2447     {
  2448       return make_fixnum (jsc_value_to_int32 (value));
  2449     }
  2450   else if (jsc_value_is_array (value))
  2451     {
  2452       JSCValue *len = jsc_value_object_get_property (value, "length");
  2453       const gint32 dlen = jsc_value_to_int32 (len);
  2454 
  2455       Lisp_Object obj;
  2456       if (! (0 <= dlen && dlen < G_MAXINT32))
  2457         memory_full (SIZE_MAX);
  2458 
  2459       ptrdiff_t n = dlen;
  2460       struct Lisp_Vector *p = allocate_nil_vector (n);
  2461 
  2462       for (ptrdiff_t i = 0; i < n; ++i)
  2463         {
  2464           p->contents[i] =
  2465             webkit_js_to_lisp (jsc_value_object_get_property_at_index (value, i));
  2466         }
  2467       XSETVECTOR (obj, p);
  2468       return obj;
  2469     }
  2470   else if (jsc_value_is_object (value))
  2471     {
  2472       char **properties_names = jsc_value_object_enumerate_properties (value);
  2473       guint n = g_strv_length (properties_names);
  2474 
  2475       Lisp_Object obj;
  2476       if (PTRDIFF_MAX < n)
  2477         memory_full (n);
  2478       struct Lisp_Vector *p = allocate_nil_vector (n);
  2479 
  2480       for (ptrdiff_t i = 0; i < n; ++i)
  2481         {
  2482           const char *name = properties_names[i];
  2483           JSCValue *property = jsc_value_object_get_property (value, name);
  2484 
  2485           p->contents[i] =
  2486             Fcons (build_string (name), webkit_js_to_lisp (property));
  2487         }
  2488 
  2489       g_strfreev (properties_names);
  2490 
  2491       XSETVECTOR (obj, p);
  2492       return obj;
  2493     }
  2494 
  2495   return Qnil;
  2496 }
  2497 
  2498 static void
  2499 webkit_javascript_finished_cb (GObject      *webview,
  2500                                GAsyncResult *result,
  2501                                gpointer      arg)
  2502 {
  2503   GError *error = NULL;
  2504   struct xwidget *xw = g_object_get_data (G_OBJECT (webview), XG_XWIDGET);
  2505 
  2506   ptrdiff_t script_idx = (intptr_t) arg;
  2507   Lisp_Object script_callback = AREF (xw->script_callbacks, script_idx);
  2508   ASET (xw->script_callbacks, script_idx, Qnil);
  2509   if (!NILP (script_callback))
  2510     xfree (xmint_pointer (XCAR (script_callback)));
  2511 
  2512   WebKitJavascriptResult *js_result =
  2513     webkit_web_view_run_javascript_finish
  2514     (WEBKIT_WEB_VIEW (webview), result, &error);
  2515 
  2516   if (!js_result)
  2517     {
  2518       if (error)
  2519         g_error_free (error);
  2520       return;
  2521     }
  2522 
  2523   if (!NILP (script_callback) && !NILP (XCDR (script_callback)))
  2524     {
  2525       JSCValue *value = webkit_javascript_result_get_js_value (js_result);
  2526 
  2527       Lisp_Object lisp_value = webkit_js_to_lisp (value);
  2528 
  2529       /* Register an xwidget event here, which then runs the callback.
  2530          This ensures that the callback runs in sync with the Emacs
  2531          event loop.  */
  2532       store_xwidget_js_callback_event (xw, XCDR (script_callback), lisp_value);
  2533     }
  2534 
  2535   webkit_javascript_result_unref (js_result);
  2536 }
  2537 
  2538 
  2539 gboolean
  2540 webkit_download_cb (WebKitWebContext *webkitwebcontext,
  2541                     WebKitDownload *arg1,
  2542                     gpointer data)
  2543 {
  2544   WebKitWebView *view = webkit_download_get_web_view(arg1);
  2545   WebKitURIRequest *request = webkit_download_get_request(arg1);
  2546   struct xwidget *xw = g_object_get_data (G_OBJECT (view),
  2547                                           XG_XWIDGET);
  2548 
  2549   store_xwidget_event_string (xw, "download-started",
  2550                               webkit_uri_request_get_uri(request));
  2551   return FALSE;
  2552 }
  2553 
  2554 static gboolean
  2555 webkit_decide_policy_cb (WebKitWebView *webView,
  2556                          WebKitPolicyDecision *decision,
  2557                          WebKitPolicyDecisionType type,
  2558                          gpointer user_data)
  2559 {
  2560   switch (type) {
  2561   case WEBKIT_POLICY_DECISION_TYPE_RESPONSE:
  2562     /* This function makes webkit send a download signal for all unknown
  2563        mime types.  TODO: Defer the decision to Lisp, so that it's
  2564        possible to make Emacs handle mime text for instance.  */
  2565     {
  2566       WebKitResponsePolicyDecision *response =
  2567         WEBKIT_RESPONSE_POLICY_DECISION (decision);
  2568       if (!webkit_response_policy_decision_is_mime_type_supported (response))
  2569         {
  2570           webkit_policy_decision_download (decision);
  2571           return TRUE;
  2572         }
  2573       else
  2574         return FALSE;
  2575       break;
  2576     }
  2577   case WEBKIT_POLICY_DECISION_TYPE_NEW_WINDOW_ACTION:
  2578     {
  2579       WebKitNavigationPolicyDecision *navigation_decision =
  2580         WEBKIT_NAVIGATION_POLICY_DECISION (decision);
  2581       WebKitNavigationAction *navigation_action =
  2582         webkit_navigation_policy_decision_get_navigation_action (navigation_decision);
  2583       WebKitURIRequest *request =
  2584         webkit_navigation_action_get_request (navigation_action);
  2585       WebKitWebView *newview;
  2586       struct xwidget *xw = g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
  2587       Lisp_Object val, new_xwidget;
  2588 
  2589       XSETXWIDGET (val, xw);
  2590 
  2591       new_xwidget = Fmake_xwidget (Qwebkit, Qnil, make_fixnum (0),
  2592                                    make_fixnum (0), Qnil,
  2593                                    build_string (" *detached xwidget buffer*"),
  2594                                    val);
  2595 
  2596       if (NILP (new_xwidget))
  2597         return FALSE;
  2598 
  2599       newview = WEBKIT_WEB_VIEW (XXWIDGET (new_xwidget)->widget_osr);
  2600       webkit_web_view_load_request (newview, request);
  2601 
  2602       store_xwidget_display_event (XXWIDGET (new_xwidget), xw);
  2603       return TRUE;
  2604     }
  2605   case WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION:
  2606     {
  2607       WebKitNavigationPolicyDecision *navigation_decision =
  2608         WEBKIT_NAVIGATION_POLICY_DECISION (decision);
  2609       WebKitNavigationAction *navigation_action =
  2610         webkit_navigation_policy_decision_get_navigation_action (navigation_decision);
  2611       WebKitURIRequest *request =
  2612         webkit_navigation_action_get_request (navigation_action);
  2613 
  2614       struct xwidget *xw = g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
  2615       store_xwidget_event_string (xw, "decide-policy",
  2616                                   webkit_uri_request_get_uri (request));
  2617       return FALSE;
  2618       break;
  2619     }
  2620   default:
  2621     return FALSE;
  2622   }
  2623 }
  2624 
  2625 static gboolean
  2626 webkit_script_dialog_cb (WebKitWebView *webview,
  2627                          WebKitScriptDialog *script_dialog,
  2628                          gpointer user)
  2629 {
  2630   struct frame *f = SELECTED_FRAME ();
  2631   WebKitScriptDialogType type;
  2632   GtkWidget *widget;
  2633   GtkWidget *dialog;
  2634   GtkWidget *entry;
  2635   GtkWidget *content_area;
  2636   GtkWidget *box;
  2637   GtkWidget *label;
  2638   const gchar *content;
  2639   const gchar *message;
  2640   gint result;
  2641 
  2642   /* Return TRUE to prevent WebKit from showing the default script
  2643      dialog in the offscreen window, which runs a nested main loop
  2644      Emacs can't respond to, and as such can't pass X events to.  */
  2645   if (!FRAME_WINDOW_P (f))
  2646     return TRUE;
  2647 
  2648   type = webkit_script_dialog_get_dialog_type (script_dialog);;
  2649   widget = FRAME_GTK_OUTER_WIDGET (f);
  2650   content = webkit_script_dialog_get_message (script_dialog);
  2651 
  2652   if (type == WEBKIT_SCRIPT_DIALOG_ALERT)
  2653     dialog = gtk_dialog_new_with_buttons ("Alert", GTK_WINDOW (widget),
  2654                                           GTK_DIALOG_MODAL,
  2655                                           "Dismiss", 1, NULL);
  2656   else
  2657     dialog = gtk_dialog_new_with_buttons ("Question", GTK_WINDOW (widget),
  2658                                           GTK_DIALOG_MODAL,
  2659                                           "OK", 0, "Cancel", 1, NULL);
  2660 
  2661   box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
  2662   label = gtk_label_new (content);
  2663   content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
  2664   gtk_container_add (GTK_CONTAINER (content_area), box);
  2665 
  2666   gtk_widget_show (box);
  2667   gtk_widget_show (label);
  2668 
  2669   gtk_box_pack_start (GTK_BOX (box), label, TRUE, TRUE, 0);
  2670 
  2671   if (type == WEBKIT_SCRIPT_DIALOG_PROMPT)
  2672     {
  2673       entry = gtk_entry_new ();
  2674       message = webkit_script_dialog_prompt_get_default_text (script_dialog);
  2675 
  2676       gtk_widget_show (entry);
  2677       gtk_entry_set_text (GTK_ENTRY (entry), message);
  2678       gtk_box_pack_end (GTK_BOX (box), entry, TRUE, TRUE, 0);
  2679     }
  2680 
  2681   result = gtk_dialog_run (GTK_DIALOG (dialog));
  2682 
  2683   if (type == WEBKIT_SCRIPT_DIALOG_CONFIRM
  2684       || type == WEBKIT_SCRIPT_DIALOG_BEFORE_UNLOAD_CONFIRM)
  2685     webkit_script_dialog_confirm_set_confirmed (script_dialog, result == 0);
  2686 
  2687   if (type == WEBKIT_SCRIPT_DIALOG_PROMPT)
  2688     webkit_script_dialog_prompt_set_text (script_dialog,
  2689                                           gtk_entry_get_text (GTK_ENTRY (entry)));
  2690 
  2691   gtk_widget_destroy (GTK_WIDGET (dialog));
  2692 
  2693   return TRUE;
  2694 }
  2695 #endif /* USE_GTK */
  2696 
  2697 
  2698 /* Initializes and does initial placement of an xwidget view on screen.  */
  2699 static struct xwidget_view *
  2700 xwidget_init_view (struct xwidget *xww,
  2701                    struct glyph_string *s,
  2702                    int x, int y)
  2703 {
  2704 
  2705 #ifdef USE_GTK
  2706   if (!xg_gtk_initialized)
  2707     error ("xwidget_init_view: GTK has not been initialized");
  2708 #endif
  2709 
  2710   struct xwidget_view *xv = allocate_xwidget_view ();
  2711   Lisp_Object val;
  2712 
  2713   XSETXWIDGET_VIEW (val, xv);
  2714   internal_xwidget_view_list = Fcons (val, internal_xwidget_view_list);
  2715   Vxwidget_view_list = Fcopy_sequence (internal_xwidget_view_list);
  2716 
  2717   XSETWINDOW (xv->w, s->w);
  2718   XSETXWIDGET (xv->model, xww);
  2719 
  2720 #ifdef HAVE_X_WINDOWS
  2721   xv->dpy = FRAME_X_DISPLAY (s->f);
  2722 
  2723   xv->x = x;
  2724   xv->y = y;
  2725 
  2726   xv->clip_left = 0;
  2727   xv->clip_right = xww->width;
  2728   xv->clip_top = 0;
  2729   xv->clip_bottom = xww->height;
  2730 
  2731   xv->wdesc = None;
  2732   xv->frame = s->f;
  2733   xv->cursor = FRAME_OUTPUT_DATA (s->f)->nontext_cursor;
  2734   xv->just_resized = false;
  2735   xv->last_crossing_window = NULL;
  2736   xv->passive_grab = NULL;
  2737 #elif defined HAVE_PGTK
  2738   xv->dpyinfo = FRAME_DISPLAY_INFO (s->f);
  2739   xv->widget = gtk_drawing_area_new ();
  2740   gtk_widget_set_app_paintable (xv->widget, TRUE);
  2741   gtk_widget_add_events (xv->widget, GDK_ALL_EVENTS_MASK);
  2742   gtk_container_add (GTK_CONTAINER (FRAME_GTK_WIDGET (s->f)),
  2743                      xv->widget);
  2744 
  2745   g_signal_connect (xv->widget, "draw",
  2746                     G_CALLBACK (xwidget_view_draw_cb), xv);
  2747   g_signal_connect (xv->widget, "event",
  2748                     G_CALLBACK (xw_forward_event_from_view), xv);
  2749 
  2750   g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET_VIEW, xv);
  2751 
  2752   xv->x = x;
  2753   xv->y = y;
  2754 
  2755   xv->clip_left = 0;
  2756   xv->clip_right = xww->width;
  2757   xv->clip_top = 0;
  2758   xv->clip_bottom = xww->height;
  2759 
  2760   xv->frame = s->f;
  2761   xv->cursor = cursor_for_hit (xww->hit_result, s->f);
  2762   xv->just_resized = false;
  2763 #elif defined NS_IMPL_COCOA
  2764   nsxwidget_init_view (xv, xww, s, x, y);
  2765   nsxwidget_resize_view(xv, xww->width, xww->height);
  2766 #endif
  2767 
  2768   return xv;
  2769 }
  2770 
  2771 void
  2772 x_draw_xwidget_glyph_string (struct glyph_string *s)
  2773 {
  2774   /* This method is called by the redisplay engine and places the
  2775      xwidget on screen.  Moving and clipping is done here.  Also view
  2776      initialization.  */
  2777   struct xwidget *xww = s->xwidget;
  2778   struct xwidget_view *xv = xwidget_view_lookup (xww, s->w);
  2779   int text_area_x, text_area_y, text_area_width, text_area_height;
  2780   int clip_right;
  2781   int clip_bottom;
  2782   int clip_top;
  2783   int clip_left;
  2784 
  2785   int x = s->x;
  2786   int y = s->y + (s->height / 2) - (xww->height / 2);
  2787 
  2788   /* Do initialization here in the display loop because there is no
  2789      other time to know things like window placement etc.  Do not
  2790      create a new view if we have found one that is usable.  */
  2791 #ifdef USE_GTK
  2792   if (!xv)
  2793     xv = xwidget_init_view (xww, s, x, y);
  2794 
  2795   xv->just_resized = false;
  2796 #elif defined NS_IMPL_COCOA
  2797   if (!xv)
  2798     {
  2799       /* Enforce 1 to 1, model and view for macOS Cocoa webkit2.  */
  2800       if (xww->xv)
  2801         {
  2802           if (xwidget_hidden (xww->xv))
  2803             {
  2804               Lisp_Object xvl;
  2805               XSETXWIDGET_VIEW (xvl, xww->xv);
  2806               Fdelete_xwidget_view (xvl);
  2807             }
  2808           else
  2809             {
  2810               message ("You can't share an xwidget (webkit2) among windows.");
  2811               return;
  2812             }
  2813         }
  2814       xv = xwidget_init_view (xww, s, x, y);
  2815     }
  2816 #endif
  2817 
  2818   xv->area = s->area;
  2819 
  2820   window_box (s->w, xv->area, &text_area_x, &text_area_y,
  2821               &text_area_width, &text_area_height);
  2822 
  2823   clip_left = max (0, text_area_x - x);
  2824   clip_right = max (clip_left,
  2825                     min (xww->width, text_area_x + text_area_width - x));
  2826   clip_top = max (0, text_area_y - y);
  2827   clip_bottom = max (clip_top,
  2828                      min (xww->height, text_area_y + text_area_height - y));
  2829 
  2830   /* We are concerned with movement of the onscreen area.  The area
  2831      might sit still when the widget actually moves.  This happens
  2832      when an Emacs window border moves across a widget window.  So, if
  2833      any corner of the outer widget clipping window moves, that counts
  2834      as movement here, even if it looks like no movement happens
  2835      because the widget sits still inside the clipping area.  The
  2836      widget can also move inside the clipping area, which happens
  2837      later.  */
  2838   bool moved = (xv->x + xv->clip_left != x + clip_left
  2839                 || xv->y + xv->clip_top != y + clip_top);
  2840 
  2841 #ifdef HAVE_X_WINDOWS
  2842   bool wdesc_was_none = xv->wdesc == None;
  2843 #endif
  2844   xv->x = x;
  2845   xv->y = y;
  2846 
  2847 #ifdef HAVE_X_WINDOWS
  2848   block_input ();
  2849   if (xv->wdesc == None)
  2850     {
  2851       Lisp_Object xvw;
  2852       XSETXWIDGET_VIEW (xvw, xv);
  2853       XSetWindowAttributes a;
  2854       a.event_mask = (ExposureMask | ButtonPressMask | ButtonReleaseMask
  2855                       | PointerMotionMask | EnterWindowMask | LeaveWindowMask);
  2856 
  2857       if (clip_right - clip_left <= 0
  2858           || clip_bottom - clip_top <= 0)
  2859         {
  2860           unblock_input ();
  2861           return;
  2862         }
  2863 
  2864       xv->wdesc = XCreateWindow (xv->dpy, FRAME_X_WINDOW (s->f),
  2865                                  x + clip_left, y + clip_top,
  2866                                  clip_right - clip_left,
  2867                                  clip_bottom - clip_top, 0,
  2868                                  CopyFromParent, CopyFromParent,
  2869                                  CopyFromParent, CWEventMask, &a);
  2870 #ifdef HAVE_XINPUT2
  2871       XIEventMask mask;
  2872       ptrdiff_t l = XIMaskLen (XI_LASTEVENT);
  2873       unsigned char *m;
  2874 
  2875       if (FRAME_DISPLAY_INFO (s->f)->supports_xi2)
  2876         {
  2877           mask.mask = m = alloca (l);
  2878           memset (m, 0, l);
  2879           mask.mask_len = l;
  2880           mask.deviceid = XIAllMasterDevices;
  2881 
  2882           XISetMask (m, XI_Motion);
  2883           XISetMask (m, XI_ButtonPress);
  2884           XISetMask (m, XI_ButtonRelease);
  2885           XISetMask (m, XI_Enter);
  2886           XISetMask (m, XI_Leave);
  2887 #ifdef HAVE_XINPUT2_4
  2888           if (FRAME_DISPLAY_INFO (s->f)->xi2_version >= 4)
  2889             {
  2890               XISetMask (m, XI_GesturePinchBegin);
  2891               XISetMask (m, XI_GesturePinchUpdate);
  2892               XISetMask (m, XI_GesturePinchEnd);
  2893             }
  2894 #endif
  2895           XISelectEvents (xv->dpy, xv->wdesc, &mask, 1);
  2896         }
  2897 #endif
  2898       XLowerWindow (xv->dpy, xv->wdesc);
  2899       XDefineCursor (xv->dpy, xv->wdesc, xv->cursor);
  2900       xv->cr_surface = cairo_xlib_surface_create (xv->dpy,
  2901                                                   xv->wdesc,
  2902                                                   FRAME_DISPLAY_INFO (s->f)->visual,
  2903                                                   clip_right - clip_left,
  2904                                                   clip_bottom - clip_top);
  2905       xv->cr_context = cairo_create (xv->cr_surface);
  2906       Fputhash (make_fixnum (xv->wdesc), xvw, x_window_to_xwv_map);
  2907 
  2908       moved = false;
  2909     }
  2910 #endif
  2911 #ifdef HAVE_PGTK
  2912   block_input ();
  2913 #endif
  2914 
  2915   /* Has it moved?  */
  2916   if (moved)
  2917     {
  2918 #ifdef HAVE_X_WINDOWS
  2919       XMoveResizeWindow (xv->dpy, xv->wdesc, x + clip_left, y + clip_top,
  2920                          clip_right - clip_left, clip_bottom - clip_top);
  2921       XFlush (xv->dpy);
  2922       cairo_xlib_surface_set_size (xv->cr_surface, clip_right - clip_left,
  2923                                    clip_bottom - clip_top);
  2924 #elif defined HAVE_PGTK
  2925       gtk_widget_set_size_request (xv->widget, clip_right - clip_left,
  2926                                    clip_bottom - clip_top);
  2927       gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (xv->frame)),
  2928                       xv->widget, x + clip_left, y + clip_top);
  2929       gtk_widget_queue_allocate (xv->widget);
  2930 #elif defined NS_IMPL_COCOA
  2931       nsxwidget_move_view (xv, x + clip_left, y + clip_top);
  2932 #endif
  2933     }
  2934 
  2935   /* Clip the widget window if some parts happen to be outside
  2936      drawable area.  An Emacs window is not a gtk window.  A gtk window
  2937      covers the entire frame.  Clipping might have changed even if we
  2938      haven't actually moved; try to figure out when we need to reclip
  2939      for real.  */
  2940 #ifndef HAVE_PGTK
  2941   if (xv->clip_right != clip_right
  2942       || xv->clip_bottom != clip_bottom
  2943       || xv->clip_top != clip_top || xv->clip_left != clip_left)
  2944 #endif
  2945     {
  2946 #ifdef USE_GTK
  2947 #ifdef HAVE_X_WINDOWS
  2948       if (!wdesc_was_none && !moved)
  2949         {
  2950           if (clip_right - clip_left <= 0
  2951               || clip_bottom - clip_top <= 0)
  2952             {
  2953               XUnmapWindow (xv->dpy, xv->wdesc);
  2954               xv->hidden = true;
  2955             }
  2956           else
  2957             {
  2958               XResizeWindow (xv->dpy, xv->wdesc, clip_right - clip_left,
  2959                              clip_bottom - clip_top);
  2960             }
  2961           XFlush (xv->dpy);
  2962           cairo_xlib_surface_set_size (xv->cr_surface, clip_right - clip_left,
  2963                                        clip_bottom - clip_top);
  2964         }
  2965 #else
  2966       gtk_widget_set_size_request (xv->widget, clip_right - clip_left,
  2967                                    clip_bottom - clip_top);
  2968       gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (xv->frame)),
  2969                       xv->widget, x + clip_left, y + clip_top);
  2970       gtk_widget_queue_allocate (xv->widget);
  2971 #endif
  2972 #elif defined NS_IMPL_COCOA
  2973       nsxwidget_resize_view (xv, clip_right - clip_left,
  2974                              clip_bottom - clip_top);
  2975       nsxwidget_move_widget_in_view (xv, -clip_left, -clip_top);
  2976 #endif
  2977 
  2978       xv->clip_right = clip_right;
  2979       xv->clip_bottom = clip_bottom;
  2980       xv->clip_top = clip_top;
  2981       xv->clip_left = clip_left;
  2982     }
  2983 
  2984   /* If emacs wants to repaint the area where the widget lives, queue
  2985      a redraw.  It seems its possible to get out of sync with emacs
  2986      redraws so emacs background sometimes shows up instead of the
  2987      xwidgets background.  It's just a visual glitch though.  */
  2988   /* When xww->buffer is nil, that means the xwidget has been killed.  */
  2989   if (!NILP (xww->buffer))
  2990     {
  2991       if (!xwidget_hidden (xv))
  2992         {
  2993 #ifdef USE_GTK
  2994           gtk_widget_queue_draw (xww->widget_osr);
  2995 #elif defined NS_IMPL_COCOA
  2996           nsxwidget_set_needsdisplay (xv);
  2997 #endif
  2998         }
  2999     }
  3000 #ifdef HAVE_X_WINDOWS
  3001   else
  3002     {
  3003       XSetWindowBackground (xv->dpy, xv->wdesc,
  3004                             FRAME_BACKGROUND_PIXEL (s->f));
  3005     }
  3006 #endif
  3007 
  3008 #if defined HAVE_XINPUT2 || defined HAVE_PGTK
  3009   if (!NILP (xww->buffer))
  3010     {
  3011       record_osr_embedder (xv);
  3012       synthesize_focus_in_event (xww->widget_osr);
  3013     }
  3014 #endif
  3015 
  3016 #ifdef USE_GTK
  3017   unblock_input ();
  3018 #endif
  3019 }
  3020 
  3021 #define CHECK_WEBKIT_WIDGET(xw)                         \
  3022   if (NILP (xw->buffer) || !EQ (xw->type, Qwebkit))     \
  3023     error ("Not a WebKit widget")
  3024 
  3025 /* Macro that checks xwidget hold webkit web view first.  */
  3026 #define WEBKIT_FN_INIT()                                                \
  3027   CHECK_LIVE_XWIDGET (xwidget);                                         \
  3028   struct xwidget *xw = XXWIDGET (xwidget);                              \
  3029   CHECK_WEBKIT_WIDGET (xw)
  3030 
  3031 DEFUN ("xwidget-webkit-uri",
  3032        Fxwidget_webkit_uri, Sxwidget_webkit_uri,
  3033        1, 1, 0,
  3034        doc: /* Get the current URL of XWIDGET webkit.  */)
  3035   (Lisp_Object xwidget)
  3036 {
  3037   WEBKIT_FN_INIT ();
  3038 #ifdef USE_GTK
  3039   WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
  3040   const gchar *uri = webkit_web_view_get_uri (wkwv);
  3041   if (!uri)
  3042     return build_string ("");
  3043   return build_string (uri);
  3044 #elif defined NS_IMPL_COCOA
  3045   return nsxwidget_webkit_uri (xw);
  3046 #endif
  3047 }
  3048 
  3049 DEFUN ("xwidget-webkit-title",
  3050        Fxwidget_webkit_title, Sxwidget_webkit_title,
  3051        1, 1, 0,
  3052        doc: /* Get the current title of XWIDGET webkit.  */)
  3053   (Lisp_Object xwidget)
  3054 {
  3055   WEBKIT_FN_INIT ();
  3056 #ifdef USE_GTK
  3057   WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
  3058   const gchar *title = webkit_web_view_get_title (wkwv);
  3059 
  3060   return build_string (title ? title : "");
  3061 #elif defined NS_IMPL_COCOA
  3062   return nsxwidget_webkit_title (xw);
  3063 #endif
  3064 }
  3065 
  3066 DEFUN ("xwidget-webkit-estimated-load-progress",
  3067        Fxwidget_webkit_estimated_load_progress, Sxwidget_webkit_estimated_load_progress,
  3068        1, 1, 0, doc: /* Get the estimated load progress of XWIDGET, a WebKit widget.
  3069 Return a value ranging from 0.0 to 1.0, based on how close XWIDGET
  3070 is to completely loading its page.  */)
  3071   (Lisp_Object xwidget)
  3072 {
  3073   struct xwidget *xw;
  3074 #ifdef USE_GTK
  3075   WebKitWebView *webview;
  3076 #endif
  3077   double value;
  3078 
  3079   CHECK_LIVE_XWIDGET (xwidget);
  3080   xw = XXWIDGET (xwidget);
  3081   CHECK_WEBKIT_WIDGET (xw);
  3082 
  3083   block_input ();
  3084 #ifdef USE_GTK
  3085   webview = WEBKIT_WEB_VIEW (xw->widget_osr);
  3086   value = webkit_web_view_get_estimated_load_progress (webview);
  3087 #elif defined NS_IMPL_COCOA
  3088   value = nsxwidget_webkit_estimated_load_progress (xw);
  3089 #endif
  3090 
  3091   unblock_input ();
  3092 
  3093   return make_float (value);
  3094 }
  3095 
  3096 DEFUN ("xwidget-webkit-goto-uri",
  3097        Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri,
  3098        2, 2, 0,
  3099        doc: /* Make the xwidget webkit instance referenced by XWIDGET browse URI.  */)
  3100   (Lisp_Object xwidget, Lisp_Object uri)
  3101 {
  3102   WEBKIT_FN_INIT ();
  3103   CHECK_STRING (uri);
  3104   uri = ENCODE_FILE (uri);
  3105 #ifdef USE_GTK
  3106   webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr), SSDATA (uri));
  3107   catch_child_signal ();
  3108 #elif defined NS_IMPL_COCOA
  3109   nsxwidget_webkit_goto_uri (xw, SSDATA (uri));
  3110 #endif
  3111   return Qnil;
  3112 }
  3113 
  3114 DEFUN ("xwidget-webkit-goto-history",
  3115        Fxwidget_webkit_goto_history, Sxwidget_webkit_goto_history,
  3116        2, 2, 0,
  3117        doc: /* Make the XWIDGET webkit the REL-POSth element in load history.
  3118 
  3119 If REL-POS is 0, the widget will be just reload the current element in
  3120 history.  If REL-POS is more or less than 0, the widget will load the
  3121 REL-POSth element around the current spot in the load history. */)
  3122   (Lisp_Object xwidget, Lisp_Object rel_pos)
  3123 {
  3124   WEBKIT_FN_INIT ();
  3125   CHECK_FIXNUM (rel_pos);
  3126 
  3127 #ifdef USE_GTK
  3128   WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
  3129   WebKitBackForwardList *list;
  3130   WebKitBackForwardListItem *it;
  3131 
  3132   if (XFIXNUM (rel_pos) == 0)
  3133     webkit_web_view_reload (wkwv);
  3134   else
  3135     {
  3136       list = webkit_web_view_get_back_forward_list (wkwv);
  3137       it = webkit_back_forward_list_get_nth_item (list, XFIXNUM (rel_pos));
  3138 
  3139       if (!it)
  3140         error ("There is no item at this index");
  3141 
  3142       webkit_web_view_go_to_back_forward_list_item (wkwv, it);
  3143     }
  3144 #elif defined NS_IMPL_COCOA
  3145   nsxwidget_webkit_goto_history (xw, XFIXNAT (rel_pos));
  3146 #endif
  3147   return Qnil;
  3148 }
  3149 
  3150 DEFUN ("xwidget-webkit-zoom",
  3151        Fxwidget_webkit_zoom, Sxwidget_webkit_zoom,
  3152        2, 2, 0,
  3153        doc: /* Change the zoom factor of the xwidget webkit instance referenced by XWIDGET.  */)
  3154   (Lisp_Object xwidget, Lisp_Object factor)
  3155 {
  3156   WEBKIT_FN_INIT ();
  3157   if (FLOATP (factor))
  3158     {
  3159       double zoom_change = XFLOAT_DATA (factor);
  3160 #ifdef USE_GTK
  3161       webkit_web_view_set_zoom_level
  3162         (WEBKIT_WEB_VIEW (xw->widget_osr),
  3163          webkit_web_view_get_zoom_level
  3164          (WEBKIT_WEB_VIEW (xw->widget_osr)) + zoom_change);
  3165 #elif defined NS_IMPL_COCOA
  3166       nsxwidget_webkit_zoom (xw, zoom_change);
  3167 #endif
  3168     }
  3169   return Qnil;
  3170 }
  3171 
  3172 #ifdef USE_GTK
  3173 /* Save script and fun in the script/callback save vector and return
  3174    its index.  */
  3175 static ptrdiff_t
  3176 save_script_callback (struct xwidget *xw, Lisp_Object script, Lisp_Object fun)
  3177 {
  3178   Lisp_Object cbs = xw->script_callbacks;
  3179   if (NILP (cbs))
  3180     xw->script_callbacks = cbs = make_nil_vector (32);
  3181 
  3182   /* Find first free index.  */
  3183   ptrdiff_t idx;
  3184   for (idx = 0; !NILP (AREF (cbs, idx)); idx++)
  3185     if (idx + 1 == ASIZE (cbs))
  3186       {
  3187         xw->script_callbacks = cbs = larger_vector (cbs, 1, -1);
  3188         break;
  3189       }
  3190 
  3191   ASET (cbs, idx, Fcons (make_mint_ptr (xlispstrdup (script)), fun));
  3192   return idx;
  3193 }
  3194 #endif
  3195 
  3196 DEFUN ("xwidget-webkit-execute-script",
  3197        Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script,
  3198        2, 3, 0,
  3199        doc: /* Make the Webkit XWIDGET execute JavaScript SCRIPT.
  3200 If FUN is provided, feed the JavaScript return value to the single
  3201 argument procedure FUN.*/)
  3202   (Lisp_Object xwidget, Lisp_Object script, Lisp_Object fun)
  3203 {
  3204   WEBKIT_FN_INIT ();
  3205   CHECK_STRING (script);
  3206   if (!NILP (fun) && !FUNCTIONP (fun))
  3207     wrong_type_argument (Qinvalid_function, fun);
  3208 
  3209   script = ENCODE_SYSTEM (script);
  3210 
  3211 #ifdef USE_GTK
  3212   /* Protect script and fun during GC.  */
  3213   intptr_t idx = save_script_callback (xw, script, fun);
  3214 
  3215   /* JavaScript execution happens asynchronously.  If an elisp
  3216      callback function is provided we pass it to the C callback
  3217      procedure that retrieves the return value.  */
  3218   gchar *script_string
  3219     = xmint_pointer (XCAR (AREF (xw->script_callbacks, idx)));
  3220   webkit_web_view_run_javascript (WEBKIT_WEB_VIEW (xw->widget_osr),
  3221                                   script_string,
  3222                                   NULL, /* cancelable */
  3223                                   webkit_javascript_finished_cb,
  3224                                   (gpointer) idx);
  3225 #elif defined NS_IMPL_COCOA
  3226   nsxwidget_webkit_execute_script (xw, SSDATA (script), fun);
  3227 #endif
  3228   return Qnil;
  3229 }
  3230 
  3231 DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
  3232        doc: /* Resize XWIDGET to NEW_WIDTH, NEW_HEIGHT.  */ )
  3233   (Lisp_Object xwidget, Lisp_Object new_width, Lisp_Object new_height)
  3234 {
  3235   CHECK_LIVE_XWIDGET (xwidget);
  3236   int w = check_integer_range (new_width, 0, INT_MAX);
  3237   int h = check_integer_range (new_height, 0, INT_MAX);
  3238   struct xwidget *xw = XXWIDGET (xwidget);
  3239 
  3240   xw->width = w;
  3241   xw->height = h;
  3242 
  3243   block_input ();
  3244 
  3245   for (Lisp_Object tail = internal_xwidget_view_list; CONSP (tail);
  3246        tail = XCDR (tail))
  3247     {
  3248       if (XWIDGET_VIEW_P (XCAR (tail)))
  3249         {
  3250           struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail));
  3251           if (XXWIDGET (xv->model) == xw)
  3252             {
  3253 #ifdef USE_GTK
  3254               xv->just_resized = true;
  3255               SET_FRAME_GARBAGED (xv->frame);
  3256 #else
  3257               wset_redisplay (XWINDOW (xv->w));
  3258 #endif
  3259             }
  3260         }
  3261     }
  3262 
  3263   redisplay ();
  3264 
  3265   /* If there is an offscreen widget resize it first.  */
  3266 #ifdef USE_GTK
  3267   if (xw->widget_osr)
  3268     {
  3269       gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
  3270                          xw->height);
  3271       gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
  3272                                    xw->height);
  3273 
  3274       gtk_widget_queue_allocate (GTK_WIDGET (xw->widget_osr));
  3275     }
  3276 #elif defined NS_IMPL_COCOA
  3277   nsxwidget_resize (xw);
  3278 #endif
  3279   unblock_input ();
  3280 
  3281   return Qnil;
  3282 }
  3283 
  3284 
  3285 
  3286 
  3287 DEFUN ("xwidget-size-request",
  3288        Fxwidget_size_request, Sxwidget_size_request,
  3289        1, 1, 0,
  3290        doc: /* Return the desired size of the XWIDGET.
  3291 This can be used to read the xwidget desired size, and resizes the
  3292 Emacs allocated area accordingly.  */)
  3293   (Lisp_Object xwidget)
  3294 {
  3295   CHECK_LIVE_XWIDGET (xwidget);
  3296 #ifdef USE_GTK
  3297   GtkRequisition requisition;
  3298   gtk_widget_size_request (XXWIDGET (xwidget)->widget_osr, &requisition);
  3299   return list2i (requisition.width, requisition.height);
  3300 #elif defined NS_IMPL_COCOA
  3301   return nsxwidget_get_size (XXWIDGET (xwidget));
  3302 #endif
  3303 }
  3304 
  3305 DEFUN ("xwidgetp",
  3306        Fxwidgetp, Sxwidgetp,
  3307        1, 1, 0,
  3308        doc: /* Return t if OBJECT is an xwidget.  */)
  3309   (Lisp_Object object)
  3310 {
  3311   return XWIDGETP (object) ? Qt : Qnil;
  3312 }
  3313 
  3314 DEFUN ("xwidget-view-p",
  3315        Fxwidget_view_p, Sxwidget_view_p,
  3316        1, 1, 0,
  3317        doc: /* Return t if OBJECT is an xwidget-view.  */)
  3318   (Lisp_Object object)
  3319 {
  3320   return XWIDGET_VIEW_P (object) ? Qt : Qnil;
  3321 }
  3322 
  3323 DEFUN ("xwidget-info",
  3324        Fxwidget_info, Sxwidget_info,
  3325        1, 1, 0,
  3326        doc: /* Return XWIDGET properties in a vector.
  3327 Currently [TYPE TITLE WIDTH HEIGHT].  */)
  3328   (Lisp_Object xwidget)
  3329 {
  3330   CHECK_LIVE_XWIDGET (xwidget);
  3331   struct xwidget *xw = XXWIDGET (xwidget);
  3332   return CALLN (Fvector, xw->type, xw->title,
  3333                 make_fixed_natnum (xw->width), make_fixed_natnum (xw->height));
  3334 }
  3335 
  3336 DEFUN ("xwidget-view-info",
  3337        Fxwidget_view_info, Sxwidget_view_info,
  3338        1, 1, 0,
  3339        doc: /* Return properties of XWIDGET-VIEW in a vector.
  3340 Currently [X Y CLIP_RIGHT CLIP_BOTTOM CLIP_TOP CLIP_LEFT].  */)
  3341   (Lisp_Object xwidget_view)
  3342 {
  3343   CHECK_XWIDGET_VIEW (xwidget_view);
  3344   struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
  3345   return CALLN (Fvector, make_fixnum (xv->x), make_fixnum (xv->y),
  3346                 make_fixnum (xv->clip_right), make_fixnum (xv->clip_bottom),
  3347                 make_fixnum (xv->clip_top), make_fixnum (xv->clip_left));
  3348 }
  3349 
  3350 DEFUN ("xwidget-view-model",
  3351        Fxwidget_view_model, Sxwidget_view_model,
  3352        1, 1, 0,
  3353        doc:  /* Return the model associated with XWIDGET-VIEW.  */)
  3354   (Lisp_Object xwidget_view)
  3355 {
  3356   CHECK_XWIDGET_VIEW (xwidget_view);
  3357   return XXWIDGET_VIEW (xwidget_view)->model;
  3358 }
  3359 
  3360 DEFUN ("xwidget-view-window",
  3361        Fxwidget_view_window, Sxwidget_view_window,
  3362        1, 1, 0,
  3363        doc:  /* Return the window of XWIDGET-VIEW.  */)
  3364   (Lisp_Object xwidget_view)
  3365 {
  3366   CHECK_XWIDGET_VIEW (xwidget_view);
  3367   return XXWIDGET_VIEW (xwidget_view)->w;
  3368 }
  3369 
  3370 
  3371 DEFUN ("delete-xwidget-view",
  3372        Fdelete_xwidget_view, Sdelete_xwidget_view,
  3373        1, 1, 0,
  3374        doc:  /* Delete the XWIDGET-VIEW.  */)
  3375   (Lisp_Object xwidget_view)
  3376 {
  3377   CHECK_XWIDGET_VIEW (xwidget_view);
  3378   struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
  3379 
  3380   block_input ();
  3381 #ifdef USE_GTK
  3382   struct xwidget *xw = XXWIDGET (xv->model);
  3383   GdkWindow *w;
  3384 #ifdef HAVE_X_WINDOWS
  3385   if (xv->wdesc != None)
  3386     {
  3387       cairo_destroy (xv->cr_context);
  3388       cairo_surface_destroy (xv->cr_surface);
  3389       XDestroyWindow (xv->dpy, xv->wdesc);
  3390       Fremhash (make_fixnum (xv->wdesc), x_window_to_xwv_map);
  3391     }
  3392 
  3393   if (xv->last_crossing_window)
  3394     g_signal_handler_disconnect (xv->last_crossing_window,
  3395                                  xv->last_crossing_cursor_signal);
  3396   g_clear_pointer (&xv->last_crossing_window,
  3397                    g_object_unref);
  3398 
  3399   if (xv->passive_grab)
  3400     {
  3401       g_signal_handler_disconnect (xv->passive_grab,
  3402                                    xv->passive_grab_destruction_signal);
  3403       g_signal_handler_disconnect (xv->passive_grab,
  3404                                    xv->passive_grab_drag_signal);
  3405       xv->passive_grab = NULL;
  3406     }
  3407 
  3408 #else
  3409   gtk_widget_destroy (xv->widget);
  3410 #endif
  3411 
  3412   if (xw->embedder_view == xv && !NILP (xw->buffer))
  3413     {
  3414       w = gtk_widget_get_window (xw->widgetwindow_osr);
  3415 
  3416       XXWIDGET (xv->model)->embedder_view = NULL;
  3417       XXWIDGET (xv->model)->embedder = NULL;
  3418 
  3419       gdk_offscreen_window_set_embedder (w, NULL);
  3420     }
  3421 #elif defined NS_IMPL_COCOA
  3422   nsxwidget_delete_view (xv);
  3423 #endif
  3424 
  3425   internal_xwidget_view_list = Fdelq (xwidget_view, internal_xwidget_view_list);
  3426   Vxwidget_view_list = Fcopy_sequence (internal_xwidget_view_list);
  3427   unblock_input ();
  3428   return Qnil;
  3429 }
  3430 
  3431 DEFUN ("xwidget-view-lookup",
  3432        Fxwidget_view_lookup, Sxwidget_view_lookup,
  3433        1, 2, 0,
  3434        doc: /* Return the xwidget-view associated with XWIDGET in WINDOW.
  3435 If WINDOW is unspecified or nil, use the selected window.
  3436 Return nil if no association is found.  */)
  3437   (Lisp_Object xwidget, Lisp_Object window)
  3438 {
  3439   CHECK_XWIDGET (xwidget);
  3440 
  3441   if (NILP (window))
  3442     window = Fselected_window ();
  3443   CHECK_WINDOW (window);
  3444 
  3445   for (Lisp_Object tail = internal_xwidget_view_list; CONSP (tail);
  3446        tail = XCDR (tail))
  3447     {
  3448       Lisp_Object xwidget_view = XCAR (tail);
  3449       if (EQ (Fxwidget_view_model (xwidget_view), xwidget)
  3450           && EQ (Fxwidget_view_window (xwidget_view), window))
  3451         return xwidget_view;
  3452     }
  3453 
  3454   return Qnil;
  3455 }
  3456 
  3457 DEFUN ("xwidget-plist",
  3458        Fxwidget_plist, Sxwidget_plist,
  3459        1, 1, 0,
  3460        doc: /* Return the plist of XWIDGET.  */)
  3461   (Lisp_Object xwidget)
  3462 {
  3463   CHECK_LIVE_XWIDGET (xwidget);
  3464   return XXWIDGET (xwidget)->plist;
  3465 }
  3466 
  3467 DEFUN ("xwidget-buffer",
  3468        Fxwidget_buffer, Sxwidget_buffer,
  3469        1, 1, 0,
  3470        doc: /* Return the buffer of XWIDGET.  */)
  3471   (Lisp_Object xwidget)
  3472 {
  3473   CHECK_XWIDGET (xwidget);
  3474   return XXWIDGET (xwidget)->buffer;
  3475 }
  3476 
  3477 DEFUN ("set-xwidget-buffer",
  3478        Fset_xwidget_buffer, Sset_xwidget_buffer,
  3479        2, 2, 0,
  3480        doc: /* Set XWIDGET's buffer to BUFFER.  */)
  3481   (Lisp_Object xwidget, Lisp_Object buffer)
  3482 {
  3483   CHECK_LIVE_XWIDGET (xwidget);
  3484   CHECK_BUFFER (buffer);
  3485 
  3486   XXWIDGET (xwidget)->buffer = buffer;
  3487   return Qnil;
  3488 }
  3489 
  3490 DEFUN ("set-xwidget-plist",
  3491        Fset_xwidget_plist, Sset_xwidget_plist,
  3492        2, 2, 0,
  3493        doc: /* Replace the plist of XWIDGET with PLIST.
  3494 Returns PLIST.  */)
  3495   (Lisp_Object xwidget, Lisp_Object plist)
  3496 {
  3497   CHECK_LIVE_XWIDGET (xwidget);
  3498   CHECK_LIST (plist);
  3499 
  3500   XXWIDGET (xwidget)->plist = plist;
  3501   return plist;
  3502 }
  3503 
  3504 DEFUN ("set-xwidget-query-on-exit-flag",
  3505        Fset_xwidget_query_on_exit_flag, Sset_xwidget_query_on_exit_flag,
  3506        2, 2, 0,
  3507        doc: /* Specify if query is needed for XWIDGET when Emacs is exited.
  3508 If the second argument FLAG is non-nil, Emacs will query the user before
  3509 exiting or killing a buffer if XWIDGET is running.
  3510 This function returns FLAG.  */)
  3511   (Lisp_Object xwidget, Lisp_Object flag)
  3512 {
  3513   CHECK_LIVE_XWIDGET (xwidget);
  3514   XXWIDGET (xwidget)->kill_without_query = NILP (flag);
  3515   return flag;
  3516 }
  3517 
  3518 DEFUN ("xwidget-query-on-exit-flag",
  3519        Fxwidget_query_on_exit_flag, Sxwidget_query_on_exit_flag,
  3520        1, 1, 0,
  3521        doc: /* Return the current value of the query-on-exit flag for XWIDGET.  */)
  3522   (Lisp_Object xwidget)
  3523 {
  3524   CHECK_LIVE_XWIDGET (xwidget);
  3525   return (XXWIDGET (xwidget)->kill_without_query ? Qnil : Qt);
  3526 }
  3527 
  3528 DEFUN ("xwidget-webkit-search", Fxwidget_webkit_search, Sxwidget_webkit_search,
  3529        2, 5, 0,
  3530        doc: /* Begin an incremental search operation in an xwidget.
  3531 QUERY should be a string containing the text to search for.  XWIDGET
  3532 should be a WebKit xwidget where the search will take place.  When the
  3533 search operation is complete, callers should also call
  3534 `xwidget-webkit-finish-search' to complete the search operation.
  3535 
  3536 CASE-INSENSITIVE, when non-nil, will cause the search to ignore the
  3537 case of characters inside QUERY.  BACKWARDS, when non-nil, will cause
  3538 the search to proceed towards the beginning of the widget's contents.
  3539 WRAP-AROUND, when nil, will cause the search to stop upon hitting the
  3540 end of the widget's contents.
  3541 
  3542 It is OK to call this function even when a search is already in
  3543 progress.  In that case, the previous search query will be replaced
  3544 with QUERY.  */)
  3545   (Lisp_Object query, Lisp_Object xwidget, Lisp_Object case_insensitive,
  3546    Lisp_Object backwards, Lisp_Object wrap_around)
  3547 {
  3548 #ifdef USE_GTK
  3549   WebKitWebView *webview;
  3550   WebKitFindController *controller;
  3551   WebKitFindOptions opt;
  3552   struct xwidget *xw;
  3553   gchar *g_query;
  3554 #endif
  3555 
  3556   CHECK_STRING (query);
  3557   CHECK_LIVE_XWIDGET (xwidget);
  3558 
  3559 #ifdef USE_GTK
  3560   xw = XXWIDGET (xwidget);
  3561   CHECK_WEBKIT_WIDGET (xw);
  3562 
  3563   webview = WEBKIT_WEB_VIEW (xw->widget_osr);
  3564   query = ENCODE_UTF_8 (query);
  3565   opt = WEBKIT_FIND_OPTIONS_NONE;
  3566   g_query = xstrdup (SSDATA (query));
  3567 
  3568   if (!NILP (case_insensitive))
  3569     opt |= WEBKIT_FIND_OPTIONS_CASE_INSENSITIVE;
  3570   if (!NILP (backwards))
  3571     opt |= WEBKIT_FIND_OPTIONS_BACKWARDS;
  3572   if (!NILP (wrap_around))
  3573     opt |= WEBKIT_FIND_OPTIONS_WRAP_AROUND;
  3574 
  3575   if (xw->find_text)
  3576     xfree (xw->find_text);
  3577   xw->find_text = g_query;
  3578 
  3579   block_input ();
  3580   controller = webkit_web_view_get_find_controller (webview);
  3581   webkit_find_controller_search (controller, g_query, opt, G_MAXUINT);
  3582   unblock_input ();
  3583 #endif
  3584 
  3585   return Qnil;
  3586 }
  3587 
  3588 DEFUN ("xwidget-webkit-next-result", Fxwidget_webkit_next_result,
  3589        Sxwidget_webkit_next_result, 1, 1, 0,
  3590        doc: /* Show the next result matching the current search query.
  3591 
  3592 XWIDGET should be an xwidget that currently has a search query.
  3593 Before calling this function, you should start a search operation
  3594 using `xwidget-webkit-search'.  */)
  3595   (Lisp_Object xwidget)
  3596 {
  3597   struct xwidget *xw;
  3598 #ifdef USE_GTK
  3599   WebKitWebView *webview;
  3600   WebKitFindController *controller;
  3601 #endif
  3602 
  3603   CHECK_LIVE_XWIDGET (xwidget);
  3604   xw = XXWIDGET (xwidget);
  3605   CHECK_WEBKIT_WIDGET (xw);
  3606 
  3607   if (!xw->find_text)
  3608     error ("Widget has no ongoing search operation");
  3609 
  3610 #ifdef USE_GTK
  3611   block_input ();
  3612   webview = WEBKIT_WEB_VIEW (xw->widget_osr);
  3613   controller = webkit_web_view_get_find_controller (webview);
  3614   webkit_find_controller_search_next (controller);
  3615   unblock_input ();
  3616 #endif
  3617 
  3618   return Qnil;
  3619 }
  3620 
  3621 DEFUN ("xwidget-webkit-previous-result", Fxwidget_webkit_previous_result,
  3622        Sxwidget_webkit_previous_result, 1, 1, 0,
  3623        doc: /* Show the previous result matching the current search query.
  3624 
  3625 XWIDGET should be an xwidget that currently has a search query.
  3626 Before calling this function, you should start a search operation
  3627 using `xwidget-webkit-search'.  */)
  3628   (Lisp_Object xwidget)
  3629 {
  3630   struct xwidget *xw;
  3631 #ifdef USE_GTK
  3632   WebKitWebView *webview;
  3633   WebKitFindController *controller;
  3634 #endif
  3635 
  3636   CHECK_LIVE_XWIDGET (xwidget);
  3637   xw = XXWIDGET (xwidget);
  3638   CHECK_WEBKIT_WIDGET (xw);
  3639 
  3640   if (!xw->find_text)
  3641     error ("Widget has no ongoing search operation");
  3642 
  3643 #ifdef USE_GTK
  3644   block_input ();
  3645   webview = WEBKIT_WEB_VIEW (xw->widget_osr);
  3646   controller = webkit_web_view_get_find_controller (webview);
  3647   webkit_find_controller_search_previous (controller);
  3648   unblock_input ();
  3649 #endif
  3650 
  3651   return Qnil;
  3652 }
  3653 
  3654 DEFUN ("xwidget-webkit-finish-search", Fxwidget_webkit_finish_search,
  3655        Sxwidget_webkit_finish_search, 1, 1, 0,
  3656        doc: /* Finish XWIDGET's search operation.
  3657 
  3658 XWIDGET should be an xwidget that currently has a search query.
  3659 Before calling this function, you should start a search operation
  3660 using `xwidget-webkit-search'.  */)
  3661   (Lisp_Object xwidget)
  3662 {
  3663   struct xwidget *xw;
  3664 #ifdef USE_GTK
  3665   WebKitWebView *webview;
  3666   WebKitFindController *controller;
  3667 #endif
  3668 
  3669   CHECK_LIVE_XWIDGET (xwidget);
  3670   xw = XXWIDGET (xwidget);
  3671   CHECK_WEBKIT_WIDGET (xw);
  3672 
  3673   if (!xw->find_text)
  3674     error ("Widget has no ongoing search operation");
  3675 
  3676 #ifdef USE_GTK
  3677   block_input ();
  3678   webview = WEBKIT_WEB_VIEW (xw->widget_osr);
  3679   controller = webkit_web_view_get_find_controller (webview);
  3680   webkit_find_controller_search_finish (controller);
  3681 
  3682   if (xw->find_text)
  3683     {
  3684       xfree (xw->find_text);
  3685       xw->find_text = NULL;
  3686     }
  3687   unblock_input ();
  3688 #endif
  3689 
  3690   return Qnil;
  3691 }
  3692 
  3693 DEFUN ("kill-xwidget", Fkill_xwidget, Skill_xwidget,
  3694        1, 1, 0,
  3695        doc: /* Kill the specified XWIDGET.
  3696 This releases all window system resources associated with XWIDGET,
  3697 removes it from `xwidget-list', and detaches it from its buffer.  */)
  3698   (Lisp_Object xwidget)
  3699 {
  3700   struct xwidget *xw;
  3701 
  3702   CHECK_LIVE_XWIDGET (xwidget);
  3703   xw = XXWIDGET (xwidget);
  3704 
  3705   block_input ();
  3706   kill_xwidget (xw);
  3707   unblock_input ();
  3708 
  3709   return Qnil;
  3710 }
  3711 
  3712 #ifdef USE_GTK
  3713 DEFUN ("xwidget-webkit-load-html", Fxwidget_webkit_load_html,
  3714        Sxwidget_webkit_load_html, 2, 3, 0,
  3715        doc: /* Make XWIDGET's WebKit widget render TEXT.
  3716 XWIDGET should be a WebKit xwidget, that will receive TEXT.  TEXT
  3717 should be a string that will be displayed by XWIDGET as HTML markup.
  3718 BASE-URI should be a string containing a URI that is used to locate
  3719 resources with relative URLs, and if not specified, defaults
  3720 to "about:blank".  */)
  3721   (Lisp_Object xwidget, Lisp_Object text, Lisp_Object base_uri)
  3722 {
  3723   struct xwidget *xw;
  3724   WebKitWebView *webview;
  3725   char *data, *uri;
  3726 
  3727   CHECK_LIVE_XWIDGET (xwidget);
  3728   CHECK_STRING (text);
  3729   if (NILP (base_uri))
  3730     base_uri = build_string ("about:blank");
  3731   else
  3732     CHECK_STRING (base_uri);
  3733 
  3734   base_uri = ENCODE_UTF_8 (base_uri);
  3735   text = ENCODE_UTF_8 (text);
  3736   xw = XXWIDGET (xwidget);
  3737   CHECK_WEBKIT_WIDGET (xw);
  3738 
  3739   data = SSDATA (text);
  3740   uri = SSDATA (base_uri);
  3741   webview = WEBKIT_WEB_VIEW (xw->widget_osr);
  3742 
  3743   block_input ();
  3744   webkit_web_view_load_html (webview, data, uri);
  3745   unblock_input ();
  3746 
  3747   return Qnil;
  3748 }
  3749 
  3750 DEFUN ("xwidget-webkit-back-forward-list", Fxwidget_webkit_back_forward_list,
  3751        Sxwidget_webkit_back_forward_list, 1, 2, 0,
  3752        doc: /* Return the navigation history of XWIDGET, a WebKit xwidget.
  3753 
  3754 Return the history as a list of the form (BACK HERE FORWARD), where
  3755 HERE is the current navigation item, while BACK and FORWARD are lists
  3756 of history items of the form (IDX TITLE URI).  Here, IDX is an index
  3757 that can be passed to `xwidget-webkit-goto-history', TITLE is a string
  3758 containing the human-readable title of the history item, and URI is
  3759 the URI of the history item.
  3760 
  3761 BACK, HERE, and FORWARD can all be nil depending on the state of the
  3762 navigation history.
  3763 
  3764 BACK and FORWARD will each not contain more elements than LIMIT.  If
  3765 LIMIT is not specified or nil, it is treated as `50'.  */)
  3766   (Lisp_Object xwidget, Lisp_Object limit)
  3767 {
  3768   struct xwidget *xw;
  3769   Lisp_Object back, here, forward;
  3770   WebKitWebView *webview;
  3771   WebKitBackForwardList *list;
  3772   WebKitBackForwardListItem *item;
  3773   GList *parent, *tem;
  3774   int i;
  3775   unsigned int lim;
  3776   Lisp_Object title, uri;
  3777   const gchar *item_title, *item_uri;
  3778 
  3779   back = Qnil;
  3780   here = Qnil;
  3781   forward = Qnil;
  3782 
  3783   if (NILP (limit))
  3784     limit = make_fixnum (50);
  3785   else
  3786     CHECK_FIXNAT (limit);
  3787 
  3788   CHECK_LIVE_XWIDGET (xwidget);
  3789   xw = XXWIDGET (xwidget);
  3790 
  3791   webview = WEBKIT_WEB_VIEW (xw->widget_osr);
  3792   list = webkit_web_view_get_back_forward_list (webview);
  3793   item = webkit_back_forward_list_get_current_item (list);
  3794   lim = XFIXNAT (limit);
  3795 
  3796   if (item)
  3797     {
  3798       item_title = webkit_back_forward_list_item_get_title (item);
  3799       item_uri = webkit_back_forward_list_item_get_uri (item);
  3800       here = list3 (make_fixnum (0),
  3801                     build_string_from_utf8 (item_title ? item_title : ""),
  3802                     build_string_from_utf8 (item_uri ? item_uri : ""));
  3803     }
  3804   parent = webkit_back_forward_list_get_back_list_with_limit (list, lim);
  3805 
  3806   if (parent)
  3807     {
  3808       for (i = 1, tem = parent; tem; tem = tem->next, ++i)
  3809         {
  3810           item = tem->data;
  3811           item_title = webkit_back_forward_list_item_get_title (item);
  3812           item_uri = webkit_back_forward_list_item_get_uri (item);
  3813           title = build_string_from_utf8 (item_title ? item_title : "");
  3814           uri = build_string_from_utf8 (item_uri ? item_uri : "");
  3815           back = Fcons (list3 (make_fixnum (-i), title, uri), back);
  3816         }
  3817     }
  3818 
  3819   back = Fnreverse (back);
  3820   g_list_free (parent);
  3821 
  3822   parent = webkit_back_forward_list_get_forward_list_with_limit (list, lim);
  3823 
  3824   if (parent)
  3825     {
  3826       for (i = 1, tem = parent; tem; tem = tem->next, ++i)
  3827         {
  3828           item = tem->data;
  3829           item_title = webkit_back_forward_list_item_get_title (item);
  3830           item_uri = webkit_back_forward_list_item_get_uri (item);
  3831           title = build_string_from_utf8 (item_title ? item_title : "");
  3832           uri = build_string_from_utf8 (item_uri ? item_uri : "");
  3833           forward = Fcons (list3 (make_fixnum (i), title, uri), forward);
  3834         }
  3835     }
  3836 
  3837   forward = Fnreverse (forward);
  3838   g_list_free (parent);
  3839 
  3840   return list3 (back, here, forward);
  3841 }
  3842 
  3843 #endif
  3844 
  3845 DEFUN ("xwidget-webkit-set-cookie-storage-file",
  3846        Fxwidget_webkit_set_cookie_storage_file, Sxwidget_webkit_set_cookie_storage_file,
  3847        2, 2, 0, doc: /* Make the WebKit widget XWIDGET load and store cookies in FILE.
  3848 
  3849 Cookies will be stored as plain text in FILE, which must be an
  3850 absolute file name.  All xwidgets related to XWIDGET will also
  3851 store cookies in FILE and load them from there.  */)
  3852   (Lisp_Object xwidget, Lisp_Object file)
  3853 {
  3854 #ifdef USE_GTK
  3855   struct xwidget *xw;
  3856   WebKitWebView *webview;
  3857   WebKitWebContext *context;
  3858   WebKitCookieManager *manager;
  3859 
  3860   CHECK_LIVE_XWIDGET (xwidget);
  3861   xw = XXWIDGET (xwidget);
  3862   CHECK_WEBKIT_WIDGET (xw);
  3863   CHECK_STRING (file);
  3864 
  3865   block_input ();
  3866   webview = WEBKIT_WEB_VIEW (xw->widget_osr);
  3867   context = webkit_web_view_get_context (webview);
  3868   manager = webkit_web_context_get_cookie_manager (context);
  3869   webkit_cookie_manager_set_persistent_storage (manager,
  3870                                                 SSDATA (ENCODE_UTF_8 (file)),
  3871                                                 WEBKIT_COOKIE_PERSISTENT_STORAGE_TEXT);
  3872   unblock_input ();
  3873 #endif
  3874 
  3875   return Qnil;
  3876 }
  3877 
  3878 DEFUN ("xwidget-webkit-stop-loading", Fxwidget_webkit_stop_loading,
  3879        Sxwidget_webkit_stop_loading,
  3880        1, 1, 0, doc: /* Stop loading data in the WebKit widget XWIDGET.
  3881 This will stop any data transfer that may still be in progress inside
  3882 XWIDGET as part of loading a page.  */)
  3883   (Lisp_Object xwidget)
  3884 {
  3885   struct xwidget *xw;
  3886 #ifdef USE_GTK
  3887   WebKitWebView *webview;
  3888 #endif
  3889 
  3890   CHECK_LIVE_XWIDGET (xwidget);
  3891   xw = XXWIDGET (xwidget);
  3892   CHECK_WEBKIT_WIDGET (xw);
  3893 
  3894   block_input ();
  3895 #ifdef USE_GTK
  3896   webview = WEBKIT_WEB_VIEW (xw->widget_osr);
  3897   webkit_web_view_stop_loading (webview);
  3898 #elif defined NS_IMPL_COCOA
  3899   nsxwidget_webkit_stop_loading (xw);
  3900 #endif
  3901   unblock_input ();
  3902 
  3903   return Qnil;
  3904 }
  3905 
  3906 void
  3907 syms_of_xwidget (void)
  3908 {
  3909   defsubr (&Smake_xwidget);
  3910   defsubr (&Sxwidgetp);
  3911   defsubr (&Sxwidget_live_p);
  3912   DEFSYM (Qxwidgetp, "xwidgetp");
  3913   DEFSYM (Qxwidget_live_p, "xwidget-live-p");
  3914   defsubr (&Sxwidget_view_p);
  3915   DEFSYM (Qxwidget_view_p, "xwidget-view-p");
  3916   defsubr (&Sxwidget_info);
  3917   defsubr (&Sxwidget_view_info);
  3918   defsubr (&Sxwidget_resize);
  3919   defsubr (&Sget_buffer_xwidgets);
  3920   defsubr (&Sxwidget_view_model);
  3921   defsubr (&Sxwidget_view_window);
  3922   defsubr (&Sxwidget_view_lookup);
  3923   defsubr (&Sxwidget_query_on_exit_flag);
  3924   defsubr (&Sset_xwidget_query_on_exit_flag);
  3925 
  3926   defsubr (&Sxwidget_webkit_uri);
  3927   defsubr (&Sxwidget_webkit_title);
  3928   defsubr (&Sxwidget_webkit_goto_uri);
  3929   defsubr (&Sxwidget_webkit_goto_history);
  3930   defsubr (&Sxwidget_webkit_zoom);
  3931   defsubr (&Sxwidget_webkit_execute_script);
  3932   DEFSYM (Qwebkit, "webkit");
  3933 
  3934   defsubr (&Sxwidget_size_request);
  3935   defsubr (&Sdelete_xwidget_view);
  3936 
  3937   defsubr (&Sxwidget_plist);
  3938   defsubr (&Sxwidget_buffer);
  3939   defsubr (&Sset_xwidget_plist);
  3940   defsubr (&Sxwidget_perform_lispy_event);
  3941   defsubr (&Sxwidget_webkit_search);
  3942   defsubr (&Sxwidget_webkit_finish_search);
  3943   defsubr (&Sxwidget_webkit_next_result);
  3944   defsubr (&Sxwidget_webkit_previous_result);
  3945   defsubr (&Sset_xwidget_buffer);
  3946   defsubr (&Sxwidget_webkit_set_cookie_storage_file);
  3947   defsubr (&Sxwidget_webkit_stop_loading);
  3948 #ifdef USE_GTK
  3949   defsubr (&Sxwidget_webkit_load_html);
  3950   defsubr (&Sxwidget_webkit_back_forward_list);
  3951 #endif
  3952 
  3953   defsubr (&Sxwidget_webkit_estimated_load_progress);
  3954   defsubr (&Skill_xwidget);
  3955 
  3956   DEFSYM (QCxwidget, ":xwidget");
  3957   DEFSYM (QCtitle, ":title");
  3958 
  3959   /* Do not forget to update the docstring of make-xwidget if you add
  3960      new types.  */
  3961 
  3962   DEFSYM (Qvertical, "vertical");
  3963   DEFSYM (Qhorizontal, "horizontal");
  3964 
  3965   DEFSYM (QCplist, ":plist");
  3966 
  3967   DEFVAR_LISP ("xwidget-list", Vxwidget_list,
  3968                doc: /* List of all xwidgets that have not been killed.  */);
  3969   Vxwidget_list = Qnil;
  3970 
  3971   DEFVAR_LISP ("xwidget-view-list", Vxwidget_view_list,
  3972                doc: /* List of all xwidget views.  */);
  3973   Vxwidget_view_list = Qnil;
  3974 
  3975   Fprovide (intern ("xwidget-internal"), Qnil);
  3976 
  3977   id_to_xwidget_map = CALLN (Fmake_hash_table, QCtest, Qeq,
  3978                              QCweakness, Qvalue);
  3979   staticpro (&id_to_xwidget_map);
  3980 
  3981   internal_xwidget_list = Qnil;
  3982   staticpro (&internal_xwidget_list);
  3983   internal_xwidget_view_list = Qnil;
  3984   staticpro (&internal_xwidget_view_list);
  3985 
  3986 #ifdef HAVE_X_WINDOWS
  3987   x_window_to_xwv_map = CALLN (Fmake_hash_table, QCtest, Qeq);
  3988 
  3989   staticpro (&x_window_to_xwv_map);
  3990 
  3991 #if WEBKIT_CHECK_VERSION (2, 34, 0)
  3992   dummy_tooltip_string = build_string ("");
  3993   staticpro (&dummy_tooltip_string);
  3994 #endif
  3995 #endif
  3996 }
  3997 
  3998 
  3999 /* Value is non-zero if OBJECT is a valid Lisp xwidget specification.  A
  4000    valid xwidget specification is a list whose car is the symbol
  4001    `xwidget', and whose rest is a property list.  The property list must
  4002    contain a value for key `:type'.  That value must be the name of a
  4003    supported xwidget type.  The rest of the property list depends on the
  4004    xwidget type.  */
  4005 
  4006 bool
  4007 valid_xwidget_spec_p (Lisp_Object object)
  4008 {
  4009   return CONSP (object) && EQ (XCAR (object), Qxwidget);
  4010 }
  4011 
  4012 
  4013 /* Find a value associated with key in spec.  */
  4014 static Lisp_Object
  4015 xwidget_spec_value (Lisp_Object spec, Lisp_Object key)
  4016 {
  4017   Lisp_Object tail;
  4018 
  4019   eassert (valid_xwidget_spec_p (spec));
  4020 
  4021   for (tail = XCDR (spec);
  4022        CONSP (tail) && CONSP (XCDR (tail)); tail = XCDR (XCDR (tail)))
  4023     {
  4024       if (EQ (XCAR (tail), key))
  4025         return XCAR (XCDR (tail));
  4026     }
  4027 
  4028   return Qnil;
  4029 }
  4030 
  4031 
  4032 void
  4033 xwidget_view_delete_all_in_window (struct window *w)
  4034 {
  4035   struct xwidget_view *xv = NULL;
  4036   for (Lisp_Object tail = internal_xwidget_view_list; CONSP (tail);
  4037        tail = XCDR (tail))
  4038     {
  4039       if (XWIDGET_VIEW_P (XCAR (tail)))
  4040         {
  4041           xv = XXWIDGET_VIEW (XCAR (tail));
  4042           if (XWINDOW (xv->w) == w)
  4043             {
  4044               Fdelete_xwidget_view (XCAR (tail));
  4045             }
  4046         }
  4047     }
  4048 }
  4049 
  4050 static struct xwidget_view *
  4051 xwidget_view_lookup (struct xwidget *xw, struct window *w)
  4052 {
  4053   Lisp_Object xwidget, window, ret;
  4054   XSETXWIDGET (xwidget, xw);
  4055   XSETWINDOW (window, w);
  4056 
  4057   ret = Fxwidget_view_lookup (xwidget, window);
  4058 
  4059   return NILP (ret) ? NULL : XXWIDGET_VIEW (ret);
  4060 }
  4061 
  4062 struct xwidget *
  4063 lookup_xwidget (Lisp_Object spec)
  4064 {
  4065   /* When a xwidget lisp spec is found initialize the C struct that is
  4066      used in the C code.  This is done by redisplay so values change
  4067      if the spec changes.  So, take special care of one-shot events.  */
  4068   Lisp_Object value;
  4069   struct xwidget *xw;
  4070 
  4071   value = xwidget_spec_value (spec, QCxwidget);
  4072   xw = XXWIDGET (value);
  4073 
  4074   return xw;
  4075 }
  4076 
  4077 /* Set up detection of touched xwidget.  */
  4078 static void
  4079 xwidget_start_redisplay (void)
  4080 {
  4081   for (Lisp_Object tail = internal_xwidget_view_list; CONSP (tail);
  4082        tail = XCDR (tail))
  4083     {
  4084       if (XWIDGET_VIEW_P (XCAR (tail)))
  4085         XXWIDGET_VIEW (XCAR (tail))->redisplayed = false;
  4086     }
  4087 }
  4088 
  4089 /* The xwidget was touched during redisplay, so it isn't a candidate
  4090    for hiding.  */
  4091 static void
  4092 xwidget_touch (struct xwidget_view *xv)
  4093 {
  4094   xv->redisplayed = true;
  4095 }
  4096 
  4097 static bool
  4098 xwidget_touched (struct xwidget_view *xv)
  4099 {
  4100   return xv->redisplayed;
  4101 }
  4102 
  4103 /* Redisplay has ended, now we should hide untouched xwidgets.  */
  4104 void
  4105 xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix)
  4106 {
  4107   int i;
  4108   int area;
  4109 
  4110   xwidget_start_redisplay ();
  4111   /* Iterate desired glyph matrix of window here, hide gtk widgets
  4112      not in the desired matrix.
  4113 
  4114      This only takes care of xwidgets in active windows.  If a window
  4115      goes away from the screen, xwidget views must be deleted.
  4116 
  4117      dump_glyph_matrix (matrix, 2);  */
  4118   for (i = 0; i < matrix->nrows; ++i)
  4119     {
  4120       /* dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs); */
  4121       struct glyph_row *row;
  4122       row = MATRIX_ROW (matrix, i);
  4123       if (row->enabled_p)
  4124         for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
  4125           {
  4126             struct glyph *glyph = row->glyphs[area];
  4127             struct glyph *glyph_end = glyph + row->used[area];
  4128             for (; glyph < glyph_end; ++glyph)
  4129               if (glyph->type == XWIDGET_GLYPH)
  4130                 {
  4131                   /* The only call to xwidget_end_redisplay is in dispnew.
  4132                      xwidget_end_redisplay (w->current_matrix);  */
  4133                   struct xwidget_view *xv
  4134                     = xwidget_view_lookup (xwidget_from_id (glyph->u.xwidget), w);
  4135 
  4136                   /* In NS xwidget, xv can be NULL for the second or
  4137                      later views for a model, the result of 1 to 1
  4138                      model view relation enforcement.  `xwidget_view_lookup'
  4139                      has also been observed to return NULL here on X-Windows
  4140                      at least once, so stay safe and only touch it if it's
  4141                      not NULL.  */
  4142 
  4143                   if (xv)
  4144                     xwidget_touch (xv);
  4145                 }
  4146           }
  4147     }
  4148 
  4149   for (Lisp_Object tail = internal_xwidget_view_list; CONSP (tail);
  4150        tail = XCDR (tail))
  4151     {
  4152       if (XWIDGET_VIEW_P (XCAR (tail)))
  4153         {
  4154           struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail));
  4155 
  4156           /* "touched" is only meaningful for the current window, so
  4157              disregard other views.  */
  4158           if (XWINDOW (xv->w) == w)
  4159             {
  4160               if (xwidget_touched (xv))
  4161                 {
  4162 #ifdef USE_GTK
  4163                   xwidget_show_view (xv);
  4164 #elif defined NS_IMPL_COCOA
  4165                   nsxwidget_show_view (xv);
  4166 #endif
  4167                 }
  4168               else
  4169                 {
  4170 #ifdef USE_GTK
  4171                   xwidget_hide_view (xv);
  4172 #elif defined NS_IMPL_COCOA
  4173                   nsxwidget_hide_view (xv);
  4174 #endif
  4175                 }
  4176             }
  4177         }
  4178     }
  4179 }
  4180 
  4181 #ifdef HAVE_X_WINDOWS
  4182 void
  4183 lower_frame_xwidget_views (struct frame *f)
  4184 {
  4185   struct xwidget_view *xv;
  4186 
  4187   for (Lisp_Object tail = internal_xwidget_view_list; CONSP (tail);
  4188        tail = XCDR (tail))
  4189     {
  4190       xv = XXWIDGET_VIEW (XCAR (tail));
  4191       if (xv->frame == f && xv->wdesc != None)
  4192         XLowerWindow (xv->dpy, xv->wdesc);
  4193     }
  4194 }
  4195 #endif
  4196 
  4197 #ifndef NS_IMPL_COCOA
  4198 void
  4199 kill_frame_xwidget_views (struct frame *f)
  4200 {
  4201   Lisp_Object rem = Qnil;
  4202 
  4203   for (Lisp_Object tail = internal_xwidget_view_list; CONSP (tail);
  4204        tail = XCDR (tail))
  4205     {
  4206       if (XWIDGET_VIEW_P (XCAR (tail))
  4207           && XXWIDGET_VIEW (XCAR (tail))->frame == f)
  4208         rem = Fcons (XCAR (tail), rem);
  4209     }
  4210 
  4211   for (; CONSP (rem); rem = XCDR (rem))
  4212     Fdelete_xwidget_view (XCAR (rem));
  4213 }
  4214 #endif
  4215 
  4216 static void
  4217 kill_xwidget (struct xwidget *xw)
  4218 {
  4219   Lisp_Object val;
  4220   XSETXWIDGET (val, xw);
  4221 
  4222   internal_xwidget_list = Fdelq (val, internal_xwidget_list);
  4223   Vxwidget_list = Fcopy_sequence (internal_xwidget_list);
  4224 #ifdef USE_GTK
  4225   xw->buffer = Qnil;
  4226 
  4227   if (xw->widget_osr && xw->widgetwindow_osr)
  4228     {
  4229       gtk_widget_destroy (xw->widget_osr);
  4230       gtk_widget_destroy (xw->widgetwindow_osr);
  4231     }
  4232 
  4233   if (xw->find_text)
  4234     xfree (xw->find_text);
  4235 
  4236   if (!NILP (xw->script_callbacks))
  4237     {
  4238       for (ptrdiff_t idx = 0; idx < ASIZE (xw->script_callbacks); idx++)
  4239         {
  4240           Lisp_Object cb = AREF (xw->script_callbacks, idx);
  4241           if (!NILP (cb))
  4242             xfree (xmint_pointer (XCAR (cb)));
  4243           ASET (xw->script_callbacks, idx, Qnil);
  4244         }
  4245     }
  4246 
  4247   xw->widget_osr = NULL;
  4248   xw->widgetwindow_osr = NULL;
  4249   xw->find_text = NULL;
  4250 
  4251   catch_child_signal ();
  4252 #elif defined NS_IMPL_COCOA
  4253   nsxwidget_kill (xw);
  4254 #endif
  4255 }
  4256 
  4257 /* Kill all xwidget in BUFFER.  */
  4258 void
  4259 kill_buffer_xwidgets (Lisp_Object buffer)
  4260 {
  4261   Lisp_Object tail, xwidget;
  4262   for (tail = Fget_buffer_xwidgets (buffer); CONSP (tail); tail = XCDR (tail))
  4263     {
  4264       xwidget = XCAR (tail);
  4265       {
  4266         CHECK_LIVE_XWIDGET (xwidget);
  4267         struct xwidget *xw = XXWIDGET (xwidget);
  4268 
  4269         kill_xwidget (xw);
  4270       }
  4271     }
  4272 
  4273   catch_child_signal ();
  4274 }

/* [<][>][^][v][top][bottom][index][help] */