This source file includes following definitions.
- allocate_xwidget
- allocate_xwidget_view
- xw_forward_event_translate
- xw_forward_event_from_view
- xw_translate_x_modifiers
- DEFUN
- set_widget_if_text_view
- DEFUN
- xwidget_hidden
- xwidget_from_id
- pick_embedded_child
- record_osr_embedder
- find_xwidget_for_offscreen_window
- from_embedder
- to_embedder
- find_suitable_pointer
- find_suitable_keyboard
- find_widget_cb
- find_widget
- find_widget_at_pos
- cursor_for_hit
- define_cursors
- mouse_target_changed
- run_file_chooser_cb
- xv_drag_begin_cb
- xwidget_button_1
- xwidget_button
- xwidget_motion_notify
- xwidget_scroll
- xwidget_pinch
- xi_translate_notify_detail
- window_coords_from_toplevel
- xw_find_common_ancestor
- xw_notify_virtual_upwards_until
- xw_notify_virtual_downwards_until
- xw_update_cursor_for_view
- xw_last_crossing_cursor_cb
- xw_maybe_synthesize_crossing
- xwidget_motion_or_crossing
- synthesize_focus_in_event
- xwidget_view_from_window
- xwidget_show_view
- xwidget_hide_view
- xv_do_draw
- xwidget_view_draw_cb
- offscreen_damage_event
- xwidget_expose
- store_xwidget_event_string
- store_xwidget_download_callback_event
- store_xwidget_js_callback_event
- store_xwidget_display_event
- webkit_ready_to_show
- webkit_create_cb_1
- webkit_create_cb
- webkit_view_load_changed_cb
- webkit_js_to_lisp
- webkit_javascript_finished_cb
- webkit_download_cb
- webkit_decide_policy_cb
- webkit_script_dialog_cb
- xwidget_init_view
- x_draw_xwidget_glyph_string
- DEFUN
- DEFUN
- DEFUN
- save_script_callback
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- syms_of_xwidget
- valid_xwidget_spec_p
- xwidget_spec_value
- xwidget_view_delete_all_in_window
- xwidget_view_lookup
- lookup_xwidget
- xwidget_start_redisplay
- xwidget_touch
- xwidget_touched
- xwidget_end_redisplay
- lower_frame_xwidget_views
- kill_frame_xwidget_views
- kill_xwidget
- kill_buffer_xwidgets
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
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
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
248
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:
285
286
287
288
289
290
291
292
293
294 )
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
369
370
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
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
413
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
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:
463 )
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:
485
486
487
488 )
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
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
634 if (WEBKIT_IS_WEB_VIEW (widget))
635 {
636
637
638
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:
678 )
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
970
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
989
990
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
1117
1118
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
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);
1209
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);
1337
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
1763
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);
1981
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
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
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
2224
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
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
2349
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
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
2530
2531
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
2563
2564
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
2643
2644
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
2696
2697
2698
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
2775
2776
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
2789
2790
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
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
2831
2832
2833
2834
2835
2836
2837
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
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
2936
2937
2938
2939
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
2985
2986
2987
2988
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
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: )
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: )
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:
3069
3070 )
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: )
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:
3118
3119
3120
3121 )
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: )
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
3174
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
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:
3200
3201 )
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
3213 intptr_t idx = save_script_callback (xw, script, fun);
3214
3215
3216
3217
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,
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: )
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
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:
3291
3292 )
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: )
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: )
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:
3327 )
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:
3340 )
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: )
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: )
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: )
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:
3435
3436 )
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: )
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: )
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: )
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:
3494 )
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:
3508
3509
3510 )
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: )
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:
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544 )
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:
3591
3592
3593
3594 )
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:
3624
3625
3626
3627 )
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:
3657
3658
3659
3660 )
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:
3696
3697 )
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:
3716
3717
3718
3719
3720 )
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:
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765 )
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:
3848
3849
3850
3851 )
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:
3881
3882 )
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
3960
3961
3962 DEFSYM (Qvertical, "vertical");
3963 DEFSYM (Qhorizontal, "horizontal");
3964
3965 DEFSYM (QCplist, ":plist");
3966
3967 DEFVAR_LISP ("xwidget-list", Vxwidget_list,
3968 doc: );
3969 Vxwidget_list = Qnil;
3970
3971 DEFVAR_LISP ("xwidget-view-list", Vxwidget_view_list,
3972 doc: );
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
4000
4001
4002
4003
4004
4005
4006 bool
4007 valid_xwidget_spec_p (Lisp_Object object)
4008 {
4009 return CONSP (object) && EQ (XCAR (object), Qxwidget);
4010 }
4011
4012
4013
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
4066
4067
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
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
4090
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
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
4112
4113
4114
4115
4116
4117
4118 for (i = 0; i < matrix->nrows; ++i)
4119 {
4120
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
4132
4133 struct xwidget_view *xv
4134 = xwidget_view_lookup (xwidget_from_id (glyph->u.xwidget), w);
4135
4136
4137
4138
4139
4140
4141
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
4157
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
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 }