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
10 (at 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/>. */
30 #include "blockinput.h"
31 #include "syssignal.h"
34 #include <X11/cursorfont.h>
37 # include <sys/types.h>
41 # include <sys/ioctl.h>
46 #ifndef INCLUDED_FCNTL
55 #include "character.h"
59 #include "dispextern.h"
61 #include "termhooks.h"
68 #include "intervals.h"
75 #include <X11/Shell.h>
77 #include <X11/extensions/Xcomposite.h>
78 #include <X11/extensions/Xrender.h>
80 #ifdef HAVE_SYS_TIME_H
89 #endif /* HAVE_X_WINDOWS */
96 #include "emacsgtkfixed.h"
100 #include <webkit/webkitwebview.h>
101 #include <webkit/webkitwebplugindatabase.h>
102 #include <webkit/webkitwebplugin.h>
103 #include <webkit/webkitglobals.h>
104 #include <webkit/webkitwebnavigationaction.h>
105 #include <webkit/webkitdownload.h>
106 #include <webkit/webkitwebpolicydecision.h>
110 static struct xwidget
*
111 allocate_xwidget (void)
113 return ALLOCATE_PSEUDOVECTOR (struct xwidget
, height
, PVEC_XWIDGET
);
116 static struct xwidget_view
*
117 allocate_xwidget_view (void)
119 return ALLOCATE_PSEUDOVECTOR (struct xwidget_view
, redisplayed
,
123 #define XSETXWIDGET(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET))
124 #define XSETXWIDGET_VIEW(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW))
126 static struct xwidget_view
*xwidget_view_lookup (struct xwidget
*,
128 static void webkit_document_load_finished_cb (WebKitWebView
*, WebKitWebFrame
*,
130 static gboolean
webkit_download_cb (WebKitWebView
*, WebKitDownload
*, gpointer
);
133 webkit_mime_type_policy_typedecision_requested_cb (WebKitWebView
*,
135 WebKitNetworkRequest
*,
137 WebKitWebPolicyDecision
*,
141 webkit_new_window_policy_decision_requested_cb (WebKitWebView
*,
143 WebKitNetworkRequest
*,
144 WebKitWebNavigationAction
*,
145 WebKitWebPolicyDecision
*,
149 webkit_navigation_policy_decision_requested_cb (WebKitWebView
*,
151 WebKitNetworkRequest
*,
152 WebKitWebNavigationAction
*,
153 WebKitWebPolicyDecision
*,
158 DEFUN ("make-xwidget",
159 Fmake_xwidget
, Smake_xwidget
,
161 doc
: /* Make an xwidget from BEG to END of TYPE.
162 If BUFFER is nil, use the current buffer.
163 If BUFFER is a string and no such buffer exists, create it.
164 TYPE is a symbol which can take one of the following values:
168 Returns the newly constructed xwidget, or nil if construction fails. */)
169 (Lisp_Object beg
, Lisp_Object end
,
172 Lisp_Object width
, Lisp_Object height
,
173 Lisp_Object arguments
, Lisp_Object buffer
)
175 //should work a bit like "make-button"(make-button BEG END &rest PROPERTIES)
176 // arg "type" and fwd should be keyword args eventually
177 //(make-xwidget 3 3 'button "oei" 31 31 nil)
178 //(xwidget-info (car xwidget-list))
179 struct xwidget
*xw
= allocate_xwidget ();
184 buffer
= Fcurrent_buffer (); // no need to gcpro because
185 // Fcurrent_buffer doesn't
186 // call Feval/eval_sub.
188 buffer
= Fget_buffer_create (buffer
);
191 xw
->height
= XFASTINT (height
);
192 xw
->width
= XFASTINT (width
);
193 xw
->kill_without_query
= 0;
194 XSETXWIDGET (val
, xw
); // set the vectorlike_header of VAL
195 // with the correct value
196 Vxwidget_list
= Fcons (val
, Vxwidget_list
);
197 xw
->widgetwindow_osr
= NULL
;
198 xw
->widget_osr
= NULL
;
202 if (EQ (xw
->type
, Qwebkit_osr
))
205 xw
->widgetwindow_osr
= gtk_offscreen_window_new ();
206 gtk_window_resize (GTK_WINDOW (xw
->widgetwindow_osr
), xw
->width
,
208 xw
->widgetscrolledwindow_osr
= NULL
; //webkit osr is the
212 if (EQ (xw
->type
, Qwebkit_osr
))
214 xw
->widgetscrolledwindow_osr
= gtk_scrolled_window_new (NULL
, NULL
);
215 gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW
217 widgetscrolledwindow_osr
),
219 gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW
221 widgetscrolledwindow_osr
),
223 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW
224 (xw
->widgetscrolledwindow_osr
),
228 xw
->widget_osr
= webkit_web_view_new ();
229 gtk_container_add (GTK_CONTAINER (xw
->widgetscrolledwindow_osr
),
230 GTK_WIDGET (WEBKIT_WEB_VIEW (xw
->widget_osr
)));
233 gtk_widget_set_size_request (GTK_WIDGET (xw
->widget_osr
), xw
->width
,
236 if (EQ (xw
->type
, Qwebkit_osr
))
238 gtk_container_add (GTK_CONTAINER (xw
->widgetwindow_osr
),
239 xw
->widgetscrolledwindow_osr
);
243 gtk_container_add (GTK_CONTAINER (xw
->widgetwindow_osr
),
247 gtk_widget_show (xw
->widget_osr
);
248 gtk_widget_show (xw
->widgetwindow_osr
);
249 gtk_widget_show (xw
->widgetscrolledwindow_osr
);
251 /* store some xwidget data in the gtk widgets for convenient
252 retrieval in the event handlers. */
253 g_object_set_data (G_OBJECT (xw
->widget_osr
), XG_XWIDGET
,
255 g_object_set_data (G_OBJECT (xw
->widgetwindow_osr
), XG_XWIDGET
,
259 if (EQ (xw
->type
, Qwebkit_osr
))
261 g_signal_connect (G_OBJECT (xw
->widget_osr
),
262 "document-load-finished",
263 G_CALLBACK (webkit_document_load_finished_cb
), xw
);
265 g_signal_connect (G_OBJECT (xw
->widget_osr
),
266 "download-requested",
267 G_CALLBACK (webkit_download_cb
), xw
);
269 g_signal_connect (G_OBJECT (xw
->widget_osr
),
270 "mime-type-policy-decision-requested",
272 (webkit_mime_type_policy_typedecision_requested_cb
),
275 g_signal_connect (G_OBJECT (xw
->widget_osr
),
276 "new-window-policy-decision-requested",
278 (webkit_new_window_policy_decision_requested_cb
),
281 g_signal_connect (G_OBJECT (xw
->widget_osr
),
282 "navigation-policy-decision-requested",
284 (webkit_navigation_policy_decision_requested_cb
),
295 DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets
, Sget_buffer_xwidgets
,
297 doc
: /* Return a list of xwidgets associated with BUFFER.
298 BUFFER may be a buffer or the name of one. */)
301 Lisp_Object xw
, tail
, xw_list
;
305 buffer
= Fget_buffer (buffer
);
311 for (tail
= Vxwidget_list
; CONSP (tail
); tail
= XCDR (tail
))
314 if (XWIDGETP (xw
) && EQ (Fxwidget_buffer (xw
), buffer
))
315 xw_list
= Fcons (xw
, xw_list
);
321 xwidget_hidden (struct xwidget_view
*xv
)
329 xwidget_show_view (struct xwidget_view
*xv
)
332 gtk_widget_show (xv
->widgetwindow
);
333 gtk_fixed_move (GTK_FIXED (xv
->emacswindow
),
335 xv
->x
+ xv
->clip_left
,
336 xv
->y
+ xv
->clip_top
);
340 /* Hide an xvidget view. */
342 xwidget_hide_view (struct xwidget_view
*xv
)
345 gtk_fixed_move (GTK_FIXED (xv
->emacswindow
), xv
->widgetwindow
,
351 /* When the off-screen webkit master view changes this signal is called.
352 It copies the bitmap from the off-screen instance. */
354 offscreen_damage_event (GtkWidget
* widget
, GdkEvent
* event
,
357 // Queue a redraw of onscreen widget.
358 // There is a guard against receiving an invalid widget,
359 // which should only happen if we failed to remove the
360 // specific signal handler for the damage event.
361 if (GTK_IS_WIDGET (xv_widget
))
362 gtk_widget_queue_draw (GTK_WIDGET (xv_widget
));
364 printf ("Warning, offscreen_damage_event received invalid xv pointer:%p\n",
371 store_xwidget_event_string (struct xwidget
*xw
, const char *eventname
,
372 const char *eventstr
)
374 struct input_event event
;
376 XSETXWIDGET (xwl
, xw
);
378 event
.kind
= XWIDGET_EVENT
;
379 event
.frame_or_window
= Qnil
;
382 event
.arg
= Fcons (build_string (eventstr
), event
.arg
);
383 event
.arg
= Fcons (xwl
, event
.arg
);
384 event
.arg
= Fcons (intern (eventname
), event
.arg
);
385 kbd_buffer_store_event (&event
);
389 //TODO deprecated, use load-status
391 webkit_document_load_finished_cb (WebKitWebView
* webkitwebview
,
392 WebKitWebFrame
* arg1
,
396 (struct xwidget
*) g_object_get_data (G_OBJECT (webkitwebview
),
399 store_xwidget_event_string (xw
, "document-load-finished", "");
403 webkit_download_cb (WebKitWebView
* webkitwebview
,
404 WebKitDownload
* arg1
,
408 (struct xwidget
*) g_object_get_data (G_OBJECT (webkitwebview
),
410 store_xwidget_event_string (xw
, "download-requested",
411 webkit_download_get_uri (arg1
));
417 webkit_mime_type_policy_typedecision_requested_cb (WebKitWebView
*webView
,
418 WebKitWebFrame
*frame
,
419 WebKitNetworkRequest
* request
,
421 WebKitWebPolicyDecision
*policy_decision
,
424 // This function makes webkit send a download signal for all unknown
425 // mime types. TODO Defer the decision to lisp, so that its possible
426 // to make Emacs handle teext mime for instance.xs
427 if (!webkit_web_view_can_show_mime_type (webView
, mimetype
))
429 webkit_web_policy_decision_download (policy_decision
);
440 webkit_new_window_policy_decision_requested_cb (WebKitWebView
*webView
,
441 WebKitWebFrame
*frame
,
442 WebKitNetworkRequest
*request
,
443 WebKitWebNavigationAction
*navigation_action
,
444 WebKitWebPolicyDecision
*policy_decision
,
448 (struct xwidget
*) g_object_get_data (G_OBJECT (webView
), XG_XWIDGET
);
449 webkit_web_navigation_action_get_original_uri (navigation_action
);
451 store_xwidget_event_string (xw
, "new-window-policy-decision-requested",
452 webkit_web_navigation_action_get_original_uri
453 (navigation_action
));
458 webkit_navigation_policy_decision_requested_cb (WebKitWebView
*webView
,
459 WebKitWebFrame
*frame
,
460 WebKitNetworkRequest
*request
,
461 WebKitWebNavigationAction
*navigation_action
,
462 WebKitWebPolicyDecision
* policy_decision
,
466 (struct xwidget
*) g_object_get_data (G_OBJECT (webView
), XG_XWIDGET
);
467 store_xwidget_event_string (xw
, "navigation-policy-decision-requested",
468 webkit_web_navigation_action_get_original_uri
469 (navigation_action
));
473 // For gtk3 offscreen rendered widgets.
475 xwidget_osr_draw_cb (GtkWidget
* widget
, cairo_t
* cr
, gpointer data
)
478 (struct xwidget
*) g_object_get_data (G_OBJECT (widget
), XG_XWIDGET
);
479 struct xwidget_view
*xv
=
480 (struct xwidget_view
*) g_object_get_data (G_OBJECT (widget
),
483 cairo_rectangle (cr
, 0, 0, xv
->clip_right
, xv
->clip_bottom
);
486 if (xw
->widgetscrolledwindow_osr
!= NULL
)
487 gtk_widget_draw (xw
->widgetscrolledwindow_osr
, cr
);
489 gtk_widget_draw (xw
->widget_osr
, cr
);
494 xwidget_osr_event_forward (GtkWidget
* widget
,
498 /* Copy events that arrive at the outer widget to the offscreen widget. */
500 (struct xwidget
*) g_object_get_data (G_OBJECT (widget
), XG_XWIDGET
);
501 GdkEvent
*eventcopy
= gdk_event_copy (event
);
502 eventcopy
->any
.window
= gtk_widget_get_window (xw
->widget_osr
);
504 //TODO This might leak events. They should be deallocated later,
505 //perhaps in xwgir_event_cb
506 gtk_main_do_event (eventcopy
);
507 return TRUE
; //dont propagate this event furter
512 xwidget_osr_event_set_embedder (GtkWidget
* widget
,
513 GdkEvent
* event
, gpointer data
)
515 struct xwidget_view
*xv
= (struct xwidget_view
*) data
;
516 struct xwidget
*xww
= XXWIDGET (xv
->model
);
517 gdk_offscreen_window_set_embedder (gtk_widget_get_window
518 (xww
->widgetwindow_osr
),
519 gtk_widget_get_window (xv
->widget
));
524 /* Initializes and does initial placement of an xwidget view on screen. */
525 static struct xwidget_view
*
526 xwidget_init_view (struct xwidget
*xww
,
527 struct glyph_string
*s
,
530 struct xwidget_view
*xv
= allocate_xwidget_view ();
533 XSETXWIDGET_VIEW (val
, xv
);
534 Vxwidget_view_list
= Fcons (val
, Vxwidget_view_list
);
536 XSETWINDOW (xv
->w
, s
->w
);
537 XSETXWIDGET (xv
->model
, xww
);
539 if (EQ (xww
->type
, Qwebkit_osr
))
541 xv
->widget
= gtk_drawing_area_new ();
542 // Expose event handling.
543 gtk_widget_set_app_paintable (xv
->widget
, TRUE
);
544 gtk_widget_add_events (xv
->widget
, GDK_ALL_EVENTS_MASK
);
546 /* Draw the view on damage-event */
547 g_signal_connect (G_OBJECT (xww
->widgetwindow_osr
), "damage-event",
548 G_CALLBACK (offscreen_damage_event
), xv
->widget
);
550 if (EQ (xww
->type
, Qwebkit_osr
))
552 g_signal_connect (G_OBJECT (xv
->widget
), "button-press-event",
553 G_CALLBACK (xwidget_osr_event_forward
), NULL
);
554 g_signal_connect (G_OBJECT (xv
->widget
), "button-release-event",
555 G_CALLBACK (xwidget_osr_event_forward
), NULL
);
556 g_signal_connect (G_OBJECT (xv
->widget
), "motion-notify-event",
557 G_CALLBACK (xwidget_osr_event_forward
), NULL
);
561 // xwgir debug , orthogonal to forwarding
562 g_signal_connect (G_OBJECT (xv
->widget
), "enter-notify-event",
563 G_CALLBACK (xwidget_osr_event_set_embedder
), xv
);
565 g_signal_connect (G_OBJECT (xv
->widget
), "draw",
566 G_CALLBACK (xwidget_osr_draw_cb
), NULL
);
568 // Widget realization.
570 // Make container widget 1st, and put the actual widget inside the
571 // container later. Drawing should crop container window if necessary
572 // to handle case where xwidget is partially obscured by other Emacs
573 // windows. Other containers than gtk_fixed where explored, but
574 // gtk_fixed had the most predictable behaviour so far.
575 xv
->emacswindow
= FRAME_GTK_WIDGET (s
->f
);
576 xv
->widgetwindow
= gtk_fixed_new ();
577 gtk_widget_set_has_window (xv
->widgetwindow
, TRUE
);
578 gtk_container_add (GTK_CONTAINER (xv
->widgetwindow
), xv
->widget
);
580 // Store some xwidget data in the gtk widgets.
582 g_object_set_data (G_OBJECT (xv
->widget
), XG_FRAME_DATA
, (gpointer
) (s
->f
));
584 g_object_set_data (G_OBJECT (xv
->widget
), XG_XWIDGET
, (gpointer
) (xww
));
586 g_object_set_data (G_OBJECT (xv
->widget
), XG_XWIDGET_VIEW
, (gpointer
) (xv
));
587 // The xwidget window.
588 g_object_set_data (G_OBJECT (xv
->widgetwindow
), XG_XWIDGET
, (gpointer
) (xww
));
590 g_object_set_data (G_OBJECT (xv
->widgetwindow
), XG_XWIDGET_VIEW
,
594 gtk_widget_set_size_request (GTK_WIDGET (xv
->widget
), xww
->width
,
596 gtk_widget_set_size_request (xv
->widgetwindow
, xww
->width
, xww
->height
);
597 gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s
->f
)), xv
->widgetwindow
, x
, y
);
600 gtk_widget_show_all (xv
->widgetwindow
);
608 x_draw_xwidget_glyph_string (struct glyph_string
*s
)
610 /* This method is called by the redisplay engine and places the
611 xwidget on screen. Moving and clipping is done here. Also view
614 struct xwidget
*xww
= s
->xwidget
;
615 struct xwidget_view
*xv
= xwidget_view_lookup (xww
, s
->w
);
622 int y
= s
->y
+ (s
->height
/ 2) - (xww
->height
/ 2);
625 /* We do initialization here in the display loop because there is no
626 other time to know things like window placement etc.
628 xv
= xwidget_init_view (xww
, s
, x
, y
);
630 // Calculate clipping, which is used for all manner of onscreen
631 // xwidget views. Each widget border can get clipped by other emacs
632 // objects so there are four clipping variables.
635 WINDOW_RIGHT_EDGE_X (s
->w
) - x
-
636 WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH (s
->w
) -
637 WINDOW_RIGHT_FRINGE_WIDTH (s
->w
));
640 WINDOW_LEFT_EDGE_X (s
->w
) - x
+
641 WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (s
->w
) +
642 WINDOW_LEFT_FRINGE_WIDTH (s
->w
));
646 WINDOW_BOTTOM_EDGE_Y (s
->w
) - WINDOW_MODE_LINE_HEIGHT (s
->w
) - y
);
647 clip_top
= max (0, WINDOW_TOP_EDGE_Y (s
->w
) - y
);
649 // We are conserned with movement of the onscreen area. The area
650 // might sit still when the widget actually moves. This happens
651 // when an Emacs window border moves across a widget window. So, if
652 // any corner of the outer widget clipping window moves, that counts
653 // as movement here, even if it looks like no movement happens
654 // because the widget sits still inside the clipping area. The
655 // widget can also move inside the clipping area, which happens
657 moved
= (xv
->x
+ xv
->clip_left
!= x
+ clip_left
)
658 || ((xv
->y
+ xv
->clip_top
) != (y
+ clip_top
));
661 if (moved
) // Has it moved?
663 gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s
->f
)),
664 xv
->widgetwindow
, x
+ clip_left
, y
+ clip_top
);
666 // Clip the widget window if some parts happen to be outside
667 // drawable area. An Emacs window is not a gtk window. A gtk window
668 // covers the entire frame. Clipping might have changed even if we
669 // havent actualy moved, we try figure out when we need to reclip
671 if ((xv
->clip_right
!= clip_right
)
672 || (xv
->clip_bottom
!= clip_bottom
)
673 || (xv
->clip_top
!= clip_top
) || (xv
->clip_left
!= clip_left
))
675 gtk_widget_set_size_request (xv
->widgetwindow
, clip_right
+ clip_left
,
676 clip_bottom
+ clip_top
);
677 gtk_fixed_move (GTK_FIXED (xv
->widgetwindow
), xv
->widget
, -clip_left
,
680 xv
->clip_right
= clip_right
;
681 xv
->clip_bottom
= clip_bottom
;
682 xv
->clip_top
= clip_top
;
683 xv
->clip_left
= clip_left
;
685 // If emacs wants to repaint the area where the widget lives, queue
686 // a redraw. It seems its possible to get out of sync with emacs
687 // redraws so emacs background sometimes shows up instead of the
688 // xwidgets background. It's just a visual glitch though.
689 if (!xwidget_hidden (xv
))
691 gtk_widget_queue_draw (xv
->widgetwindow
);
692 gtk_widget_queue_draw (xv
->widget
);
697 // Macro that checks WEBKIT_IS_WEB_VIEW(xw->widget_osr) first
698 #define WEBKIT_FN_INIT() \
699 struct xwidget* xw; \
700 CHECK_XWIDGET (xwidget); \
701 if (NILP (xwidget)) {printf("ERROR xwidget nil\n"); return Qnil;}; \
702 xw = XXWIDGET (xwidget); \
703 if (NULL == xw) printf("ERROR xw is 0\n"); \
704 if ((NULL == xw->widget_osr) || !WEBKIT_IS_WEB_VIEW(xw->widget_osr)){ \
705 printf ("ERROR xw->widget_osr does not hold a webkit instance\n");\
710 DEFUN ("xwidget-webkit-goto-uri",
711 Fxwidget_webkit_goto_uri
, Sxwidget_webkit_goto_uri
,
713 doc
: /* Make the xwidget webkit instance referenced by XWIDGET browse URI. */)
714 (Lisp_Object xwidget
, Lisp_Object uri
)
718 webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw
->widget_osr
), SSDATA (uri
));
723 DEFUN ("xwidget-webkit-execute-script",
724 Fxwidget_webkit_execute_script
, Sxwidget_webkit_execute_script
,
726 doc
: /* Make the Webkit XWIDGET execute javascript SCRIPT. */)
727 (Lisp_Object xwidget
, Lisp_Object script
)
730 CHECK_STRING (script
);
731 webkit_web_view_execute_script (WEBKIT_WEB_VIEW (xw
->widget_osr
),
736 DEFUN ("xwidget-webkit-get-title",
737 Fxwidget_webkit_get_title
, Sxwidget_webkit_get_title
,
739 doc
: /* Return the title from the Webkit instance in XWIDGET.
740 This can be used to work around the lack of a return value from the
742 (Lisp_Object xwidget
)
744 // TODO support multibyte strings
747 webkit_web_view_get_title (WEBKIT_WEB_VIEW (xw
->widget_osr
));
750 // TODO maybe return Qnil instead. I suppose webkit returns
751 // nullpointer when doc is not properly loaded or something
752 return build_string ("");
754 return build_string (str
);
757 DEFUN ("xwidget-resize", Fxwidget_resize
, Sxwidget_resize
, 3, 3, 0,
758 doc
: /* Resize XWIDGET. NEW_WIDTH, NEW_HEIGHT define the new size. */ )
759 (Lisp_Object xwidget
, Lisp_Object new_width
, Lisp_Object new_height
)
761 CHECK_XWIDGET (xwidget
);
762 struct xwidget
*xw
= XXWIDGET (xwidget
);
763 struct xwidget_view
*xv
;
766 CHECK_NUMBER (new_width
);
767 CHECK_NUMBER (new_height
);
768 w
= XFASTINT (new_width
);
769 h
= XFASTINT (new_height
);
773 // If there is a offscreen widget resize it 1st.
776 gtk_widget_set_size_request (GTK_WIDGET (xw
->widget_osr
),
777 xw
->width
, xw
->height
); //minimum size
778 gtk_window_resize (GTK_WINDOW (xw
->widgetwindow_osr
), xw
->width
,
780 gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW
782 widgetscrolledwindow_osr
),
784 gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW
786 widgetscrolledwindow_osr
),
789 gtk_container_resize_children (GTK_CONTAINER (xw
->widgetwindow_osr
));
793 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
); tail
= XCDR (tail
))
795 if (XWIDGET_VIEW_P (XCAR (tail
)))
797 xv
= XXWIDGET_VIEW (XCAR (tail
));
798 if (XXWIDGET (xv
->model
) == xw
)
799 gtk_widget_set_size_request (GTK_WIDGET (xv
->widget
), xw
->width
,
809 DEFUN ("xwidget-set-adjustment",
810 Fxwidget_set_adjustment
, Sxwidget_set_adjustment
, 4, 4, 0,
811 doc
: /* Set native scrolling for XWIDGET.
812 AXIS can be 'vertical or 'horizontal.
813 If RELATIVE is t, scroll relative, otherwise absolutely.
814 VALUE is the amount to scroll, either relatively or absolutely. */)
815 (Lisp_Object xwidget
, Lisp_Object axis
, Lisp_Object relative
,
818 CHECK_XWIDGET (xwidget
);
819 struct xwidget
*xw
= XXWIDGET (xwidget
);
820 GtkAdjustment
*adjustment
;
821 float final_value
= 0.0;
824 gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
825 (xw
->widgetscrolledwindow_osr
));
826 if (EQ (Qvertical
, axis
))
829 gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
830 (xw
->widgetscrolledwindow_osr
));
832 if (EQ (Qhorizontal
, axis
))
835 gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW
836 (xw
->widgetscrolledwindow_osr
));
839 if (EQ (Qt
, relative
))
841 final_value
= gtk_adjustment_get_value (adjustment
) + XFASTINT (value
);
845 final_value
= 0.0 + XFASTINT (value
);
848 gtk_adjustment_set_value (adjustment
, final_value
);
854 DEFUN ("xwidget-size-request",
855 Fxwidget_size_request
, Sxwidget_size_request
,
857 doc
: /* Return the desired size of the XWIDGET.
858 This can be used to read the xwidget desired size, and resizes the
859 Emacs allocated area accordingly. */)
860 (Lisp_Object xwidget
)
862 CHECK_XWIDGET (xwidget
);
863 GtkRequisition requisition
;
865 gtk_widget_size_request (XXWIDGET (xwidget
)->widget_osr
, &requisition
);
867 rv
= Fcons (make_number (requisition
.height
), rv
);
868 rv
= Fcons (make_number (requisition
.width
), rv
);
874 Fxwidgetp
, Sxwidgetp
,
876 doc
: /* Return t if OBJECT is an xwidget. */)
879 return XWIDGETP (object
) ? Qt
: Qnil
;
882 DEFUN ("xwidget-view-p",
883 Fxwidget_view_p
, Sxwidget_view_p
,
885 doc
: /* Return t if OBJECT is an xwidget-view. */)
888 return XWIDGET_VIEW_P (object
) ? Qt
: Qnil
;
891 DEFUN ("xwidget-info",
892 Fxwidget_info
, Sxwidget_info
,
894 doc
: /* Return XWIDGET properties in a vector.
895 Currently [TYPE TITLE WIDTH HEIGHT]. */)
896 (Lisp_Object xwidget
)
898 CHECK_XWIDGET (xwidget
);
900 struct xwidget
*xw
= XXWIDGET (xwidget
);
902 info
= Fmake_vector (make_number (4), Qnil
);
903 ASET (info
, 0, xw
->type
);
904 ASET (info
, 1, xw
->title
);
905 XSETFASTINT (n
, xw
->width
);
907 XSETFASTINT (n
, xw
->height
);
913 DEFUN ("xwidget-view-info",
914 Fxwidget_view_info
, Sxwidget_view_info
,
916 doc
: /* Return properties of XWIDGET-VIEW in a vector.
917 Currently [X Y CLIP_RIGHT CLIP_BOTTOM CLIP_TOP CLIP_LEFT]. */)
918 (Lisp_Object xwidget_view
)
920 CHECK_XWIDGET_VIEW (xwidget_view
);
921 struct xwidget_view
*xv
= XXWIDGET_VIEW (xwidget_view
);
924 info
= Fmake_vector (make_number (6), Qnil
);
925 ASET (info
, 0, make_number (xv
->x
));
926 ASET (info
, 1, make_number (xv
->y
));
927 ASET (info
, 2, make_number (xv
->clip_right
));
928 ASET (info
, 3, make_number (xv
->clip_bottom
));
929 ASET (info
, 4, make_number (xv
->clip_top
));
930 ASET (info
, 5, make_number (xv
->clip_left
));
935 DEFUN ("xwidget-view-model",
936 Fxwidget_view_model
, Sxwidget_view_model
,
938 doc
: /* Return the model associated with XWIDGET-VIEW. */)
939 (Lisp_Object xwidget_view
)
941 CHECK_XWIDGET_VIEW (xwidget_view
);
942 return XXWIDGET_VIEW (xwidget_view
)->model
;
945 DEFUN ("xwidget-view-window",
946 Fxwidget_view_window
, Sxwidget_view_window
,
948 doc
: /* Return the window of XWIDGET-VIEW. */)
949 (Lisp_Object xwidget_view
)
951 CHECK_XWIDGET_VIEW (xwidget_view
);
952 return XXWIDGET_VIEW (xwidget_view
)->w
;
956 DEFUN ("delete-xwidget-view",
957 Fdelete_xwidget_view
, Sdelete_xwidget_view
,
959 doc
: /* Delete the XWIDGET-VIEW. */)
960 (Lisp_Object xwidget_view
)
962 CHECK_XWIDGET_VIEW (xwidget_view
);
963 struct xwidget_view
*xv
= XXWIDGET_VIEW (xwidget_view
);
964 gtk_widget_destroy (xv
->widgetwindow
);
965 Vxwidget_view_list
= Fdelq (xwidget_view
, Vxwidget_view_list
);
966 // xv->model still has signals pointing to the view. There can be
967 // several views. Find the matching signals and delete them all.
968 g_signal_handlers_disconnect_matched (XXWIDGET (xv
->model
)->widgetwindow_osr
,
975 DEFUN ("xwidget-view-lookup",
976 Fxwidget_view_lookup
, Sxwidget_view_lookup
,
978 doc
: /* Return the xwidget-view associated with XWIDGET in WINDOW.
979 If WINDOW is unspecified or nil, use the selected window.
980 Return nil if no association is found. */)
981 (Lisp_Object xwidget
, Lisp_Object window
)
983 CHECK_XWIDGET (xwidget
);
986 window
= Fselected_window ();
987 CHECK_WINDOW (window
);
989 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
);
992 Lisp_Object xwidget_view
= XCAR (tail
);
993 if (EQ (Fxwidget_view_model (xwidget_view
), xwidget
)
994 && EQ (Fxwidget_view_window (xwidget_view
), window
))
1001 DEFUN ("xwidget-plist",
1002 Fxwidget_plist
, Sxwidget_plist
,
1004 doc
: /* Return the plist of XWIDGET. */)
1005 (register Lisp_Object xwidget
)
1007 CHECK_XWIDGET (xwidget
);
1008 return XXWIDGET (xwidget
)->plist
;
1011 DEFUN ("xwidget-buffer",
1012 Fxwidget_buffer
, Sxwidget_buffer
,
1014 doc
: /* Return the buffer of XWIDGET. */)
1015 (register Lisp_Object xwidget
)
1017 CHECK_XWIDGET (xwidget
);
1018 return XXWIDGET (xwidget
)->buffer
;
1021 DEFUN ("set-xwidget-plist",
1022 Fset_xwidget_plist
, Sset_xwidget_plist
,
1024 doc
: /* Replace the plist of XWIDGET with PLIST.
1026 (register Lisp_Object xwidget
, Lisp_Object plist
)
1028 CHECK_XWIDGET (xwidget
);
1031 XXWIDGET (xwidget
)->plist
= plist
;
1035 DEFUN ("set-xwidget-query-on-exit-flag",
1036 Fset_xwidget_query_on_exit_flag
, Sset_xwidget_query_on_exit_flag
,
1038 doc
: /* Specify if query is needed for XWIDGET when Emacs is exited.
1039 If the second argument FLAG is non-nil, Emacs will query the user before
1040 exiting or killing a buffer if XWIDGET is running.
1041 This function returns FLAG. */)
1042 (Lisp_Object xwidget
, Lisp_Object flag
)
1044 CHECK_XWIDGET (xwidget
);
1045 XXWIDGET (xwidget
)->kill_without_query
= NILP (flag
);
1049 DEFUN ("xwidget-query-on-exit-flag",
1050 Fxwidget_query_on_exit_flag
, Sxwidget_query_on_exit_flag
,
1052 doc
: /* Return the current value of the query-on-exit flag for XWIDGET. */)
1053 (Lisp_Object xwidget
)
1055 CHECK_XWIDGET (xwidget
);
1056 return (XXWIDGET (xwidget
)->kill_without_query
? Qnil
: Qt
);
1060 syms_of_xwidget (void)
1063 defsubr (&Smake_xwidget
);
1064 defsubr (&Sxwidgetp
);
1065 DEFSYM (Qxwidgetp
, "xwidgetp");
1066 defsubr (&Sxwidget_view_p
);
1067 DEFSYM (Qxwidget_view_p
, "xwidget-view-p");
1068 defsubr (&Sxwidget_info
);
1069 defsubr (&Sxwidget_view_info
);
1070 defsubr (&Sxwidget_resize
);
1071 defsubr (&Sget_buffer_xwidgets
);
1072 defsubr (&Sxwidget_view_model
);
1073 defsubr (&Sxwidget_view_window
);
1074 defsubr (&Sxwidget_view_lookup
);
1075 defsubr (&Sxwidget_query_on_exit_flag
);
1076 defsubr (&Sset_xwidget_query_on_exit_flag
);
1078 defsubr (&Sxwidget_webkit_goto_uri
);
1079 defsubr (&Sxwidget_webkit_execute_script
);
1080 defsubr (&Sxwidget_webkit_get_title
);
1081 DEFSYM (Qwebkit_osr
, "webkit-osr");
1083 defsubr (&Sxwidget_size_request
);
1084 defsubr (&Sdelete_xwidget_view
);
1086 defsubr (&Sxwidget_plist
);
1087 defsubr (&Sxwidget_buffer
);
1088 defsubr (&Sset_xwidget_plist
);
1090 defsubr (&Sxwidget_set_adjustment
);
1092 DEFSYM (Qxwidget
, "xwidget");
1094 DEFSYM (QCxwidget
, ":xwidget");
1095 DEFSYM (QCtitle
, ":title");
1097 /* Do not forget to update the docstring of make-xwidget if you add
1100 DEFSYM (Qvertical
, "vertical");
1101 DEFSYM (Qhorizontal
, "horizontal");
1103 DEFSYM (QCplist
, ":plist");
1105 DEFVAR_LISP ("xwidget-list", Vxwidget_list
,
1106 doc
: /* xwidgets list. */);
1107 Vxwidget_list
= Qnil
;
1109 DEFVAR_LISP ("xwidget-view-list", Vxwidget_view_list
,
1110 doc
: /* xwidget views list. */);
1111 Vxwidget_view_list
= Qnil
;
1113 Fprovide (intern ("xwidget-internal"), Qnil
);
1118 /* Value is non-zero if OBJECT is a valid Lisp xwidget specification. A
1119 valid xwidget specification is a list whose car is the symbol
1120 `xwidget', and whose rest is a property list. The property list must
1121 contain a value for key `:type'. That value must be the name of a
1122 supported xwidget type. The rest of the property list depends on the
1126 valid_xwidget_spec_p (Lisp_Object object
)
1128 int valid_p
= false;
1130 if (CONSP (object
) && EQ (XCAR (object
), Qxwidget
))
1138 /* Find a value associated with key in spec. */
1140 xwidget_spec_value (Lisp_Object spec
, Lisp_Object key
, int *found
)
1144 eassert (valid_xwidget_spec_p (spec
));
1146 for (tail
= XCDR (spec
);
1147 CONSP (tail
) && CONSP (XCDR (tail
)); tail
= XCDR (XCDR (tail
)))
1149 if (EQ (XCAR (tail
), key
))
1153 return XCAR (XCDR (tail
));
1164 xwidget_view_delete_all_in_window (struct window
*w
)
1166 struct xwidget_view
*xv
= NULL
;
1167 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
);
1170 if (XWIDGET_VIEW_P (XCAR (tail
)))
1172 xv
= XXWIDGET_VIEW (XCAR (tail
));
1173 if (XWINDOW (xv
->w
) == w
)
1175 Fdelete_xwidget_view (XCAR (tail
));
1181 static struct xwidget_view
*
1182 xwidget_view_lookup (struct xwidget
*xw
, struct window
*w
)
1184 Lisp_Object xwidget
, window
, ret
;
1185 XSETXWIDGET (xwidget
, xw
);
1186 XSETWINDOW (window
, w
);
1188 ret
= Fxwidget_view_lookup (xwidget
, window
);
1190 return EQ (ret
, Qnil
) ? NULL
: XXWIDGET_VIEW (ret
);
1194 lookup_xwidget (Lisp_Object spec
)
1196 /* When a xwidget lisp spec is found initialize the C struct that is
1197 used in the C code. This is done by redisplay so values change
1198 if the spec changes. So, take special care of one-shot events.
1204 value
= xwidget_spec_value (spec
, QCxwidget
, &found
);
1205 xw
= XXWIDGET (value
);
1210 /* Set up detection of touched xwidget */
1212 xwidget_start_redisplay (void)
1214 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
);
1217 if (XWIDGET_VIEW_P (XCAR (tail
)))
1218 XXWIDGET_VIEW (XCAR (tail
))->redisplayed
= 0;
1222 /* The xwidget was touched during redisplay, so it isn't a candidate
1225 xwidget_touch (struct xwidget_view
*xv
)
1227 xv
->redisplayed
= 1;
1231 xwidget_touched (struct xwidget_view
*xv
)
1233 return xv
->redisplayed
;
1236 /* Redisplay has ended, now we should hide untouched xwidgets
1239 xwidget_end_redisplay (struct window
*w
, struct glyph_matrix
*matrix
)
1245 xwidget_start_redisplay ();
1246 // Iterate desired glyph matrix of window here, hide gtk widgets
1247 // not in the desired matrix.
1249 // This only takes care of xwidgets in active windows. If a window
1250 // goes away from screen xwidget views wust be deleted
1252 // dump_glyph_matrix (matrix, 2);
1253 for (i
= 0; i
< matrix
->nrows
; ++i
)
1255 // dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs);
1256 struct glyph_row
*row
;
1257 row
= MATRIX_ROW (matrix
, i
);
1258 if (row
->enabled_p
!= 0)
1260 for (area
= LEFT_MARGIN_AREA
; area
< LAST_AREA
; ++area
)
1262 struct glyph
*glyph
= row
->glyphs
[area
];
1263 struct glyph
*glyph_end
= glyph
+ row
->used
[area
];
1264 for (; glyph
< glyph_end
; ++glyph
)
1266 if (glyph
->type
== XWIDGET_GLYPH
)
1269 The only call to xwidget_end_redisplay is in dispnew
1270 xwidget_end_redisplay (w->current_matrix);
1272 xwidget_touch (xwidget_view_lookup (glyph
->u
.xwidget
,
1280 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
);
1283 if (XWIDGET_VIEW_P (XCAR (tail
)))
1285 struct xwidget_view
*xv
= XXWIDGET_VIEW (XCAR (tail
));
1287 // "touched" is only meaningful for the current window, so
1288 // disregard other views.
1289 if (XWINDOW (xv
->w
) == w
)
1291 if (xwidget_touched (xv
))
1292 xwidget_show_view (xv
);
1294 xwidget_hide_view (xv
);
1300 /* Kill all xwidget in BUFFER. */
1302 kill_buffer_xwidgets (Lisp_Object buffer
)
1304 Lisp_Object tail
, xwidget
;
1305 for (tail
= Fget_buffer_xwidgets (buffer
); CONSP (tail
); tail
= XCDR (tail
))
1307 xwidget
= XCAR (tail
);
1308 Vxwidget_list
= Fdelq (xwidget
, Vxwidget_list
);
1309 /* TODO free the GTK things in xw */
1311 CHECK_XWIDGET (xwidget
);
1312 struct xwidget
*xw
= XXWIDGET (xwidget
);
1313 if (xw
->widget_osr
&& xw
->widgetwindow_osr
)
1315 gtk_widget_destroy (xw
->widget_osr
);
1316 gtk_widget_destroy (xw
->widgetwindow_osr
);