Trivial doc copyedits.
[emacs.git] / src / xwidget.c
blob88cdb941c4ca679fa09d3d84a33c955eadcf014a
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/>. */
20 #include <config.h>
23 #include <signal.h>
25 #include <stdio.h>
26 #include <setjmp.h>
27 #ifdef HAVE_X_WINDOWS
29 #include "lisp.h"
30 #include "blockinput.h"
31 #include "syssignal.h"
33 #include "xterm.h"
34 #include <X11/cursorfont.h>
36 #ifndef makedev
37 # include <sys/types.h>
38 #endif
40 #ifdef BSD_SYSTEM
41 # include <sys/ioctl.h>
42 #endif
44 #include "systime.h"
46 #ifndef INCLUDED_FCNTL
47 # include <fcntl.h>
48 #endif
49 #include <ctype.h>
50 #include <errno.h>
51 #include <setjmp.h>
52 #include <sys/stat.h>
54 #include "charset.h"
55 #include "character.h"
56 #include "coding.h"
57 #include "ccl.h"
58 #include "frame.h"
59 #include "dispextern.h"
60 #include "fontset.h"
61 #include "termhooks.h"
62 #include "termopts.h"
63 #include "termchar.h"
64 #include "disptab.h"
65 #include "buffer.h"
66 #include "window.h"
67 #include "keyboard.h"
68 #include "intervals.h"
69 #include "process.h"
70 #include "atimer.h"
71 #include "keymap.h"
74 #ifdef USE_X_TOOLKIT
75 #include <X11/Shell.h>
76 #endif
77 #include <X11/extensions/Xcomposite.h>
78 #include <X11/extensions/Xrender.h>
79 #include <cairo.h>
80 #ifdef HAVE_SYS_TIME_H
81 #include <sys/time.h>
82 #endif
83 #ifdef HAVE_UNISTD_H
84 #include <unistd.h>
85 #endif
87 #include "gtkutil.h"
88 #include "font.h"
89 #endif /* HAVE_X_WINDOWS */
91 #include <gtk/gtk.h>
92 #include <gdk/gdk.h>
94 #include <gtk/gtkx.h>
96 #include "emacsgtkfixed.h"
98 #include <wchar.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>
108 #include "xwidget.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,
120 PVEC_XWIDGET_VIEW);
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 *,
130 gpointer );
131 gboolean webkit_download_cb (WebKitWebView *, WebKitDownload *, gpointer);
133 gboolean
134 webkit_mime_type_policy_typedecision_requested_cb (WebKitWebView *,
135 WebKitWebFrame *,
136 WebKitNetworkRequest *,
137 gchar *,
138 WebKitWebPolicyDecision *,
139 gpointer);
141 gboolean
142 webkit_new_window_policy_decision_requested_cb (WebKitWebView *,
143 WebKitWebFrame *,
144 WebKitNetworkRequest *,
145 WebKitWebNavigationAction *,
146 WebKitWebPolicyDecision *,
147 gpointer);
149 gboolean
150 webkit_navigation_policy_decision_requested_cb (WebKitWebView *,
151 WebKitWebFrame *,
152 WebKitNetworkRequest *,
153 WebKitWebNavigationAction *,
154 WebKitWebPolicyDecision *,
155 gpointer);
159 DEFUN ("make-xwidget",
160 Fmake_xwidget, Smake_xwidget,
161 7, 8, 0,
162 doc: /* Make an xwidget from BEG to END of TYPE.
163 If BUFFER is nil, use the current buffer.
164 If BUFFER is a string and no such buffer exists, create it.
165 TYPE is a symbol which can take one of the following values:
167 - webkit_osr
169 Returns the newly constructed xwidget, or nil if construction fails. */)
170 (Lisp_Object beg, Lisp_Object end,
171 Lisp_Object type,
172 Lisp_Object title,
173 Lisp_Object width, Lisp_Object height,
174 Lisp_Object arguments, Lisp_Object buffer)
176 //should work a bit like "make-button"(make-button BEG END &rest PROPERTIES)
177 // arg "type" and fwd should be keyword args eventually
178 //(make-xwidget 3 3 'button "oei" 31 31 nil)
179 //(xwidget-info (car xwidget-list))
180 struct xwidget *xw = allocate_xwidget ();
181 Lisp_Object val;
182 xw->type = type;
183 xw->title = title;
184 if (NILP (buffer))
185 buffer = Fcurrent_buffer (); // no need to gcpro because
186 // Fcurrent_buffer doesn't
187 // call Feval/eval_sub.
188 else
189 buffer = Fget_buffer_create (buffer);
190 xw->buffer = buffer;
192 xw->height = XFASTINT (height);
193 xw->width = XFASTINT (width);
194 xw->kill_without_query = 0;
195 XSETXWIDGET (val, xw); // set the vectorlike_header of VAL
196 // with the correct value
197 Vxwidget_list = Fcons (val, Vxwidget_list);
198 xw->widgetwindow_osr = NULL;
199 xw->widget_osr = NULL;
200 xw->plist = Qnil;
203 if (EQ (xw->type, Qwebkit_osr))
205 block_input ();
206 xw->widgetwindow_osr = gtk_offscreen_window_new ();
207 gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
208 xw->height);
209 xw->widgetscrolledwindow_osr = NULL; //webkit osr is the
210 //only scrolled
211 //component atm
213 if (EQ (xw->type, Qwebkit_osr))
215 xw->widgetscrolledwindow_osr = gtk_scrolled_window_new (NULL, NULL);
216 gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW
217 (xw->
218 widgetscrolledwindow_osr),
219 xw->height);
220 gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW
221 (xw->
222 widgetscrolledwindow_osr),
223 xw->width);
224 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW
225 (xw->widgetscrolledwindow_osr),
226 GTK_POLICY_ALWAYS,
227 GTK_POLICY_ALWAYS);
229 xw->widget_osr = webkit_web_view_new ();
230 gtk_container_add (GTK_CONTAINER (xw->widgetscrolledwindow_osr),
231 GTK_WIDGET (WEBKIT_WEB_VIEW (xw->widget_osr)));
234 gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
235 xw->height);
237 if (EQ (xw->type, Qwebkit_osr))
239 gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
240 xw->widgetscrolledwindow_osr);
242 else
244 gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
245 xw->widget_osr);
248 gtk_widget_show (xw->widget_osr);
249 gtk_widget_show (xw->widgetwindow_osr);
250 gtk_widget_show (xw->widgetscrolledwindow_osr);
252 /* store some xwidget data in the gtk widgets for convenient
253 retrieval in the event handlers. */
254 g_object_set_data (G_OBJECT (xw->widget_osr), XG_XWIDGET,
255 (gpointer) (xw));
256 g_object_set_data (G_OBJECT (xw->widgetwindow_osr), XG_XWIDGET,
257 (gpointer) (xw));
259 /* signals */
260 if (EQ (xw->type, Qwebkit_osr))
262 g_signal_connect (G_OBJECT (xw->widget_osr),
263 "document-load-finished",
264 G_CALLBACK
265 (webkit_document_load_finished_cb), xw);
267 g_signal_connect (G_OBJECT (xw->widget_osr),
268 "download-requested",
269 G_CALLBACK (webkit_download_cb), xw);
271 g_signal_connect (G_OBJECT (xw->widget_osr),
272 "mime-type-policy-decision-requested",
273 G_CALLBACK
274 (webkit_mime_type_policy_typedecision_requested_cb),
275 xw);
277 g_signal_connect (G_OBJECT (xw->widget_osr),
278 "new-window-policy-decision-requested",
279 G_CALLBACK
280 (webkit_new_window_policy_decision_requested_cb),
281 xw);
283 g_signal_connect (G_OBJECT (xw->widget_osr),
284 "navigation-policy-decision-requested",
285 G_CALLBACK
286 (webkit_navigation_policy_decision_requested_cb),
287 xw);
290 unblock_input ();
294 return val;
297 DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets, Sget_buffer_xwidgets,
298 1, 1, 0,
299 doc: /* Return a list of xwidgets associated with BUFFER.
300 BUFFER may be a buffer or the name of one. */)
301 (Lisp_Object buffer)
303 Lisp_Object xw, tail, xw_list;
305 if (NILP (buffer))
306 return Qnil;
307 buffer = Fget_buffer (buffer);
308 if (NILP (buffer))
309 return Qnil;
311 xw_list = Qnil;
313 for (tail = Vxwidget_list; CONSP (tail); tail = XCDR (tail))
315 xw = XCAR (tail);
316 if (XWIDGETP (xw) && EQ (Fxwidget_buffer (xw), buffer))
317 xw_list = Fcons (xw, xw_list);
319 return xw_list;
322 static int
323 xwidget_hidden (struct xwidget_view *xv)
325 return xv->hidden;
330 static void
331 xwidget_show_view (struct xwidget_view *xv)
333 xv->hidden = 0;
334 gtk_widget_show (xv->widgetwindow);
335 gtk_fixed_move (GTK_FIXED (xv->emacswindow),
336 xv->widgetwindow,
337 xv->x + xv->clip_left,
338 xv->y + xv->clip_top);
342 /* Hide an xvidget view. */
343 static void
344 xwidget_hide_view (struct xwidget_view *xv)
346 xv->hidden = 1;
347 gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow,
348 10000, 10000);
353 /* When the off-screen webkit master view changes this signal is called.
354 It copies the bitmap from the off-screen instance. */
355 gboolean
356 offscreen_damage_event (GtkWidget * widget, GdkEvent * event,
357 gpointer xv_widget)
359 // Queue a redraw of onscreen widget.
360 // There is a guard against receiving an invalid widget,
361 // which should only happen if we failed to remove the
362 // specific signal handler for the damage event.
363 if (GTK_IS_WIDGET (xv_widget))
364 gtk_widget_queue_draw (GTK_WIDGET (xv_widget));
365 else
366 printf ("Warning, offscreen_damage_event received invalid xv pointer:%p\n",
367 (void *) xv_widget);
369 return FALSE;
372 static void
373 store_xwidget_event_string (struct xwidget *xw, const char *eventname,
374 const char *eventstr)
376 struct input_event event;
377 Lisp_Object xwl;
378 XSETXWIDGET (xwl, xw);
379 EVENT_INIT (event);
380 event.kind = XWIDGET_EVENT;
381 event.frame_or_window = Qnil;
383 event.arg = Qnil;
384 event.arg = Fcons (build_string (eventstr), event.arg);
385 event.arg = Fcons (xwl, event.arg);
386 event.arg = Fcons (intern (eventname), event.arg);
387 kbd_buffer_store_event (&event);
391 //TODO deprecated, use load-status
392 void
393 webkit_document_load_finished_cb (WebKitWebView * webkitwebview,
394 WebKitWebFrame * arg1,
395 gpointer data)
397 struct xwidget *xw =
398 (struct xwidget *) g_object_get_data (G_OBJECT (webkitwebview),
399 XG_XWIDGET);
401 store_xwidget_event_string (xw, "document-load-finished", "");
404 gboolean
405 webkit_download_cb (WebKitWebView * webkitwebview,
406 WebKitDownload * arg1,
407 gpointer data)
409 struct xwidget *xw =
410 (struct xwidget *) g_object_get_data (G_OBJECT (webkitwebview),
411 XG_XWIDGET);
412 store_xwidget_event_string (xw, "download-requested",
413 webkit_download_get_uri (arg1));
415 return FALSE;
418 gboolean
419 webkit_mime_type_policy_typedecision_requested_cb (WebKitWebView *webView,
420 WebKitWebFrame *frame,
421 WebKitNetworkRequest * request,
422 gchar * mimetype,
423 WebKitWebPolicyDecision *policy_decision,
424 gpointer user_data)
426 // This function makes webkit send a download signal for all unknown
427 // mime types. TODO Defer the decision to lisp, so that its possible
428 // to make Emacs handle teext mime for instance.xs
429 if (!webkit_web_view_can_show_mime_type (webView, mimetype))
431 webkit_web_policy_decision_download (policy_decision);
432 return TRUE;
434 else
436 return FALSE;
441 gboolean
442 webkit_new_window_policy_decision_requested_cb (WebKitWebView *webView,
443 WebKitWebFrame *frame,
444 WebKitNetworkRequest *request,
445 WebKitWebNavigationAction *navigation_action,
446 WebKitWebPolicyDecision *policy_decision,
447 gpointer user_data)
449 struct xwidget *xw =
450 (struct xwidget *) g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
451 webkit_web_navigation_action_get_original_uri (navigation_action);
453 store_xwidget_event_string (xw, "new-window-policy-decision-requested",
454 webkit_web_navigation_action_get_original_uri
455 (navigation_action));
456 return FALSE;
459 gboolean
460 webkit_navigation_policy_decision_requested_cb (WebKitWebView *webView,
461 WebKitWebFrame *frame,
462 WebKitNetworkRequest *request,
463 WebKitWebNavigationAction *navigation_action,
464 WebKitWebPolicyDecision * policy_decision,
465 gpointer user_data)
467 struct xwidget *xw =
468 (struct xwidget *) g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
469 store_xwidget_event_string (xw, "navigation-policy-decision-requested",
470 webkit_web_navigation_action_get_original_uri
471 (navigation_action));
472 return FALSE;
475 // For gtk3 offscreen rendered widgets.
476 static gboolean
477 xwidget_osr_draw_cb (GtkWidget * widget, cairo_t * cr, gpointer data)
479 struct xwidget *xw =
480 (struct xwidget *) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
481 struct xwidget_view *xv =
482 (struct xwidget_view *) g_object_get_data (G_OBJECT (widget),
483 XG_XWIDGET_VIEW);
485 cairo_rectangle (cr, 0, 0, xv->clip_right, xv->clip_bottom);
486 cairo_clip (cr);
488 if (xw->widgetscrolledwindow_osr != NULL)
489 gtk_widget_draw (xw->widgetscrolledwindow_osr, cr);
490 else
491 gtk_widget_draw (xw->widget_osr, cr);
492 return FALSE;
495 static gboolean
496 xwidget_osr_event_forward (GtkWidget * widget,
497 GdkEvent * event,
498 gpointer user_data)
500 /* Copy events that arrive at the outer widget to the offscreen widget. */
501 struct xwidget *xw =
502 (struct xwidget *) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
503 GdkEvent *eventcopy = gdk_event_copy (event);
504 eventcopy->any.window = gtk_widget_get_window (xw->widget_osr);
506 //TODO This might leak events. They should be deallocated later,
507 //perhaps in xwgir_event_cb
508 gtk_main_do_event (eventcopy);
509 return TRUE; //dont propagate this event furter
513 static gboolean
514 xwidget_osr_event_set_embedder (GtkWidget * widget,
515 GdkEvent * event, gpointer data)
517 struct xwidget_view *xv = (struct xwidget_view *) data;
518 struct xwidget *xww = XXWIDGET (xv->model);
519 gdk_offscreen_window_set_embedder (gtk_widget_get_window
520 (xww->widgetwindow_osr),
521 gtk_widget_get_window (xv->widget));
522 return FALSE;
526 /* Initializes and does initial placement of an xwidget view on screen. */
527 static struct xwidget_view *
528 xwidget_init_view (struct xwidget *xww,
529 struct glyph_string *s,
530 int x, int y)
532 struct xwidget_view *xv = allocate_xwidget_view ();
533 Lisp_Object val;
535 XSETXWIDGET_VIEW (val, xv);
536 Vxwidget_view_list = Fcons (val, Vxwidget_view_list);
538 XSETWINDOW (xv->w, s->w);
539 XSETXWIDGET (xv->model, xww);
541 if (EQ (xww->type, Qwebkit_osr))
543 xv->widget = gtk_drawing_area_new ();
544 // Expose event handling.
545 gtk_widget_set_app_paintable (xv->widget, TRUE);
546 gtk_widget_add_events (xv->widget, GDK_ALL_EVENTS_MASK);
548 /* Draw the view on damage-event */
549 g_signal_connect (G_OBJECT (xww->widgetwindow_osr), "damage-event",
550 G_CALLBACK (offscreen_damage_event), xv->widget);
552 if (EQ (xww->type, Qwebkit_osr))
554 g_signal_connect (G_OBJECT (xv->widget), "button-press-event",
555 G_CALLBACK (xwidget_osr_event_forward), NULL);
556 g_signal_connect (G_OBJECT (xv->widget), "button-release-event",
557 G_CALLBACK (xwidget_osr_event_forward), NULL);
558 g_signal_connect (G_OBJECT (xv->widget), "motion-notify-event",
559 G_CALLBACK (xwidget_osr_event_forward), NULL);
561 else
563 // xwgir debug , orthogonal to forwarding
564 g_signal_connect (G_OBJECT (xv->widget), "enter-notify-event",
565 G_CALLBACK (xwidget_osr_event_set_embedder), xv);
567 g_signal_connect (G_OBJECT (xv->widget), "draw",
568 G_CALLBACK (xwidget_osr_draw_cb), NULL);
570 // Widget realization.
572 // Make container widget 1st, and put the actual widget inside the
573 // container later. Drawing should crop container window if necessary
574 // to handle case where xwidget is partially obscured by other Emacs
575 // windows. Other containers than gtk_fixed where explored, but
576 // gtk_fixed had the most predictable behaviour so far.
577 xv->emacswindow = FRAME_GTK_WIDGET (s->f);
578 xv->widgetwindow = gtk_fixed_new ();
579 gtk_widget_set_has_window (xv->widgetwindow, TRUE);
580 gtk_container_add (GTK_CONTAINER (xv->widgetwindow), xv->widget);
582 // Store some xwidget data in the gtk widgets.
583 // The emacs frame.
584 g_object_set_data (G_OBJECT (xv->widget), XG_FRAME_DATA, (gpointer) (s->f));
585 // The xwidget.
586 g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET, (gpointer) (xww));
587 // The xwidget.
588 g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET_VIEW, (gpointer) (xv));
589 // The xwidget window.
590 g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET, (gpointer) (xww));
591 // the xwidget view.
592 g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET_VIEW,
593 (gpointer) (xv));
596 gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xww->width,
597 xww->height);
598 gtk_widget_set_size_request (xv->widgetwindow, xww->width, xww->height);
599 gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), xv->widgetwindow, x, y);
600 xv->x = x;
601 xv->y = y;
602 gtk_widget_show_all (xv->widgetwindow);
605 return xv;
609 void
610 x_draw_xwidget_glyph_string (struct glyph_string *s)
612 /* This method is called by the redisplay engine and places the
613 xwidget on screen. Moving and clipping is done here. Also view
614 initialization.
616 struct xwidget *xww = s->xwidget;
617 struct xwidget_view *xv = xwidget_view_lookup (xww, s->w);
618 int clip_right;
619 int clip_bottom;
620 int clip_top;
621 int clip_left;
623 int x = s->x;
624 int y = s->y + (s->height / 2) - (xww->height / 2);
625 int moved = 0;
627 /* We do initialization here in the display loop because there is no
628 other time to know things like window placement etc.
630 xv = xwidget_init_view (xww, s, x, y);
632 // Calculate clipping, which is used for all manner of onscreen
633 // xwidget views. Each widget border can get clipped by other emacs
634 // objects so there are four clipping variables.
635 clip_right =
636 min (xww->width,
637 WINDOW_RIGHT_EDGE_X (s->w) - x -
638 WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH (s->w) -
639 WINDOW_RIGHT_FRINGE_WIDTH (s->w));
640 clip_left =
641 max (0,
642 WINDOW_LEFT_EDGE_X (s->w) - x +
643 WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (s->w) +
644 WINDOW_LEFT_FRINGE_WIDTH (s->w));
646 clip_bottom =
647 min (xww->height,
648 WINDOW_BOTTOM_EDGE_Y (s->w) - WINDOW_MODE_LINE_HEIGHT (s->w) - y);
649 clip_top = max (0, WINDOW_TOP_EDGE_Y (s->w) - y);
651 // We are conserned with movement of the onscreen area. The area
652 // might sit still when the widget actually moves. This happens
653 // when an Emacs window border moves across a widget window. So, if
654 // any corner of the outer widget clipping window moves, that counts
655 // as movement here, even if it looks like no movement happens
656 // because the widget sits still inside the clipping area. The
657 // widget can also move inside the clipping area, which happens
658 // later
659 moved = (xv->x + xv->clip_left != x + clip_left)
660 || ((xv->y + xv->clip_top) != (y + clip_top));
661 xv->x = x;
662 xv->y = y;
663 if (moved) // Has it moved?
665 gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)),
666 xv->widgetwindow, x + clip_left, y + clip_top);
668 // Clip the widget window if some parts happen to be outside
669 // drawable area. An Emacs window is not a gtk window. A gtk window
670 // covers the entire frame. Clipping might have changed even if we
671 // havent actualy moved, we try figure out when we need to reclip
672 // for real.
673 if ((xv->clip_right != clip_right)
674 || (xv->clip_bottom != clip_bottom)
675 || (xv->clip_top != clip_top) || (xv->clip_left != clip_left))
677 gtk_widget_set_size_request (xv->widgetwindow, clip_right + clip_left,
678 clip_bottom + clip_top);
679 gtk_fixed_move (GTK_FIXED (xv->widgetwindow), xv->widget, -clip_left,
680 -clip_top);
682 xv->clip_right = clip_right;
683 xv->clip_bottom = clip_bottom;
684 xv->clip_top = clip_top;
685 xv->clip_left = clip_left;
687 // If emacs wants to repaint the area where the widget lives, queue
688 // a redraw. It seems its possible to get out of sync with emacs
689 // redraws so emacs background sometimes shows up instead of the
690 // xwidgets background. It's just a visual glitch though.
691 if (!xwidget_hidden (xv))
693 gtk_widget_queue_draw (xv->widgetwindow);
694 gtk_widget_queue_draw (xv->widget);
699 // Macro that checks WEBKIT_IS_WEB_VIEW(xw->widget_osr) first
700 #define WEBKIT_FN_INIT() \
701 struct xwidget* xw; \
702 CHECK_XWIDGET (xwidget); \
703 if (NILP (xwidget)) {printf("ERROR xwidget nil\n"); return Qnil;}; \
704 xw = XXWIDGET (xwidget); \
705 if (NULL == xw) printf("ERROR xw is 0\n"); \
706 if ((NULL == xw->widget_osr) || !WEBKIT_IS_WEB_VIEW(xw->widget_osr)){ \
707 printf ("ERROR xw->widget_osr does not hold a webkit instance\n");\
708 return Qnil;\
712 DEFUN ("xwidget-webkit-goto-uri",
713 Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri,
714 2, 2, 0,
715 doc: /* Make the xwidget webkit instance referenced by XWIDGET browse URI. */)
716 (Lisp_Object xwidget, Lisp_Object uri)
718 WEBKIT_FN_INIT ();
719 CHECK_STRING (uri);
720 webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr), SSDATA (uri));
721 return Qnil;
725 DEFUN ("xwidget-webkit-execute-script",
726 Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script,
727 2, 2, 0,
728 doc: /* Make the Webkit XWIDGET execute javascript SCRIPT. */)
729 (Lisp_Object xwidget, Lisp_Object script)
731 WEBKIT_FN_INIT ();
732 CHECK_STRING (script);
733 webkit_web_view_execute_script (WEBKIT_WEB_VIEW (xw->widget_osr),
734 SSDATA (script));
735 return Qnil;
738 DEFUN ("xwidget-webkit-get-title",
739 Fxwidget_webkit_get_title, Sxwidget_webkit_get_title,
740 1, 1, 0,
741 doc: /* Return the title from the Webkit instance in XWIDGET.
742 This can be used to work around the lack of a return value from the
743 exec method. */ )
744 (Lisp_Object xwidget)
746 // TODO support multibyte strings
747 WEBKIT_FN_INIT ();
748 const gchar *str =
749 webkit_web_view_get_title (WEBKIT_WEB_VIEW (xw->widget_osr));
750 if (str == 0)
752 // TODO maybe return Qnil instead. I suppose webkit returns
753 // nullpointer when doc is not properly loaded or something
754 return build_string ("");
756 return build_string (str);
759 DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
760 doc: /* Resize XWIDGET. NEW_WIDTH, NEW_HEIGHT define the new size. */ )
761 (Lisp_Object xwidget, Lisp_Object new_width, Lisp_Object new_height)
763 CHECK_XWIDGET (xwidget);
764 struct xwidget *xw = XXWIDGET (xwidget);
765 struct xwidget_view *xv;
766 int w, h;
768 CHECK_NUMBER (new_width);
769 CHECK_NUMBER (new_height);
770 w = XFASTINT (new_width);
771 h = XFASTINT (new_height);
773 xw->width = w;
774 xw->height = h;
775 // If there is a offscreen widget resize it 1st.
776 if (xw->widget_osr)
778 gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr),
779 xw->width, xw->height); //minimum size
780 gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
781 xw->height);
782 gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW
783 (xw->
784 widgetscrolledwindow_osr),
785 xw->height);
786 gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW
787 (xw->
788 widgetscrolledwindow_osr),
789 xw->width);
791 gtk_container_resize_children (GTK_CONTAINER (xw->widgetwindow_osr));
795 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
797 if (XWIDGET_VIEW_P (XCAR (tail)))
799 xv = XXWIDGET_VIEW (XCAR (tail));
800 if (XXWIDGET (xv->model) == xw)
801 gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width,
802 xw->height);
806 return Qnil;
811 DEFUN ("xwidget-set-adjustment",
812 Fxwidget_set_adjustment, Sxwidget_set_adjustment, 4, 4, 0,
813 doc: /* Set native scrolling for XWIDGET.
814 AXIS can be 'vertical or 'horizontal.
815 If RELATIVE is t, scroll relative, otherwise absolutely.
816 VALUE is the amount to scroll, either relatively or absolutely. */)
817 (Lisp_Object xwidget, Lisp_Object axis, Lisp_Object relative,
818 Lisp_Object value)
820 CHECK_XWIDGET (xwidget);
821 struct xwidget *xw = XXWIDGET (xwidget);
822 GtkAdjustment *adjustment;
823 float final_value = 0.0;
825 adjustment =
826 gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
827 (xw->widgetscrolledwindow_osr));
828 if (EQ (Qvertical, axis))
830 adjustment =
831 gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
832 (xw->widgetscrolledwindow_osr));
834 if (EQ (Qhorizontal, axis))
836 adjustment =
837 gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW
838 (xw->widgetscrolledwindow_osr));
841 if (EQ (Qt, relative))
843 final_value = gtk_adjustment_get_value (adjustment) + XFASTINT (value);
845 else
847 final_value = 0.0 + XFASTINT (value);
850 gtk_adjustment_set_value (adjustment, final_value);
852 return Qnil;
856 DEFUN ("xwidget-size-request",
857 Fxwidget_size_request, Sxwidget_size_request,
858 1, 1, 0,
859 doc: /* Return the desired size of the XWIDGET.
860 This can be used to read the xwidget desired size, and resizes the
861 Emacs allocated area accordingly. */)
862 (Lisp_Object xwidget)
864 CHECK_XWIDGET (xwidget);
865 GtkRequisition requisition;
866 Lisp_Object rv;
867 gtk_widget_size_request (XXWIDGET (xwidget)->widget_osr, &requisition);
868 rv = Qnil;
869 rv = Fcons (make_number (requisition.height), rv);
870 rv = Fcons (make_number (requisition.width), rv);
871 return rv;
875 DEFUN ("xwidgetp",
876 Fxwidgetp, Sxwidgetp,
877 1, 1, 0,
878 doc: /* Return t if OBJECT is an xwidget. */)
879 (Lisp_Object object)
881 return XWIDGETP (object) ? Qt : Qnil;
884 DEFUN ("xwidget-view-p",
885 Fxwidget_view_p, Sxwidget_view_p,
886 1, 1, 0,
887 doc: /* Return t if OBJECT is an xwidget-view. */)
888 (Lisp_Object object)
890 return XWIDGET_VIEW_P (object) ? Qt : Qnil;
893 DEFUN ("xwidget-info",
894 Fxwidget_info, Sxwidget_info,
895 1, 1, 0,
896 doc: /* Return XWIDGET properties in a vector.
897 Currently [TYPE TITLE WIDTH HEIGHT]. */)
898 (Lisp_Object xwidget)
900 CHECK_XWIDGET (xwidget);
901 Lisp_Object info, n;
902 struct xwidget *xw = XXWIDGET (xwidget);
904 info = Fmake_vector (make_number (4), Qnil);
905 ASET (info, 0, xw->type);
906 ASET (info, 1, xw->title);
907 XSETFASTINT (n, xw->width);
908 ASET (info, 2, n);
909 XSETFASTINT (n, xw->height);
910 ASET (info, 3, n);
912 return info;
915 DEFUN ("xwidget-view-info",
916 Fxwidget_view_info, Sxwidget_view_info,
917 1, 1, 0,
918 doc: /* Return properties of XWIDGET-VIEW in a vector.
919 Currently [X Y CLIP_RIGHT CLIP_BOTTOM CLIP_TOP CLIP_LEFT]. */)
920 (Lisp_Object xwidget_view)
922 CHECK_XWIDGET_VIEW (xwidget_view);
923 struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
924 Lisp_Object info;
926 info = Fmake_vector (make_number (6), Qnil);
927 ASET (info, 0, make_number (xv->x));
928 ASET (info, 1, make_number (xv->y));
929 ASET (info, 2, make_number (xv->clip_right));
930 ASET (info, 3, make_number (xv->clip_bottom));
931 ASET (info, 4, make_number (xv->clip_top));
932 ASET (info, 5, make_number (xv->clip_left));
934 return info;
937 DEFUN ("xwidget-view-model",
938 Fxwidget_view_model, Sxwidget_view_model,
939 1, 1, 0,
940 doc: /* Return the model associated with XWIDGET-VIEW. */)
941 (Lisp_Object xwidget_view)
943 CHECK_XWIDGET_VIEW (xwidget_view);
944 return XXWIDGET_VIEW (xwidget_view)->model;
947 DEFUN ("xwidget-view-window",
948 Fxwidget_view_window, Sxwidget_view_window,
949 1, 1, 0,
950 doc: /* Return the window of XWIDGET-VIEW. */)
951 (Lisp_Object xwidget_view)
953 CHECK_XWIDGET_VIEW (xwidget_view);
954 return XXWIDGET_VIEW (xwidget_view)->w;
958 DEFUN ("delete-xwidget-view",
959 Fdelete_xwidget_view, Sdelete_xwidget_view,
960 1, 1, 0,
961 doc: /* Delete the XWIDGET-VIEW. */)
962 (Lisp_Object xwidget_view)
964 CHECK_XWIDGET_VIEW (xwidget_view);
965 struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
966 gtk_widget_destroy (xv->widgetwindow);
967 Vxwidget_view_list = Fdelq (xwidget_view, Vxwidget_view_list);
968 // xv->model still has signals pointing to the view. There can be
969 // several views. Find the matching signals and delete them all.
970 g_signal_handlers_disconnect_matched (XXWIDGET (xv->model)->widgetwindow_osr,
971 G_SIGNAL_MATCH_DATA,
972 0, 0, 0, 0,
973 xv->widget);
974 return Qnil;
977 DEFUN ("xwidget-view-lookup",
978 Fxwidget_view_lookup, Sxwidget_view_lookup,
979 1, 2, 0,
980 doc: /* Return the xwidget-view associated with XWIDGET in WINDOW.
981 If WINDOW is unspecified or nil, use the selected window.
982 Return nil if no association is found. */)
983 (Lisp_Object xwidget, Lisp_Object window)
985 CHECK_XWIDGET (xwidget);
987 if (NILP (window))
988 window = Fselected_window ();
989 CHECK_WINDOW (window);
991 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
992 tail = XCDR (tail))
994 Lisp_Object xwidget_view = XCAR (tail);
995 if (EQ (Fxwidget_view_model (xwidget_view), xwidget)
996 && EQ (Fxwidget_view_window (xwidget_view), window))
997 return xwidget_view;
1000 return Qnil;
1003 DEFUN ("xwidget-plist",
1004 Fxwidget_plist, Sxwidget_plist,
1005 1, 1, 0,
1006 doc: /* Return the plist of XWIDGET. */)
1007 (register Lisp_Object xwidget)
1009 CHECK_XWIDGET (xwidget);
1010 return XXWIDGET (xwidget)->plist;
1013 DEFUN ("xwidget-buffer",
1014 Fxwidget_buffer, Sxwidget_buffer,
1015 1, 1, 0,
1016 doc: /* Return the buffer of XWIDGET. */)
1017 (register Lisp_Object xwidget)
1019 CHECK_XWIDGET (xwidget);
1020 return XXWIDGET (xwidget)->buffer;
1023 DEFUN ("set-xwidget-plist",
1024 Fset_xwidget_plist, Sset_xwidget_plist,
1025 2, 2, 0,
1026 doc: /* Replace the plist of XWIDGET with PLIST.
1027 Returns PLIST. */)
1028 (register Lisp_Object xwidget, Lisp_Object plist)
1030 CHECK_XWIDGET (xwidget);
1031 CHECK_LIST (plist);
1033 XXWIDGET (xwidget)->plist = plist;
1034 return plist;
1037 DEFUN ("set-xwidget-query-on-exit-flag",
1038 Fset_xwidget_query_on_exit_flag, Sset_xwidget_query_on_exit_flag,
1039 2, 2, 0,
1040 doc: /* Specify if query is needed for XWIDGET when Emacs is exited.
1041 If the second argument FLAG is non-nil, Emacs will query the user before
1042 exiting or killing a buffer if XWIDGET is running.
1043 This function returns FLAG. */)
1044 (Lisp_Object xwidget, Lisp_Object flag)
1046 CHECK_XWIDGET (xwidget);
1047 XXWIDGET (xwidget)->kill_without_query = NILP (flag);
1048 return flag;
1051 DEFUN ("xwidget-query-on-exit-flag",
1052 Fxwidget_query_on_exit_flag, Sxwidget_query_on_exit_flag,
1053 1, 1, 0,
1054 doc: /* Return the current value of the query-on-exit flag for XWIDGET. */)
1055 (Lisp_Object xwidget)
1057 CHECK_XWIDGET (xwidget);
1058 return (XXWIDGET (xwidget)->kill_without_query ? Qnil : Qt);
1061 void
1062 syms_of_xwidget (void)
1065 defsubr (&Smake_xwidget);
1066 defsubr (&Sxwidgetp);
1067 DEFSYM (Qxwidgetp, "xwidgetp");
1068 defsubr (&Sxwidget_view_p);
1069 DEFSYM (Qxwidget_view_p, "xwidget-view-p");
1070 defsubr (&Sxwidget_info);
1071 defsubr (&Sxwidget_view_info);
1072 defsubr (&Sxwidget_resize);
1073 defsubr (&Sget_buffer_xwidgets);
1074 defsubr (&Sxwidget_view_model);
1075 defsubr (&Sxwidget_view_window);
1076 defsubr (&Sxwidget_view_lookup);
1077 defsubr (&Sxwidget_query_on_exit_flag);
1078 defsubr (&Sset_xwidget_query_on_exit_flag);
1080 #ifdef HAVE_WEBKIT_OSR
1081 defsubr (&Sxwidget_webkit_goto_uri);
1082 defsubr (&Sxwidget_webkit_execute_script);
1083 defsubr (&Sxwidget_webkit_get_title);
1084 DEFSYM (Qwebkit_osr, "webkit-osr");
1085 #endif
1087 defsubr (&Sxwidget_size_request);
1088 defsubr (&Sdelete_xwidget_view);
1090 defsubr (&Sxwidget_plist);
1091 defsubr (&Sxwidget_buffer);
1092 defsubr (&Sset_xwidget_plist);
1094 defsubr (&Sxwidget_set_adjustment);
1096 DEFSYM (Qxwidget, "xwidget");
1098 DEFSYM (QCxwidget, ":xwidget");
1099 DEFSYM (QCtitle, ":title");
1101 /* Do not forget to update the docstring of make-xwidget if you add
1102 new types. */
1104 DEFSYM (Qvertical, "vertical");
1105 DEFSYM (Qhorizontal, "horizontal");
1107 DEFSYM (QCplist, ":plist");
1109 DEFVAR_LISP ("xwidget-list", Vxwidget_list,
1110 doc: /* xwidgets list. */);
1111 Vxwidget_list = Qnil;
1113 DEFVAR_LISP ("xwidget-view-list", Vxwidget_view_list,
1114 doc: /* xwidget views list. */);
1115 Vxwidget_view_list = Qnil;
1117 Fprovide (intern ("xwidget-internal"), Qnil);
1122 /* Value is non-zero if OBJECT is a valid Lisp xwidget specification. A
1123 valid xwidget specification is a list whose car is the symbol
1124 `xwidget', and whose rest is a property list. The property list must
1125 contain a value for key `:type'. That value must be the name of a
1126 supported xwidget type. The rest of the property list depends on the
1127 xwidget type. */
1129 bool
1130 valid_xwidget_spec_p (Lisp_Object object)
1132 int valid_p = false;
1134 if (CONSP (object) && EQ (XCAR (object), Qxwidget))
1135 valid_p = true;
1137 return valid_p;
1142 /* Find a value associated with key in spec. */
1143 Lisp_Object
1144 xwidget_spec_value (Lisp_Object spec, Lisp_Object key, int *found)
1146 Lisp_Object tail;
1148 eassert (valid_xwidget_spec_p (spec));
1150 for (tail = XCDR (spec);
1151 CONSP (tail) && CONSP (XCDR (tail)); tail = XCDR (XCDR (tail)))
1153 if (EQ (XCAR (tail), key))
1155 if (found)
1156 *found = 1;
1157 return XCAR (XCDR (tail));
1161 if (found)
1162 *found = 0;
1163 return Qnil;
1167 void
1168 xwidget_view_delete_all_in_window (struct window *w)
1170 struct xwidget_view *xv = NULL;
1171 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
1172 tail = XCDR (tail))
1174 if (XWIDGET_VIEW_P (XCAR (tail)))
1176 xv = XXWIDGET_VIEW (XCAR (tail));
1177 if (XWINDOW (xv->w) == w)
1179 Fdelete_xwidget_view (XCAR (tail));
1185 struct xwidget_view *
1186 xwidget_view_lookup (struct xwidget *xw, struct window *w)
1188 Lisp_Object xwidget, window, ret;
1189 XSETXWIDGET (xwidget, xw);
1190 XSETWINDOW (window, w);
1192 ret = Fxwidget_view_lookup (xwidget, window);
1194 return EQ (ret, Qnil) ? NULL : XXWIDGET_VIEW (ret);
1197 struct xwidget *
1198 lookup_xwidget (Lisp_Object spec)
1200 /* When a xwidget lisp spec is found initialize the C struct that is
1201 used in the C code. This is done by redisplay so values change
1202 if the spec changes. So, take special care of one-shot events.
1204 int found = 0;
1205 Lisp_Object value;
1206 struct xwidget *xw;
1208 value = xwidget_spec_value (spec, QCxwidget, &found);
1209 xw = XXWIDGET (value);
1211 return xw;
1214 /* Set up detection of touched xwidget */
1215 void
1216 xwidget_start_redisplay (void)
1218 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
1219 tail = XCDR (tail))
1221 if (XWIDGET_VIEW_P (XCAR (tail)))
1222 XXWIDGET_VIEW (XCAR (tail))->redisplayed = 0;
1226 /* The xwidget was touched during redisplay, so it isn't a candidate
1227 for hiding. */
1228 void
1229 xwidget_touch (struct xwidget_view *xv)
1231 xv->redisplayed = 1;
1234 static int
1235 xwidget_touched (struct xwidget_view *xv)
1237 return xv->redisplayed;
1240 /* Redisplay has ended, now we should hide untouched xwidgets
1242 void
1243 xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix)
1246 int i;
1247 int area;
1249 xwidget_start_redisplay ();
1250 // Iterate desired glyph matrix of window here, hide gtk widgets
1251 // not in the desired matrix.
1253 // This only takes care of xwidgets in active windows. If a window
1254 // goes away from screen xwidget views wust be deleted
1256 // dump_glyph_matrix (matrix, 2);
1257 for (i = 0; i < matrix->nrows; ++i)
1259 // dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs);
1260 struct glyph_row *row;
1261 row = MATRIX_ROW (matrix, i);
1262 if (row->enabled_p != 0)
1264 for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
1266 struct glyph *glyph = row->glyphs[area];
1267 struct glyph *glyph_end = glyph + row->used[area];
1268 for (; glyph < glyph_end; ++glyph)
1270 if (glyph->type == XWIDGET_GLYPH)
1273 The only call to xwidget_end_redisplay is in dispnew
1274 xwidget_end_redisplay (w->current_matrix);
1276 xwidget_touch (xwidget_view_lookup (glyph->u.xwidget,
1277 w));
1284 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
1285 tail = XCDR (tail))
1287 if (XWIDGET_VIEW_P (XCAR (tail)))
1289 struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail));
1291 // "touched" is only meaningful for the current window, so
1292 // disregard other views.
1293 if (XWINDOW (xv->w) == w)
1295 if (xwidget_touched (xv))
1296 xwidget_show_view (xv);
1297 else
1298 xwidget_hide_view (xv);
1304 /* Kill all xwidget in BUFFER. */
1305 void
1306 kill_buffer_xwidgets (Lisp_Object buffer)
1308 Lisp_Object tail, xwidget;
1309 for (tail = Fget_buffer_xwidgets (buffer); CONSP (tail); tail = XCDR (tail))
1311 xwidget = XCAR (tail);
1312 Vxwidget_list = Fdelq (xwidget, Vxwidget_list);
1313 /* TODO free the GTK things in xw */
1315 CHECK_XWIDGET (xwidget);
1316 struct xwidget *xw = XXWIDGET (xwidget);
1317 if (xw->widget_osr && xw->widgetwindow_osr)
1319 gtk_widget_destroy (xw->widget_osr);
1320 gtk_widget_destroy (xw->widgetwindow_osr);