gnu indent on src/xwidget.*
[emacs.git] / src / xwidget.c
blob7ffb132771149353ea49d645bd9ea763fb544c7c
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"
99 /* Convert STRING, a string constant, to a type acceptable as glib data.
100 Paul Eggert*/
101 static char *
102 gstr (char const *string)
104 return (char *) string;
108 //TODO embryo of lisp allocators for xwidgets
109 //TODO xwidget* should be Lisp_xwidget*
110 static struct xwidget *
111 allocate_xwidget (void)
113 return ALLOCATE_PSEUDOVECTOR (struct xwidget, height, PVEC_XWIDGET);
116 //TODO xwidget_view* should be Lisp_xwidget_view*
117 static struct xwidget_view *
118 allocate_xwidget_view (void)
120 return ALLOCATE_PSEUDOVECTOR (struct xwidget_view, redisplayed,
121 PVEC_XWIDGET_VIEW);
124 #define XSETXWIDGET(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET))
125 #define XSETXWIDGET_VIEW(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW))
127 struct xwidget_view *xwidget_view_lookup (struct xwidget *xw,
128 struct window *w);
129 Lisp_Object xwidget_spec_value (Lisp_Object spec, Lisp_Object key,
130 int *found);
131 gboolean offscreen_damage_event (GtkWidget * widget, GdkEvent * event,
132 gpointer data);
133 void webkit_osr_document_load_finished_callback (WebKitWebView *
134 webkitwebview,
135 WebKitWebFrame * arg1,
136 gpointer user_data);
137 gboolean webkit_osr_download_callback (WebKitWebView * webkitwebview,
138 WebKitDownload * arg1, gpointer data);
140 gboolean
141 webkit_osr_mime_type_policy_typedecision_requested_callback (WebKitWebView *
142 webView,
143 WebKitWebFrame *
144 frame,
145 WebKitNetworkRequest
146 * request,
147 gchar * mimetype,
148 WebKitWebPolicyDecision
150 policy_decision,
151 gpointer
152 user_data);
154 gboolean
155 webkit_osr_new_window_policy_decision_requested_callback (WebKitWebView *
156 webView,
157 WebKitWebFrame *
158 frame,
159 WebKitNetworkRequest
160 * request,
161 WebKitWebNavigationAction
162 * navigation_action,
163 WebKitWebPolicyDecision
164 * policy_decision,
165 gpointer user_data);
168 gboolean
169 webkit_osr_navigation_policy_decision_requested_callback (WebKitWebView *
170 webView,
171 WebKitWebFrame *
172 frame,
173 WebKitNetworkRequest
174 * request,
175 WebKitWebNavigationAction
176 * navigation_action,
177 WebKitWebPolicyDecision
178 * policy_decision,
179 gpointer user_data);
181 static GtkWidget *xwgir_create (char *, char *);
184 static void send_xembed_ready_event (struct xwidget *xw, int xembedid);
185 DEFUN ("make-xwidget", Fmake_xwidget, Smake_xwidget, 7, 8, 0, doc: /* Make an xwidget from BEG to END of TYPE.
187 If BUFFER is nil it uses the current buffer. If BUFFER is a string and
188 no such buffer exists, it is created.
190 TYPE is a symbol which can take one of the following values:
191 - Button
192 - ToggleButton
193 - slider
194 - socket
195 - socket-osr
196 - cairo
198 )(Lisp_Object beg, Lisp_Object end,
199 Lisp_Object type,
200 Lisp_Object title,
201 Lisp_Object width, Lisp_Object height, Lisp_Object data, Lisp_Object buffer)
203 //should work a bit like "make-button"(make-button BEG END &rest PROPERTIES)
204 // arg "type" and fwd should be keyword args eventually
205 //(make-xwidget 3 3 'button "oei" 31 31 nil)
206 //(xwidget-info (car xwidget-list))
207 struct xwidget *xw = allocate_xwidget ();
208 Lisp_Object val;
209 xw->type = type;
210 xw->title = title;
211 if (NILP (buffer))
212 buffer = Fcurrent_buffer (); // no need to gcpro because Fcurrent_buffer doesn't call Feval/eval_sub.
213 else
214 buffer = Fget_buffer_create (buffer);
215 xw->buffer = buffer;
217 xw->height = XFASTINT (height);
218 xw->width = XFASTINT (width);
219 xw->kill_without_query = 0;
220 XSETXWIDGET (val, xw); // set the vectorlike_header of VAL with the correct value
221 Vxwidget_list = Fcons (val, Vxwidget_list);
222 xw->widgetwindow_osr = NULL;
223 xw->widget_osr = NULL;
224 xw->plist = Qnil;
229 #ifdef HAVE_WEBKIT_OSR
230 /* DIY mvc. widget is rendered offscreen,
231 later bitmap copied to the views.
233 if (EQ (xw->type, Qwebkit_osr) ||
234 EQ (xw->type, Qsocket_osr) || (!NILP (Fget (xw->type, QCxwgir_class))))
236 block_input ();
237 xw->widgetwindow_osr = gtk_offscreen_window_new ();
238 gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
239 xw->height);
240 xw->widgetscrolledwindow_osr = NULL; //webkit osr is the only scrolled component atm
242 if (EQ (xw->type, Qwebkit_osr))
244 xw->widgetscrolledwindow_osr = gtk_scrolled_window_new (NULL, NULL);
245 gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW
246 (xw->
247 widgetscrolledwindow_osr),
248 xw->height);
249 gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW
250 (xw->
251 widgetscrolledwindow_osr),
252 xw->width);
253 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW
254 (xw->widgetscrolledwindow_osr),
255 GTK_POLICY_ALWAYS,
256 GTK_POLICY_ALWAYS);
258 xw->widget_osr = webkit_web_view_new ();
259 gtk_container_add (GTK_CONTAINER (xw->widgetscrolledwindow_osr),
260 GTK_WIDGET (WEBKIT_WEB_VIEW (xw->widget_osr)));
262 if (EQ (xw->type, Qsocket_osr))
263 xw->widget_osr = gtk_socket_new ();
264 if (!NILP (Fget (xw->type, QCxwgir_class)))
265 xw->widget_osr =
266 xwgir_create (SSDATA (Fcar (Fcdr (Fget (xw->type, QCxwgir_class)))),
267 SSDATA (Fcar (Fget (xw->type, QCxwgir_class))));
269 gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
270 xw->height);
272 if (EQ (xw->type, Qwebkit_osr))
274 gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
275 xw->widgetscrolledwindow_osr);
277 else
279 gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
280 xw->widget_osr);
283 gtk_widget_show (xw->widget_osr);
284 gtk_widget_show (xw->widgetwindow_osr);
285 gtk_widget_show (xw->widgetscrolledwindow_osr);
287 /* store some xwidget data in the gtk widgets for convenient retrieval in the event handlers. */
288 g_object_set_data (G_OBJECT (xw->widget_osr), XG_XWIDGET,
289 (gpointer) (xw));
290 g_object_set_data (G_OBJECT (xw->widgetwindow_osr), XG_XWIDGET,
291 (gpointer) (xw));
293 /* signals */
294 if (EQ (xw->type, Qwebkit_osr))
296 g_signal_connect (G_OBJECT (xw->widget_osr),
297 "document-load-finished",
298 G_CALLBACK
299 (webkit_osr_document_load_finished_callback), xw);
301 g_signal_connect (G_OBJECT (xw->widget_osr),
302 "download-requested",
303 G_CALLBACK (webkit_osr_download_callback), xw);
305 g_signal_connect (G_OBJECT (xw->widget_osr),
306 "mime-type-policy-decision-requested",
307 G_CALLBACK
308 (webkit_osr_mime_type_policy_typedecision_requested_callback),
309 xw);
311 g_signal_connect (G_OBJECT (xw->widget_osr),
312 "new-window-policy-decision-requested",
313 G_CALLBACK
314 (webkit_osr_new_window_policy_decision_requested_callback),
315 xw);
317 g_signal_connect (G_OBJECT (xw->widget_osr),
318 "navigation-policy-decision-requested",
319 G_CALLBACK
320 (webkit_osr_navigation_policy_decision_requested_callback),
321 xw);
324 if (EQ (xw->type, Qsocket_osr))
326 send_xembed_ready_event (xw,
327 gtk_socket_get_id (GTK_SOCKET
328 (xw->widget_osr)));
329 //gtk_widget_realize(xw->widget);
333 unblock_input ();
336 #endif /* HAVE_WEBKIT_OSR */
338 return val;
341 DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets, Sget_buffer_xwidgets, 1, 1, 0, doc:/* Return a list of xwidgets associated with BUFFER.
342 BUFFER may be a buffer or the name of one.
344 )(Lisp_Object
345 buffer)
347 Lisp_Object xw, tail, xw_list;
349 if (NILP (buffer))
350 return Qnil;
351 buffer = Fget_buffer (buffer);
352 if (NILP (buffer))
353 return Qnil;
355 xw_list = Qnil;
357 for (tail = Vxwidget_list; CONSP (tail); tail = XCDR (tail))
359 xw = XCAR (tail);
360 if (XWIDGETP (xw) && EQ (Fxwidget_buffer (xw), buffer))
361 xw_list = Fcons (xw, xw_list);
363 return xw_list;
366 static int
367 xwidget_hidden (struct xwidget_view *xv)
369 return xv->hidden;
373 static void
374 buttonclick_handler (GtkWidget * widget, gpointer data)
376 Lisp_Object xwidget_view, xwidget;
377 XSETXWIDGET_VIEW (xwidget_view, (struct xwidget_view *) data);
378 xwidget = Fxwidget_view_model (xwidget_view);
380 struct input_event event;
381 Lisp_Object frame = Fwindow_frame (Fxwidget_view_window (xwidget_view));
382 EVENT_INIT (event);
383 event.kind = XWIDGET_EVENT;
385 event.frame_or_window = frame;
387 event.arg = Qnil;
388 event.arg = Fcons (xwidget, event.arg);
389 event.arg = Fcons (intern ("buttonclick"), event.arg);
391 kbd_buffer_store_event (&event);
395 static void
396 send_xembed_ready_event (struct xwidget *xw, int xembedid)
398 Lisp_Object xw_lo;
399 XSETXWIDGET (xw_lo, xw);
400 struct input_event event;
401 EVENT_INIT (event);
402 event.kind = XWIDGET_EVENT;
403 event.frame_or_window = Qnil; //frame; //how to get the frame here? //TODO i store it in the xwidget now
405 event.arg = Qnil;
406 event.arg = Fcons (make_number (xembedid), event.arg);
407 event.arg = Fcons (xw_lo, event.arg);
408 event.arg = Fcons (intern ("xembed-ready"), event.arg);
411 kbd_buffer_store_event (&event);
415 static void
416 xwidget_show_view (struct xwidget_view *xv)
418 xv->hidden = 0;
419 gtk_widget_show (xv->widgetwindow);
420 gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow, xv->x + xv->clip_left, xv->y + xv->clip_top); //TODO refactor
424 /* hide an xvidget view */
425 static void
426 xwidget_hide_view (struct xwidget_view *xv)
428 xv->hidden = 1;
429 //gtk_widget_hide(xw->widgetwindow);
430 gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow,
431 10000, 10000);
435 static void
436 xwidget_plug_added (GtkSocket * socket, gpointer user_data)
438 //hmm this doesnt seem to get called for foreign windows
439 printf ("xwidget_plug_added\n");
442 static gboolean
443 xwidget_plug_removed (GtkSocket * socket, gpointer user_data)
445 printf ("xwidget_plug_removed\n");
446 return TRUE; /* dont run the default handler because that kills the socket and we want to reuse it */
450 static void
451 xwidget_slider_changed (GtkRange * range, gpointer user_data)
453 //slider value changed. change value of siblings
454 //correspondingly. but remember that changing value will again
455 //trigger signal
457 //TODO MVC view storage wont be an array futureish so the loop needs to change eventually
458 //TODO MVC it would be nice if this code could be reusable but, alas, C is not a functional language
459 //issues are:
460 // - the type of the controllers value (double, boolean etc)
461 // - the getter and setter (but they can be func pointers)
462 // a behemoth macro is always an option.
463 double v = gtk_range_get_value (range);
464 struct xwidget_view *xvp =
465 g_object_get_data (G_OBJECT (range), XG_XWIDGET_VIEW);
466 struct xwidget_view *xv;
468 printf ("slider changed val:%f\n", v);
470 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
471 tail = XCDR (tail))
473 if (XWIDGET_VIEW_P (XCAR (tail)))
475 xv = XXWIDGET_VIEW (XCAR (tail));
476 if (EQ (xvp->model, xv->model))
478 //block sibling views signal handlers
479 g_signal_handler_block (xv->widget, xv->handler_id);
481 //set values of sibling views and unblock
482 gtk_range_set_value (GTK_RANGE (xv->widget), v);
483 g_signal_handler_unblock (xv->widget, xv->handler_id);
490 /* when the off-screen webkit master view changes this signal is called.
491 it copies the bitmap from the off-screen webkit instance */
492 gboolean
493 offscreen_damage_event (GtkWidget * widget, GdkEvent * event,
494 gpointer xv_widget)
496 //queue a redraw of onscreen widget
497 if (GTK_IS_WIDGET (xv_widget))
498 gtk_widget_queue_draw (GTK_WIDGET (xv_widget));
499 else
500 printf
501 ("Warning, offscreen_damage_event received invalid xv pointer:%p\n",
502 (void *) xv_widget);
505 return FALSE;
508 static void
509 store_xwidget_event_string (struct xwidget *xw, const char *eventname,
510 const char *eventstr)
512 //refactor attempt
513 struct input_event event;
514 Lisp_Object xwl;
515 XSETXWIDGET (xwl, xw);
516 EVENT_INIT (event);
517 event.kind = XWIDGET_EVENT;
518 event.frame_or_window = Qnil; //frame; //how to get the frame here? //TODO i store it in the xwidget now
520 event.arg = Qnil;
521 event.arg = Fcons (build_string (eventstr), event.arg); //string so dont intern
522 event.arg = Fcons (xwl, event.arg); //TODO
523 event.arg = Fcons (intern (eventname), event.arg); //interning should be ok
524 kbd_buffer_store_event (&event);
528 //TODO deprecated, use load-status
529 void
530 webkit_osr_document_load_finished_callback (WebKitWebView * webkitwebview,
531 WebKitWebFrame * arg1,
532 gpointer data)
534 //TODO this event sending code should be refactored
535 // struct xwidget *xw = (struct xwidget *) data;
536 struct xwidget *xw =
537 (struct xwidget *) g_object_get_data (G_OBJECT (webkitwebview),
538 XG_XWIDGET);
539 printf ("webkit finished loading\n");
541 store_xwidget_event_string (xw, "document-load-finished", "");
544 gboolean
545 webkit_osr_download_callback (WebKitWebView * webkitwebview,
546 WebKitDownload * arg1, gpointer data)
548 struct xwidget *xw =
549 (struct xwidget *) g_object_get_data (G_OBJECT (webkitwebview),
550 XG_XWIDGET);
551 printf ("download requested %s\n", webkit_download_get_uri (arg1));
554 printf ("webkit finished loading\n");
556 store_xwidget_event_string (xw, "download-requested",
557 webkit_download_get_uri (arg1));
559 return FALSE;
562 gboolean
563 webkit_osr_mime_type_policy_typedecision_requested_callback (WebKitWebView *
564 webView,
565 WebKitWebFrame *
566 frame,
567 WebKitNetworkRequest
568 * request,
569 gchar * mimetype,
570 WebKitWebPolicyDecision
572 policy_decision,
573 gpointer
574 user_data)
576 printf ("mime policy requested\n");
577 // this function makes webkit send a download signal for all unknown mime types
578 // TODO defer the decision to lisp, so that its possible to make Emacs handle text mime for instance
579 if (!webkit_web_view_can_show_mime_type (webView, mimetype))
581 webkit_web_policy_decision_download (policy_decision);
582 return TRUE;
584 else
586 return FALSE;
591 gboolean
592 webkit_osr_new_window_policy_decision_requested_callback (WebKitWebView *
593 webView,
594 WebKitWebFrame *
595 frame,
596 WebKitNetworkRequest
597 * request,
598 WebKitWebNavigationAction
599 * navigation_action,
600 WebKitWebPolicyDecision
601 * policy_decision,
602 gpointer user_data)
604 struct xwidget *xw =
605 (struct xwidget *) g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
606 printf ("webkit_osr_new_window_policy_decision_requested_callback %s\n",
607 webkit_web_navigation_action_get_original_uri (navigation_action));
609 store_xwidget_event_string (xw, "new-window-policy-decision-requested",
610 webkit_web_navigation_action_get_original_uri
611 (navigation_action));
612 return FALSE;
615 gboolean
616 webkit_osr_navigation_policy_decision_requested_callback (WebKitWebView *
617 webView,
618 WebKitWebFrame *
619 frame,
620 WebKitNetworkRequest
621 * request,
622 WebKitWebNavigationAction
623 * navigation_action,
624 WebKitWebPolicyDecision
625 * policy_decision,
626 gpointer user_data)
628 struct xwidget *xw =
629 (struct xwidget *) g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
630 printf ("webkit_osr_navigation_policy_decision_requested_callback %s\n",
631 webkit_web_navigation_action_get_original_uri (navigation_action));
632 store_xwidget_event_string (xw, "navigation-policy-decision-requested",
633 webkit_web_navigation_action_get_original_uri
634 (navigation_action));
635 return FALSE;
638 //for gtk3 offscreen rendered widgets
639 static gboolean
640 xwidget_osr_draw_callback (GtkWidget * widget, cairo_t * cr, gpointer data)
642 struct xwidget *xw =
643 (struct xwidget *) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
644 struct xwidget_view *xv =
645 (struct xwidget_view *) g_object_get_data (G_OBJECT (widget),
646 XG_XWIDGET_VIEW);
648 cairo_rectangle (cr, 0, 0, xv->clip_right, xv->clip_bottom); //xw->width, xw->height);
649 cairo_clip (cr);
652 if (xw->widgetscrolledwindow_osr != NULL)
653 gtk_widget_draw (xw->widgetscrolledwindow_osr, cr);
654 else
655 gtk_widget_draw (xw->widget_osr, cr);
656 return FALSE;
659 GtkWidget *xwgir_create_debug;
663 static gboolean
664 xwidget_osr_event_forward (GtkWidget * widget,
665 GdkEvent * event, gpointer user_data)
667 /* copy events that arrive at the outer widget to the offscreen widget */
668 struct xwidget *xw =
669 (struct xwidget *) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
670 GdkEvent *eventcopy = gdk_event_copy (event);
671 eventcopy->any.window = gtk_widget_get_window (xw->widget_osr); // works
673 /* printf("xwidget_osr_event_forward redirect event to window:%d\n", ((GdkEventAny*)eventcopy)->window); */
674 /* printf("A type:%d x:%f y:%f \n", event->type, event->button.x, event->button.y); */
675 /* printf("B type:%d x:%f y:%f \n", eventcopy->type, eventcopy->button.x, eventcopy->button.y); */
676 //gtk_button_get_event_window(xwgir_create_debug);
677 gtk_main_do_event (eventcopy); //TODO this will leak events. they should be deallocated later, perhaps in xwgir_event_callback
678 return TRUE; //dont propagate this event furter
681 GIRepository *girepository;
683 DEFUN ("xwgir-require-namespace", Fxwgir_require_namespace, Sxwgir_require_namespace, 2, 2, 0, doc: /* Require a GObject Introspection namespace.
684 This must be done for all namespaces we want to use, before using other xwgir functions. */ )
685 (Lisp_Object lnamespace, Lisp_Object lnamespace_version)
687 const gchar *namespace = SSDATA (lnamespace);
688 const gchar *namespace_version = SSDATA (lnamespace_version);
689 GError *error = NULL;
691 girepository = g_irepository_get_default ();
692 g_irepository_require (girepository, namespace, namespace_version, 0,
693 &error);
694 if (error)
696 g_error ("ERROR: %s\n", error->message);
697 return Qnil;
699 return Qt;
702 GtkWidget *
703 xwgir_create (char *class, char *namespace)
705 //TODO this is more or less the same as xwgir-call-method, so should be refactored
706 //create a gtk widget, given its name
707 //find the constructor
708 //call it
709 //also figure out how to pass args
711 GIArgument return_value;
713 GIObjectInfo *obj_info =
714 g_irepository_find_by_name (girepository, namespace, class);
715 GIFunctionInfo *f_info = g_object_info_find_method (obj_info, "new");
716 g_function_info_invoke (f_info, NULL, 0, NULL, 0, &return_value, NULL);
717 xwgir_create_debug = return_value.v_pointer;
718 return return_value.v_pointer;
722 static int
723 xwgir_convert_lisp_to_gir_arg (GIArgument * giarg,
724 GIArgInfo * arginfo, Lisp_Object lisparg)
727 GITypeTag tag;
728 tag = g_type_info_get_tag (g_arg_info_get_type (arginfo));
730 switch (tag)
732 case GI_TYPE_TAG_BOOLEAN:
733 giarg->v_boolean = XFASTINT (lisparg);
734 break;
735 case GI_TYPE_TAG_INT8:
736 giarg->v_int8 = XFASTINT (lisparg);
737 break;
738 case GI_TYPE_TAG_UINT8:
739 giarg->v_uint8 = XFASTINT (lisparg);
740 break;
741 case GI_TYPE_TAG_INT16:
742 giarg->v_int16 = XFASTINT (lisparg);
743 break;
744 case GI_TYPE_TAG_UINT16:
745 giarg->v_uint16 = XFASTINT (lisparg);
746 break;
747 case GI_TYPE_TAG_INT32:
748 giarg->v_int32 = XFASTINT (lisparg);
749 break;
750 case GI_TYPE_TAG_UINT32:
751 giarg->v_uint32 = XFASTINT (lisparg);
752 break;
754 case GI_TYPE_TAG_INT64:
755 giarg->v_int64 = XFASTINT (lisparg);
756 break;
757 case GI_TYPE_TAG_UINT64:
758 giarg->v_uint64 = XFASTINT (lisparg);
759 break;
762 case GI_TYPE_TAG_FLOAT:
763 giarg->v_float = XFLOAT_DATA (lisparg);
764 break;
766 case GI_TYPE_TAG_DOUBLE:
767 giarg->v_double = XFLOAT_DATA (lisparg);
768 break;
770 case GI_TYPE_TAG_UTF8:
771 case GI_TYPE_TAG_FILENAME:
772 //giarg->v_string = SDATA(lisparg);
773 giarg->v_pointer = SDATA (lisparg);
774 break;
776 case GI_TYPE_TAG_ARRAY:
777 case GI_TYPE_TAG_GLIST:
778 case GI_TYPE_TAG_GSLIST:
779 case GI_TYPE_TAG_GHASH:
780 case GI_TYPE_TAG_ERROR:
781 case GI_TYPE_TAG_INTERFACE:
782 case GI_TYPE_TAG_VOID:
783 case GI_TYPE_TAG_UNICHAR:
784 case GI_TYPE_TAG_GTYPE:
785 //?? i dont know how to handle these yet TODO
786 printf ("failed in my lisp to gir arg conversion duties. sob!\n");
787 return -1;
788 break;
790 return 0;
793 DEFUN ("xwgir-xwidget-call-method", Fxwgir_xwidget_call_method, Sxwgir_xwidget_call_method, 3, 3, 0, doc: /* Call Xwidget object method using GObject Introspection.
794 XWIDGET is the xwidget instance to act upon.
795 METHOD is the Gobject intrsopsection method name.
796 ARGUMENTS is a list of arguments for the call. They will be converted to GObject types from Lisp types.
797 */ )
798 (Lisp_Object xwidget, Lisp_Object method, Lisp_Object arguments)
800 CHECK_XWIDGET (xwidget);
801 GError *error = NULL;
802 GIArgument return_value;
803 GIArgument in_args[20];
806 struct xwidget *xw;
807 if (NILP (xwidget))
809 printf ("ERROR xwidget nil\n");
810 return Qnil;
812 xw = XXWIDGET (xwidget);
813 if (NULL == xw)
814 printf ("ERROR xw is 0\n");
815 char *namespace = SSDATA (Fcar (Fget (xw->type, QCxwgir_class)));
816 //we need the concrete widget, which happens in 2 ways depending on OSR or not TODO
817 GtkWidget *widget = NULL;
818 if (NULL == xw->widget_osr)
820 widget =
821 xwidget_view_lookup (xw,
822 XWINDOW (FRAME_SELECTED_WINDOW
823 (SELECTED_FRAME ())))->widget;
825 else
827 widget = xw->widget_osr;
830 //char* class = SDATA(SYMBOL_NAME(xw->type)); //this works but is unflexible
831 //figure out the class from the widget instead
832 /* printf("type class: %s %s\n", G_OBJECT_TYPE_NAME(widget), G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(widget))); */
833 /* char* class = G_OBJECT_TYPE_NAME(widget); //gives "GtkButton"(I want "Button") */
834 /* class += strlen(namespace); //TODO check for corresponding api method. but this seems to work. */
836 char *class = SSDATA (Fcar (Fcdr (Fget (xw->type, QCxwgir_class))));
838 GIObjectInfo *obj_info =
839 g_irepository_find_by_name (girepository, namespace, class);
840 GIFunctionInfo *f_info =
841 g_object_info_find_method (obj_info, SSDATA (method));
843 //loop over args, convert from lisp to primitive type, given arg introspection data
844 //TODO g_callable_info_get_n_args(f_info) should match
845 int argscount = XFASTINT (Flength (arguments));
846 if (argscount != g_callable_info_get_n_args (f_info))
848 printf ("xwgir call method arg count doesn match! \n");
849 return Qnil;
851 int i;
852 Lisp_Object n;
853 for (i = 1; i < argscount + 1; ++i)
855 XSETFASTINT (n, i - 1);
856 xwgir_convert_lisp_to_gir_arg (&in_args[i],
857 g_callable_info_get_arg (f_info, i - 1),
858 Fnth (n, arguments));
861 in_args[0].v_pointer = widget;
862 if (g_function_info_invoke (f_info,
863 in_args, argscount + 1,
864 NULL, 0, &return_value, &error))
866 //g_error("ERROR: %s\n", error->message);
867 printf ("invokation error\n");
868 return Qnil;
870 return Qt;
873 static GdkWindow *
874 offscreen_pick_embedded_child (GdkWindow * window,
875 double x, double y, gpointer * data)
877 //in this simple case we assume the window contains a single widget. easy.
878 //but then we get the problem that the widget cant be embedded in several windows
879 return gtk_widget_get_window (GTK_WIDGET (data));
882 static void
883 offscreen_to_embedder (GdkWindow * window,
884 gdouble offscreen_x,
885 gdouble offscreen_y,
886 gpointer embedder_x,
887 gpointer embedder_y, gpointer data)
889 *(gdouble *) embedder_x = offscreen_x;
890 *(gdouble *) embedder_y = offscreen_y;
893 static void
894 offscreen_from_embedder (GdkWindow * window,
895 gdouble embedder_x,
896 gdouble embedder_y,
897 gpointer offscreen_x,
898 gpointer offscreen_y, gpointer user_data)
900 *(gdouble *) offscreen_x = embedder_x;
901 *(gdouble *) offscreen_y = embedder_y;
904 static gboolean
905 xwidget_osr_event_set_embedder (GtkWidget * widget,
906 GdkEvent * event, gpointer data)
908 struct xwidget_view *xv = (struct xwidget_view *) data;
909 struct xwidget *xww = XXWIDGET (xv->model);
910 printf ("gdk_offscreen_window_set_embedder %d %d\n",
911 GDK_IS_WINDOW (gtk_widget_get_window (xww->widget_osr)),
912 GDK_IS_WINDOW (gtk_widget_get_window (GTK_WIDGET (xv->widget))));
913 gdk_offscreen_window_set_embedder (gtk_widget_get_window
914 (xww->widgetwindow_osr),
915 gtk_widget_get_window (xv->widget));
916 return FALSE;
920 /* initializes and does initial placement of an xwidget view on screen */
921 static struct xwidget_view *
922 xwidget_init_view (struct xwidget *xww, struct glyph_string *s, int x, int y)
924 struct xwidget_view *xv = allocate_xwidget_view ();
925 Lisp_Object val;
927 XSETXWIDGET_VIEW (val, xv);
928 Vxwidget_view_list = Fcons (val, Vxwidget_view_list);
930 XSETWINDOW (xv->w, s->w);
931 XSETXWIDGET (xv->model, xww);
933 //widget creation
934 if (EQ (xww->type, Qbutton))
936 xv->widget = gtk_button_new_with_label (SSDATA (xww->title));
937 g_signal_connect (G_OBJECT (xv->widget), "clicked", G_CALLBACK (buttonclick_handler), xv); // the view rather than the model
939 else if (EQ (xww->type, Qtoggle))
941 xv->widget = gtk_toggle_button_new_with_label (SSDATA (xww->title));
942 //xv->widget = gtk_entry_new ();//temp hack to experiment with key propagation TODO entry widget is useful for testing
944 else if (EQ (xww->type, Qsocket))
946 xv->widget = gtk_socket_new ();
947 g_signal_connect_after (xv->widget, "plug-added",
948 G_CALLBACK (xwidget_plug_added),
949 gstr ("plug added"));
950 g_signal_connect_after (xv->widget, "plug-removed",
951 G_CALLBACK (xwidget_plug_removed),
952 gstr ("plug removed"));
953 //TODO these doesnt help
954 gtk_widget_add_events (xv->widget, GDK_KEY_PRESS);
955 gtk_widget_add_events (xv->widget, GDK_KEY_RELEASE);
957 else if (EQ (xww->type, Qslider))
959 xv->widget =
960 //gtk_hscale_new (GTK_ADJUSTMENT(gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 10.0, 10.0)));
961 gtk_hscale_new_with_range (0.0, 100.0, 10.0);
962 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
963 xv->handler_id =
964 g_signal_connect_after (xv->widget, "value-changed",
965 G_CALLBACK (xwidget_slider_changed),
966 gstr ("slider changed"));
968 else if (EQ (xww->type, Qcairo))
970 //Cairo view
971 //uhm cairo is differentish in gtk 3.
972 //gdk_cairo_create (gtk_widget_get_window (FRAME_GTK_WIDGET (s->f)));
973 xv->widget = gtk_drawing_area_new ();
974 g_signal_connect (G_OBJECT (xv->widget), "draw",
975 G_CALLBACK (xwidget_osr_draw_callback), NULL);
978 else if (EQ (xww->type, Qwebkit_osr) || EQ (xww->type, Qsocket_osr) || (!NILP (Fget (xww->type, QCxwgir_class)))) //xwgir widgets are OSR
980 printf ("osr init:%s\n", SDATA (SYMBOL_NAME (xww->type)));
981 xv->widget = gtk_drawing_area_new ();
982 gtk_widget_set_app_paintable (xv->widget, TRUE); //because expose event handling
983 gtk_widget_add_events (xv->widget, GDK_ALL_EVENTS_MASK);
985 /* Draw the view on damage-event */
986 g_signal_connect (G_OBJECT (xww->widgetwindow_osr), "damage-event",
987 G_CALLBACK (offscreen_damage_event), xv->widget);
989 if (EQ (xww->type, Qwebkit_osr))
991 /* ///xwgir debug */
992 /* //forward events. this isnt compatible with the set_embedded strategy */
993 g_signal_connect (G_OBJECT (xv->widget), "button-press-event",
994 G_CALLBACK (xwidget_osr_event_forward), NULL);
995 g_signal_connect (G_OBJECT (xv->widget), "button-release-event",
996 G_CALLBACK (xwidget_osr_event_forward), NULL);
997 g_signal_connect (G_OBJECT (xv->widget), "motion-notify-event",
998 G_CALLBACK (xwidget_osr_event_forward), NULL);
1000 else
1002 //xwgir debug , orthogonal to forwarding
1003 g_signal_connect (G_OBJECT (xv->widget), "enter-notify-event",
1004 G_CALLBACK (xwidget_osr_event_set_embedder), xv);
1007 //draw
1008 g_signal_connect (G_OBJECT (xv->widget), "draw",
1009 G_CALLBACK (xwidget_osr_draw_callback), NULL);
1012 //else return NULL;
1014 //widget realization
1015 //make container widget 1st, and put the actual widget inside the container
1016 //later, drawing should crop container window if necessary to handle case where xwidget
1017 //is partially obscured by other emacs windows
1018 //other containers than gtk_fixed where explored, but gtk_fixed had the most predictable behaviour so far.
1019 xv->emacswindow = FRAME_GTK_WIDGET (s->f);
1020 xv->widgetwindow = gtk_fixed_new ();
1021 gtk_widget_set_has_window (xv->widgetwindow, TRUE);
1022 gtk_container_add (GTK_CONTAINER (xv->widgetwindow), xv->widget);
1024 //store some xwidget data in the gtk widgets
1025 g_object_set_data (G_OBJECT (xv->widget), XG_FRAME_DATA, (gpointer) (s->f)); //the emacs frame
1026 g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET, (gpointer) (xww)); //the xwidget
1027 g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET_VIEW, (gpointer) (xv)); //the xwidget
1028 g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET, (gpointer) (xww)); //the xwidget window
1029 g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET_VIEW, (gpointer) (xv)); //the xwidget window
1032 gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xww->width,
1033 xww->height);
1034 gtk_widget_set_size_request (xv->widgetwindow, xww->width, xww->height);
1035 gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), xv->widgetwindow, x, y);
1036 xv->x = x;
1037 xv->y = y;
1038 gtk_widget_show_all (xv->widgetwindow);
1042 //widgettype specific initialization only possible after realization
1043 if (EQ (xww->type, Qsocket))
1045 printf ("xwid:%p socket id:%p %p\n",
1046 (void *) xww,
1047 (void *) gtk_socket_get_id (GTK_SOCKET (xv->widget)),
1048 (void *) gtk_socket_get_id (GTK_SOCKET (xv->widget)));
1049 send_xembed_ready_event (xww,
1050 gtk_socket_get_id (GTK_SOCKET (xv->widget)));
1051 //gtk_widget_realize(xw->widget);
1054 //////////////////////////////////////////////////////////////
1055 // xwgir debug
1056 if ( //EQ(xww->type, Qwebkit_osr)|| //TODO should be able to choose compile time which method to use with webkit
1057 EQ (xww->type, Qsocket_osr) || (!NILP (Fget (xww->type, QCxwgir_class)))) //xwgir widgets are OSR
1059 printf ("gdk_offscreen_window_set_embedder %d %d\n",
1060 GDK_IS_WINDOW (gtk_widget_get_window (xww->widget_osr)),
1061 GDK_IS_WINDOW (gtk_widget_get_window
1062 (GTK_WIDGET (xv->widget))));
1063 // set_embedder needs to be called after xv->widget realization
1064 gdk_offscreen_window_set_embedder (gtk_widget_get_window
1065 (xww->widgetwindow_osr),
1066 gtk_widget_get_window (xv->widget));
1067 g_signal_connect (gtk_widget_get_window (xv->widget),
1068 "pick-embedded-child",
1069 G_CALLBACK (offscreen_pick_embedded_child),
1070 xww->widgetwindow_osr);
1072 g_signal_connect (gtk_widget_get_window (xww->widgetwindow_osr),
1073 "from-embedder", G_CALLBACK (offscreen_from_embedder),
1074 NULL);
1075 g_signal_connect (gtk_widget_get_window (xww->widgetwindow_osr),
1076 "to-embedder", G_CALLBACK (offscreen_to_embedder),
1077 NULL);
1079 ////////////////////////////////////////
1081 return xv;
1085 void
1086 x_draw_xwidget_glyph_string (struct glyph_string *s)
1089 this method is called by the redisplay engine and places the xwidget on screen.
1090 moving and clipping is done here. also view init.
1093 struct xwidget *xww = s->xwidget;
1094 struct xwidget_view *xv = xwidget_view_lookup (xww, s->w);
1095 int clip_right;
1096 int clip_bottom;
1097 int clip_top;
1098 int clip_left;
1100 int x = s->x;
1101 int y = s->y + (s->height / 2) - (xww->height / 2);
1102 int moved = 0;
1104 /* We do it here in the display loop because there is no other
1105 time to know things like window placement etc.
1107 xv = xwidget_init_view (xww, s, x, y);
1109 //calculate clipping, which is used for all manner of onscreen xwidget views
1110 //each widget border can get clipped by other emacs objects so there are four clipping variables
1111 clip_right =
1112 min (xww->width,
1113 WINDOW_RIGHT_EDGE_X (s->w) - x -
1114 WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH (s->w) -
1115 WINDOW_RIGHT_FRINGE_WIDTH (s->w));
1116 clip_left =
1117 max (0,
1118 WINDOW_LEFT_EDGE_X (s->w) - x +
1119 WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH (s->w) +
1120 WINDOW_LEFT_FRINGE_WIDTH (s->w));
1122 clip_bottom =
1123 min (xww->height,
1124 WINDOW_BOTTOM_EDGE_Y (s->w) - WINDOW_MODE_LINE_HEIGHT (s->w) - y);
1125 clip_top = max (0, WINDOW_TOP_EDGE_Y (s->w) - y);
1127 //we are conserned with movement of the onscreen area. the area might sit still when the widget actually moves
1128 //this happens when an emacs window border moves across a widget window
1129 //so, if any corner of the outer widget clippng window moves, that counts as movement here, even
1130 //if it looks like no movement happens because the widget sits still inside the clipping area.
1131 //the widget can also move inside the clipping area, which happens later
1132 moved = (xv->x + xv->clip_left != x + clip_left)
1133 || ((xv->y + xv->clip_top) != (y + clip_top));
1134 xv->x = x;
1135 xv->y = y;
1136 if (moved) //has it moved?
1138 if (1) //!xwidget_hidden(xv)) //hidden equals not being seen during redisplay
1140 //TODO should be possible to use xwidget_show_view here
1141 gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)),
1142 xv->widgetwindow, x + clip_left, y + clip_top);
1145 //clip the widget window if some parts happen to be outside drawable area
1146 //an emacs window is not a gtk window, a gtk window covers the entire frame
1147 //cliping might have changed even if we havent actualy moved, we try figure out when we need to reclip for real
1148 if ((xv->clip_right != clip_right)
1149 || (xv->clip_bottom != clip_bottom)
1150 || (xv->clip_top != clip_top) || (xv->clip_left != clip_left))
1152 gtk_widget_set_size_request (xv->widgetwindow, clip_right + clip_left,
1153 clip_bottom + clip_top);
1154 gtk_fixed_move (GTK_FIXED (xv->widgetwindow), xv->widget, -clip_left,
1155 -clip_top);
1157 xv->clip_right = clip_right;
1158 xv->clip_bottom = clip_bottom;
1159 xv->clip_top = clip_top;
1160 xv->clip_left = clip_left;
1162 //if emacs wants to repaint the area where the widget lives, queue a redraw
1163 //TODO it seems its possible to get out of sync with emacs redraws so emacs bg sometimes shows up instead of xwidget
1164 //its just a visual glitch though
1165 if (!xwidget_hidden (xv))
1167 gtk_widget_queue_draw (xv->widgetwindow);
1168 gtk_widget_queue_draw (xv->widget);
1173 #ifdef HAVE_WEBKIT_OSR
1175 //FUGLY macro that checks WEBKIT_IS_WEB_VIEW(xw->widget_osr) first
1176 #define WEBKIT_FN_INIT() \
1177 struct xwidget* xw; \
1178 CHECK_XWIDGET (xwidget); \
1179 if(NILP (xwidget)) {printf("ERROR xwidget nil\n"); return Qnil;}; \
1180 xw = XXWIDGET(xwidget); \
1181 if(NULL == xw) printf("ERROR xw is 0\n"); \
1182 if((NULL == xw->widget_osr) || !WEBKIT_IS_WEB_VIEW(xw->widget_osr)){ \
1183 printf("ERROR xw->widget_osr does not hold a webkit instance\n");\
1184 return Qnil;\
1188 DEFUN ("xwidget-webkit-goto-uri", Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri, 2, 2, 0, doc: /* Make the webkit instance referenced by XWIDGET browse URI. */
1190 (Lisp_Object xwidget, Lisp_Object uri)
1192 WEBKIT_FN_INIT ();
1193 CHECK_STRING (uri);
1194 webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr), SSDATA (uri));
1195 return Qnil;
1199 DEFUN ("xwidget-webkit-execute-script", Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script, 2, 2, 0, doc: /* webkit exec js. */
1201 (Lisp_Object xwidget, Lisp_Object script)
1203 WEBKIT_FN_INIT ();
1204 CHECK_STRING (script);
1205 webkit_web_view_execute_script (WEBKIT_WEB_VIEW (xw->widget_osr),
1206 SSDATA (script));
1207 return Qnil;
1210 DEFUN ("xwidget-webkit-get-title", Fxwidget_webkit_get_title, Sxwidget_webkit_get_title, 1, 1, 0, doc: /* Get the title from the Webkit instance in XWIDGET.
1211 This can be used to work around the lack of a return value from the exec method.
1212 */ )
1213 (Lisp_Object xwidget)
1215 //TODO support multibyte strings
1216 WEBKIT_FN_INIT ();
1217 const gchar *str =
1218 webkit_web_view_get_title (WEBKIT_WEB_VIEW (xw->widget_osr));
1219 //return make_string_from_bytes(str, wcslen((const wchar_t *)str), strlen(str));
1220 if (str == 0)
1222 //TODO maybe return Qnil instead. I suppose webkit returns nullpointer when doc is not properly loaded or something
1223 printf ("xwidget-webkit-get-title null webkit title\n");
1224 return build_string ("");
1226 return build_string (str);
1229 //TODO missnamed
1230 DEFUN ("xwidget-disable-plugin-for-mime", Fxwidget_disable_plugin_for_mime, Sxwidget_disable_plugin_for_mime, 1, 1, 0, doc: /* */ )
1231 (Lisp_Object mime)
1233 WebKitWebPlugin *wp = webkit_web_plugin_database_get_plugin_for_mimetype
1234 (webkit_get_web_plugin_database (), SSDATA (mime));
1235 if (wp == NULL)
1236 return Qnil;
1237 if (webkit_web_plugin_get_enabled (wp))
1239 webkit_web_plugin_set_enabled (wp, FALSE);
1240 return Qt;
1242 return Qnil;
1245 #ifdef HAVE_XLXW_DOMDUMP
1246 /* dom dumping is work in progress.
1247 2 of the methods used from webkit are deprecated nowm and replacements sought
1249 static void
1250 xwidget_webkit_dom_dump (WebKitDOMNode * parent)
1252 WebKitDOMNodeList *list;
1253 int length;
1254 WebKitDOMNode *attribute;
1255 WebKitDOMNamedNodeMap *attrs;
1256 WebKitDOMNode *child;
1257 printf ("node:%d type:%d name:%s content:%s\n", parent, webkit_dom_node_get_node_type (parent), //1 element 3 text 8 comment 2 attribute
1258 webkit_dom_node_get_local_name (parent),
1259 webkit_dom_node_get_text_content (parent));
1261 if (webkit_dom_node_has_attributes (parent))
1263 attrs = webkit_dom_node_get_attributes (parent);
1265 length = webkit_dom_named_node_map_get_length (attrs);
1266 for (int i = 0; i < length; i++)
1268 attribute = webkit_dom_named_node_map_item (attrs, i);
1269 printf (" attr node:%d type:%d name:%s content:%s\n", attribute, webkit_dom_node_get_node_type (attribute), //1 element 3 text 8 comment
1270 webkit_dom_node_get_local_name (attribute),
1271 webkit_dom_node_get_text_content (attribute));
1274 list = webkit_dom_node_get_child_nodes (parent);
1275 length = webkit_dom_node_list_get_length (list);
1277 for (int i = 0; i < length; i++)
1279 child = webkit_dom_node_list_item (list, i);
1280 //if(webkit_dom_node_has_child_nodes(child))
1281 xwidget_webkit_dom_dump (child);
1286 DEFUN ("xwidget-webkit-dom-dump", Fxwidget_webkit_dom_dump, Sxwidget_webkit_dom_dump, 1, 1, 0, doc: /*Dump the DOM contained in the webkit instance in XWIDGET. */
1288 (Lisp_Object xwidget)
1290 WEBKIT_FN_INIT ();
1291 xwidget_webkit_dom_dump (WEBKIT_DOM_NODE
1292 (webkit_web_view_get_dom_document
1293 (WEBKIT_WEB_VIEW (xw->widget_osr))));
1294 return Qnil;
1297 #endif /* HAVE_XLXW_DOMDUMP */
1299 #endif /* HAVE_WEBKIT_OSR */
1303 DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0, doc:
1304 /* Resize XWIDGET.
1305 NEW_WIDTH NEW_HEIGHT defines the new size.)
1306 */ )
1307 (Lisp_Object xwidget, Lisp_Object new_width, Lisp_Object new_height)
1309 CHECK_XWIDGET (xwidget);
1310 struct xwidget *xw = XXWIDGET (xwidget);
1311 struct xwidget_view *xv;
1312 int w, h;
1314 CHECK_NUMBER (new_width);
1315 CHECK_NUMBER (new_height);
1316 w = XFASTINT (new_width);
1317 h = XFASTINT (new_height);
1319 xw->width = w;
1320 xw->height = h;
1321 //if theres a osr resize it 1st
1322 if (xw->widget_osr)
1324 gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height); //minimum size
1325 //gtk_window_resize( GTK_WINDOW(xw->widget_osr), xw->width, xw->height);
1326 gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
1327 xw->height);
1328 gtk_window_resize (GTK_WINDOW (xw->widgetscrolledwindow_osr), xw->width,
1329 xw->height);
1330 gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW
1331 (xw->
1332 widgetscrolledwindow_osr),
1333 xw->height);
1334 gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW
1335 (xw->
1336 widgetscrolledwindow_osr),
1337 xw->width);
1339 //gtk_container_resize_children ( GTK_WINDOW(xw->widgetwindow_osr));
1340 gtk_container_resize_children (GTK_CONTAINER (xw->widgetwindow_osr));
1344 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail)) //TODO MVC refactor lazy linear search
1346 if (XWIDGET_VIEW_P (XCAR (tail)))
1348 xv = XXWIDGET_VIEW (XCAR (tail));
1349 if (XXWIDGET (xv->model) == xw)
1351 gtk_layout_set_size (GTK_LAYOUT (xv->widgetwindow), xw->width,
1352 xw->height);
1353 gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width,
1354 xw->height);
1359 return Qnil;
1364 DEFUN ("xwidget-set-adjustment", Fxwidget_set_adjustment, Sxwidget_set_adjustment, 4, 4, 0, doc:
1365 /* set scrolling */
1367 (Lisp_Object xwidget, Lisp_Object axis, Lisp_Object relative,
1368 Lisp_Object value)
1370 CHECK_XWIDGET (xwidget);
1371 struct xwidget *xw = XXWIDGET (xwidget);
1372 GtkAdjustment *adjustment;
1373 float final_value = 0.0;
1375 adjustment =
1376 gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
1377 (xw->widgetscrolledwindow_osr));
1378 if (EQ (Qvertical, axis))
1380 adjustment =
1381 gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
1382 (xw->widgetscrolledwindow_osr));
1384 if (EQ (Qhorizontal, axis))
1386 adjustment =
1387 gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW
1388 (xw->widgetscrolledwindow_osr));
1391 if (EQ (Qt, relative))
1393 final_value = gtk_adjustment_get_value (adjustment) + XFASTINT (value);
1395 else
1397 final_value = 0.0 + XFASTINT (value);
1400 gtk_adjustment_set_value (adjustment, final_value);
1402 return Qnil;
1406 DEFUN ("xwidget-size-request", Fxwidget_size_request, Sxwidget_size_request, 1, 1, 0, doc:
1407 /* Desired size of the XWIDGET.
1409 This can be used to read the xwidget desired size, and resizes the Emacs allocated area accordingly.
1411 (TODO crashes if arg not osr widget) */
1413 (Lisp_Object xwidget)
1415 CHECK_XWIDGET (xwidget);
1416 GtkRequisition requisition;
1417 Lisp_Object rv;
1418 gtk_widget_size_request (XXWIDGET (xwidget)->widget_osr, &requisition);
1419 rv = Qnil;
1420 rv = Fcons (make_number (requisition.height), rv);
1421 rv = Fcons (make_number (requisition.width), rv);
1422 return rv;
1426 DEFUN ("xwidgetp", Fxwidgetp, Sxwidgetp, 1, 1, 0, doc: /* Return t if OBJECT is a xwidget. */
1428 (Lisp_Object object)
1430 return XWIDGETP (object) ? Qt : Qnil;
1433 DEFUN ("xwidget-view-p", Fxwidget_view_p, Sxwidget_view_p, 1, 1, 0, doc:/* Return t if OBJECT is a xwidget-view. */
1435 (Lisp_Object object)
1437 return XWIDGET_VIEW_P (object) ? Qt : Qnil;
1440 DEFUN ("xwidget-info", Fxwidget_info, Sxwidget_info, 1, 1, 0, doc: /* Get XWIDGET properties.
1441 Currently type, title, width, height. */ )
1442 (Lisp_Object xwidget)
1444 CHECK_XWIDGET (xwidget);
1445 Lisp_Object info, n;
1446 struct xwidget *xw = XXWIDGET (xwidget);
1448 info = Fmake_vector (make_number (4), Qnil);
1449 ASET (info, 0, xw->type);
1450 ASET (info, 1, xw->title);
1451 XSETFASTINT (n, xw->width);
1452 ASET (info, 2, n);
1453 XSETFASTINT (n, xw->height);
1454 ASET (info, 3, n);
1456 return info;
1459 DEFUN ("xwidget-view-info", Fxwidget_view_info, Sxwidget_view_info, 1, 1, 0, doc:
1460 /* Get XWIDGET-VIEW properties.
1461 Currently x,y clip right, clip bottom, clip top, clip left */
1463 (Lisp_Object xwidget_view)
1465 CHECK_XWIDGET_VIEW (xwidget_view);
1466 struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
1467 Lisp_Object info;
1469 info = Fmake_vector (make_number (6), Qnil);
1470 ASET (info, 0, make_number (xv->x));
1471 ASET (info, 1, make_number (xv->y));
1472 ASET (info, 2, make_number (xv->clip_right));
1473 ASET (info, 3, make_number (xv->clip_bottom));
1474 ASET (info, 4, make_number (xv->clip_top));
1475 ASET (info, 5, make_number (xv->clip_left));
1477 return info;
1480 DEFUN ("xwidget-view-model", Fxwidget_view_model, Sxwidget_view_model, 1, 1, 0, doc: /* Get XWIDGET-VIEW model. */
1482 (Lisp_Object xwidget_view)
1484 CHECK_XWIDGET_VIEW (xwidget_view);
1485 return XXWIDGET_VIEW (xwidget_view)->model;
1488 DEFUN ("xwidget-view-window", Fxwidget_view_window, Sxwidget_view_window, 1, 1, 0, doc:/* Get XWIDGET-VIEW window. */
1490 (Lisp_Object xwidget_view)
1492 CHECK_XWIDGET_VIEW (xwidget_view);
1493 return XXWIDGET_VIEW (xwidget_view)->w;
1496 DEFUN ("xwidget-send-keyboard-event", Fxwidget_send_keyboard_event, Sxwidget_send_keyboard_event, 2, 2, 0, doc:/* Synthesize a kbd event for XWIDGET. TODO crashes atm.. */
1497 )(Lisp_Object xwidget,
1498 Lisp_Object keydescriptor)
1500 //TODO this code crashes for offscreen widgets and ive tried many different strategies
1501 //int keyval = 0x058; //X
1502 int keyval = XFASTINT (keydescriptor); //X
1503 GdkKeymapKey *keys;
1504 gint n_keys;
1505 GdkDeviceManager *manager;
1506 struct xwidget *xw;
1507 GtkWidget *widget;
1508 GdkEventKey *ev;
1509 Lisp_Object window;
1510 //popup_activated_flag = 1; //TODO just a hack
1511 gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (), keyval, &keys,
1512 &n_keys);
1514 xw = XXWIDGET (xwidget);
1516 ev = (GdkEventKey *) gdk_event_new (GDK_KEY_PRESS);
1519 //todo what about windowless widgets?
1521 window = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
1524 //TODO maybe we also need to special case sockets by picking up the plug rather than the socket
1525 if (xw->widget_osr)
1526 widget = xw->widget_osr;
1527 else
1528 widget = xwidget_view_lookup (xw, XWINDOW (window))->widget;
1530 ev->window = gtk_widget_get_window (widget);
1531 gtk_widget_grab_focus (widget);
1532 ev->send_event = FALSE;
1534 ev->hardware_keycode = keys[0].keycode;
1535 ev->group = keys[0].group;
1537 ev->keyval = keyval;
1538 ev->time = GDK_CURRENT_TIME;
1540 //ev->device = gdk_device_get_core_pointer();
1541 manager =
1542 gdk_display_get_device_manager (gdk_window_get_display (ev->window));
1543 gdk_event_set_device ((GdkEvent *) ev,
1544 gdk_device_manager_get_client_pointer (manager));
1545 gdk_event_put ((GdkEvent *) ev);
1546 //g_signal_emit_by_name(ev->window,"key-press-event", ev);
1548 ev->type = GDK_KEY_RELEASE;
1549 gdk_event_put ((GdkEvent *) ev);
1550 //g_signal_emit_by_name(ev->window,"key-release-event", ev);
1551 //gtk_main_do_event(ev);
1553 //TODO
1554 //if I delete the event the receiving component eventually crashes.
1555 //it ough TDTRT since event_put is supposed to copy the event
1556 //so probably this leaks events now
1557 //gdk_event_free((GdkEvent*)ev);
1559 return Qnil;
1562 DEFUN ("delete-xwidget-view", Fdelete_xwidget_view, Sdelete_xwidget_view, 1, 1, 0, doc:/* Delete the XWIDGET-VIEW. */
1564 (Lisp_Object xwidget_view)
1566 CHECK_XWIDGET_VIEW (xwidget_view);
1567 struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
1568 gtk_widget_destroy (xv->widgetwindow);
1569 Vxwidget_view_list = Fdelq (xwidget_view, Vxwidget_view_list);
1570 return Qnil;
1573 DEFUN ("xwidget-view-lookup", Fxwidget_view_lookup, Sxwidget_view_lookup, 1, 2, 0, doc:/* Return the xwidget-view associated to XWIDGET in
1574 WINDOW if specified, otherwise it uses the selected window. */
1576 (Lisp_Object xwidget, Lisp_Object window)
1578 CHECK_XWIDGET (xwidget);
1580 if (NILP (window))
1581 window = Fselected_window ();
1582 CHECK_WINDOW (window);
1584 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
1585 tail = XCDR (tail))
1587 Lisp_Object xwidget_view = XCAR (tail);
1588 if (EQ (Fxwidget_view_model (xwidget_view), xwidget)
1589 && EQ (Fxwidget_view_window (xwidget_view), window))
1590 return xwidget_view;
1593 return Qnil;
1596 DEFUN ("set-frame-visible", Fset_frame_visible, Sset_frame_visible, 2, 2, 0, doc: /* HACKY */
1598 (Lisp_Object frame, Lisp_Object flag)
1600 CHECK_FRAME (frame);
1601 struct frame *f = XFRAME (frame);
1602 SET_FRAME_VISIBLE (f, !NILP (flag));
1603 return flag;
1606 DEFUN ("xwidget-plist", Fxwidget_plist, Sxwidget_plist, 1, 1, 0, doc: /* Return the plist of XWIDGET. */
1608 (register Lisp_Object xwidget)
1610 CHECK_XWIDGET (xwidget);
1611 return XXWIDGET (xwidget)->plist;
1614 DEFUN ("xwidget-buffer", Fxwidget_buffer, Sxwidget_buffer, 1, 1, 0, doc:/* Return the buffer of XWIDGET. */
1616 (register Lisp_Object xwidget)
1618 CHECK_XWIDGET (xwidget);
1619 return XXWIDGET (xwidget)->buffer;
1622 DEFUN ("set-xwidget-plist", Fset_xwidget_plist, Sset_xwidget_plist, 2, 2, 0, doc: /* Replace the plist of XWIDGET with PLIST. Returns PLIST. */
1624 (register Lisp_Object xwidget, Lisp_Object plist)
1626 CHECK_XWIDGET (xwidget);
1627 CHECK_LIST (plist);
1629 XXWIDGET (xwidget)->plist = plist;
1630 return plist;
1633 DEFUN ("set-xwidget-query-on-exit-flag", Fset_xwidget_query_on_exit_flag, Sset_xwidget_query_on_exit_flag, 2, 2, 0, doc:
1634 /* Specify if query is needed for XWIDGET when Emacs is
1635 exited. If the second argument FLAG is non-nil, Emacs will query the
1636 user before exiting or killing a buffer if XWIDGET is running. This
1637 function returns FLAG. */
1639 (Lisp_Object xwidget, Lisp_Object flag)
1641 CHECK_XWIDGET (xwidget);
1642 XXWIDGET (xwidget)->kill_without_query = NILP (flag);
1643 return flag;
1646 DEFUN ("xwidget-query-on-exit-flag", Fxwidget_query_on_exit_flag, Sxwidget_query_on_exit_flag, 1, 1, 0, doc: /* Return the current value of query-on-exit flag for XWIDGET. */
1648 (Lisp_Object xwidget)
1650 CHECK_XWIDGET (xwidget);
1651 return (XXWIDGET (xwidget)->kill_without_query ? Qnil : Qt);
1654 void
1655 syms_of_xwidget (void)
1658 defsubr (&Smake_xwidget);
1659 defsubr (&Sxwidgetp);
1660 DEFSYM (Qxwidgetp, "xwidgetp");
1661 defsubr (&Sxwidget_view_p);
1662 DEFSYM (Qxwidget_view_p, "xwidget-view-p");
1663 defsubr (&Sxwidget_info);
1664 defsubr (&Sxwidget_view_info);
1665 defsubr (&Sxwidget_resize);
1666 defsubr (&Sget_buffer_xwidgets);
1667 defsubr (&Sxwidget_view_model);
1668 defsubr (&Sxwidget_view_window);
1669 defsubr (&Sxwidget_view_lookup);
1670 defsubr (&Sxwidget_query_on_exit_flag);
1671 defsubr (&Sset_xwidget_query_on_exit_flag);
1672 defsubr (&Sset_frame_visible);
1674 #ifdef HAVE_WEBKIT_OSR
1675 defsubr (&Sxwidget_webkit_goto_uri);
1676 defsubr (&Sxwidget_webkit_execute_script);
1677 defsubr (&Sxwidget_webkit_get_title);
1678 DEFSYM (Qwebkit_osr, "webkit-osr");
1679 #endif
1681 defsubr (&Sxwgir_xwidget_call_method);
1682 defsubr (&Sxwgir_require_namespace);
1683 defsubr (&Sxwidget_size_request);
1684 defsubr (&Sdelete_xwidget_view);
1685 defsubr (&Sxwidget_disable_plugin_for_mime);
1687 defsubr (&Sxwidget_send_keyboard_event);
1688 #ifdef HAVE_XLXW_DOMDUMP
1689 defsubr (&Sxwidget_webkit_dom_dump);
1690 #endif
1692 defsubr (&Sxwidget_plist);
1693 defsubr (&Sxwidget_buffer);
1694 defsubr (&Sset_xwidget_plist);
1696 defsubr (&Sxwidget_set_adjustment);
1698 DEFSYM (Qxwidget, "xwidget");
1700 DEFSYM (QCxwidget, ":xwidget");
1701 DEFSYM (QCxwgir_class, ":xwgir-class");
1702 DEFSYM (QCtitle, ":title");
1704 /* Do not forget to update the docstring of make-xwidget if you add
1705 new types. */
1706 DEFSYM (Qbutton, "Button"); //changed to match the gtk class because xwgir(experimental and not really needed)
1707 DEFSYM (Qtoggle, "ToggleButton");
1708 DEFSYM (Qslider, "slider");
1709 DEFSYM (Qsocket, "socket");
1710 DEFSYM (Qsocket_osr, "socket-osr");
1711 DEFSYM (Qcairo, "cairo");
1713 DEFSYM (Qvertical, "vertical");
1714 DEFSYM (Qhorizontal, "horizontal");
1716 DEFSYM (QCplist, ":plist");
1718 DEFVAR_LISP ("xwidget-list", Vxwidget_list,
1719 doc: /* xwidgets list. */);
1720 Vxwidget_list = Qnil;
1722 DEFVAR_LISP ("xwidget-view-list", Vxwidget_view_list,
1723 doc: /* xwidget views list. */);
1724 Vxwidget_view_list = Qnil;
1726 Fprovide (intern ("xwidget-internal"), Qnil);
1731 /* Value is non-zero if OBJECT is a valid Lisp xwidget specification. A
1732 valid xwidget specification is a list whose car is the symbol
1733 `xwidget', and whose rest is a property list. The property list must
1734 contain a value for key `:type'. That value must be the name of a
1735 supported xwidget type. The rest of the property list depends on the
1736 xwidget type. */
1739 valid_xwidget_spec_p (Lisp_Object object)
1741 int valid_p = 0;
1743 if (CONSP (object) && EQ (XCAR (object), Qxwidget))
1745 /* Lisp_Object tem; */
1747 /* for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem)) */
1748 /* if (EQ (XCAR (tem), QCtype)) */
1749 /* { */
1750 /* tem = XCDR (tem); */
1751 /* if (CONSP (tem) && SYMBOLP (XCAR (tem))) */
1752 /* { */
1753 /* struct xwidget_type *type; */
1754 /* type = lookup_xwidget_type (XCAR (tem)); */
1755 /* if (type) */
1756 /* valid_p = type->valid_p (object); */
1757 /* } */
1759 /* break; */
1760 /* } */
1761 //never mind type support for now
1762 valid_p = 1;
1765 return valid_p;
1770 /* find a value associated with key in spec */
1771 Lisp_Object
1772 xwidget_spec_value (Lisp_Object spec, Lisp_Object key, int *found)
1774 Lisp_Object tail;
1776 eassert (valid_xwidget_spec_p (spec));
1778 for (tail = XCDR (spec);
1779 CONSP (tail) && CONSP (XCDR (tail)); tail = XCDR (XCDR (tail)))
1781 if (EQ (XCAR (tail), key))
1783 if (found)
1784 *found = 1;
1785 return XCAR (XCDR (tail));
1789 if (found)
1790 *found = 0;
1791 return Qnil;
1795 void
1796 xwidget_view_delete_all_in_window (struct window *w)
1798 struct xwidget_view *xv = NULL;
1799 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
1800 tail = XCDR (tail))
1802 if (XWIDGET_VIEW_P (XCAR (tail)))
1804 xv = XXWIDGET_VIEW (XCAR (tail));
1805 if (XWINDOW (xv->w) == w)
1807 gtk_widget_destroy (xv->widgetwindow);
1808 Vxwidget_view_list = Fdelq (XCAR (tail), Vxwidget_view_list);
1814 struct xwidget_view *
1815 xwidget_view_lookup (struct xwidget *xw, struct window *w)
1817 Lisp_Object xwidget, window, ret;
1818 XSETXWIDGET (xwidget, xw);
1819 XSETWINDOW (window, w);
1821 ret = Fxwidget_view_lookup (xwidget, window);
1823 return EQ (ret, Qnil) ? NULL : XXWIDGET_VIEW (ret);
1826 struct xwidget *
1827 lookup_xwidget (Lisp_Object spec)
1829 /* When a xwidget lisp spec is found initialize the C struct that is used in the C code.
1830 This is done by redisplay so values change if the spec changes.
1831 So, take special care of one-shot events
1833 TODO remove xwidget init from display spec. simply store an xwidget reference only and set
1834 size etc when creating the xwidget, which should happen before insertion into buffer
1836 int found = 0;
1837 Lisp_Object value;
1838 struct xwidget *xw;
1840 value = xwidget_spec_value (spec, QCxwidget, &found);
1841 xw = XXWIDGET (value);
1843 return xw;
1846 /*set up detection of touched xwidget*/
1847 void
1848 xwidget_start_redisplay (void)
1850 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
1851 tail = XCDR (tail))
1853 if (XWIDGET_VIEW_P (XCAR (tail)))
1854 XXWIDGET_VIEW (XCAR (tail))->redisplayed = 0;
1858 /* the xwidget was touched during redisplay, so it isnt a candidate for hiding*/
1859 void
1860 xwidget_touch (struct xwidget_view *xv)
1862 xv->redisplayed = 1;
1865 static int
1866 xwidget_touched (struct xwidget_view *xv)
1868 return xv->redisplayed;
1871 /* redisplay has ended, now we should hide untouched xwidgets
1873 void
1874 xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix)
1877 int i;
1878 int area;
1881 xwidget_start_redisplay ();
1882 //iterate desired glyph matrix of window here, hide gtk widgets
1883 //not in the desired matrix.
1885 //this only takes care of xwidgets in active windows.
1886 //if a window goes away from screen xwidget views wust be deleted
1888 // dump_glyph_matrix(matrix, 2);
1889 for (i = 0; i < matrix->nrows; ++i)
1891 // dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs);
1892 struct glyph_row *row;
1893 row = MATRIX_ROW (matrix, i);
1894 if (row->enabled_p != 0)
1896 for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
1898 struct glyph *glyph = row->glyphs[area];
1899 struct glyph *glyph_end = glyph + row->used[area];
1900 for (; glyph < glyph_end; ++glyph)
1902 if (glyph->type == XWIDGET_GLYPH)
1905 the only call to xwidget_end_redisplay is in dispnew
1906 xwidget_end_redisplay(w->current_matrix);
1908 xwidget_touch (xwidget_view_lookup (glyph->u.xwidget,
1909 w));
1916 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
1917 tail = XCDR (tail))
1919 if (XWIDGET_VIEW_P (XCAR (tail)))
1921 struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail));
1923 //"touched" is only meaningful for the current window, so disregard other views
1924 if (XWINDOW (xv->w) == w)
1926 if (xwidget_touched (xv))
1927 xwidget_show_view (xv);
1928 else
1929 xwidget_hide_view (xv);
1935 /* Kill all xwidget in BUFFER. */
1936 void
1937 kill_buffer_xwidgets (Lisp_Object buffer)
1939 Lisp_Object tail, xwidget;
1940 for (tail = Fget_buffer_xwidgets (buffer); CONSP (tail); tail = XCDR (tail))
1942 xwidget = XCAR (tail);
1943 Vxwidget_list = Fdelq (xwidget, Vxwidget_list);
1944 /* TODO free the GTK things in xw */
1946 CHECK_XWIDGET (xwidget);
1947 struct xwidget *xw = XXWIDGET (xwidget);
1948 if (xw->widget_osr && xw->widgetwindow_osr)
1950 gtk_widget_destroy (xw->widget_osr);
1951 gtk_widget_destroy (xw->widgetwindow_osr);
1957 #endif /* HAVE_XWIDGETS */