1 /* Support for embedding graphical components in a buffer.
3 Copyright (C) 2011-2016 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or (at
10 your option) any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
31 #include "blockinput.h"
32 #include "syssignal.h"
35 #include <X11/cursorfont.h>
38 # include <sys/types.h>
42 # include <sys/ioctl.h>
47 #ifndef INCLUDED_FCNTL
56 #include "character.h"
60 #include "dispextern.h"
62 #include "termhooks.h"
69 #include "intervals.h"
76 #include <X11/Shell.h>
78 #include <X11/extensions/Xcomposite.h>
79 #include <X11/extensions/Xrender.h>
81 #ifdef HAVE_SYS_TIME_H
90 #endif /* HAVE_X_WINDOWS */
97 #include "emacsgtkfixed.h"
101 #include <webkit/webkitwebview.h>
102 #include <webkit/webkitwebplugindatabase.h>
103 #include <webkit/webkitwebplugin.h>
104 #include <webkit/webkitglobals.h>
105 #include <webkit/webkitwebnavigationaction.h>
106 #include <webkit/webkitdownload.h>
107 #include <webkit/webkitwebpolicydecision.h>
109 static struct xwidget
*
110 allocate_xwidget (void)
112 return ALLOCATE_PSEUDOVECTOR (struct xwidget
, height
, PVEC_XWIDGET
);
115 static struct xwidget_view
*
116 allocate_xwidget_view (void)
118 return ALLOCATE_PSEUDOVECTOR (struct xwidget_view
, redisplayed
,
122 #define XSETXWIDGET(a, b) XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET)
123 #define XSETXWIDGET_VIEW(a, b) XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW)
125 static struct xwidget_view
*xwidget_view_lookup (struct xwidget
*,
127 static void webkit_document_load_finished_cb (WebKitWebView
*, WebKitWebFrame
*,
129 static gboolean
webkit_download_cb (WebKitWebView
*, WebKitDownload
*, gpointer
);
132 webkit_mime_type_policy_typedecision_requested_cb (WebKitWebView
*,
134 WebKitNetworkRequest
*,
136 WebKitWebPolicyDecision
*,
140 webkit_new_window_policy_decision_requested_cb (WebKitWebView
*,
142 WebKitNetworkRequest
*,
143 WebKitWebNavigationAction
*,
144 WebKitWebPolicyDecision
*,
148 webkit_navigation_policy_decision_requested_cb (WebKitWebView
*,
150 WebKitNetworkRequest
*,
151 WebKitWebNavigationAction
*,
152 WebKitWebPolicyDecision
*,
157 DEFUN ("make-xwidget",
158 Fmake_xwidget
, Smake_xwidget
,
160 doc
: /* Make an xwidget from BEG to END of TYPE.
161 If BUFFER is nil, use the current buffer.
162 If BUFFER is a string and no such buffer exists, create it.
163 TYPE is a symbol which can take one of the following values:
167 Returns the newly constructed xwidget, or nil if construction fails. */)
168 (Lisp_Object beg
, Lisp_Object end
, Lisp_Object type
,
169 Lisp_Object title
, Lisp_Object width
, Lisp_Object height
,
170 Lisp_Object arguments
, Lisp_Object buffer
)
173 CHECK_NATNUM (width
);
174 CHECK_NATNUM (height
);
175 /* This should work a bit like "make-button"
176 (make-button BEG END &rest PROPERTIES)
177 TYPE etc. should be keyword args eventually.
178 (make-xwidget 3 3 'button "oei" 31 31 nil)
179 (xwidget-info (car xwidget-list)) */
180 struct xwidget
*xw
= allocate_xwidget ();
184 xw
->buffer
= NILP (buffer
) ? Fcurrent_buffer () : Fget_buffer_create (buffer
);
185 xw
->height
= XFASTINT (height
);
186 xw
->width
= XFASTINT (width
);
187 xw
->kill_without_query
= false;
188 XSETXWIDGET (val
, xw
);
189 Vxwidget_list
= Fcons (val
, Vxwidget_list
);
190 xw
->widgetwindow_osr
= NULL
;
191 xw
->widget_osr
= NULL
;
194 if (EQ (xw
->type
, Qwebkit_osr
))
197 xw
->widgetwindow_osr
= gtk_offscreen_window_new ();
198 gtk_window_resize (GTK_WINDOW (xw
->widgetwindow_osr
), xw
->width
,
201 /* WebKit OSR is the only scrolled component at the moment. */
202 xw
->widgetscrolledwindow_osr
= NULL
;
204 if (EQ (xw
->type
, Qwebkit_osr
))
206 xw
->widgetscrolledwindow_osr
= gtk_scrolled_window_new (NULL
, NULL
);
207 gtk_scrolled_window_set_min_content_height
208 (GTK_SCROLLED_WINDOW (xw
->widgetscrolledwindow_osr
),
210 gtk_scrolled_window_set_min_content_width
211 (GTK_SCROLLED_WINDOW (xw
->widgetscrolledwindow_osr
),
213 gtk_scrolled_window_set_policy
214 (GTK_SCROLLED_WINDOW (xw
->widgetscrolledwindow_osr
),
215 GTK_POLICY_ALWAYS
, GTK_POLICY_ALWAYS
);
217 xw
->widget_osr
= webkit_web_view_new ();
218 gtk_container_add (GTK_CONTAINER (xw
->widgetscrolledwindow_osr
),
219 GTK_WIDGET (WEBKIT_WEB_VIEW (xw
->widget_osr
)));
222 gtk_widget_set_size_request (GTK_WIDGET (xw
->widget_osr
), xw
->width
,
225 if (EQ (xw
->type
, Qwebkit_osr
))
227 gtk_container_add (GTK_CONTAINER (xw
->widgetwindow_osr
),
228 xw
->widgetscrolledwindow_osr
);
232 gtk_container_add (GTK_CONTAINER (xw
->widgetwindow_osr
),
236 gtk_widget_show (xw
->widget_osr
);
237 gtk_widget_show (xw
->widgetwindow_osr
);
238 gtk_widget_show (xw
->widgetscrolledwindow_osr
);
240 /* Store some xwidget data in the gtk widgets for convenient
241 retrieval in the event handlers. */
242 g_object_set_data (G_OBJECT (xw
->widget_osr
), XG_XWIDGET
, xw
);
243 g_object_set_data (G_OBJECT (xw
->widgetwindow_osr
), XG_XWIDGET
, xw
);
246 if (EQ (xw
->type
, Qwebkit_osr
))
248 g_signal_connect (G_OBJECT (xw
->widget_osr
),
249 "document-load-finished",
250 G_CALLBACK (webkit_document_load_finished_cb
), xw
);
252 g_signal_connect (G_OBJECT (xw
->widget_osr
),
253 "download-requested",
254 G_CALLBACK (webkit_download_cb
), xw
);
256 g_signal_connect (G_OBJECT (xw
->widget_osr
),
257 "mime-type-policy-decision-requested",
259 (webkit_mime_type_policy_typedecision_requested_cb
),
262 g_signal_connect (G_OBJECT (xw
->widget_osr
),
263 "new-window-policy-decision-requested",
265 (webkit_new_window_policy_decision_requested_cb
),
268 g_signal_connect (G_OBJECT (xw
->widget_osr
),
269 "navigation-policy-decision-requested",
271 (webkit_navigation_policy_decision_requested_cb
),
281 DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets
, Sget_buffer_xwidgets
,
283 doc
: /* Return a list of xwidgets associated with BUFFER.
284 BUFFER may be a buffer or the name of one. */)
287 Lisp_Object xw
, tail
, xw_list
;
291 buffer
= Fget_buffer (buffer
);
297 for (tail
= Vxwidget_list
; CONSP (tail
); tail
= XCDR (tail
))
300 if (XWIDGETP (xw
) && EQ (Fxwidget_buffer (xw
), buffer
))
301 xw_list
= Fcons (xw
, xw_list
);
307 xwidget_hidden (struct xwidget_view
*xv
)
313 xwidget_show_view (struct xwidget_view
*xv
)
316 gtk_widget_show (xv
->widgetwindow
);
317 gtk_fixed_move (GTK_FIXED (xv
->emacswindow
),
319 xv
->x
+ xv
->clip_left
,
320 xv
->y
+ xv
->clip_top
);
323 /* Hide an xwidget view. */
325 xwidget_hide_view (struct xwidget_view
*xv
)
328 gtk_fixed_move (GTK_FIXED (xv
->emacswindow
), xv
->widgetwindow
,
332 /* When the off-screen webkit master view changes this signal is called.
333 It copies the bitmap from the off-screen instance. */
335 offscreen_damage_event (GtkWidget
*widget
, GdkEvent
*event
,
338 /* Queue a redraw of onscreen widget.
339 There is a guard against receiving an invalid widget,
340 which should only happen if we failed to remove the
341 specific signal handler for the damage event. */
342 if (GTK_IS_WIDGET (xv_widget
))
343 gtk_widget_queue_draw (GTK_WIDGET (xv_widget
));
345 printf ("Warning, offscreen_damage_event received invalid xv pointer:%p\n",
352 store_xwidget_event_string (struct xwidget
*xw
, const char *eventname
,
353 const char *eventstr
)
355 struct input_event event
;
357 XSETXWIDGET (xwl
, xw
);
359 event
.kind
= XWIDGET_EVENT
;
360 event
.frame_or_window
= Qnil
;
361 event
.arg
= list3 (intern (eventname
), xwl
, build_string (eventstr
));
362 kbd_buffer_store_event (&event
);
365 /* TODO deprecated, use load-status. */
367 webkit_document_load_finished_cb (WebKitWebView
*webkitwebview
,
368 WebKitWebFrame
*arg1
,
371 struct xwidget
*xw
= g_object_get_data (G_OBJECT (webkitwebview
),
374 store_xwidget_event_string (xw
, "document-load-finished", "");
378 webkit_download_cb (WebKitWebView
*webkitwebview
,
379 WebKitDownload
*arg1
,
382 struct xwidget
*xw
= g_object_get_data (G_OBJECT (webkitwebview
),
384 store_xwidget_event_string (xw
, "download-requested",
385 webkit_download_get_uri (arg1
));
390 webkit_mime_type_policy_typedecision_requested_cb (WebKitWebView
*webView
,
391 WebKitWebFrame
*frame
,
392 WebKitNetworkRequest
*request
,
394 WebKitWebPolicyDecision
*policy_decision
,
397 /* This function makes webkit send a download signal for all unknown
398 mime types. TODO: Defer the decision to Lisp, so that it's
399 possible to make Emacs handle mime text for instance. */
400 if (!webkit_web_view_can_show_mime_type (webView
, mimetype
))
402 webkit_web_policy_decision_download (policy_decision
);
410 webkit_new_window_policy_decision_requested_cb (WebKitWebView
*webView
,
411 WebKitWebFrame
*frame
,
412 WebKitNetworkRequest
*request
,
413 WebKitWebNavigationAction
*navigation_action
,
414 WebKitWebPolicyDecision
*policy_decision
,
417 struct xwidget
*xw
= g_object_get_data (G_OBJECT (webView
), XG_XWIDGET
);
418 webkit_web_navigation_action_get_original_uri (navigation_action
);
420 store_xwidget_event_string (xw
, "new-window-policy-decision-requested",
421 webkit_web_navigation_action_get_original_uri
422 (navigation_action
));
427 webkit_navigation_policy_decision_requested_cb (WebKitWebView
*webView
,
428 WebKitWebFrame
*frame
,
429 WebKitNetworkRequest
*request
,
430 WebKitWebNavigationAction
*navigation_action
,
431 WebKitWebPolicyDecision
*policy_decision
,
434 struct xwidget
*xw
= g_object_get_data (G_OBJECT (webView
), XG_XWIDGET
);
435 store_xwidget_event_string (xw
, "navigation-policy-decision-requested",
436 webkit_web_navigation_action_get_original_uri
437 (navigation_action
));
441 /* For gtk3 offscreen rendered widgets. */
443 xwidget_osr_draw_cb (GtkWidget
*widget
, cairo_t
*cr
, gpointer data
)
445 struct xwidget
*xw
= g_object_get_data (G_OBJECT (widget
), XG_XWIDGET
);
446 struct xwidget_view
*xv
= g_object_get_data (G_OBJECT (widget
),
449 cairo_rectangle (cr
, 0, 0, xv
->clip_right
, xv
->clip_bottom
);
452 if (xw
->widgetscrolledwindow_osr
!= NULL
)
453 gtk_widget_draw (xw
->widgetscrolledwindow_osr
, cr
);
455 gtk_widget_draw (xw
->widget_osr
, cr
);
460 xwidget_osr_event_forward (GtkWidget
*widget
, GdkEvent
*event
,
463 /* Copy events that arrive at the outer widget to the offscreen widget. */
464 struct xwidget
*xw
= g_object_get_data (G_OBJECT (widget
), XG_XWIDGET
);
465 GdkEvent
*eventcopy
= gdk_event_copy (event
);
466 eventcopy
->any
.window
= gtk_widget_get_window (xw
->widget_osr
);
468 /* TODO: This might leak events. They should be deallocated later,
469 perhaps in xwgir_event_cb. */
470 gtk_main_do_event (eventcopy
);
472 /* Don't propagate this event further. */
477 xwidget_osr_event_set_embedder (GtkWidget
*widget
, GdkEvent
*event
,
480 struct xwidget_view
*xv
= data
;
481 struct xwidget
*xww
= XXWIDGET (xv
->model
);
482 gdk_offscreen_window_set_embedder (gtk_widget_get_window
483 (xww
->widgetwindow_osr
),
484 gtk_widget_get_window (xv
->widget
));
489 /* Initializes and does initial placement of an xwidget view on screen. */
490 static struct xwidget_view
*
491 xwidget_init_view (struct xwidget
*xww
,
492 struct glyph_string
*s
,
495 struct xwidget_view
*xv
= allocate_xwidget_view ();
498 XSETXWIDGET_VIEW (val
, xv
);
499 Vxwidget_view_list
= Fcons (val
, Vxwidget_view_list
);
501 XSETWINDOW (xv
->w
, s
->w
);
502 XSETXWIDGET (xv
->model
, xww
);
504 if (EQ (xww
->type
, Qwebkit_osr
))
506 xv
->widget
= gtk_drawing_area_new ();
507 /* Expose event handling. */
508 gtk_widget_set_app_paintable (xv
->widget
, TRUE
);
509 gtk_widget_add_events (xv
->widget
, GDK_ALL_EVENTS_MASK
);
511 /* Draw the view on damage-event. */
512 g_signal_connect (G_OBJECT (xww
->widgetwindow_osr
), "damage-event",
513 G_CALLBACK (offscreen_damage_event
), xv
->widget
);
515 if (EQ (xww
->type
, Qwebkit_osr
))
517 g_signal_connect (G_OBJECT (xv
->widget
), "button-press-event",
518 G_CALLBACK (xwidget_osr_event_forward
), NULL
);
519 g_signal_connect (G_OBJECT (xv
->widget
), "button-release-event",
520 G_CALLBACK (xwidget_osr_event_forward
), NULL
);
521 g_signal_connect (G_OBJECT (xv
->widget
), "motion-notify-event",
522 G_CALLBACK (xwidget_osr_event_forward
), NULL
);
526 /* xwgir debug, orthogonal to forwarding. */
527 g_signal_connect (G_OBJECT (xv
->widget
), "enter-notify-event",
528 G_CALLBACK (xwidget_osr_event_set_embedder
), xv
);
530 g_signal_connect (G_OBJECT (xv
->widget
), "draw",
531 G_CALLBACK (xwidget_osr_draw_cb
), NULL
);
534 /* Widget realization.
536 Make container widget first, and put the actual widget inside the
537 container later. Drawing should crop container window if necessary
538 to handle case where xwidget is partially obscured by other Emacs
539 windows. Other containers than gtk_fixed where explored, but
540 gtk_fixed had the most predictable behavior so far. */
542 xv
->emacswindow
= FRAME_GTK_WIDGET (s
->f
);
543 xv
->widgetwindow
= gtk_fixed_new ();
544 gtk_widget_set_has_window (xv
->widgetwindow
, TRUE
);
545 gtk_container_add (GTK_CONTAINER (xv
->widgetwindow
), xv
->widget
);
547 /* Store some xwidget data in the gtk widgets. */
548 g_object_set_data (G_OBJECT (xv
->widget
), XG_FRAME_DATA
, s
->f
);
549 g_object_set_data (G_OBJECT (xv
->widget
), XG_XWIDGET
, xww
);
550 g_object_set_data (G_OBJECT (xv
->widget
), XG_XWIDGET_VIEW
, xv
);
551 g_object_set_data (G_OBJECT (xv
->widgetwindow
), XG_XWIDGET
, xww
);
552 g_object_set_data (G_OBJECT (xv
->widgetwindow
), XG_XWIDGET_VIEW
, xv
);
554 gtk_widget_set_size_request (GTK_WIDGET (xv
->widget
), xww
->width
,
556 gtk_widget_set_size_request (xv
->widgetwindow
, xww
->width
, xww
->height
);
557 gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s
->f
)), xv
->widgetwindow
, x
, y
);
560 gtk_widget_show_all (xv
->widgetwindow
);
566 x_draw_xwidget_glyph_string (struct glyph_string
*s
)
568 /* This method is called by the redisplay engine and places the
569 xwidget on screen. Moving and clipping is done here. Also view
571 struct xwidget
*xww
= s
->xwidget
;
572 struct xwidget_view
*xv
= xwidget_view_lookup (xww
, s
->w
);
579 int y
= s
->y
+ (s
->height
/ 2) - (xww
->height
/ 2);
581 /* Do initialization here in the display loop because there is no
582 other time to know things like window placement etc. */
583 xv
= xwidget_init_view (xww
, s
, x
, y
);
585 /* Calculate clipping, which is used for all manner of onscreen
586 xwidget views. Each widget border can get clipped by other emacs
587 objects so there are four clipping variables. */
590 WINDOW_RIGHT_EDGE_X (s
->w
) - x
-
591 WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH (s
->w
) -
592 WINDOW_RIGHT_FRINGE_WIDTH (s
->w
));
595 WINDOW_LEFT_EDGE_X (s
->w
) - x
+
596 WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (s
->w
) +
597 WINDOW_LEFT_FRINGE_WIDTH (s
->w
));
601 WINDOW_BOTTOM_EDGE_Y (s
->w
) - WINDOW_MODE_LINE_HEIGHT (s
->w
) - y
);
602 clip_top
= max (0, WINDOW_TOP_EDGE_Y (s
->w
) - y
);
604 /* We are concerned with movement of the onscreen area. The area
605 might sit still when the widget actually moves. This happens
606 when an Emacs window border moves across a widget window. So, if
607 any corner of the outer widget clipping window moves, that counts
608 as movement here, even if it looks like no movement happens
609 because the widget sits still inside the clipping area. The
610 widget can also move inside the clipping area, which happens
612 bool moved
= (xv
->x
+ xv
->clip_left
!= x
+ clip_left
613 || xv
->y
+ xv
->clip_top
!= y
+ clip_top
);
619 gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s
->f
)),
620 xv
->widgetwindow
, x
+ clip_left
, y
+ clip_top
);
622 /* Clip the widget window if some parts happen to be outside
623 drawable area. An Emacs window is not a gtk window. A gtk window
624 covers the entire frame. Clipping might have changed even if we
625 haven't actually moved; try to figure out when we need to reclip
627 if (xv
->clip_right
!= clip_right
628 || xv
->clip_bottom
!= clip_bottom
629 || xv
->clip_top
!= clip_top
|| xv
->clip_left
!= clip_left
)
631 gtk_widget_set_size_request (xv
->widgetwindow
, clip_right
+ clip_left
,
632 clip_bottom
+ clip_top
);
633 gtk_fixed_move (GTK_FIXED (xv
->widgetwindow
), xv
->widget
, -clip_left
,
636 xv
->clip_right
= clip_right
;
637 xv
->clip_bottom
= clip_bottom
;
638 xv
->clip_top
= clip_top
;
639 xv
->clip_left
= clip_left
;
642 /* If emacs wants to repaint the area where the widget lives, queue
643 a redraw. It seems its possible to get out of sync with emacs
644 redraws so emacs background sometimes shows up instead of the
645 xwidgets background. It's just a visual glitch though. */
646 if (!xwidget_hidden (xv
))
648 gtk_widget_queue_draw (xv
->widgetwindow
);
649 gtk_widget_queue_draw (xv
->widget
);
653 /* Macro that checks WEBKIT_IS_WEB_VIEW (xw->widget_osr) first. */
654 #define WEBKIT_FN_INIT() \
655 CHECK_XWIDGET (xwidget); \
656 struct xwidget *xw = XXWIDGET (xwidget); \
657 if (!xw->widget_osr || !WEBKIT_IS_WEB_VIEW (xw->widget_osr)) \
659 printf ("ERROR xw->widget_osr does not hold a webkit instance\n"); \
663 DEFUN ("xwidget-webkit-goto-uri",
664 Fxwidget_webkit_goto_uri
, Sxwidget_webkit_goto_uri
,
666 doc
: /* Make the xwidget webkit instance referenced by XWIDGET browse URI. */)
667 (Lisp_Object xwidget
, Lisp_Object uri
)
671 webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw
->widget_osr
), SSDATA (uri
));
676 DEFUN ("xwidget-webkit-execute-script",
677 Fxwidget_webkit_execute_script
, Sxwidget_webkit_execute_script
,
679 doc
: /* Make the Webkit XWIDGET execute JavaScript SCRIPT. */)
680 (Lisp_Object xwidget
, Lisp_Object script
)
683 CHECK_STRING (script
);
684 webkit_web_view_execute_script (WEBKIT_WEB_VIEW (xw
->widget_osr
),
689 DEFUN ("xwidget-webkit-get-title",
690 Fxwidget_webkit_get_title
, Sxwidget_webkit_get_title
,
692 doc
: /* Return the title from the Webkit instance in XWIDGET.
693 This can be used to work around the lack of a return value from the
695 (Lisp_Object xwidget
)
697 /* TODO support multibyte strings. */
700 webkit_web_view_get_title (WEBKIT_WEB_VIEW (xw
->widget_osr
));
703 /* TODO maybe return Qnil instead. I suppose webkit returns
704 null pointer when doc is not properly loaded or something. */
705 return build_string ("");
707 return build_string (str
);
710 DEFUN ("xwidget-resize", Fxwidget_resize
, Sxwidget_resize
, 3, 3, 0,
711 doc
: /* Resize XWIDGET. NEW_WIDTH, NEW_HEIGHT define the new size. */ )
712 (Lisp_Object xwidget
, Lisp_Object new_width
, Lisp_Object new_height
)
714 CHECK_XWIDGET (xwidget
);
715 CHECK_NATNUM (new_width
);
716 CHECK_NATNUM (new_height
);
717 struct xwidget
*xw
= XXWIDGET (xwidget
);
718 int w
= XFASTINT (new_width
);
719 int h
= XFASTINT (new_height
);
724 /* If there is an offscreen widget resize it first. */
727 /* Use minimum size. */
728 gtk_widget_set_size_request (GTK_WIDGET (xw
->widget_osr
),
729 xw
->width
, xw
->height
);
731 gtk_window_resize (GTK_WINDOW (xw
->widgetwindow_osr
), xw
->width
,
733 gtk_scrolled_window_set_min_content_height
734 (GTK_SCROLLED_WINDOW (xw
->widgetscrolledwindow_osr
),
736 gtk_scrolled_window_set_min_content_width
737 (GTK_SCROLLED_WINDOW (xw
->widgetscrolledwindow_osr
),
740 gtk_container_resize_children (GTK_CONTAINER (xw
->widgetwindow_osr
));
744 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
); tail
= XCDR (tail
))
746 if (XWIDGET_VIEW_P (XCAR (tail
)))
748 struct xwidget_view
*xv
= XXWIDGET_VIEW (XCAR (tail
));
749 if (XXWIDGET (xv
->model
) == xw
)
750 gtk_widget_set_size_request (GTK_WIDGET (xv
->widget
), xw
->width
,
760 DEFUN ("xwidget-set-adjustment",
761 Fxwidget_set_adjustment
, Sxwidget_set_adjustment
, 4, 4, 0,
762 doc
: /* Set native scrolling for XWIDGET.
763 AXIS can be `vertical' or `horizontal'.
764 If RELATIVE is t, scroll relative, otherwise absolutely.
765 VALUE is the amount to scroll, either relatively or absolutely. */)
766 (Lisp_Object xwidget
, Lisp_Object axis
, Lisp_Object relative
,
769 CHECK_XWIDGET (xwidget
);
770 CHECK_NATNUM (value
);
771 struct xwidget
*xw
= XXWIDGET (xwidget
);
772 GtkAdjustment
*adjustment
773 = ((EQ (Qhorizontal
, axis
)
774 ? gtk_scrolled_window_get_hadjustment
775 : gtk_scrolled_window_get_vadjustment
)
776 (GTK_SCROLLED_WINDOW (xw
->widgetscrolledwindow_osr
)));
777 double final_value
= XFASTINT (value
);
778 if (EQ (Qt
, relative
))
779 final_value
+= gtk_adjustment_get_value (adjustment
);
780 gtk_adjustment_set_value (adjustment
, final_value
);
785 DEFUN ("xwidget-size-request",
786 Fxwidget_size_request
, Sxwidget_size_request
,
788 doc
: /* Return the desired size of the XWIDGET.
789 This can be used to read the xwidget desired size, and resizes the
790 Emacs allocated area accordingly. */)
791 (Lisp_Object xwidget
)
793 CHECK_XWIDGET (xwidget
);
794 GtkRequisition requisition
;
795 gtk_widget_size_request (XXWIDGET (xwidget
)->widget_osr
, &requisition
);
796 return list2 (make_number (requisition
.width
),
797 make_number (requisition
.height
));
801 Fxwidgetp
, Sxwidgetp
,
803 doc
: /* Return t if OBJECT is an xwidget. */)
806 return XWIDGETP (object
) ? Qt
: Qnil
;
809 DEFUN ("xwidget-view-p",
810 Fxwidget_view_p
, Sxwidget_view_p
,
812 doc
: /* Return t if OBJECT is an xwidget-view. */)
815 return XWIDGET_VIEW_P (object
) ? Qt
: Qnil
;
818 DEFUN ("xwidget-info",
819 Fxwidget_info
, Sxwidget_info
,
821 doc
: /* Return XWIDGET properties in a vector.
822 Currently [TYPE TITLE WIDTH HEIGHT]. */)
823 (Lisp_Object xwidget
)
825 CHECK_XWIDGET (xwidget
);
826 struct xwidget
*xw
= XXWIDGET (xwidget
);
827 return CALLN (Fvector
, xw
->type
, xw
->title
,
828 make_natnum (xw
->width
), make_natnum (xw
->height
));
831 DEFUN ("xwidget-view-info",
832 Fxwidget_view_info
, Sxwidget_view_info
,
834 doc
: /* Return properties of XWIDGET-VIEW in a vector.
835 Currently [X Y CLIP_RIGHT CLIP_BOTTOM CLIP_TOP CLIP_LEFT]. */)
836 (Lisp_Object xwidget_view
)
838 CHECK_XWIDGET_VIEW (xwidget_view
);
839 struct xwidget_view
*xv
= XXWIDGET_VIEW (xwidget_view
);
840 return CALLN (Fvector
, make_number (xv
->x
), make_number (xv
->y
),
841 make_number (xv
->clip_right
), make_number (xv
->clip_bottom
),
842 make_number (xv
->clip_top
), make_number (xv
->clip_left
));
845 DEFUN ("xwidget-view-model",
846 Fxwidget_view_model
, Sxwidget_view_model
,
848 doc
: /* Return the model associated with XWIDGET-VIEW. */)
849 (Lisp_Object xwidget_view
)
851 CHECK_XWIDGET_VIEW (xwidget_view
);
852 return XXWIDGET_VIEW (xwidget_view
)->model
;
855 DEFUN ("xwidget-view-window",
856 Fxwidget_view_window
, Sxwidget_view_window
,
858 doc
: /* Return the window of XWIDGET-VIEW. */)
859 (Lisp_Object xwidget_view
)
861 CHECK_XWIDGET_VIEW (xwidget_view
);
862 return XXWIDGET_VIEW (xwidget_view
)->w
;
866 DEFUN ("delete-xwidget-view",
867 Fdelete_xwidget_view
, Sdelete_xwidget_view
,
869 doc
: /* Delete the XWIDGET-VIEW. */)
870 (Lisp_Object xwidget_view
)
872 CHECK_XWIDGET_VIEW (xwidget_view
);
873 struct xwidget_view
*xv
= XXWIDGET_VIEW (xwidget_view
);
874 gtk_widget_destroy (xv
->widgetwindow
);
875 Vxwidget_view_list
= Fdelq (xwidget_view
, Vxwidget_view_list
);
876 /* xv->model still has signals pointing to the view. There can be
877 several views. Find the matching signals and delete them all. */
878 g_signal_handlers_disconnect_matched (XXWIDGET (xv
->model
)->widgetwindow_osr
,
885 DEFUN ("xwidget-view-lookup",
886 Fxwidget_view_lookup
, Sxwidget_view_lookup
,
888 doc
: /* Return the xwidget-view associated with XWIDGET in WINDOW.
889 If WINDOW is unspecified or nil, use the selected window.
890 Return nil if no association is found. */)
891 (Lisp_Object xwidget
, Lisp_Object window
)
893 CHECK_XWIDGET (xwidget
);
896 window
= Fselected_window ();
897 CHECK_WINDOW (window
);
899 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
);
902 Lisp_Object xwidget_view
= XCAR (tail
);
903 if (EQ (Fxwidget_view_model (xwidget_view
), xwidget
)
904 && EQ (Fxwidget_view_window (xwidget_view
), window
))
911 DEFUN ("xwidget-plist",
912 Fxwidget_plist
, Sxwidget_plist
,
914 doc
: /* Return the plist of XWIDGET. */)
915 (Lisp_Object xwidget
)
917 CHECK_XWIDGET (xwidget
);
918 return XXWIDGET (xwidget
)->plist
;
921 DEFUN ("xwidget-buffer",
922 Fxwidget_buffer
, Sxwidget_buffer
,
924 doc
: /* Return the buffer of XWIDGET. */)
925 (Lisp_Object xwidget
)
927 CHECK_XWIDGET (xwidget
);
928 return XXWIDGET (xwidget
)->buffer
;
931 DEFUN ("set-xwidget-plist",
932 Fset_xwidget_plist
, Sset_xwidget_plist
,
934 doc
: /* Replace the plist of XWIDGET with PLIST.
936 (Lisp_Object xwidget
, Lisp_Object plist
)
938 CHECK_XWIDGET (xwidget
);
941 XXWIDGET (xwidget
)->plist
= plist
;
945 DEFUN ("set-xwidget-query-on-exit-flag",
946 Fset_xwidget_query_on_exit_flag
, Sset_xwidget_query_on_exit_flag
,
948 doc
: /* Specify if query is needed for XWIDGET when Emacs is exited.
949 If the second argument FLAG is non-nil, Emacs will query the user before
950 exiting or killing a buffer if XWIDGET is running.
951 This function returns FLAG. */)
952 (Lisp_Object xwidget
, Lisp_Object flag
)
954 CHECK_XWIDGET (xwidget
);
955 XXWIDGET (xwidget
)->kill_without_query
= NILP (flag
);
959 DEFUN ("xwidget-query-on-exit-flag",
960 Fxwidget_query_on_exit_flag
, Sxwidget_query_on_exit_flag
,
962 doc
: /* Return the current value of the query-on-exit flag for XWIDGET. */)
963 (Lisp_Object xwidget
)
965 CHECK_XWIDGET (xwidget
);
966 return (XXWIDGET (xwidget
)->kill_without_query
? Qnil
: Qt
);
970 syms_of_xwidget (void)
972 defsubr (&Smake_xwidget
);
973 defsubr (&Sxwidgetp
);
974 DEFSYM (Qxwidgetp
, "xwidgetp");
975 defsubr (&Sxwidget_view_p
);
976 DEFSYM (Qxwidget_view_p
, "xwidget-view-p");
977 defsubr (&Sxwidget_info
);
978 defsubr (&Sxwidget_view_info
);
979 defsubr (&Sxwidget_resize
);
980 defsubr (&Sget_buffer_xwidgets
);
981 defsubr (&Sxwidget_view_model
);
982 defsubr (&Sxwidget_view_window
);
983 defsubr (&Sxwidget_view_lookup
);
984 defsubr (&Sxwidget_query_on_exit_flag
);
985 defsubr (&Sset_xwidget_query_on_exit_flag
);
987 defsubr (&Sxwidget_webkit_goto_uri
);
988 defsubr (&Sxwidget_webkit_execute_script
);
989 defsubr (&Sxwidget_webkit_get_title
);
990 DEFSYM (Qwebkit_osr
, "webkit-osr");
992 defsubr (&Sxwidget_size_request
);
993 defsubr (&Sdelete_xwidget_view
);
995 defsubr (&Sxwidget_plist
);
996 defsubr (&Sxwidget_buffer
);
997 defsubr (&Sset_xwidget_plist
);
999 defsubr (&Sxwidget_set_adjustment
);
1001 DEFSYM (Qxwidget
, "xwidget");
1003 DEFSYM (QCxwidget
, ":xwidget");
1004 DEFSYM (QCtitle
, ":title");
1006 /* Do not forget to update the docstring of make-xwidget if you add
1009 DEFSYM (Qvertical
, "vertical");
1010 DEFSYM (Qhorizontal
, "horizontal");
1012 DEFSYM (QCplist
, ":plist");
1014 DEFVAR_LISP ("xwidget-list", Vxwidget_list
,
1015 doc
: /* xwidgets list. */);
1016 Vxwidget_list
= Qnil
;
1018 DEFVAR_LISP ("xwidget-view-list", Vxwidget_view_list
,
1019 doc
: /* xwidget views list. */);
1020 Vxwidget_view_list
= Qnil
;
1022 Fprovide (intern ("xwidget-internal"), Qnil
);
1026 /* Value is non-zero if OBJECT is a valid Lisp xwidget specification. A
1027 valid xwidget specification is a list whose car is the symbol
1028 `xwidget', and whose rest is a property list. The property list must
1029 contain a value for key `:type'. That value must be the name of a
1030 supported xwidget type. The rest of the property list depends on the
1034 valid_xwidget_spec_p (Lisp_Object object
)
1036 return CONSP (object
) && EQ (XCAR (object
), Qxwidget
);
1040 /* Find a value associated with key in spec. */
1042 xwidget_spec_value (Lisp_Object spec
, Lisp_Object key
)
1046 eassert (valid_xwidget_spec_p (spec
));
1048 for (tail
= XCDR (spec
);
1049 CONSP (tail
) && CONSP (XCDR (tail
)); tail
= XCDR (XCDR (tail
)))
1051 if (EQ (XCAR (tail
), key
))
1052 return XCAR (XCDR (tail
));
1060 xwidget_view_delete_all_in_window (struct window
*w
)
1062 struct xwidget_view
*xv
= NULL
;
1063 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
);
1066 if (XWIDGET_VIEW_P (XCAR (tail
)))
1068 xv
= XXWIDGET_VIEW (XCAR (tail
));
1069 if (XWINDOW (xv
->w
) == w
)
1071 Fdelete_xwidget_view (XCAR (tail
));
1077 static struct xwidget_view
*
1078 xwidget_view_lookup (struct xwidget
*xw
, struct window
*w
)
1080 Lisp_Object xwidget
, window
, ret
;
1081 XSETXWIDGET (xwidget
, xw
);
1082 XSETWINDOW (window
, w
);
1084 ret
= Fxwidget_view_lookup (xwidget
, window
);
1086 return EQ (ret
, Qnil
) ? NULL
: XXWIDGET_VIEW (ret
);
1090 lookup_xwidget (Lisp_Object spec
)
1092 /* When a xwidget lisp spec is found initialize the C struct that is
1093 used in the C code. This is done by redisplay so values change
1094 if the spec changes. So, take special care of one-shot events. */
1098 value
= xwidget_spec_value (spec
, QCxwidget
);
1099 xw
= XXWIDGET (value
);
1104 /* Set up detection of touched xwidget. */
1106 xwidget_start_redisplay (void)
1108 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
);
1111 if (XWIDGET_VIEW_P (XCAR (tail
)))
1112 XXWIDGET_VIEW (XCAR (tail
))->redisplayed
= false;
1116 /* The xwidget was touched during redisplay, so it isn't a candidate
1119 xwidget_touch (struct xwidget_view
*xv
)
1121 xv
->redisplayed
= true;
1125 xwidget_touched (struct xwidget_view
*xv
)
1127 return xv
->redisplayed
;
1130 /* Redisplay has ended, now we should hide untouched xwidgets. */
1132 xwidget_end_redisplay (struct window
*w
, struct glyph_matrix
*matrix
)
1137 xwidget_start_redisplay ();
1138 /* Iterate desired glyph matrix of window here, hide gtk widgets
1139 not in the desired matrix.
1141 This only takes care of xwidgets in active windows. If a window
1142 goes away from the screen, xwidget views must be deleted.
1144 dump_glyph_matrix (matrix, 2); */
1145 for (i
= 0; i
< matrix
->nrows
; ++i
)
1147 /* dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs); */
1148 struct glyph_row
*row
;
1149 row
= MATRIX_ROW (matrix
, i
);
1151 for (area
= LEFT_MARGIN_AREA
; area
< LAST_AREA
; ++area
)
1153 struct glyph
*glyph
= row
->glyphs
[area
];
1154 struct glyph
*glyph_end
= glyph
+ row
->used
[area
];
1155 for (; glyph
< glyph_end
; ++glyph
)
1156 if (glyph
->type
== XWIDGET_GLYPH
)
1158 /* The only call to xwidget_end_redisplay is in dispnew.
1159 xwidget_end_redisplay (w->current_matrix); */
1160 xwidget_touch (xwidget_view_lookup (glyph
->u
.xwidget
, w
));
1165 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
);
1168 if (XWIDGET_VIEW_P (XCAR (tail
)))
1170 struct xwidget_view
*xv
= XXWIDGET_VIEW (XCAR (tail
));
1172 /* "touched" is only meaningful for the current window, so
1173 disregard other views. */
1174 if (XWINDOW (xv
->w
) == w
)
1176 if (xwidget_touched (xv
))
1177 xwidget_show_view (xv
);
1179 xwidget_hide_view (xv
);
1185 /* Kill all xwidget in BUFFER. */
1187 kill_buffer_xwidgets (Lisp_Object buffer
)
1189 Lisp_Object tail
, xwidget
;
1190 for (tail
= Fget_buffer_xwidgets (buffer
); CONSP (tail
); tail
= XCDR (tail
))
1192 xwidget
= XCAR (tail
);
1193 Vxwidget_list
= Fdelq (xwidget
, Vxwidget_list
);
1194 /* TODO free the GTK things in xw. */
1196 CHECK_XWIDGET (xwidget
);
1197 struct xwidget
*xw
= XXWIDGET (xwidget
);
1198 if (xw
->widget_osr
&& xw
->widgetwindow_osr
)
1200 gtk_widget_destroy (xw
->widget_osr
);
1201 gtk_widget_destroy (xw
->widgetwindow_osr
);