Revert "Revert changes installed by xwidgets merge"
[emacs.git] / src / xwidget.c
blob747e803acc96ddd1885b4bc01bd2584cd49fb2d3
1 #include <config.h>
2 #ifdef HAVE_XWIDGETS
4 #include <signal.h>
6 #include <stdio.h>
7 #include <setjmp.h>
8 #ifdef HAVE_X_WINDOWS
10 #include "lisp.h"
11 #include "blockinput.h"
12 #include "syssignal.h"
14 #include "xterm.h"
15 #include <X11/cursorfont.h>
17 #ifndef makedev
18 #include <sys/types.h>
19 #endif /* makedev */
21 #ifdef BSD_SYSTEM
22 #include <sys/ioctl.h>
23 #endif /* ! defined (BSD_SYSTEM) */
25 #include "systime.h"
27 #ifndef INCLUDED_FCNTL
28 #include <fcntl.h>
29 #endif
30 #include <ctype.h>
31 #include <errno.h>
32 #include <setjmp.h>
33 #include <sys/stat.h>
35 #include "charset.h"
36 #include "character.h"
37 #include "coding.h"
38 #include "ccl.h"
39 #include "frame.h"
40 #include "dispextern.h"
41 #include "fontset.h"
42 #include "termhooks.h"
43 #include "termopts.h"
44 #include "termchar.h"
45 #include "emacs-icon.h"
46 #include "disptab.h"
47 #include "buffer.h"
48 #include "window.h"
49 #include "keyboard.h"
50 #include "intervals.h"
51 #include "process.h"
52 #include "atimer.h"
53 #include "keymap.h"
56 #ifdef USE_X_TOOLKIT
57 #include <X11/Shell.h>
58 #endif
59 #include <X11/extensions/Xcomposite.h>
60 #include <X11/extensions/Xrender.h>
61 #include <cairo.h>
62 #ifdef HAVE_SYS_TIME_H
63 #include <sys/time.h>
64 #endif
65 #ifdef HAVE_UNISTD_H
66 #include <unistd.h>
67 #endif
69 #include "gtkutil.h"
70 #include "font.h"
71 #endif /* HAVE_X_WINDOWS */
73 #include <gtk/gtk.h>
74 #include <gdk/gdk.h>
76 #ifdef HAVE_GTK3
77 //for gtk3; sockets and plugs
78 #include <gtk/gtkx.h>
79 #include <gtk/gtkscrolledwindow.h>
80 #include "emacsgtkfixed.h"
81 #endif
83 #include <wchar.h>
85 #ifdef HAVE_WEBKIT_OSR
86 #include <webkit/webkitwebview.h>
87 #include <webkit/webkitwebplugindatabase.h>
88 #include <webkit/webkitwebplugin.h>
89 #include <webkit/webkitglobals.h>
90 #include <webkit/webkitwebnavigationaction.h>
91 #include <webkit/webkitdownload.h>
92 #include <webkit/webkitwebpolicydecision.h>
93 #endif
95 //for GIR
96 #include <girepository.h>
98 #include "xwidget.h"
100 //TODO embryo of lisp allocators for xwidgets
101 //TODO xwidget* should be Lisp_xwidget*
102 struct xwidget*
103 allocate_xwidget (void)
105 return ALLOCATE_PSEUDOVECTOR (struct xwidget, height, PVEC_XWIDGET);
108 //TODO xwidget_view* should be Lisp_xwidget_view*
109 struct xwidget_view*
110 allocate_xwidget_view (void)
112 return ALLOCATE_PSEUDOVECTOR (struct xwidget_view, redisplayed, PVEC_XWIDGET_VIEW);
114 #define XSETXWIDGET(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET))
115 #define XSETXWIDGET_VIEW(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW))
117 struct xwidget_view* xwidget_view_lookup(struct xwidget* xw, struct window *w);
118 Lisp_Object xwidget_spec_value ( Lisp_Object spec, Lisp_Object key, int *found);
119 gboolean offscreen_damage_event (GtkWidget *widget, GdkEvent *event, gpointer data);
120 void webkit_osr_document_load_finished_callback (WebKitWebView *webkitwebview,
121 WebKitWebFrame *arg1,
122 gpointer user_data);
123 gboolean webkit_osr_download_callback (WebKitWebView *webkitwebview,
124 WebKitDownload *arg1,
125 gpointer data);
127 gboolean webkit_osr_mime_type_policy_typedecision_requested_callback(WebKitWebView *webView,
128 WebKitWebFrame *frame,
129 WebKitNetworkRequest *request,
130 gchar *mimetype,
131 WebKitWebPolicyDecision *policy_decision,
132 gpointer user_data);
134 gboolean webkit_osr_new_window_policy_decision_requested_callback(WebKitWebView *webView,
135 WebKitWebFrame *frame,
136 WebKitNetworkRequest *request,
137 WebKitWebNavigationAction *navigation_action,
138 WebKitWebPolicyDecision *policy_decision,
139 gpointer user_data);
142 gboolean webkit_osr_navigation_policy_decision_requested_callback(WebKitWebView *webView,
143 WebKitWebFrame *frame,
144 WebKitNetworkRequest *request,
145 WebKitWebNavigationAction *navigation_action,
146 WebKitWebPolicyDecision *policy_decision,
147 gpointer user_data);
149 GtkWidget* xwgir_create(char* class, char* namespace);
153 static void
154 send_xembed_ready_event (struct xwidget* xw, int xembedid);
155 DEFUN ("make-xwidget", Fmake_xwidget, Smake_xwidget, 7, 8, 0,
156 doc: /* Make an xwidget from BEG to END of TYPE.
158 If BUFFER is nil it uses the current buffer. If BUFFER is a string and
159 no such buffer exists, it is created.
161 TYPE is a symbol which can take one of the following values:
162 - Button
163 - ToggleButton
164 - slider
165 - socket
166 - socket-osr
167 - cairo
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 data,
175 Lisp_Object buffer)
177 //should work a bit like "make-button"(make-button BEG END &rest PROPERTIES)
178 // arg "type" and fwd should be keyword args eventually
179 //(make-xwidget 3 3 'button "oei" 31 31 nil)
180 //(xwidget-info (car xwidget-list))
181 struct xwidget* xw = allocate_xwidget();
182 Lisp_Object val;
183 xw->type = type;
184 xw->title = title;
185 if (NILP (buffer))
186 buffer = Fcurrent_buffer(); // no need to gcpro because Fcurrent_buffer doesn't call Feval/eval_sub.
187 else
188 buffer = Fget_buffer_create (buffer);
189 xw->buffer = buffer;
191 xw->height = XFASTINT(height);
192 xw->width = XFASTINT(width);
193 xw->kill_without_query = 0;
194 XSETXWIDGET (val, xw); // set the vectorlike_header of VAL with the correct value
195 Vxwidget_list = Fcons (val, Vxwidget_list);
196 xw->widgetwindow_osr = NULL;
197 xw->widget_osr = NULL;
198 xw->plist = Qnil;
203 #ifdef HAVE_WEBKIT_OSR
204 /* DIY mvc. widget is rendered offscreen,
205 later bitmap copied to the views.
207 if (EQ(xw->type, Qwebkit_osr)||
208 EQ(xw->type, Qsocket_osr)||
209 (!NILP (Fget(xw->type, QCxwgir_class)))) {
210 block_input();
211 xw->widgetwindow_osr = gtk_offscreen_window_new ();
212 gtk_window_resize(GTK_WINDOW(xw->widgetwindow_osr), xw->width, xw->height);
213 xw->widgetscrolledwindow_osr = NULL; //webkit osr is the only scrolled component atm
215 if (EQ(xw->type, Qwebkit_osr)){
216 xw->widgetscrolledwindow_osr = gtk_scrolled_window_new(NULL, NULL);
217 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(xw->widgetscrolledwindow_osr ),xw->height);
218 gtk_scrolled_window_set_min_content_width(GTK_SCROLLED_WINDOW(xw->widgetscrolledwindow_osr ),xw->width);
219 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(xw->widgetscrolledwindow_osr ), GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS);
221 xw->widget_osr=webkit_web_view_new();
222 gtk_container_add(GTK_CONTAINER(xw->widgetscrolledwindow_osr ), GTK_WIDGET( WEBKIT_WEB_VIEW(xw->widget_osr)));
224 if(EQ(xw->type, Qsocket_osr))
225 xw->widget_osr = gtk_socket_new();
226 if(!NILP (Fget(xw->type, QCxwgir_class)))
227 xw->widget_osr = xwgir_create(SDATA(Fcar(Fcdr(Fget(xw->type, QCxwgir_class)))),
228 SDATA(Fcar(Fget(xw->type, QCxwgir_class))));
230 gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height);
232 if (EQ(xw->type, Qwebkit_osr)){
233 gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr), xw->widgetscrolledwindow_osr);
234 }else{
235 gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr), xw->widget_osr);
238 gtk_widget_show (xw->widget_osr);
239 gtk_widget_show (xw->widgetwindow_osr);
240 gtk_widget_show (xw->widgetscrolledwindow_osr);
242 /* store some xwidget data in the gtk widgets for convenient retrieval in the event handlers. */
243 g_object_set_data (G_OBJECT (xw->widget_osr), XG_XWIDGET, (gpointer) (xw));
244 g_object_set_data (G_OBJECT (xw->widgetwindow_osr), XG_XWIDGET, (gpointer) (xw));
246 /* signals */
247 if (EQ(xw->type, Qwebkit_osr)) {
248 g_signal_connect (G_OBJECT (xw->widget_osr),
249 "document-load-finished",
250 G_CALLBACK (webkit_osr_document_load_finished_callback),
251 xw);
253 g_signal_connect (G_OBJECT (xw->widget_osr),
254 "download-requested",
255 G_CALLBACK (webkit_osr_download_callback),
256 xw);
258 g_signal_connect (G_OBJECT (xw->widget_osr),
259 "mime-type-policy-decision-requested",
260 G_CALLBACK (webkit_osr_mime_type_policy_typedecision_requested_callback),
261 xw);
263 g_signal_connect (G_OBJECT (xw->widget_osr),
264 "new-window-policy-decision-requested",
265 G_CALLBACK (webkit_osr_new_window_policy_decision_requested_callback),
266 xw);
268 g_signal_connect (G_OBJECT (xw->widget_osr),
269 "navigation-policy-decision-requested",
270 G_CALLBACK (webkit_osr_navigation_policy_decision_requested_callback),
271 xw);
274 if (EQ(xw->type, Qsocket_osr)) {
275 send_xembed_ready_event (xw, gtk_socket_get_id (GTK_SOCKET (xw->widget_osr)));
276 //gtk_widget_realize(xw->widget);
280 unblock_input();
283 #endif /* HAVE_WEBKIT_OSR */
285 return val;
288 DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets, Sget_buffer_xwidgets, 1, 1, 0,
289 doc: /* Return a list of xwidgets associated with BUFFER.
290 BUFFER may be a buffer or the name of one.
293 (Lisp_Object buffer)
295 Lisp_Object xw, tail, xw_list;
297 if (NILP (buffer)) return Qnil;
298 buffer = Fget_buffer (buffer);
299 if (NILP (buffer)) return Qnil;
301 xw_list = Qnil;
303 for (tail = Vxwidget_list; CONSP (tail); tail = XCDR (tail))
305 xw = XCAR (tail);
306 if (XWIDGETP (xw) && EQ (Fxwidget_buffer (xw), buffer))
307 xw_list = Fcons (xw, xw_list);
309 return xw_list;
313 xwidget_hidden(struct xwidget_view *xv)
315 return xv->hidden;
319 static void
320 buttonclick_handler (GtkWidget * widget, gpointer data)
322 Lisp_Object xwidget_view, xwidget;
323 XSETXWIDGET_VIEW (xwidget_view, (struct xwidget_view *) data);
324 xwidget = Fxwidget_view_model (xwidget_view);
326 struct input_event event;
327 Lisp_Object frame = Fwindow_frame (Fxwidget_view_window (xwidget_view));
328 struct frame *f = XFRAME (frame);
329 printf ("button clicked xw:%d '%s'\n", XXWIDGET (xwidget), XXWIDGET (xwidget)->title);
331 EVENT_INIT (event);
332 event.kind = XWIDGET_EVENT;
334 event.frame_or_window = frame;
336 event.arg = Qnil;
337 event.arg = Fcons (xwidget, event.arg);
338 event.arg = Fcons (intern ("buttonclick"), event.arg);
340 kbd_buffer_store_event (&event);
344 static void
345 send_xembed_ready_event (struct xwidget* xw, int xembedid)
347 Lisp_Object xw_lo;
348 XSETXWIDGET(xw_lo, xw);
349 struct input_event event;
350 EVENT_INIT (event);
351 event.kind = XWIDGET_EVENT;
352 event.frame_or_window = Qnil; //frame; //how to get the frame here? //TODO i store it in the xwidget now
354 event.arg = Qnil;
355 event.arg = Fcons (make_number (xembedid), event.arg);
356 event.arg = Fcons (xw_lo, event.arg);
357 event.arg = Fcons (intern ("xembed-ready"), event.arg);
360 kbd_buffer_store_event (&event);
364 void
365 xwidget_show_view (struct xwidget_view *xv)
367 xv->hidden = 0;
368 gtk_widget_show(xv->widgetwindow);
369 gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow, xv->x + xv->clip_left, xv->y + xv->clip_top); //TODO refactor
373 /* hide an xvidget view */
374 void
375 xwidget_hide_view (struct xwidget_view *xv)
377 xv->hidden = 1;
378 //gtk_widget_hide(xw->widgetwindow);
379 gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow,
380 10000, 10000);
384 void
385 xwidget_plug_added(GtkSocket *socket,
386 gpointer user_data)
388 //hmm this doesnt seem to get called for foreign windows
389 printf("xwidget_plug_added\n");
392 gboolean
393 xwidget_plug_removed(GtkSocket *socket,
394 gpointer user_data)
396 printf("xwidget_plug_removed\n");
397 return TRUE; /* dont run the default handler because that kills the socket and we want to reuse it*/
401 void
402 xwidget_slider_changed (GtkRange *range,
403 gpointer user_data)
405 //slider value changed. change value of siblings
406 //correspondingly. but remember that changing value will again
407 //trigger signal
409 //TODO MVC view storage wont be an array futureish so the loop needs to change eventually
410 //TODO MVC it would be nice if this code could be reusable but, alas, C is not a functional language
411 //issues are:
412 // - the type of the controllers value (double, boolean etc)
413 // - the getter and setter (but they can be func pointers)
414 // a behemoth macro is always an option.
415 double v=gtk_range_get_value(range);
416 struct xwidget_view* xvp = g_object_get_data (G_OBJECT (range), XG_XWIDGET_VIEW);
417 struct xwidget_view* xv;
419 printf("slider changed val:%f\n", v);
421 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
423 if (XWIDGET_VIEW_P (XCAR (tail))) {
424 xv = XXWIDGET_VIEW (XCAR (tail));
425 if (EQ (xvp->model, xv->model)) {
426 //block sibling views signal handlers
427 g_signal_handler_block(xv->widget, xv->handler_id);
429 //set values of sibling views and unblock
430 gtk_range_set_value(GTK_RANGE(xv->widget), v);
431 g_signal_handler_unblock(xv->widget,xv->handler_id);
438 /* when the off-screen webkit master view changes this signal is called.
439 it copies the bitmap from the off-screen webkit instance */
440 gboolean
441 offscreen_damage_event (GtkWidget *widget, GdkEvent *event, gpointer data)
443 //TODO this is wrong! should just queu a redraw of onscreen widget
444 gtk_widget_queue_draw (GTK_WIDGET (data));
445 return FALSE;
448 void
449 store_xwidget_event_string(struct xwidget* xw, char* eventname, const char* eventstr)
451 //refactor attempt
452 struct input_event event;
453 Lisp_Object xwl;
454 XSETXWIDGET(xwl,xw);
455 EVENT_INIT (event);
456 event.kind = XWIDGET_EVENT;
457 event.frame_or_window = Qnil; //frame; //how to get the frame here? //TODO i store it in the xwidget now
459 event.arg = Qnil;
460 event.arg = Fcons (build_string(eventstr), event.arg); //string so dont intern
461 event.arg = Fcons (xwl, event.arg); //TODO
462 event.arg = Fcons (intern (eventname), event.arg);//interning should be ok
463 kbd_buffer_store_event (&event);
467 //TODO deprecated, use load-status
468 void
469 webkit_osr_document_load_finished_callback (WebKitWebView *webkitwebview,
470 WebKitWebFrame *arg1,
471 gpointer data)
473 //TODO this event sending code should be refactored
474 // struct xwidget *xw = (struct xwidget *) data;
475 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webkitwebview), XG_XWIDGET);
476 printf("webkit finished loading\n");
478 store_xwidget_event_string(xw,
479 "document-load-finished", "");
482 gboolean
483 webkit_osr_download_callback (WebKitWebView *webkitwebview,
484 WebKitDownload *arg1,
485 gpointer data)
487 //TODO this event sending code should be refactored
488 struct input_event event;
489 // struct xwidget *xw = (struct xwidget *) data;
490 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webkitwebview), XG_XWIDGET);
491 printf("download requested %s\n", webkit_download_get_uri (arg1));
494 printf("webkit finished loading\n");
496 store_xwidget_event_string(xw, "download-requested", webkit_download_get_uri (arg1));
498 return FALSE;
501 gboolean
502 webkit_osr_mime_type_policy_typedecision_requested_callback(WebKitWebView *webView,
503 WebKitWebFrame *frame,
504 WebKitNetworkRequest *request,
505 gchar *mimetype,
506 WebKitWebPolicyDecision *policy_decision,
507 gpointer user_data)
509 printf("mime policy requested\n");
510 // this function makes webkit send a download signal for all unknown mime types
511 // TODO defer the decision to lisp, so that its possible to make Emacs handle text mime for instance
512 if(!webkit_web_view_can_show_mime_type(webView, mimetype)){
513 webkit_web_policy_decision_download (policy_decision);
514 return TRUE;
515 }else{
516 return FALSE;
521 gboolean
522 webkit_osr_new_window_policy_decision_requested_callback(WebKitWebView *webView,
523 WebKitWebFrame *frame,
524 WebKitNetworkRequest *request,
525 WebKitWebNavigationAction *navigation_action,
526 WebKitWebPolicyDecision *policy_decision,
527 gpointer user_data)
529 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
530 printf("webkit_osr_new_window_policy_decision_requested_callback %s\n",
531 webkit_web_navigation_action_get_original_uri (navigation_action));
533 store_xwidget_event_string(xw, "new-window-policy-decision-requested", webkit_web_navigation_action_get_original_uri (navigation_action)
535 return FALSE;
538 gboolean
539 webkit_osr_navigation_policy_decision_requested_callback(WebKitWebView *webView,
540 WebKitWebFrame *frame,
541 WebKitNetworkRequest *request,
542 WebKitWebNavigationAction *navigation_action,
543 WebKitWebPolicyDecision *policy_decision,
544 gpointer user_data)
546 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
547 printf("webkit_osr_navigation_policy_decision_requested_callback %s\n",
548 webkit_web_navigation_action_get_original_uri (navigation_action));
549 store_xwidget_event_string(xw, "navigation-policy-decision-requested", webkit_web_navigation_action_get_original_uri (navigation_action)
551 return FALSE;
554 //for gtk3 offscreen rendered widgets
555 gboolean
556 xwidget_osr_draw_callback (GtkWidget *widget, cairo_t *cr, gpointer data)
558 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
559 struct xwidget_view* xv = (struct xwidget_view*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET_VIEW);
561 cairo_rectangle(cr, 0,0, xv->clip_right, xv->clip_bottom);//xw->width, xw->height);
562 cairo_clip(cr);
565 if(xw->widgetscrolledwindow_osr != NULL)
566 gtk_widget_draw (xw->widgetscrolledwindow_osr, cr);
567 else
568 gtk_widget_draw (xw->widget_osr, cr);
569 return FALSE;
572 GtkWidget* xwgir_create_debug;
576 gboolean
577 xwidget_osr_event_forward (GtkWidget *widget,
578 GdkEvent *event,
579 gpointer user_data)
581 /* copy events that arrive at the outer widget to the offscreen widget */
582 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
583 GdkEvent* eventcopy = gdk_event_copy(event);
584 eventcopy->any.window = gtk_widget_get_window(xw->widget_osr);// works
586 /* printf("xwidget_osr_event_forward redirect event to window:%d\n", ((GdkEventAny*)eventcopy)->window); */
587 /* printf("A type:%d x:%f y:%f \n", event->type, event->button.x, event->button.y); */
588 /* printf("B type:%d x:%f y:%f \n", eventcopy->type, eventcopy->button.x, eventcopy->button.y); */
589 //gtk_button_get_event_window(xwgir_create_debug);
590 gtk_main_do_event(eventcopy); //TODO this will leak events. they should be deallocated later, perhaps in xwgir_event_callback
591 return TRUE; //dont propagate this event furter
594 GIRepository *girepository ;
596 DEFUN ("xwgir-require-namespace", Fxwgir_require_namespace, Sxwgir_require_namespace, 2,2,0,
597 doc: /* Require a GObject Introspection namespace.
598 This must be done for all namespaces we want to use, before using other xwgir functions.*/)
599 (Lisp_Object lnamespace, Lisp_Object lnamespace_version)
601 char* namespace = SDATA(lnamespace);
602 char* namespace_version = SDATA(lnamespace_version);
603 GError *error = NULL;
605 girepository = g_irepository_get_default();
606 g_irepository_require(girepository, namespace, namespace_version, 0, &error);
607 if (error) {
608 g_error("ERROR: %s\n", error->message);
609 return Qnil;
611 return Qt;
614 GtkWidget* xwgir_create(char* class, char* namespace){
615 //TODO this is more or less the same as xwgir-call-method, so should be refactored
616 //create a gtk widget, given its name
617 //find the constructor
618 //call it
619 //also figure out how to pass args
621 GError *error = NULL;
622 GIArgument return_value;
624 GIObjectInfo* obj_info = g_irepository_find_by_name(girepository, namespace, class);
625 GIFunctionInfo* f_info = g_object_info_find_method (obj_info, "new");
626 g_function_info_invoke(f_info,
627 NULL, 0,
628 NULL, 0,
629 &return_value,
630 NULL);
631 xwgir_create_debug = return_value.v_pointer;
632 return return_value.v_pointer;
637 xwgir_convert_lisp_to_gir_arg(GIArgument* giarg,
638 GIArgInfo* arginfo,
639 Lisp_Object lisparg )
642 GITypeTag tag;
643 gboolean is_pointer;
644 gboolean is_enum;
645 tag = g_type_info_get_tag (g_arg_info_get_type (arginfo));
647 switch (tag)
649 case GI_TYPE_TAG_BOOLEAN:
650 giarg->v_boolean = XFASTINT(lisparg);
651 break;
652 case GI_TYPE_TAG_INT8:
653 giarg->v_int8 = XFASTINT(lisparg);
654 break;
655 case GI_TYPE_TAG_UINT8:
656 giarg->v_uint8 = XFASTINT(lisparg);
657 break;
658 case GI_TYPE_TAG_INT16:
659 giarg->v_int16 = XFASTINT(lisparg);
660 break;
661 case GI_TYPE_TAG_UINT16:
662 giarg->v_uint16 = XFASTINT(lisparg);
663 break;
664 case GI_TYPE_TAG_INT32:
665 giarg->v_int32 = XFASTINT(lisparg);
666 break;
667 case GI_TYPE_TAG_UINT32:
668 giarg->v_uint32 = XFASTINT(lisparg);
669 break;
671 case GI_TYPE_TAG_INT64:
672 giarg->v_int64 = XFASTINT(lisparg);
673 break;
674 case GI_TYPE_TAG_UINT64:
675 giarg->v_uint64 = XFASTINT(lisparg);
676 break;
679 case GI_TYPE_TAG_FLOAT:
680 giarg->v_float = XFLOAT_DATA(lisparg);
681 break;
683 case GI_TYPE_TAG_DOUBLE:
684 giarg->v_double = XFLOAT_DATA(lisparg);
685 break;
687 case GI_TYPE_TAG_UTF8:
688 case GI_TYPE_TAG_FILENAME:
689 //giarg->v_string = SDATA(lisparg);
690 giarg->v_pointer = SDATA(lisparg);
691 break;
693 case GI_TYPE_TAG_ARRAY:
694 case GI_TYPE_TAG_GLIST:
695 case GI_TYPE_TAG_GSLIST:
696 case GI_TYPE_TAG_GHASH:
697 case GI_TYPE_TAG_ERROR:
698 case GI_TYPE_TAG_INTERFACE:
699 case GI_TYPE_TAG_VOID:
700 case GI_TYPE_TAG_UNICHAR:
701 case GI_TYPE_TAG_GTYPE:
702 //?? i dont know how to handle these yet TODO
703 printf("failed in my lisp to gir arg conversion duties. sob!\n");
704 return -1;
705 break;
707 return 0;
710 #if 0
711 void
712 refactor_attempt(){
713 //this methhod should be called from xwgir-xwidget-call-method and from xwgir xwidget construction
714 char* class = SDATA(Fcar(Fcdr(Fget(xw->type, QCxwgir_class))));
716 GIObjectInfo* obj_info = g_irepository_find_by_name(girepository, namespace, class);
717 GIFunctionInfo* f_info = g_object_info_find_method (obj_info, SDATA(method));
719 //loop over args, convert from lisp to primitive type, given arg introspection data
720 //TODO g_callable_info_get_n_args(f_info) should match
721 int argscount = XFASTINT(Flength(arguments));
722 if(argscount != g_callable_info_get_n_args(f_info)){
723 printf("xwgir call method arg count doesn match! \n");
724 return Qnil;
726 int i;
727 for (i = 1; i < argscount + 1; ++i)
729 xwgir_convert_lisp_to_gir_arg(&in_args[i], g_callable_info_get_arg(f_info, i - 1), Fnth(i - 1, arguments));
732 in_args[0].v_pointer = widget;
733 if(g_function_info_invoke(f_info,
734 in_args, argscount + 1,
735 NULL, 0,
736 &return_value,
737 &error)) {
738 //g_error("ERROR: %s\n", error->message);
739 printf("invokation error\n");
740 return Qnil;
742 return Qt;
744 #endif /* 0 */
746 DEFUN ("xwgir-xwidget-call-method", Fxwgir_xwidget_call_method, Sxwgir_xwidget_call_method, 3, 3, 0,
747 doc: /* Call Xwidget object method using GObject Introspection.
748 XWIDGET is the xwidget instance to act upon.
749 METHOD is the Gobject intrsopsection method name.
750 ARGUMENTS is a list of arguments for the call. They will be converted to GObject types from Lisp types.
752 (Lisp_Object xwidget, Lisp_Object method, Lisp_Object arguments)
754 CHECK_XWIDGET (xwidget);
755 GError *error = NULL;
756 GIArgument return_value;
757 GIArgument in_args[20];
760 struct xwidget* xw;
761 if (NILP (xwidget)) { printf("ERROR xwidget nil\n"); return Qnil; };
762 xw = XXWIDGET(xwidget);
763 if(NULL == xw) printf("ERROR xw is 0\n");
764 char* namespace = SDATA(Fcar(Fget(xw->type, QCxwgir_class)));
765 //we need the concrete widget, which happens in 2 ways depending on OSR or not TODO
766 GtkWidget* widget = NULL;
767 if(NULL == xw->widget_osr) {
768 widget = xwidget_view_lookup (xw, XWINDOW(FRAME_SELECTED_WINDOW (SELECTED_FRAME ()))) -> widget;
769 } else {
770 widget = xw->widget_osr;
773 //char* class = SDATA(SYMBOL_NAME(xw->type)); //this works but is unflexible
774 //figure out the class from the widget instead
775 /* printf("type class: %s %s\n", G_OBJECT_TYPE_NAME(widget), G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(widget))); */
776 /* char* class = G_OBJECT_TYPE_NAME(widget); //gives "GtkButton"(I want "Button") */
777 /* class += strlen(namespace); //TODO check for corresponding api method. but this seems to work. */
779 char* class = SDATA(Fcar(Fcdr(Fget(xw->type, QCxwgir_class))));
781 GIObjectInfo* obj_info = g_irepository_find_by_name(girepository, namespace, class);
782 GIFunctionInfo* f_info = g_object_info_find_method (obj_info, SDATA(method));
784 //loop over args, convert from lisp to primitive type, given arg introspection data
785 //TODO g_callable_info_get_n_args(f_info) should match
786 int argscount = XFASTINT(Flength(arguments));
787 if(argscount != g_callable_info_get_n_args(f_info)){
788 printf("xwgir call method arg count doesn match! \n");
789 return Qnil;
791 int i;
792 Lisp_Object n;
793 for (i = 1; i < argscount + 1; ++i)
795 XSETFASTINT (n, i - 1);
796 xwgir_convert_lisp_to_gir_arg(&in_args[i], g_callable_info_get_arg(f_info, i - 1), Fnth(n, arguments));
799 in_args[0].v_pointer = widget;
800 if(g_function_info_invoke(f_info,
801 in_args, argscount + 1,
802 NULL, 0,
803 &return_value,
804 &error)) {
805 //g_error("ERROR: %s\n", error->message);
806 printf("invokation error\n");
807 return Qnil;
809 return Qt;
812 void
813 to_child (GtkWidget *bin,
814 double widget_x,
815 double widget_y,
816 double *x_out,
817 double *y_out)
819 *x_out = widget_x;
820 *y_out = widget_y;
824 GdkWindow *
825 offscreen_pick_embedded_child (GdkWindow *window,
826 double x,
827 double y,
828 gpointer *data)
830 //in this simple case we assume the window contains a single widget. easy.
831 //but then we get the problem that the widget cant be embedded in several windows
832 return gtk_widget_get_window (GTK_WIDGET (data));
835 void
836 offscreen_to_embedder (GdkWindow *window,
837 gdouble offscreen_x,
838 gdouble offscreen_y,
839 gpointer embedder_x,
840 gpointer embedder_y,
841 gpointer data)
843 * (gdouble *) embedder_x = offscreen_x;
844 * (gdouble *) embedder_y = offscreen_y;
847 void
848 offscreen_from_embedder (GdkWindow *window,
849 gdouble embedder_x,
850 gdouble embedder_y,
851 gpointer offscreen_x,
852 gpointer offscreen_y,
853 gpointer user_data)
855 * (gdouble *) offscreen_x = embedder_x;
856 * (gdouble *) offscreen_y = embedder_y;
859 gboolean
860 xwidget_osr_event_set_embedder (GtkWidget *widget,
861 GdkEvent *event,
862 gpointer data)
864 struct xwidget_view *xv = (struct xwidget_view *) data;
865 struct xwidget *xww = XXWIDGET (xv->model);
866 printf("gdk_offscreen_window_set_embedder %d %d\n",
867 GDK_IS_WINDOW(gtk_widget_get_window (xww->widget_osr)),
868 GDK_IS_WINDOW(gtk_widget_get_window (GTK_WIDGET (xv->widget))));
869 gdk_offscreen_window_set_embedder (gtk_widget_get_window (xww->widgetwindow_osr),
870 gtk_widget_get_window (xv->widget));
874 /* initializes and does initial placement of an xwidget view on screen */
875 struct xwidget_view*
876 xwidget_init_view (struct xwidget *xww,
877 struct glyph_string *s,
878 int x, int y)
880 struct xwidget_view *xv = allocate_xwidget_view();
881 Lisp_Object val;
882 GdkColor color;
884 XSETXWIDGET_VIEW (val, xv) ;
885 Vxwidget_view_list = Fcons (val, Vxwidget_view_list);
887 XSETWINDOW(xv->w, s->w);
888 XSETXWIDGET(xv->model, xww);
890 //widget creation
891 if(EQ(xww->type, Qbutton))
893 xv->widget = gtk_button_new_with_label (XSTRING(xww->title)->data);
894 g_signal_connect (G_OBJECT (xv->widget), "clicked",
895 G_CALLBACK (buttonclick_handler), xv); // the view rather than the model
896 } else if (EQ(xww->type, Qtoggle)) {
897 xv->widget = gtk_toggle_button_new_with_label (XSTRING(xww->title)->data);
898 //xv->widget = gtk_entry_new ();//temp hack to experiment with key propagation TODO entry widget is useful for testing
899 } else if (EQ(xww->type, Qsocket)) {
900 xv->widget = gtk_socket_new ();
901 g_signal_connect_after(xv->widget, "plug-added", G_CALLBACK(xwidget_plug_added), "plug added");
902 g_signal_connect_after(xv->widget, "plug-removed", G_CALLBACK(xwidget_plug_removed), "plug removed");
903 //TODO these doesnt help
904 gtk_widget_add_events(xv->widget, GDK_KEY_PRESS);
905 gtk_widget_add_events(xv->widget, GDK_KEY_RELEASE);
906 } else if (EQ(xww->type, Qslider)) {
907 xv->widget =
908 //gtk_hscale_new (GTK_ADJUSTMENT(gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 10.0, 10.0)));
909 gtk_hscale_new_with_range ( 0.0, 100.0, 10.0);
910 gtk_scale_set_draw_value (GTK_SCALE (xv->widget), FALSE); //i think its emacs role to show text and stuff, so disable the widgets own text
911 xv->handler_id = g_signal_connect_after(xv->widget, "value-changed", G_CALLBACK(xwidget_slider_changed), "slider changed");
912 } else if (EQ(xww->type, Qcairo)) {
913 //Cairo view
914 //uhm cairo is differentish in gtk 3.
915 //gdk_cairo_create (gtk_widget_get_window (FRAME_GTK_WIDGET (s->f)));
916 xv->widget = gtk_drawing_area_new();
917 g_signal_connect (G_OBJECT ( xv->widget), "draw",
918 G_CALLBACK (xwidget_osr_draw_callback), NULL);
920 } else if (EQ(xww->type, Qwebkit_osr)||
921 EQ(xww->type, Qsocket_osr)||
922 (!NILP (Fget(xww->type, QCxwgir_class))))//xwgir widgets are OSR
924 printf("osr init:%s\n",SDATA(SYMBOL_NAME(xww->type)));
925 xv->widget = gtk_drawing_area_new();
926 gtk_widget_set_app_paintable ( xv->widget, TRUE); //because expose event handling
927 gtk_widget_add_events(xv->widget, GDK_ALL_EVENTS_MASK);
929 /* Draw the view on damage-event */
930 g_signal_connect (G_OBJECT (xww->widgetwindow_osr), "damage-event",
931 G_CALLBACK (offscreen_damage_event), xv->widget);
933 if (EQ(xww->type, Qwebkit_osr)){
934 /* ///xwgir debug */
935 /* //forward events. this isnt compatible with the set_embedded strategy */
936 g_signal_connect (G_OBJECT ( xv->widget), "button-press-event",
937 G_CALLBACK (xwidget_osr_event_forward), NULL);
938 g_signal_connect (G_OBJECT ( xv->widget), "button-release-event",
939 G_CALLBACK (xwidget_osr_event_forward), NULL);
940 g_signal_connect (G_OBJECT ( xv->widget), "motion-notify-event",
941 G_CALLBACK (xwidget_osr_event_forward), NULL);
942 }else{
943 //xwgir debug , orthogonal to forwarding
944 g_signal_connect (G_OBJECT (xv->widget), "enter-notify-event",
945 G_CALLBACK (xwidget_osr_event_set_embedder), xv);
948 //draw
949 g_signal_connect (G_OBJECT (xv->widget), "draw",
950 G_CALLBACK (xwidget_osr_draw_callback), NULL);
953 //else return NULL;
955 //widget realization
956 //make container widget 1st, and put the actual widget inside the container
957 //later, drawing should crop container window if necessary to handle case where xwidget
958 //is partially obscured by other emacs windows
959 //other containers than gtk_fixed where explored, but gtk_fixed had the most predictable behaviour so far.
960 xv->emacswindow = FRAME_GTK_WIDGET (s->f);
961 xv->widgetwindow = gtk_fixed_new ();
962 gtk_widget_set_has_window(xv->widgetwindow, TRUE);
963 gtk_container_add (GTK_CONTAINER (xv->widgetwindow), xv->widget);
965 //store some xwidget data in the gtk widgets
966 g_object_set_data (G_OBJECT (xv->widget), XG_FRAME_DATA, (gpointer) (s->f)); //the emacs frame
967 g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET, (gpointer) (xww)); //the xwidget
968 g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET_VIEW, (gpointer) (xv)); //the xwidget
969 g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET, (gpointer) (xww)); //the xwidget window
970 g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET_VIEW, (gpointer) (xv)); //the xwidget window
973 gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xww->width, xww->height);
974 gtk_widget_set_size_request (xv->widgetwindow, xww->width, xww->height);
975 gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), xv->widgetwindow, x, y);
976 xv->x = x; xv->y = y;
977 gtk_widget_show_all (xv->widgetwindow);
981 //widgettype specific initialization only possible after realization
982 if (EQ(xww->type, Qsocket)) {
983 printf ("xwid:%d socket id:%x %d\n",
984 xww,
985 gtk_socket_get_id (GTK_SOCKET (xv->widget)),
986 gtk_socket_get_id (GTK_SOCKET (xv->widget)));
987 send_xembed_ready_event (xww,
988 gtk_socket_get_id (GTK_SOCKET (xv->widget)));
989 //gtk_widget_realize(xw->widget);
992 //////////////////////////////////////////////////////////////
993 // xwgir debug
994 if (//EQ(xww->type, Qwebkit_osr)|| //TODO should be able to choose compile time which method to use with webkit
995 EQ(xww->type, Qsocket_osr)||
996 (!NILP (Fget(xww->type, QCxwgir_class))))//xwgir widgets are OSR
998 printf("gdk_offscreen_window_set_embedder %d %d\n",
999 GDK_IS_WINDOW(gtk_widget_get_window (xww->widget_osr)),
1000 GDK_IS_WINDOW(gtk_widget_get_window (GTK_WIDGET (xv->widget))));
1001 // set_embedder needs to be called after xv->widget realization
1002 gdk_offscreen_window_set_embedder (gtk_widget_get_window (xww->widgetwindow_osr),
1003 gtk_widget_get_window (xv->widget));
1004 g_signal_connect (gtk_widget_get_window (xv->widget), "pick-embedded-child",
1005 G_CALLBACK (offscreen_pick_embedded_child), xww->widgetwindow_osr);
1007 g_signal_connect (gtk_widget_get_window (xww->widgetwindow_osr), "from-embedder",
1008 G_CALLBACK (offscreen_from_embedder), NULL);
1009 g_signal_connect (gtk_widget_get_window (xww->widgetwindow_osr), "to-embedder",
1010 G_CALLBACK (offscreen_to_embedder), NULL);
1012 ////////////////////////////////////////
1014 return xv;
1018 void
1019 x_draw_xwidget_glyph_string (struct glyph_string *s)
1022 this method is called by the redisplay engine and places the xwidget on screen.
1023 moving and clipping is done here. also view init.
1026 int box_line_hwidth = eabs (s->face->box_line_width);
1027 int box_line_vwidth = max (s->face->box_line_width, 0);
1028 int height = s->height;
1029 struct xwidget *xww = s->xwidget;
1030 struct xwidget_view *xv = xwidget_view_lookup(xww, s->w);
1031 int clip_right; int clip_bottom; int clip_top; int clip_left;
1033 int x = s->x;
1034 int y = s->y + (s->height / 2) - (xww->height / 2);
1035 int moved=0;
1037 /* We do it here in the display loop because there is no other
1038 time to know things like window placement etc.
1040 printf ("xv init for xw %d\n", xww);
1041 xv = xwidget_init_view (xww, s, x, y);
1043 //calculate clipping, which is used for all manner of onscreen xwidget views
1044 //each widget border can get clipped by other emacs objects so there are four clipping variables
1045 clip_right = min (xww->width, WINDOW_RIGHT_EDGE_X (s->w) - x - WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH(s->w) - WINDOW_RIGHT_FRINGE_WIDTH(s->w));
1046 clip_left = max (0, WINDOW_LEFT_EDGE_X (s->w) - x + WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH(s->w) + WINDOW_LEFT_FRINGE_WIDTH(s->w));
1048 clip_bottom = min (xww->height, WINDOW_BOTTOM_EDGE_Y (s->w) - WINDOW_MODE_LINE_HEIGHT (s->w) - y);
1049 clip_top = max(0, WINDOW_TOP_EDGE_Y(s->w) -y );
1051 //we are conserned with movement of the onscreen area. the area might sit still when the widget actually moves
1052 //this happens when an emacs window border moves across a widget window
1053 //so, if any corner of the outer widget clippng window moves, that counts as movement here, even
1054 //if it looks like no movement happens because the widget sits still inside the clipping area.
1055 //the widget can also move inside the clipping area, which happens later
1056 moved = (xv->x + xv->clip_left != x+clip_left)
1057 || ((xv->y + xv->clip_top)!= (y+clip_top));
1058 xv->x = x;
1059 xv->y = y;
1060 if (moved) //has it moved?
1062 if (1)//!xwidget_hidden(xv)) //hidden equals not being seen during redisplay
1064 //TODO should be possible to use xwidget_show_view here
1065 gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)),
1066 xv->widgetwindow,
1067 x + clip_left, y + clip_top);
1070 //clip the widget window if some parts happen to be outside drawable area
1071 //an emacs window is not a gtk window, a gtk window covers the entire frame
1072 //cliping might have changed even if we havent actualy moved, we try figure out when we need to reclip for real
1073 if((xv->clip_right != clip_right)
1074 || (xv->clip_bottom != clip_bottom)
1075 || (xv->clip_top != clip_top)
1076 || (xv->clip_left != clip_left)){
1077 gtk_widget_set_size_request (xv->widgetwindow, clip_right + clip_left, clip_bottom + clip_top);
1078 gtk_fixed_move(GTK_FIXED(xv->widgetwindow), xv->widget, -clip_left, -clip_top);
1080 xv->clip_right = clip_right; xv->clip_bottom = clip_bottom; xv->clip_top = clip_top;xv->clip_left = clip_left;
1082 //if emacs wants to repaint the area where the widget lives, queue a redraw
1083 //TODO it seems its possible to get out of sync with emacs redraws so emacs bg sometimes shows up instead of xwidget
1084 //its just a visual glitch though
1085 if (!xwidget_hidden(xv)){
1086 gtk_widget_queue_draw (xv->widgetwindow);
1087 gtk_widget_queue_draw (xv->widget);
1092 #ifdef HAVE_WEBKIT_OSR
1094 //FUGLY macro that checks WEBKIT_IS_WEB_VIEW(xw->widget_osr) first
1095 #define WEBKIT_FN_INIT() \
1096 struct xwidget* xw; \
1097 CHECK_XWIDGET (xwidget); \
1098 if(NILP (xwidget)) {printf("ERROR xwidget nil\n"); return Qnil;}; \
1099 xw = XXWIDGET(xwidget); \
1100 if(NULL == xw) printf("ERROR xw is 0\n"); \
1101 if((NULL == xw->widget_osr) || !WEBKIT_IS_WEB_VIEW(xw->widget_osr)){ \
1102 printf("ERROR xw->widget_osr does not hold a webkit instance\n");\
1103 return Qnil;\
1107 DEFUN ("xwidget-webkit-goto-uri", Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri,
1108 2, 2, 0,
1109 doc: /* Make the webkit instance referenced by XWIDGET browse URI. */)
1110 (Lisp_Object xwidget, Lisp_Object uri)
1112 WEBKIT_FN_INIT();
1113 CHECK_STRING(uri);
1114 webkit_web_view_load_uri ( WEBKIT_WEB_VIEW(xw->widget_osr), SDATA(uri));
1115 return Qnil;
1119 DEFUN ("xwidget-webkit-execute-script", Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script,
1120 2, 2, 0,
1121 doc: /* webkit exec js.*/)
1122 (Lisp_Object xwidget, Lisp_Object script)
1124 WEBKIT_FN_INIT();
1125 CHECK_STRING(script);
1126 webkit_web_view_execute_script( WEBKIT_WEB_VIEW(xw->widget_osr), SDATA(script));
1127 return Qnil;
1130 DEFUN ("xwidget-webkit-get-title", Fxwidget_webkit_get_title, Sxwidget_webkit_get_title,
1131 1, 1, 0,
1132 doc: /* Get the title from the Webkit instance in XWIDGET.
1133 This can be used to work around the lack of a return value from the exec method.
1135 (Lisp_Object xwidget)
1137 //TODO support multibyte strings
1138 WEBKIT_FN_INIT();
1139 const gchar* str=webkit_web_view_get_title( WEBKIT_WEB_VIEW(xw->widget_osr));
1140 //return make_string_from_bytes(str, wcslen((const wchar_t *)str), strlen(str));
1141 if(str == 0){
1142 //TODO maybe return Qnil instead. I suppose webkit returns nullpointer when doc is not properly loaded or something
1143 printf("xwidget-webkit-get-title null webkit title\n");
1144 return build_string("");
1146 return build_string(str);
1149 //TODO missnamed
1150 DEFUN ("xwidget-disable-plugin-for-mime", Fxwidget_disable_plugin_for_mime , Sxwidget_disable_plugin_for_mime,
1151 1,1,0, doc: /* */)
1152 (Lisp_Object mime)
1154 WebKitWebPlugin *wp = webkit_web_plugin_database_get_plugin_for_mimetype
1155 (webkit_get_web_plugin_database(), SDATA(mime));
1156 if(wp == NULL) return Qnil;
1157 if(webkit_web_plugin_get_enabled (wp)){
1158 webkit_web_plugin_set_enabled (wp, FALSE);
1159 return Qt;
1161 return Qnil;
1165 void
1166 xwidget_webkit_dom_dump(WebKitDOMNode* parent)
1168 WebKitDOMNodeList* list;
1169 int i;
1170 int length;
1171 WebKitDOMNode* attribute;
1172 WebKitDOMNamedNodeMap* attrs;
1173 WebKitDOMNode* child;
1174 printf("node:%d type:%d name:%s content:%s\n",
1175 parent,
1176 webkit_dom_node_get_node_type(parent),//1 element 3 text 8 comment 2 attribute
1177 webkit_dom_node_get_local_name(parent),
1178 webkit_dom_node_get_text_content(parent));
1180 if(webkit_dom_node_has_attributes(parent)){
1181 attrs = webkit_dom_node_get_attributes(parent);
1183 length = webkit_dom_named_node_map_get_length(attrs);
1184 for (int i = 0; i < length; i++) {
1185 attribute = webkit_dom_named_node_map_item(attrs,i);
1186 printf(" attr node:%d type:%d name:%s content:%s\n",
1187 attribute,
1188 webkit_dom_node_get_node_type(attribute),//1 element 3 text 8 comment
1189 webkit_dom_node_get_local_name(attribute),
1190 webkit_dom_node_get_text_content(attribute));
1193 list = webkit_dom_node_get_child_nodes(parent);
1194 length = webkit_dom_node_list_get_length(list);
1196 for (int i = 0; i < length; i++) {
1197 child = webkit_dom_node_list_item(list, i);
1198 //if(webkit_dom_node_has_child_nodes(child))
1199 xwidget_webkit_dom_dump(child);
1204 DEFUN ("xwidget-webkit-dom-dump", Fxwidget_webkit_dom_dump, Sxwidget_webkit_dom_dump,
1205 1, 1, 0,
1206 doc: /*Dump the DOM contained in the webkit instance in XWIDGET.*/)
1207 (Lisp_Object xwidget)
1209 WEBKIT_FN_INIT();
1210 xwidget_webkit_dom_dump(WEBKIT_DOM_NODE(webkit_web_view_get_dom_document( WEBKIT_WEB_VIEW(xw->widget_osr))));
1211 return Qnil;
1216 #endif /* HAVE_WEBKIT_OSR */
1220 DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0, doc:
1221 /* Resize XWIDGET.
1222 NEW_WIDTH NEW_HEIGHT defines the new size.)
1224 (Lisp_Object xwidget, Lisp_Object new_width, Lisp_Object new_height)
1226 CHECK_XWIDGET (xwidget);
1227 struct xwidget* xw = XXWIDGET(xwidget);
1228 struct xwidget_view *xv;
1229 int w, h;
1231 CHECK_NUMBER (new_width);
1232 CHECK_NUMBER (new_height);
1233 w = XFASTINT (new_width);
1234 h = XFASTINT (new_height);
1237 printf("resize xwidget %d (%d,%d)->(%d,%d)\n",xw, xw->width,xw->height,w,h);
1238 xw->width=w;
1239 xw->height=h;
1240 //if theres a osr resize it 1st
1241 if(xw->widget_osr){
1242 printf("resize xwidget_osr\n");
1243 //gtk_container_set_resize_mode ( GTK_WINDOW(xw->widgetwindow_osr), GTK_RESIZE_QUEUE);
1244 //gtk_container_set_resize_mode ( GTK_WINDOW(xw->widget_osr), GTK_RESIZE_QUEUE);
1247 //gtk_layout_set_size (GTK_LAYOUT (xw->widgetwindow_osr), xw->width, xw->height);
1248 gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height); //minimum size
1249 //gtk_window_resize( GTK_WINDOW(xw->widget_osr), xw->width, xw->height);
1250 gtk_window_resize( GTK_WINDOW(xw->widgetwindow_osr), xw->width, xw->height);
1251 gtk_window_resize( GTK_WINDOW(xw->widgetscrolledwindow_osr), xw->width, xw->height);
1252 gtk_scrolled_window_set_min_content_height(GTK_SCROLLED_WINDOW(xw->widgetscrolledwindow_osr ),xw->height);
1253 gtk_scrolled_window_set_min_content_width(GTK_SCROLLED_WINDOW(xw->widgetscrolledwindow_osr ),xw->width);
1255 //gtk_container_resize_children ( GTK_WINDOW(xw->widgetwindow_osr));
1256 gtk_container_resize_children (GTK_CONTAINER(xw->widgetwindow_osr));
1260 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail)) //TODO MVC refactor lazy linear search
1262 if (XWIDGET_VIEW_P (XCAR (tail))) {
1263 xv = XXWIDGET_VIEW (XCAR (tail));
1264 if(XXWIDGET (xv->model) == xw) {
1265 gtk_layout_set_size (GTK_LAYOUT (xv->widgetwindow), xw->width, xw->height);
1266 gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width, xw->height);
1271 return Qnil;
1276 DEFUN ("xwidget-set-adjustment", Fxwidget_set_adjustment, Sxwidget_set_adjustment, 4, 4, 0, doc:
1277 /* set scrolling */)
1278 (Lisp_Object xwidget, Lisp_Object axis, Lisp_Object relative, Lisp_Object value)
1280 CHECK_XWIDGET (xwidget);
1281 struct xwidget* xw = XXWIDGET(xwidget);
1282 GtkAdjustment* adjustment;
1283 float final_value=0.0;
1285 if(EQ(Qvertical, axis)){
1286 adjustment = gtk_scrolled_window_get_vadjustment(GTK_SCROLLED_WINDOW(xw->widgetscrolledwindow_osr));
1288 if(EQ(Qhorizontal, axis)){
1289 adjustment = gtk_scrolled_window_get_hadjustment(GTK_SCROLLED_WINDOW(xw->widgetscrolledwindow_osr));
1292 if(EQ(Qt, relative)){
1293 final_value=gtk_adjustment_get_value(adjustment)+XFASTINT(value);
1294 }else{
1295 final_value=0.0+XFASTINT(value);
1298 gtk_adjustment_set_value(adjustment, final_value);
1300 return Qnil;
1304 DEFUN ("xwidget-size-request", Fxwidget_size_request, Sxwidget_size_request, 1, 1, 0, doc:
1305 /* Desired size of the XWIDGET.
1307 This can be used to read the xwidget desired size, and resizes the Emacs allocated area accordingly.
1309 (TODO crashes if arg not osr widget)*/)
1310 (Lisp_Object xwidget)
1312 CHECK_XWIDGET (xwidget);
1313 GtkRequisition requisition;
1314 Lisp_Object rv;
1315 gtk_widget_size_request(XXWIDGET(xwidget)->widget_osr, &requisition);
1316 rv = Qnil;
1317 rv = Fcons (make_number(requisition.height), rv);
1318 rv = Fcons (make_number(requisition.width), rv);
1319 return rv;
1323 DEFUN ("xwidgetp", Fxwidgetp, Sxwidgetp, 1, 1, 0,
1324 doc: /* Return t if OBJECT is a xwidget. */)
1325 (Lisp_Object object)
1327 return XWIDGETP (object) ? Qt : Qnil;
1330 DEFUN ("xwidget-view-p", Fxwidget_view_p, Sxwidget_view_p, 1, 1, 0,
1331 doc: /* Return t if OBJECT is a xwidget-view. */)
1332 (Lisp_Object object)
1334 return XWIDGET_VIEW_P (object) ? Qt : Qnil;
1337 DEFUN ("xwidget-info", Fxwidget_info , Sxwidget_info, 1,1,0,
1338 doc: /* Get XWIDGET properties.
1339 Currently type, title, width, height.*/)
1340 (Lisp_Object xwidget)
1342 CHECK_XWIDGET (xwidget);
1343 Lisp_Object info, n;
1344 struct xwidget* xw = XXWIDGET(xwidget);
1346 info = Fmake_vector (make_number (4), Qnil);
1347 ASET (info, 0, xw->type);
1348 ASET (info, 1, xw->title);
1349 XSETFASTINT(n, xw->width);
1350 ASET (info, 2, n);
1351 XSETFASTINT(n, xw->height);
1352 ASET (info, 3, n);
1354 return info;
1357 DEFUN ("xwidget-view-info", Fxwidget_view_info , Sxwidget_view_info, 1, 1, 0, doc:
1358 /* Get XWIDGET-VIEW properties.
1359 Currently x,y clip right, clip bottom, clip top, clip left*/)
1360 (Lisp_Object xwidget_view)
1362 CHECK_XWIDGET_VIEW (xwidget_view);
1363 struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
1364 Lisp_Object info;
1366 info = Fmake_vector (make_number (6), Qnil);
1367 ASET (info, 0, make_number(xv->x));
1368 ASET (info, 1, make_number(xv->y));
1369 ASET (info, 2, make_number(xv->clip_right));
1370 ASET (info, 3, make_number(xv->clip_bottom));
1371 ASET (info, 4, make_number(xv->clip_top));
1372 ASET (info, 5, make_number(xv->clip_left));
1374 return info;
1377 DEFUN ("xwidget-view-model", Fxwidget_view_model, Sxwidget_view_model,
1378 1, 1, 0,
1379 doc: /* Get XWIDGET-VIEW model. */)
1380 (Lisp_Object xwidget_view)
1382 CHECK_XWIDGET_VIEW (xwidget_view);
1383 return XXWIDGET_VIEW (xwidget_view)->model;
1386 DEFUN ("xwidget-view-window", Fxwidget_view_window, Sxwidget_view_window,
1387 1, 1, 0,
1388 doc: /* Get XWIDGET-VIEW window. */)
1389 (Lisp_Object xwidget_view)
1391 CHECK_XWIDGET_VIEW (xwidget_view);
1392 return XXWIDGET_VIEW (xwidget_view)->w;
1395 DEFUN ("xwidget-send-keyboard-event", Fxwidget_send_keyboard_event, Sxwidget_send_keyboard_event, 2, 2, 0,
1396 doc:/* Synthesize a kbd event for XWIDGET. TODO crashes atm.. */
1398 (Lisp_Object xwidget, Lisp_Object keydescriptor)
1400 //TODO this code crashes for offscreen widgets and ive tried many different strategies
1401 //int keyval = 0x058; //X
1402 int keyval = XFASTINT(keydescriptor); //X
1403 char *keystring = "";
1404 GdkKeymapKey* keys;
1405 gint n_keys;
1406 GdkDeviceManager* manager;
1407 struct xwidget *xw;
1408 GtkWidget* widget;
1409 GdkEventKey* ev;
1410 Lisp_Object window;
1411 //popup_activated_flag = 1; //TODO just a hack
1412 gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), keyval, &keys, &n_keys);
1414 xw = XXWIDGET(xwidget);
1416 ev = (GdkEventKey*)gdk_event_new(GDK_KEY_PRESS);
1419 //todo what about windowless widgets?
1421 window = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
1424 //TODO maybe we also need to special case sockets by picking up the plug rather than the socket
1425 if(xw->widget_osr)
1426 widget = xw->widget_osr;
1427 else
1428 widget = xwidget_view_lookup(xw, XWINDOW(window))->widget;
1430 ev->window = gtk_widget_get_window(widget);
1431 gtk_widget_grab_focus(widget);
1432 ev->send_event = FALSE;
1434 ev->hardware_keycode = keys[0].keycode;
1435 ev->group = keys[0].group;
1437 ev->keyval = keyval;
1438 ev->time = GDK_CURRENT_TIME;
1440 //ev->device = gdk_device_get_core_pointer();
1441 manager = gdk_display_get_device_manager(gdk_window_get_display(ev->window));
1442 gdk_event_set_device ((GdkEvent*)ev, gdk_device_manager_get_client_pointer(manager));
1443 gdk_event_put((GdkEvent*)ev);
1444 //g_signal_emit_by_name(ev->window,"key-press-event", ev);
1446 ev->type = GDK_KEY_RELEASE;
1447 gdk_event_put((GdkEvent*)ev);
1448 //g_signal_emit_by_name(ev->window,"key-release-event", ev);
1449 //gtk_main_do_event(ev);
1451 //TODO
1452 //if I delete the event the receiving component eventually crashes.
1453 //it ough TDTRT since event_put is supposed to copy the event
1454 //so probably this leaks events now
1455 //gdk_event_free((GdkEvent*)ev);
1457 return Qnil;
1460 DEFUN ("delete-xwidget-view", Fdelete_xwidget_view, Sdelete_xwidget_view,
1461 1, 1, 0,
1462 doc: /* Delete the XWIDGET-VIEW. */)
1463 (Lisp_Object xwidget_view)
1465 CHECK_XWIDGET_VIEW (xwidget_view);
1466 struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
1467 gtk_widget_destroy(xv->widgetwindow);
1468 Vxwidget_view_list = Fdelq (xwidget_view, Vxwidget_view_list);
1471 DEFUN ("xwidget-view-lookup", Fxwidget_view_lookup, Sxwidget_view_lookup,
1472 1, 2, 0,
1473 doc: /* Return the xwidget-view associated to XWIDGET in
1474 WINDOW if specified, otherwise it uses the selected window. */)
1475 (Lisp_Object xwidget, Lisp_Object window)
1477 CHECK_XWIDGET (xwidget);
1479 if (NILP (window))
1480 window = Fselected_window();
1481 CHECK_WINDOW (window);
1483 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
1485 Lisp_Object xwidget_view = XCAR (tail);
1486 if (EQ (Fxwidget_view_model (xwidget_view), xwidget)
1487 && EQ (Fxwidget_view_window (xwidget_view), window))
1488 return xwidget_view;
1491 return Qnil;
1494 DEFUN ("set-frame-visible", Fset_frame_visible, Sset_frame_visible,
1495 2, 2, 0,
1496 doc: /* HACKY */)
1497 (Lisp_Object frame, Lisp_Object flag)
1499 CHECK_FRAME (frame);
1500 struct frame *f = XFRAME (frame);
1501 SET_FRAME_VISIBLE (f, !NILP (flag));
1502 return flag;
1505 DEFUN ("xwidget-plist", Fxwidget_plist, Sxwidget_plist,
1506 1, 1, 0,
1507 doc: /* Return the plist of XWIDGET. */)
1508 (register Lisp_Object xwidget)
1510 CHECK_XWIDGET (xwidget);
1511 return XXWIDGET (xwidget)->plist;
1514 DEFUN ("xwidget-buffer", Fxwidget_buffer, Sxwidget_buffer,
1515 1, 1, 0,
1516 doc: /* Return the buffer of XWIDGET. */)
1517 (register Lisp_Object xwidget)
1519 CHECK_XWIDGET (xwidget);
1520 return XXWIDGET (xwidget)->buffer;
1523 DEFUN ("set-xwidget-plist", Fset_xwidget_plist, Sset_xwidget_plist,
1524 2, 2, 0,
1525 doc: /* Replace the plist of XWIDGET with PLIST. Returns PLIST. */)
1526 (register Lisp_Object xwidget, Lisp_Object plist)
1528 CHECK_XWIDGET (xwidget);
1529 CHECK_LIST (plist);
1531 XXWIDGET (xwidget)->plist = plist;
1532 return plist;
1535 DEFUN ("set-xwidget-query-on-exit-flag",
1536 Fset_xwidget_query_on_exit_flag, Sset_xwidget_query_on_exit_flag,
1537 2, 2, 0,
1538 doc: /* Specify if query is needed for XWIDGET when Emacs is
1539 exited. If the second argument FLAG is non-nil, Emacs will query the
1540 user before exiting or killing a buffer if XWIDGET is running. This
1541 function returns FLAG. */)
1542 (Lisp_Object xwidget, Lisp_Object flag)
1544 CHECK_XWIDGET (xwidget);
1545 XXWIDGET (xwidget)->kill_without_query = NILP (flag);
1546 return flag;
1549 DEFUN ("xwidget-query-on-exit-flag",
1550 Fxwidget_query_on_exit_flag, Sxwidget_query_on_exit_flag,
1551 1, 1, 0,
1552 doc: /* Return the current value of query-on-exit flag for XWIDGET. */)
1553 (Lisp_Object xwidget)
1555 CHECK_XWIDGET (xwidget);
1556 return (XXWIDGET (xwidget)->kill_without_query ? Qnil : Qt);
1559 void
1560 syms_of_xwidget (void)
1562 int i;
1564 defsubr (&Smake_xwidget);
1565 defsubr (&Sxwidgetp);
1566 DEFSYM (Qxwidgetp, "xwidgetp");
1567 defsubr (&Sxwidget_view_p);
1568 DEFSYM (Qxwidget_view_p, "xwidget-view-p");
1569 defsubr (&Sxwidget_info);
1570 defsubr (&Sxwidget_view_info);
1571 defsubr (&Sxwidget_resize);
1572 defsubr (&Sget_buffer_xwidgets);
1573 defsubr (&Sxwidget_view_model);
1574 defsubr (&Sxwidget_view_window);
1575 defsubr (&Sxwidget_view_lookup);
1576 defsubr (&Sxwidget_query_on_exit_flag);
1577 defsubr (&Sset_xwidget_query_on_exit_flag);
1578 defsubr (&Sset_frame_visible);
1580 #ifdef HAVE_WEBKIT_OSR
1581 defsubr (&Sxwidget_webkit_goto_uri);
1582 defsubr (&Sxwidget_webkit_execute_script);
1583 defsubr (&Sxwidget_webkit_get_title);
1584 DEFSYM (Qwebkit_osr, "webkit-osr");
1585 #endif
1587 defsubr (&Sxwgir_xwidget_call_method );
1588 defsubr (&Sxwgir_require_namespace);
1589 defsubr (&Sxwidget_size_request );
1590 defsubr (&Sdelete_xwidget_view);
1591 defsubr (&Sxwidget_disable_plugin_for_mime);
1593 defsubr (&Sxwidget_send_keyboard_event);
1594 defsubr (&Sxwidget_webkit_dom_dump);
1595 defsubr (&Sxwidget_plist);
1596 defsubr (&Sxwidget_buffer);
1597 defsubr (&Sset_xwidget_plist);
1599 defsubr (&Sxwidget_set_adjustment);
1601 DEFSYM (Qxwidget, "xwidget");
1603 DEFSYM (QCxwidget, ":xwidget");
1604 DEFSYM (QCxwgir_class, ":xwgir-class");
1605 DEFSYM (QCtitle, ":title");
1607 /* Do not forget to update the docstring of make-xwidget if you add
1608 new types. */
1609 DEFSYM (Qbutton, "Button"); //changed to match the gtk class because xwgir(experimental and not really needed)
1610 DEFSYM (Qtoggle, "ToggleButton");
1611 DEFSYM (Qslider, "slider");
1612 DEFSYM (Qsocket, "socket");
1613 DEFSYM (Qsocket_osr, "socket-osr");
1614 DEFSYM (Qcairo, "cairo");
1616 DEFSYM (Qvertical, "vertical");
1617 DEFSYM (Qhorizontal, "horizontal");
1619 DEFSYM (QCplist, ":plist");
1621 DEFVAR_LISP ("xwidget-list", Vxwidget_list, doc: /*xwidgets list*/);
1622 Vxwidget_list = Qnil;
1624 DEFVAR_LISP ("xwidget-view-list", Vxwidget_view_list, doc: /*xwidget views list*/);
1625 Vxwidget_view_list = Qnil;
1627 Fprovide (intern ("xwidget-internal"), Qnil);
1632 /* Value is non-zero if OBJECT is a valid Lisp xwidget specification. A
1633 valid xwidget specification is a list whose car is the symbol
1634 `xwidget', and whose rest is a property list. The property list must
1635 contain a value for key `:type'. That value must be the name of a
1636 supported xwidget type. The rest of the property list depends on the
1637 xwidget type. */
1640 valid_xwidget_spec_p (Lisp_Object object)
1642 int valid_p = 0;
1644 if (CONSP (object) && EQ (XCAR (object), Qxwidget))
1646 /* Lisp_Object tem; */
1648 /* for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem)) */
1649 /* if (EQ (XCAR (tem), QCtype)) */
1650 /* { */
1651 /* tem = XCDR (tem); */
1652 /* if (CONSP (tem) && SYMBOLP (XCAR (tem))) */
1653 /* { */
1654 /* struct xwidget_type *type; */
1655 /* type = lookup_xwidget_type (XCAR (tem)); */
1656 /* if (type) */
1657 /* valid_p = type->valid_p (object); */
1658 /* } */
1660 /* break; */
1661 /* } */
1662 //never mind type support for now
1663 valid_p = 1;
1666 return valid_p;
1671 /* find a value associated with key in spec */
1672 Lisp_Object
1673 xwidget_spec_value ( Lisp_Object spec, Lisp_Object key,
1674 int *found)
1676 Lisp_Object tail;
1678 eassert (valid_xwidget_spec_p (spec));
1680 for (tail = XCDR (spec);
1681 CONSP (tail) && CONSP (XCDR (tail)); tail = XCDR (XCDR (tail)))
1683 if (EQ (XCAR (tail), key))
1685 if (found)
1686 *found = 1;
1687 return XCAR (XCDR (tail));
1691 if (found)
1692 *found = 0;
1693 return Qnil;
1697 void
1698 xwidget_view_delete_all_in_window (struct window *w)
1700 struct xwidget_view* xv = NULL;
1701 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
1703 if (XWIDGET_VIEW_P (XCAR (tail))) {
1704 xv = XXWIDGET_VIEW (XCAR (tail));
1705 if(XWINDOW (xv->w) == w) {
1706 gtk_widget_destroy(xv->widgetwindow);
1707 Vxwidget_view_list = Fdelq (XCAR (tail), Vxwidget_view_list);
1713 struct xwidget_view*
1714 xwidget_view_lookup (struct xwidget* xw, struct window *w)
1716 Lisp_Object xwidget, window, ret;
1717 XSETXWIDGET (xwidget, xw);
1718 XSETWINDOW (window, w);
1720 ret = Fxwidget_view_lookup (xwidget, window);
1722 return EQ (ret, Qnil) ? NULL : XXWIDGET_VIEW (ret);
1725 struct xwidget*
1726 lookup_xwidget (Lisp_Object spec)
1728 /* When a xwidget lisp spec is found initialize the C struct that is used in the C code.
1729 This is done by redisplay so values change if the spec changes.
1730 So, take special care of one-shot events
1732 TODO remove xwidget init from display spec. simply store an xwidget reference only and set
1733 size etc when creating the xwidget, which should happen before insertion into buffer
1735 int found = 0, found1 = 0, found2 = 0;
1736 Lisp_Object value;
1737 struct xwidget *xw;
1739 value = xwidget_spec_value (spec, QCxwidget, &found1);
1740 xw = XXWIDGET(value);
1742 return xw;
1745 /*set up detection of touched xwidget*/
1746 void
1747 xwidget_start_redisplay (void)
1749 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
1751 if (XWIDGET_VIEW_P (XCAR (tail)))
1752 XXWIDGET_VIEW (XCAR (tail))->redisplayed = 0;
1756 /* the xwidget was touched during redisplay, so it isnt a candidate for hiding*/
1757 void
1758 xwidget_touch (struct xwidget_view *xv)
1760 xv->redisplayed = 1;
1764 xwidget_touched (struct xwidget_view *xv)
1766 return xv->redisplayed;
1769 /* redisplay has ended, now we should hide untouched xwidgets
1771 void
1772 xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix)
1775 int i;
1776 struct xwidget *xw;
1777 int area;
1780 xwidget_start_redisplay ();
1781 //iterate desired glyph matrix of window here, hide gtk widgets
1782 //not in the desired matrix.
1784 //this only takes care of xwidgets in active windows.
1785 //if a window goes away from screen xwidget views wust be deleted
1787 // dump_glyph_matrix(matrix, 2);
1788 for (i = 0; i < matrix->nrows; ++i)
1790 // dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs);
1791 struct glyph_row *row;
1792 row = MATRIX_ROW (matrix, i);
1793 if (row->enabled_p != 0)
1795 for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
1797 struct glyph *glyph = row->glyphs[area];
1798 struct glyph *glyph_end = glyph + row->used[area];
1799 for (; glyph < glyph_end; ++glyph)
1801 if (glyph->type == XWIDGET_GLYPH)
1804 the only call to xwidget_end_redisplay is in dispnew
1805 xwidget_end_redisplay(w->current_matrix);
1807 xwidget_touch (xwidget_view_lookup(glyph->u.xwidget,
1808 w));
1815 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
1817 if (XWIDGET_VIEW_P (XCAR (tail))) {
1818 struct xwidget_view* xv = XXWIDGET_VIEW (XCAR (tail));
1820 //"touched" is only meaningful for the current window, so disregard other views
1821 if (XWINDOW (xv->w) == w) {
1822 if (xwidget_touched(xv))
1823 xwidget_show_view (xv);
1824 else
1825 xwidget_hide_view (xv);
1831 /* Kill all xwidget in BUFFER. */
1832 void
1833 kill_buffer_xwidgets (Lisp_Object buffer)
1835 Lisp_Object tail, xwidget;
1836 for (tail = Fget_buffer_xwidgets (buffer); CONSP (tail); tail = XCDR (tail))
1838 xwidget = XCAR (tail);
1839 Vxwidget_list = Fdelq (xwidget, Vxwidget_list);
1840 /* TODO free the GTK things in xw */
1842 CHECK_XWIDGET (xwidget);
1843 struct xwidget *xw = XXWIDGET (xwidget);
1844 if (xw->widget_osr && xw->widgetwindow_osr)
1846 gtk_widget_destroy(xw->widget_osr);
1847 gtk_widget_destroy(xw->widgetwindow_osr);
1853 #endif /* HAVE_XWIDGETS */