10 #include "blockinput.h"
11 #include "syssignal.h"
14 #include <X11/cursorfont.h>
17 #include <sys/types.h>
21 #include <sys/ioctl.h>
22 #endif /* ! defined (BSD_SYSTEM) */
26 #ifndef INCLUDED_FCNTL
35 #include "character.h"
39 #include "dispextern.h"
41 #include "termhooks.h"
44 #include "emacs-icon.h"
49 #include "intervals.h"
56 #include <X11/Shell.h>
58 #include <X11/extensions/Xcomposite.h>
59 #include <X11/extensions/Xrender.h>
61 #ifdef HAVE_SYS_TIME_H
76 //for gtk3; sockets and plugs
78 #include "emacsgtkfixed.h"
81 #include <librsvg/rsvg.h>
84 #include <goocanvas.h>
88 #include <clutter/clutter.h>
89 #include <clutter-gtk/clutter-gtk.h>
94 #ifdef HAVE_WEBKIT_OSR
95 #include <webkit/webkitwebview.h>
96 #include <webkit/webkitwebplugindatabase.h>
97 #include <webkit/webkitwebplugin.h>
98 #include <webkit/webkitglobals.h>
103 //TODO should of course not be a hardcoded array but I can't be bothered atm
104 //just a fixed array of xwidgets for now
105 //would need to be hashtables or something
107 #define MAX_XWIDGETS 100
108 struct xwidget_view xwidget_views
[MAX_XWIDGETS
];
110 //TODO embryo of lisp allocators for xwidgets
111 //TODO xwidget* should be Lisp_xwidget*
113 allocate_xwidget (void)
115 return ALLOCATE_PSEUDOVECTOR (struct xwidget
, height
, PVEC_XWIDGET
);
118 //TODO xwidget_view* should be Lisp_xwidget_view*
120 allocate_xwidget_view (void)
122 return ALLOCATE_PSEUDOVECTOR (struct xwidget_view
, redisplayed
, PVEC_XWIDGET_VIEW
);
126 Lisp_Object Qxwidget
;
127 Lisp_Object Qcxwidget
;
129 Lisp_Object Qxwidget_set_keyboard_grab
;
130 Lisp_Object Qxwidget_embed_steal_window
;
131 Lisp_Object Qxwidget_info
;
132 Lisp_Object Qxwidget_resize
;
133 Lisp_Object Qxwidget_send_keyboard_event
;
135 Lisp_Object Qbutton
, Qtoggle
, Qslider
, Qsocket
, Qsocket_osr
, Qcairo
,
136 Qwebkit_osr
, QCplist
;
139 extern Lisp_Object QCtype
;
140 extern Lisp_Object QCwidth
, QCheight
;
142 struct xwidget_view
* xwidget_view_lookup(struct xwidget
* xw
, struct window
*w
);
143 Lisp_Object
xwidget_spec_value ( Lisp_Object spec
, Lisp_Object key
, int *found
);
144 gboolean
webkit_osr_damage_event_callback (GtkWidget
*widget
, GdkEventExpose
*event
, gpointer data
) ;
145 gboolean
webkit_osr_key_event_callback (GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
) ;
146 void webkit_osr_document_load_finished_callback (WebKitWebView
*webkitwebview
,
147 WebKitWebFrame
*arg1
,
150 DEFUN ("make-xwidget", Fmake_xwidget
, Smake_xwidget
, 7, 7, 0,
153 (Lisp_Object beg
, Lisp_Object end
,
156 Lisp_Object width
, Lisp_Object height
,
159 //should work a bit like "make-button"(make-button BEG END &rest PROPERTIES)
160 // arg "type" and fwd should be keyword args eventually
161 //(make-xwidget 3 3 'button "oei" 31 31 nil)
162 //(xwidget-info (car xwidget-alist))
163 struct xwidget
* xw
= allocate_xwidget();
167 XSETSYMBOL(xw
->type
, type
);
168 XSETSTRING(xw
->title
, title
);
169 //TODO buffer should be an optional argument not just assumed to be the current buffer
170 XSETBUFFER(xw
->buffer
, Fcurrent_buffer()); // conservatively gcpro xw since we call lisp
171 xw
->height
= XFASTINT(height
);
172 xw
->width
= XFASTINT(width
);
173 XSETPSEUDOVECTOR (val
, xw
, PVEC_XWIDGET
); //?? dunno why i need this
174 Vxwidget_alist
= Fcons ( val
, Vxwidget_alist
);
175 xw
->widgetwindow_osr
= NULL
;
176 xw
->widget_osr
= NULL
;
180 #ifdef HAVE_WEBKIT_OSR
181 /* DIY mvc. widget is rendered offscreen,
182 later bitmap copied to the views.
184 if (EQ(xw
->type
, Qwebkit_osr
)){
185 printf("init webkit osr\n");
187 xw
->widgetwindow_osr
= GTK_CONTAINER (gtk_offscreen_window_new ());
188 gtk_window_resize( GTK_WINDOW(xw
->widgetwindow_osr
), xw
->width
, xw
->height
);
189 xw
->widget_osr
= webkit_web_view_new();
191 gtk_widget_set_size_request (GTK_WIDGET (xw
->widget_osr
), xw
->width
, xw
->height
);
192 gtk_container_add (xw
->widgetwindow_osr
, xw
->widget_osr
);
194 gtk_widget_show_all (GTK_WIDGET (xw
->widgetwindow_osr
));
196 /* store some xwidget data in the gtk widgets for convenient retrieval in the event handlers. */
197 g_object_set_data (G_OBJECT (xw
->widget_osr
), XG_XWIDGET
, (gpointer
) (xw
));
198 g_object_set_data (G_OBJECT (xw
->widgetwindow_osr
), XG_XWIDGET
, (gpointer
) (xw
));
200 g_signal_connect (G_OBJECT ( xw
->widgetwindow_osr
), "damage-event", G_CALLBACK (webkit_osr_damage_event_callback
), NULL
);
202 g_signal_connect (G_OBJECT ( xw
->widget_osr
), "key-press-event", G_CALLBACK (webkit_osr_key_event_callback
), NULL
);
203 g_signal_connect (G_OBJECT ( xw
->widget_osr
), "key-release-event", G_CALLBACK (webkit_osr_key_event_callback
), NULL
);
205 g_signal_connect (G_OBJECT ( xw
->widget_osr
),
206 "document-load-finished",
207 G_CALLBACK (webkit_osr_document_load_finished_callback
),
210 webkit_web_view_load_uri(WEBKIT_WEB_VIEW(xw
->widget_osr
), "http://www.fsf.org");
215 if (EQ(xw
->type
, Qsocket_osr
)){
216 printf("init socket osr\n");
218 xw
->widgetwindow_osr
= GTK_CONTAINER (gtk_offscreen_window_new ());
219 gtk_window_resize( GTK_WINDOW(xw
->widgetwindow_osr
), xw
->width
, xw
->height
);
222 //xw->widget_osr = webkit_web_view_new();
223 xw
->widget_osr
= gtk_socket_new();
224 //g_signal_connect_after(xv->widget, "plug-added", G_CALLBACK(xwidget_plug_added), "plug added");
225 //g_signal_connect_after(xv->widget, "plug-removed", G_CALLBACK(xwidget_plug_removed), "plug removed");
228 gtk_widget_set_size_request (GTK_WIDGET (xw
->widget_osr
), xw
->width
, xw
->height
);
229 gtk_container_add (xw
->widgetwindow_osr
, xw
->widget_osr
);
231 gtk_widget_show_all (GTK_WIDGET (xw
->widgetwindow_osr
));
233 /* store some xwidget data in the gtk widgets for convenient retrieval in the event handlers. */
234 g_object_set_data (G_OBJECT (xw
->widget_osr
), XG_XWIDGET
, (gpointer
) (xw
));
235 g_object_set_data (G_OBJECT (xw
->widgetwindow_osr
), XG_XWIDGET
, (gpointer
) (xw
));
236 g_signal_connect (G_OBJECT ( xw
->widgetwindow_osr
), "damage-event", G_CALLBACK (webkit_osr_damage_event_callback
), NULL
);
238 //webkit_web_view_load_uri(WEBKIT_WEB_VIEW(xw->widget_osr), "http://www.fsf.org");
248 xwidget_hidden(struct xwidget_view
*xv
)
255 buttonclick_handler (GtkWidget
* widget
, gpointer data
)
257 struct xwidget
*xw
= (struct xwidget
*) data
;
258 struct input_event event
;
260 FRAME_PTR f
= NULL
;//(FRAME_PTR) g_object_get_data (G_OBJECT (xw->widget), XG_FRAME_DATA); //TODO
261 printf ("button clicked xw:%d '%s'\n", xw
, xw
->title
);
264 event
.kind
= XWIDGET_EVENT
;
266 XSETFRAME (frame
, f
);
268 event
.frame_or_window
= Qnil
; //frame; //how to get the frame here?
272 event
.arg
= Fcons (xw
, event
.arg
); //TODO send the actual xwidget object now instead
273 event
.arg
= Fcons (intern ("buttonclick"), event
.arg
);
275 kbd_buffer_store_event (&event
);
282 send_xembed_ready_event (struct xwidget
* xw
, int xembedid
)
284 struct input_event event
;
286 event
.kind
= XWIDGET_EVENT
;
287 event
.frame_or_window
= Qnil
; //frame; //how to get the frame here? //TODO i store it in the xwidget now
290 event
.arg
= Fcons (make_number (xembedid
), event
.arg
);
291 event
.arg
= Fcons (intern ("xembed-ready"), event
.arg
);
292 event
.arg
= Fcons (xw
, event
.arg
); //TODO
295 kbd_buffer_store_event (&event
);
300 xwidget_show_view (struct xwidget_view
*xv
)
303 gtk_widget_show(GTK_WIDGET(xv
->widgetwindow
));
304 gtk_fixed_move (GTK_FIXED (xv
->emacswindow
), GTK_WIDGET (xv
->widgetwindow
), xv
->x
+ xv
->clip_left
, xv
->y
+ xv
->clip_top
); //TODO refactor
308 /* hide an xvidget view */
310 xwidget_hide_view (struct xwidget_view
*xv
)
313 //gtk_widget_hide(GTK_WIDGET(xw->widgetwindow));
314 gtk_fixed_move (GTK_FIXED (xv
->emacswindow
), GTK_WIDGET (xv
->widgetwindow
),
319 void xwidget_plug_added(GtkSocket
*socket
,
322 //hmm this doesnt seem to get called for foreign windows
323 printf("xwidget_plug_added\n");
326 gboolean
xwidget_plug_removed(GtkSocket
*socket
,
329 printf("xwidget_plug_removed\n");
330 return TRUE
; /* dont run the default handler because that kills the socket and we want to reuse it*/
334 void xwidget_slider_changed (GtkRange
*range
,
337 //slider value changed. change value of siblings
338 //correspondingly. but remember that changing value will again
341 //TODO MVC view storage wont be an array futureish so the loop needs to change eventually
342 //TODO MVC it would be nice if this code could be reusable but, alas, C is not a functional language
344 // - the type of the controllers value (double, boolean etc)
345 // - the getter and setter (but they can be func pointers)
346 // a behemoth macro is always an option.
347 double v
=gtk_range_get_value(range
);
348 struct xwidget_view
* xvp
= g_object_get_data (G_OBJECT (range
), XG_XWIDGET_VIEW
);
349 struct xwidget_view
* xv
;
351 printf("slider changed val:%f\n", v
);
354 //block sibling views signal handlers
355 for (int i
= 0; i
< MAX_XWIDGETS
; i
++)
357 xv
= &xwidget_views
[i
];
358 if(xv
->initialized
&& xvp
->model
== xv
->model
){
359 g_signal_handler_block( xv
->widget
,xv
->handler_id
);
362 //set values of sibling views and unblock
363 for (int i
= 0; i
< MAX_XWIDGETS
; i
++)
365 xv
= &xwidget_views
[i
];
366 if(xv
->initialized
&& xvp
->model
== xv
->model
){
367 gtk_range_set_value(GTK_RANGE(xv
->widget
), v
);
368 g_signal_handler_unblock( xv
->widget
,xv
->handler_id
);
375 /* when the off-screen webkit master view changes this signal is called.
376 it copies the bitmap from the off-screen webkit instance */
377 gboolean
webkit_osr_damage_event_callback (GtkWidget
*widget
, GdkEventExpose
*event
, gpointer data
)
379 //TODO this is wrong! should just oueu a redraw of onscreen widget
380 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (widget
), XG_XWIDGET
);
381 struct xwidget_view
* xv
;
382 //webkit_osr_redraw_child(xw, widget);
384 for (int i
= 0; i
< MAX_XWIDGETS
; i
++)//todo mvc refactor
386 xv
= &xwidget_views
[i
];
387 if(xv
->initialized
&& xv
->model
== xw
){
388 gtk_widget_queue_draw (xv
->widget
); //redraw all views, the master has changed
397 gboolean
webkit_osr_key_event_callback (GtkWidget
*widget
, GdkEventKey
*event
, gpointer data
)
399 printf("terminating a webkit osr keypress\n");
400 //TRUE terminate the event here. no paren handlers will be called. but webkit then doesng get the event and it still crashes
401 //FALSE paren handlers will be called. webkit then gets the event and it still crashes
406 void webkit_osr_document_load_finished_callback (WebKitWebView
*webkitwebview
,
407 WebKitWebFrame
*arg1
,
410 //TODO this event sending code should be refactored
411 struct input_event event
;
412 // struct xwidget *xw = (struct xwidget *) data;
413 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (webkitwebview
), XG_XWIDGET
);
414 printf("webkit finished loading\n");
417 event
.kind
= XWIDGET_EVENT
;
418 event
.frame_or_window
= Qnil
; //frame; //how to get the frame here? //TODO i store it in the xwidget now
421 event
.arg
= Fcons (xw
, event
.arg
); //TODO
422 event
.arg
= Fcons (intern ("document-load-finished"), event
.arg
);
425 kbd_buffer_store_event (&event
);
429 //for gtk3 webkit_osr
431 xwidget_osr_draw_callback (GtkWidget
*widget
, cairo_t
*cr
, gpointer data
)
433 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (widget
), XG_XWIDGET
);
434 struct xwidget_view
* xv
= (struct xwidget_view
*) g_object_get_data (G_OBJECT (widget
), XG_XWIDGET_VIEW
);
436 // printf("xwidget_osr_draw_callback gtk3 xw.id:%d xw.type:%d window:%d vis:%d\n",
437 // xw,xw->type, gtk_widget_get_window (widget), gtk_widget_get_visible (xw->widget_osr));
439 cairo_rectangle(cr
, 0,0, xv
->clip_right
, xv
->clip_bottom
);//xw->width, xw->height);
442 gtk_widget_draw (xw
->widget_osr
, cr
);
450 xwidget_osr_button_callback ( GtkWidget
*widget
,
454 struct xwidget
* xw
= (struct xwidget
*) g_object_get_data (G_OBJECT (widget
), XG_XWIDGET
);
455 GdkEvent
* eventcopy
= gdk_event_copy(event
);
457 ((GdkEventButton
*)eventcopy
)->window
= gtk_widget_get_window(xw
->widget_osr
);
458 gtk_main_do_event(eventcopy
); //TODO this will leak events. they should be deallocated later
459 return TRUE
; //dont propagate this event furter
462 int xwidget_view_index
=0;
464 /* initializes and does initial placement of an xwidget view on screen */
468 struct glyph_string
*s
,
471 //TODO temp code replace with lisp list
472 struct xwidget_view
*xv
;
476 if(xwidget_view_index
< MAX_XWIDGETS
)
477 xwidget_view_index
++;
479 xwidget_view_index
=0;
481 xv
= &xwidget_views
[xwidget_view_index
];
482 }while( xv
->initialized
== 1); //TODO yeah this can infloop if there are MAX_WIDGETS on-screen
489 if(EQ(xww
->type
, Qbutton
))
491 xv
->widget
= gtk_button_new_with_label (XSTRING(xww
->title
)->data
);
492 g_signal_connect (G_OBJECT (xv
->widget
), "clicked",
493 G_CALLBACK (buttonclick_handler
), xww
); //the model rather than the view
494 } else if (EQ(xww
->type
, Qtoggle
)) {
495 xv
->widget
= gtk_toggle_button_new_with_label (XSTRING(xww
->title
)->data
);
496 } else if (EQ(xww
->type
, Qsocket
)) {
497 xv
->widget
= gtk_socket_new ();
498 g_signal_connect_after(xv
->widget
, "plug-added", G_CALLBACK(xwidget_plug_added
), "plug added");
499 g_signal_connect_after(xv
->widget
, "plug-removed", G_CALLBACK(xwidget_plug_removed
), "plug removed");
500 //TODO these doesnt help
501 gtk_widget_add_events(xv
->widget
, GDK_KEY_PRESS
);
502 gtk_widget_add_events(xv
->widget
, GDK_KEY_RELEASE
);
503 } else if (EQ(xww
->type
, Qslider
)) {
505 //gtk_hscale_new (GTK_ADJUSTMENT(gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 10.0, 10.0)));
506 gtk_hscale_new_with_range ( 0.0, 100.0, 10.0);
507 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
508 xv
->handler_id
= g_signal_connect_after(xv
->widget
, "value-changed", G_CALLBACK(xwidget_slider_changed
), "slider changed");
509 } else if (EQ(xww
->type
, Qcairo
)) {
511 //uhm cairo is differentish in gtk 3.
512 //gdk_cairo_create (gtk_widget_get_window (FRAME_GTK_WIDGET (s->f)));
513 #ifdef HAVE_GOOCANVAS
514 xv
->widget
= goo_canvas_new();
515 GooCanvasItem
*root
, *rect_item
, *text_item
;
516 goo_canvas_set_bounds (GOO_CANVAS (xv
->widget
), 0, 0, 1000, 1000);
517 root
= goo_canvas_get_root_item (GOO_CANVAS (xv
->widget
));
518 rect_item
= goo_canvas_rect_new (root
, 100, 100, 400, 400,
522 "stroke-color", "yellow",
526 text_item
= goo_canvas_text_new (root
, "Hello World", 300, 300, -1,
530 goo_canvas_item_rotate (text_item
, 45, 300, 300);
534 xv
->widget
= gtk_clutter_embed_new ();;
535 ClutterActor
*stage
= NULL
;
536 stage
= gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED ( xv
->widget
));
537 ClutterColor stage_color
= { 0xaa, 0xaa, 0xaa, 0xff }; /* Black */
538 clutter_stage_set_color (CLUTTER_STAGE (stage
), &stage_color
);
540 ClutterActor
* texture
= clutter_cairo_texture_new (1000, 1000);
541 clutter_container_add_actor(stage
, texture
);
542 clutter_actor_set_position(texture
, 0,0);
543 clutter_actor_show(texture
);
546 cr
= clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (texture
));
548 /* draw on the context */
549 RsvgHandle
*h
= rsvg_handle_new_from_file ("/tmp/tst.svg",
552 rsvg_handle_render_cairo(h
, cr
);
555 /* Show the stage: */
556 clutter_actor_show (stage
);
558 } else if (EQ(xww
->type
, Qwebkit_osr
)||EQ(xww
->type
, Qsocket_osr
)) {
559 #ifdef HAVE_WEBKIT_OSR
560 xv
->widget
= gtk_drawing_area_new();
561 gtk_widget_set_app_paintable ( xv
->widget
, TRUE
); //because expose event handling
562 gtk_widget_add_events(xv
->widget
,
563 GDK_BUTTON_PRESS_MASK
564 | GDK_BUTTON_RELEASE_MASK
565 | GDK_POINTER_MOTION_MASK
);
566 g_signal_connect (G_OBJECT ( xv
->widget
), "draw",
567 G_CALLBACK (xwidget_osr_draw_callback
), NULL
);
568 g_signal_connect (G_OBJECT ( xv
->widget
), "button-press-event",
569 G_CALLBACK (xwidget_osr_button_callback
), NULL
);
570 g_signal_connect (G_OBJECT ( xv
->widget
), "button-release-event",
571 G_CALLBACK (xwidget_osr_button_callback
), NULL
);
572 g_signal_connect (G_OBJECT ( xv
->widget
), "motion-notify-event",
573 G_CALLBACK (xwidget_osr_button_callback
), NULL
);
574 g_signal_connect (G_OBJECT ( xv
->widget
), "key-press-event",
575 G_CALLBACK (xwidget_osr_button_callback
), NULL
);
576 g_signal_connect (G_OBJECT ( xv
->widget
), "key-release-event",
577 G_CALLBACK (xwidget_osr_button_callback
), NULL
);
585 //make container widget 1st, and put the actual widget inside the container
586 //later, drawing should crop container window if necessary to handle case where xwidget
587 //is partially obscured by other emacs windows
588 //other containers than gtk_fixed where explored, but gtk_fixed had the most predictable behaviour so far.
589 xv
->emacswindow
= GTK_CONTAINER (FRAME_GTK_WIDGET (s
->f
));
590 xv
->widgetwindow
= GTK_CONTAINER (gtk_fixed_new ());
591 gtk_widget_set_has_window(GTK_WIDGET ( xv
->widgetwindow
), TRUE
);
592 gtk_container_add (xv
->widgetwindow
, xv
->widget
);
594 //store some xwidget data in the gtk widgets
595 g_object_set_data (G_OBJECT (xv
->widget
), XG_FRAME_DATA
, (gpointer
) (s
->f
)); //the emacs frame
596 g_object_set_data (G_OBJECT (xv
->widget
), XG_XWIDGET
, (gpointer
) (xww
)); //the xwidget
597 g_object_set_data (G_OBJECT (xv
->widget
), XG_XWIDGET_VIEW
, (gpointer
) (xv
)); //the xwidget
598 g_object_set_data (G_OBJECT (xv
->widgetwindow
), XG_XWIDGET
, (gpointer
) (xww
)); //the xwidget window
599 g_object_set_data (G_OBJECT (xv
->widgetwindow
), XG_XWIDGET_VIEW
, (gpointer
) (xv
)); //the xwidget window
602 gtk_widget_set_size_request (GTK_WIDGET (xv
->widget
), xww
->width
, xww
->height
);
603 gtk_widget_set_size_request (GTK_WIDGET (xv
->widgetwindow
), xww
->width
, xww
->height
);
604 gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s
->f
)), GTK_WIDGET (xv
->widgetwindow
), x
, y
);
605 xv
->x
= x
; xv
->y
= y
;
606 gtk_widget_show_all (GTK_WIDGET (xv
->widgetwindow
));
608 //widgettype specific initialization only possible after realization
609 if (EQ(xww
->type
, Qsocket
)) {
610 printf ("xwid:%d socket id:%x %d\n",
612 gtk_socket_get_id (GTK_SOCKET (xv
->widget
)),
613 gtk_socket_get_id (GTK_SOCKET (xv
->widget
)));
614 send_xembed_ready_event (xww
,
615 gtk_socket_get_id (GTK_SOCKET (xv
->widget
)));
616 //gtk_widget_realize(xw->widget);
623 x_draw_xwidget_glyph_string (struct glyph_string
*s
)
626 this method is called by the redisplay engine and places the xwidget on screen.
627 moving and clipping is done here. also view init.
630 int box_line_hwidth
= eabs (s
->face
->box_line_width
);
631 int box_line_vwidth
= max (s
->face
->box_line_width
, 0);
632 int height
= s
->height
;
633 struct xwidget
*xww
= s
->xwidget
;
634 struct xwidget_view
*xv
= xwidget_view_lookup(xww
, (s
->w
));
635 int clip_right
; int clip_bottom
; int clip_top
; int clip_left
;
638 int y
= s
->y
+ (s
->height
/ 2) - (xww
->height
/ 2);
641 if (xv
== NULL
|| xv
->initialized
== 0){
642 /* Views must be initialized once(only once).
643 We do it here in the display loop because there is no other time to know things like
644 window placement etc.
646 printf ("xv init for xw %d\n", xww
);
647 xv
= xwidget_init_view (xww
, s
, x
, y
);
650 //calculate clipping, which is used for all manner of onscreen xwidget views
651 //each widget border can get clipped by other emacs objects so there are four clipping variables
652 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
));
653 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
));
655 clip_bottom
= min (xww
->height
, WINDOW_BOTTOM_EDGE_Y (s
->w
) - WINDOW_MODE_LINE_HEIGHT (s
->w
) - y
);
656 clip_top
= max(0, WINDOW_TOP_EDGE_Y(s
->w
) -y
);
658 //we are conserned with movement of the onscreen area. the area might sit still when the widget actually moves
659 //this happens when an emacs window border moves across a widget window
660 //so, if any corner of the outer widget clippng window moves, that counts as movement here, even
661 //if it looks like no movement happens because the widget sits still inside the clipping area.
662 //the widget can also move inside the clipping area, which happens later
663 moved
= (xv
->x
+ xv
->clip_left
!= x
+clip_left
)
664 || ((xv
->y
+ xv
->clip_top
)!= (y
+clip_top
));
665 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
);
667 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
);
670 if (moved
) //has it moved?
672 if (1)//!xwidget_hidden(xv)) //hidden equals not being seen during redisplay
674 //TODO should be possible to use xwidget_show_view here
675 gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s
->f
)),
676 GTK_WIDGET (xv
->widgetwindow
),
677 x
+ clip_left
, y
+ clip_top
);
680 //clip the widget window if some parts happen to be outside drawable area
681 //an emacs window is not a gtk window, a gtk window covers the entire frame
682 //cliping might have changed even if we havent actualy moved, we try figure out when we need to reclip for real
683 if((xv
->clip_right
!= clip_right
)
684 || (xv
->clip_bottom
!= clip_bottom
)
685 || (xv
->clip_top
!= clip_top
)
686 || (xv
->clip_left
!= clip_left
)){
687 gtk_widget_set_size_request (GTK_WIDGET (xv
->widgetwindow
), clip_right
+ clip_left
, clip_bottom
+ clip_top
);
688 gtk_fixed_move(GTK_FIXED(xv
->widgetwindow
), xv
->widget
, -clip_left
, -clip_top
);
689 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
);
692 xv
->clip_right
= clip_right
; xv
->clip_bottom
= clip_bottom
; xv
->clip_top
= clip_top
;xv
->clip_left
= clip_left
;
694 //if emacs wants to repaint the area where the widget lives, queue a redraw
695 //TODO it seems its possible to get out of sync with emacs redraws so emacs bg sometimes shows up instead of xwidget
696 //its just a visual glitch though
697 if (!xwidget_hidden(xv
)){
698 gtk_widget_queue_draw (GTK_WIDGET(xv
->widgetwindow
));
699 gtk_widget_queue_draw (xv
->widget
);
704 #ifdef HAVE_WEBKIT_OSR
705 DEFUN ("xwidget-webkit-goto-uri", Fxwidget_webkit_goto_uri
, Sxwidget_webkit_goto_uri
, 2, 2, 0,
706 doc
: /* webkit goto uri.*/
708 (Lisp_Object xwidget
, Lisp_Object uri
)
710 struct xwidget
* xw
= XXWIDGET(xwidget
);
711 webkit_web_view_load_uri ( WEBKIT_WEB_VIEW(xw
->widget_osr
), SDATA(uri
));
715 DEFUN ("xwidget-webkit-execute-script", Fxwidget_webkit_execute_script
, Sxwidget_webkit_execute_script
, 2, 2, 0,
716 doc
: /* webkit exec js.*/
718 (Lisp_Object xwidget
, Lisp_Object script
)
720 struct xwidget
* xw
= XXWIDGET(xwidget
);
721 webkit_web_view_execute_script( WEBKIT_WEB_VIEW(xw
->widget_osr
), SDATA(script
));
725 DEFUN ("xwidget-webkit-get-title", Fxwidget_webkit_get_title
, Sxwidget_webkit_get_title
, 1, 1, 0,
726 doc
: /* webkit get title. can be used to work around exec method lacks return val*/
728 (Lisp_Object xwidget
)
730 //TODO support multibyte strings
731 struct xwidget
* xw
= XXWIDGET(xwidget
);
732 const gchar
* str
=webkit_web_view_get_title( WEBKIT_WEB_VIEW(xw
->widget_osr
));
733 //return make_string_from_bytes(str, wcslen((const wchar_t *)str), strlen(str));
734 return build_string(str
);
738 DEFUN("xwidget-disable-plugin-for-mime", Fxwidget_disable_plugin_for_mime
, Sxwidget_disable_plugin_for_mime
, 1,1,0, doc
: /* */)
741 WebKitWebPlugin
*wp
= webkit_web_plugin_database_get_plugin_for_mimetype
742 (webkit_get_web_plugin_database(), SDATA(mime
));
743 if(wp
== NULL
) return Qnil
;
744 if(webkit_web_plugin_get_enabled (wp
)){
745 webkit_web_plugin_set_enabled (wp
, FALSE
);
752 //attempting a workaround for a webkit offscreen bug
753 //TODO verify its still needed
754 void gtk_window_get_position (GtkWindow
*window
,
757 printf("my getsize\n");
762 DEFUN ("xwidget-webkit-dom-dump", Fxwidget_webkit_dom_dump
, Sxwidget_webkit_dom_dump
, 1, 1, 0,
763 doc
: /* webkit dom dump*/
765 (Lisp_Object xwidget
)
767 struct xwidget
* xw
= XXWIDGET(xwidget
);
768 xwidget_webkit_dom_dump(webkit_web_view_get_dom_document(xw
->widget_osr
));
773 xwidget_webkit_dom_dump(WebKitDOMNode
* parent
){
774 WebKitDOMNodeList
* list
;
777 WebKitDOMNode
* attribute
;
778 WebKitDOMNamedNodeMap
* attrs
;
779 printf("node:%d type:%d name:%s content:%s\n",
781 webkit_dom_node_get_node_type(parent
),//1 element 3 text 8 comment 2 attribute
782 webkit_dom_node_get_local_name(parent
),
783 webkit_dom_node_get_text_content(parent
));
785 if(webkit_dom_node_has_attributes(parent
)){
786 attrs
= webkit_dom_node_get_attributes(parent
);
788 length
= webkit_dom_named_node_map_get_length(attrs
);
789 for (int i
= 0; i
< length
; i
++) {
790 attribute
= webkit_dom_named_node_map_item(attrs
,i
);
791 printf(" attr node:%d type:%d name:%s content:%s\n",
793 webkit_dom_node_get_node_type(attribute
),//1 element 3 text 8 comment
794 webkit_dom_node_get_local_name(attribute
),
795 webkit_dom_node_get_text_content(attribute
));
798 list
= webkit_dom_node_get_child_nodes(parent
);
799 length
= webkit_dom_node_list_get_length(list
);
800 WebKitDOMNode
* child
;
801 for (int i
= 0; i
< length
; i
++) {
802 child
= webkit_dom_node_list_item(list
, i
);
803 //if(webkit_dom_node_has_child_nodes(child))
804 xwidget_webkit_dom_dump(child
);
815 DEFUN ("xwidget-resize", Fxwidget_resize
, Sxwidget_resize
, 3, 3, 0, doc
:
816 /* resize xwidgets*/)
817 (Lisp_Object xwidget
, Lisp_Object new_width
, Lisp_Object new_height
)
819 struct xwidget
* xw
= XXWIDGET(xwidget
);
820 struct xwidget_view
*xv
;
823 CHECK_NUMBER (new_width
);
824 CHECK_NUMBER (new_height
);
825 w
= XFASTINT (new_width
);
826 h
= XFASTINT (new_height
);
829 printf("resize xwidget %d (%d,%d)->(%d,%d)",xw
, xw
->width
,xw
->height
,w
,h
);
832 //if theres a osr resize it 1st
834 gtk_layout_set_size (GTK_LAYOUT (xw
->widgetwindow_osr
), xw
->width
, xw
->height
);
835 gtk_widget_set_size_request (GTK_WIDGET (xw
->widget_osr
), xw
->width
, xw
->height
);
838 for (int i
= 0; i
< MAX_XWIDGETS
; i
++) //TODO MVC refactor lazy linear search
840 xv
= &xwidget_views
[i
];
841 if(xv
->initialized
&& xv
->model
== xw
){
842 gtk_layout_set_size (GTK_LAYOUT (xv
->widgetwindow
), xw
->width
, xw
->height
);
843 gtk_widget_set_size_request (GTK_WIDGET (xv
->widget
), xw
->width
, xw
->height
);
850 DEFUN ("xwidget-size-request", Fxwidget_size_request
, Sxwidget_size_request
, 1, 1, 0, doc
:
851 /* desired size (TODO crashes if arg not osr widget)*/)
852 (Lisp_Object xwidget
)
854 GtkRequisition requisition
;
856 gtk_widget_size_request(XXWIDGET(xwidget
)->widget_osr
, &requisition
);
858 rv
= Fcons (make_number(requisition
.height
), rv
);
859 rv
= Fcons (make_number(requisition
.width
), rv
);
864 DEFUN ("xwidgetp", Fxwidgetp
, Sxwidgetp
, 1, 1, 0,
865 doc
: /* Return t if OBJECT is a xwidget. */)
868 return XWIDGETP (object
) ? Qt
: Qnil
;
871 DEFUN("xwidget-info", Fxwidget_info
, Sxwidget_info
, 1,1,0, doc
: /* get xwidget props */)
872 (Lisp_Object xwidget
)
875 struct xwidget
* xw
= XXWIDGET(xwidget
);
877 info
= Fmake_vector (make_number (4), Qnil
);
878 XSETSYMBOL (XVECTOR (info
)->contents
[0], xw
->type
);
879 XSETSTRING (XVECTOR (info
)->contents
[1], xw
->title
);
880 XSETINT (XVECTOR (info
)->contents
[2], xw
->width
);
881 XSETINT (XVECTOR (info
)->contents
[3], xw
->height
);
888 DEFUN("xwidget-view-info", Fxwidget_view_info
, Sxwidget_view_info
, 2,2,0, doc
: /* get xwidget view props */)
889 (Lisp_Object xwidget
, Lisp_Object window
)
891 struct xwidget
* xw
= XXWIDGET(xwidget
);
892 struct xwidget_view
* xv
= xwidget_view_lookup(xw
, XWINDOW(window
));
896 info
= Fmake_vector (make_number (6), Qnil
);
897 XVECTOR (info
)->contents
[0] = make_number(xv
->x
);
898 XVECTOR (info
)->contents
[1] = make_number(xv
->y
);
899 XVECTOR (info
)->contents
[2] = make_number(xv
->clip_right
);
900 XVECTOR (info
)->contents
[3] = make_number(xv
->clip_bottom
);
901 XVECTOR (info
)->contents
[4] = make_number(xv
->clip_top
);
902 XVECTOR (info
)->contents
[5] = make_number(xv
->clip_left
);
907 DEFUN ("xwidget-send-keyboard-event", Fxwidget_send_keyboard_event
, Sxwidget_send_keyboard_event
, 2, 2, 0, doc
:/* synthesize a kbd event for a xwidget. */
909 (Lisp_Object xwidget
, Lisp_Object keydescriptor
)
911 //TODO this code crashes for offscreen widgets and ive tried many different strategies
912 int keyval
= 0x058; //X
913 char *keystring
= "";
916 gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), keyval
, &keys
, &n_keys
);
918 struct xwidget
*xw
= XXWIDGET(xwidget
);
920 GdkEventKey
* ev
= (GdkEventKey
*)gdk_event_new(GDK_KEY_PRESS
);
923 //todo what about windowless widgets?
925 window
= FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
929 widget
= xw
->widget_osr
;
931 widget
= xwidget_view_lookup(xw
, XWINDOW(window
))->widget
;
933 ev
->window
= gtk_widget_get_window(widget
);
934 gtk_widget_grab_focus(widget
);
935 ev
->send_event
= FALSE
;
937 ev
->hardware_keycode
= keys
[0].keycode
;
938 ev
->group
= keys
[0].group
;
941 ev
->time
= GDK_CURRENT_TIME
;
943 //ev->device = gdk_device_get_core_pointer();
944 GdkDeviceManager
* manager
= gdk_display_get_device_manager(gdk_window_get_display(ev
->window
));
945 gdk_event_set_device ((GdkEvent
*)ev
, gdk_device_manager_get_client_pointer(manager
));
946 gdk_event_put((GdkEvent
*)ev
);
947 //g_signal_emit_by_name(ev->window,"key-press-event", ev);
949 ev
->type
= GDK_KEY_RELEASE
;
950 gdk_event_put((GdkEvent
*)ev
);
951 //g_signal_emit_by_name(ev->window,"key-release-event", ev);
952 //gtk_main_do_event(ev);
953 gdk_event_free((GdkEvent
*)ev
);
960 DEFUN("xwidget-delete-zombies", Fxwidget_delete_zombies
, Sxwidget_delete_zombies
, 0,0,0, doc
: /* */)
964 - remove all views with window gone
967 - remove all xwidgets with buffer gone
968 - remove all views with xw gone
971 struct xwidget_view
* xv
= NULL
;
973 for (int i
= 0; i
< MAX_XWIDGETS
; i
++){
974 xv
= &xwidget_views
[i
];
975 XSETWINDOW(w
, xv
->w
);
976 if(xv
->initialized
&& (! (WINDOW_LIVE_P(w
)))){
978 gtk_widget_destroy(GTK_WIDGET(xv
->widgetwindow
));
985 DEFUN ("xwidget-plist", Fxwidget_plist
, Sxwidget_plist
,
987 doc
: /* Return the plist of XWIDGET. */)
988 (register Lisp_Object xwidget
)
990 //CHECK_XWIDGET (xwidget); //todo
991 return XXWIDGET (xwidget
)->plist
;
994 DEFUN ("xwidget-buffer", Fxwidget_buffer
, Sxwidget_buffer
,
996 doc
: /* Return the buffer of XWIDGET. */)
997 (register Lisp_Object xwidget
)
999 //CHECK_XWIDGET (xwidget); //todo
1000 return XXWIDGET (xwidget
)->buffer
;
1003 DEFUN ("set-xwidget-plist", Fset_xwidget_plist
, Sset_xwidget_plist
,
1005 doc
: /* Replace the plist of XWIDGET with PLIST. Returns PLIST. */)
1006 (register Lisp_Object xwidget
, Lisp_Object plist
)
1008 //CHECK_XWIDGET (xwidget); //todo
1011 XXWIDGET (xwidget
)->plist
= plist
;
1018 syms_of_xwidget (void)
1022 defsubr (&Smake_xwidget
);
1023 defsubr (&Sxwidgetp
);
1024 defsubr (&Sxwidget_info
);
1025 defsubr (&Sxwidget_view_info
);
1026 defsubr (&Sxwidget_resize
);
1028 #ifdef HAVE_WEBKIT_OSR
1029 defsubr (&Sxwidget_webkit_goto_uri
);
1030 defsubr (&Sxwidget_webkit_execute_script
);
1031 defsubr (&Sxwidget_webkit_get_title
);
1032 DEFSYM (Qwebkit_osr
,"webkit-osr");
1035 defsubr (&Sxwidget_size_request
);
1036 defsubr (&Sxwidget_delete_zombies
);
1037 defsubr (&Sxwidget_disable_plugin_for_mime
);
1039 defsubr (&Sxwidget_send_keyboard_event
);
1040 defsubr (&Sxwidget_webkit_dom_dump
);
1041 defsubr (&Sxwidget_plist
);
1042 defsubr (&Sxwidget_buffer
);
1043 defsubr (&Sset_xwidget_plist
);
1045 DEFSYM (Qxwidget
,"xwidget");
1047 DEFSYM (Qcxwidget
,":xwidget");
1048 DEFSYM (Qtitle
,":title");
1050 DEFSYM (Qbutton
, "button");
1051 DEFSYM (Qtoggle
, "toggle");
1052 DEFSYM (Qslider
, "slider");
1053 DEFSYM (Qsocket
, "socket");
1054 DEFSYM (Qsocket_osr
, "socket-osr");
1055 DEFSYM (Qcairo
, "cairo");
1057 DEFSYM (QCplist
, ":plist");
1059 DEFVAR_LISP ("xwidget-alist", Vxwidget_alist
, doc
: /*xwidgets list*/);
1060 Vxwidget_alist
= Qnil
;
1061 DEFVAR_LISP ("xwidget-view-alist", Vxwidget_view_alist
, doc
: /*xwidget views list*/);
1062 Vxwidget_alist
= Qnil
;
1064 Fprovide (intern ("xwidget-internal"), Qnil
);
1066 // for (i = 0; i < MAX_XWIDGETS; i++)
1067 //xwidgets[i].initialized = 0;
1071 /* Value is non-zero if OBJECT is a valid Lisp xwidget specification. A
1072 valid xwidget specification is a list whose car is the symbol
1073 `xwidget', and whose rest is a property list. The property list must
1074 contain a value for key `:type'. That value must be the name of a
1075 supported xwidget type. The rest of the property list depends on the
1079 valid_xwidget_p (Lisp_Object object
)
1083 if (XWIDGETP (object
))
1085 /* Lisp_Object tem; */
1087 /* for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem)) */
1088 /* if (EQ (XCAR (tem), QCtype)) */
1090 /* tem = XCDR (tem); */
1091 /* if (CONSP (tem) && SYMBOLP (XCAR (tem))) */
1093 /* struct xwidget_type *type; */
1094 /* type = lookup_xwidget_type (XCAR (tem)); */
1096 /* valid_p = type->valid_p (object); */
1101 //never mind type support for now
1110 /* find a value associated with key in spec */
1112 xwidget_spec_value ( Lisp_Object spec
, Lisp_Object key
,
1117 xassert (valid_xwidget_p (spec
));
1119 for (tail
= XCDR (spec
);
1120 CONSP (tail
) && CONSP (XCDR (tail
)); tail
= XCDR (XCDR (tail
)))
1122 if (EQ (XCAR (tail
), key
))
1126 return XCAR (XCDR (tail
));
1136 void xwidget_view_delete_all_in_window( struct window
*w
)
1138 struct xwidget_view
* xv
= NULL
;
1139 for (int i
= 0; i
< MAX_XWIDGETS
; i
++){
1140 xv
= &xwidget_views
[i
];
1141 if(xv
->initialized
&& xv
->w
== w
){
1142 gtk_widget_destroy(GTK_WIDGET(xv
->widgetwindow
));
1143 xv
->initialized
= 0;
1150 struct xwidget_view
* xwidget_view_lookup(struct xwidget
* xw
, struct window
*w
){
1151 struct xwidget_view
* xv
= NULL
;
1152 for (int i
= 0; i
< MAX_XWIDGETS
; i
++){
1153 xv
= &xwidget_views
[i
];
1154 if (xv
->initialized
&& (xv
->model
== xw
) && (xv
->w
== w
))
1160 lookup_xwidget (Lisp_Object spec
)
1162 /* When a xwidget lisp spec is found initialize the C struct that is used in the C code.
1163 This is done by redisplay so values change if the spec changes.
1164 So, take special care of one-shot events
1166 TODO remove xwidget init from display spec. simply store an xwidget reference only and set
1167 size etc when creating the xwidget, which should happen before insertion into buffer
1169 int found
= 0, found1
= 0, found2
= 0;
1173 value
= xwidget_spec_value (spec
, Qcxwidget
, &found1
);
1174 xw
= XXWIDGET(value
);
1176 /* value = xwidget_spec_value (spec, QCtype, &found); */
1177 /* xw->type = SYMBOLP (value) ? value : Qbutton; //default to button */
1178 /* value = xwidget_spec_value (spec, Qtitle, &found2); */
1179 /* xw->title = STRINGP (value) ? (char *) SDATA (value) : "?"; //funky cast FIXME TODO */
1181 /* value = xwidget_spec_value (spec, QCheight, NULL); */
1182 /* xw->height = INTEGERP (value) ? XFASTINT (value) : 50; */
1183 /* value = xwidget_spec_value (spec, QCwidth, NULL); */
1184 /* xw->width = INTEGERP (value) ? XFASTINT (value) : 50; */
1186 /* value = xwidget_spec_value (spec, QCplist, NULL); */
1187 /* xw->plist = value; */
1188 /* coordinates are not known here */
1189 printf ("lookup_xwidget xwidget_id:%d type:%d found:%d %d %d title:'%s' (%d,%d)\n", xw
,
1190 xw
->type
, found
, found1
, found2
, xw
->title
, xw
->height
, xw
->width
);
1192 //assert_valid_xwidget_id (id, "lookup_xwidget");
1196 /*set up detection of touched xwidget*/
1198 xwidget_start_redisplay (void)
1201 for (i
= 0; i
< MAX_XWIDGETS
; i
++)
1202 xwidget_views
[i
].redisplayed
= 0;
1206 /* the xwidget was touched during redisplay, so it isnt a candidate for hiding*/
1208 xwidget_touch (struct xwidget_view
*xv
)
1210 xv
->redisplayed
= 1;
1214 xwidget_touched (struct xwidget_view
*xv
)
1216 return xv
->redisplayed
;
1219 /* redisplay has ended, now we should hide untouched xwidgets
1222 xwidget_end_redisplay (struct window
*w
, struct glyph_matrix
*matrix
)
1230 xwidget_start_redisplay ();
1231 //iterate desired glyph matrix of window here, hide gtk widgets
1232 //not in the desired matrix.
1234 //this only takes care of xwidgets in active windows.
1235 //if a window goes away from screen xwidget views wust be deleted
1237 // dump_glyph_matrix(matrix, 2);
1238 for (i
= 0; i
< matrix
->nrows
; ++i
)
1240 // dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs);
1241 struct glyph_row
*row
;
1242 row
= MATRIX_ROW (matrix
, i
);
1243 if (row
->enabled_p
!= 0)
1245 for (area
= LEFT_MARGIN_AREA
; area
< LAST_AREA
; ++area
)
1247 struct glyph
*glyph
= row
->glyphs
[area
];
1248 struct glyph
*glyph_end
= glyph
+ row
->used
[area
];
1249 for (; glyph
< glyph_end
; ++glyph
)
1251 if (glyph
->type
== XWIDGET_GLYPH
)
1254 the only call to xwidget_end_redisplay is in dispnew
1255 xwidget_end_redisplay(w->current_matrix);
1257 xwidget_touch (xwidget_view_lookup(glyph
->u
.xwidget
,
1265 for (i
= 0; i
< MAX_XWIDGETS
; i
++)
1267 struct xwidget_view
* xv
= &xwidget_views
[i
];
1269 //"touched" is only meaningful for the current window, so disregard other views
1270 if (xv
->initialized
&& ( xv
->w
== w
))
1272 if (xwidget_touched(xv
))
1273 xwidget_show_view (xv
);
1275 xwidget_hide_view (xv
);