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 Lisp_Object Qxwidget
;
117 Lisp_Object QCxwidget
;
119 Lisp_Object Qxwidget_set_keyboard_grab
;
120 Lisp_Object Qxwidget_embed_steal_window
;
121 Lisp_Object Qxwidget_info
;
122 Lisp_Object Qxwidget_resize
;
123 Lisp_Object Qxwidget_send_keyboard_event
;
124 Lisp_Object QCxwgir_class
;
125 Lisp_Object Qbutton
, Qtoggle
, Qslider
, Qsocket
, Qsocket_osr
, Qcairo
, Qxwgir
,
126 Qwebkit_osr
, QCplist
;
127 Lisp_Object Qxwidgetp
, Qxwidget_view_p
;
130 extern Lisp_Object QCtype
;
131 extern Lisp_Object QCwidth
, QCheight
;
133 struct xwidget_view
* xwidget_view_lookup(struct xwidget
* xw
, struct window
*w
);
134 Lisp_Object
xwidget_spec_value ( Lisp_Object spec
, Lisp_Object key
, int *found
);
135 gboolean
offscreen_damage_event (GtkWidget
*widget
, GdkEvent
*event
, gpointer data
);
136 void webkit_osr_document_load_finished_callback (WebKitWebView
*webkitwebview
,
137 WebKitWebFrame
*arg1
,
139 gboolean
webkit_osr_download_callback (WebKitWebView
*webkitwebview
,
140 WebKitDownload
*arg1
,
143 gboolean
webkit_osr_mime_type_policy_typedecision_requested_callback(WebKitWebView
*webView
,
144 WebKitWebFrame
*frame
,
145 WebKitNetworkRequest
*request
,
147 WebKitWebPolicyDecision
*policy_decision
,
150 gboolean
webkit_osr_new_window_policy_decision_requested_callback(WebKitWebView
*webView
,
151 WebKitWebFrame
*frame
,
152 WebKitNetworkRequest
*request
,
153 WebKitWebNavigationAction
*navigation_action
,
154 WebKitWebPolicyDecision
*policy_decision
,
158 gboolean
webkit_osr_navigation_policy_decision_requested_callback(WebKitWebView
*webView
,
159 WebKitWebFrame
*frame
,
160 WebKitNetworkRequest
*request
,
161 WebKitWebNavigationAction
*navigation_action
,
162 WebKitWebPolicyDecision
*policy_decision
,
165 GtkWidget
* xwgir_create(char* class, char* namespace);
167 send_xembed_ready_event (struct xwidget
* xw
, int xembedid
);
168 DEFUN ("make-xwidget", Fmake_xwidget
, Smake_xwidget
, 7, 8, 0,
169 doc
: /* Make an xwidget from BEG to END of TYPE.
171 If BUFFER is nil it uses the current buffer. If BUFFER is a string and
172 no such buffer exists, it is created.
174 TYPE is a symbol which can take one of the following values:
183 (Lisp_Object beg
, Lisp_Object end
,
186 Lisp_Object width
, Lisp_Object height
,
190 //should work a bit like "make-button"(make-button BEG END &rest PROPERTIES)
191 // arg "type" and fwd should be keyword args eventually
192 //(make-xwidget 3 3 'button "oei" 31 31 nil)
193 //(xwidget-info (car xwidget-list))
194 struct xwidget
* xw
= allocate_xwidget();
199 buffer
= Fcurrent_buffer(); // no need to gcpro because Fcurrent_buffer doesn't call Feval/eval_sub.
201 buffer
= Fget_buffer_create (buffer
);
204 xw
->height
= XFASTINT(height
);
205 xw
->width
= XFASTINT(width
);
206 xw
->kill_without_query
= 0;
207 XSETXWIDGET (val
, xw
); // set the vectorlike_header of VAL with the correct value
208 Vxwidget_list
= Fcons (val
, Vxwidget_list
);
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 EQ(xw
->type
, Qsocket_osr
)||
220 (!NILP (Fget(xw
->type
, QCxwgir_class
)))) {
222 xw
->widgetwindow_osr
= gtk_offscreen_window_new ();
223 gtk_window_resize(GTK_WINDOW(xw
->widgetwindow_osr
), xw
->width
, xw
->height
);
225 if (EQ(xw
->type
, Qwebkit_osr
))
226 xw
->widget_osr
= webkit_web_view_new();
227 if(EQ(xw
->type
, Qsocket_osr
))
228 xw
->widget_osr
= gtk_socket_new();
229 if(!NILP (Fget(xw
->type
, QCxwgir_class
)))
230 xw
->widget_osr
= xwgir_create(SDATA(Fcar(Fcdr(Fget(xw
->type
, QCxwgir_class
)))),
231 SDATA(Fcar(Fget(xw
->type
, QCxwgir_class
))));
233 gtk_widget_set_size_request (GTK_WIDGET (xw
->widget_osr
), xw
->width
, xw
->height
);
234 gtk_container_add (GTK_CONTAINER (xw
->widgetwindow_osr
), xw
->widget_osr
);
236 gtk_widget_show (xw
->widget_osr
);
237 gtk_widget_show (xw
->widgetwindow_osr
);
239 /* store some xwidget data in the gtk widgets for convenient retrieval in the event handlers. */
240 g_object_set_data (G_OBJECT (xw
->widget_osr
), XG_XWIDGET
, (gpointer
) (xw
));
241 g_object_set_data (G_OBJECT (xw
->widgetwindow_osr
), XG_XWIDGET
, (gpointer
) (xw
));
244 if (EQ(xw
->type
, Qwebkit_osr
)) {
245 g_signal_connect (G_OBJECT (xw
->widget_osr
),
246 "document-load-finished",
247 G_CALLBACK (webkit_osr_document_load_finished_callback
),
250 g_signal_connect (G_OBJECT (xw
->widget_osr
),
251 "download-requested",
252 G_CALLBACK (webkit_osr_download_callback
),
255 g_signal_connect (G_OBJECT (xw
->widget_osr
),
256 "mime-type-policy-decision-requested",
257 G_CALLBACK (webkit_osr_mime_type_policy_typedecision_requested_callback
),
260 g_signal_connect (G_OBJECT (xw
->widget_osr
),
261 "new-window-policy-decision-requested",
262 G_CALLBACK (webkit_osr_new_window_policy_decision_requested_callback
),
265 g_signal_connect (G_OBJECT (xw
->widget_osr
),
266 "navigation-policy-decision-requested",
267 G_CALLBACK (webkit_osr_navigation_policy_decision_requested_callback
),
271 if (EQ(xw
->type
, Qsocket_osr
)) {
272 send_xembed_ready_event (xw
, gtk_socket_get_id (GTK_SOCKET (xw
->widget_osr
)));
273 //gtk_widget_realize(xw->widget);
280 #endif /* HAVE_WEBKIT_OSR */
285 DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets
, Sget_buffer_xwidgets
, 1, 1, 0,
286 doc
: /* Return a list of xwidgets associated with BUFFER.
287 BUFFER may be a buffer or the name of one.
292 Lisp_Object xw
, tail
, xw_list
;
294 if (NILP (buffer
)) return Qnil
;
295 buffer
= Fget_buffer (buffer
);
296 if (NILP (buffer
)) return Qnil
;
300 for (tail
= Vxwidget_list
; CONSP (tail
); tail
= XCDR (tail
))
303 if (XWIDGETP (xw
) && EQ (Fxwidget_buffer (xw
), buffer
))
304 xw_list
= Fcons (xw
, xw_list
);
310 xwidget_hidden(struct xwidget_view
*xv
)
317 buttonclick_handler (GtkWidget
* widget
, gpointer data
)
319 Lisp_Object xwidget_view
, xwidget
;
320 XSETXWIDGET_VIEW (xwidget_view
, (struct xwidget_view
*) data
);
321 xwidget
= Fxwidget_view_model (xwidget_view
);
323 struct input_event event
;
324 Lisp_Object frame
= Fwindow_frame (Fxwidget_view_window (xwidget_view
));
325 struct frame
*f
= XFRAME (frame
);
326 printf ("button clicked xw:%d '%s'\n", XXWIDGET (xwidget
), XXWIDGET (xwidget
)->title
);
329 event
.kind
= XWIDGET_EVENT
;
331 event
.frame_or_window
= frame
;
334 event
.arg
= Fcons (xwidget
, event
.arg
);
335 event
.arg
= Fcons (intern ("buttonclick"), event
.arg
);
337 kbd_buffer_store_event (&event
);
342 send_xembed_ready_event (struct xwidget
* xw
, int xembedid
)
345 XSETXWIDGET(xw_lo
, xw
);
346 struct input_event event
;
348 event
.kind
= XWIDGET_EVENT
;
349 event
.frame_or_window
= Qnil
; //frame; //how to get the frame here? //TODO i store it in the xwidget now
352 event
.arg
= Fcons (make_number (xembedid
), event
.arg
);
353 event
.arg
= Fcons (xw_lo
, event
.arg
);
354 event
.arg
= Fcons (intern ("xembed-ready"), event
.arg
);
357 kbd_buffer_store_event (&event
);
362 xwidget_show_view (struct xwidget_view
*xv
)
365 gtk_widget_show(xv
->widgetwindow
);
366 gtk_fixed_move (GTK_FIXED (xv
->emacswindow
), xv
->widgetwindow
, xv
->x
+ xv
->clip_left
, xv
->y
+ xv
->clip_top
); //TODO refactor
370 /* hide an xvidget view */
372 xwidget_hide_view (struct xwidget_view
*xv
)
375 //gtk_widget_hide(xw->widgetwindow);
376 gtk_fixed_move (GTK_FIXED (xv
->emacswindow
), xv
->widgetwindow
,
382 xwidget_plug_added(GtkSocket
*socket
,
385 //hmm this doesnt seem to get called for foreign windows
386 printf("xwidget_plug_added\n");
390 xwidget_plug_removed(GtkSocket
*socket
,
393 printf("xwidget_plug_removed\n");
394 return TRUE
; /* dont run the default handler because that kills the socket and we want to reuse it*/
399 xwidget_slider_changed (GtkRange
*range
,
402 //slider value changed. change value of siblings
403 //correspondingly. but remember that changing value will again
406 //TODO MVC view storage wont be an array futureish so the loop needs to change eventually
407 //TODO MVC it would be nice if this code could be reusable but, alas, C is not a functional language
409 // - the type of the controllers value (double, boolean etc)
410 // - the getter and setter (but they can be func pointers)
411 // a behemoth macro is always an option.
412 double v
=gtk_range_get_value(range
);
413 struct xwidget_view
* xvp
= g_object_get_data (G_OBJECT (range
), XG_XWIDGET_VIEW
);
414 struct xwidget_view
* xv
;
416 printf("slider changed val:%f\n", v
);
418 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
); tail
= XCDR (tail
))
420 if (XWIDGET_VIEW_P (XCAR (tail
))) {
421 xv
= XXWIDGET_VIEW (XCAR (tail
));
422 if (EQ (xvp
->model
, xv
->model
)) {
423 //block sibling views signal handlers
424 g_signal_handler_block(xv
->widget
, xv
->handler_id
);
426 //set values of sibling views and unblock
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 offscreen_damage_event (GtkWidget
*widget
, GdkEvent
*event
, gpointer data
)
440 //TODO this is wrong! should just queu a redraw of onscreen widget
441 gtk_widget_queue_draw (GTK_WIDGET (data
));
446 store_xwidget_event_string(struct xwidget
* xw
, char* eventname
, const char* eventstr
)
449 struct input_event event
;
453 event
.kind
= XWIDGET_EVENT
;
454 event
.frame_or_window
= Qnil
; //frame; //how to get the frame here? //TODO i store it in the xwidget now
457 event
.arg
= Fcons (build_string(eventstr
), event
.arg
); //string so dont intern
458 event
.arg
= Fcons (xwl
, event
.arg
); //TODO
459 event
.arg
= Fcons (intern (eventname
), event
.arg
);//interning should be ok
460 kbd_buffer_store_event (&event
);
464 //TODO deprecated, use load-status
466 webkit_osr_document_load_finished_callback (WebKitWebView
*webkitwebview
,
467 WebKitWebFrame
*arg1
,
470 //TODO this event sending code should be refactored
471 // struct xwidget *xw = (struct xwidget *) data;
472 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (webkitwebview
), XG_XWIDGET
);
473 printf("webkit finished loading\n");
475 store_xwidget_event_string(xw
,
476 "document-load-finished", "");
480 webkit_osr_download_callback (WebKitWebView
*webkitwebview
,
481 WebKitDownload
*arg1
,
484 //TODO this event sending code should be refactored
485 struct input_event event
;
486 // struct xwidget *xw = (struct xwidget *) data;
487 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (webkitwebview
), XG_XWIDGET
);
488 printf("download requested %s\n", webkit_download_get_uri (arg1
));
491 printf("webkit finished loading\n");
493 store_xwidget_event_string(xw
, "download-requested", webkit_download_get_uri (arg1
));
499 webkit_osr_mime_type_policy_typedecision_requested_callback(WebKitWebView
*webView
,
500 WebKitWebFrame
*frame
,
501 WebKitNetworkRequest
*request
,
503 WebKitWebPolicyDecision
*policy_decision
,
506 printf("mime policy requested\n");
507 // this function makes webkit send a download signal for all unknown mime types
508 // TODO defer the decision to lisp, so that its possible to make Emacs handle text mime for instance
509 if(!webkit_web_view_can_show_mime_type(webView
, mimetype
)){
510 webkit_web_policy_decision_download (policy_decision
);
519 webkit_osr_new_window_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_new_window_policy_decision_requested_callback %s\n",
528 webkit_web_navigation_action_get_original_uri (navigation_action
));
530 store_xwidget_event_string(xw
, "new-window-policy-decision-requested", webkit_web_navigation_action_get_original_uri (navigation_action
)
536 webkit_osr_navigation_policy_decision_requested_callback(WebKitWebView
*webView
,
537 WebKitWebFrame
*frame
,
538 WebKitNetworkRequest
*request
,
539 WebKitWebNavigationAction
*navigation_action
,
540 WebKitWebPolicyDecision
*policy_decision
,
543 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (webView
), XG_XWIDGET
);
544 printf("webkit_osr_navigation_policy_decision_requested_callback %s\n",
545 webkit_web_navigation_action_get_original_uri (navigation_action
));
546 store_xwidget_event_string(xw
, "navigation-policy-decision-requested", webkit_web_navigation_action_get_original_uri (navigation_action
)
551 //for gtk3 offscreen rendered widgets
553 xwidget_osr_draw_callback (GtkWidget
*widget
, cairo_t
*cr
, gpointer data
)
555 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (widget
), XG_XWIDGET
);
556 struct xwidget_view
* xv
= (struct xwidget_view
*) g_object_get_data (G_OBJECT (widget
), XG_XWIDGET_VIEW
);
558 cairo_rectangle(cr
, 0,0, xv
->clip_right
, xv
->clip_bottom
);//xw->width, xw->height);
561 gtk_widget_draw (xw
->widget_osr
, cr
);
566 GtkWidget
* xwgir_create_debug
;
571 xwidget_osr_event_forward (GtkWidget
*widget
,
575 /* copy events that arrive at the outer widget to the offscreen widget */
576 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (widget
), XG_XWIDGET
);
577 GdkEvent
* eventcopy
= gdk_event_copy(event
);
578 //GdkEvent* eventcopy = gdk_event_new(GDK_BUTTON_PRESS);
581 //((GdkEventAny*)eventcopy)->window = gtk_widget_get_window(xw->widget_osr);
582 //eventcopy->any.window = gtk_widget_get_window(GTK_WIDGET (xw->widgetwindow_osr));
583 //((GdkEventAny*)eventcopy)->window = gtk_widget_get_window(xwgir_create_debug);
584 eventcopy
->any
.window
= gtk_widget_get_window(xw
->widget_osr
);//gtk_widget_get_window(xwgir_create_debug);
585 //eventcopy->any.window = gtk_button_get_event_window(GTK_BUTTON(xw->widget_osr));//gtk_widget_get_window(xwgir_create_debug);
586 //eventcopy->button.x=200; eventcopy->button.y=200;
587 //event->button.button = GDK_BUTTON_PRIMARY; //debug
589 //eventcopy->any.window = xw->widgetwindow_osr;//gtk_widget_get_window(xwgir_create_debug);
590 /* eventcopy->any.send_event = TRUE; */
591 /* eventcopy->button.time = GDK_CURRENT_TIME; */
592 /* eventcopy->button.device = event->button.device; */
595 printf("xwidget_osr_event_forward redirect event to window:%d\n", ((GdkEventAny
*)eventcopy
)->window
);
596 printf("A type:%d x:%f y:%f \n", event
->type
, event
->button
.x
, event
->button
.y
);
597 printf("B type:%d x:%f y:%f \n", eventcopy
->type
, eventcopy
->button
.x
, eventcopy
->button
.y
);
598 //gtk_button_get_event_window(xwgir_create_debug);
599 gtk_main_do_event(eventcopy
); //TODO this will leak events. they should be deallocated later, perhaps in xwgir_event_callback
600 //printf("gtk_widget_event:%d\n",gtk_widget_event(xw->widget_osr, eventcopy));
601 //gdk_event_put(eventcopy);
602 //gdk_event_queue_append(eventcopy);
603 //gdk_event_free(eventcopy);
604 return TRUE
; //dont propagate this event furter
605 //return FALSE; //dont propagate this event furter
608 GIRepository
*girepository
;
610 DEFUN ("xwgir-require-namespace", Fxwgir_require_namespace
, Sxwgir_require_namespace
, 2,2,0,
611 doc
: /* Require a GObject Introspection namespace.
612 This must be done for all namespaces we want to use, before using other xwgir functions.*/)
613 (Lisp_Object lnamespace
, Lisp_Object lnamespace_version
)
615 char* namespace = SDATA(lnamespace
);
616 char* namespace_version
= SDATA(lnamespace_version
);
617 GError
*error
= NULL
;
619 girepository
= g_irepository_get_default();
620 g_irepository_require(girepository
, namespace, namespace_version
, 0, &error
);
622 g_error("ERROR: %s\n", error
->message
);
628 GtkWidget
* xwgir_create(char* class, char* namespace){
629 //TODO this is more or less the same as xwgir-call-method, so should be refactored
630 //create a gtk widget, given its name
631 //find the constructor
633 //also figure out how to pass args
635 GError
*error
= NULL
;
636 GIArgument return_value
;
638 GIObjectInfo
* obj_info
= g_irepository_find_by_name(girepository
, namespace, class);
639 GIFunctionInfo
* f_info
= g_object_info_find_method (obj_info
, "new");
640 g_function_info_invoke(f_info
,
645 xwgir_create_debug
= return_value
.v_pointer
;
646 return return_value
.v_pointer
;
651 xwgir_convert_lisp_to_gir_arg(GIArgument
* giarg
,
653 Lisp_Object lisparg
)
659 tag
= g_type_info_get_tag (g_arg_info_get_type (arginfo
));
663 case GI_TYPE_TAG_BOOLEAN
:
664 giarg
->v_boolean
= XFASTINT(lisparg
);
666 case GI_TYPE_TAG_INT8
:
667 giarg
->v_int8
= XFASTINT(lisparg
);
669 case GI_TYPE_TAG_UINT8
:
670 giarg
->v_uint8
= XFASTINT(lisparg
);
672 case GI_TYPE_TAG_INT16
:
673 giarg
->v_int16
= XFASTINT(lisparg
);
675 case GI_TYPE_TAG_UINT16
:
676 giarg
->v_uint16
= XFASTINT(lisparg
);
678 case GI_TYPE_TAG_INT32
:
679 giarg
->v_int32
= XFASTINT(lisparg
);
681 case GI_TYPE_TAG_UINT32
:
682 giarg
->v_uint32
= XFASTINT(lisparg
);
685 case GI_TYPE_TAG_INT64
:
686 giarg
->v_int64
= XFASTINT(lisparg
);
688 case GI_TYPE_TAG_UINT64
:
689 giarg
->v_uint64
= XFASTINT(lisparg
);
693 case GI_TYPE_TAG_FLOAT
:
694 giarg
->v_float
= XFLOAT_DATA(lisparg
);
697 case GI_TYPE_TAG_DOUBLE
:
698 giarg
->v_double
= XFLOAT_DATA(lisparg
);
701 case GI_TYPE_TAG_UTF8
:
702 case GI_TYPE_TAG_FILENAME
:
703 //giarg->v_string = SDATA(lisparg);
704 giarg
->v_pointer
= SDATA(lisparg
);
707 case GI_TYPE_TAG_ARRAY
:
708 case GI_TYPE_TAG_GLIST
:
709 case GI_TYPE_TAG_GSLIST
:
710 case GI_TYPE_TAG_GHASH
:
711 case GI_TYPE_TAG_ERROR
:
712 case GI_TYPE_TAG_INTERFACE
:
713 case GI_TYPE_TAG_VOID
:
714 case GI_TYPE_TAG_UNICHAR
:
715 case GI_TYPE_TAG_GTYPE
:
716 //?? i dont know how to handle these yet TODO
717 printf("failed in my lisp to gir arg conversion duties. sob!\n");
727 //this methhod should be called from xwgir-xwidget-call-method and from xwgir xwidget construction
728 char* class = SDATA(Fcar(Fcdr(Fget(xw
->type
, QCxwgir_class
))));
730 GIObjectInfo
* obj_info
= g_irepository_find_by_name(girepository
, namespace, class);
731 GIFunctionInfo
* f_info
= g_object_info_find_method (obj_info
, SDATA(method
));
733 //loop over args, convert from lisp to primitive type, given arg introspection data
734 //TODO g_callable_info_get_n_args(f_info) should match
735 int argscount
= XFASTINT(Flength(arguments
));
736 if(argscount
!= g_callable_info_get_n_args(f_info
)){
737 printf("xwgir call method arg count doesn match! \n");
741 for (i
= 1; i
< argscount
+ 1; ++i
)
743 xwgir_convert_lisp_to_gir_arg(&in_args
[i
], g_callable_info_get_arg(f_info
, i
- 1), Fnth(i
- 1, arguments
));
746 in_args
[0].v_pointer
= widget
;
747 if(g_function_info_invoke(f_info
,
748 in_args
, argscount
+ 1,
752 //g_error("ERROR: %s\n", error->message);
753 printf("invokation error\n");
760 DEFUN ("xwgir-xwidget-call-method", Fxwgir_xwidget_call_method
, Sxwgir_xwidget_call_method
, 3, 3, 0,
761 doc
: /* Call Xwidget object method using GObject Introspection.
762 XWIDGET is the xwidget instance to act upon.
763 METHOD is the Gobject intrsopsection method name.
764 ARGUMENTS is a list of arguments for the call. They will be converted to GObject types from Lisp types.
766 (Lisp_Object xwidget
, Lisp_Object method
, Lisp_Object arguments
)
768 CHECK_XWIDGET (xwidget
);
769 GError
*error
= NULL
;
770 GIArgument return_value
;
771 GIArgument in_args
[20];
775 if (NILP (xwidget
)) { printf("ERROR xwidget nil\n"); return Qnil
; };
776 xw
= XXWIDGET(xwidget
);
777 if(NULL
== xw
) printf("ERROR xw is 0\n");
778 char* namespace = SDATA(Fcar(Fget(xw
->type
, QCxwgir_class
)));
779 //we need the concrete widget, which happens in 2 ways depending on OSR or not TODO
780 GtkWidget
* widget
= NULL
;
781 if(NULL
== xw
->widget_osr
) {
782 widget
= xwidget_view_lookup (xw
, XWINDOW(FRAME_SELECTED_WINDOW (SELECTED_FRAME ()))) -> widget
;
784 widget
= xw
->widget_osr
;
787 //char* class = SDATA(SYMBOL_NAME(xw->type)); //this works but is unflexible
788 //figure out the class from the widget instead
789 /* printf("type class: %s %s\n", G_OBJECT_TYPE_NAME(widget), G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(widget))); */
790 /* char* class = G_OBJECT_TYPE_NAME(widget); //gives "GtkButton"(I want "Button") */
791 /* class += strlen(namespace); //TODO check for corresponding api method. but this seems to work. */
793 char* class = SDATA(Fcar(Fcdr(Fget(xw
->type
, QCxwgir_class
))));
795 GIObjectInfo
* obj_info
= g_irepository_find_by_name(girepository
, namespace, class);
796 GIFunctionInfo
* f_info
= g_object_info_find_method (obj_info
, SDATA(method
));
798 //loop over args, convert from lisp to primitive type, given arg introspection data
799 //TODO g_callable_info_get_n_args(f_info) should match
800 int argscount
= XFASTINT(Flength(arguments
));
801 if(argscount
!= g_callable_info_get_n_args(f_info
)){
802 printf("xwgir call method arg count doesn match! \n");
807 for (i
= 1; i
< argscount
+ 1; ++i
)
809 XSETFASTINT (n
, i
- 1);
810 xwgir_convert_lisp_to_gir_arg(&in_args
[i
], g_callable_info_get_arg(f_info
, i
- 1), Fnth(n
, arguments
));
813 in_args
[0].v_pointer
= widget
;
814 if(g_function_info_invoke(f_info
,
815 in_args
, argscount
+ 1,
819 //g_error("ERROR: %s\n", error->message);
820 printf("invokation error\n");
827 to_child (GtkWidget
*bin
,
839 offscreen_pick_embedded_child (GdkWindow
*window
,
844 //in this simple case we assume the window contains a single widget. easy.
845 //but then we get the problem that the widget cant be embedded in several windows
846 return gtk_widget_get_window (GTK_WIDGET (data
));
850 offscreen_to_embedder (GdkWindow
*window
,
857 * (gdouble
*) embedder_x
= offscreen_x
;
858 * (gdouble
*) embedder_y
= offscreen_y
;
862 offscreen_from_embedder (GdkWindow
*window
,
865 gpointer offscreen_x
,
866 gpointer offscreen_y
,
869 * (gdouble
*) offscreen_x
= embedder_x
;
870 * (gdouble
*) offscreen_y
= embedder_y
;
874 xwidget_osr_event_set_embedder (GtkWidget
*widget
,
878 struct xwidget_view
*xv
= (struct xwidget_view
*) data
;
879 struct xwidget
*xww
= XXWIDGET (xv
->model
);
880 printf("gdk_offscreen_window_set_embedder %d %d\n",
881 GDK_IS_WINDOW(gtk_widget_get_window (xww
->widget_osr
)),
882 GDK_IS_WINDOW(gtk_widget_get_window (GTK_WIDGET (xv
->widget
))));
883 gdk_offscreen_window_set_embedder (gtk_widget_get_window (xww
->widgetwindow_osr
),
884 gtk_widget_get_window (xv
->widget
));
888 /* initializes and does initial placement of an xwidget view on screen */
890 xwidget_init_view (struct xwidget
*xww
,
891 struct glyph_string
*s
,
894 struct xwidget_view
*xv
= allocate_xwidget_view();
898 XSETXWIDGET_VIEW (val
, xv
) ;
899 Vxwidget_view_list
= Fcons (val
, Vxwidget_view_list
);
901 XSETWINDOW(xv
->w
, s
->w
);
902 XSETXWIDGET(xv
->model
, xww
);
905 if(EQ(xww
->type
, Qbutton
))
907 xv
->widget
= gtk_button_new_with_label (XSTRING(xww
->title
)->data
);
908 g_signal_connect (G_OBJECT (xv
->widget
), "clicked",
909 G_CALLBACK (buttonclick_handler
), xv
); // the view rather than the model
910 } else if (EQ(xww
->type
, Qtoggle
)) {
911 xv
->widget
= gtk_toggle_button_new_with_label (XSTRING(xww
->title
)->data
);
912 //xv->widget = gtk_entry_new ();//temp hack to experiment with key propagation TODO entry widget is useful for testing
913 } else if (EQ(xww
->type
, Qsocket
)) {
914 xv
->widget
= gtk_socket_new ();
915 g_signal_connect_after(xv
->widget
, "plug-added", G_CALLBACK(xwidget_plug_added
), "plug added");
916 g_signal_connect_after(xv
->widget
, "plug-removed", G_CALLBACK(xwidget_plug_removed
), "plug removed");
917 //TODO these doesnt help
918 gtk_widget_add_events(xv
->widget
, GDK_KEY_PRESS
);
919 gtk_widget_add_events(xv
->widget
, GDK_KEY_RELEASE
);
920 } else if (EQ(xww
->type
, Qslider
)) {
922 //gtk_hscale_new (GTK_ADJUSTMENT(gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 10.0, 10.0)));
923 gtk_hscale_new_with_range ( 0.0, 100.0, 10.0);
924 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
925 xv
->handler_id
= g_signal_connect_after(xv
->widget
, "value-changed", G_CALLBACK(xwidget_slider_changed
), "slider changed");
926 } else if (EQ(xww
->type
, Qcairo
)) {
928 //uhm cairo is differentish in gtk 3.
929 //gdk_cairo_create (gtk_widget_get_window (FRAME_GTK_WIDGET (s->f)));
930 xv
->widget
= gtk_drawing_area_new();
931 g_signal_connect (G_OBJECT ( xv
->widget
), "draw",
932 G_CALLBACK (xwidget_osr_draw_callback
), NULL
);
934 } else if (EQ(xww
->type
, Qwebkit_osr
)||
935 EQ(xww
->type
, Qsocket_osr
)||
936 (!NILP (Fget(xww
->type
, QCxwgir_class
))))//xwgir widgets are OSR
938 printf("osr init:%s\n",SDATA(SYMBOL_NAME(xww
->type
)));
939 xv
->widget
= gtk_drawing_area_new();
940 gtk_widget_set_app_paintable ( xv
->widget
, TRUE
); //because expose event handling
941 gtk_widget_add_events(xv
->widget
, GDK_ALL_EVENTS_MASK
);
943 /* Draw the view on damage-event */
944 g_signal_connect (G_OBJECT (xww
->widgetwindow_osr
), "damage-event",
945 G_CALLBACK (offscreen_damage_event
), xv
->widget
);
947 if (EQ(xww
->type
, Qwebkit_osr
)){
949 /* //forward events. this isnt compatible with the set_embedded strategy */
950 g_signal_connect (G_OBJECT ( xv
->widget
), "button-press-event",
951 G_CALLBACK (xwidget_osr_event_forward
), NULL
);
952 g_signal_connect (G_OBJECT ( xv
->widget
), "button-release-event",
953 G_CALLBACK (xwidget_osr_event_forward
), NULL
);
954 g_signal_connect (G_OBJECT ( xv
->widget
), "motion-notify-event",
955 G_CALLBACK (xwidget_osr_event_forward
), NULL
);
957 //xwgir debug , orthogonal to forwarding
958 g_signal_connect (G_OBJECT (xv
->widget
), "enter-notify-event",
959 G_CALLBACK (xwidget_osr_event_set_embedder
), xv
);
963 g_signal_connect (G_OBJECT (xv
->widget
), "draw",
964 G_CALLBACK (xwidget_osr_draw_callback
), NULL
);
970 //make container widget 1st, and put the actual widget inside the container
971 //later, drawing should crop container window if necessary to handle case where xwidget
972 //is partially obscured by other emacs windows
973 //other containers than gtk_fixed where explored, but gtk_fixed had the most predictable behaviour so far.
974 xv
->emacswindow
= FRAME_GTK_WIDGET (s
->f
);
975 xv
->widgetwindow
= gtk_fixed_new ();
976 gtk_widget_set_has_window(xv
->widgetwindow
, TRUE
);
977 gtk_container_add (GTK_CONTAINER (xv
->widgetwindow
), xv
->widget
);
979 //store some xwidget data in the gtk widgets
980 g_object_set_data (G_OBJECT (xv
->widget
), XG_FRAME_DATA
, (gpointer
) (s
->f
)); //the emacs frame
981 g_object_set_data (G_OBJECT (xv
->widget
), XG_XWIDGET
, (gpointer
) (xww
)); //the xwidget
982 g_object_set_data (G_OBJECT (xv
->widget
), XG_XWIDGET_VIEW
, (gpointer
) (xv
)); //the xwidget
983 g_object_set_data (G_OBJECT (xv
->widgetwindow
), XG_XWIDGET
, (gpointer
) (xww
)); //the xwidget window
984 g_object_set_data (G_OBJECT (xv
->widgetwindow
), XG_XWIDGET_VIEW
, (gpointer
) (xv
)); //the xwidget window
987 gtk_widget_set_size_request (GTK_WIDGET (xv
->widget
), xww
->width
, xww
->height
);
988 gtk_widget_set_size_request (xv
->widgetwindow
, xww
->width
, xww
->height
);
989 gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s
->f
)), xv
->widgetwindow
, x
, y
);
990 xv
->x
= x
; xv
->y
= y
;
991 gtk_widget_show_all (xv
->widgetwindow
);
995 //widgettype specific initialization only possible after realization
996 if (EQ(xww
->type
, Qsocket
)) {
997 printf ("xwid:%d socket id:%x %d\n",
999 gtk_socket_get_id (GTK_SOCKET (xv
->widget
)),
1000 gtk_socket_get_id (GTK_SOCKET (xv
->widget
)));
1001 send_xembed_ready_event (xww
,
1002 gtk_socket_get_id (GTK_SOCKET (xv
->widget
)));
1003 //gtk_widget_realize(xw->widget);
1006 //////////////////////////////////////////////////////////////
1008 if (//EQ(xww->type, Qwebkit_osr)|| //TODO should be able to choose compile time which method to use with webkit
1009 EQ(xww
->type
, Qsocket_osr
)||
1010 (!NILP (Fget(xww
->type
, QCxwgir_class
))))//xwgir widgets are OSR
1012 printf("gdk_offscreen_window_set_embedder %d %d\n",
1013 GDK_IS_WINDOW(gtk_widget_get_window (xww
->widget_osr
)),
1014 GDK_IS_WINDOW(gtk_widget_get_window (GTK_WIDGET (xv
->widget
))));
1015 // set_embedder needs to be called after xv->widget realization
1016 gdk_offscreen_window_set_embedder (gtk_widget_get_window (xww
->widgetwindow_osr
),
1017 gtk_widget_get_window (xv
->widget
));
1018 g_signal_connect (gtk_widget_get_window (xv
->widget
), "pick-embedded-child",
1019 G_CALLBACK (offscreen_pick_embedded_child
), xww
->widgetwindow_osr
);
1021 g_signal_connect (gtk_widget_get_window (xww
->widgetwindow_osr
), "from-embedder",
1022 G_CALLBACK (offscreen_from_embedder
), NULL
);
1023 g_signal_connect (gtk_widget_get_window (xww
->widgetwindow_osr
), "to-embedder",
1024 G_CALLBACK (offscreen_to_embedder
), NULL
);
1026 ////////////////////////////////////////
1033 x_draw_xwidget_glyph_string (struct glyph_string
*s
)
1036 this method is called by the redisplay engine and places the xwidget on screen.
1037 moving and clipping is done here. also view init.
1040 int box_line_hwidth
= eabs (s
->face
->box_line_width
);
1041 int box_line_vwidth
= max (s
->face
->box_line_width
, 0);
1042 int height
= s
->height
;
1043 struct xwidget
*xww
= s
->xwidget
;
1044 struct xwidget_view
*xv
= xwidget_view_lookup(xww
, s
->w
);
1045 int clip_right
; int clip_bottom
; int clip_top
; int clip_left
;
1048 int y
= s
->y
+ (s
->height
/ 2) - (xww
->height
/ 2);
1051 /* We do it here in the display loop because there is no other
1052 time to know things like window placement etc.
1054 printf ("xv init for xw %d\n", xww
);
1055 xv
= xwidget_init_view (xww
, s
, x
, y
);
1057 //calculate clipping, which is used for all manner of onscreen xwidget views
1058 //each widget border can get clipped by other emacs objects so there are four clipping variables
1059 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
));
1060 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
));
1062 clip_bottom
= min (xww
->height
, WINDOW_BOTTOM_EDGE_Y (s
->w
) - WINDOW_MODE_LINE_HEIGHT (s
->w
) - y
);
1063 clip_top
= max(0, WINDOW_TOP_EDGE_Y(s
->w
) -y
);
1065 //we are conserned with movement of the onscreen area. the area might sit still when the widget actually moves
1066 //this happens when an emacs window border moves across a widget window
1067 //so, if any corner of the outer widget clippng window moves, that counts as movement here, even
1068 //if it looks like no movement happens because the widget sits still inside the clipping area.
1069 //the widget can also move inside the clipping area, which happens later
1070 moved
= (xv
->x
+ xv
->clip_left
!= x
+clip_left
)
1071 || ((xv
->y
+ xv
->clip_top
)!= (y
+clip_top
));
1072 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
);
1074 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
);
1077 if (moved
) //has it moved?
1079 if (1)//!xwidget_hidden(xv)) //hidden equals not being seen during redisplay
1081 //TODO should be possible to use xwidget_show_view here
1082 gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s
->f
)),
1084 x
+ clip_left
, y
+ clip_top
);
1087 //clip the widget window if some parts happen to be outside drawable area
1088 //an emacs window is not a gtk window, a gtk window covers the entire frame
1089 //cliping might have changed even if we havent actualy moved, we try figure out when we need to reclip for real
1090 if((xv
->clip_right
!= clip_right
)
1091 || (xv
->clip_bottom
!= clip_bottom
)
1092 || (xv
->clip_top
!= clip_top
)
1093 || (xv
->clip_left
!= clip_left
)){
1094 gtk_widget_set_size_request (xv
->widgetwindow
, clip_right
+ clip_left
, clip_bottom
+ clip_top
);
1095 gtk_fixed_move(GTK_FIXED(xv
->widgetwindow
), xv
->widget
, -clip_left
, -clip_top
);
1096 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
);
1099 xv
->clip_right
= clip_right
; xv
->clip_bottom
= clip_bottom
; xv
->clip_top
= clip_top
;xv
->clip_left
= clip_left
;
1101 //if emacs wants to repaint the area where the widget lives, queue a redraw
1102 //TODO it seems its possible to get out of sync with emacs redraws so emacs bg sometimes shows up instead of xwidget
1103 //its just a visual glitch though
1104 if (!xwidget_hidden(xv
)){
1105 gtk_widget_queue_draw (xv
->widgetwindow
);
1106 gtk_widget_queue_draw (xv
->widget
);
1111 #ifdef HAVE_WEBKIT_OSR
1113 //FUGLY macro that checks WEBKIT_IS_WEB_VIEW(xw->widget_osr) first
1114 #define WEBKIT_FN_INIT() \
1115 struct xwidget* xw; \
1116 CHECK_XWIDGET (xwidget); \
1117 if(NILP (xwidget)) {printf("ERROR xwidget nil\n"); return Qnil;}; \
1118 xw = XXWIDGET(xwidget); \
1119 if(NULL == xw) printf("ERROR xw is 0\n"); \
1120 if((NULL == xw->widget_osr) || !WEBKIT_IS_WEB_VIEW(xw->widget_osr)){ \
1121 printf("ERROR xw->widget_osr does not hold a webkit instance\n");\
1126 DEFUN ("xwidget-webkit-goto-uri", Fxwidget_webkit_goto_uri
, Sxwidget_webkit_goto_uri
,
1128 doc
: /* Make the webkit instance referenced by XWIDGET browse URI. */)
1129 (Lisp_Object xwidget
, Lisp_Object uri
)
1133 webkit_web_view_load_uri ( WEBKIT_WEB_VIEW(xw
->widget_osr
), SDATA(uri
));
1138 DEFUN ("xwidget-webkit-execute-script", Fxwidget_webkit_execute_script
, Sxwidget_webkit_execute_script
,
1140 doc
: /* webkit exec js.*/)
1141 (Lisp_Object xwidget
, Lisp_Object script
)
1144 CHECK_STRING(script
);
1145 webkit_web_view_execute_script( WEBKIT_WEB_VIEW(xw
->widget_osr
), SDATA(script
));
1149 DEFUN ("xwidget-webkit-get-title", Fxwidget_webkit_get_title
, Sxwidget_webkit_get_title
,
1151 doc
: /* Get the title from the Webkit instance in XWIDGET.
1152 This can be used to work around the lack of a return value from the exec method.
1154 (Lisp_Object xwidget
)
1156 //TODO support multibyte strings
1158 const gchar
* str
=webkit_web_view_get_title( WEBKIT_WEB_VIEW(xw
->widget_osr
));
1159 //return make_string_from_bytes(str, wcslen((const wchar_t *)str), strlen(str));
1161 //TODO maybe return Qnil instead. I suppose webkit returns nullpointer when doc is not properly loaded or something
1162 printf("xwidget-webkit-get-title null webkit title\n");
1163 return build_string("");
1165 return build_string(str
);
1169 DEFUN("xwidget-disable-plugin-for-mime", Fxwidget_disable_plugin_for_mime
, Sxwidget_disable_plugin_for_mime
,
1173 WebKitWebPlugin
*wp
= webkit_web_plugin_database_get_plugin_for_mimetype
1174 (webkit_get_web_plugin_database(), SDATA(mime
));
1175 if(wp
== NULL
) return Qnil
;
1176 if(webkit_web_plugin_get_enabled (wp
)){
1177 webkit_web_plugin_set_enabled (wp
, FALSE
);
1185 xwidget_webkit_dom_dump(WebKitDOMNode
* parent
)
1187 WebKitDOMNodeList
* list
;
1190 WebKitDOMNode
* attribute
;
1191 WebKitDOMNamedNodeMap
* attrs
;
1192 WebKitDOMNode
* child
;
1193 printf("node:%d type:%d name:%s content:%s\n",
1195 webkit_dom_node_get_node_type(parent
),//1 element 3 text 8 comment 2 attribute
1196 webkit_dom_node_get_local_name(parent
),
1197 webkit_dom_node_get_text_content(parent
));
1199 if(webkit_dom_node_has_attributes(parent
)){
1200 attrs
= webkit_dom_node_get_attributes(parent
);
1202 length
= webkit_dom_named_node_map_get_length(attrs
);
1203 for (int i
= 0; i
< length
; i
++) {
1204 attribute
= webkit_dom_named_node_map_item(attrs
,i
);
1205 printf(" attr node:%d type:%d name:%s content:%s\n",
1207 webkit_dom_node_get_node_type(attribute
),//1 element 3 text 8 comment
1208 webkit_dom_node_get_local_name(attribute
),
1209 webkit_dom_node_get_text_content(attribute
));
1212 list
= webkit_dom_node_get_child_nodes(parent
);
1213 length
= webkit_dom_node_list_get_length(list
);
1215 for (int i
= 0; i
< length
; i
++) {
1216 child
= webkit_dom_node_list_item(list
, i
);
1217 //if(webkit_dom_node_has_child_nodes(child))
1218 xwidget_webkit_dom_dump(child
);
1223 DEFUN ("xwidget-webkit-dom-dump", Fxwidget_webkit_dom_dump
, Sxwidget_webkit_dom_dump
,
1225 doc
: /*Dump the DOM contained in the webkit instance in XWIDGET.*/)
1226 (Lisp_Object xwidget
)
1229 xwidget_webkit_dom_dump(WEBKIT_DOM_NODE(webkit_web_view_get_dom_document( WEBKIT_WEB_VIEW(xw
->widget_osr
))));
1235 #endif /* HAVE_WEBKIT_OSR */
1241 DEFUN ("xwidget-resize", Fxwidget_resize
, Sxwidget_resize
, 3, 3, 0, doc
:
1243 NEW_WIDTH NEW_HEIGHT defines the new size.)
1245 (Lisp_Object xwidget
, Lisp_Object new_width
, Lisp_Object new_height
)
1247 CHECK_XWIDGET (xwidget
);
1248 struct xwidget
* xw
= XXWIDGET(xwidget
);
1249 struct xwidget_view
*xv
;
1252 CHECK_NUMBER (new_width
);
1253 CHECK_NUMBER (new_height
);
1254 w
= XFASTINT (new_width
);
1255 h
= XFASTINT (new_height
);
1258 printf("resize xwidget %d (%d,%d)->(%d,%d)\n",xw
, xw
->width
,xw
->height
,w
,h
);
1261 //if theres a osr resize it 1st
1263 printf("resize xwidget_osr\n");
1264 //gtk_container_set_resize_mode ( GTK_WINDOW(xw->widgetwindow_osr), GTK_RESIZE_QUEUE);
1265 //gtk_container_set_resize_mode ( GTK_WINDOW(xw->widget_osr), GTK_RESIZE_QUEUE);
1268 //gtk_layout_set_size (GTK_LAYOUT (xw->widgetwindow_osr), xw->width, xw->height);
1269 gtk_widget_set_size_request (GTK_WIDGET (xw
->widget_osr
), xw
->width
, xw
->height
); //minimum size
1270 //gtk_window_resize( GTK_WINDOW(xw->widget_osr), xw->width, xw->height);
1271 gtk_window_resize( GTK_WINDOW(xw
->widgetwindow_osr
), xw
->width
, xw
->height
);
1272 //gtk_container_resize_children ( GTK_WINDOW(xw->widgetwindow_osr));
1273 gtk_container_resize_children (GTK_CONTAINER(xw
->widgetwindow_osr
));
1277 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
); tail
= XCDR (tail
)) //TODO MVC refactor lazy linear search
1279 if (XWIDGET_VIEW_P (XCAR (tail
))) {
1280 xv
= XXWIDGET_VIEW (XCAR (tail
));
1281 if(XXWIDGET (xv
->model
) == xw
) {
1282 gtk_layout_set_size (GTK_LAYOUT (xv
->widgetwindow
), xw
->width
, xw
->height
);
1283 gtk_widget_set_size_request (GTK_WIDGET (xv
->widget
), xw
->width
, xw
->height
);
1291 DEFUN ("xwidget-size-request", Fxwidget_size_request
, Sxwidget_size_request
, 1, 1, 0, doc
:
1292 - /* Desired size of the XWIDGET.
1294 This can be used to read the xwidget desired size, and resizes the Emacs allocated area accordingly.
1296 (TODO crashes if arg not osr widget)*/)
1297 (Lisp_Object xwidget
)
1299 CHECK_XWIDGET (xwidget
);
1300 GtkRequisition requisition
;
1302 gtk_widget_size_request(XXWIDGET(xwidget
)->widget_osr
, &requisition
);
1304 rv
= Fcons (make_number(requisition
.height
), rv
);
1305 rv
= Fcons (make_number(requisition
.width
), rv
);
1310 DEFUN ("xwidgetp", Fxwidgetp
, Sxwidgetp
, 1, 1, 0,
1311 doc
: /* Return t if OBJECT is a xwidget. */)
1312 (Lisp_Object object
)
1314 return XWIDGETP (object
) ? Qt
: Qnil
;
1317 DEFUN ("xwidget-view-p", Fxwidget_view_p
, Sxwidget_view_p
, 1, 1, 0,
1318 doc
: /* Return t if OBJECT is a xwidget-view. */)
1319 (Lisp_Object object
)
1321 return XWIDGET_VIEW_P (object
) ? Qt
: Qnil
;
1324 DEFUN ("xwidget-info", Fxwidget_info
, Sxwidget_info
, 1,1,0,
1325 doc
: /* Get XWIDGET properties.
1326 Currently type, title, width, height.*/)
1327 (Lisp_Object xwidget
)
1329 CHECK_XWIDGET (xwidget
);
1330 Lisp_Object info
, n
;
1331 struct xwidget
* xw
= XXWIDGET(xwidget
);
1333 info
= Fmake_vector (make_number (4), Qnil
);
1334 ASET (info
, 0, xw
->type
);
1335 ASET (info
, 1, xw
->title
);
1336 XSETFASTINT(n
, xw
->width
);
1338 XSETFASTINT(n
, xw
->height
);
1344 DEFUN ("xwidget-view-info", Fxwidget_view_info
, Sxwidget_view_info
, 1, 1, 0, doc
:
1345 /* Get XWIDGET-VIEW properties.
1346 Currently x,y clip right, clip bottom, clip top, clip left*/)
1347 (Lisp_Object xwidget_view
)
1349 CHECK_XWIDGET_VIEW (xwidget_view
);
1350 struct xwidget_view
*xv
= XXWIDGET_VIEW (xwidget_view
);
1353 info
= Fmake_vector (make_number (6), Qnil
);
1354 ASET (info
, 0, make_number(xv
->x
));
1355 ASET (info
, 1, make_number(xv
->y
));
1356 ASET (info
, 2, make_number(xv
->clip_right
));
1357 ASET (info
, 3, make_number(xv
->clip_bottom
));
1358 ASET (info
, 4, make_number(xv
->clip_top
));
1359 ASET (info
, 5, make_number(xv
->clip_left
));
1364 DEFUN ("xwidget-view-model", Fxwidget_view_model
, Sxwidget_view_model
,
1366 doc
: /* Get XWIDGET-VIEW model. */)
1367 (Lisp_Object xwidget_view
)
1369 CHECK_XWIDGET_VIEW (xwidget_view
);
1370 return XXWIDGET_VIEW (xwidget_view
)->model
;
1373 DEFUN ("xwidget-view-window", Fxwidget_view_window
, Sxwidget_view_window
,
1375 doc
: /* Get XWIDGET-VIEW window. */)
1376 (Lisp_Object xwidget_view
)
1378 CHECK_XWIDGET_VIEW (xwidget_view
);
1379 return XXWIDGET_VIEW (xwidget_view
)->w
;
1382 DEFUN ("xwidget-send-keyboard-event", Fxwidget_send_keyboard_event
, Sxwidget_send_keyboard_event
, 2, 2, 0,
1383 doc
:/* Synthesize a kbd event for XWIDGET. TODO crashes atm.. */
1385 (Lisp_Object xwidget
, Lisp_Object keydescriptor
)
1387 //TODO this code crashes for offscreen widgets and ive tried many different strategies
1388 //int keyval = 0x058; //X
1389 int keyval
= XFASTINT(keydescriptor
); //X
1390 char *keystring
= "";
1393 GdkDeviceManager
* manager
;
1398 //popup_activated_flag = 1; //TODO just a hack
1399 gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), keyval
, &keys
, &n_keys
);
1401 xw
= XXWIDGET(xwidget
);
1403 ev
= (GdkEventKey
*)gdk_event_new(GDK_KEY_PRESS
);
1406 //todo what about windowless widgets?
1408 window
= FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
1411 //TODO maybe we also need to special case sockets by picking up the plug rather than the socket
1413 widget
= xw
->widget_osr
;
1415 widget
= xwidget_view_lookup(xw
, XWINDOW(window
))->widget
;
1417 ev
->window
= gtk_widget_get_window(widget
);
1418 gtk_widget_grab_focus(widget
);
1419 ev
->send_event
= FALSE
;
1421 ev
->hardware_keycode
= keys
[0].keycode
;
1422 ev
->group
= keys
[0].group
;
1424 ev
->keyval
= keyval
;
1425 ev
->time
= GDK_CURRENT_TIME
;
1427 //ev->device = gdk_device_get_core_pointer();
1428 manager
= gdk_display_get_device_manager(gdk_window_get_display(ev
->window
));
1429 gdk_event_set_device ((GdkEvent
*)ev
, gdk_device_manager_get_client_pointer(manager
));
1430 gdk_event_put((GdkEvent
*)ev
);
1431 //g_signal_emit_by_name(ev->window,"key-press-event", ev);
1433 ev
->type
= GDK_KEY_RELEASE
;
1434 gdk_event_put((GdkEvent
*)ev
);
1435 //g_signal_emit_by_name(ev->window,"key-release-event", ev);
1436 //gtk_main_do_event(ev);
1439 //if I delete the event the receiving component eventually crashes.
1440 //it ough TDTRT since event_put is supposed to copy the event
1441 //so probably this leaks events now
1442 //gdk_event_free((GdkEvent*)ev);
1447 DEFUN ("delete-xwidget-view", Fdelete_xwidget_view
, Sdelete_xwidget_view
,
1449 doc
: /* Delete the XWIDGET-VIEW. */)
1450 (Lisp_Object xwidget_view
)
1452 CHECK_XWIDGET_VIEW (xwidget_view
);
1453 struct xwidget_view
*xv
= XXWIDGET_VIEW (xwidget_view
);
1454 gtk_widget_destroy(xv
->widgetwindow
);
1455 Vxwidget_view_list
= Fdelq (xwidget_view
, Vxwidget_view_list
);
1458 DEFUN ("xwidget-view-lookup", Fxwidget_view_lookup
, Sxwidget_view_lookup
,
1460 doc
: /* Return the xwidget-view associated to XWIDGET in
1461 WINDOW if specified, otherwise it uses the selected window. */)
1462 (Lisp_Object xwidget
, Lisp_Object window
)
1464 CHECK_XWIDGET (xwidget
);
1467 window
= Fselected_window();
1468 CHECK_WINDOW (window
);
1470 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
); tail
= XCDR (tail
))
1472 Lisp_Object xwidget_view
= XCAR (tail
);
1473 if (EQ (Fxwidget_view_model (xwidget_view
), xwidget
)
1474 && EQ (Fxwidget_view_window (xwidget_view
), window
))
1475 return xwidget_view
;
1481 DEFUN ("set-frame-visible", Fset_frame_visible
, Sset_frame_visible
,
1484 (Lisp_Object frame
, Lisp_Object flag
)
1486 CHECK_FRAME (frame
);
1487 struct frame
*f
= XFRAME (frame
);
1488 SET_FRAME_VISIBLE (f
, !NILP (flag
));
1492 DEFUN ("xwidget-plist", Fxwidget_plist
, Sxwidget_plist
,
1494 doc
: /* Return the plist of XWIDGET. */)
1495 (register Lisp_Object xwidget
)
1497 CHECK_XWIDGET (xwidget
);
1498 return XXWIDGET (xwidget
)->plist
;
1501 DEFUN ("xwidget-buffer", Fxwidget_buffer
, Sxwidget_buffer
,
1503 doc
: /* Return the buffer of XWIDGET. */)
1504 (register Lisp_Object xwidget
)
1506 CHECK_XWIDGET (xwidget
);
1507 return XXWIDGET (xwidget
)->buffer
;
1510 DEFUN ("set-xwidget-plist", Fset_xwidget_plist
, Sset_xwidget_plist
,
1512 doc
: /* Replace the plist of XWIDGET with PLIST. Returns PLIST. */)
1513 (register Lisp_Object xwidget
, Lisp_Object plist
)
1515 CHECK_XWIDGET (xwidget
);
1518 XXWIDGET (xwidget
)->plist
= plist
;
1522 DEFUN ("set-xwidget-query-on-exit-flag",
1523 Fset_xwidget_query_on_exit_flag
, Sset_xwidget_query_on_exit_flag
,
1525 doc
: /* Specify if query is needed for XWIDGET when Emacs is
1526 exited. If the second argument FLAG is non-nil, Emacs will query the
1527 user before exiting or killing a buffer if XWIDGET is running. This
1528 function returns FLAG. */)
1529 (Lisp_Object xwidget
, Lisp_Object flag
)
1531 CHECK_XWIDGET (xwidget
);
1532 XXWIDGET (xwidget
)->kill_without_query
= NILP (flag
);
1536 DEFUN ("xwidget-query-on-exit-flag",
1537 Fxwidget_query_on_exit_flag
, Sxwidget_query_on_exit_flag
,
1539 doc
: /* Return the current value of query-on-exit flag for XWIDGET. */)
1540 (Lisp_Object xwidget
)
1542 CHECK_XWIDGET (xwidget
);
1543 return (XXWIDGET (xwidget
)->kill_without_query
? Qnil
: Qt
);
1547 syms_of_xwidget (void)
1551 defsubr (&Smake_xwidget
);
1552 defsubr (&Sxwidgetp
);
1553 DEFSYM (Qxwidgetp
, "xwidgetp");
1554 defsubr (&Sxwidget_view_p
);
1555 DEFSYM (Qxwidget_view_p
, "xwidget-view-p");
1556 defsubr (&Sxwidget_info
);
1557 defsubr (&Sxwidget_view_info
);
1558 defsubr (&Sxwidget_resize
);
1559 defsubr (&Sget_buffer_xwidgets
);
1560 defsubr (&Sxwidget_view_model
);
1561 defsubr (&Sxwidget_view_window
);
1562 defsubr (&Sxwidget_view_lookup
);
1563 defsubr (&Sxwidget_query_on_exit_flag
);
1564 defsubr (&Sset_xwidget_query_on_exit_flag
);
1565 defsubr (&Sset_frame_visible
);
1567 #ifdef HAVE_WEBKIT_OSR
1568 defsubr (&Sxwidget_webkit_goto_uri
);
1569 defsubr (&Sxwidget_webkit_execute_script
);
1570 defsubr (&Sxwidget_webkit_get_title
);
1571 DEFSYM (Qwebkit_osr
,"webkit-osr");
1574 defsubr (&Sxwgir_xwidget_call_method
);
1575 defsubr (&Sxwgir_require_namespace
);
1576 defsubr (&Sxwidget_size_request
);
1577 defsubr (&Sdelete_xwidget_view
);
1578 defsubr (&Sxwidget_disable_plugin_for_mime
);
1580 defsubr (&Sxwidget_send_keyboard_event
);
1581 defsubr (&Sxwidget_webkit_dom_dump
);
1582 defsubr (&Sxwidget_plist
);
1583 defsubr (&Sxwidget_buffer
);
1584 defsubr (&Sset_xwidget_plist
);
1586 DEFSYM (Qxwidget
, "xwidget");
1588 DEFSYM (QCxwidget
, ":xwidget");
1589 DEFSYM (QCxwgir_class
, ":xwgir-class");
1590 DEFSYM (QCtitle
, ":title");
1592 /* Do not forget to update the docstring of make-xwidget if you add
1594 DEFSYM (Qbutton
, "Button"); //changed to match the gtk class because xwgir(experimental and not really needed)
1595 DEFSYM (Qtoggle
, "ToggleButton");
1596 DEFSYM (Qslider
, "slider");
1597 DEFSYM (Qsocket
, "socket");
1598 DEFSYM (Qsocket_osr
, "socket-osr");
1599 DEFSYM (Qcairo
, "cairo");
1601 DEFSYM (QCplist
, ":plist");
1603 DEFVAR_LISP ("xwidget-list", Vxwidget_list
, doc
: /*xwidgets list*/);
1604 Vxwidget_list
= Qnil
;
1606 DEFVAR_LISP ("xwidget-view-list", Vxwidget_view_list
, doc
: /*xwidget views list*/);
1607 Vxwidget_view_list
= Qnil
;
1609 Fprovide (intern ("xwidget-internal"), Qnil
);
1614 /* Value is non-zero if OBJECT is a valid Lisp xwidget specification. A
1615 valid xwidget specification is a list whose car is the symbol
1616 `xwidget', and whose rest is a property list. The property list must
1617 contain a value for key `:type'. That value must be the name of a
1618 supported xwidget type. The rest of the property list depends on the
1622 valid_xwidget_spec_p (Lisp_Object object
)
1626 if (CONSP (object
) && EQ (XCAR (object
), Qxwidget
))
1628 /* Lisp_Object tem; */
1630 /* for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem)) */
1631 /* if (EQ (XCAR (tem), QCtype)) */
1633 /* tem = XCDR (tem); */
1634 /* if (CONSP (tem) && SYMBOLP (XCAR (tem))) */
1636 /* struct xwidget_type *type; */
1637 /* type = lookup_xwidget_type (XCAR (tem)); */
1639 /* valid_p = type->valid_p (object); */
1644 //never mind type support for now
1653 /* find a value associated with key in spec */
1655 xwidget_spec_value ( Lisp_Object spec
, Lisp_Object key
,
1660 eassert (valid_xwidget_spec_p (spec
));
1662 for (tail
= XCDR (spec
);
1663 CONSP (tail
) && CONSP (XCDR (tail
)); tail
= XCDR (XCDR (tail
)))
1665 if (EQ (XCAR (tail
), key
))
1669 return XCAR (XCDR (tail
));
1680 xwidget_view_delete_all_in_window (struct window
*w
)
1682 struct xwidget_view
* xv
= NULL
;
1683 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
); tail
= XCDR (tail
))
1685 if (XWIDGET_VIEW_P (XCAR (tail
))) {
1686 xv
= XXWIDGET_VIEW (XCAR (tail
));
1687 if(XWINDOW (xv
->w
) == w
) {
1688 gtk_widget_destroy(xv
->widgetwindow
);
1689 Vxwidget_view_list
= Fdelq (XCAR (tail
), Vxwidget_view_list
);
1695 struct xwidget_view
*
1696 xwidget_view_lookup (struct xwidget
* xw
, struct window
*w
)
1698 Lisp_Object xwidget
, window
, ret
;
1699 XSETXWIDGET (xwidget
, xw
);
1700 XSETWINDOW (window
, w
);
1702 ret
= Fxwidget_view_lookup (xwidget
, window
);
1704 return EQ (ret
, Qnil
) ? NULL
: XXWIDGET_VIEW (ret
);
1708 lookup_xwidget (Lisp_Object spec
)
1710 /* When a xwidget lisp spec is found initialize the C struct that is used in the C code.
1711 This is done by redisplay so values change if the spec changes.
1712 So, take special care of one-shot events
1714 TODO remove xwidget init from display spec. simply store an xwidget reference only and set
1715 size etc when creating the xwidget, which should happen before insertion into buffer
1717 int found
= 0, found1
= 0, found2
= 0;
1721 value
= xwidget_spec_value (spec
, QCxwidget
, &found1
);
1722 xw
= XXWIDGET(value
);
1724 /* value = xwidget_spec_value (spec, QCtype, &found); */
1725 /* xw->type = SYMBOLP (value) ? value : Qbutton; //default to button */
1726 /* value = xwidget_spec_value (spec, QCtitle, &found2); */
1727 /* xw->title = STRINGP (value) ? (char *) SDATA (value) : "?"; //funky cast FIXME TODO */
1729 /* value = xwidget_spec_value (spec, QCheight, NULL); */
1730 /* xw->height = INTEGERP (value) ? XFASTINT (value) : 50; */
1731 /* value = xwidget_spec_value (spec, QCwidth, NULL); */
1732 /* xw->width = INTEGERP (value) ? XFASTINT (value) : 50; */
1734 /* value = xwidget_spec_value (spec, QCplist, NULL); */
1735 /* xw->plist = value; */
1736 /* coordinates are not known here */
1737 printf ("lookup_xwidget xwidget_id:%d type:%d found:%d %d %d title:'%s' (%d,%d)\n", xw
,
1738 xw
->type
, found
, found1
, found2
, xw
->title
, xw
->height
, xw
->width
);
1740 //assert_valid_xwidget_id (id, "lookup_xwidget");
1744 /*set up detection of touched xwidget*/
1746 xwidget_start_redisplay (void)
1748 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
); tail
= XCDR (tail
))
1750 if (XWIDGET_VIEW_P (XCAR (tail
)))
1751 XXWIDGET_VIEW (XCAR (tail
))->redisplayed
= 0;
1755 /* the xwidget was touched during redisplay, so it isnt a candidate for hiding*/
1757 xwidget_touch (struct xwidget_view
*xv
)
1759 xv
->redisplayed
= 1;
1763 xwidget_touched (struct xwidget_view
*xv
)
1765 return xv
->redisplayed
;
1768 /* redisplay has ended, now we should hide untouched xwidgets
1771 xwidget_end_redisplay (struct window
*w
, struct glyph_matrix
*matrix
)
1779 xwidget_start_redisplay ();
1780 //iterate desired glyph matrix of window here, hide gtk widgets
1781 //not in the desired matrix.
1783 //this only takes care of xwidgets in active windows.
1784 //if a window goes away from screen xwidget views wust be deleted
1786 // dump_glyph_matrix(matrix, 2);
1787 for (i
= 0; i
< matrix
->nrows
; ++i
)
1789 // dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs);
1790 struct glyph_row
*row
;
1791 row
= MATRIX_ROW (matrix
, i
);
1792 if (row
->enabled_p
!= 0)
1794 for (area
= LEFT_MARGIN_AREA
; area
< LAST_AREA
; ++area
)
1796 struct glyph
*glyph
= row
->glyphs
[area
];
1797 struct glyph
*glyph_end
= glyph
+ row
->used
[area
];
1798 for (; glyph
< glyph_end
; ++glyph
)
1800 if (glyph
->type
== XWIDGET_GLYPH
)
1803 the only call to xwidget_end_redisplay is in dispnew
1804 xwidget_end_redisplay(w->current_matrix);
1806 xwidget_touch (xwidget_view_lookup(glyph
->u
.xwidget
,
1814 for (Lisp_Object tail
= Vxwidget_view_list
; CONSP (tail
); tail
= XCDR (tail
))
1816 if (XWIDGET_VIEW_P (XCAR (tail
))) {
1817 struct xwidget_view
* xv
= XXWIDGET_VIEW (XCAR (tail
));
1819 //"touched" is only meaningful for the current window, so disregard other views
1820 if (XWINDOW (xv
->w
) == w
) {
1821 if (xwidget_touched(xv
))
1822 xwidget_show_view (xv
);
1824 xwidget_hide_view (xv
);
1830 /* Kill all xwidget in BUFFER. */
1832 kill_buffer_xwidgets (Lisp_Object buffer
)
1834 Lisp_Object tail
, xwidget
;
1835 for (tail
= Fget_buffer_xwidgets (buffer
); CONSP (tail
); tail
= XCDR (tail
))
1837 xwidget
= XCAR (tail
);
1838 Vxwidget_list
= Fdelq (xwidget
, Vxwidget_list
);
1839 /* TODO free the GTK things in xw */
1841 CHECK_XWIDGET (xwidget
);
1842 struct xwidget
*xw
= XXWIDGET (xwidget
);
1843 if (xw
->widget_osr
&& xw
->widgetwindow_osr
)
1845 gtk_widget_destroy(xw
->widget_osr
);
1846 gtk_widget_destroy(xw
->widgetwindow_osr
);
1852 #endif /* HAVE_XWIDGETS */