aboutsummaryrefslogtreecommitdiffstats
path: root/src/xwidget.c
diff options
context:
space:
mode:
authorPaul Eggert2016-01-30 11:27:34 -0800
committerPaul Eggert2016-01-30 11:27:34 -0800
commit82b089783e71b2aeef950eaecfe4cbc0735e64a2 (patch)
treea826c20768071bda95a69b2632718c1641c6d0cc /src/xwidget.c
parentd27c8078ef766dae3587bc82b70128a70efaa223 (diff)
parentf7dc6d8b5bb318e02a4016d93f8b34de0716f4dc (diff)
downloademacs-82b089783e71b2aeef950eaecfe4cbc0735e64a2.tar.gz
emacs-82b089783e71b2aeef950eaecfe4cbc0735e64a2.zip
-
Diffstat (limited to 'src/xwidget.c')
-rw-r--r--src/xwidget.c1320
1 files changed, 1320 insertions, 0 deletions
diff --git a/src/xwidget.c b/src/xwidget.c
new file mode 100644
index 00000000000..ea5dea0f9fe
--- /dev/null
+++ b/src/xwidget.c
@@ -0,0 +1,1320 @@
1/* Support for embedding graphical components in a buffer.
2
3Copyright (C) 2011-2016 Free Software Foundation, Inc.
4
5This file is part of GNU Emacs.
6
7GNU Emacs is free software: you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
19
20#include <config.h>
21
22
23#include <signal.h>
24
25#include <stdio.h>
26#include <setjmp.h>
27#ifdef HAVE_X_WINDOWS
28
29#include "lisp.h"
30#include "blockinput.h"
31#include "syssignal.h"
32
33#include "xterm.h"
34#include <X11/cursorfont.h>
35
36#ifndef makedev
37# include <sys/types.h>
38#endif
39
40#ifdef BSD_SYSTEM
41# include <sys/ioctl.h>
42#endif
43
44#include "systime.h"
45
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>
53
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"
72
73
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
86
87#include "gtkutil.h"
88#include "font.h"
89#endif /* HAVE_X_WINDOWS */
90
91#include <gtk/gtk.h>
92#include <gdk/gdk.h>
93
94#include <gtk/gtkx.h>
95
96#include "emacsgtkfixed.h"
97
98#include <wchar.h>
99
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>
107
108#include "xwidget.h"
109
110static struct xwidget *
111allocate_xwidget (void)
112{
113 return ALLOCATE_PSEUDOVECTOR (struct xwidget, height, PVEC_XWIDGET);
114}
115
116static struct xwidget_view *
117allocate_xwidget_view (void)
118{
119 return ALLOCATE_PSEUDOVECTOR (struct xwidget_view, redisplayed,
120 PVEC_XWIDGET_VIEW);
121}
122
123#define XSETXWIDGET(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET))
124#define XSETXWIDGET_VIEW(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW))
125
126static struct xwidget_view *xwidget_view_lookup (struct xwidget *,
127 struct window *);
128static void webkit_document_load_finished_cb (WebKitWebView *, WebKitWebFrame *,
129 gpointer);
130static gboolean webkit_download_cb (WebKitWebView *, WebKitDownload *, gpointer);
131
132static gboolean
133webkit_mime_type_policy_typedecision_requested_cb (WebKitWebView *,
134 WebKitWebFrame *,
135 WebKitNetworkRequest *,
136 gchar *,
137 WebKitWebPolicyDecision *,
138 gpointer);
139
140static gboolean
141webkit_new_window_policy_decision_requested_cb (WebKitWebView *,
142 WebKitWebFrame *,
143 WebKitNetworkRequest *,
144 WebKitWebNavigationAction *,
145 WebKitWebPolicyDecision *,
146 gpointer);
147
148static gboolean
149webkit_navigation_policy_decision_requested_cb (WebKitWebView *,
150 WebKitWebFrame *,
151 WebKitNetworkRequest *,
152 WebKitWebNavigationAction *,
153 WebKitWebPolicyDecision *,
154 gpointer);
155
156
157
158DEFUN ("make-xwidget",
159 Fmake_xwidget, Smake_xwidget,
160 7, 8, 0,
161 doc: /* Make an xwidget from BEG to END of TYPE.
162If BUFFER is nil, use the current buffer.
163If BUFFER is a string and no such buffer exists, create it.
164TYPE is a symbol which can take one of the following values:
165
166- webkit_osr
167
168Returns the newly constructed xwidget, or nil if construction fails. */)
169 (Lisp_Object beg, Lisp_Object end,
170 Lisp_Object type,
171 Lisp_Object title,
172 Lisp_Object width, Lisp_Object height,
173 Lisp_Object arguments, Lisp_Object buffer)
174{
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 ();
180 Lisp_Object val;
181 xw->type = type;
182 xw->title = title;
183 if (NILP (buffer))
184 buffer = Fcurrent_buffer (); // no need to gcpro because
185 // Fcurrent_buffer doesn't
186 // call Feval/eval_sub.
187 else
188 buffer = Fget_buffer_create (buffer);
189 xw->buffer = buffer;
190
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;
199 xw->plist = Qnil;
200
201
202 if (EQ (xw->type, Qwebkit_osr))
203 {
204 block_input ();
205 xw->widgetwindow_osr = gtk_offscreen_window_new ();
206 gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
207 xw->height);
208 xw->widgetscrolledwindow_osr = NULL; //webkit osr is the
209 //only scrolled
210 //component atm
211
212 if (EQ (xw->type, Qwebkit_osr))
213 {
214 xw->widgetscrolledwindow_osr = gtk_scrolled_window_new (NULL, NULL);
215 gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW
216 (xw->
217 widgetscrolledwindow_osr),
218 xw->height);
219 gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW
220 (xw->
221 widgetscrolledwindow_osr),
222 xw->width);
223 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW
224 (xw->widgetscrolledwindow_osr),
225 GTK_POLICY_ALWAYS,
226 GTK_POLICY_ALWAYS);
227
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)));
231 }
232
233 gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
234 xw->height);
235
236 if (EQ (xw->type, Qwebkit_osr))
237 {
238 gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
239 xw->widgetscrolledwindow_osr);
240 }
241 else
242 {
243 gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
244 xw->widget_osr);
245 }
246
247 gtk_widget_show (xw->widget_osr);
248 gtk_widget_show (xw->widgetwindow_osr);
249 gtk_widget_show (xw->widgetscrolledwindow_osr);
250
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,
254 (gpointer) (xw));
255 g_object_set_data (G_OBJECT (xw->widgetwindow_osr), XG_XWIDGET,
256 (gpointer) (xw));
257
258 /* signals */
259 if (EQ (xw->type, Qwebkit_osr))
260 {
261 g_signal_connect (G_OBJECT (xw->widget_osr),
262 "document-load-finished",
263 G_CALLBACK (webkit_document_load_finished_cb), xw);
264
265 g_signal_connect (G_OBJECT (xw->widget_osr),
266 "download-requested",
267 G_CALLBACK (webkit_download_cb), xw);
268
269 g_signal_connect (G_OBJECT (xw->widget_osr),
270 "mime-type-policy-decision-requested",
271 G_CALLBACK
272 (webkit_mime_type_policy_typedecision_requested_cb),
273 xw);
274
275 g_signal_connect (G_OBJECT (xw->widget_osr),
276 "new-window-policy-decision-requested",
277 G_CALLBACK
278 (webkit_new_window_policy_decision_requested_cb),
279 xw);
280
281 g_signal_connect (G_OBJECT (xw->widget_osr),
282 "navigation-policy-decision-requested",
283 G_CALLBACK
284 (webkit_navigation_policy_decision_requested_cb),
285 xw);
286 }
287
288 unblock_input ();
289
290 }
291
292 return val;
293}
294
295DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets, Sget_buffer_xwidgets,
296 1, 1, 0,
297 doc: /* Return a list of xwidgets associated with BUFFER.
298BUFFER may be a buffer or the name of one. */)
299 (Lisp_Object buffer)
300{
301 Lisp_Object xw, tail, xw_list;
302
303 if (NILP (buffer))
304 return Qnil;
305 buffer = Fget_buffer (buffer);
306 if (NILP (buffer))
307 return Qnil;
308
309 xw_list = Qnil;
310
311 for (tail = Vxwidget_list; CONSP (tail); tail = XCDR (tail))
312 {
313 xw = XCAR (tail);
314 if (XWIDGETP (xw) && EQ (Fxwidget_buffer (xw), buffer))
315 xw_list = Fcons (xw, xw_list);
316 }
317 return xw_list;
318}
319
320static int
321xwidget_hidden (struct xwidget_view *xv)
322{
323 return xv->hidden;
324}
325
326
327
328static void
329xwidget_show_view (struct xwidget_view *xv)
330{
331 xv->hidden = 0;
332 gtk_widget_show (xv->widgetwindow);
333 gtk_fixed_move (GTK_FIXED (xv->emacswindow),
334 xv->widgetwindow,
335 xv->x + xv->clip_left,
336 xv->y + xv->clip_top);
337}
338
339
340/* Hide an xvidget view. */
341static void
342xwidget_hide_view (struct xwidget_view *xv)
343{
344 xv->hidden = 1;
345 gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow,
346 10000, 10000);
347}
348
349
350
351/* When the off-screen webkit master view changes this signal is called.
352 It copies the bitmap from the off-screen instance. */
353static gboolean
354offscreen_damage_event (GtkWidget * widget, GdkEvent * event,
355 gpointer xv_widget)
356{
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));
363 else
364 printf ("Warning, offscreen_damage_event received invalid xv pointer:%p\n",
365 (void *) xv_widget);
366
367 return FALSE;
368}
369
370static void
371store_xwidget_event_string (struct xwidget *xw, const char *eventname,
372 const char *eventstr)
373{
374 struct input_event event;
375 Lisp_Object xwl;
376 XSETXWIDGET (xwl, xw);
377 EVENT_INIT (event);
378 event.kind = XWIDGET_EVENT;
379 event.frame_or_window = Qnil;
380
381 event.arg = 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);
386
387}
388
389//TODO deprecated, use load-status
390void
391webkit_document_load_finished_cb (WebKitWebView * webkitwebview,
392 WebKitWebFrame * arg1,
393 gpointer data)
394{
395 struct xwidget *xw =
396 (struct xwidget *) g_object_get_data (G_OBJECT (webkitwebview),
397 XG_XWIDGET);
398
399 store_xwidget_event_string (xw, "document-load-finished", "");
400}
401
402gboolean
403webkit_download_cb (WebKitWebView * webkitwebview,
404 WebKitDownload * arg1,
405 gpointer data)
406{
407 struct xwidget *xw =
408 (struct xwidget *) g_object_get_data (G_OBJECT (webkitwebview),
409 XG_XWIDGET);
410 store_xwidget_event_string (xw, "download-requested",
411 webkit_download_get_uri (arg1));
412
413 return FALSE;
414}
415
416static gboolean
417webkit_mime_type_policy_typedecision_requested_cb (WebKitWebView *webView,
418 WebKitWebFrame *frame,
419 WebKitNetworkRequest * request,
420 gchar * mimetype,
421 WebKitWebPolicyDecision *policy_decision,
422 gpointer user_data)
423{
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))
428 {
429 webkit_web_policy_decision_download (policy_decision);
430 return TRUE;
431 }
432 else
433 {
434 return FALSE;
435 }
436}
437
438
439static gboolean
440webkit_new_window_policy_decision_requested_cb (WebKitWebView *webView,
441 WebKitWebFrame *frame,
442 WebKitNetworkRequest *request,
443 WebKitWebNavigationAction *navigation_action,
444 WebKitWebPolicyDecision *policy_decision,
445 gpointer user_data)
446{
447 struct xwidget *xw =
448 (struct xwidget *) g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
449 webkit_web_navigation_action_get_original_uri (navigation_action);
450
451 store_xwidget_event_string (xw, "new-window-policy-decision-requested",
452 webkit_web_navigation_action_get_original_uri
453 (navigation_action));
454 return FALSE;
455}
456
457static gboolean
458webkit_navigation_policy_decision_requested_cb (WebKitWebView *webView,
459 WebKitWebFrame *frame,
460 WebKitNetworkRequest *request,
461 WebKitWebNavigationAction *navigation_action,
462 WebKitWebPolicyDecision * policy_decision,
463 gpointer user_data)
464{
465 struct xwidget *xw =
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));
470 return FALSE;
471}
472
473// For gtk3 offscreen rendered widgets.
474static gboolean
475xwidget_osr_draw_cb (GtkWidget * widget, cairo_t * cr, gpointer data)
476{
477 struct xwidget *xw =
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),
481 XG_XWIDGET_VIEW);
482
483 cairo_rectangle (cr, 0, 0, xv->clip_right, xv->clip_bottom);
484 cairo_clip (cr);
485
486 if (xw->widgetscrolledwindow_osr != NULL)
487 gtk_widget_draw (xw->widgetscrolledwindow_osr, cr);
488 else
489 gtk_widget_draw (xw->widget_osr, cr);
490 return FALSE;
491}
492
493static gboolean
494xwidget_osr_event_forward (GtkWidget * widget,
495 GdkEvent * event,
496 gpointer user_data)
497{
498 /* Copy events that arrive at the outer widget to the offscreen widget. */
499 struct xwidget *xw =
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);
503
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
508}
509
510
511static gboolean
512xwidget_osr_event_set_embedder (GtkWidget * widget,
513 GdkEvent * event, gpointer data)
514{
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));
520 return FALSE;
521}
522
523
524/* Initializes and does initial placement of an xwidget view on screen. */
525static struct xwidget_view *
526xwidget_init_view (struct xwidget *xww,
527 struct glyph_string *s,
528 int x, int y)
529{
530 struct xwidget_view *xv = allocate_xwidget_view ();
531 Lisp_Object val;
532
533 XSETXWIDGET_VIEW (val, xv);
534 Vxwidget_view_list = Fcons (val, Vxwidget_view_list);
535
536 XSETWINDOW (xv->w, s->w);
537 XSETXWIDGET (xv->model, xww);
538
539 if (EQ (xww->type, Qwebkit_osr))
540 {
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);
545
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);
549
550 if (EQ (xww->type, Qwebkit_osr))
551 {
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);
558 }
559 else
560 {
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);
564 }
565 g_signal_connect (G_OBJECT (xv->widget), "draw",
566 G_CALLBACK (xwidget_osr_draw_cb), NULL);
567 }
568 // Widget realization.
569
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);
579
580 // Store some xwidget data in the gtk widgets.
581 // The emacs frame.
582 g_object_set_data (G_OBJECT (xv->widget), XG_FRAME_DATA, (gpointer) (s->f));
583 // The xwidget.
584 g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET, (gpointer) (xww));
585 // The xwidget.
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));
589 // the xwidget view.
590 g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET_VIEW,
591 (gpointer) (xv));
592
593
594 gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xww->width,
595 xww->height);
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);
598 xv->x = x;
599 xv->y = y;
600 gtk_widget_show_all (xv->widgetwindow);
601
602
603 return xv;
604}
605
606
607void
608x_draw_xwidget_glyph_string (struct glyph_string *s)
609{
610 /* This method is called by the redisplay engine and places the
611 xwidget on screen. Moving and clipping is done here. Also view
612 initialization.
613 */
614 struct xwidget *xww = s->xwidget;
615 struct xwidget_view *xv = xwidget_view_lookup (xww, s->w);
616 int clip_right;
617 int clip_bottom;
618 int clip_top;
619 int clip_left;
620
621 int x = s->x;
622 int y = s->y + (s->height / 2) - (xww->height / 2);
623 int moved = 0;
624
625 /* We do initialization here in the display loop because there is no
626 other time to know things like window placement etc.
627 */
628 xv = xwidget_init_view (xww, s, x, y);
629
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.
633 clip_right =
634 min (xww->width,
635 WINDOW_RIGHT_EDGE_X (s->w) - x -
636 WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH (s->w) -
637 WINDOW_RIGHT_FRINGE_WIDTH (s->w));
638 clip_left =
639 max (0,
640 WINDOW_LEFT_EDGE_X (s->w) - x +
641 WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (s->w) +
642 WINDOW_LEFT_FRINGE_WIDTH (s->w));
643
644 clip_bottom =
645 min (xww->height,
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);
648
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
656 // later
657 moved = (xv->x + xv->clip_left != x + clip_left)
658 || ((xv->y + xv->clip_top) != (y + clip_top));
659 xv->x = x;
660 xv->y = y;
661 if (moved) // Has it moved?
662 {
663 gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)),
664 xv->widgetwindow, x + clip_left, y + clip_top);
665 }
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
670 // for real.
671 if ((xv->clip_right != clip_right)
672 || (xv->clip_bottom != clip_bottom)
673 || (xv->clip_top != clip_top) || (xv->clip_left != clip_left))
674 {
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,
678 -clip_top);
679
680 xv->clip_right = clip_right;
681 xv->clip_bottom = clip_bottom;
682 xv->clip_top = clip_top;
683 xv->clip_left = clip_left;
684 }
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))
690 {
691 gtk_widget_queue_draw (xv->widgetwindow);
692 gtk_widget_queue_draw (xv->widget);
693 }
694}
695
696
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");\
706 return Qnil;\
707 };
708
709
710DEFUN ("xwidget-webkit-goto-uri",
711 Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri,
712 2, 2, 0,
713 doc: /* Make the xwidget webkit instance referenced by XWIDGET browse URI. */)
714 (Lisp_Object xwidget, Lisp_Object uri)
715{
716 WEBKIT_FN_INIT ();
717 CHECK_STRING (uri);
718 webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr), SSDATA (uri));
719 return Qnil;
720}
721
722
723DEFUN ("xwidget-webkit-execute-script",
724 Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script,
725 2, 2, 0,
726 doc: /* Make the Webkit XWIDGET execute javascript SCRIPT. */)
727 (Lisp_Object xwidget, Lisp_Object script)
728{
729 WEBKIT_FN_INIT ();
730 CHECK_STRING (script);
731 webkit_web_view_execute_script (WEBKIT_WEB_VIEW (xw->widget_osr),
732 SSDATA (script));
733 return Qnil;
734}
735
736DEFUN ("xwidget-webkit-get-title",
737 Fxwidget_webkit_get_title, Sxwidget_webkit_get_title,
738 1, 1, 0,
739 doc: /* Return the title from the Webkit instance in XWIDGET.
740This can be used to work around the lack of a return value from the
741exec method. */ )
742 (Lisp_Object xwidget)
743{
744 // TODO support multibyte strings
745 WEBKIT_FN_INIT ();
746 const gchar *str =
747 webkit_web_view_get_title (WEBKIT_WEB_VIEW (xw->widget_osr));
748 if (str == 0)
749 {
750 // TODO maybe return Qnil instead. I suppose webkit returns
751 // nullpointer when doc is not properly loaded or something
752 return build_string ("");
753 }
754 return build_string (str);
755}
756
757DEFUN ("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)
760{
761 CHECK_XWIDGET (xwidget);
762 struct xwidget *xw = XXWIDGET (xwidget);
763 struct xwidget_view *xv;
764 int w, h;
765
766 CHECK_NUMBER (new_width);
767 CHECK_NUMBER (new_height);
768 w = XFASTINT (new_width);
769 h = XFASTINT (new_height);
770
771 xw->width = w;
772 xw->height = h;
773 // If there is a offscreen widget resize it 1st.
774 if (xw->widget_osr)
775 {
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,
779 xw->height);
780 gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW
781 (xw->
782 widgetscrolledwindow_osr),
783 xw->height);
784 gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW
785 (xw->
786 widgetscrolledwindow_osr),
787 xw->width);
788
789 gtk_container_resize_children (GTK_CONTAINER (xw->widgetwindow_osr));
790
791 }
792
793 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
794 {
795 if (XWIDGET_VIEW_P (XCAR (tail)))
796 {
797 xv = XXWIDGET_VIEW (XCAR (tail));
798 if (XXWIDGET (xv->model) == xw)
799 gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width,
800 xw->height);
801 }
802 }
803
804 return Qnil;
805}
806
807
808
809DEFUN ("xwidget-set-adjustment",
810 Fxwidget_set_adjustment, Sxwidget_set_adjustment, 4, 4, 0,
811 doc: /* Set native scrolling for XWIDGET.
812AXIS can be 'vertical or 'horizontal.
813If RELATIVE is t, scroll relative, otherwise absolutely.
814VALUE is the amount to scroll, either relatively or absolutely. */)
815 (Lisp_Object xwidget, Lisp_Object axis, Lisp_Object relative,
816 Lisp_Object value)
817{
818 CHECK_XWIDGET (xwidget);
819 struct xwidget *xw = XXWIDGET (xwidget);
820 GtkAdjustment *adjustment;
821 float final_value = 0.0;
822
823 adjustment =
824 gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
825 (xw->widgetscrolledwindow_osr));
826 if (EQ (Qvertical, axis))
827 {
828 adjustment =
829 gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
830 (xw->widgetscrolledwindow_osr));
831 }
832 if (EQ (Qhorizontal, axis))
833 {
834 adjustment =
835 gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW
836 (xw->widgetscrolledwindow_osr));
837 }
838
839 if (EQ (Qt, relative))
840 {
841 final_value = gtk_adjustment_get_value (adjustment) + XFASTINT (value);
842 }
843 else
844 {
845 final_value = 0.0 + XFASTINT (value);
846 }
847
848 gtk_adjustment_set_value (adjustment, final_value);
849
850 return Qnil;
851}
852
853
854DEFUN ("xwidget-size-request",
855 Fxwidget_size_request, Sxwidget_size_request,
856 1, 1, 0,
857 doc: /* Return the desired size of the XWIDGET.
858This can be used to read the xwidget desired size, and resizes the
859Emacs allocated area accordingly. */)
860 (Lisp_Object xwidget)
861{
862 CHECK_XWIDGET (xwidget);
863 GtkRequisition requisition;
864 Lisp_Object rv;
865 gtk_widget_size_request (XXWIDGET (xwidget)->widget_osr, &requisition);
866 rv = Qnil;
867 rv = Fcons (make_number (requisition.height), rv);
868 rv = Fcons (make_number (requisition.width), rv);
869 return rv;
870
871}
872
873DEFUN ("xwidgetp",
874 Fxwidgetp, Sxwidgetp,
875 1, 1, 0,
876 doc: /* Return t if OBJECT is an xwidget. */)
877 (Lisp_Object object)
878{
879 return XWIDGETP (object) ? Qt : Qnil;
880}
881
882DEFUN ("xwidget-view-p",
883 Fxwidget_view_p, Sxwidget_view_p,
884 1, 1, 0,
885 doc: /* Return t if OBJECT is an xwidget-view. */)
886 (Lisp_Object object)
887{
888 return XWIDGET_VIEW_P (object) ? Qt : Qnil;
889}
890
891DEFUN ("xwidget-info",
892 Fxwidget_info, Sxwidget_info,
893 1, 1, 0,
894 doc: /* Return XWIDGET properties in a vector.
895Currently [TYPE TITLE WIDTH HEIGHT]. */)
896 (Lisp_Object xwidget)
897{
898 CHECK_XWIDGET (xwidget);
899 Lisp_Object info, n;
900 struct xwidget *xw = XXWIDGET (xwidget);
901
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);
906 ASET (info, 2, n);
907 XSETFASTINT (n, xw->height);
908 ASET (info, 3, n);
909
910 return info;
911}
912
913DEFUN ("xwidget-view-info",
914 Fxwidget_view_info, Sxwidget_view_info,
915 1, 1, 0,
916 doc: /* Return properties of XWIDGET-VIEW in a vector.
917Currently [X Y CLIP_RIGHT CLIP_BOTTOM CLIP_TOP CLIP_LEFT]. */)
918 (Lisp_Object xwidget_view)
919{
920 CHECK_XWIDGET_VIEW (xwidget_view);
921 struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
922 Lisp_Object info;
923
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));
931
932 return info;
933}
934
935DEFUN ("xwidget-view-model",
936 Fxwidget_view_model, Sxwidget_view_model,
937 1, 1, 0,
938 doc: /* Return the model associated with XWIDGET-VIEW. */)
939 (Lisp_Object xwidget_view)
940{
941 CHECK_XWIDGET_VIEW (xwidget_view);
942 return XXWIDGET_VIEW (xwidget_view)->model;
943}
944
945DEFUN ("xwidget-view-window",
946 Fxwidget_view_window, Sxwidget_view_window,
947 1, 1, 0,
948 doc: /* Return the window of XWIDGET-VIEW. */)
949 (Lisp_Object xwidget_view)
950{
951 CHECK_XWIDGET_VIEW (xwidget_view);
952 return XXWIDGET_VIEW (xwidget_view)->w;
953}
954
955
956DEFUN ("delete-xwidget-view",
957 Fdelete_xwidget_view, Sdelete_xwidget_view,
958 1, 1, 0,
959 doc: /* Delete the XWIDGET-VIEW. */)
960 (Lisp_Object xwidget_view)
961{
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,
969 G_SIGNAL_MATCH_DATA,
970 0, 0, 0, 0,
971 xv->widget);
972 return Qnil;
973}
974
975DEFUN ("xwidget-view-lookup",
976 Fxwidget_view_lookup, Sxwidget_view_lookup,
977 1, 2, 0,
978 doc: /* Return the xwidget-view associated with XWIDGET in WINDOW.
979If WINDOW is unspecified or nil, use the selected window.
980Return nil if no association is found. */)
981 (Lisp_Object xwidget, Lisp_Object window)
982{
983 CHECK_XWIDGET (xwidget);
984
985 if (NILP (window))
986 window = Fselected_window ();
987 CHECK_WINDOW (window);
988
989 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
990 tail = XCDR (tail))
991 {
992 Lisp_Object xwidget_view = XCAR (tail);
993 if (EQ (Fxwidget_view_model (xwidget_view), xwidget)
994 && EQ (Fxwidget_view_window (xwidget_view), window))
995 return xwidget_view;
996 }
997
998 return Qnil;
999}
1000
1001DEFUN ("xwidget-plist",
1002 Fxwidget_plist, Sxwidget_plist,
1003 1, 1, 0,
1004 doc: /* Return the plist of XWIDGET. */)
1005 (register Lisp_Object xwidget)
1006{
1007 CHECK_XWIDGET (xwidget);
1008 return XXWIDGET (xwidget)->plist;
1009}
1010
1011DEFUN ("xwidget-buffer",
1012 Fxwidget_buffer, Sxwidget_buffer,
1013 1, 1, 0,
1014 doc: /* Return the buffer of XWIDGET. */)
1015 (register Lisp_Object xwidget)
1016{
1017 CHECK_XWIDGET (xwidget);
1018 return XXWIDGET (xwidget)->buffer;
1019}
1020
1021DEFUN ("set-xwidget-plist",
1022 Fset_xwidget_plist, Sset_xwidget_plist,
1023 2, 2, 0,
1024 doc: /* Replace the plist of XWIDGET with PLIST.
1025Returns PLIST. */)
1026 (register Lisp_Object xwidget, Lisp_Object plist)
1027{
1028 CHECK_XWIDGET (xwidget);
1029 CHECK_LIST (plist);
1030
1031 XXWIDGET (xwidget)->plist = plist;
1032 return plist;
1033}
1034
1035DEFUN ("set-xwidget-query-on-exit-flag",
1036 Fset_xwidget_query_on_exit_flag, Sset_xwidget_query_on_exit_flag,
1037 2, 2, 0,
1038 doc: /* Specify if query is needed for XWIDGET when Emacs is exited.
1039If the second argument FLAG is non-nil, Emacs will query the user before
1040exiting or killing a buffer if XWIDGET is running.
1041This function returns FLAG. */)
1042 (Lisp_Object xwidget, Lisp_Object flag)
1043{
1044 CHECK_XWIDGET (xwidget);
1045 XXWIDGET (xwidget)->kill_without_query = NILP (flag);
1046 return flag;
1047}
1048
1049DEFUN ("xwidget-query-on-exit-flag",
1050 Fxwidget_query_on_exit_flag, Sxwidget_query_on_exit_flag,
1051 1, 1, 0,
1052 doc: /* Return the current value of the query-on-exit flag for XWIDGET. */)
1053 (Lisp_Object xwidget)
1054{
1055 CHECK_XWIDGET (xwidget);
1056 return (XXWIDGET (xwidget)->kill_without_query ? Qnil : Qt);
1057}
1058
1059void
1060syms_of_xwidget (void)
1061{
1062
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);
1077
1078 defsubr (&Sxwidget_webkit_goto_uri);
1079 defsubr (&Sxwidget_webkit_execute_script);
1080 defsubr (&Sxwidget_webkit_get_title);
1081 DEFSYM (Qwebkit_osr, "webkit-osr");
1082
1083 defsubr (&Sxwidget_size_request);
1084 defsubr (&Sdelete_xwidget_view);
1085
1086 defsubr (&Sxwidget_plist);
1087 defsubr (&Sxwidget_buffer);
1088 defsubr (&Sset_xwidget_plist);
1089
1090 defsubr (&Sxwidget_set_adjustment);
1091
1092 DEFSYM (Qxwidget, "xwidget");
1093
1094 DEFSYM (QCxwidget, ":xwidget");
1095 DEFSYM (QCtitle, ":title");
1096
1097 /* Do not forget to update the docstring of make-xwidget if you add
1098 new types. */
1099
1100 DEFSYM (Qvertical, "vertical");
1101 DEFSYM (Qhorizontal, "horizontal");
1102
1103 DEFSYM (QCplist, ":plist");
1104
1105 DEFVAR_LISP ("xwidget-list", Vxwidget_list,
1106 doc: /* xwidgets list. */);
1107 Vxwidget_list = Qnil;
1108
1109 DEFVAR_LISP ("xwidget-view-list", Vxwidget_view_list,
1110 doc: /* xwidget views list. */);
1111 Vxwidget_view_list = Qnil;
1112
1113 Fprovide (intern ("xwidget-internal"), Qnil);
1114
1115}
1116
1117
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
1123 xwidget type. */
1124
1125bool
1126valid_xwidget_spec_p (Lisp_Object object)
1127{
1128 int valid_p = false;
1129
1130 if (CONSP (object) && EQ (XCAR (object), Qxwidget))
1131 valid_p = true;
1132
1133 return valid_p;
1134}
1135
1136
1137
1138/* Find a value associated with key in spec. */
1139static Lisp_Object
1140xwidget_spec_value (Lisp_Object spec, Lisp_Object key, int *found)
1141{
1142 Lisp_Object tail;
1143
1144 eassert (valid_xwidget_spec_p (spec));
1145
1146 for (tail = XCDR (spec);
1147 CONSP (tail) && CONSP (XCDR (tail)); tail = XCDR (XCDR (tail)))
1148 {
1149 if (EQ (XCAR (tail), key))
1150 {
1151 if (found)
1152 *found = 1;
1153 return XCAR (XCDR (tail));
1154 }
1155 }
1156
1157 if (found)
1158 *found = 0;
1159 return Qnil;
1160}
1161
1162
1163void
1164xwidget_view_delete_all_in_window (struct window *w)
1165{
1166 struct xwidget_view *xv = NULL;
1167 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
1168 tail = XCDR (tail))
1169 {
1170 if (XWIDGET_VIEW_P (XCAR (tail)))
1171 {
1172 xv = XXWIDGET_VIEW (XCAR (tail));
1173 if (XWINDOW (xv->w) == w)
1174 {
1175 Fdelete_xwidget_view (XCAR (tail));
1176 }
1177 }
1178 }
1179}
1180
1181static struct xwidget_view *
1182xwidget_view_lookup (struct xwidget *xw, struct window *w)
1183{
1184 Lisp_Object xwidget, window, ret;
1185 XSETXWIDGET (xwidget, xw);
1186 XSETWINDOW (window, w);
1187
1188 ret = Fxwidget_view_lookup (xwidget, window);
1189
1190 return EQ (ret, Qnil) ? NULL : XXWIDGET_VIEW (ret);
1191}
1192
1193struct xwidget *
1194lookup_xwidget (Lisp_Object spec)
1195{
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.
1199 */
1200 int found = 0;
1201 Lisp_Object value;
1202 struct xwidget *xw;
1203
1204 value = xwidget_spec_value (spec, QCxwidget, &found);
1205 xw = XXWIDGET (value);
1206
1207 return xw;
1208}
1209
1210/* Set up detection of touched xwidget */
1211static void
1212xwidget_start_redisplay (void)
1213{
1214 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
1215 tail = XCDR (tail))
1216 {
1217 if (XWIDGET_VIEW_P (XCAR (tail)))
1218 XXWIDGET_VIEW (XCAR (tail))->redisplayed = 0;
1219 }
1220}
1221
1222/* The xwidget was touched during redisplay, so it isn't a candidate
1223 for hiding. */
1224static void
1225xwidget_touch (struct xwidget_view *xv)
1226{
1227 xv->redisplayed = 1;
1228}
1229
1230static int
1231xwidget_touched (struct xwidget_view *xv)
1232{
1233 return xv->redisplayed;
1234}
1235
1236/* Redisplay has ended, now we should hide untouched xwidgets
1237*/
1238void
1239xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix)
1240{
1241
1242 int i;
1243 int area;
1244
1245 xwidget_start_redisplay ();
1246 // Iterate desired glyph matrix of window here, hide gtk widgets
1247 // not in the desired matrix.
1248
1249 // This only takes care of xwidgets in active windows. If a window
1250 // goes away from screen xwidget views wust be deleted
1251
1252 // dump_glyph_matrix (matrix, 2);
1253 for (i = 0; i < matrix->nrows; ++i)
1254 {
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)
1259 {
1260 for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
1261 {
1262 struct glyph *glyph = row->glyphs[area];
1263 struct glyph *glyph_end = glyph + row->used[area];
1264 for (; glyph < glyph_end; ++glyph)
1265 {
1266 if (glyph->type == XWIDGET_GLYPH)
1267 {
1268 /*
1269 The only call to xwidget_end_redisplay is in dispnew
1270 xwidget_end_redisplay (w->current_matrix);
1271 */
1272 xwidget_touch (xwidget_view_lookup (glyph->u.xwidget,
1273 w));
1274 }
1275 }
1276 }
1277 }
1278 }
1279
1280 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
1281 tail = XCDR (tail))
1282 {
1283 if (XWIDGET_VIEW_P (XCAR (tail)))
1284 {
1285 struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail));
1286
1287 // "touched" is only meaningful for the current window, so
1288 // disregard other views.
1289 if (XWINDOW (xv->w) == w)
1290 {
1291 if (xwidget_touched (xv))
1292 xwidget_show_view (xv);
1293 else
1294 xwidget_hide_view (xv);
1295 }
1296 }
1297 }
1298}
1299
1300/* Kill all xwidget in BUFFER. */
1301void
1302kill_buffer_xwidgets (Lisp_Object buffer)
1303{
1304 Lisp_Object tail, xwidget;
1305 for (tail = Fget_buffer_xwidgets (buffer); CONSP (tail); tail = XCDR (tail))
1306 {
1307 xwidget = XCAR (tail);
1308 Vxwidget_list = Fdelq (xwidget, Vxwidget_list);
1309 /* TODO free the GTK things in xw */
1310 {
1311 CHECK_XWIDGET (xwidget);
1312 struct xwidget *xw = XXWIDGET (xwidget);
1313 if (xw->widget_osr && xw->widgetwindow_osr)
1314 {
1315 gtk_widget_destroy (xw->widget_osr);
1316 gtk_widget_destroy (xw->widgetwindow_osr);
1317 }
1318 }
1319 }
1320}