11 #include "blockinput.h"
12 #include "syssignal.h"
15 #include <X11/cursorfont.h>
18 #include <sys/types.h>
22 #include <sys/ioctl.h>
23 #endif /* ! defined (BSD_SYSTEM) */
27 #ifndef INCLUDED_FCNTL
36 #include "character.h"
40 #include "dispextern.h"
42 #include "termhooks.h"
45 #include "emacs-icon.h"
50 #include "intervals.h"
57 #include <X11/Shell.h>
59 #include <X11/extensions/Xcomposite.h>
60 #include <X11/extensions/Xrender.h>
62 #ifdef HAVE_SYS_TIME_H
71 #endif /* HAVE_X_WINDOWS */
77 //for gtk3; sockets and plugs
79 #include "emacsgtkfixed.h"
84 #ifdef HAVE_WEBKIT_OSR
85 #include <webkit/webkitwebview.h>
86 #include <webkit/webkitwebplugindatabase.h>
87 #include <webkit/webkitwebplugin.h>
88 #include <webkit/webkitglobals.h>
89 #include <webkit/webkitwebnavigationaction.h>
90 #include <webkit/webkitdownload.h>
91 #include <webkit/webkitwebpolicydecision.h>
95 #include <girepository.h>
99 //TODO embryo of lisp allocators for xwidgets
100 //TODO xwidget* should be Lisp_xwidget*
102 allocate_xwidget (void)
104 return ALLOCATE_PSEUDOVECTOR (struct xwidget
, height
, PVEC_XWIDGET
);
107 //TODO xwidget_view* should be Lisp_xwidget_view*
109 allocate_xwidget_view (void)
111 return ALLOCATE_PSEUDOVECTOR (struct xwidget_view
, redisplayed
, PVEC_XWIDGET_VIEW
);
113 #define XSETXWIDGET(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET))
114 #define XSETXWIDGET_VIEW(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW))
116 struct xwidget_view
* xwidget_view_lookup(struct xwidget
* xw
, struct window
*w
);
117 Lisp_Object
xwidget_spec_value ( Lisp_Object spec
, Lisp_Object key
, int *found
);
118 gboolean
offscreen_damage_event (GtkWidget
*widget
, GdkEvent
*event
, gpointer data
);
119 void webkit_osr_document_load_finished_callback (WebKitWebView
*webkitwebview
,
120 WebKitWebFrame
*arg1
,
122 gboolean
webkit_osr_download_callback (WebKitWebView
*webkitwebview
,
123 WebKitDownload
*arg1
,
126 gboolean
webkit_osr_mime_type_policy_typedecision_requested_callback(WebKitWebView
*webView
,
127 WebKitWebFrame
*frame
,
128 WebKitNetworkRequest
*request
,
130 WebKitWebPolicyDecision
*policy_decision
,
133 gboolean
webkit_osr_new_window_policy_decision_requested_callback(WebKitWebView
*webView
,
134 WebKitWebFrame
*frame
,
135 WebKitNetworkRequest
*request
,
136 WebKitWebNavigationAction
*navigation_action
,
137 WebKitWebPolicyDecision
*policy_decision
,
141 gboolean
webkit_osr_navigation_policy_decision_requested_callback(WebKitWebView
*webView
,
142 WebKitWebFrame
*frame
,
143 WebKitNetworkRequest
*request
,
144 WebKitWebNavigationAction
*navigation_action
,
145 WebKitWebPolicyDecision
*policy_decision
,
148 GtkWidget
* xwgir_create(char* class, char* namespace);
150 send_xembed_ready_event (struct xwidget
* xw
, int xembedid
);
151 DEFUN ("make-xwidget", Fmake_xwidget
, Smake_xwidget
, 7, 8, 0,
152 doc
: /* Make an xwidget from BEG to END of TYPE.
154 If BUFFER is nil it uses the current buffer. If BUFFER is a string and
155 no such buffer exists, it is created.
157 TYPE is a symbol which can take one of the following values:
166 (Lisp_Object beg
, Lisp_Object end
,
169 Lisp_Object width
, Lisp_Object height
,
173 //should work a bit like "make-button"(make-button BEG END &rest PROPERTIES)
174 // arg "type" and fwd should be keyword args eventually
175 //(make-xwidget 3 3 'button "oei" 31 31 nil)
176 //(xwidget-info (car xwidget-list))
177 struct xwidget
* xw
= allocate_xwidget();
182 buffer
= Fcurrent_buffer(); // no need to gcpro because Fcurrent_buffer doesn't call Feval/eval_sub.
184 buffer
= Fget_buffer_create (buffer
);
187 xw
->height
= XFASTINT(height
);
188 xw
->width
= XFASTINT(width
);
189 xw
->kill_without_query
= 0;
190 XSETXWIDGET (val
, xw
); // set the vectorlike_header of VAL with the correct value
191 Vxwidget_list
= Fcons (val
, Vxwidget_list
);
192 xw
->widgetwindow_osr
= NULL
;
193 xw
->widget_osr
= NULL
;
197 #ifdef HAVE_WEBKIT_OSR
198 /* DIY mvc. widget is rendered offscreen,
199 later bitmap copied to the views.
201 if (EQ(xw
->type
, Qwebkit_osr
)||
202 EQ(xw
->type
, Qsocket_osr
)||
203 (!NILP (Fget(xw
->type
, QCxwgir_class
)))) {
205 xw
->widgetwindow_osr
= gtk_offscreen_window_new ();
206 gtk_window_resize(GTK_WINDOW(xw
->widgetwindow_osr
), xw
->width
, xw
->height
);
208 if (EQ(xw
->type
, Qwebkit_osr
))
209 xw
->widget_osr
= webkit_web_view_new();
210 if(EQ(xw
->type
, Qsocket_osr
))
211 xw
->widget_osr
= gtk_socket_new();
212 if(!NILP (Fget(xw
->type
, QCxwgir_class
)))
213 xw
->widget_osr
= xwgir_create(SDATA(Fcar(Fcdr(Fget(xw
->type
, QCxwgir_class
)))),
214 SDATA(Fcar(Fget(xw
->type
, QCxwgir_class
))));
216 gtk_widget_set_size_request (GTK_WIDGET (xw
->widget_osr
), xw
->width
, xw
->height
);
217 gtk_container_add (GTK_CONTAINER (xw
->widgetwindow_osr
), xw
->widget_osr
);
219 gtk_widget_show (xw
->widget_osr
);
220 gtk_widget_show (xw
->widgetwindow_osr
);
222 /* store some xwidget data in the gtk widgets for convenient retrieval in the event handlers. */
223 g_object_set_data (G_OBJECT (xw
->widget_osr
), XG_XWIDGET
, (gpointer
) (xw
));
224 g_object_set_data (G_OBJECT (xw
->widgetwindow_osr
), XG_XWIDGET
, (gpointer
) (xw
));
227 if (EQ(xw
->type
, Qwebkit_osr
)) {
228 g_signal_connect (G_OBJECT (xw
->widget_osr
),
229 "document-load-finished",
230 G_CALLBACK (webkit_osr_document_load_finished_callback
),
233 g_signal_connect (G_OBJECT (xw
->widget_osr
),
234 "download-requested",
235 G_CALLBACK (webkit_osr_download_callback
),
238 g_signal_connect (G_OBJECT (xw
->widget_osr
),
239 "mime-type-policy-decision-requested",
240 G_CALLBACK (webkit_osr_mime_type_policy_typedecision_requested_callback
),
243 g_signal_connect (G_OBJECT (xw
->widget_osr
),
244 "new-window-policy-decision-requested",
245 G_CALLBACK (webkit_osr_new_window_policy_decision_requested_callback
),
248 g_signal_connect (G_OBJECT (xw
->widget_osr
),
249 "navigation-policy-decision-requested",
250 G_CALLBACK (webkit_osr_navigation_policy_decision_requested_callback
),
254 if (EQ(xw
->type
, Qsocket_osr
)) {
255 send_xembed_ready_event (xw
, gtk_socket_get_id (GTK_SOCKET (xw
->widget_osr
)));
256 //gtk_widget_realize(xw->widget);
263 #endif /* HAVE_WEBKIT_OSR */
268 DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets
, Sget_buffer_xwidgets
, 1, 1, 0,
269 doc
: /* Return a list of xwidgets associated with BUFFER.
270 BUFFER may be a buffer or the name of one.
275 Lisp_Object xw
, tail
, xw_list
;
277 if (NILP (buffer
)) return Qnil
;
278 buffer
= Fget_buffer (buffer
);
279 if (NILP (buffer
)) return Qnil
;
283 for (tail
= Vxwidget_list
; CONSP (tail
); tail
= XCDR (tail
))
286 if (XWIDGETP (xw
) && EQ (Fxwidget_buffer (xw
), buffer
))
287 xw_list
= Fcons (xw
, xw_list
);
293 xwidget_hidden(struct xwidget_view
*xv
)
300 buttonclick_handler (GtkWidget
* widget
, gpointer data
)
302 Lisp_Object xwidget_view
, xwidget
;
303 XSETXWIDGET_VIEW (xwidget_view
, (struct xwidget_view
*) data
);
304 xwidget
= Fxwidget_view_model (xwidget_view
);
306 struct input_event event
;
307 Lisp_Object frame
= Fwindow_frame (Fxwidget_view_window (xwidget_view
));
308 struct frame
*f
= XFRAME (frame
);
309 printf ("button clicked xw:%d '%s'\n", XXWIDGET (xwidget
), XXWIDGET (xwidget
)->title
);
312 event
.kind
= XWIDGET_EVENT
;
314 event
.frame_or_window
= frame
;
317 event
.arg
= Fcons (xwidget
, event
.arg
);
318 event
.arg
= Fcons (intern ("buttonclick"), event
.arg
);
320 kbd_buffer_store_event (&event
);
325 send_xembed_ready_event (struct xwidget
* xw
, int xembedid
)
328 XSETXWIDGET(xw_lo
, xw
);
329 struct input_event event
;
331 event
.kind
= XWIDGET_EVENT
;
332 event
.frame_or_window
= Qnil
; //frame; //how to get the frame here? //TODO i store it in the xwidget now
335 event
.arg
= Fcons (make_number (xembedid
), event
.arg
);
336 event
.arg
= Fcons (xw_lo
, event
.arg
);
337 event
.arg
= Fcons (intern ("xembed-ready"), event
.arg
);
340 kbd_buffer_store_event (&event
);
345 xwidget_show_view (struct xwidget_view
*xv
)
348 gtk_widget_show(xv
->widgetwindow
);
349 gtk_fixed_move (GTK_FIXED (xv
->emacswindow
), xv
->widgetwindow
, xv
->x
+ xv
->clip_left
, xv
->y
+ xv
->clip_top
); //TODO refactor
353 /* hide an xvidget view */
355 xwidget_hide_view (struct xwidget_view
*xv
)
358 //gtk_widget_hide(xw->widgetwindow);
359 gtk_fixed_move (GTK_FIXED (xv
->emacswindow
), xv
->widgetwindow
,
365 xwidget_plug_added(GtkSocket
*socket
,
368 //hmm this doesnt seem to get called for foreign windows
369 printf("xwidget_plug_added\n");
373 xwidget_plug_removed(GtkSocket
*socket
,
376 printf("xwidget_plug_removed\n");
377 return TRUE
; /* dont run the default handler because that kills the socket and we want to reuse it*/
382 xwidget_slider_changed (GtkRange
*range
,
385 //slider value changed. change value of siblings
386 //correspondingly. but remember that changing value will again
389 //TODO MVC view storage wont be an array futureish so the loop needs to change eventually
390 //TODO MVC it would be nice if this code could be reusable but, alas, C is not a functional language
392 // - the type of the controllers value (double, boolean etc)
393 // - the getter and setter (but they can be func pointers)
394 // a behemoth macro is always an option.
395 double v
=gtk_range_get_value(range
);
396 struct xwidget_view
* xvp
= g_object_get_data (G_OBJECT (range
), XG_XWIDGET_VIEW
);
397 struct xwidget_view
* xv
;
399 printf("slider changed val:%f\n", v
);
401 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
); tail
= XCDR (tail
))
403 if (XWIDGET_VIEW_P (XCAR (tail
))) {
404 xv
= XXWIDGET_VIEW (XCAR (tail
));
405 if (EQ (xvp
->model
, xv
->model
)) {
406 //block sibling views signal handlers
407 g_signal_handler_block(xv
->widget
, xv
->handler_id
);
409 //set values of sibling views and unblock
410 gtk_range_set_value(GTK_RANGE(xv
->widget
), v
);
411 g_signal_handler_unblock(xv
->widget
,xv
->handler_id
);
418 /* when the off-screen webkit master view changes this signal is called.
419 it copies the bitmap from the off-screen webkit instance */
421 offscreen_damage_event (GtkWidget
*widget
, GdkEvent
*event
, gpointer data
)
423 //TODO this is wrong! should just queu a redraw of onscreen widget
424 gtk_widget_queue_draw (GTK_WIDGET (data
));
429 store_xwidget_event_string(struct xwidget
* xw
, char* eventname
, const char* eventstr
)
432 struct input_event event
;
436 event
.kind
= XWIDGET_EVENT
;
437 event
.frame_or_window
= Qnil
; //frame; //how to get the frame here? //TODO i store it in the xwidget now
440 event
.arg
= Fcons (build_string(eventstr
), event
.arg
); //string so dont intern
441 event
.arg
= Fcons (xwl
, event
.arg
); //TODO
442 event
.arg
= Fcons (intern (eventname
), event
.arg
);//interning should be ok
443 kbd_buffer_store_event (&event
);
447 //TODO deprecated, use load-status
449 webkit_osr_document_load_finished_callback (WebKitWebView
*webkitwebview
,
450 WebKitWebFrame
*arg1
,
453 //TODO this event sending code should be refactored
454 // struct xwidget *xw = (struct xwidget *) data;
455 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (webkitwebview
), XG_XWIDGET
);
456 printf("webkit finished loading\n");
458 store_xwidget_event_string(xw
,
459 "document-load-finished", "");
463 webkit_osr_download_callback (WebKitWebView
*webkitwebview
,
464 WebKitDownload
*arg1
,
467 //TODO this event sending code should be refactored
468 struct input_event event
;
469 // struct xwidget *xw = (struct xwidget *) data;
470 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (webkitwebview
), XG_XWIDGET
);
471 printf("download requested %s\n", webkit_download_get_uri (arg1
));
474 printf("webkit finished loading\n");
476 store_xwidget_event_string(xw
, "download-requested", webkit_download_get_uri (arg1
));
482 webkit_osr_mime_type_policy_typedecision_requested_callback(WebKitWebView
*webView
,
483 WebKitWebFrame
*frame
,
484 WebKitNetworkRequest
*request
,
486 WebKitWebPolicyDecision
*policy_decision
,
489 printf("mime policy requested\n");
490 // this function makes webkit send a download signal for all unknown mime types
491 // TODO defer the decision to lisp, so that its possible to make Emacs handle text mime for instance
492 if(!webkit_web_view_can_show_mime_type(webView
, mimetype
)){
493 webkit_web_policy_decision_download (policy_decision
);
502 webkit_osr_new_window_policy_decision_requested_callback(WebKitWebView
*webView
,
503 WebKitWebFrame
*frame
,
504 WebKitNetworkRequest
*request
,
505 WebKitWebNavigationAction
*navigation_action
,
506 WebKitWebPolicyDecision
*policy_decision
,
509 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (webView
), XG_XWIDGET
);
510 printf("webkit_osr_new_window_policy_decision_requested_callback %s\n",
511 webkit_web_navigation_action_get_original_uri (navigation_action
));
513 store_xwidget_event_string(xw
, "new-window-policy-decision-requested", webkit_web_navigation_action_get_original_uri (navigation_action
)
519 webkit_osr_navigation_policy_decision_requested_callback(WebKitWebView
*webView
,
520 WebKitWebFrame
*frame
,
521 WebKitNetworkRequest
*request
,
522 WebKitWebNavigationAction
*navigation_action
,
523 WebKitWebPolicyDecision
*policy_decision
,
526 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (webView
), XG_XWIDGET
);
527 printf("webkit_osr_navigation_policy_decision_requested_callback %s\n",
528 webkit_web_navigation_action_get_original_uri (navigation_action
));
529 store_xwidget_event_string(xw
, "navigation-policy-decision-requested", webkit_web_navigation_action_get_original_uri (navigation_action
)
534 //for gtk3 offscreen rendered widgets
536 xwidget_osr_draw_callback (GtkWidget
*widget
, cairo_t
*cr
, gpointer data
)
538 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (widget
), XG_XWIDGET
);
539 struct xwidget_view
* xv
= (struct xwidget_view
*) g_object_get_data (G_OBJECT (widget
), XG_XWIDGET_VIEW
);
541 cairo_rectangle(cr
, 0,0, xv
->clip_right
, xv
->clip_bottom
);//xw->width, xw->height);
544 gtk_widget_draw (xw
->widget_osr
, cr
);
549 GtkWidget
* xwgir_create_debug
;
554 xwidget_osr_event_forward (GtkWidget
*widget
,
558 /* copy events that arrive at the outer widget to the offscreen widget */
559 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (widget
), XG_XWIDGET
);
560 GdkEvent
* eventcopy
= gdk_event_copy(event
);
561 //GdkEvent* eventcopy = gdk_event_new(GDK_BUTTON_PRESS);
564 //((GdkEventAny*)eventcopy)->window = gtk_widget_get_window(xw->widget_osr);
565 //eventcopy->any.window = gtk_widget_get_window(GTK_WIDGET (xw->widgetwindow_osr));
566 //((GdkEventAny*)eventcopy)->window = gtk_widget_get_window(xwgir_create_debug);
567 eventcopy
->any
.window
= gtk_widget_get_window(xw
->widget_osr
);//gtk_widget_get_window(xwgir_create_debug);
568 //eventcopy->any.window = gtk_button_get_event_window(GTK_BUTTON(xw->widget_osr));//gtk_widget_get_window(xwgir_create_debug);
569 //eventcopy->button.x=200; eventcopy->button.y=200;
570 //event->button.button = GDK_BUTTON_PRIMARY; //debug
572 //eventcopy->any.window = xw->widgetwindow_osr;//gtk_widget_get_window(xwgir_create_debug);
573 /* eventcopy->any.send_event = TRUE; */
574 /* eventcopy->button.time = GDK_CURRENT_TIME; */
575 /* eventcopy->button.device = event->button.device; */
578 printf("xwidget_osr_event_forward redirect event to window:%d\n", ((GdkEventAny
*)eventcopy
)->window
);
579 printf("A type:%d x:%f y:%f \n", event
->type
, event
->button
.x
, event
->button
.y
);
580 printf("B type:%d x:%f y:%f \n", eventcopy
->type
, eventcopy
->button
.x
, eventcopy
->button
.y
);
581 //gtk_button_get_event_window(xwgir_create_debug);
582 gtk_main_do_event(eventcopy
); //TODO this will leak events. they should be deallocated later, perhaps in xwgir_event_callback
583 //printf("gtk_widget_event:%d\n",gtk_widget_event(xw->widget_osr, eventcopy));
584 //gdk_event_put(eventcopy);
585 //gdk_event_queue_append(eventcopy);
586 //gdk_event_free(eventcopy);
587 return TRUE
; //dont propagate this event furter
588 //return FALSE; //dont propagate this event furter
591 GIRepository
*girepository
;
593 DEFUN ("xwgir-require-namespace", Fxwgir_require_namespace
, Sxwgir_require_namespace
, 2,2,0,
594 doc
: /* Require a GObject Introspection namespace.
595 This must be done for all namespaces we want to use, before using other xwgir functions.*/)
596 (Lisp_Object lnamespace
, Lisp_Object lnamespace_version
)
598 char* namespace = SDATA(lnamespace
);
599 char* namespace_version
= SDATA(lnamespace_version
);
600 GError
*error
= NULL
;
602 girepository
= g_irepository_get_default();
603 g_irepository_require(girepository
, namespace, namespace_version
, 0, &error
);
605 g_error("ERROR: %s\n", error
->message
);
611 GtkWidget
* xwgir_create(char* class, char* namespace){
612 //TODO this is more or less the same as xwgir-call-method, so should be refactored
613 //create a gtk widget, given its name
614 //find the constructor
616 //also figure out how to pass args
618 GError
*error
= NULL
;
619 GIArgument return_value
;
621 GIObjectInfo
* obj_info
= g_irepository_find_by_name(girepository
, namespace, class);
622 GIFunctionInfo
* f_info
= g_object_info_find_method (obj_info
, "new");
623 g_function_info_invoke(f_info
,
628 xwgir_create_debug
= return_value
.v_pointer
;
629 return return_value
.v_pointer
;
634 xwgir_convert_lisp_to_gir_arg(GIArgument
* giarg
,
636 Lisp_Object lisparg
)
642 tag
= g_type_info_get_tag (g_arg_info_get_type (arginfo
));
646 case GI_TYPE_TAG_BOOLEAN
:
647 giarg
->v_boolean
= XFASTINT(lisparg
);
649 case GI_TYPE_TAG_INT8
:
650 giarg
->v_int8
= XFASTINT(lisparg
);
652 case GI_TYPE_TAG_UINT8
:
653 giarg
->v_uint8
= XFASTINT(lisparg
);
655 case GI_TYPE_TAG_INT16
:
656 giarg
->v_int16
= XFASTINT(lisparg
);
658 case GI_TYPE_TAG_UINT16
:
659 giarg
->v_uint16
= XFASTINT(lisparg
);
661 case GI_TYPE_TAG_INT32
:
662 giarg
->v_int32
= XFASTINT(lisparg
);
664 case GI_TYPE_TAG_UINT32
:
665 giarg
->v_uint32
= XFASTINT(lisparg
);
668 case GI_TYPE_TAG_INT64
:
669 giarg
->v_int64
= XFASTINT(lisparg
);
671 case GI_TYPE_TAG_UINT64
:
672 giarg
->v_uint64
= XFASTINT(lisparg
);
676 case GI_TYPE_TAG_FLOAT
:
677 giarg
->v_float
= XFLOAT_DATA(lisparg
);
680 case GI_TYPE_TAG_DOUBLE
:
681 giarg
->v_double
= XFLOAT_DATA(lisparg
);
684 case GI_TYPE_TAG_UTF8
:
685 case GI_TYPE_TAG_FILENAME
:
686 //giarg->v_string = SDATA(lisparg);
687 giarg
->v_pointer
= SDATA(lisparg
);
690 case GI_TYPE_TAG_ARRAY
:
691 case GI_TYPE_TAG_GLIST
:
692 case GI_TYPE_TAG_GSLIST
:
693 case GI_TYPE_TAG_GHASH
:
694 case GI_TYPE_TAG_ERROR
:
695 case GI_TYPE_TAG_INTERFACE
:
696 case GI_TYPE_TAG_VOID
:
697 case GI_TYPE_TAG_UNICHAR
:
698 case GI_TYPE_TAG_GTYPE
:
699 //?? i dont know how to handle these yet TODO
700 printf("failed in my lisp to gir arg conversion duties. sob!\n");
710 //this methhod should be called from xwgir-xwidget-call-method and from xwgir xwidget construction
711 char* class = SDATA(Fcar(Fcdr(Fget(xw
->type
, QCxwgir_class
))));
713 GIObjectInfo
* obj_info
= g_irepository_find_by_name(girepository
, namespace, class);
714 GIFunctionInfo
* f_info
= g_object_info_find_method (obj_info
, SDATA(method
));
716 //loop over args, convert from lisp to primitive type, given arg introspection data
717 //TODO g_callable_info_get_n_args(f_info) should match
718 int argscount
= XFASTINT(Flength(arguments
));
719 if(argscount
!= g_callable_info_get_n_args(f_info
)){
720 printf("xwgir call method arg count doesn match! \n");
724 for (i
= 1; i
< argscount
+ 1; ++i
)
726 xwgir_convert_lisp_to_gir_arg(&in_args
[i
], g_callable_info_get_arg(f_info
, i
- 1), Fnth(i
- 1, arguments
));
729 in_args
[0].v_pointer
= widget
;
730 if(g_function_info_invoke(f_info
,
731 in_args
, argscount
+ 1,
735 //g_error("ERROR: %s\n", error->message);
736 printf("invokation error\n");
743 DEFUN ("xwgir-xwidget-call-method", Fxwgir_xwidget_call_method
, Sxwgir_xwidget_call_method
, 3, 3, 0,
744 doc
: /* Call Xwidget object method using GObject Introspection.
745 XWIDGET is the xwidget instance to act upon.
746 METHOD is the Gobject intrsopsection method name.
747 ARGUMENTS is a list of arguments for the call. They will be converted to GObject types from Lisp types.
749 (Lisp_Object xwidget
, Lisp_Object method
, Lisp_Object arguments
)
751 CHECK_XWIDGET (xwidget
);
752 GError
*error
= NULL
;
753 GIArgument return_value
;
754 GIArgument in_args
[20];
758 if (NILP (xwidget
)) { printf("ERROR xwidget nil\n"); return Qnil
; };
759 xw
= XXWIDGET(xwidget
);
760 if(NULL
== xw
) printf("ERROR xw is 0\n");
761 char* namespace = SDATA(Fcar(Fget(xw
->type
, QCxwgir_class
)));
762 //we need the concrete widget, which happens in 2 ways depending on OSR or not TODO
763 GtkWidget
* widget
= NULL
;
764 if(NULL
== xw
->widget_osr
) {
765 widget
= xwidget_view_lookup (xw
, XWINDOW(FRAME_SELECTED_WINDOW (SELECTED_FRAME ()))) -> widget
;
767 widget
= xw
->widget_osr
;
770 //char* class = SDATA(SYMBOL_NAME(xw->type)); //this works but is unflexible
771 //figure out the class from the widget instead
772 /* printf("type class: %s %s\n", G_OBJECT_TYPE_NAME(widget), G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(widget))); */
773 /* char* class = G_OBJECT_TYPE_NAME(widget); //gives "GtkButton"(I want "Button") */
774 /* class += strlen(namespace); //TODO check for corresponding api method. but this seems to work. */
776 char* class = SDATA(Fcar(Fcdr(Fget(xw
->type
, QCxwgir_class
))));
778 GIObjectInfo
* obj_info
= g_irepository_find_by_name(girepository
, namespace, class);
779 GIFunctionInfo
* f_info
= g_object_info_find_method (obj_info
, SDATA(method
));
781 //loop over args, convert from lisp to primitive type, given arg introspection data
782 //TODO g_callable_info_get_n_args(f_info) should match
783 int argscount
= XFASTINT(Flength(arguments
));
784 if(argscount
!= g_callable_info_get_n_args(f_info
)){
785 printf("xwgir call method arg count doesn match! \n");
790 for (i
= 1; i
< argscount
+ 1; ++i
)
792 XSETFASTINT (n
, i
- 1);
793 xwgir_convert_lisp_to_gir_arg(&in_args
[i
], g_callable_info_get_arg(f_info
, i
- 1), Fnth(n
, arguments
));
796 in_args
[0].v_pointer
= widget
;
797 if(g_function_info_invoke(f_info
,
798 in_args
, argscount
+ 1,
802 //g_error("ERROR: %s\n", error->message);
803 printf("invokation error\n");
810 to_child (GtkWidget
*bin
,
822 offscreen_pick_embedded_child (GdkWindow
*window
,
827 //in this simple case we assume the window contains a single widget. easy.
828 //but then we get the problem that the widget cant be embedded in several windows
829 return gtk_widget_get_window (GTK_WIDGET (data
));
833 offscreen_to_embedder (GdkWindow
*window
,
840 * (gdouble
*) embedder_x
= offscreen_x
;
841 * (gdouble
*) embedder_y
= offscreen_y
;
845 offscreen_from_embedder (GdkWindow
*window
,
848 gpointer offscreen_x
,
849 gpointer offscreen_y
,
852 * (gdouble
*) offscreen_x
= embedder_x
;
853 * (gdouble
*) offscreen_y
= embedder_y
;
857 xwidget_osr_event_set_embedder (GtkWidget
*widget
,
861 struct xwidget_view
*xv
= (struct xwidget_view
*) data
;
862 struct xwidget
*xww
= XXWIDGET (xv
->model
);
863 printf("gdk_offscreen_window_set_embedder %d %d\n",
864 GDK_IS_WINDOW(gtk_widget_get_window (xww
->widget_osr
)),
865 GDK_IS_WINDOW(gtk_widget_get_window (GTK_WIDGET (xv
->widget
))));
866 gdk_offscreen_window_set_embedder (gtk_widget_get_window (xww
->widgetwindow_osr
),
867 gtk_widget_get_window (xv
->widget
));
871 /* initializes and does initial placement of an xwidget view on screen */
873 xwidget_init_view (struct xwidget
*xww
,
874 struct glyph_string
*s
,
877 struct xwidget_view
*xv
= allocate_xwidget_view();
881 XSETXWIDGET_VIEW (val
, xv
) ;
882 Vxwidget_view_list
= Fcons (val
, Vxwidget_view_list
);
884 XSETWINDOW(xv
->w
, s
->w
);
885 XSETXWIDGET(xv
->model
, xww
);
888 if(EQ(xww
->type
, Qbutton
))
890 xv
->widget
= gtk_button_new_with_label (XSTRING(xww
->title
)->data
);
891 g_signal_connect (G_OBJECT (xv
->widget
), "clicked",
892 G_CALLBACK (buttonclick_handler
), xv
); // the view rather than the model
893 } else if (EQ(xww
->type
, Qtoggle
)) {
894 xv
->widget
= gtk_toggle_button_new_with_label (XSTRING(xww
->title
)->data
);
895 //xv->widget = gtk_entry_new ();//temp hack to experiment with key propagation TODO entry widget is useful for testing
896 } else if (EQ(xww
->type
, Qsocket
)) {
897 xv
->widget
= gtk_socket_new ();
898 g_signal_connect_after(xv
->widget
, "plug-added", G_CALLBACK(xwidget_plug_added
), "plug added");
899 g_signal_connect_after(xv
->widget
, "plug-removed", G_CALLBACK(xwidget_plug_removed
), "plug removed");
900 //TODO these doesnt help
901 gtk_widget_add_events(xv
->widget
, GDK_KEY_PRESS
);
902 gtk_widget_add_events(xv
->widget
, GDK_KEY_RELEASE
);
903 } else if (EQ(xww
->type
, Qslider
)) {
905 //gtk_hscale_new (GTK_ADJUSTMENT(gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 10.0, 10.0)));
906 gtk_hscale_new_with_range ( 0.0, 100.0, 10.0);
907 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
908 xv
->handler_id
= g_signal_connect_after(xv
->widget
, "value-changed", G_CALLBACK(xwidget_slider_changed
), "slider changed");
909 } else if (EQ(xww
->type
, Qcairo
)) {
911 //uhm cairo is differentish in gtk 3.
912 //gdk_cairo_create (gtk_widget_get_window (FRAME_GTK_WIDGET (s->f)));
913 xv
->widget
= gtk_drawing_area_new();
914 g_signal_connect (G_OBJECT ( xv
->widget
), "draw",
915 G_CALLBACK (xwidget_osr_draw_callback
), NULL
);
917 } else if (EQ(xww
->type
, Qwebkit_osr
)||
918 EQ(xww
->type
, Qsocket_osr
)||
919 (!NILP (Fget(xww
->type
, QCxwgir_class
))))//xwgir widgets are OSR
921 printf("osr init:%s\n",SDATA(SYMBOL_NAME(xww
->type
)));
922 xv
->widget
= gtk_drawing_area_new();
923 gtk_widget_set_app_paintable ( xv
->widget
, TRUE
); //because expose event handling
924 gtk_widget_add_events(xv
->widget
, GDK_ALL_EVENTS_MASK
);
926 /* Draw the view on damage-event */
927 g_signal_connect (G_OBJECT (xww
->widgetwindow_osr
), "damage-event",
928 G_CALLBACK (offscreen_damage_event
), xv
->widget
);
930 if (EQ(xww
->type
, Qwebkit_osr
)){
932 /* //forward events. this isnt compatible with the set_embedded strategy */
933 g_signal_connect (G_OBJECT ( xv
->widget
), "button-press-event",
934 G_CALLBACK (xwidget_osr_event_forward
), NULL
);
935 g_signal_connect (G_OBJECT ( xv
->widget
), "button-release-event",
936 G_CALLBACK (xwidget_osr_event_forward
), NULL
);
937 g_signal_connect (G_OBJECT ( xv
->widget
), "motion-notify-event",
938 G_CALLBACK (xwidget_osr_event_forward
), NULL
);
940 //xwgir debug , orthogonal to forwarding
941 g_signal_connect (G_OBJECT (xv
->widget
), "enter-notify-event",
942 G_CALLBACK (xwidget_osr_event_set_embedder
), xv
);
946 g_signal_connect (G_OBJECT (xv
->widget
), "draw",
947 G_CALLBACK (xwidget_osr_draw_callback
), NULL
);
953 //make container widget 1st, and put the actual widget inside the container
954 //later, drawing should crop container window if necessary to handle case where xwidget
955 //is partially obscured by other emacs windows
956 //other containers than gtk_fixed where explored, but gtk_fixed had the most predictable behaviour so far.
957 xv
->emacswindow
= FRAME_GTK_WIDGET (s
->f
);
958 xv
->widgetwindow
= gtk_fixed_new ();
959 gtk_widget_set_has_window(xv
->widgetwindow
, TRUE
);
960 gtk_container_add (GTK_CONTAINER (xv
->widgetwindow
), xv
->widget
);
962 //store some xwidget data in the gtk widgets
963 g_object_set_data (G_OBJECT (xv
->widget
), XG_FRAME_DATA
, (gpointer
) (s
->f
)); //the emacs frame
964 g_object_set_data (G_OBJECT (xv
->widget
), XG_XWIDGET
, (gpointer
) (xww
)); //the xwidget
965 g_object_set_data (G_OBJECT (xv
->widget
), XG_XWIDGET_VIEW
, (gpointer
) (xv
)); //the xwidget
966 g_object_set_data (G_OBJECT (xv
->widgetwindow
), XG_XWIDGET
, (gpointer
) (xww
)); //the xwidget window
967 g_object_set_data (G_OBJECT (xv
->widgetwindow
), XG_XWIDGET_VIEW
, (gpointer
) (xv
)); //the xwidget window
970 gtk_widget_set_size_request (GTK_WIDGET (xv
->widget
), xww
->width
, xww
->height
);
971 gtk_widget_set_size_request (xv
->widgetwindow
, xww
->width
, xww
->height
);
972 gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s
->f
)), xv
->widgetwindow
, x
, y
);
973 xv
->x
= x
; xv
->y
= y
;
974 gtk_widget_show_all (xv
->widgetwindow
);
978 //widgettype specific initialization only possible after realization
979 if (EQ(xww
->type
, Qsocket
)) {
980 printf ("xwid:%d socket id:%x %d\n",
982 gtk_socket_get_id (GTK_SOCKET (xv
->widget
)),
983 gtk_socket_get_id (GTK_SOCKET (xv
->widget
)));
984 send_xembed_ready_event (xww
,
985 gtk_socket_get_id (GTK_SOCKET (xv
->widget
)));
986 //gtk_widget_realize(xw->widget);
989 //////////////////////////////////////////////////////////////
991 if (//EQ(xww->type, Qwebkit_osr)|| //TODO should be able to choose compile time which method to use with webkit
992 EQ(xww
->type
, Qsocket_osr
)||
993 (!NILP (Fget(xww
->type
, QCxwgir_class
))))//xwgir widgets are OSR
995 printf("gdk_offscreen_window_set_embedder %d %d\n",
996 GDK_IS_WINDOW(gtk_widget_get_window (xww
->widget_osr
)),
997 GDK_IS_WINDOW(gtk_widget_get_window (GTK_WIDGET (xv
->widget
))));
998 // set_embedder needs to be called after xv->widget realization
999 gdk_offscreen_window_set_embedder (gtk_widget_get_window (xww
->widgetwindow_osr
),
1000 gtk_widget_get_window (xv
->widget
));
1001 g_signal_connect (gtk_widget_get_window (xv
->widget
), "pick-embedded-child",
1002 G_CALLBACK (offscreen_pick_embedded_child
), xww
->widgetwindow_osr
);
1004 g_signal_connect (gtk_widget_get_window (xww
->widgetwindow_osr
), "from-embedder",
1005 G_CALLBACK (offscreen_from_embedder
), NULL
);
1006 g_signal_connect (gtk_widget_get_window (xww
->widgetwindow_osr
), "to-embedder",
1007 G_CALLBACK (offscreen_to_embedder
), NULL
);
1009 ////////////////////////////////////////
1016 x_draw_xwidget_glyph_string (struct glyph_string
*s
)
1019 this method is called by the redisplay engine and places the xwidget on screen.
1020 moving and clipping is done here. also view init.
1023 int box_line_hwidth
= eabs (s
->face
->box_line_width
);
1024 int box_line_vwidth
= max (s
->face
->box_line_width
, 0);
1025 int height
= s
->height
;
1026 struct xwidget
*xww
= s
->xwidget
;
1027 struct xwidget_view
*xv
= xwidget_view_lookup(xww
, s
->w
);
1028 int clip_right
; int clip_bottom
; int clip_top
; int clip_left
;
1031 int y
= s
->y
+ (s
->height
/ 2) - (xww
->height
/ 2);
1034 /* We do it here in the display loop because there is no other
1035 time to know things like window placement etc.
1037 printf ("xv init for xw %d\n", xww
);
1038 xv
= xwidget_init_view (xww
, s
, x
, y
);
1040 //calculate clipping, which is used for all manner of onscreen xwidget views
1041 //each widget border can get clipped by other emacs objects so there are four clipping variables
1042 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
));
1043 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
));
1045 clip_bottom
= min (xww
->height
, WINDOW_BOTTOM_EDGE_Y (s
->w
) - WINDOW_MODE_LINE_HEIGHT (s
->w
) - y
);
1046 clip_top
= max(0, WINDOW_TOP_EDGE_Y(s
->w
) -y
);
1048 //we are conserned with movement of the onscreen area. the area might sit still when the widget actually moves
1049 //this happens when an emacs window border moves across a widget window
1050 //so, if any corner of the outer widget clippng window moves, that counts as movement here, even
1051 //if it looks like no movement happens because the widget sits still inside the clipping area.
1052 //the widget can also move inside the clipping area, which happens later
1053 moved
= (xv
->x
+ xv
->clip_left
!= x
+clip_left
)
1054 || ((xv
->y
+ xv
->clip_top
)!= (y
+clip_top
));
1055 if(moved
) printf ("lxwidget moved: id:%d (%d,%d)->(%d,%d) y+clip_top:%d\n", xww
, xv
->x
, xv
->y
, x
, y
, y
+ clip_top
);
1057 printf ("lxwidget DIDNT move: id:%d (%d,%d)->(%d,%d) y+clip_top:%d\n", xww
, xv
->x
, xv
->y
, x
, y
, y
+ clip_top
);
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
)),
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
);
1079 printf("reclip %d %d -> %d %d clip_top:%d clip_left:%d\n",xv
->clip_right
, xv
->clip_bottom
, clip_right
, clip_bottom
, clip_top
, clip_left
);
1082 xv
->clip_right
= clip_right
; xv
->clip_bottom
= clip_bottom
; xv
->clip_top
= clip_top
;xv
->clip_left
= clip_left
;
1084 //if emacs wants to repaint the area where the widget lives, queue a redraw
1085 //TODO it seems its possible to get out of sync with emacs redraws so emacs bg sometimes shows up instead of xwidget
1086 //its just a visual glitch though
1087 if (!xwidget_hidden(xv
)){
1088 gtk_widget_queue_draw (xv
->widgetwindow
);
1089 gtk_widget_queue_draw (xv
->widget
);
1094 #ifdef HAVE_WEBKIT_OSR
1096 //FUGLY macro that checks WEBKIT_IS_WEB_VIEW(xw->widget_osr) first
1097 #define WEBKIT_FN_INIT() \
1098 struct xwidget* xw; \
1099 CHECK_XWIDGET (xwidget); \
1100 if(NILP (xwidget)) {printf("ERROR xwidget nil\n"); return Qnil;}; \
1101 xw = XXWIDGET(xwidget); \
1102 if(NULL == xw) printf("ERROR xw is 0\n"); \
1103 if((NULL == xw->widget_osr) || !WEBKIT_IS_WEB_VIEW(xw->widget_osr)){ \
1104 printf("ERROR xw->widget_osr does not hold a webkit instance\n");\
1109 DEFUN ("xwidget-webkit-goto-uri", Fxwidget_webkit_goto_uri
, Sxwidget_webkit_goto_uri
,
1111 doc
: /* Make the webkit instance referenced by XWIDGET browse URI. */)
1112 (Lisp_Object xwidget
, Lisp_Object uri
)
1116 webkit_web_view_load_uri ( WEBKIT_WEB_VIEW(xw
->widget_osr
), SDATA(uri
));
1121 DEFUN ("xwidget-webkit-execute-script", Fxwidget_webkit_execute_script
, Sxwidget_webkit_execute_script
,
1123 doc
: /* webkit exec js.*/)
1124 (Lisp_Object xwidget
, Lisp_Object script
)
1127 CHECK_STRING(script
);
1128 webkit_web_view_execute_script( WEBKIT_WEB_VIEW(xw
->widget_osr
), SDATA(script
));
1132 DEFUN ("xwidget-webkit-get-title", Fxwidget_webkit_get_title
, Sxwidget_webkit_get_title
,
1134 doc
: /* Get the title from the Webkit instance in XWIDGET.
1135 This can be used to work around the lack of a return value from the exec method.
1137 (Lisp_Object xwidget
)
1139 //TODO support multibyte strings
1141 const gchar
* str
=webkit_web_view_get_title( WEBKIT_WEB_VIEW(xw
->widget_osr
));
1142 //return make_string_from_bytes(str, wcslen((const wchar_t *)str), strlen(str));
1144 //TODO maybe return Qnil instead. I suppose webkit returns nullpointer when doc is not properly loaded or something
1145 printf("xwidget-webkit-get-title null webkit title\n");
1146 return build_string("");
1148 return build_string(str
);
1152 DEFUN("xwidget-disable-plugin-for-mime", Fxwidget_disable_plugin_for_mime
, Sxwidget_disable_plugin_for_mime
,
1156 WebKitWebPlugin
*wp
= webkit_web_plugin_database_get_plugin_for_mimetype
1157 (webkit_get_web_plugin_database(), SDATA(mime
));
1158 if(wp
== NULL
) return Qnil
;
1159 if(webkit_web_plugin_get_enabled (wp
)){
1160 webkit_web_plugin_set_enabled (wp
, FALSE
);
1168 xwidget_webkit_dom_dump(WebKitDOMNode
* parent
)
1170 WebKitDOMNodeList
* list
;
1173 WebKitDOMNode
* attribute
;
1174 WebKitDOMNamedNodeMap
* attrs
;
1175 WebKitDOMNode
* child
;
1176 printf("node:%d type:%d name:%s content:%s\n",
1178 webkit_dom_node_get_node_type(parent
),//1 element 3 text 8 comment 2 attribute
1179 webkit_dom_node_get_local_name(parent
),
1180 webkit_dom_node_get_text_content(parent
));
1182 if(webkit_dom_node_has_attributes(parent
)){
1183 attrs
= webkit_dom_node_get_attributes(parent
);
1185 length
= webkit_dom_named_node_map_get_length(attrs
);
1186 for (int i
= 0; i
< length
; i
++) {
1187 attribute
= webkit_dom_named_node_map_item(attrs
,i
);
1188 printf(" attr node:%d type:%d name:%s content:%s\n",
1190 webkit_dom_node_get_node_type(attribute
),//1 element 3 text 8 comment
1191 webkit_dom_node_get_local_name(attribute
),
1192 webkit_dom_node_get_text_content(attribute
));
1195 list
= webkit_dom_node_get_child_nodes(parent
);
1196 length
= webkit_dom_node_list_get_length(list
);
1198 for (int i
= 0; i
< length
; i
++) {
1199 child
= webkit_dom_node_list_item(list
, i
);
1200 //if(webkit_dom_node_has_child_nodes(child))
1201 xwidget_webkit_dom_dump(child
);
1206 DEFUN ("xwidget-webkit-dom-dump", Fxwidget_webkit_dom_dump
, Sxwidget_webkit_dom_dump
,
1208 doc
: /*Dump the DOM contained in the webkit instance in XWIDGET.*/)
1209 (Lisp_Object xwidget
)
1212 xwidget_webkit_dom_dump(WEBKIT_DOM_NODE(webkit_web_view_get_dom_document( WEBKIT_WEB_VIEW(xw
->widget_osr
))));
1218 #endif /* HAVE_WEBKIT_OSR */
1224 DEFUN ("xwidget-resize", Fxwidget_resize
, Sxwidget_resize
, 3, 3, 0, doc
:
1226 NEW_WIDTH NEW_HEIGHT defines the new size.)
1228 (Lisp_Object xwidget
, Lisp_Object new_width
, Lisp_Object new_height
)
1230 CHECK_XWIDGET (xwidget
);
1231 struct xwidget
* xw
= XXWIDGET(xwidget
);
1232 struct xwidget_view
*xv
;
1235 CHECK_NUMBER (new_width
);
1236 CHECK_NUMBER (new_height
);
1237 w
= XFASTINT (new_width
);
1238 h
= XFASTINT (new_height
);
1241 printf("resize xwidget %d (%d,%d)->(%d,%d)\n",xw
, xw
->width
,xw
->height
,w
,h
);
1244 //if theres a osr resize it 1st
1246 printf("resize xwidget_osr\n");
1247 //gtk_container_set_resize_mode ( GTK_WINDOW(xw->widgetwindow_osr), GTK_RESIZE_QUEUE);
1248 //gtk_container_set_resize_mode ( GTK_WINDOW(xw->widget_osr), GTK_RESIZE_QUEUE);
1251 //gtk_layout_set_size (GTK_LAYOUT (xw->widgetwindow_osr), xw->width, xw->height);
1252 gtk_widget_set_size_request (GTK_WIDGET (xw
->widget_osr
), xw
->width
, xw
->height
); //minimum size
1253 //gtk_window_resize( GTK_WINDOW(xw->widget_osr), xw->width, xw->height);
1254 gtk_window_resize( GTK_WINDOW(xw
->widgetwindow_osr
), xw
->width
, xw
->height
);
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
);
1274 DEFUN ("xwidget-size-request", Fxwidget_size_request
, Sxwidget_size_request
, 1, 1, 0, doc
:
1275 - /* Desired size of the XWIDGET.
1277 This can be used to read the xwidget desired size, and resizes the Emacs allocated area accordingly.
1279 (TODO crashes if arg not osr widget)*/)
1280 (Lisp_Object xwidget
)
1282 CHECK_XWIDGET (xwidget
);
1283 GtkRequisition requisition
;
1285 gtk_widget_size_request(XXWIDGET(xwidget
)->widget_osr
, &requisition
);
1287 rv
= Fcons (make_number(requisition
.height
), rv
);
1288 rv
= Fcons (make_number(requisition
.width
), rv
);
1293 DEFUN ("xwidgetp", Fxwidgetp
, Sxwidgetp
, 1, 1, 0,
1294 doc
: /* Return t if OBJECT is a xwidget. */)
1295 (Lisp_Object object
)
1297 return XWIDGETP (object
) ? Qt
: Qnil
;
1300 DEFUN ("xwidget-view-p", Fxwidget_view_p
, Sxwidget_view_p
, 1, 1, 0,
1301 doc
: /* Return t if OBJECT is a xwidget-view. */)
1302 (Lisp_Object object
)
1304 return XWIDGET_VIEW_P (object
) ? Qt
: Qnil
;
1307 DEFUN ("xwidget-info", Fxwidget_info
, Sxwidget_info
, 1,1,0,
1308 doc
: /* Get XWIDGET properties.
1309 Currently type, title, width, height.*/)
1310 (Lisp_Object xwidget
)
1312 CHECK_XWIDGET (xwidget
);
1313 Lisp_Object info
, n
;
1314 struct xwidget
* xw
= XXWIDGET(xwidget
);
1316 info
= Fmake_vector (make_number (4), Qnil
);
1317 ASET (info
, 0, xw
->type
);
1318 ASET (info
, 1, xw
->title
);
1319 XSETFASTINT(n
, xw
->width
);
1321 XSETFASTINT(n
, xw
->height
);
1327 DEFUN ("xwidget-view-info", Fxwidget_view_info
, Sxwidget_view_info
, 1, 1, 0, doc
:
1328 /* Get XWIDGET-VIEW properties.
1329 Currently x,y clip right, clip bottom, clip top, clip left*/)
1330 (Lisp_Object xwidget_view
)
1332 CHECK_XWIDGET_VIEW (xwidget_view
);
1333 struct xwidget_view
*xv
= XXWIDGET_VIEW (xwidget_view
);
1336 info
= Fmake_vector (make_number (6), Qnil
);
1337 ASET (info
, 0, make_number(xv
->x
));
1338 ASET (info
, 1, make_number(xv
->y
));
1339 ASET (info
, 2, make_number(xv
->clip_right
));
1340 ASET (info
, 3, make_number(xv
->clip_bottom
));
1341 ASET (info
, 4, make_number(xv
->clip_top
));
1342 ASET (info
, 5, make_number(xv
->clip_left
));
1347 DEFUN ("xwidget-view-model", Fxwidget_view_model
, Sxwidget_view_model
,
1349 doc
: /* Get XWIDGET-VIEW model. */)
1350 (Lisp_Object xwidget_view
)
1352 CHECK_XWIDGET_VIEW (xwidget_view
);
1353 return XXWIDGET_VIEW (xwidget_view
)->model
;
1356 DEFUN ("xwidget-view-window", Fxwidget_view_window
, Sxwidget_view_window
,
1358 doc
: /* Get XWIDGET-VIEW window. */)
1359 (Lisp_Object xwidget_view
)
1361 CHECK_XWIDGET_VIEW (xwidget_view
);
1362 return XXWIDGET_VIEW (xwidget_view
)->w
;
1365 DEFUN ("xwidget-send-keyboard-event", Fxwidget_send_keyboard_event
, Sxwidget_send_keyboard_event
, 2, 2, 0,
1366 doc
:/* Synthesize a kbd event for XWIDGET. TODO crashes atm.. */
1368 (Lisp_Object xwidget
, Lisp_Object keydescriptor
)
1370 //TODO this code crashes for offscreen widgets and ive tried many different strategies
1371 //int keyval = 0x058; //X
1372 int keyval
= XFASTINT(keydescriptor
); //X
1373 char *keystring
= "";
1376 GdkDeviceManager
* manager
;
1381 //popup_activated_flag = 1; //TODO just a hack
1382 gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), keyval
, &keys
, &n_keys
);
1384 xw
= XXWIDGET(xwidget
);
1386 ev
= (GdkEventKey
*)gdk_event_new(GDK_KEY_PRESS
);
1389 //todo what about windowless widgets?
1391 window
= FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
1394 //TODO maybe we also need to special case sockets by picking up the plug rather than the socket
1396 widget
= xw
->widget_osr
;
1398 widget
= xwidget_view_lookup(xw
, XWINDOW(window
))->widget
;
1400 ev
->window
= gtk_widget_get_window(widget
);
1401 gtk_widget_grab_focus(widget
);
1402 ev
->send_event
= FALSE
;
1404 ev
->hardware_keycode
= keys
[0].keycode
;
1405 ev
->group
= keys
[0].group
;
1407 ev
->keyval
= keyval
;
1408 ev
->time
= GDK_CURRENT_TIME
;
1410 //ev->device = gdk_device_get_core_pointer();
1411 manager
= gdk_display_get_device_manager(gdk_window_get_display(ev
->window
));
1412 gdk_event_set_device ((GdkEvent
*)ev
, gdk_device_manager_get_client_pointer(manager
));
1413 gdk_event_put((GdkEvent
*)ev
);
1414 //g_signal_emit_by_name(ev->window,"key-press-event", ev);
1416 ev
->type
= GDK_KEY_RELEASE
;
1417 gdk_event_put((GdkEvent
*)ev
);
1418 //g_signal_emit_by_name(ev->window,"key-release-event", ev);
1419 //gtk_main_do_event(ev);
1422 //if I delete the event the receiving component eventually crashes.
1423 //it ough TDTRT since event_put is supposed to copy the event
1424 //so probably this leaks events now
1425 //gdk_event_free((GdkEvent*)ev);
1430 DEFUN ("delete-xwidget-view", Fdelete_xwidget_view
, Sdelete_xwidget_view
,
1432 doc
: /* Delete the XWIDGET-VIEW. */)
1433 (Lisp_Object xwidget_view
)
1435 CHECK_XWIDGET_VIEW (xwidget_view
);
1436 struct xwidget_view
*xv
= XXWIDGET_VIEW (xwidget_view
);
1437 gtk_widget_destroy(xv
->widgetwindow
);
1438 Vxwidget_view_list
= Fdelq (xwidget_view
, Vxwidget_view_list
);
1441 DEFUN ("xwidget-view-lookup", Fxwidget_view_lookup
, Sxwidget_view_lookup
,
1443 doc
: /* Return the xwidget-view associated to XWIDGET in
1444 WINDOW if specified, otherwise it uses the selected window. */)
1445 (Lisp_Object xwidget
, Lisp_Object window
)
1447 CHECK_XWIDGET (xwidget
);
1450 window
= Fselected_window();
1451 CHECK_WINDOW (window
);
1453 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
); tail
= XCDR (tail
))
1455 Lisp_Object xwidget_view
= XCAR (tail
);
1456 if (EQ (Fxwidget_view_model (xwidget_view
), xwidget
)
1457 && EQ (Fxwidget_view_window (xwidget_view
), window
))
1458 return xwidget_view
;
1464 DEFUN ("set-frame-visible", Fset_frame_visible
, Sset_frame_visible
,
1467 (Lisp_Object frame
, Lisp_Object flag
)
1469 CHECK_FRAME (frame
);
1470 struct frame
*f
= XFRAME (frame
);
1471 SET_FRAME_VISIBLE (f
, !NILP (flag
));
1475 DEFUN ("xwidget-plist", Fxwidget_plist
, Sxwidget_plist
,
1477 doc
: /* Return the plist of XWIDGET. */)
1478 (register Lisp_Object xwidget
)
1480 CHECK_XWIDGET (xwidget
);
1481 return XXWIDGET (xwidget
)->plist
;
1484 DEFUN ("xwidget-buffer", Fxwidget_buffer
, Sxwidget_buffer
,
1486 doc
: /* Return the buffer of XWIDGET. */)
1487 (register Lisp_Object xwidget
)
1489 CHECK_XWIDGET (xwidget
);
1490 return XXWIDGET (xwidget
)->buffer
;
1493 DEFUN ("set-xwidget-plist", Fset_xwidget_plist
, Sset_xwidget_plist
,
1495 doc
: /* Replace the plist of XWIDGET with PLIST. Returns PLIST. */)
1496 (register Lisp_Object xwidget
, Lisp_Object plist
)
1498 CHECK_XWIDGET (xwidget
);
1501 XXWIDGET (xwidget
)->plist
= plist
;
1505 DEFUN ("set-xwidget-query-on-exit-flag",
1506 Fset_xwidget_query_on_exit_flag
, Sset_xwidget_query_on_exit_flag
,
1508 doc
: /* Specify if query is needed for XWIDGET when Emacs is
1509 exited. If the second argument FLAG is non-nil, Emacs will query the
1510 user before exiting or killing a buffer if XWIDGET is running. This
1511 function returns FLAG. */)
1512 (Lisp_Object xwidget
, Lisp_Object flag
)
1514 CHECK_XWIDGET (xwidget
);
1515 XXWIDGET (xwidget
)->kill_without_query
= NILP (flag
);
1519 DEFUN ("xwidget-query-on-exit-flag",
1520 Fxwidget_query_on_exit_flag
, Sxwidget_query_on_exit_flag
,
1522 doc
: /* Return the current value of query-on-exit flag for XWIDGET. */)
1523 (Lisp_Object xwidget
)
1525 CHECK_XWIDGET (xwidget
);
1526 return (XXWIDGET (xwidget
)->kill_without_query
? Qnil
: Qt
);
1530 syms_of_xwidget (void)
1534 defsubr (&Smake_xwidget
);
1535 defsubr (&Sxwidgetp
);
1536 DEFSYM (Qxwidgetp
, "xwidgetp");
1537 defsubr (&Sxwidget_view_p
);
1538 DEFSYM (Qxwidget_view_p
, "xwidget-view-p");
1539 defsubr (&Sxwidget_info
);
1540 defsubr (&Sxwidget_view_info
);
1541 defsubr (&Sxwidget_resize
);
1542 defsubr (&Sget_buffer_xwidgets
);
1543 defsubr (&Sxwidget_view_model
);
1544 defsubr (&Sxwidget_view_window
);
1545 defsubr (&Sxwidget_view_lookup
);
1546 defsubr (&Sxwidget_query_on_exit_flag
);
1547 defsubr (&Sset_xwidget_query_on_exit_flag
);
1548 defsubr (&Sset_frame_visible
);
1550 #ifdef HAVE_WEBKIT_OSR
1551 defsubr (&Sxwidget_webkit_goto_uri
);
1552 defsubr (&Sxwidget_webkit_execute_script
);
1553 defsubr (&Sxwidget_webkit_get_title
);
1554 DEFSYM (Qwebkit_osr
, "webkit-osr");
1557 defsubr (&Sxwgir_xwidget_call_method
);
1558 defsubr (&Sxwgir_require_namespace
);
1559 defsubr (&Sxwidget_size_request
);
1560 defsubr (&Sdelete_xwidget_view
);
1561 defsubr (&Sxwidget_disable_plugin_for_mime
);
1563 defsubr (&Sxwidget_send_keyboard_event
);
1564 defsubr (&Sxwidget_webkit_dom_dump
);
1565 defsubr (&Sxwidget_plist
);
1566 defsubr (&Sxwidget_buffer
);
1567 defsubr (&Sset_xwidget_plist
);
1569 DEFSYM (Qxwidget
, "xwidget");
1571 DEFSYM (QCxwidget
, ":xwidget");
1572 DEFSYM (QCxwgir_class
, ":xwgir-class");
1573 DEFSYM (QCtitle
, ":title");
1575 /* Do not forget to update the docstring of make-xwidget if you add
1577 DEFSYM (Qbutton
, "Button"); //changed to match the gtk class because xwgir(experimental and not really needed)
1578 DEFSYM (Qtoggle
, "ToggleButton");
1579 DEFSYM (Qslider
, "slider");
1580 DEFSYM (Qsocket
, "socket");
1581 DEFSYM (Qsocket_osr
, "socket-osr");
1582 DEFSYM (Qcairo
, "cairo");
1584 DEFSYM (QCplist
, ":plist");
1586 DEFVAR_LISP ("xwidget-list", Vxwidget_list
, doc
: /*xwidgets list*/);
1587 Vxwidget_list
= Qnil
;
1589 DEFVAR_LISP ("xwidget-view-list", Vxwidget_view_list
, doc
: /*xwidget views list*/);
1590 Vxwidget_view_list
= Qnil
;
1592 Fprovide (intern ("xwidget-internal"), Qnil
);
1597 /* Value is non-zero if OBJECT is a valid Lisp xwidget specification. A
1598 valid xwidget specification is a list whose car is the symbol
1599 `xwidget', and whose rest is a property list. The property list must
1600 contain a value for key `:type'. That value must be the name of a
1601 supported xwidget type. The rest of the property list depends on the
1605 valid_xwidget_spec_p (Lisp_Object object
)
1609 if (CONSP (object
) && EQ (XCAR (object
), Qxwidget
))
1611 /* Lisp_Object tem; */
1613 /* for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem)) */
1614 /* if (EQ (XCAR (tem), QCtype)) */
1616 /* tem = XCDR (tem); */
1617 /* if (CONSP (tem) && SYMBOLP (XCAR (tem))) */
1619 /* struct xwidget_type *type; */
1620 /* type = lookup_xwidget_type (XCAR (tem)); */
1622 /* valid_p = type->valid_p (object); */
1627 //never mind type support for now
1636 /* find a value associated with key in spec */
1638 xwidget_spec_value ( Lisp_Object spec
, Lisp_Object key
,
1643 eassert (valid_xwidget_spec_p (spec
));
1645 for (tail
= XCDR (spec
);
1646 CONSP (tail
) && CONSP (XCDR (tail
)); tail
= XCDR (XCDR (tail
)))
1648 if (EQ (XCAR (tail
), key
))
1652 return XCAR (XCDR (tail
));
1663 xwidget_view_delete_all_in_window (struct window
*w
)
1665 struct xwidget_view
* xv
= NULL
;
1666 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
); tail
= XCDR (tail
))
1668 if (XWIDGET_VIEW_P (XCAR (tail
))) {
1669 xv
= XXWIDGET_VIEW (XCAR (tail
));
1670 if(XWINDOW (xv
->w
) == w
) {
1671 gtk_widget_destroy(xv
->widgetwindow
);
1672 Vxwidget_view_list
= Fdelq (XCAR (tail
), Vxwidget_view_list
);
1678 struct xwidget_view
*
1679 xwidget_view_lookup (struct xwidget
* xw
, struct window
*w
)
1681 Lisp_Object xwidget
, window
, ret
;
1682 XSETXWIDGET (xwidget
, xw
);
1683 XSETWINDOW (window
, w
);
1685 ret
= Fxwidget_view_lookup (xwidget
, window
);
1687 return EQ (ret
, Qnil
) ? NULL
: XXWIDGET_VIEW (ret
);
1691 lookup_xwidget (Lisp_Object spec
)
1693 /* When a xwidget lisp spec is found initialize the C struct that is used in the C code.
1694 This is done by redisplay so values change if the spec changes.
1695 So, take special care of one-shot events
1697 TODO remove xwidget init from display spec. simply store an xwidget reference only and set
1698 size etc when creating the xwidget, which should happen before insertion into buffer
1700 int found
= 0, found1
= 0, found2
= 0;
1704 value
= xwidget_spec_value (spec
, QCxwidget
, &found1
);
1705 xw
= XXWIDGET(value
);
1707 /* value = xwidget_spec_value (spec, QCtype, &found); */
1708 /* xw->type = SYMBOLP (value) ? value : Qbutton; //default to button */
1709 /* value = xwidget_spec_value (spec, QCtitle, &found2); */
1710 /* xw->title = STRINGP (value) ? (char *) SDATA (value) : "?"; //funky cast FIXME TODO */
1712 /* value = xwidget_spec_value (spec, QCheight, NULL); */
1713 /* xw->height = INTEGERP (value) ? XFASTINT (value) : 50; */
1714 /* value = xwidget_spec_value (spec, QCwidth, NULL); */
1715 /* xw->width = INTEGERP (value) ? XFASTINT (value) : 50; */
1717 /* value = xwidget_spec_value (spec, QCplist, NULL); */
1718 /* xw->plist = value; */
1719 /* coordinates are not known here */
1720 printf ("lookup_xwidget xwidget_id:%d type:%d found:%d %d %d title:'%s' (%d,%d)\n", xw
,
1721 xw
->type
, found
, found1
, found2
, xw
->title
, xw
->height
, xw
->width
);
1723 //assert_valid_xwidget_id (id, "lookup_xwidget");
1727 /*set up detection of touched xwidget*/
1729 xwidget_start_redisplay (void)
1731 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
); tail
= XCDR (tail
))
1733 if (XWIDGET_VIEW_P (XCAR (tail
)))
1734 XXWIDGET_VIEW (XCAR (tail
))->redisplayed
= 0;
1738 /* the xwidget was touched during redisplay, so it isnt a candidate for hiding*/
1740 xwidget_touch (struct xwidget_view
*xv
)
1742 xv
->redisplayed
= 1;
1746 xwidget_touched (struct xwidget_view
*xv
)
1748 return xv
->redisplayed
;
1751 /* redisplay has ended, now we should hide untouched xwidgets
1754 xwidget_end_redisplay (struct window
*w
, struct glyph_matrix
*matrix
)
1762 xwidget_start_redisplay ();
1763 //iterate desired glyph matrix of window here, hide gtk widgets
1764 //not in the desired matrix.
1766 //this only takes care of xwidgets in active windows.
1767 //if a window goes away from screen xwidget views wust be deleted
1769 // dump_glyph_matrix(matrix, 2);
1770 for (i
= 0; i
< matrix
->nrows
; ++i
)
1772 // dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs);
1773 struct glyph_row
*row
;
1774 row
= MATRIX_ROW (matrix
, i
);
1775 if (row
->enabled_p
!= 0)
1777 for (area
= LEFT_MARGIN_AREA
; area
< LAST_AREA
; ++area
)
1779 struct glyph
*glyph
= row
->glyphs
[area
];
1780 struct glyph
*glyph_end
= glyph
+ row
->used
[area
];
1781 for (; glyph
< glyph_end
; ++glyph
)
1783 if (glyph
->type
== XWIDGET_GLYPH
)
1786 the only call to xwidget_end_redisplay is in dispnew
1787 xwidget_end_redisplay(w->current_matrix);
1789 xwidget_touch (xwidget_view_lookup(glyph
->u
.xwidget
,
1797 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
); tail
= XCDR (tail
))
1799 if (XWIDGET_VIEW_P (XCAR (tail
))) {
1800 struct xwidget_view
* xv
= XXWIDGET_VIEW (XCAR (tail
));
1802 //"touched" is only meaningful for the current window, so disregard other views
1803 if (XWINDOW (xv
->w
) == w
) {
1804 if (xwidget_touched(xv
))
1805 xwidget_show_view (xv
);
1807 xwidget_hide_view (xv
);
1813 /* Kill all xwidget in BUFFER. */
1815 kill_buffer_xwidgets (Lisp_Object buffer
)
1817 Lisp_Object tail
, xwidget
;
1818 for (tail
= Fget_buffer_xwidgets (buffer
); CONSP (tail
); tail
= XCDR (tail
))
1820 xwidget
= XCAR (tail
);
1821 Vxwidget_list
= Fdelq (xwidget
, Vxwidget_list
);
1822 /* TODO free the GTK things in xw */
1824 CHECK_XWIDGET (xwidget
);
1825 struct xwidget
*xw
= XXWIDGET (xwidget
);
1826 if (xw
->widget_osr
&& xw
->widgetwindow_osr
)
1828 gtk_widget_destroy(xw
->widget_osr
);
1829 gtk_widget_destroy(xw
->widgetwindow_osr
);
1835 #endif /* HAVE_XWIDGETS */