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 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. */)
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
);
176 struct xwidget
*xw
= allocate_xwidget ();
180 xw
->buffer
= NILP (buffer
) ? Fcurrent_buffer () : Fget_buffer_create (buffer
);
181 xw
->height
= XFASTINT (height
);
182 xw
->width
= XFASTINT (width
);
183 xw
->kill_without_query
= false;
184 XSETXWIDGET (val
, xw
);
185 Vxwidget_list
= Fcons (val
, Vxwidget_list
);
186 xw
->widgetwindow_osr
= NULL
;
187 xw
->widget_osr
= NULL
;
190 if (EQ (xw
->type
, Qwebkit
))
193 xw
->widgetwindow_osr
= gtk_offscreen_window_new ();
194 gtk_window_resize (GTK_WINDOW (xw
->widgetwindow_osr
), xw
->width
,
197 /* WebKit OSR is the only scrolled component at the moment. */
198 xw
->widgetscrolledwindow_osr
= NULL
;
200 if (EQ (xw
->type
, Qwebkit
))
202 xw
->widgetscrolledwindow_osr
= gtk_scrolled_window_new (NULL
, NULL
);
203 gtk_scrolled_window_set_min_content_height
204 (GTK_SCROLLED_WINDOW (xw
->widgetscrolledwindow_osr
),
206 gtk_scrolled_window_set_min_content_width
207 (GTK_SCROLLED_WINDOW (xw
->widgetscrolledwindow_osr
),
209 gtk_scrolled_window_set_policy
210 (GTK_SCROLLED_WINDOW (xw
->widgetscrolledwindow_osr
),
211 GTK_POLICY_ALWAYS
, GTK_POLICY_ALWAYS
);
213 xw
->widget_osr
= webkit_web_view_new ();
214 gtk_container_add (GTK_CONTAINER (xw
->widgetscrolledwindow_osr
),
215 GTK_WIDGET (WEBKIT_WEB_VIEW (xw
->widget_osr
)));
218 gtk_widget_set_size_request (GTK_WIDGET (xw
->widget_osr
), xw
->width
,
221 if (EQ (xw
->type
, Qwebkit
))
223 gtk_container_add (GTK_CONTAINER (xw
->widgetwindow_osr
),
224 xw
->widgetscrolledwindow_osr
);
228 gtk_container_add (GTK_CONTAINER (xw
->widgetwindow_osr
),
232 gtk_widget_show (xw
->widget_osr
);
233 gtk_widget_show (xw
->widgetwindow_osr
);
234 gtk_widget_show (xw
->widgetscrolledwindow_osr
);
236 /* Store some xwidget data in the gtk widgets for convenient
237 retrieval in the event handlers. */
238 g_object_set_data (G_OBJECT (xw
->widget_osr
), XG_XWIDGET
, xw
);
239 g_object_set_data (G_OBJECT (xw
->widgetwindow_osr
), XG_XWIDGET
, xw
);
242 if (EQ (xw
->type
, Qwebkit
))
244 g_signal_connect (G_OBJECT (xw
->widget_osr
),
245 "document-load-finished",
246 G_CALLBACK (webkit_document_load_finished_cb
), xw
);
248 g_signal_connect (G_OBJECT (xw
->widget_osr
),
249 "download-requested",
250 G_CALLBACK (webkit_download_cb
), xw
);
252 g_signal_connect (G_OBJECT (xw
->widget_osr
),
253 "mime-type-policy-decision-requested",
255 (webkit_mime_type_policy_typedecision_requested_cb
),
258 g_signal_connect (G_OBJECT (xw
->widget_osr
),
259 "new-window-policy-decision-requested",
261 (webkit_new_window_policy_decision_requested_cb
),
264 g_signal_connect (G_OBJECT (xw
->widget_osr
),
265 "navigation-policy-decision-requested",
267 (webkit_navigation_policy_decision_requested_cb
),
277 DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets
, Sget_buffer_xwidgets
,
279 doc
: /* Return a list of xwidgets associated with BUFFER.
280 BUFFER may be a buffer or the name of one. */)
283 Lisp_Object xw
, tail
, xw_list
;
287 buffer
= Fget_buffer (buffer
);
293 for (tail
= Vxwidget_list
; CONSP (tail
); tail
= XCDR (tail
))
296 if (XWIDGETP (xw
) && EQ (Fxwidget_buffer (xw
), buffer
))
297 xw_list
= Fcons (xw
, xw_list
);
303 xwidget_hidden (struct xwidget_view
*xv
)
309 xwidget_show_view (struct xwidget_view
*xv
)
312 gtk_widget_show (xv
->widgetwindow
);
313 gtk_fixed_move (GTK_FIXED (xv
->emacswindow
),
315 xv
->x
+ xv
->clip_left
,
316 xv
->y
+ xv
->clip_top
);
319 /* Hide an xwidget view. */
321 xwidget_hide_view (struct xwidget_view
*xv
)
324 gtk_fixed_move (GTK_FIXED (xv
->emacswindow
), xv
->widgetwindow
,
328 /* When the off-screen webkit master view changes this signal is called.
329 It copies the bitmap from the off-screen instance. */
331 offscreen_damage_event (GtkWidget
*widget
, GdkEvent
*event
,
334 /* Queue a redraw of onscreen widget.
335 There is a guard against receiving an invalid widget,
336 which should only happen if we failed to remove the
337 specific signal handler for the damage event. */
338 if (GTK_IS_WIDGET (xv_widget
))
339 gtk_widget_queue_draw (GTK_WIDGET (xv_widget
));
341 printf ("Warning, offscreen_damage_event received invalid xv pointer:%p\n",
348 store_xwidget_event_string (struct xwidget
*xw
, const char *eventname
,
349 const char *eventstr
)
351 struct input_event event
;
353 XSETXWIDGET (xwl
, xw
);
355 event
.kind
= XWIDGET_EVENT
;
356 event
.frame_or_window
= Qnil
;
357 event
.arg
= list3 (intern (eventname
), xwl
, build_string (eventstr
));
358 kbd_buffer_store_event (&event
);
361 /* TODO deprecated, use load-status. */
363 webkit_document_load_finished_cb (WebKitWebView
*webkitwebview
,
364 WebKitWebFrame
*arg1
,
367 struct xwidget
*xw
= g_object_get_data (G_OBJECT (webkitwebview
),
370 store_xwidget_event_string (xw
, "document-load-finished", "");
374 webkit_download_cb (WebKitWebView
*webkitwebview
,
375 WebKitDownload
*arg1
,
378 struct xwidget
*xw
= g_object_get_data (G_OBJECT (webkitwebview
),
380 store_xwidget_event_string (xw
, "download-requested",
381 webkit_download_get_uri (arg1
));
386 webkit_mime_type_policy_typedecision_requested_cb (WebKitWebView
*webView
,
387 WebKitWebFrame
*frame
,
388 WebKitNetworkRequest
*request
,
390 WebKitWebPolicyDecision
*policy_decision
,
393 /* This function makes webkit send a download signal for all unknown
394 mime types. TODO: Defer the decision to Lisp, so that it's
395 possible to make Emacs handle mime text for instance. */
396 if (!webkit_web_view_can_show_mime_type (webView
, mimetype
))
398 webkit_web_policy_decision_download (policy_decision
);
406 webkit_new_window_policy_decision_requested_cb (WebKitWebView
*webView
,
407 WebKitWebFrame
*frame
,
408 WebKitNetworkRequest
*request
,
409 WebKitWebNavigationAction
*navigation_action
,
410 WebKitWebPolicyDecision
*policy_decision
,
413 struct xwidget
*xw
= g_object_get_data (G_OBJECT (webView
), XG_XWIDGET
);
414 webkit_web_navigation_action_get_original_uri (navigation_action
);
416 store_xwidget_event_string (xw
, "new-window-policy-decision-requested",
417 webkit_web_navigation_action_get_original_uri
418 (navigation_action
));
423 webkit_navigation_policy_decision_requested_cb (WebKitWebView
*webView
,
424 WebKitWebFrame
*frame
,
425 WebKitNetworkRequest
*request
,
426 WebKitWebNavigationAction
*navigation_action
,
427 WebKitWebPolicyDecision
*policy_decision
,
430 struct xwidget
*xw
= g_object_get_data (G_OBJECT (webView
), XG_XWIDGET
);
431 store_xwidget_event_string (xw
, "navigation-policy-decision-requested",
432 webkit_web_navigation_action_get_original_uri
433 (navigation_action
));
437 /* For gtk3 offscreen rendered widgets. */
439 xwidget_osr_draw_cb (GtkWidget
*widget
, cairo_t
*cr
, gpointer data
)
441 struct xwidget
*xw
= g_object_get_data (G_OBJECT (widget
), XG_XWIDGET
);
442 struct xwidget_view
*xv
= g_object_get_data (G_OBJECT (widget
),
445 cairo_rectangle (cr
, 0, 0, xv
->clip_right
, xv
->clip_bottom
);
448 if (xw
->widgetscrolledwindow_osr
!= NULL
)
449 gtk_widget_draw (xw
->widgetscrolledwindow_osr
, cr
);
451 gtk_widget_draw (xw
->widget_osr
, cr
);
456 xwidget_osr_event_forward (GtkWidget
*widget
, GdkEvent
*event
,
459 /* Copy events that arrive at the outer widget to the offscreen widget. */
460 struct xwidget
*xw
= g_object_get_data (G_OBJECT (widget
), XG_XWIDGET
);
461 GdkEvent
*eventcopy
= gdk_event_copy (event
);
462 eventcopy
->any
.window
= gtk_widget_get_window (xw
->widget_osr
);
464 /* TODO: This might leak events. They should be deallocated later,
465 perhaps in xwgir_event_cb. */
466 gtk_main_do_event (eventcopy
);
468 /* Don't propagate this event further. */
473 xwidget_osr_event_set_embedder (GtkWidget
*widget
, GdkEvent
*event
,
476 struct xwidget_view
*xv
= data
;
477 struct xwidget
*xww
= XXWIDGET (xv
->model
);
478 gdk_offscreen_window_set_embedder (gtk_widget_get_window
479 (xww
->widgetwindow_osr
),
480 gtk_widget_get_window (xv
->widget
));
485 /* Initializes and does initial placement of an xwidget view on screen. */
486 static struct xwidget_view
*
487 xwidget_init_view (struct xwidget
*xww
,
488 struct glyph_string
*s
,
491 struct xwidget_view
*xv
= allocate_xwidget_view ();
494 XSETXWIDGET_VIEW (val
, xv
);
495 Vxwidget_view_list
= Fcons (val
, Vxwidget_view_list
);
497 XSETWINDOW (xv
->w
, s
->w
);
498 XSETXWIDGET (xv
->model
, xww
);
500 if (EQ (xww
->type
, Qwebkit
))
502 xv
->widget
= gtk_drawing_area_new ();
503 /* Expose event handling. */
504 gtk_widget_set_app_paintable (xv
->widget
, TRUE
);
505 gtk_widget_add_events (xv
->widget
, GDK_ALL_EVENTS_MASK
);
507 /* Draw the view on damage-event. */
508 g_signal_connect (G_OBJECT (xww
->widgetwindow_osr
), "damage-event",
509 G_CALLBACK (offscreen_damage_event
), xv
->widget
);
511 if (EQ (xww
->type
, Qwebkit
))
513 g_signal_connect (G_OBJECT (xv
->widget
), "button-press-event",
514 G_CALLBACK (xwidget_osr_event_forward
), NULL
);
515 g_signal_connect (G_OBJECT (xv
->widget
), "button-release-event",
516 G_CALLBACK (xwidget_osr_event_forward
), NULL
);
517 g_signal_connect (G_OBJECT (xv
->widget
), "motion-notify-event",
518 G_CALLBACK (xwidget_osr_event_forward
), NULL
);
522 /* xwgir debug, orthogonal to forwarding. */
523 g_signal_connect (G_OBJECT (xv
->widget
), "enter-notify-event",
524 G_CALLBACK (xwidget_osr_event_set_embedder
), xv
);
526 g_signal_connect (G_OBJECT (xv
->widget
), "draw",
527 G_CALLBACK (xwidget_osr_draw_cb
), NULL
);
530 /* Widget realization.
532 Make container widget first, and put the actual widget inside the
533 container later. Drawing should crop container window if necessary
534 to handle case where xwidget is partially obscured by other Emacs
535 windows. Other containers than gtk_fixed where explored, but
536 gtk_fixed had the most predictable behavior so far. */
538 xv
->emacswindow
= FRAME_GTK_WIDGET (s
->f
);
539 xv
->widgetwindow
= gtk_fixed_new ();
540 gtk_widget_set_has_window (xv
->widgetwindow
, TRUE
);
541 gtk_container_add (GTK_CONTAINER (xv
->widgetwindow
), xv
->widget
);
543 /* Store some xwidget data in the gtk widgets. */
544 g_object_set_data (G_OBJECT (xv
->widget
), XG_FRAME_DATA
, s
->f
);
545 g_object_set_data (G_OBJECT (xv
->widget
), XG_XWIDGET
, xww
);
546 g_object_set_data (G_OBJECT (xv
->widget
), XG_XWIDGET_VIEW
, xv
);
547 g_object_set_data (G_OBJECT (xv
->widgetwindow
), XG_XWIDGET
, xww
);
548 g_object_set_data (G_OBJECT (xv
->widgetwindow
), XG_XWIDGET_VIEW
, xv
);
550 gtk_widget_set_size_request (GTK_WIDGET (xv
->widget
), xww
->width
,
552 gtk_widget_set_size_request (xv
->widgetwindow
, xww
->width
, xww
->height
);
553 gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s
->f
)), xv
->widgetwindow
, x
, y
);
556 gtk_widget_show_all (xv
->widgetwindow
);
562 x_draw_xwidget_glyph_string (struct glyph_string
*s
)
564 /* This method is called by the redisplay engine and places the
565 xwidget on screen. Moving and clipping is done here. Also view
567 struct xwidget
*xww
= s
->xwidget
;
568 struct xwidget_view
*xv
= xwidget_view_lookup (xww
, s
->w
);
575 int y
= s
->y
+ (s
->height
/ 2) - (xww
->height
/ 2);
577 /* Do initialization here in the display loop because there is no
578 other time to know things like window placement etc. */
579 xv
= xwidget_init_view (xww
, s
, x
, y
);
581 int text_area_x
, text_area_y
, text_area_width
, text_area_height
;
589 clip_right
= min (xww
->width
,
594 clip_bottom
= min (xww
->height
,
596 clip_top
= max (0, text_area_y
);
598 /* We are concerned with movement of the onscreen area. The area
599 might sit still when the widget actually moves. This happens
600 when an Emacs window border moves across a widget window. So, if
601 any corner of the outer widget clipping window moves, that counts
602 as movement here, even if it looks like no movement happens
603 because the widget sits still inside the clipping area. The
604 widget can also move inside the clipping area, which happens
606 bool moved
= (xv
->x
+ xv
->clip_left
!= x
+ clip_left
607 || xv
->y
+ xv
->clip_top
!= y
+ clip_top
);
613 gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s
->f
)),
614 xv
->widgetwindow
, x
+ clip_left
, y
+ clip_top
);
616 /* Clip the widget window if some parts happen to be outside
617 drawable area. An Emacs window is not a gtk window. A gtk window
618 covers the entire frame. Clipping might have changed even if we
619 haven't actually moved; try to figure out when we need to reclip
621 if (xv
->clip_right
!= clip_right
622 || xv
->clip_bottom
!= clip_bottom
623 || xv
->clip_top
!= clip_top
|| xv
->clip_left
!= clip_left
)
625 gtk_widget_set_size_request (xv
->widgetwindow
, clip_right
+ clip_left
,
626 clip_bottom
+ clip_top
);
627 gtk_fixed_move (GTK_FIXED (xv
->widgetwindow
), xv
->widget
, -clip_left
,
630 xv
->clip_right
= clip_right
;
631 xv
->clip_bottom
= clip_bottom
;
632 xv
->clip_top
= clip_top
;
633 xv
->clip_left
= clip_left
;
636 /* If emacs wants to repaint the area where the widget lives, queue
637 a redraw. It seems its possible to get out of sync with emacs
638 redraws so emacs background sometimes shows up instead of the
639 xwidgets background. It's just a visual glitch though. */
640 if (!xwidget_hidden (xv
))
642 gtk_widget_queue_draw (xv
->widgetwindow
);
643 gtk_widget_queue_draw (xv
->widget
);
647 /* Macro that checks WEBKIT_IS_WEB_VIEW (xw->widget_osr) first. */
648 #define WEBKIT_FN_INIT() \
649 CHECK_XWIDGET (xwidget); \
650 struct xwidget *xw = XXWIDGET (xwidget); \
651 if (!xw->widget_osr || !WEBKIT_IS_WEB_VIEW (xw->widget_osr)) \
653 printf ("ERROR xw->widget_osr does not hold a webkit instance\n"); \
657 DEFUN ("xwidget-webkit-goto-uri",
658 Fxwidget_webkit_goto_uri
, Sxwidget_webkit_goto_uri
,
660 doc
: /* Make the xwidget webkit instance referenced by XWIDGET browse URI. */)
661 (Lisp_Object xwidget
, Lisp_Object uri
)
665 webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw
->widget_osr
), SSDATA (uri
));
670 DEFUN ("xwidget-webkit-execute-script",
671 Fxwidget_webkit_execute_script
, Sxwidget_webkit_execute_script
,
673 doc
: /* Make the Webkit XWIDGET execute JavaScript SCRIPT. */)
674 (Lisp_Object xwidget
, Lisp_Object script
)
677 CHECK_STRING (script
);
678 webkit_web_view_execute_script (WEBKIT_WEB_VIEW (xw
->widget_osr
),
683 DEFUN ("xwidget-webkit-get-title",
684 Fxwidget_webkit_get_title
, Sxwidget_webkit_get_title
,
686 doc
: /* Return the title from the Webkit instance in XWIDGET.
687 This can be used to work around the lack of a return value from the
689 (Lisp_Object xwidget
)
691 /* TODO support multibyte strings. */
694 webkit_web_view_get_title (WEBKIT_WEB_VIEW (xw
->widget_osr
));
697 /* TODO maybe return Qnil instead. I suppose webkit returns
698 null pointer when doc is not properly loaded or something. */
699 return build_string ("");
701 return build_string (str
);
704 DEFUN ("xwidget-resize", Fxwidget_resize
, Sxwidget_resize
, 3, 3, 0,
705 doc
: /* Resize XWIDGET. NEW_WIDTH, NEW_HEIGHT define the new size. */ )
706 (Lisp_Object xwidget
, Lisp_Object new_width
, Lisp_Object new_height
)
708 CHECK_XWIDGET (xwidget
);
709 CHECK_NATNUM (new_width
);
710 CHECK_NATNUM (new_height
);
711 struct xwidget
*xw
= XXWIDGET (xwidget
);
712 int w
= XFASTINT (new_width
);
713 int h
= XFASTINT (new_height
);
718 /* If there is an offscreen widget resize it first. */
721 /* Use minimum size. */
722 gtk_widget_set_size_request (GTK_WIDGET (xw
->widget_osr
),
723 xw
->width
, xw
->height
);
725 gtk_window_resize (GTK_WINDOW (xw
->widgetwindow_osr
), xw
->width
,
727 gtk_scrolled_window_set_min_content_height
728 (GTK_SCROLLED_WINDOW (xw
->widgetscrolledwindow_osr
),
730 gtk_scrolled_window_set_min_content_width
731 (GTK_SCROLLED_WINDOW (xw
->widgetscrolledwindow_osr
),
734 gtk_container_resize_children (GTK_CONTAINER (xw
->widgetwindow_osr
));
738 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
); tail
= XCDR (tail
))
740 if (XWIDGET_VIEW_P (XCAR (tail
)))
742 struct xwidget_view
*xv
= XXWIDGET_VIEW (XCAR (tail
));
743 if (XXWIDGET (xv
->model
) == xw
)
744 gtk_widget_set_size_request (GTK_WIDGET (xv
->widget
), xw
->width
,
754 DEFUN ("xwidget-set-adjustment",
755 Fxwidget_set_adjustment
, Sxwidget_set_adjustment
, 4, 4, 0,
756 doc
: /* Set native scrolling for XWIDGET.
757 AXIS can be `vertical' or `horizontal'.
758 If RELATIVE is t, scroll relative, otherwise absolutely.
759 VALUE is the amount to scroll, either relatively or absolutely. */)
760 (Lisp_Object xwidget
, Lisp_Object axis
, Lisp_Object relative
,
763 CHECK_XWIDGET (xwidget
);
764 CHECK_NUMBER (value
);
765 struct xwidget
*xw
= XXWIDGET (xwidget
);
766 GtkAdjustment
*adjustment
767 = ((EQ (Qhorizontal
, axis
)
768 ? gtk_scrolled_window_get_hadjustment
769 : gtk_scrolled_window_get_vadjustment
)
770 (GTK_SCROLLED_WINDOW (xw
->widgetscrolledwindow_osr
)));
771 double final_value
= XINT (value
);
772 if (EQ (Qt
, relative
))
773 final_value
+= gtk_adjustment_get_value (adjustment
);
774 gtk_adjustment_set_value (adjustment
, final_value
);
779 DEFUN ("xwidget-size-request",
780 Fxwidget_size_request
, Sxwidget_size_request
,
782 doc
: /* Return the desired size of the XWIDGET.
783 This can be used to read the xwidget desired size, and resizes the
784 Emacs allocated area accordingly. */)
785 (Lisp_Object xwidget
)
787 CHECK_XWIDGET (xwidget
);
788 GtkRequisition requisition
;
789 gtk_widget_size_request (XXWIDGET (xwidget
)->widget_osr
, &requisition
);
790 return list2 (make_number (requisition
.width
),
791 make_number (requisition
.height
));
795 Fxwidgetp
, Sxwidgetp
,
797 doc
: /* Return t if OBJECT is an xwidget. */)
800 return XWIDGETP (object
) ? Qt
: Qnil
;
803 DEFUN ("xwidget-view-p",
804 Fxwidget_view_p
, Sxwidget_view_p
,
806 doc
: /* Return t if OBJECT is an xwidget-view. */)
809 return XWIDGET_VIEW_P (object
) ? Qt
: Qnil
;
812 DEFUN ("xwidget-info",
813 Fxwidget_info
, Sxwidget_info
,
815 doc
: /* Return XWIDGET properties in a vector.
816 Currently [TYPE TITLE WIDTH HEIGHT]. */)
817 (Lisp_Object xwidget
)
819 CHECK_XWIDGET (xwidget
);
820 struct xwidget
*xw
= XXWIDGET (xwidget
);
821 return CALLN (Fvector
, xw
->type
, xw
->title
,
822 make_natnum (xw
->width
), make_natnum (xw
->height
));
825 DEFUN ("xwidget-view-info",
826 Fxwidget_view_info
, Sxwidget_view_info
,
828 doc
: /* Return properties of XWIDGET-VIEW in a vector.
829 Currently [X Y CLIP_RIGHT CLIP_BOTTOM CLIP_TOP CLIP_LEFT]. */)
830 (Lisp_Object xwidget_view
)
832 CHECK_XWIDGET_VIEW (xwidget_view
);
833 struct xwidget_view
*xv
= XXWIDGET_VIEW (xwidget_view
);
834 return CALLN (Fvector
, make_number (xv
->x
), make_number (xv
->y
),
835 make_number (xv
->clip_right
), make_number (xv
->clip_bottom
),
836 make_number (xv
->clip_top
), make_number (xv
->clip_left
));
839 DEFUN ("xwidget-view-model",
840 Fxwidget_view_model
, Sxwidget_view_model
,
842 doc
: /* Return the model associated with XWIDGET-VIEW. */)
843 (Lisp_Object xwidget_view
)
845 CHECK_XWIDGET_VIEW (xwidget_view
);
846 return XXWIDGET_VIEW (xwidget_view
)->model
;
849 DEFUN ("xwidget-view-window",
850 Fxwidget_view_window
, Sxwidget_view_window
,
852 doc
: /* Return the window of XWIDGET-VIEW. */)
853 (Lisp_Object xwidget_view
)
855 CHECK_XWIDGET_VIEW (xwidget_view
);
856 return XXWIDGET_VIEW (xwidget_view
)->w
;
860 DEFUN ("delete-xwidget-view",
861 Fdelete_xwidget_view
, Sdelete_xwidget_view
,
863 doc
: /* Delete the XWIDGET-VIEW. */)
864 (Lisp_Object xwidget_view
)
866 CHECK_XWIDGET_VIEW (xwidget_view
);
867 struct xwidget_view
*xv
= XXWIDGET_VIEW (xwidget_view
);
868 gtk_widget_destroy (xv
->widgetwindow
);
869 Vxwidget_view_list
= Fdelq (xwidget_view
, Vxwidget_view_list
);
870 /* xv->model still has signals pointing to the view. There can be
871 several views. Find the matching signals and delete them all. */
872 g_signal_handlers_disconnect_matched (XXWIDGET (xv
->model
)->widgetwindow_osr
,
879 DEFUN ("xwidget-view-lookup",
880 Fxwidget_view_lookup
, Sxwidget_view_lookup
,
882 doc
: /* Return the xwidget-view associated with XWIDGET in WINDOW.
883 If WINDOW is unspecified or nil, use the selected window.
884 Return nil if no association is found. */)
885 (Lisp_Object xwidget
, Lisp_Object window
)
887 CHECK_XWIDGET (xwidget
);
890 window
= Fselected_window ();
891 CHECK_WINDOW (window
);
893 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
);
896 Lisp_Object xwidget_view
= XCAR (tail
);
897 if (EQ (Fxwidget_view_model (xwidget_view
), xwidget
)
898 && EQ (Fxwidget_view_window (xwidget_view
), window
))
905 DEFUN ("xwidget-plist",
906 Fxwidget_plist
, Sxwidget_plist
,
908 doc
: /* Return the plist of XWIDGET. */)
909 (Lisp_Object xwidget
)
911 CHECK_XWIDGET (xwidget
);
912 return XXWIDGET (xwidget
)->plist
;
915 DEFUN ("xwidget-buffer",
916 Fxwidget_buffer
, Sxwidget_buffer
,
918 doc
: /* Return the buffer of XWIDGET. */)
919 (Lisp_Object xwidget
)
921 CHECK_XWIDGET (xwidget
);
922 return XXWIDGET (xwidget
)->buffer
;
925 DEFUN ("set-xwidget-plist",
926 Fset_xwidget_plist
, Sset_xwidget_plist
,
928 doc
: /* Replace the plist of XWIDGET with PLIST.
930 (Lisp_Object xwidget
, Lisp_Object plist
)
932 CHECK_XWIDGET (xwidget
);
935 XXWIDGET (xwidget
)->plist
= plist
;
939 DEFUN ("set-xwidget-query-on-exit-flag",
940 Fset_xwidget_query_on_exit_flag
, Sset_xwidget_query_on_exit_flag
,
942 doc
: /* Specify if query is needed for XWIDGET when Emacs is exited.
943 If the second argument FLAG is non-nil, Emacs will query the user before
944 exiting or killing a buffer if XWIDGET is running.
945 This function returns FLAG. */)
946 (Lisp_Object xwidget
, Lisp_Object flag
)
948 CHECK_XWIDGET (xwidget
);
949 XXWIDGET (xwidget
)->kill_without_query
= NILP (flag
);
953 DEFUN ("xwidget-query-on-exit-flag",
954 Fxwidget_query_on_exit_flag
, Sxwidget_query_on_exit_flag
,
956 doc
: /* Return the current value of the query-on-exit flag for XWIDGET. */)
957 (Lisp_Object xwidget
)
959 CHECK_XWIDGET (xwidget
);
960 return (XXWIDGET (xwidget
)->kill_without_query
? Qnil
: Qt
);
964 syms_of_xwidget (void)
966 defsubr (&Smake_xwidget
);
967 defsubr (&Sxwidgetp
);
968 DEFSYM (Qxwidgetp
, "xwidgetp");
969 defsubr (&Sxwidget_view_p
);
970 DEFSYM (Qxwidget_view_p
, "xwidget-view-p");
971 defsubr (&Sxwidget_info
);
972 defsubr (&Sxwidget_view_info
);
973 defsubr (&Sxwidget_resize
);
974 defsubr (&Sget_buffer_xwidgets
);
975 defsubr (&Sxwidget_view_model
);
976 defsubr (&Sxwidget_view_window
);
977 defsubr (&Sxwidget_view_lookup
);
978 defsubr (&Sxwidget_query_on_exit_flag
);
979 defsubr (&Sset_xwidget_query_on_exit_flag
);
981 defsubr (&Sxwidget_webkit_goto_uri
);
982 defsubr (&Sxwidget_webkit_execute_script
);
983 defsubr (&Sxwidget_webkit_get_title
);
984 DEFSYM (Qwebkit
, "webkit");
986 defsubr (&Sxwidget_size_request
);
987 defsubr (&Sdelete_xwidget_view
);
989 defsubr (&Sxwidget_plist
);
990 defsubr (&Sxwidget_buffer
);
991 defsubr (&Sset_xwidget_plist
);
993 defsubr (&Sxwidget_set_adjustment
);
995 DEFSYM (Qxwidget
, "xwidget");
997 DEFSYM (QCxwidget
, ":xwidget");
998 DEFSYM (QCtitle
, ":title");
1000 /* Do not forget to update the docstring of make-xwidget if you add
1003 DEFSYM (Qvertical
, "vertical");
1004 DEFSYM (Qhorizontal
, "horizontal");
1006 DEFSYM (QCplist
, ":plist");
1008 DEFVAR_LISP ("xwidget-list", Vxwidget_list
,
1009 doc
: /* xwidgets list. */);
1010 Vxwidget_list
= Qnil
;
1012 DEFVAR_LISP ("xwidget-view-list", Vxwidget_view_list
,
1013 doc
: /* xwidget views list. */);
1014 Vxwidget_view_list
= Qnil
;
1016 Fprovide (intern ("xwidget-internal"), Qnil
);
1020 /* Value is non-zero if OBJECT is a valid Lisp xwidget specification. A
1021 valid xwidget specification is a list whose car is the symbol
1022 `xwidget', and whose rest is a property list. The property list must
1023 contain a value for key `:type'. That value must be the name of a
1024 supported xwidget type. The rest of the property list depends on the
1028 valid_xwidget_spec_p (Lisp_Object object
)
1030 return CONSP (object
) && EQ (XCAR (object
), Qxwidget
);
1034 /* Find a value associated with key in spec. */
1036 xwidget_spec_value (Lisp_Object spec
, Lisp_Object key
)
1040 eassert (valid_xwidget_spec_p (spec
));
1042 for (tail
= XCDR (spec
);
1043 CONSP (tail
) && CONSP (XCDR (tail
)); tail
= XCDR (XCDR (tail
)))
1045 if (EQ (XCAR (tail
), key
))
1046 return XCAR (XCDR (tail
));
1054 xwidget_view_delete_all_in_window (struct window
*w
)
1056 struct xwidget_view
*xv
= NULL
;
1057 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
);
1060 if (XWIDGET_VIEW_P (XCAR (tail
)))
1062 xv
= XXWIDGET_VIEW (XCAR (tail
));
1063 if (XWINDOW (xv
->w
) == w
)
1065 Fdelete_xwidget_view (XCAR (tail
));
1071 static struct xwidget_view
*
1072 xwidget_view_lookup (struct xwidget
*xw
, struct window
*w
)
1074 Lisp_Object xwidget
, window
, ret
;
1075 XSETXWIDGET (xwidget
, xw
);
1076 XSETWINDOW (window
, w
);
1078 ret
= Fxwidget_view_lookup (xwidget
, window
);
1080 return EQ (ret
, Qnil
) ? NULL
: XXWIDGET_VIEW (ret
);
1084 lookup_xwidget (Lisp_Object spec
)
1086 /* When a xwidget lisp spec is found initialize the C struct that is
1087 used in the C code. This is done by redisplay so values change
1088 if the spec changes. So, take special care of one-shot events. */
1092 value
= xwidget_spec_value (spec
, QCxwidget
);
1093 xw
= XXWIDGET (value
);
1098 /* Set up detection of touched xwidget. */
1100 xwidget_start_redisplay (void)
1102 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
);
1105 if (XWIDGET_VIEW_P (XCAR (tail
)))
1106 XXWIDGET_VIEW (XCAR (tail
))->redisplayed
= false;
1110 /* The xwidget was touched during redisplay, so it isn't a candidate
1113 xwidget_touch (struct xwidget_view
*xv
)
1115 xv
->redisplayed
= true;
1119 xwidget_touched (struct xwidget_view
*xv
)
1121 return xv
->redisplayed
;
1124 /* Redisplay has ended, now we should hide untouched xwidgets. */
1126 xwidget_end_redisplay (struct window
*w
, struct glyph_matrix
*matrix
)
1131 xwidget_start_redisplay ();
1132 /* Iterate desired glyph matrix of window here, hide gtk widgets
1133 not in the desired matrix.
1135 This only takes care of xwidgets in active windows. If a window
1136 goes away from the screen, xwidget views must be deleted.
1138 dump_glyph_matrix (matrix, 2); */
1139 for (i
= 0; i
< matrix
->nrows
; ++i
)
1141 /* dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs); */
1142 struct glyph_row
*row
;
1143 row
= MATRIX_ROW (matrix
, i
);
1145 for (area
= LEFT_MARGIN_AREA
; area
< LAST_AREA
; ++area
)
1147 struct glyph
*glyph
= row
->glyphs
[area
];
1148 struct glyph
*glyph_end
= glyph
+ row
->used
[area
];
1149 for (; glyph
< glyph_end
; ++glyph
)
1150 if (glyph
->type
== XWIDGET_GLYPH
)
1152 /* The only call to xwidget_end_redisplay is in dispnew.
1153 xwidget_end_redisplay (w->current_matrix); */
1154 xwidget_touch (xwidget_view_lookup (glyph
->u
.xwidget
, w
));
1159 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
);
1162 if (XWIDGET_VIEW_P (XCAR (tail
)))
1164 struct xwidget_view
*xv
= XXWIDGET_VIEW (XCAR (tail
));
1166 /* "touched" is only meaningful for the current window, so
1167 disregard other views. */
1168 if (XWINDOW (xv
->w
) == w
)
1170 if (xwidget_touched (xv
))
1171 xwidget_show_view (xv
);
1173 xwidget_hide_view (xv
);
1179 /* Kill all xwidget in BUFFER. */
1181 kill_buffer_xwidgets (Lisp_Object buffer
)
1183 Lisp_Object tail
, xwidget
;
1184 for (tail
= Fget_buffer_xwidgets (buffer
); CONSP (tail
); tail
= XCDR (tail
))
1186 xwidget
= XCAR (tail
);
1187 Vxwidget_list
= Fdelq (xwidget
, Vxwidget_list
);
1188 /* TODO free the GTK things in xw. */
1190 CHECK_XWIDGET (xwidget
);
1191 struct xwidget
*xw
= XXWIDGET (xwidget
);
1192 if (xw
->widget_osr
&& xw
->widgetwindow_osr
)
1194 gtk_widget_destroy (xw
->widget_osr
);
1195 gtk_widget_destroy (xw
->widgetwindow_osr
);