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
77 //for gtk3; sockets and plugs
79 #include "emacsgtkfixed.h"
85 #include <goocanvas.h>
89 #include <librsvg/rsvg.h>
90 #include <clutter/clutter.h>
91 #include <clutter-gtk/clutter-gtk.h>
96 #ifdef HAVE_WEBKIT_OSR
97 #include <webkit/webkitwebview.h>
98 #include <webkit/webkitwebplugindatabase.h>
99 #include <webkit/webkitwebplugin.h>
100 #include <webkit/webkitglobals.h>
101 #include <webkit/webkitwebnavigationaction.h>
102 #include <webkit/webkitdownload.h>
106 #include <girepository.h>
110 //TODO should of course not be a hardcoded array but I can't be bothered atm
111 //just a fixed array of xwidgets for now
112 //would need to be hashtables or something
114 #define MAX_XWIDGETS 100
115 struct xwidget_view xwidget_views
[MAX_XWIDGETS
];
117 //TODO embryo of lisp allocators for xwidgets
118 //TODO xwidget* should be Lisp_xwidget*
120 allocate_xwidget (void)
122 return ALLOCATE_PSEUDOVECTOR (struct xwidget
, height
, PVEC_XWIDGET
);
125 //TODO xwidget_view* should be Lisp_xwidget_view*
127 allocate_xwidget_view (void)
129 return ALLOCATE_PSEUDOVECTOR (struct xwidget_view
, redisplayed
, PVEC_XWIDGET_VIEW
);
131 #define XSETXWIDGET(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET))
132 #define XSETXWIDGET_VIEW(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW))
134 Lisp_Object Qxwidget
;
135 Lisp_Object Qcxwidget
;
137 Lisp_Object Qxwidget_set_keyboard_grab
;
138 Lisp_Object Qxwidget_embed_steal_window
;
139 Lisp_Object Qxwidget_info
;
140 Lisp_Object Qxwidget_resize
;
141 Lisp_Object Qxwidget_send_keyboard_event
;
142 Lisp_Object Qcxwgir_class
;
143 Lisp_Object Qbutton
, Qtoggle
, Qslider
, Qsocket
, Qsocket_osr
, Qcairo
, Qxwgir
,
144 Qwebkit_osr
, QCplist
;
147 extern Lisp_Object QCtype
;
148 extern Lisp_Object QCwidth
, QCheight
;
150 struct xwidget_view
* xwidget_view_lookup(struct xwidget
* xw
, struct window
*w
);
151 Lisp_Object
xwidget_spec_value ( Lisp_Object spec
, Lisp_Object key
, int *found
);
152 gboolean
webkit_osr_damage_event_callback (GtkWidget
*widget
, GdkEventExpose
*event
, gpointer data
) ;
153 gboolean
webkit_osr_key_event_callback (GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
) ;
154 void webkit_osr_document_load_finished_callback (WebKitWebView
*webkitwebview
,
155 WebKitWebFrame
*arg1
,
157 gboolean
webkit_osr_download_callback (WebKitWebView
*webkitwebview
,
158 WebKitDownload
*arg1
,
161 gboolean
webkit_osr_mime_type_policy_typedecision_requested_callback(WebKitWebView
*webView
,
162 WebKitWebFrame
*frame
,
163 WebKitNetworkRequest
*request
,
165 WebKitWebPolicyDecision
*policy_decision
,
168 gboolean
webkit_osr_new_window_policy_decision_requested_callback(WebKitWebView
*webView
,
169 WebKitWebFrame
*frame
,
170 WebKitNetworkRequest
*request
,
171 WebKitWebNavigationAction
*navigation_action
,
172 WebKitWebPolicyDecision
*policy_decision
,
176 gboolean
webkit_osr_navigation_policy_decision_requested_callback(WebKitWebView
*webView
,
177 WebKitWebFrame
*frame
,
178 WebKitNetworkRequest
*request
,
179 WebKitWebNavigationAction
*navigation_action
,
180 WebKitWebPolicyDecision
*policy_decision
,
184 DEFUN ("make-xwidget", Fmake_xwidget
, Smake_xwidget
, 7, 7, 0,
187 (Lisp_Object beg
, Lisp_Object end
,
190 Lisp_Object width
, Lisp_Object height
,
193 //should work a bit like "make-button"(make-button BEG END &rest PROPERTIES)
194 // arg "type" and fwd should be keyword args eventually
195 //(make-xwidget 3 3 'button "oei" 31 31 nil)
196 //(xwidget-info (car xwidget-alist))
197 struct xwidget
* xw
= allocate_xwidget();
201 XSETSYMBOL(xw
->type
, type
);
202 XSETSTRING(xw
->title
, title
);
203 //TODO buffer should be an optional argument not just assumed to be the current buffer
204 XSETBUFFER(xw
->buffer
, Fcurrent_buffer()); // conservatively gcpro xw since we call lisp
205 xw
->height
= XFASTINT(height
);
206 xw
->width
= XFASTINT(width
);
207 XSETPSEUDOVECTOR (val
, xw
, PVEC_XWIDGET
); //?? dunno why i need this
208 Vxwidget_alist
= Fcons ( val
, Vxwidget_alist
);
209 xw
->widgetwindow_osr
= NULL
;
210 xw
->widget_osr
= NULL
;
214 #ifdef HAVE_WEBKIT_OSR
215 /* DIY mvc. widget is rendered offscreen,
216 later bitmap copied to the views.
218 if (EQ(xw
->type
, Qwebkit_osr
)){
219 printf("init webkit osr\n");
221 xw
->widgetwindow_osr
= GTK_CONTAINER (gtk_offscreen_window_new ());
222 gtk_window_resize( GTK_WINDOW(xw
->widgetwindow_osr
), xw
->width
, xw
->height
);
223 xw
->widget_osr
= webkit_web_view_new();
225 gtk_widget_set_size_request (GTK_WIDGET (xw
->widget_osr
), xw
->width
, xw
->height
);
226 gtk_container_add (xw
->widgetwindow_osr
, xw
->widget_osr
);
228 gtk_widget_show_all (GTK_WIDGET (xw
->widgetwindow_osr
));
230 /* store some xwidget data in the gtk widgets for convenient retrieval in the event handlers. */
231 g_object_set_data (G_OBJECT (xw
->widget_osr
), XG_XWIDGET
, (gpointer
) (xw
));
232 g_object_set_data (G_OBJECT (xw
->widgetwindow_osr
), XG_XWIDGET
, (gpointer
) (xw
));
234 g_signal_connect (G_OBJECT ( xw
->widgetwindow_osr
), "damage-event", G_CALLBACK (webkit_osr_damage_event_callback
), NULL
);
236 //TODO these were just a test hack
237 /* g_signal_connect (G_OBJECT ( xw->widget_osr), "key-press-event", G_CALLBACK (webkit_osr_key_event_callback), NULL); */
238 /* g_signal_connect (G_OBJECT ( xw->widget_osr), "key-release-event", G_CALLBACK (webkit_osr_key_event_callback), NULL); */
240 g_signal_connect (G_OBJECT ( xw
->widget_osr
),
241 "document-load-finished",
242 G_CALLBACK (webkit_osr_document_load_finished_callback
),
245 g_signal_connect (G_OBJECT ( xw
->widget_osr
),
246 "download-requested",
247 G_CALLBACK (webkit_osr_download_callback
),
250 g_signal_connect (G_OBJECT ( xw
->widget_osr
),
251 "mime-type-policy-decision-requested",
252 G_CALLBACK (webkit_osr_mime_type_policy_typedecision_requested_callback
),
255 g_signal_connect (G_OBJECT ( xw
->widget_osr
),
256 "new-window-policy-decision-requested",
257 G_CALLBACK (webkit_osr_new_window_policy_decision_requested_callback
),
260 g_signal_connect (G_OBJECT ( xw
->widget_osr
),
261 "navigation-policy-decision-requested",
262 G_CALLBACK (webkit_osr_navigation_policy_decision_requested_callback
),
266 webkit_web_view_load_uri(WEBKIT_WEB_VIEW(xw
->widget_osr
), "http://www.fsf.org");
272 if (EQ(xw
->type
, Qsocket_osr
)){
273 printf("init socket osr\n");
275 xw
->widgetwindow_osr
= GTK_CONTAINER (gtk_offscreen_window_new ());
276 gtk_window_resize( GTK_WINDOW(xw
->widgetwindow_osr
), xw
->width
, xw
->height
);
279 //xw->widget_osr = webkit_web_view_new();
280 xw
->widget_osr
= gtk_socket_new();
281 //g_signal_connect_after(xv->widget, "plug-added", G_CALLBACK(xwidget_plug_added), "plug added");
282 //g_signal_connect_after(xv->widget, "plug-removed", G_CALLBACK(xwidget_plug_removed), "plug removed");
285 gtk_widget_set_size_request (GTK_WIDGET (xw
->widget_osr
), xw
->width
, xw
->height
);
286 gtk_container_add (xw
->widgetwindow_osr
, xw
->widget_osr
);
288 gtk_widget_show_all (GTK_WIDGET (xw
->widgetwindow_osr
));
290 /* store some xwidget data in the gtk widgets for convenient retrieval in the event handlers. */
291 g_object_set_data (G_OBJECT (xw
->widget_osr
), XG_XWIDGET
, (gpointer
) (xw
));
292 g_object_set_data (G_OBJECT (xw
->widgetwindow_osr
), XG_XWIDGET
, (gpointer
) (xw
));
293 g_signal_connect (G_OBJECT ( xw
->widgetwindow_osr
), "damage-event", G_CALLBACK (webkit_osr_damage_event_callback
), NULL
);
295 //webkit_web_view_load_uri(WEBKIT_WEB_VIEW(xw->widget_osr), "http://www.fsf.org");
305 xwidget_hidden(struct xwidget_view
*xv
)
312 buttonclick_handler (GtkWidget
* widget
, gpointer data
)
314 struct xwidget
*xw
= (struct xwidget
*) data
;
315 struct input_event event
;
317 FRAME_PTR f
= NULL
;//(FRAME_PTR) g_object_get_data (G_OBJECT (xw->widget), XG_FRAME_DATA); //TODO
318 printf ("button clicked xw:%d '%s'\n", xw
, xw
->title
);
321 event
.kind
= XWIDGET_EVENT
;
323 XSETFRAME (frame
, f
);
325 event
.frame_or_window
= Qnil
; //frame; //how to get the frame here?
329 event
.arg
= Fcons ((Lisp_Object
)xw
, event
.arg
); //TODO send the actual xwidget object now instead
330 event
.arg
= Fcons (intern ("buttonclick"), event
.arg
);
332 kbd_buffer_store_event (&event
);
339 send_xembed_ready_event (struct xwidget
* xw
, int xembedid
)
341 struct input_event event
;
343 event
.kind
= XWIDGET_EVENT
;
344 event
.frame_or_window
= Qnil
; //frame; //how to get the frame here? //TODO i store it in the xwidget now
347 event
.arg
= Fcons (make_number (xembedid
), event
.arg
);
348 event
.arg
= Fcons ((Lisp_Object
)xw
, event
.arg
); //TODO
349 event
.arg
= Fcons (intern ("xembed-ready"), event
.arg
);
352 kbd_buffer_store_event (&event
);
357 xwidget_show_view (struct xwidget_view
*xv
)
360 gtk_widget_show(GTK_WIDGET(xv
->widgetwindow
));
361 gtk_fixed_move (GTK_FIXED (xv
->emacswindow
), GTK_WIDGET (xv
->widgetwindow
), xv
->x
+ xv
->clip_left
, xv
->y
+ xv
->clip_top
); //TODO refactor
365 /* hide an xvidget view */
367 xwidget_hide_view (struct xwidget_view
*xv
)
370 //gtk_widget_hide(GTK_WIDGET(xw->widgetwindow));
371 gtk_fixed_move (GTK_FIXED (xv
->emacswindow
), GTK_WIDGET (xv
->widgetwindow
),
377 xwidget_plug_added(GtkSocket
*socket
,
380 //hmm this doesnt seem to get called for foreign windows
381 printf("xwidget_plug_added\n");
385 xwidget_plug_removed(GtkSocket
*socket
,
388 printf("xwidget_plug_removed\n");
389 return TRUE
; /* dont run the default handler because that kills the socket and we want to reuse it*/
394 xwidget_slider_changed (GtkRange
*range
,
397 //slider value changed. change value of siblings
398 //correspondingly. but remember that changing value will again
401 //TODO MVC view storage wont be an array futureish so the loop needs to change eventually
402 //TODO MVC it would be nice if this code could be reusable but, alas, C is not a functional language
404 // - the type of the controllers value (double, boolean etc)
405 // - the getter and setter (but they can be func pointers)
406 // a behemoth macro is always an option.
407 double v
=gtk_range_get_value(range
);
408 struct xwidget_view
* xvp
= g_object_get_data (G_OBJECT (range
), XG_XWIDGET_VIEW
);
409 struct xwidget_view
* xv
;
411 printf("slider changed val:%f\n", v
);
414 //block sibling views signal handlers
415 for (int i
= 0; i
< MAX_XWIDGETS
; i
++)
417 xv
= &xwidget_views
[i
];
418 if(xv
->initialized
&& xvp
->model
== xv
->model
){
419 g_signal_handler_block( xv
->widget
,xv
->handler_id
);
422 //set values of sibling views and unblock
423 for (int i
= 0; i
< MAX_XWIDGETS
; i
++)
425 xv
= &xwidget_views
[i
];
426 if(xv
->initialized
&& xvp
->model
== xv
->model
){
427 gtk_range_set_value(GTK_RANGE(xv
->widget
), v
);
428 g_signal_handler_unblock( xv
->widget
,xv
->handler_id
);
435 /* when the off-screen webkit master view changes this signal is called.
436 it copies the bitmap from the off-screen webkit instance */
438 webkit_osr_damage_event_callback (GtkWidget
*widget
, GdkEventExpose
*event
, gpointer data
)
440 //TODO this is wrong! should just oueu a redraw of onscreen widget
441 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (widget
), XG_XWIDGET
);
442 struct xwidget_view
* xv
;
443 //webkit_osr_redraw_child(xw, widget);
445 for (int i
= 0; i
< MAX_XWIDGETS
; i
++)//todo mvc refactor
447 xv
= &xwidget_views
[i
];
448 if(xv
->initialized
&& xv
->model
== xw
){
449 gtk_widget_queue_draw (xv
->widget
); //redraw all views, the master has changed
459 webkit_osr_key_event_callback (GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
)
461 printf("terminating a webkit osr keypress\n");
462 //TRUE terminate the event here. no paren handlers will be called. but webkit then doesng get the event and it still crashes
463 //FALSE paren handlers will be called. webkit then gets the event and it still crashes
469 store_xwidget_event_string(struct xwidget
* xw
, char* eventname
,char* eventstr
)
472 struct input_event event
;
476 event
.kind
= XWIDGET_EVENT
;
477 event
.frame_or_window
= Qnil
; //frame; //how to get the frame here? //TODO i store it in the xwidget now
480 event
.arg
= Fcons (build_string(eventstr
), event
.arg
); //string so dont intern
481 event
.arg
= Fcons (xwl
, event
.arg
); //TODO
482 event
.arg
= Fcons (intern (eventname
), event
.arg
);//interning should be ok
483 kbd_buffer_store_event (&event
);
487 //TODO deprecated, use load-status
489 webkit_osr_document_load_finished_callback (WebKitWebView
*webkitwebview
,
490 WebKitWebFrame
*arg1
,
493 //TODO this event sending code should be refactored
494 // struct xwidget *xw = (struct xwidget *) data;
495 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (webkitwebview
), XG_XWIDGET
);
496 printf("webkit finished loading\n");
498 store_xwidget_event_string(xw
,
499 "document-load-finished", "");
503 webkit_osr_download_callback (WebKitWebView
*webkitwebview
,
504 WebKitDownload
*arg1
,
507 //TODO this event sending code should be refactored
508 struct input_event event
;
509 // struct xwidget *xw = (struct xwidget *) data;
510 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (webkitwebview
), XG_XWIDGET
);
511 printf("download requested %s\n", webkit_download_get_uri (arg1
));
514 printf("webkit finished loading\n");
516 store_xwidget_event_string(xw
, "download-requested", webkit_download_get_uri (arg1
));
522 webkit_osr_mime_type_policy_typedecision_requested_callback(WebKitWebView
*webView
,
523 WebKitWebFrame
*frame
,
524 WebKitNetworkRequest
*request
,
526 WebKitWebPolicyDecision
*policy_decision
,
529 printf("mime policy requested\n");
530 // this function makes webkit send a download signal for all unknown mime types
531 // TODO defer the decision to lisp, so that its possible to make Emacs handle text mime for instance
532 if(!webkit_web_view_can_show_mime_type(webView
, mimetype
)){
533 webkit_web_policy_decision_download (policy_decision
);
542 webkit_osr_new_window_policy_decision_requested_callback(WebKitWebView
*webView
,
543 WebKitWebFrame
*frame
,
544 WebKitNetworkRequest
*request
,
545 WebKitWebNavigationAction
*navigation_action
,
546 WebKitWebPolicyDecision
*policy_decision
,
549 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (webView
), XG_XWIDGET
);
550 printf("webkit_osr_new_window_policy_decision_requested_callback %s\n",
551 webkit_web_navigation_action_get_original_uri (navigation_action
));
553 store_xwidget_event_string(xw
, "new-window-policy-decision-requested", webkit_web_navigation_action_get_original_uri (navigation_action
)
559 webkit_osr_navigation_policy_decision_requested_callback(WebKitWebView
*webView
,
560 WebKitWebFrame
*frame
,
561 WebKitNetworkRequest
*request
,
562 WebKitWebNavigationAction
*navigation_action
,
563 WebKitWebPolicyDecision
*policy_decision
,
566 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (webView
), XG_XWIDGET
);
567 printf("webkit_osr_navigation_policy_decision_requested_callback %s\n",
568 webkit_web_navigation_action_get_original_uri (navigation_action
));
569 store_xwidget_event_string(xw
, "navigation-policy-decision-requested", webkit_web_navigation_action_get_original_uri (navigation_action
)
574 //for gtk3 webkit_osr
576 xwidget_osr_draw_callback (GtkWidget
*widget
, cairo_t
*cr
, gpointer data
)
578 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (widget
), XG_XWIDGET
);
579 struct xwidget_view
* xv
= (struct xwidget_view
*) g_object_get_data (G_OBJECT (widget
), XG_XWIDGET_VIEW
);
581 // printf("xwidget_osr_draw_callback gtk3 xw.id:%d xw.type:%d window:%d vis:%d\n",
582 // xw,xw->type, gtk_widget_get_window (widget), gtk_widget_get_visible (xw->widget_osr));
584 cairo_rectangle(cr
, 0,0, xv
->clip_right
, xv
->clip_bottom
);//xw->width, xw->height);
587 gtk_widget_draw (xw
->widget_osr
, cr
);
595 xwidget_osr_button_callback (GtkWidget
*widget
,
599 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (widget
), XG_XWIDGET
);
600 GdkEvent
* eventcopy
= gdk_event_copy(event
);
602 ((GdkEventButton
*)eventcopy
)->window
= gtk_widget_get_window(xw
->widget_osr
);
603 gtk_main_do_event(eventcopy
); //TODO this will leak events. they should be deallocated later
604 return TRUE
; //dont propagate this event furter
608 GIRepository
*girepository
;
609 DEFUN( "xwgir-require-namespace",Fxwgir_require_namespace
, Sxwgir_require_namespace
, 2,2,0,
610 doc
: /*require a namespace. must be done for all namespaces we want to use, before using other xwgir functions.*/)
611 (Lisp_Object lnamespace
, Lisp_Object lnamespace_version
)
613 char* namespace = SDATA(lnamespace
);
614 char* namespace_version
= SDATA(lnamespace_version
);
615 GError
*error
= NULL
;
617 girepository
= g_irepository_get_default();
618 g_irepository_require(girepository
, namespace, namespace_version
, 0, &error
);
620 g_error("ERROR: %s\n", error
->message
);
626 GtkWidget
* xwgir_create(char* class, char* namespace){
627 //TODO this is more or less the same as xwgir-call-method, so should be refactored
628 //create a gtk widget, given its name
629 //find the constructor
631 //also figure out how to pass args
633 GError
*error
= NULL
;
634 GIArgument return_value
;
636 GIObjectInfo
* obj_info
= g_irepository_find_by_name(girepository
, namespace, class);
637 GIFunctionInfo
* f_info
= g_object_info_find_method (obj_info
, "new");
638 g_function_info_invoke(f_info
,
643 return return_value
.v_pointer
;
648 xwgir_convert_lisp_to_gir_arg(GIArgument
* giarg
,
650 Lisp_Object lisparg
)
656 tag
= g_type_info_get_tag (g_arg_info_get_type (arginfo
));
660 case GI_TYPE_TAG_BOOLEAN
:
661 giarg
->v_boolean
= XFASTINT(lisparg
);
663 case GI_TYPE_TAG_INT8
:
664 giarg
->v_int8
= XFASTINT(lisparg
);
666 case GI_TYPE_TAG_UINT8
:
667 giarg
->v_uint8
= XFASTINT(lisparg
);
669 case GI_TYPE_TAG_INT16
:
670 giarg
->v_int16
= XFASTINT(lisparg
);
672 case GI_TYPE_TAG_UINT16
:
673 giarg
->v_uint16
= XFASTINT(lisparg
);
675 case GI_TYPE_TAG_INT32
:
676 giarg
->v_int32
= XFASTINT(lisparg
);
678 case GI_TYPE_TAG_UINT32
:
679 giarg
->v_uint32
= XFASTINT(lisparg
);
682 case GI_TYPE_TAG_INT64
:
683 giarg
->v_int64
= XFASTINT(lisparg
);
685 case GI_TYPE_TAG_UINT64
:
686 giarg
->v_uint64
= XFASTINT(lisparg
);
690 case GI_TYPE_TAG_FLOAT
:
691 giarg
->v_float
= XFLOAT_DATA(lisparg
);
694 case GI_TYPE_TAG_DOUBLE
:
695 giarg
->v_double
= XFLOAT_DATA(lisparg
);
698 case GI_TYPE_TAG_UTF8
:
699 case GI_TYPE_TAG_FILENAME
:
700 //giarg->v_string = SDATA(lisparg);
701 giarg
->v_pointer
= SDATA(lisparg
);
704 case GI_TYPE_TAG_ARRAY
:
705 case GI_TYPE_TAG_GLIST
:
706 case GI_TYPE_TAG_GSLIST
:
707 case GI_TYPE_TAG_GHASH
:
708 case GI_TYPE_TAG_ERROR
:
709 case GI_TYPE_TAG_INTERFACE
:
710 case GI_TYPE_TAG_VOID
:
711 case GI_TYPE_TAG_UNICHAR
:
712 case GI_TYPE_TAG_GTYPE
:
713 //?? i dont know how to handle these yet TODO
714 printf("failed in my lisp to gir arg conversion duties. sob!\n");
721 DEFUN ("xwgir-call-method", Fxwgir_call_method
, Sxwgir_call_method
, 3, 3, 0,
722 doc
: /* call xwidget object method.*/)
723 (Lisp_Object xwidget
, Lisp_Object method
, Lisp_Object arguments
)
725 GError
*error
= NULL
;
726 GIArgument return_value
;
727 GIArgument in_args
[20];
731 if(!XXWIDGETP(xwidget
)) {printf("ERROR not an xwidget\n"); return Qnil
;};
732 if(Qnil
== xwidget
) {printf("ERROR xwidget nil\n"); return Qnil
;};
733 xw
= XXWIDGET(xwidget
);
734 if(NULL
== xw
) printf("ERROR xw is 0\n");
735 char* namespace = SDATA(Fcar(Fget(xw
->type
, Qcxwgir_class
)));
736 //we need the concrete widget, which happens in 2 ways depending on OSR or not TODO
737 GtkWidget
* widget
= NULL
;
738 if(NULL
== xw
->widget_osr
) {
739 widget
= xwidget_view_lookup (xw
, XWINDOW(FRAME_SELECTED_WINDOW (SELECTED_FRAME ()))) -> widget
;
741 widget
= xw
->widget_osr
;
744 //char* class = SDATA(SYMBOL_NAME(xw->type)); //this works but is unflexible
745 //figure out the class from the widget instead
746 /* printf("type class: %s %s\n", G_OBJECT_TYPE_NAME(widget), G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(widget))); */
747 /* char* class = G_OBJECT_TYPE_NAME(widget); //gives "GtkButton"(I want "Button") */
748 /* class += strlen(namespace); //TODO check for corresponding api method. but this seems to work. */
750 char* class = SDATA(Fcar(Fcdr(Fget(xw
->type
, Qcxwgir_class
))));
752 GIObjectInfo
* obj_info
= g_irepository_find_by_name(girepository
, namespace, class);
753 GIFunctionInfo
* f_info
= g_object_info_find_method (obj_info
, SDATA(method
));
755 //loop over args, convert from lisp to primitive type, given arg introspection data
756 //TODO g_callable_info_get_n_args(f_info) should match
757 int argscount
= XFASTINT(Flength(arguments
));
758 if(argscount
!= g_callable_info_get_n_args(f_info
)){
759 printf("xwgir call method arg count doesn match! \n");
763 for (i
= 1; i
< argscount
+ 1; ++i
)
765 xwgir_convert_lisp_to_gir_arg(&in_args
[i
], g_callable_info_get_arg(f_info
, i
- 1), Fnth(i
- 1, arguments
));
768 in_args
[0].v_pointer
= widget
;
769 if(g_function_info_invoke(f_info
,
770 in_args
, argscount
+ 1,
774 //g_error("ERROR: %s\n", error->message);
775 printf("invokation error\n");
784 int xwidget_view_index
=0;
786 /* initializes and does initial placement of an xwidget view on screen */
788 xwidget_init_view (struct xwidget
*xww
,
789 struct glyph_string
*s
,
792 //TODO temp code replace with lisp list
793 struct xwidget_view
*xv
;
797 if(xwidget_view_index
< MAX_XWIDGETS
)
798 xwidget_view_index
++;
800 xwidget_view_index
=0;
802 xv
= &xwidget_views
[xwidget_view_index
];
803 }while( xv
->initialized
== 1); //TODO yeah this can infloop if there are MAX_WIDGETS on-screen
810 if(EQ(xww
->type
, Qbutton
))
812 xv
->widget
= gtk_button_new_with_label (XSTRING(xww
->title
)->data
);
813 g_signal_connect (G_OBJECT (xv
->widget
), "clicked",
814 G_CALLBACK (buttonclick_handler
), xww
); //the model rather than the view
815 } else if (EQ(xww
->type
, Qtoggle
)) {
816 xv
->widget
= gtk_toggle_button_new_with_label (XSTRING(xww
->title
)->data
);
817 //xv->widget = gtk_entry_new ();//temp hack to experiment with key propagation TODO entry widget is useful for testing
818 } else if (EQ(xww
->type
, Qsocket
)) {
819 xv
->widget
= gtk_socket_new ();
820 g_signal_connect_after(xv
->widget
, "plug-added", G_CALLBACK(xwidget_plug_added
), "plug added");
821 g_signal_connect_after(xv
->widget
, "plug-removed", G_CALLBACK(xwidget_plug_removed
), "plug removed");
822 //TODO these doesnt help
823 gtk_widget_add_events(xv
->widget
, GDK_KEY_PRESS
);
824 gtk_widget_add_events(xv
->widget
, GDK_KEY_RELEASE
);
825 } else if (EQ(xww
->type
, Qslider
)) {
827 //gtk_hscale_new (GTK_ADJUSTMENT(gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 10.0, 10.0)));
828 gtk_hscale_new_with_range ( 0.0, 100.0, 10.0);
829 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
830 xv
->handler_id
= g_signal_connect_after(xv
->widget
, "value-changed", G_CALLBACK(xwidget_slider_changed
), "slider changed");
831 } else if (EQ(xww
->type
, Qcairo
)) {
833 //uhm cairo is differentish in gtk 3.
834 //gdk_cairo_create (gtk_widget_get_window (FRAME_GTK_WIDGET (s->f)));
835 #ifdef HAVE_GOOCANVAS
836 xv
->widget
= goo_canvas_new();
837 GooCanvasItem
*root
, *rect_item
, *text_item
;
838 goo_canvas_set_bounds (GOO_CANVAS (xv
->widget
), 0, 0, 1000, 1000);
839 root
= goo_canvas_get_root_item (GOO_CANVAS (xv
->widget
));
840 rect_item
= goo_canvas_rect_new (root
, 100, 100, 400, 400,
844 "stroke-color", "yellow",
848 text_item
= goo_canvas_text_new (root
, "Hello World", 300, 300, -1,
852 goo_canvas_item_rotate (text_item
, 45, 300, 300);
856 xv
->widget
= gtk_clutter_embed_new ();;
857 ClutterActor
*stage
= NULL
;
858 stage
= gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED ( xv
->widget
));
859 ClutterColor stage_color
= { 0xaa, 0xaa, 0xaa, 0xff }; /* Black */
860 clutter_stage_set_color (CLUTTER_STAGE (stage
), &stage_color
);
862 ClutterActor
* texture
= clutter_cairo_texture_new (1000, 1000);
863 clutter_container_add_actor(stage
, texture
);
864 clutter_actor_set_position(texture
, 0,0);
865 clutter_actor_show(texture
);
868 cr
= clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (texture
));
870 /* draw on the context */
871 RsvgHandle
*h
= rsvg_handle_new_from_file ("/tmp/tst.svg",
874 rsvg_handle_render_cairo(h
, cr
);
877 /* Show the stage: */
878 clutter_actor_show (stage
);
880 } else if (EQ(xww
->type
, Qwebkit_osr
)||EQ(xww
->type
, Qsocket_osr
)) {
881 #ifdef HAVE_WEBKIT_OSR
882 xv
->widget
= gtk_drawing_area_new();
883 gtk_widget_set_app_paintable ( xv
->widget
, TRUE
); //because expose event handling
884 gtk_widget_add_events(xv
->widget
,
885 GDK_BUTTON_PRESS_MASK
886 | GDK_BUTTON_RELEASE_MASK
887 | GDK_POINTER_MOTION_MASK
);
888 g_signal_connect (G_OBJECT ( xv
->widget
), "draw",
889 G_CALLBACK (xwidget_osr_draw_callback
), NULL
);
890 g_signal_connect (G_OBJECT ( xv
->widget
), "button-press-event",
891 G_CALLBACK (xwidget_osr_button_callback
), NULL
);
892 g_signal_connect (G_OBJECT ( xv
->widget
), "button-release-event",
893 G_CALLBACK (xwidget_osr_button_callback
), NULL
);
894 g_signal_connect (G_OBJECT ( xv
->widget
), "motion-notify-event",
895 G_CALLBACK (xwidget_osr_button_callback
), NULL
);
896 /* g_signal_connect (G_OBJECT ( xv->widget), "key-press-event", */
897 /* G_CALLBACK (xwidget_osr_button_callback), NULL); */
898 /* g_signal_connect (G_OBJECT ( xv->widget), "key-release-event", */
899 /* G_CALLBACK (xwidget_osr_button_callback), NULL); */
905 //here we have run out of hard coded symbols, we will now attempt to create
906 //a widget dynamically
909 // - support constructor args
911 // - check that the argument widget type actually exists
912 printf("xwgir symbol %s %s %s:\n",SDATA(SYMBOL_NAME(xww
->type
)), SDATA(Fcar(Fcdr(Fget(xww
->type
, Qcxwgir_class
)))), SDATA(Fcar(Fget(xww
->type
, Qcxwgir_class
))));
913 //xv->widget = xwgir_create ("Button");
914 Fcar(Fget(xww
->type
, Qcxwgir_class
));
915 xv
->widget
= xwgir_create( SDATA(Fcar(Fcdr(Fget(xww
->type
, Qcxwgir_class
)))),
916 SDATA(Fcar(Fget(xww
->type
, Qcxwgir_class
))));
923 //make container widget 1st, and put the actual widget inside the container
924 //later, drawing should crop container window if necessary to handle case where xwidget
925 //is partially obscured by other emacs windows
926 //other containers than gtk_fixed where explored, but gtk_fixed had the most predictable behaviour so far.
927 xv
->emacswindow
= GTK_CONTAINER (FRAME_GTK_WIDGET (s
->f
));
928 xv
->widgetwindow
= GTK_CONTAINER (gtk_fixed_new ());
929 gtk_widget_set_has_window(GTK_WIDGET ( xv
->widgetwindow
), TRUE
);
930 gtk_container_add (xv
->widgetwindow
, xv
->widget
);
932 //store some xwidget data in the gtk widgets
933 g_object_set_data (G_OBJECT (xv
->widget
), XG_FRAME_DATA
, (gpointer
) (s
->f
)); //the emacs frame
934 g_object_set_data (G_OBJECT (xv
->widget
), XG_XWIDGET
, (gpointer
) (xww
)); //the xwidget
935 g_object_set_data (G_OBJECT (xv
->widget
), XG_XWIDGET_VIEW
, (gpointer
) (xv
)); //the xwidget
936 g_object_set_data (G_OBJECT (xv
->widgetwindow
), XG_XWIDGET
, (gpointer
) (xww
)); //the xwidget window
937 g_object_set_data (G_OBJECT (xv
->widgetwindow
), XG_XWIDGET_VIEW
, (gpointer
) (xv
)); //the xwidget window
940 gtk_widget_set_size_request (GTK_WIDGET (xv
->widget
), xww
->width
, xww
->height
);
941 gtk_widget_set_size_request (GTK_WIDGET (xv
->widgetwindow
), xww
->width
, xww
->height
);
942 gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s
->f
)), GTK_WIDGET (xv
->widgetwindow
), x
, y
);
943 xv
->x
= x
; xv
->y
= y
;
944 gtk_widget_show_all (GTK_WIDGET (xv
->widgetwindow
));
946 //widgettype specific initialization only possible after realization
947 if (EQ(xww
->type
, Qsocket
)) {
948 printf ("xwid:%d socket id:%x %d\n",
950 gtk_socket_get_id (GTK_SOCKET (xv
->widget
)),
951 gtk_socket_get_id (GTK_SOCKET (xv
->widget
)));
952 send_xembed_ready_event (xww
,
953 gtk_socket_get_id (GTK_SOCKET (xv
->widget
)));
954 //gtk_widget_realize(xw->widget);
961 x_draw_xwidget_glyph_string (struct glyph_string
*s
)
964 this method is called by the redisplay engine and places the xwidget on screen.
965 moving and clipping is done here. also view init.
968 int box_line_hwidth
= eabs (s
->face
->box_line_width
);
969 int box_line_vwidth
= max (s
->face
->box_line_width
, 0);
970 int height
= s
->height
;
971 struct xwidget
*xww
= s
->xwidget
;
972 struct xwidget_view
*xv
= xwidget_view_lookup(xww
, (s
->w
));
973 int clip_right
; int clip_bottom
; int clip_top
; int clip_left
;
976 int y
= s
->y
+ (s
->height
/ 2) - (xww
->height
/ 2);
979 if (xv
== NULL
|| xv
->initialized
== 0){
980 /* Views must be initialized once(only once).
981 We do it here in the display loop because there is no other time to know things like
982 window placement etc.
984 printf ("xv init for xw %d\n", xww
);
985 xv
= xwidget_init_view (xww
, s
, x
, y
);
988 //calculate clipping, which is used for all manner of onscreen xwidget views
989 //each widget border can get clipped by other emacs objects so there are four clipping variables
990 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
));
991 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
));
993 clip_bottom
= min (xww
->height
, WINDOW_BOTTOM_EDGE_Y (s
->w
) - WINDOW_MODE_LINE_HEIGHT (s
->w
) - y
);
994 clip_top
= max(0, WINDOW_TOP_EDGE_Y(s
->w
) -y
);
996 //we are conserned with movement of the onscreen area. the area might sit still when the widget actually moves
997 //this happens when an emacs window border moves across a widget window
998 //so, if any corner of the outer widget clippng window moves, that counts as movement here, even
999 //if it looks like no movement happens because the widget sits still inside the clipping area.
1000 //the widget can also move inside the clipping area, which happens later
1001 moved
= (xv
->x
+ xv
->clip_left
!= x
+clip_left
)
1002 || ((xv
->y
+ xv
->clip_top
)!= (y
+clip_top
));
1003 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
);
1005 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
);
1008 if (moved
) //has it moved?
1010 if (1)//!xwidget_hidden(xv)) //hidden equals not being seen during redisplay
1012 //TODO should be possible to use xwidget_show_view here
1013 gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s
->f
)),
1014 GTK_WIDGET (xv
->widgetwindow
),
1015 x
+ clip_left
, y
+ clip_top
);
1018 //clip the widget window if some parts happen to be outside drawable area
1019 //an emacs window is not a gtk window, a gtk window covers the entire frame
1020 //cliping might have changed even if we havent actualy moved, we try figure out when we need to reclip for real
1021 if((xv
->clip_right
!= clip_right
)
1022 || (xv
->clip_bottom
!= clip_bottom
)
1023 || (xv
->clip_top
!= clip_top
)
1024 || (xv
->clip_left
!= clip_left
)){
1025 gtk_widget_set_size_request (GTK_WIDGET (xv
->widgetwindow
), clip_right
+ clip_left
, clip_bottom
+ clip_top
);
1026 gtk_fixed_move(GTK_FIXED(xv
->widgetwindow
), xv
->widget
, -clip_left
, -clip_top
);
1027 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
);
1030 xv
->clip_right
= clip_right
; xv
->clip_bottom
= clip_bottom
; xv
->clip_top
= clip_top
;xv
->clip_left
= clip_left
;
1032 //if emacs wants to repaint the area where the widget lives, queue a redraw
1033 //TODO it seems its possible to get out of sync with emacs redraws so emacs bg sometimes shows up instead of xwidget
1034 //its just a visual glitch though
1035 if (!xwidget_hidden(xv
)){
1036 gtk_widget_queue_draw (GTK_WIDGET(xv
->widgetwindow
));
1037 gtk_widget_queue_draw (xv
->widget
);
1042 #ifdef HAVE_WEBKIT_OSR
1044 //FUGLY macro that checks WEBKIT_IS_WEB_VIEW(xw->widget_osr) first
1045 #define WEBKIT_FN_INIT() \
1046 struct xwidget* xw; \
1047 if(!XXWIDGETP(xwidget)) {printf("ERROR not an xwidget\n"); return Qnil;}; \
1048 if(Qnil == xwidget) {printf("ERROR xwidget nil\n"); return Qnil;}; \
1049 xw = XXWIDGET(xwidget); \
1050 if(NULL == xw) printf("ERROR xw is 0\n"); \
1051 if((NULL == xw->widget_osr) || !WEBKIT_IS_WEB_VIEW(xw->widget_osr)){ \
1052 printf("ERROR xw->widget_osr does not hold a webkit instance\n");\
1057 DEFUN ("xwidget-webkit-goto-uri", Fxwidget_webkit_goto_uri
, Sxwidget_webkit_goto_uri
,
1059 doc
: /* webkit goto uri.*/)
1060 (Lisp_Object xwidget
, Lisp_Object uri
)
1063 webkit_web_view_load_uri ( WEBKIT_WEB_VIEW(xw
->widget_osr
), SDATA(uri
));
1068 DEFUN ("xwidget-webkit-execute-script", Fxwidget_webkit_execute_script
, Sxwidget_webkit_execute_script
,
1070 doc
: /* webkit exec js.*/)
1071 (Lisp_Object xwidget
, Lisp_Object script
)
1074 webkit_web_view_execute_script( WEBKIT_WEB_VIEW(xw
->widget_osr
), SDATA(script
));
1078 DEFUN ("xwidget-webkit-get-title", Fxwidget_webkit_get_title
, Sxwidget_webkit_get_title
,
1080 doc
: /* webkit get title. can be used to work around exec method lacks return val*/)
1081 (Lisp_Object xwidget
)
1083 //TODO support multibyte strings
1085 const gchar
* str
=webkit_web_view_get_title( WEBKIT_WEB_VIEW(xw
->widget_osr
));
1086 //return make_string_from_bytes(str, wcslen((const wchar_t *)str), strlen(str));
1088 //TODO maybe return Qnil instead. I suppose webkit returns nullpointer when doc is not properly loaded or something
1089 printf("xwidget-webkit-get-title null webkit title\n");
1090 return build_string("");
1092 return build_string(str
);
1096 DEFUN("xwidget-disable-plugin-for-mime", Fxwidget_disable_plugin_for_mime
, Sxwidget_disable_plugin_for_mime
,
1100 WebKitWebPlugin
*wp
= webkit_web_plugin_database_get_plugin_for_mimetype
1101 (webkit_get_web_plugin_database(), SDATA(mime
));
1102 if(wp
== NULL
) return Qnil
;
1103 if(webkit_web_plugin_get_enabled (wp
)){
1104 webkit_web_plugin_set_enabled (wp
, FALSE
);
1111 //attempting a workaround for a webkit offscreen bug
1112 //TODO verify its still needed
1114 gtk_window_get_position (GtkWindow
*window
,
1118 printf("my getsize\n");
1124 xwidget_webkit_dom_dump(WebKitDOMNode
* parent
)
1126 WebKitDOMNodeList
* list
;
1129 WebKitDOMNode
* attribute
;
1130 WebKitDOMNamedNodeMap
* attrs
;
1131 WebKitDOMNode
* child
;
1132 printf("node:%d type:%d name:%s content:%s\n",
1134 webkit_dom_node_get_node_type(parent
),//1 element 3 text 8 comment 2 attribute
1135 webkit_dom_node_get_local_name(parent
),
1136 webkit_dom_node_get_text_content(parent
));
1138 if(webkit_dom_node_has_attributes(parent
)){
1139 attrs
= webkit_dom_node_get_attributes(parent
);
1141 length
= webkit_dom_named_node_map_get_length(attrs
);
1142 for (int i
= 0; i
< length
; i
++) {
1143 attribute
= webkit_dom_named_node_map_item(attrs
,i
);
1144 printf(" attr node:%d type:%d name:%s content:%s\n",
1146 webkit_dom_node_get_node_type(attribute
),//1 element 3 text 8 comment
1147 webkit_dom_node_get_local_name(attribute
),
1148 webkit_dom_node_get_text_content(attribute
));
1151 list
= webkit_dom_node_get_child_nodes(parent
);
1152 length
= webkit_dom_node_list_get_length(list
);
1154 for (int i
= 0; i
< length
; i
++) {
1155 child
= webkit_dom_node_list_item(list
, i
);
1156 //if(webkit_dom_node_has_child_nodes(child))
1157 xwidget_webkit_dom_dump(child
);
1162 DEFUN ("xwidget-webkit-dom-dump", Fxwidget_webkit_dom_dump
, Sxwidget_webkit_dom_dump
,
1164 doc
: /* webkit dom dump*/)
1165 (Lisp_Object xwidget
)
1168 xwidget_webkit_dom_dump(WEBKIT_DOM_NODE(webkit_web_view_get_dom_document( WEBKIT_WEB_VIEW(xw
->widget_osr
))));
1180 DEFUN ("xwidget-resize", Fxwidget_resize
, Sxwidget_resize
, 3, 3, 0, doc
:
1181 /* resize xwidgets*/)
1182 (Lisp_Object xwidget
, Lisp_Object new_width
, Lisp_Object new_height
)
1184 struct xwidget
* xw
= XXWIDGET(xwidget
);
1185 struct xwidget_view
*xv
;
1188 CHECK_NUMBER (new_width
);
1189 CHECK_NUMBER (new_height
);
1190 w
= XFASTINT (new_width
);
1191 h
= XFASTINT (new_height
);
1194 printf("resize xwidget %d (%d,%d)->(%d,%d)\n",xw
, xw
->width
,xw
->height
,w
,h
);
1197 //if theres a osr resize it 1st
1199 printf("resize xwidget_osr\n");
1200 //gtk_container_set_resize_mode ( GTK_WINDOW(xw->widgetwindow_osr), GTK_RESIZE_QUEUE);
1201 //gtk_container_set_resize_mode ( GTK_WINDOW(xw->widget_osr), GTK_RESIZE_QUEUE);
1204 //gtk_layout_set_size (GTK_LAYOUT (xw->widgetwindow_osr), xw->width, xw->height);
1205 gtk_widget_set_size_request (GTK_WIDGET (xw
->widget_osr
), xw
->width
, xw
->height
); //minimum size
1206 //gtk_window_resize( GTK_WINDOW(xw->widget_osr), xw->width, xw->height);
1207 gtk_window_resize( GTK_WINDOW(xw
->widgetwindow_osr
), xw
->width
, xw
->height
);
1208 gtk_container_resize_children ( GTK_WINDOW(xw
->widgetwindow_osr
));
1212 for (int i
= 0; i
< MAX_XWIDGETS
; i
++) //TODO MVC refactor lazy linear search
1214 xv
= &xwidget_views
[i
];
1215 if(xv
->initialized
&& xv
->model
== xw
){
1216 gtk_layout_set_size (GTK_LAYOUT (xv
->widgetwindow
), xw
->width
, xw
->height
);
1217 gtk_widget_set_size_request (GTK_WIDGET (xv
->widget
), xw
->width
, xw
->height
);
1224 DEFUN ("xwidget-size-request", Fxwidget_size_request
, Sxwidget_size_request
, 1, 1, 0, doc
:
1225 /* desired size (TODO crashes if arg not osr widget)*/)
1226 (Lisp_Object xwidget
)
1228 GtkRequisition requisition
;
1230 gtk_widget_size_request(XXWIDGET(xwidget
)->widget_osr
, &requisition
);
1232 rv
= Fcons (make_number(requisition
.height
), rv
);
1233 rv
= Fcons (make_number(requisition
.width
), rv
);
1238 DEFUN ("xwidgetp", Fxwidgetp
, Sxwidgetp
, 1, 1, 0,
1239 doc
: /* Return t if OBJECT is a xwidget. */)
1240 (Lisp_Object object
)
1242 return XWIDGETP (object
) ? Qt
: Qnil
;
1245 DEFUN("xwidget-info", Fxwidget_info
, Sxwidget_info
, 1,1,0, doc
: /* get xwidget props */)
1246 (Lisp_Object xwidget
)
1249 struct xwidget
* xw
= XXWIDGET(xwidget
);
1251 info
= Fmake_vector (make_number (4), Qnil
);
1252 XSETSYMBOL (XVECTOR (info
)->contents
[0], xw
->type
);
1253 XSETSTRING (XVECTOR (info
)->contents
[1], xw
->title
);
1254 XSETINT (XVECTOR (info
)->contents
[2], xw
->width
);
1255 XSETINT (XVECTOR (info
)->contents
[3], xw
->height
);
1262 DEFUN("xwidget-view-info", Fxwidget_view_info
, Sxwidget_view_info
, 2,2,0, doc
: /* get xwidget view props */)
1263 (Lisp_Object xwidget
, Lisp_Object window
)
1265 struct xwidget
* xw
= XXWIDGET(xwidget
);
1266 struct xwidget_view
* xv
= xwidget_view_lookup(xw
, XWINDOW(window
));
1270 info
= Fmake_vector (make_number (6), Qnil
);
1271 XVECTOR (info
)->contents
[0] = make_number(xv
->x
);
1272 XVECTOR (info
)->contents
[1] = make_number(xv
->y
);
1273 XVECTOR (info
)->contents
[2] = make_number(xv
->clip_right
);
1274 XVECTOR (info
)->contents
[3] = make_number(xv
->clip_bottom
);
1275 XVECTOR (info
)->contents
[4] = make_number(xv
->clip_top
);
1276 XVECTOR (info
)->contents
[5] = make_number(xv
->clip_left
);
1281 DEFUN ("xwidget-send-keyboard-event", Fxwidget_send_keyboard_event
, Sxwidget_send_keyboard_event
, 2, 2, 0, doc
:/* synthesize a kbd event for a xwidget. */
1283 (Lisp_Object xwidget
, Lisp_Object keydescriptor
)
1285 //TODO this code crashes for offscreen widgets and ive tried many different strategies
1286 //int keyval = 0x058; //X
1287 int keyval
= XFASTINT(keydescriptor
); //X
1288 char *keystring
= "";
1291 GdkDeviceManager
* manager
;
1296 //popup_activated_flag = 1; //TODO just a hack
1297 gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), keyval
, &keys
, &n_keys
);
1299 xw
= XXWIDGET(xwidget
);
1301 ev
= (GdkEventKey
*)gdk_event_new(GDK_KEY_PRESS
);
1304 //todo what about windowless widgets?
1306 window
= FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
1309 //TODO maybe we also need to special case sockets by picking up the plug rather than the socket
1311 widget
= xw
->widget_osr
;
1313 widget
= xwidget_view_lookup(xw
, XWINDOW(window
))->widget
;
1315 ev
->window
= gtk_widget_get_window(widget
);
1316 gtk_widget_grab_focus(widget
);
1317 ev
->send_event
= FALSE
;
1319 ev
->hardware_keycode
= keys
[0].keycode
;
1320 ev
->group
= keys
[0].group
;
1322 ev
->keyval
= keyval
;
1323 ev
->time
= GDK_CURRENT_TIME
;
1325 //ev->device = gdk_device_get_core_pointer();
1326 manager
= gdk_display_get_device_manager(gdk_window_get_display(ev
->window
));
1327 gdk_event_set_device ((GdkEvent
*)ev
, gdk_device_manager_get_client_pointer(manager
));
1328 gdk_event_put((GdkEvent
*)ev
);
1329 //g_signal_emit_by_name(ev->window,"key-press-event", ev);
1331 ev
->type
= GDK_KEY_RELEASE
;
1332 gdk_event_put((GdkEvent
*)ev
);
1333 //g_signal_emit_by_name(ev->window,"key-release-event", ev);
1334 //gtk_main_do_event(ev);
1337 //if I delete the event the receiving component eventually crashes.
1338 //it ough TDTRT since event_put is supposed to copy the event
1339 //so probably this leaks events now
1340 //gdk_event_free((GdkEvent*)ev);
1347 DEFUN("xwidget-delete-zombies", Fxwidget_delete_zombies
, Sxwidget_delete_zombies
, 0,0,0, doc
: /* */)
1351 - remove all views with window gone
1354 - remove all xwidgets with buffer gone
1355 - remove all views with xw gone
1358 struct xwidget_view
* xv
= NULL
;
1360 for (int i
= 0; i
< MAX_XWIDGETS
; i
++){
1361 xv
= &xwidget_views
[i
];
1362 XSETWINDOW(w
, xv
->w
);
1363 if(xv
->initialized
&& (! (WINDOW_LIVE_P(w
)))){
1365 gtk_widget_destroy(GTK_WIDGET(xv
->widgetwindow
));
1366 xv
->initialized
= 0;
1372 DEFUN ("xwidget-plist", Fxwidget_plist
, Sxwidget_plist
,
1374 doc
: /* Return the plist of XWIDGET. */)
1375 (register Lisp_Object xwidget
)
1377 //CHECK_XWIDGET (xwidget); //todo
1378 return XXWIDGET (xwidget
)->plist
;
1381 DEFUN ("xwidget-buffer", Fxwidget_buffer
, Sxwidget_buffer
,
1383 doc
: /* Return the buffer of XWIDGET. */)
1384 (register Lisp_Object xwidget
)
1386 //CHECK_XWIDGET (xwidget); //todo
1387 return XXWIDGET (xwidget
)->buffer
;
1390 DEFUN ("set-xwidget-plist", Fset_xwidget_plist
, Sset_xwidget_plist
,
1392 doc
: /* Replace the plist of XWIDGET with PLIST. Returns PLIST. */)
1393 (register Lisp_Object xwidget
, Lisp_Object plist
)
1395 //CHECK_XWIDGET (xwidget); //todo
1398 XXWIDGET (xwidget
)->plist
= plist
;
1405 syms_of_xwidget (void)
1409 defsubr (&Smake_xwidget
);
1410 defsubr (&Sxwidgetp
);
1411 defsubr (&Sxwidget_info
);
1412 defsubr (&Sxwidget_view_info
);
1413 defsubr (&Sxwidget_resize
);
1415 #ifdef HAVE_WEBKIT_OSR
1416 defsubr (&Sxwidget_webkit_goto_uri
);
1417 defsubr (&Sxwidget_webkit_execute_script
);
1418 defsubr (&Sxwidget_webkit_get_title
);
1419 DEFSYM (Qwebkit_osr
,"webkit-osr");
1422 defsubr (&Sxwgir_call_method
);
1423 defsubr (&Sxwgir_require_namespace
);
1424 defsubr (&Sxwidget_size_request
);
1425 defsubr (&Sxwidget_delete_zombies
);
1426 defsubr (&Sxwidget_disable_plugin_for_mime
);
1428 defsubr (&Sxwidget_send_keyboard_event
);
1429 defsubr (&Sxwidget_webkit_dom_dump
);
1430 defsubr (&Sxwidget_plist
);
1431 defsubr (&Sxwidget_buffer
);
1432 defsubr (&Sset_xwidget_plist
);
1434 DEFSYM (Qxwidget
,"xwidget");
1436 DEFSYM (Qcxwidget
,":xwidget");
1437 DEFSYM (Qcxwgir_class
,":xwgir-class");
1438 DEFSYM (Qtitle
,":title");
1440 DEFSYM (Qbutton
, "Button"); //changed to match the gtk class because xwgir(experimental and not really needed)
1441 DEFSYM (Qtoggle
, "ToggleButton");
1442 DEFSYM (Qslider
, "slider");
1443 DEFSYM (Qsocket
, "socket");
1444 DEFSYM (Qsocket_osr
, "socket-osr");
1445 DEFSYM (Qcairo
, "cairo");
1447 DEFSYM (QCplist
, ":plist");
1449 DEFVAR_LISP ("xwidget-alist", Vxwidget_alist
, doc
: /*xwidgets list*/);
1450 Vxwidget_alist
= Qnil
;
1451 DEFVAR_LISP ("xwidget-view-alist", Vxwidget_view_alist
, doc
: /*xwidget views list*/);
1452 Vxwidget_alist
= Qnil
;
1454 Fprovide (intern ("xwidget-internal"), Qnil
);
1456 // for (i = 0; i < MAX_XWIDGETS; i++)
1457 //xwidgets[i].initialized = 0;
1461 /* Value is non-zero if OBJECT is a valid Lisp xwidget specification. A
1462 valid xwidget specification is a list whose car is the symbol
1463 `xwidget', and whose rest is a property list. The property list must
1464 contain a value for key `:type'. That value must be the name of a
1465 supported xwidget type. The rest of the property list depends on the
1469 valid_xwidget_p (Lisp_Object object
)
1473 if (XWIDGETP (object
))
1475 /* Lisp_Object tem; */
1477 /* for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem)) */
1478 /* if (EQ (XCAR (tem), QCtype)) */
1480 /* tem = XCDR (tem); */
1481 /* if (CONSP (tem) && SYMBOLP (XCAR (tem))) */
1483 /* struct xwidget_type *type; */
1484 /* type = lookup_xwidget_type (XCAR (tem)); */
1486 /* valid_p = type->valid_p (object); */
1491 //never mind type support for now
1500 /* find a value associated with key in spec */
1502 xwidget_spec_value ( Lisp_Object spec
, Lisp_Object key
,
1507 eassert (valid_xwidget_p (spec
));
1509 for (tail
= XCDR (spec
);
1510 CONSP (tail
) && CONSP (XCDR (tail
)); tail
= XCDR (XCDR (tail
)))
1512 if (EQ (XCAR (tail
), key
))
1516 return XCAR (XCDR (tail
));
1527 xwidget_view_delete_all_in_window (struct window
*w
)
1529 struct xwidget_view
* xv
= NULL
;
1530 for (int i
= 0; i
< MAX_XWIDGETS
; i
++){
1531 xv
= &xwidget_views
[i
];
1532 if(xv
->initialized
&& xv
->w
== w
){
1533 gtk_widget_destroy(GTK_WIDGET(xv
->widgetwindow
));
1534 xv
->initialized
= 0;
1541 struct xwidget_view
*
1542 xwidget_view_lookup (struct xwidget
* xw
, struct window
*w
)
1544 struct xwidget_view
* xv
= NULL
;
1545 for (int i
= 0; i
< MAX_XWIDGETS
; i
++){
1546 xv
= &xwidget_views
[i
];
1547 if (xv
->initialized
&& (xv
->model
== xw
) && (xv
->w
== w
))
1550 return NULL
; /* we didnt find a matching view */
1554 lookup_xwidget (Lisp_Object spec
)
1556 /* When a xwidget lisp spec is found initialize the C struct that is used in the C code.
1557 This is done by redisplay so values change if the spec changes.
1558 So, take special care of one-shot events
1560 TODO remove xwidget init from display spec. simply store an xwidget reference only and set
1561 size etc when creating the xwidget, which should happen before insertion into buffer
1563 int found
= 0, found1
= 0, found2
= 0;
1567 value
= xwidget_spec_value (spec
, Qcxwidget
, &found1
);
1568 xw
= XXWIDGET(value
);
1570 /* value = xwidget_spec_value (spec, QCtype, &found); */
1571 /* xw->type = SYMBOLP (value) ? value : Qbutton; //default to button */
1572 /* value = xwidget_spec_value (spec, Qtitle, &found2); */
1573 /* xw->title = STRINGP (value) ? (char *) SDATA (value) : "?"; //funky cast FIXME TODO */
1575 /* value = xwidget_spec_value (spec, QCheight, NULL); */
1576 /* xw->height = INTEGERP (value) ? XFASTINT (value) : 50; */
1577 /* value = xwidget_spec_value (spec, QCwidth, NULL); */
1578 /* xw->width = INTEGERP (value) ? XFASTINT (value) : 50; */
1580 /* value = xwidget_spec_value (spec, QCplist, NULL); */
1581 /* xw->plist = value; */
1582 /* coordinates are not known here */
1583 printf ("lookup_xwidget xwidget_id:%d type:%d found:%d %d %d title:'%s' (%d,%d)\n", xw
,
1584 xw
->type
, found
, found1
, found2
, xw
->title
, xw
->height
, xw
->width
);
1586 //assert_valid_xwidget_id (id, "lookup_xwidget");
1590 /*set up detection of touched xwidget*/
1592 xwidget_start_redisplay (void)
1595 for (i
= 0; i
< MAX_XWIDGETS
; i
++)
1596 xwidget_views
[i
].redisplayed
= 0;
1600 /* the xwidget was touched during redisplay, so it isnt a candidate for hiding*/
1602 xwidget_touch (struct xwidget_view
*xv
)
1604 xv
->redisplayed
= 1;
1608 xwidget_touched (struct xwidget_view
*xv
)
1610 return xv
->redisplayed
;
1613 /* redisplay has ended, now we should hide untouched xwidgets
1616 xwidget_end_redisplay (struct window
*w
, struct glyph_matrix
*matrix
)
1624 xwidget_start_redisplay ();
1625 //iterate desired glyph matrix of window here, hide gtk widgets
1626 //not in the desired matrix.
1628 //this only takes care of xwidgets in active windows.
1629 //if a window goes away from screen xwidget views wust be deleted
1631 // dump_glyph_matrix(matrix, 2);
1632 for (i
= 0; i
< matrix
->nrows
; ++i
)
1634 // dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs);
1635 struct glyph_row
*row
;
1636 row
= MATRIX_ROW (matrix
, i
);
1637 if (row
->enabled_p
!= 0)
1639 for (area
= LEFT_MARGIN_AREA
; area
< LAST_AREA
; ++area
)
1641 struct glyph
*glyph
= row
->glyphs
[area
];
1642 struct glyph
*glyph_end
= glyph
+ row
->used
[area
];
1643 for (; glyph
< glyph_end
; ++glyph
)
1645 if (glyph
->type
== XWIDGET_GLYPH
)
1648 the only call to xwidget_end_redisplay is in dispnew
1649 xwidget_end_redisplay(w->current_matrix);
1651 xwidget_touch (xwidget_view_lookup(glyph
->u
.xwidget
,
1659 for (i
= 0; i
< MAX_XWIDGETS
; i
++)
1661 struct xwidget_view
* xv
= &xwidget_views
[i
];
1663 //"touched" is only meaningful for the current window, so disregard other views
1664 if (xv
->initialized
&& ( xv
->w
== w
))
1666 if (xwidget_touched(xv
))
1667 xwidget_show_view (xv
);
1669 xwidget_hide_view (xv
);