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 struct xwidget_view
*xwidget_view_lookup (struct xwidget
*, struct window
*);
127 Lisp_Object
xwidget_spec_value (Lisp_Object
, Lisp_Object
, int *);
128 gboolean
offscreen_damage_event (GtkWidget
* , GdkEvent
* , gpointer
);
129 void webkit_document_load_finished_cb (WebKitWebView
*, WebKitWebFrame
*,
131 gboolean
webkit_download_cb (WebKitWebView
*, WebKitDownload
*, gpointer
);
134 webkit_mime_type_policy_typedecision_requested_cb (WebKitWebView
*,
136 WebKitNetworkRequest
*,
138 WebKitWebPolicyDecision
*,
142 webkit_new_window_policy_decision_requested_cb (WebKitWebView
*,
144 WebKitNetworkRequest
*,
145 WebKitWebNavigationAction
*,
146 WebKitWebPolicyDecision
*,
150 webkit_navigation_policy_decision_requested_cb (WebKitWebView
*,
152 WebKitNetworkRequest
*,
153 WebKitWebNavigationAction
*,
154 WebKitWebPolicyDecision
*,
159 DEFUN ("make-xwidget",
160 Fmake_xwidget
, Smake_xwidget
,
162 doc
: /* Make an xwidget from BEG to END of TYPE.
164 If BUFFER is nil it uses the current
165 buffer. If BUFFER is a string and no such
166 buffer exists, it is created.
168 TYPE is a symbol which can take one of the
173 Returns the newly constructed xwidget, or nil if construction
175 (Lisp_Object beg
, Lisp_Object end
,
178 Lisp_Object width
, Lisp_Object height
,
179 Lisp_Object arguments
, Lisp_Object buffer
)
181 //should work a bit like "make-button"(make-button BEG END &rest PROPERTIES)
182 // arg "type" and fwd should be keyword args eventually
183 //(make-xwidget 3 3 'button "oei" 31 31 nil)
184 //(xwidget-info (car xwidget-list))
185 struct xwidget
*xw
= allocate_xwidget ();
190 buffer
= Fcurrent_buffer (); // no need to gcpro because
191 // Fcurrent_buffer doesn't
192 // call Feval/eval_sub.
194 buffer
= Fget_buffer_create (buffer
);
197 xw
->height
= XFASTINT (height
);
198 xw
->width
= XFASTINT (width
);
199 xw
->kill_without_query
= 0;
200 XSETXWIDGET (val
, xw
); // set the vectorlike_header of VAL
201 // with the correct value
202 Vxwidget_list
= Fcons (val
, Vxwidget_list
);
203 xw
->widgetwindow_osr
= NULL
;
204 xw
->widget_osr
= NULL
;
208 if (EQ (xw
->type
, Qwebkit_osr
))
211 xw
->widgetwindow_osr
= gtk_offscreen_window_new ();
212 gtk_window_resize (GTK_WINDOW (xw
->widgetwindow_osr
), xw
->width
,
214 xw
->widgetscrolledwindow_osr
= NULL
; //webkit osr is the
218 if (EQ (xw
->type
, Qwebkit_osr
))
220 xw
->widgetscrolledwindow_osr
= gtk_scrolled_window_new (NULL
, NULL
);
221 gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW
223 widgetscrolledwindow_osr
),
225 gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW
227 widgetscrolledwindow_osr
),
229 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW
230 (xw
->widgetscrolledwindow_osr
),
234 xw
->widget_osr
= webkit_web_view_new ();
235 gtk_container_add (GTK_CONTAINER (xw
->widgetscrolledwindow_osr
),
236 GTK_WIDGET (WEBKIT_WEB_VIEW (xw
->widget_osr
)));
239 gtk_widget_set_size_request (GTK_WIDGET (xw
->widget_osr
), xw
->width
,
242 if (EQ (xw
->type
, Qwebkit_osr
))
244 gtk_container_add (GTK_CONTAINER (xw
->widgetwindow_osr
),
245 xw
->widgetscrolledwindow_osr
);
249 gtk_container_add (GTK_CONTAINER (xw
->widgetwindow_osr
),
253 gtk_widget_show (xw
->widget_osr
);
254 gtk_widget_show (xw
->widgetwindow_osr
);
255 gtk_widget_show (xw
->widgetscrolledwindow_osr
);
257 /* store some xwidget data in the gtk widgets for convenient
258 retrieval in the event handlers. */
259 g_object_set_data (G_OBJECT (xw
->widget_osr
), XG_XWIDGET
,
261 g_object_set_data (G_OBJECT (xw
->widgetwindow_osr
), XG_XWIDGET
,
265 if (EQ (xw
->type
, Qwebkit_osr
))
267 g_signal_connect (G_OBJECT (xw
->widget_osr
),
268 "document-load-finished",
270 (webkit_document_load_finished_cb
), xw
);
272 g_signal_connect (G_OBJECT (xw
->widget_osr
),
273 "download-requested",
274 G_CALLBACK (webkit_download_cb
), xw
);
276 g_signal_connect (G_OBJECT (xw
->widget_osr
),
277 "mime-type-policy-decision-requested",
279 (webkit_mime_type_policy_typedecision_requested_cb
),
282 g_signal_connect (G_OBJECT (xw
->widget_osr
),
283 "new-window-policy-decision-requested",
285 (webkit_new_window_policy_decision_requested_cb
),
288 g_signal_connect (G_OBJECT (xw
->widget_osr
),
289 "navigation-policy-decision-requested",
291 (webkit_navigation_policy_decision_requested_cb
),
302 DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets
, Sget_buffer_xwidgets
,
304 doc
: /* Return a list of xwidgets associated with BUFFER.
305 BUFFER may be a buffer or the name of one. */)
308 Lisp_Object xw
, tail
, xw_list
;
312 buffer
= Fget_buffer (buffer
);
318 for (tail
= Vxwidget_list
; CONSP (tail
); tail
= XCDR (tail
))
321 if (XWIDGETP (xw
) && EQ (Fxwidget_buffer (xw
), buffer
))
322 xw_list
= Fcons (xw
, xw_list
);
328 xwidget_hidden (struct xwidget_view
*xv
)
336 xwidget_show_view (struct xwidget_view
*xv
)
339 gtk_widget_show (xv
->widgetwindow
);
340 gtk_fixed_move (GTK_FIXED (xv
->emacswindow
),
342 xv
->x
+ xv
->clip_left
,
343 xv
->y
+ xv
->clip_top
);
347 /* Hide an xvidget view. */
349 xwidget_hide_view (struct xwidget_view
*xv
)
352 gtk_fixed_move (GTK_FIXED (xv
->emacswindow
), xv
->widgetwindow
,
358 /* When the off-screen webkit master view changes this signal is called.
359 It copies the bitmap from the off-screen instance. */
361 offscreen_damage_event (GtkWidget
* widget
, GdkEvent
* event
,
364 // Queue a redraw of onscreen widget.
365 // There is a guard against receiving an invalid widget,
366 // which should only happen if we failed to remove the
367 // specific signal handler for the damage event.
368 if (GTK_IS_WIDGET (xv_widget
))
369 gtk_widget_queue_draw (GTK_WIDGET (xv_widget
));
371 printf ("Warning, offscreen_damage_event received invalid xv pointer:%p\n",
378 store_xwidget_event_string (struct xwidget
*xw
, const char *eventname
,
379 const char *eventstr
)
381 struct input_event event
;
383 XSETXWIDGET (xwl
, xw
);
385 event
.kind
= XWIDGET_EVENT
;
386 event
.frame_or_window
= Qnil
;
389 event
.arg
= Fcons (build_string (eventstr
), event
.arg
);
390 event
.arg
= Fcons (xwl
, event
.arg
);
391 event
.arg
= Fcons (intern (eventname
), event
.arg
);
392 kbd_buffer_store_event (&event
);
396 //TODO deprecated, use load-status
398 webkit_document_load_finished_cb (WebKitWebView
* webkitwebview
,
399 WebKitWebFrame
* arg1
,
403 (struct xwidget
*) g_object_get_data (G_OBJECT (webkitwebview
),
406 store_xwidget_event_string (xw
, "document-load-finished", "");
410 webkit_download_cb (WebKitWebView
* webkitwebview
,
411 WebKitDownload
* arg1
,
415 (struct xwidget
*) g_object_get_data (G_OBJECT (webkitwebview
),
417 store_xwidget_event_string (xw
, "download-requested",
418 webkit_download_get_uri (arg1
));
424 webkit_mime_type_policy_typedecision_requested_cb (WebKitWebView
*webView
,
425 WebKitWebFrame
*frame
,
426 WebKitNetworkRequest
* request
,
428 WebKitWebPolicyDecision
*policy_decision
,
431 // This function makes webkit send a download signal for all unknown
432 // mime types. TODO Defer the decision to lisp, so that its possible
433 // to make Emacs handle teext mime for instance.xs
434 if (!webkit_web_view_can_show_mime_type (webView
, mimetype
))
436 webkit_web_policy_decision_download (policy_decision
);
447 webkit_new_window_policy_decision_requested_cb (WebKitWebView
*webView
,
448 WebKitWebFrame
*frame
,
449 WebKitNetworkRequest
*request
,
450 WebKitWebNavigationAction
*navigation_action
,
451 WebKitWebPolicyDecision
*policy_decision
,
455 (struct xwidget
*) g_object_get_data (G_OBJECT (webView
), XG_XWIDGET
);
456 webkit_web_navigation_action_get_original_uri (navigation_action
);
458 store_xwidget_event_string (xw
, "new-window-policy-decision-requested",
459 webkit_web_navigation_action_get_original_uri
460 (navigation_action
));
465 webkit_navigation_policy_decision_requested_cb (WebKitWebView
*webView
,
466 WebKitWebFrame
*frame
,
467 WebKitNetworkRequest
*request
,
468 WebKitWebNavigationAction
*navigation_action
,
469 WebKitWebPolicyDecision
* policy_decision
,
473 (struct xwidget
*) g_object_get_data (G_OBJECT (webView
), XG_XWIDGET
);
474 store_xwidget_event_string (xw
, "navigation-policy-decision-requested",
475 webkit_web_navigation_action_get_original_uri
476 (navigation_action
));
480 // For gtk3 offscreen rendered widgets.
482 xwidget_osr_draw_cb (GtkWidget
* widget
, cairo_t
* cr
, gpointer data
)
485 (struct xwidget
*) g_object_get_data (G_OBJECT (widget
), XG_XWIDGET
);
486 struct xwidget_view
*xv
=
487 (struct xwidget_view
*) g_object_get_data (G_OBJECT (widget
),
490 cairo_rectangle (cr
, 0, 0, xv
->clip_right
, xv
->clip_bottom
);
493 if (xw
->widgetscrolledwindow_osr
!= NULL
)
494 gtk_widget_draw (xw
->widgetscrolledwindow_osr
, cr
);
496 gtk_widget_draw (xw
->widget_osr
, cr
);
501 xwidget_osr_event_forward (GtkWidget
* widget
,
505 /* Copy events that arrive at the outer widget to the offscreen widget. */
507 (struct xwidget
*) g_object_get_data (G_OBJECT (widget
), XG_XWIDGET
);
508 GdkEvent
*eventcopy
= gdk_event_copy (event
);
509 eventcopy
->any
.window
= gtk_widget_get_window (xw
->widget_osr
);
511 //TODO This might leak events. They should be deallocated later,
512 //perhaps in xwgir_event_cb
513 gtk_main_do_event (eventcopy
);
514 return TRUE
; //dont propagate this event furter
519 xwidget_osr_event_set_embedder (GtkWidget
* widget
,
520 GdkEvent
* event
, gpointer data
)
522 struct xwidget_view
*xv
= (struct xwidget_view
*) data
;
523 struct xwidget
*xww
= XXWIDGET (xv
->model
);
524 gdk_offscreen_window_set_embedder (gtk_widget_get_window
525 (xww
->widgetwindow_osr
),
526 gtk_widget_get_window (xv
->widget
));
531 /* Initializes and does initial placement of an xwidget view on screen. */
532 static struct xwidget_view
*
533 xwidget_init_view (struct xwidget
*xww
,
534 struct glyph_string
*s
,
537 struct xwidget_view
*xv
= allocate_xwidget_view ();
540 XSETXWIDGET_VIEW (val
, xv
);
541 Vxwidget_view_list
= Fcons (val
, Vxwidget_view_list
);
543 XSETWINDOW (xv
->w
, s
->w
);
544 XSETXWIDGET (xv
->model
, xww
);
546 if (EQ (xww
->type
, Qwebkit_osr
))
548 xv
->widget
= gtk_drawing_area_new ();
549 // Expose event handling.
550 gtk_widget_set_app_paintable (xv
->widget
, TRUE
);
551 gtk_widget_add_events (xv
->widget
, GDK_ALL_EVENTS_MASK
);
553 /* Draw the view on damage-event */
554 g_signal_connect (G_OBJECT (xww
->widgetwindow_osr
), "damage-event",
555 G_CALLBACK (offscreen_damage_event
), xv
->widget
);
557 if (EQ (xww
->type
, Qwebkit_osr
))
559 g_signal_connect (G_OBJECT (xv
->widget
), "button-press-event",
560 G_CALLBACK (xwidget_osr_event_forward
), NULL
);
561 g_signal_connect (G_OBJECT (xv
->widget
), "button-release-event",
562 G_CALLBACK (xwidget_osr_event_forward
), NULL
);
563 g_signal_connect (G_OBJECT (xv
->widget
), "motion-notify-event",
564 G_CALLBACK (xwidget_osr_event_forward
), NULL
);
568 // xwgir debug , orthogonal to forwarding
569 g_signal_connect (G_OBJECT (xv
->widget
), "enter-notify-event",
570 G_CALLBACK (xwidget_osr_event_set_embedder
), xv
);
572 g_signal_connect (G_OBJECT (xv
->widget
), "draw",
573 G_CALLBACK (xwidget_osr_draw_cb
), NULL
);
575 // Widget realization.
577 // Make container widget 1st, and put the actual widget inside the
578 // container later. Drawing should crop container window if necessary
579 // to handle case where xwidget is partially obscured by other Emacs
580 // windows. Other containers than gtk_fixed where explored, but
581 // gtk_fixed had the most predictable behaviour so far.
582 xv
->emacswindow
= FRAME_GTK_WIDGET (s
->f
);
583 xv
->widgetwindow
= gtk_fixed_new ();
584 gtk_widget_set_has_window (xv
->widgetwindow
, TRUE
);
585 gtk_container_add (GTK_CONTAINER (xv
->widgetwindow
), xv
->widget
);
587 // Store some xwidget data in the gtk widgets.
589 g_object_set_data (G_OBJECT (xv
->widget
), XG_FRAME_DATA
, (gpointer
) (s
->f
));
591 g_object_set_data (G_OBJECT (xv
->widget
), XG_XWIDGET
, (gpointer
) (xww
));
593 g_object_set_data (G_OBJECT (xv
->widget
), XG_XWIDGET_VIEW
, (gpointer
) (xv
));
594 // The xwidget window.
595 g_object_set_data (G_OBJECT (xv
->widgetwindow
), XG_XWIDGET
, (gpointer
) (xww
));
597 g_object_set_data (G_OBJECT (xv
->widgetwindow
), XG_XWIDGET_VIEW
,
601 gtk_widget_set_size_request (GTK_WIDGET (xv
->widget
), xww
->width
,
603 gtk_widget_set_size_request (xv
->widgetwindow
, xww
->width
, xww
->height
);
604 gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s
->f
)), xv
->widgetwindow
, x
, y
);
607 gtk_widget_show_all (xv
->widgetwindow
);
615 x_draw_xwidget_glyph_string (struct glyph_string
*s
)
617 /* This method is called by the redisplay engine and places the
618 xwidget on screen. Moving and clipping is done here. Also view
621 struct xwidget
*xww
= s
->xwidget
;
622 struct xwidget_view
*xv
= xwidget_view_lookup (xww
, s
->w
);
629 int y
= s
->y
+ (s
->height
/ 2) - (xww
->height
/ 2);
632 /* We do initialization here in the display loop because there is no
633 other time to know things like window placement etc.
635 xv
= xwidget_init_view (xww
, s
, x
, y
);
637 // Calculate clipping, which is used for all manner of onscreen
638 // xwidget views. Each widget border can get clipped by other emacs
639 // objects so there are four clipping variables.
642 WINDOW_RIGHT_EDGE_X (s
->w
) - x
-
643 WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH (s
->w
) -
644 WINDOW_RIGHT_FRINGE_WIDTH (s
->w
));
647 WINDOW_LEFT_EDGE_X (s
->w
) - x
+
648 WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (s
->w
) +
649 WINDOW_LEFT_FRINGE_WIDTH (s
->w
));
653 WINDOW_BOTTOM_EDGE_Y (s
->w
) - WINDOW_MODE_LINE_HEIGHT (s
->w
) - y
);
654 clip_top
= max (0, WINDOW_TOP_EDGE_Y (s
->w
) - y
);
656 // We are conserned with movement of the onscreen area. The area
657 // might sit still when the widget actually moves. This happens
658 // when an Emacs window border moves across a widget window. So, if
659 // any corner of the outer widget clipping window moves, that counts
660 // as movement here, even if it looks like no movement happens
661 // because the widget sits still inside the clipping area. The
662 // widget can also move inside the clipping area, which happens
664 moved
= (xv
->x
+ xv
->clip_left
!= x
+ clip_left
)
665 || ((xv
->y
+ xv
->clip_top
) != (y
+ clip_top
));
668 if (moved
) // Has it moved?
670 gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s
->f
)),
671 xv
->widgetwindow
, x
+ clip_left
, y
+ clip_top
);
673 // Clip the widget window if some parts happen to be outside
674 // drawable area. An Emacs window is not a gtk window. A gtk window
675 // covers the entire frame. Clipping might have changed even if we
676 // havent actualy moved, we try figure out when we need to reclip
678 if ((xv
->clip_right
!= clip_right
)
679 || (xv
->clip_bottom
!= clip_bottom
)
680 || (xv
->clip_top
!= clip_top
) || (xv
->clip_left
!= clip_left
))
682 gtk_widget_set_size_request (xv
->widgetwindow
, clip_right
+ clip_left
,
683 clip_bottom
+ clip_top
);
684 gtk_fixed_move (GTK_FIXED (xv
->widgetwindow
), xv
->widget
, -clip_left
,
687 xv
->clip_right
= clip_right
;
688 xv
->clip_bottom
= clip_bottom
;
689 xv
->clip_top
= clip_top
;
690 xv
->clip_left
= clip_left
;
692 // If emacs wants to repaint the area where the widget lives, queue
693 // a redraw. It seems its possible to get out of sync with emacs
694 // redraws so emacs background sometimes shows up instead of the
695 // xwidgets background. It's just a visual glitch though.
696 if (!xwidget_hidden (xv
))
698 gtk_widget_queue_draw (xv
->widgetwindow
);
699 gtk_widget_queue_draw (xv
->widget
);
704 // Macro that checks WEBKIT_IS_WEB_VIEW(xw->widget_osr) first
705 #define WEBKIT_FN_INIT() \
706 struct xwidget* xw; \
707 CHECK_XWIDGET (xwidget); \
708 if (NILP (xwidget)) {printf("ERROR xwidget nil\n"); return Qnil;}; \
709 xw = XXWIDGET (xwidget); \
710 if (NULL == xw) printf("ERROR xw is 0\n"); \
711 if ((NULL == xw->widget_osr) || !WEBKIT_IS_WEB_VIEW(xw->widget_osr)){ \
712 printf ("ERROR xw->widget_osr does not hold a webkit instance\n");\
717 DEFUN ("xwidget-webkit-goto-uri",
718 Fxwidget_webkit_goto_uri
, Sxwidget_webkit_goto_uri
,
720 doc
: /* Make the xwidget webkit instance referenced by XWIDGET
722 (Lisp_Object xwidget
, Lisp_Object uri
)
726 webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw
->widget_osr
), SSDATA (uri
));
731 DEFUN ("xwidget-webkit-execute-script",
732 Fxwidget_webkit_execute_script
, Sxwidget_webkit_execute_script
,
734 doc
: /* Make the Webkit XWIDGET execute javascript SCRIPT. */)
735 (Lisp_Object xwidget
, Lisp_Object script
)
738 CHECK_STRING (script
);
739 webkit_web_view_execute_script (WEBKIT_WEB_VIEW (xw
->widget_osr
),
744 DEFUN ("xwidget-webkit-get-title",
745 Fxwidget_webkit_get_title
, Sxwidget_webkit_get_title
,
747 doc
: /* Returns the title from the Webkit instance in XWIDGET.
748 This can be used to work around the lack of a return value from the
750 (Lisp_Object xwidget
)
752 // TODO support multibyte strings
755 webkit_web_view_get_title (WEBKIT_WEB_VIEW (xw
->widget_osr
));
758 // TODO maybe return Qnil instead. I suppose webkit returns
759 // nullpointer when doc is not properly loaded or something
760 return build_string ("");
762 return build_string (str
);
765 DEFUN ("xwidget-resize", Fxwidget_resize
, Sxwidget_resize
, 3, 3, 0,
766 doc
: /* Resize XWIDGET. NEW_WIDTH NEW_HEIGHT defines the new
768 (Lisp_Object xwidget
, Lisp_Object new_width
, Lisp_Object new_height
)
770 CHECK_XWIDGET (xwidget
);
771 struct xwidget
*xw
= XXWIDGET (xwidget
);
772 struct xwidget_view
*xv
;
775 CHECK_NUMBER (new_width
);
776 CHECK_NUMBER (new_height
);
777 w
= XFASTINT (new_width
);
778 h
= XFASTINT (new_height
);
782 // If there is a offscreen widget resize it 1st.
785 gtk_widget_set_size_request (GTK_WIDGET (xw
->widget_osr
),
786 xw
->width
, xw
->height
); //minimum size
787 gtk_window_resize (GTK_WINDOW (xw
->widgetwindow_osr
), xw
->width
,
789 gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW
791 widgetscrolledwindow_osr
),
793 gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW
795 widgetscrolledwindow_osr
),
798 gtk_container_resize_children (GTK_CONTAINER (xw
->widgetwindow_osr
));
802 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
); tail
= XCDR (tail
))
804 if (XWIDGET_VIEW_P (XCAR (tail
)))
806 xv
= XXWIDGET_VIEW (XCAR (tail
));
807 if (XXWIDGET (xv
->model
) == xw
)
808 gtk_widget_set_size_request (GTK_WIDGET (xv
->widget
), xw
->width
,
818 DEFUN ("xwidget-set-adjustment",
819 Fxwidget_set_adjustment
, Sxwidget_set_adjustment
, 4, 4, 0,
820 doc
: /* Set native scrolling for XWIDGET. AXIS can be 'vertical or
821 'horizontal. If RELATIVE is t, scroll relative, otherwise absolutely.
822 VALUE is the amount to scroll, either relatively or absolutely. */)
823 (Lisp_Object xwidget
, Lisp_Object axis
, Lisp_Object relative
,
826 CHECK_XWIDGET (xwidget
);
827 struct xwidget
*xw
= XXWIDGET (xwidget
);
828 GtkAdjustment
*adjustment
;
829 float final_value
= 0.0;
832 gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
833 (xw
->widgetscrolledwindow_osr
));
834 if (EQ (Qvertical
, axis
))
837 gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
838 (xw
->widgetscrolledwindow_osr
));
840 if (EQ (Qhorizontal
, axis
))
843 gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW
844 (xw
->widgetscrolledwindow_osr
));
847 if (EQ (Qt
, relative
))
849 final_value
= gtk_adjustment_get_value (adjustment
) + XFASTINT (value
);
853 final_value
= 0.0 + XFASTINT (value
);
856 gtk_adjustment_set_value (adjustment
, final_value
);
862 DEFUN ("xwidget-size-request",
863 Fxwidget_size_request
, Sxwidget_size_request
,
865 doc
: /* Return the desired size of the XWIDGET.
867 This can be used to read the xwidget desired size, and resizes the
868 Emacs allocated area accordingly. */)
869 (Lisp_Object xwidget
)
871 CHECK_XWIDGET (xwidget
);
872 GtkRequisition requisition
;
874 gtk_widget_size_request (XXWIDGET (xwidget
)->widget_osr
, &requisition
);
876 rv
= Fcons (make_number (requisition
.height
), rv
);
877 rv
= Fcons (make_number (requisition
.width
), rv
);
883 Fxwidgetp
, Sxwidgetp
,
885 doc
: /* Return t if OBJECT is a xwidget. */)
888 return XWIDGETP (object
) ? Qt
: Qnil
;
891 DEFUN ("xwidget-view-p",
892 Fxwidget_view_p
, Sxwidget_view_p
,
894 doc
: /* Return t if OBJECT is a xwidget-view. */)
897 return XWIDGET_VIEW_P (object
) ? Qt
: Qnil
;
900 DEFUN ("xwidget-info",
901 Fxwidget_info
, Sxwidget_info
,
903 doc
: /* Return XWIDGET properties in a vector. Currently [TYPE
904 TITLE WIDTH HEIGHT]. */)
905 (Lisp_Object xwidget
)
907 CHECK_XWIDGET (xwidget
);
909 struct xwidget
*xw
= XXWIDGET (xwidget
);
911 info
= Fmake_vector (make_number (4), Qnil
);
912 ASET (info
, 0, xw
->type
);
913 ASET (info
, 1, xw
->title
);
914 XSETFASTINT (n
, xw
->width
);
916 XSETFASTINT (n
, xw
->height
);
922 DEFUN ("xwidget-view-info",
923 Fxwidget_view_info
, Sxwidget_view_info
,
925 doc
: /* Return properties of XWIDGET-VIEW in a vector.
926 Currently [X Y CLIP_RIGHT CLIP_BOTTOM CLIP_TOP CLIP_LEFT] */)
927 (Lisp_Object xwidget_view
)
929 CHECK_XWIDGET_VIEW (xwidget_view
);
930 struct xwidget_view
*xv
= XXWIDGET_VIEW (xwidget_view
);
933 info
= Fmake_vector (make_number (6), Qnil
);
934 ASET (info
, 0, make_number (xv
->x
));
935 ASET (info
, 1, make_number (xv
->y
));
936 ASET (info
, 2, make_number (xv
->clip_right
));
937 ASET (info
, 3, make_number (xv
->clip_bottom
));
938 ASET (info
, 4, make_number (xv
->clip_top
));
939 ASET (info
, 5, make_number (xv
->clip_left
));
944 DEFUN ("xwidget-view-model",
945 Fxwidget_view_model
, Sxwidget_view_model
,
947 doc
: /* Return the model associated with XWIDGET-VIEW. */)
948 (Lisp_Object xwidget_view
)
950 CHECK_XWIDGET_VIEW (xwidget_view
);
951 return XXWIDGET_VIEW (xwidget_view
)->model
;
954 DEFUN ("xwidget-view-window",
955 Fxwidget_view_window
, Sxwidget_view_window
,
957 doc
: /* Return the window of XWIDGET-VIEW. */)
958 (Lisp_Object xwidget_view
)
960 CHECK_XWIDGET_VIEW (xwidget_view
);
961 return XXWIDGET_VIEW (xwidget_view
)->w
;
965 DEFUN ("delete-xwidget-view",
966 Fdelete_xwidget_view
, Sdelete_xwidget_view
,
968 doc
: /* Delete the XWIDGET-VIEW. */)
969 (Lisp_Object xwidget_view
)
971 CHECK_XWIDGET_VIEW (xwidget_view
);
972 struct xwidget_view
*xv
= XXWIDGET_VIEW (xwidget_view
);
973 gtk_widget_destroy (xv
->widgetwindow
);
974 Vxwidget_view_list
= Fdelq (xwidget_view
, Vxwidget_view_list
);
975 // xv->model still has signals pointing to the view. There can be
976 // several views. Find the matching signals and delete them all.
977 g_signal_handlers_disconnect_matched (XXWIDGET (xv
->model
)->widgetwindow_osr
,
984 DEFUN ("xwidget-view-lookup",
985 Fxwidget_view_lookup
, Sxwidget_view_lookup
,
987 doc
: /* Return the xwidget-view associated with XWIDGET in
988 WINDOW if specified, otherwise it uses the selected window. Return nil
989 if no association is found. */)
990 (Lisp_Object xwidget
, Lisp_Object window
)
992 CHECK_XWIDGET (xwidget
);
995 window
= Fselected_window ();
996 CHECK_WINDOW (window
);
998 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
);
1001 Lisp_Object xwidget_view
= XCAR (tail
);
1002 if (EQ (Fxwidget_view_model (xwidget_view
), xwidget
)
1003 && EQ (Fxwidget_view_window (xwidget_view
), window
))
1004 return xwidget_view
;
1010 DEFUN ("xwidget-plist",
1011 Fxwidget_plist
, Sxwidget_plist
,
1013 doc
: /* Return the plist of XWIDGET. */)
1014 (register Lisp_Object xwidget
)
1016 CHECK_XWIDGET (xwidget
);
1017 return XXWIDGET (xwidget
)->plist
;
1020 DEFUN ("xwidget-buffer",
1021 Fxwidget_buffer
, Sxwidget_buffer
,
1023 doc
: /* Return the buffer of XWIDGET. */)
1024 (register Lisp_Object xwidget
)
1026 CHECK_XWIDGET (xwidget
);
1027 return XXWIDGET (xwidget
)->buffer
;
1030 DEFUN ("set-xwidget-plist",
1031 Fset_xwidget_plist
, Sset_xwidget_plist
,
1033 doc
: /* Replace the plist of XWIDGET with PLIST.
1035 (register Lisp_Object xwidget
, Lisp_Object plist
)
1037 CHECK_XWIDGET (xwidget
);
1040 XXWIDGET (xwidget
)->plist
= plist
;
1044 DEFUN ("set-xwidget-query-on-exit-flag",
1045 Fset_xwidget_query_on_exit_flag
, Sset_xwidget_query_on_exit_flag
,
1047 doc
: /* Specify if query is needed for XWIDGET when
1048 Emacs is exited. If the second argument FLAG is non-nil, Emacs will
1049 queries the user before exiting or killing a buffer if XWIDGET is
1050 running. This function returns FLAG. */)
1051 (Lisp_Object xwidget
, Lisp_Object flag
)
1053 CHECK_XWIDGET (xwidget
);
1054 XXWIDGET (xwidget
)->kill_without_query
= NILP (flag
);
1058 DEFUN ("xwidget-query-on-exit-flag",
1059 Fxwidget_query_on_exit_flag
, Sxwidget_query_on_exit_flag
,
1061 doc
: /* Return the current value of query-on-exit
1062 flag for XWIDGET. */)
1063 (Lisp_Object xwidget
)
1065 CHECK_XWIDGET (xwidget
);
1066 return (XXWIDGET (xwidget
)->kill_without_query
? Qnil
: Qt
);
1070 syms_of_xwidget (void)
1073 defsubr (&Smake_xwidget
);
1074 defsubr (&Sxwidgetp
);
1075 DEFSYM (Qxwidgetp
, "xwidgetp");
1076 defsubr (&Sxwidget_view_p
);
1077 DEFSYM (Qxwidget_view_p
, "xwidget-view-p");
1078 defsubr (&Sxwidget_info
);
1079 defsubr (&Sxwidget_view_info
);
1080 defsubr (&Sxwidget_resize
);
1081 defsubr (&Sget_buffer_xwidgets
);
1082 defsubr (&Sxwidget_view_model
);
1083 defsubr (&Sxwidget_view_window
);
1084 defsubr (&Sxwidget_view_lookup
);
1085 defsubr (&Sxwidget_query_on_exit_flag
);
1086 defsubr (&Sset_xwidget_query_on_exit_flag
);
1088 #ifdef HAVE_WEBKIT_OSR
1089 defsubr (&Sxwidget_webkit_goto_uri
);
1090 defsubr (&Sxwidget_webkit_execute_script
);
1091 defsubr (&Sxwidget_webkit_get_title
);
1092 DEFSYM (Qwebkit_osr
, "webkit-osr");
1095 defsubr (&Sxwidget_size_request
);
1096 defsubr (&Sdelete_xwidget_view
);
1098 defsubr (&Sxwidget_plist
);
1099 defsubr (&Sxwidget_buffer
);
1100 defsubr (&Sset_xwidget_plist
);
1102 defsubr (&Sxwidget_set_adjustment
);
1104 DEFSYM (Qxwidget
, "xwidget");
1106 DEFSYM (QCxwidget
, ":xwidget");
1107 DEFSYM (QCtitle
, ":title");
1109 /* Do not forget to update the docstring of make-xwidget if you add
1112 DEFSYM (Qvertical
, "vertical");
1113 DEFSYM (Qhorizontal
, "horizontal");
1115 DEFSYM (QCplist
, ":plist");
1117 DEFVAR_LISP ("xwidget-list", Vxwidget_list
,
1118 doc
: /* xwidgets list. */);
1119 Vxwidget_list
= Qnil
;
1121 DEFVAR_LISP ("xwidget-view-list", Vxwidget_view_list
,
1122 doc
: /* xwidget views list. */);
1123 Vxwidget_view_list
= Qnil
;
1125 Fprovide (intern ("xwidget-internal"), Qnil
);
1130 /* Value is non-zero if OBJECT is a valid Lisp xwidget specification. A
1131 valid xwidget specification is a list whose car is the symbol
1132 `xwidget', and whose rest is a property list. The property list must
1133 contain a value for key `:type'. That value must be the name of a
1134 supported xwidget type. The rest of the property list depends on the
1138 valid_xwidget_spec_p (Lisp_Object object
)
1140 int valid_p
= false;
1142 if (CONSP (object
) && EQ (XCAR (object
), Qxwidget
))
1150 /* Find a value associated with key in spec. */
1152 xwidget_spec_value (Lisp_Object spec
, Lisp_Object key
, int *found
)
1156 eassert (valid_xwidget_spec_p (spec
));
1158 for (tail
= XCDR (spec
);
1159 CONSP (tail
) && CONSP (XCDR (tail
)); tail
= XCDR (XCDR (tail
)))
1161 if (EQ (XCAR (tail
), key
))
1165 return XCAR (XCDR (tail
));
1176 xwidget_view_delete_all_in_window (struct window
*w
)
1178 struct xwidget_view
*xv
= NULL
;
1179 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
);
1182 if (XWIDGET_VIEW_P (XCAR (tail
)))
1184 xv
= XXWIDGET_VIEW (XCAR (tail
));
1185 if (XWINDOW (xv
->w
) == w
)
1187 Fdelete_xwidget_view (XCAR (tail
));
1193 struct xwidget_view
*
1194 xwidget_view_lookup (struct xwidget
*xw
, struct window
*w
)
1196 Lisp_Object xwidget
, window
, ret
;
1197 XSETXWIDGET (xwidget
, xw
);
1198 XSETWINDOW (window
, w
);
1200 ret
= Fxwidget_view_lookup (xwidget
, window
);
1202 return EQ (ret
, Qnil
) ? NULL
: XXWIDGET_VIEW (ret
);
1206 lookup_xwidget (Lisp_Object spec
)
1208 /* When a xwidget lisp spec is found initialize the C struct that is
1209 used in the C code. This is done by redisplay so values change
1210 if the spec changes. So, take special care of one-shot events.
1216 value
= xwidget_spec_value (spec
, QCxwidget
, &found
);
1217 xw
= XXWIDGET (value
);
1222 /* Set up detection of touched xwidget*/
1224 xwidget_start_redisplay (void)
1226 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
);
1229 if (XWIDGET_VIEW_P (XCAR (tail
)))
1230 XXWIDGET_VIEW (XCAR (tail
))->redisplayed
= 0;
1234 /* The xwidget was touched during redisplay, so it isn't a candidate
1237 xwidget_touch (struct xwidget_view
*xv
)
1239 xv
->redisplayed
= 1;
1243 xwidget_touched (struct xwidget_view
*xv
)
1245 return xv
->redisplayed
;
1248 /* Redisplay has ended, now we should hide untouched xwidgets
1251 xwidget_end_redisplay (struct window
*w
, struct glyph_matrix
*matrix
)
1257 xwidget_start_redisplay ();
1258 // Iterate desired glyph matrix of window here, hide gtk widgets
1259 // not in the desired matrix.
1261 // This only takes care of xwidgets in active windows. if a window
1262 // goes away from screen xwidget views wust be deleted
1264 // dump_glyph_matrix (matrix, 2);
1265 for (i
= 0; i
< matrix
->nrows
; ++i
)
1267 // dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs);
1268 struct glyph_row
*row
;
1269 row
= MATRIX_ROW (matrix
, i
);
1270 if (row
->enabled_p
!= 0)
1272 for (area
= LEFT_MARGIN_AREA
; area
< LAST_AREA
; ++area
)
1274 struct glyph
*glyph
= row
->glyphs
[area
];
1275 struct glyph
*glyph_end
= glyph
+ row
->used
[area
];
1276 for (; glyph
< glyph_end
; ++glyph
)
1278 if (glyph
->type
== XWIDGET_GLYPH
)
1281 The only call to xwidget_end_redisplay is in dispnew
1282 xwidget_end_redisplay (w->current_matrix);
1284 xwidget_touch (xwidget_view_lookup (glyph
->u
.xwidget
,
1292 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
);
1295 if (XWIDGET_VIEW_P (XCAR (tail
)))
1297 struct xwidget_view
*xv
= XXWIDGET_VIEW (XCAR (tail
));
1299 // "touched" is only meaningful for the current window, so
1300 // disregard other views.
1301 if (XWINDOW (xv
->w
) == w
)
1303 if (xwidget_touched (xv
))
1304 xwidget_show_view (xv
);
1306 xwidget_hide_view (xv
);
1312 /* Kill all xwidget in BUFFER. */
1314 kill_buffer_xwidgets (Lisp_Object buffer
)
1316 Lisp_Object tail
, xwidget
;
1317 for (tail
= Fget_buffer_xwidgets (buffer
); CONSP (tail
); tail
= XCDR (tail
))
1319 xwidget
= XCAR (tail
);
1320 Vxwidget_list
= Fdelq (xwidget
, Vxwidget_list
);
1321 /* TODO free the GTK things in xw */
1323 CHECK_XWIDGET (xwidget
);
1324 struct xwidget
*xw
= XXWIDGET (xwidget
);
1325 if (xw
->widget_osr
&& xw
->widgetwindow_osr
)
1327 gtk_widget_destroy (xw
->widget_osr
);
1328 gtk_widget_destroy (xw
->widgetwindow_osr
);