]> code.delx.au - gnu-emacs/blob - src/xwidget.c
upstream
[gnu-emacs] / src / xwidget.c
1 #include <config.h>
2 #ifdef HAVE_XWIDGETS
3
4 #include <signal.h>
5
6 #include <stdio.h>
7 #include <setjmp.h>
8 #ifdef HAVE_X_WINDOWS
9
10 #include "lisp.h"
11 #include "blockinput.h"
12 #include "syssignal.h"
13
14 #include "xterm.h"
15 #include <X11/cursorfont.h>
16
17 #ifndef makedev
18 #include <sys/types.h>
19 #endif /* makedev */
20
21 #ifdef BSD_SYSTEM
22 #include <sys/ioctl.h>
23 #endif /* ! defined (BSD_SYSTEM) */
24
25 #include "systime.h"
26
27 #ifndef INCLUDED_FCNTL
28 #include <fcntl.h>
29 #endif
30 #include <ctype.h>
31 #include <errno.h>
32 #include <setjmp.h>
33 #include <sys/stat.h>
34
35 #include "charset.h"
36 #include "character.h"
37 #include "coding.h"
38 #include "ccl.h"
39 #include "frame.h"
40 #include "dispextern.h"
41 #include "fontset.h"
42 #include "termhooks.h"
43 #include "termopts.h"
44 #include "termchar.h"
45 #include "emacs-icon.h"
46 #include "disptab.h"
47 #include "buffer.h"
48 #include "window.h"
49 #include "keyboard.h"
50 #include "intervals.h"
51 #include "process.h"
52 #include "atimer.h"
53 #include "keymap.h"
54
55
56 #ifdef USE_X_TOOLKIT
57 #include <X11/Shell.h>
58 #endif
59 #include <X11/extensions/Xcomposite.h>
60 #include <X11/extensions/Xrender.h>
61 #include <cairo.h>
62 #ifdef HAVE_SYS_TIME_H
63 #include <sys/time.h>
64 #endif
65 #ifdef HAVE_UNISTD_H
66 #include <unistd.h>
67 #endif
68
69 #include "gtkutil.h"
70 #include "font.h"
71 #endif
72
73 #include <gtk/gtk.h>
74 #include <gdk/gdk.h>
75
76 #ifdef HAVE_GTK3
77 //for gtk3; sockets and plugs
78 #include <gtk/gtkx.h>
79 #include "emacsgtkfixed.h"
80 #endif
81
82
83
84 #ifdef HAVE_GOOCANVAS
85 #include <goocanvas.h>
86 #endif
87
88 #ifdef HAVE_CLUTTER
89 #include <librsvg/rsvg.h>
90 #include <clutter/clutter.h>
91 #include <clutter-gtk/clutter-gtk.h>
92 #endif
93
94 #include <wchar.h>
95
96 #ifdef HAVE_WEBKIT_OSR
97 #include <webkit/webkitwebview.h>
98 #include <webkit/webkitwebplugindatabase.h>
99 #include <webkit/webkitwebplugin.h>
100 #include <webkit/webkitglobals.h>
101 #include <webkit/webkitwebnavigationaction.h>
102 #include <webkit/webkitdownload.h>
103 #endif
104
105 //for GIR
106 #include <girepository.h>
107
108 #include "xwidget.h"
109
110 //TODO should of course not be a hardcoded array but I can't be bothered atm
111 //just a fixed array of xwidgets for now
112 //would need to be hashtables or something
113
114 #define MAX_XWIDGETS 100
115 struct xwidget_view xwidget_views[MAX_XWIDGETS];
116
117 //TODO embryo of lisp allocators for xwidgets
118 //TODO xwidget* should be Lisp_xwidget*
119 struct xwidget*
120 allocate_xwidget (void)
121 {
122 return ALLOCATE_PSEUDOVECTOR (struct xwidget, height, PVEC_XWIDGET);
123 }
124
125 //TODO xwidget_view* should be Lisp_xwidget_view*
126 struct xwidget_view*
127 allocate_xwidget_view (void)
128 {
129 return ALLOCATE_PSEUDOVECTOR (struct xwidget_view, redisplayed, PVEC_XWIDGET_VIEW);
130 }
131 #define XSETXWIDGET(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET))
132 #define XSETXWIDGET_VIEW(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW))
133
134 Lisp_Object Qxwidget;
135 Lisp_Object Qcxwidget;
136 Lisp_Object Qtitle;
137 Lisp_Object Qxwidget_set_keyboard_grab;
138 Lisp_Object Qxwidget_embed_steal_window;
139 Lisp_Object Qxwidget_info;
140 Lisp_Object Qxwidget_resize;
141 Lisp_Object Qxwidget_send_keyboard_event;
142 Lisp_Object Qcxwgir_class;
143 Lisp_Object Qbutton, Qtoggle, Qslider, Qsocket, Qsocket_osr, Qcairo, Qxwgir,
144 Qwebkit_osr, QCplist;
145
146
147 extern Lisp_Object QCtype;
148 extern Lisp_Object QCwidth, QCheight;
149
150 struct xwidget_view* xwidget_view_lookup(struct xwidget* xw, struct window *w);
151 Lisp_Object xwidget_spec_value ( Lisp_Object spec, Lisp_Object key, int *found);
152 gboolean webkit_osr_damage_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data) ;
153 gboolean webkit_osr_key_event_callback (GtkWidget *widget, GdkEventKey *event, gpointer data) ;
154 void webkit_osr_document_load_finished_callback (WebKitWebView *webkitwebview,
155 WebKitWebFrame *arg1,
156 gpointer user_data);
157 gboolean webkit_osr_download_callback (WebKitWebView *webkitwebview,
158 WebKitDownload *arg1,
159 gpointer data);
160
161 gboolean webkit_osr_mime_type_policy_typedecision_requested_callback(WebKitWebView *webView,
162 WebKitWebFrame *frame,
163 WebKitNetworkRequest *request,
164 gchar *mimetype,
165 WebKitWebPolicyDecision *policy_decision,
166 gpointer user_data);
167
168 gboolean webkit_osr_new_window_policy_decision_requested_callback(WebKitWebView *webView,
169 WebKitWebFrame *frame,
170 WebKitNetworkRequest *request,
171 WebKitWebNavigationAction *navigation_action,
172 WebKitWebPolicyDecision *policy_decision,
173 gpointer user_data);
174
175
176 gboolean webkit_osr_navigation_policy_decision_requested_callback(WebKitWebView *webView,
177 WebKitWebFrame *frame,
178 WebKitNetworkRequest *request,
179 WebKitWebNavigationAction *navigation_action,
180 WebKitWebPolicyDecision *policy_decision,
181 gpointer user_data);
182
183
184 DEFUN ("make-xwidget", Fmake_xwidget, Smake_xwidget, 7, 7, 0,
185 doc: /* xw */
186 )
187 (Lisp_Object beg, Lisp_Object end,
188 Lisp_Object type,
189 Lisp_Object title,
190 Lisp_Object width, Lisp_Object height,
191 Lisp_Object data)
192 {
193 //should work a bit like "make-button"(make-button BEG END &rest PROPERTIES)
194 // arg "type" and fwd should be keyword args eventually
195 //(make-xwidget 3 3 'button "oei" 31 31 nil)
196 //(xwidget-info (car xwidget-alist))
197 struct xwidget* xw = allocate_xwidget();
198 Lisp_Object val;
199 struct gcpro gcpro1;
200 GCPRO1(xw);
201 XSETSYMBOL(xw->type, type);
202 XSETSTRING(xw->title, title);
203 //TODO buffer should be an optional argument not just assumed to be the current buffer
204 XSETBUFFER(xw->buffer, Fcurrent_buffer()); // conservatively gcpro xw since we call lisp
205 xw->height = XFASTINT(height);
206 xw->width = XFASTINT(width);
207 XSETPSEUDOVECTOR (val, xw, PVEC_XWIDGET); //?? dunno why i need this
208 Vxwidget_alist = Fcons ( val, Vxwidget_alist);
209 xw->widgetwindow_osr = NULL;
210 xw->widget_osr = NULL;
211 xw->plist = Qnil;
212
213
214 #ifdef HAVE_WEBKIT_OSR
215 /* DIY mvc. widget is rendered offscreen,
216 later bitmap copied to the views.
217 */
218 if (EQ(xw->type, Qwebkit_osr)){
219 printf("init webkit osr\n");
220 BLOCK_INPUT;
221 xw->widgetwindow_osr = GTK_CONTAINER (gtk_offscreen_window_new ());
222 gtk_window_resize( GTK_WINDOW(xw->widgetwindow_osr), xw->width, xw->height);
223 xw->widget_osr = webkit_web_view_new();
224
225 gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height);
226 gtk_container_add (xw->widgetwindow_osr, xw->widget_osr);
227
228 gtk_widget_show_all (GTK_WIDGET (xw->widgetwindow_osr));
229
230 /* store some xwidget data in the gtk widgets for convenient retrieval in the event handlers. */
231 g_object_set_data (G_OBJECT (xw->widget_osr), XG_XWIDGET, (gpointer) (xw));
232 g_object_set_data (G_OBJECT (xw->widgetwindow_osr), XG_XWIDGET, (gpointer) (xw));
233 /* signals */
234 g_signal_connect (G_OBJECT ( xw->widgetwindow_osr), "damage-event", G_CALLBACK (webkit_osr_damage_event_callback), NULL);
235
236 //TODO these were just a test hack
237 /* g_signal_connect (G_OBJECT ( xw->widget_osr), "key-press-event", G_CALLBACK (webkit_osr_key_event_callback), NULL); */
238 /* g_signal_connect (G_OBJECT ( xw->widget_osr), "key-release-event", G_CALLBACK (webkit_osr_key_event_callback), NULL); */
239
240 g_signal_connect (G_OBJECT ( xw->widget_osr),
241 "document-load-finished",
242 G_CALLBACK (webkit_osr_document_load_finished_callback),
243 xw);
244
245 g_signal_connect (G_OBJECT ( xw->widget_osr),
246 "download-requested",
247 G_CALLBACK (webkit_osr_download_callback),
248 xw);
249
250 g_signal_connect (G_OBJECT ( xw->widget_osr),
251 "mime-type-policy-decision-requested",
252 G_CALLBACK (webkit_osr_mime_type_policy_typedecision_requested_callback),
253 xw);
254
255 g_signal_connect (G_OBJECT ( xw->widget_osr),
256 "new-window-policy-decision-requested",
257 G_CALLBACK (webkit_osr_new_window_policy_decision_requested_callback),
258 xw);
259
260 g_signal_connect (G_OBJECT ( xw->widget_osr),
261 "navigation-policy-decision-requested",
262 G_CALLBACK (webkit_osr_navigation_policy_decision_requested_callback),
263 xw);
264
265
266 webkit_web_view_load_uri(WEBKIT_WEB_VIEW(xw->widget_osr), "http://www.fsf.org");
267 UNBLOCK_INPUT;
268
269 }
270 #endif
271
272 if (EQ(xw->type, Qsocket_osr)){
273 printf("init socket osr\n");
274 BLOCK_INPUT;
275 xw->widgetwindow_osr = GTK_CONTAINER (gtk_offscreen_window_new ());
276 gtk_window_resize( GTK_WINDOW(xw->widgetwindow_osr), xw->width, xw->height);
277
278 ////////////////////
279 //xw->widget_osr = webkit_web_view_new();
280 xw->widget_osr = gtk_socket_new();
281 //g_signal_connect_after(xv->widget, "plug-added", G_CALLBACK(xwidget_plug_added), "plug added");
282 //g_signal_connect_after(xv->widget, "plug-removed", G_CALLBACK(xwidget_plug_removed), "plug removed");
283 ///////////////////
284
285 gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height);
286 gtk_container_add (xw->widgetwindow_osr, xw->widget_osr);
287
288 gtk_widget_show_all (GTK_WIDGET (xw->widgetwindow_osr));
289
290 /* store some xwidget data in the gtk widgets for convenient retrieval in the event handlers. */
291 g_object_set_data (G_OBJECT (xw->widget_osr), XG_XWIDGET, (gpointer) (xw));
292 g_object_set_data (G_OBJECT (xw->widgetwindow_osr), XG_XWIDGET, (gpointer) (xw));
293 g_signal_connect (G_OBJECT ( xw->widgetwindow_osr), "damage-event", G_CALLBACK (webkit_osr_damage_event_callback), NULL);
294
295 //webkit_web_view_load_uri(WEBKIT_WEB_VIEW(xw->widget_osr), "http://www.fsf.org");
296 UNBLOCK_INPUT;
297
298 }
299
300 UNGCPRO;
301 return val;
302 }
303
304 int
305 xwidget_hidden(struct xwidget_view *xv)
306 {
307 return xv->hidden;
308 }
309
310
311 static void
312 buttonclick_handler (GtkWidget * widget, gpointer data)
313 {
314 struct xwidget *xw = (struct xwidget *) data;
315 struct input_event event;
316 Lisp_Object frame;
317 FRAME_PTR f = NULL;//(FRAME_PTR) g_object_get_data (G_OBJECT (xw->widget), XG_FRAME_DATA); //TODO
318 printf ("button clicked xw:%d '%s'\n", xw, xw->title);
319
320 EVENT_INIT (event);
321 event.kind = XWIDGET_EVENT;
322
323 XSETFRAME (frame, f);
324
325 event.frame_or_window = Qnil; //frame; //how to get the frame here?
326
327
328 event.arg = Qnil;
329 event.arg = Fcons ((Lisp_Object)xw, event.arg); //TODO send the actual xwidget object now instead
330 event.arg = Fcons (intern ("buttonclick"), event.arg);
331
332 kbd_buffer_store_event (&event);
333
334
335 }
336
337
338 static void
339 send_xembed_ready_event (struct xwidget* xw, int xembedid)
340 {
341 struct input_event event;
342 EVENT_INIT (event);
343 event.kind = XWIDGET_EVENT;
344 event.frame_or_window = Qnil; //frame; //how to get the frame here? //TODO i store it in the xwidget now
345
346 event.arg = Qnil;
347 event.arg = Fcons (make_number (xembedid), event.arg);
348 event.arg = Fcons ((Lisp_Object)xw, event.arg); //TODO
349 event.arg = Fcons (intern ("xembed-ready"), event.arg);
350
351
352 kbd_buffer_store_event (&event);
353
354 }
355
356 void
357 xwidget_show_view (struct xwidget_view *xv)
358 {
359 xv->hidden = 0;
360 gtk_widget_show(GTK_WIDGET(xv->widgetwindow));
361 gtk_fixed_move (GTK_FIXED (xv->emacswindow), GTK_WIDGET (xv->widgetwindow), xv->x + xv->clip_left, xv->y + xv->clip_top); //TODO refactor
362 }
363
364
365 /* hide an xvidget view */
366 void
367 xwidget_hide_view (struct xwidget_view *xv)
368 {
369 xv->hidden = 1;
370 //gtk_widget_hide(GTK_WIDGET(xw->widgetwindow));
371 gtk_fixed_move (GTK_FIXED (xv->emacswindow), GTK_WIDGET (xv->widgetwindow),
372 10000, 10000);
373 }
374
375
376 void
377 xwidget_plug_added(GtkSocket *socket,
378 gpointer user_data)
379 {
380 //hmm this doesnt seem to get called for foreign windows
381 printf("xwidget_plug_added\n");
382 }
383
384 gboolean
385 xwidget_plug_removed(GtkSocket *socket,
386 gpointer user_data)
387 {
388 printf("xwidget_plug_removed\n");
389 return TRUE; /* dont run the default handler because that kills the socket and we want to reuse it*/
390 }
391
392
393 void
394 xwidget_slider_changed (GtkRange *range,
395 gpointer user_data)
396 {
397 //slider value changed. change value of siblings
398 //correspondingly. but remember that changing value will again
399 //trigger signal
400
401 //TODO MVC view storage wont be an array futureish so the loop needs to change eventually
402 //TODO MVC it would be nice if this code could be reusable but, alas, C is not a functional language
403 //issues are:
404 // - the type of the controllers value (double, boolean etc)
405 // - the getter and setter (but they can be func pointers)
406 // a behemoth macro is always an option.
407 double v=gtk_range_get_value(range);
408 struct xwidget_view* xvp = g_object_get_data (G_OBJECT (range), XG_XWIDGET_VIEW);
409 struct xwidget_view* xv;
410
411 printf("slider changed val:%f\n", v);
412
413
414 //block sibling views signal handlers
415 for (int i = 0; i < MAX_XWIDGETS; i++)
416 {
417 xv = &xwidget_views[i];
418 if(xv->initialized && xvp->model == xv->model){
419 g_signal_handler_block( xv->widget,xv->handler_id);
420 }
421 }
422 //set values of sibling views and unblock
423 for (int i = 0; i < MAX_XWIDGETS; i++)
424 {
425 xv = &xwidget_views[i];
426 if(xv->initialized && xvp->model == xv->model){
427 gtk_range_set_value(GTK_RANGE(xv->widget), v);
428 g_signal_handler_unblock( xv->widget,xv->handler_id);
429 }
430 }
431
432 }
433
434
435 /* when the off-screen webkit master view changes this signal is called.
436 it copies the bitmap from the off-screen webkit instance */
437 gboolean
438 webkit_osr_damage_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data)
439 {
440 //TODO this is wrong! should just oueu a redraw of onscreen widget
441 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
442 struct xwidget_view* xv;
443 //webkit_osr_redraw_child(xw, widget);
444 printf ("damage\n");
445 for (int i = 0; i < MAX_XWIDGETS; i++)//todo mvc refactor
446 {
447 xv = &xwidget_views[i];
448 if(xv->initialized && xv->model == xw){
449 gtk_widget_queue_draw (xv->widget); //redraw all views, the master has changed
450 }
451 }
452
453 return FALSE;
454 }
455
456
457
458 gboolean
459 webkit_osr_key_event_callback (GtkWidget *widget, GdkEventKey *event, gpointer data)
460 {
461 printf("terminating a webkit osr keypress\n");
462 //TRUE terminate the event here. no paren handlers will be called. but webkit then doesng get the event and it still crashes
463 //FALSE paren handlers will be called. webkit then gets the event and it still crashes
464 return TRUE;
465 }
466
467
468 void
469 store_xwidget_event_string(struct xwidget* xw, char* eventname,char* eventstr)
470 {
471 //refactor attempt
472 struct input_event event;
473 Lisp_Object xwl;
474 XSETXWIDGET(xwl,xw);
475 EVENT_INIT (event);
476 event.kind = XWIDGET_EVENT;
477 event.frame_or_window = Qnil; //frame; //how to get the frame here? //TODO i store it in the xwidget now
478
479 event.arg = Qnil;
480 event.arg = Fcons (build_string(eventstr), event.arg); //string so dont intern
481 event.arg = Fcons (xwl, event.arg); //TODO
482 event.arg = Fcons (intern (eventname), event.arg);//interning should be ok
483 kbd_buffer_store_event (&event);
484
485 }
486
487 //TODO deprecated, use load-status
488 void
489 webkit_osr_document_load_finished_callback (WebKitWebView *webkitwebview,
490 WebKitWebFrame *arg1,
491 gpointer data)
492 {
493 //TODO this event sending code should be refactored
494 // struct xwidget *xw = (struct xwidget *) data;
495 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webkitwebview), XG_XWIDGET);
496 printf("webkit finished loading\n");
497
498 store_xwidget_event_string(xw,
499 "document-load-finished", "");
500 }
501
502 gboolean
503 webkit_osr_download_callback (WebKitWebView *webkitwebview,
504 WebKitDownload *arg1,
505 gpointer data)
506 {
507 //TODO this event sending code should be refactored
508 struct input_event event;
509 // struct xwidget *xw = (struct xwidget *) data;
510 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webkitwebview), XG_XWIDGET);
511 printf("download requested %s\n", webkit_download_get_uri (arg1));
512
513
514 printf("webkit finished loading\n");
515
516 store_xwidget_event_string(xw, "download-requested", webkit_download_get_uri (arg1));
517
518 return FALSE;
519 }
520
521 gboolean
522 webkit_osr_mime_type_policy_typedecision_requested_callback(WebKitWebView *webView,
523 WebKitWebFrame *frame,
524 WebKitNetworkRequest *request,
525 gchar *mimetype,
526 WebKitWebPolicyDecision *policy_decision,
527 gpointer user_data)
528 {
529 printf("mime policy requested\n");
530 // this function makes webkit send a download signal for all unknown mime types
531 // TODO defer the decision to lisp, so that its possible to make Emacs handle text mime for instance
532 if(!webkit_web_view_can_show_mime_type(webView, mimetype)){
533 webkit_web_policy_decision_download (policy_decision);
534 return TRUE;
535 }else{
536 return FALSE;
537 }
538 }
539
540
541 gboolean
542 webkit_osr_new_window_policy_decision_requested_callback(WebKitWebView *webView,
543 WebKitWebFrame *frame,
544 WebKitNetworkRequest *request,
545 WebKitWebNavigationAction *navigation_action,
546 WebKitWebPolicyDecision *policy_decision,
547 gpointer user_data)
548 {
549 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
550 printf("webkit_osr_new_window_policy_decision_requested_callback %s\n",
551 webkit_web_navigation_action_get_original_uri (navigation_action));
552
553 store_xwidget_event_string(xw, "new-window-policy-decision-requested", webkit_web_navigation_action_get_original_uri (navigation_action)
554 );
555 return FALSE;
556 }
557
558 gboolean
559 webkit_osr_navigation_policy_decision_requested_callback(WebKitWebView *webView,
560 WebKitWebFrame *frame,
561 WebKitNetworkRequest *request,
562 WebKitWebNavigationAction *navigation_action,
563 WebKitWebPolicyDecision *policy_decision,
564 gpointer user_data)
565 {
566 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
567 printf("webkit_osr_navigation_policy_decision_requested_callback %s\n",
568 webkit_web_navigation_action_get_original_uri (navigation_action));
569 store_xwidget_event_string(xw, "navigation-policy-decision-requested", webkit_web_navigation_action_get_original_uri (navigation_action)
570 );
571 return FALSE;
572 }
573
574 //for gtk3 webkit_osr
575 gboolean
576 xwidget_osr_draw_callback (GtkWidget *widget, cairo_t *cr, gpointer data)
577 {
578 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
579 struct xwidget_view* xv = (struct xwidget_view*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET_VIEW);
580
581 // printf("xwidget_osr_draw_callback gtk3 xw.id:%d xw.type:%d window:%d vis:%d\n",
582 // xw,xw->type, gtk_widget_get_window (widget), gtk_widget_get_visible (xw->widget_osr));
583
584 cairo_rectangle(cr, 0,0, xv->clip_right, xv->clip_bottom);//xw->width, xw->height);
585 cairo_clip(cr);
586
587 gtk_widget_draw (xw->widget_osr, cr);
588
589
590 return FALSE;
591 }
592
593
594 gboolean
595 xwidget_osr_button_callback (GtkWidget *widget,
596 GdkEvent *event,
597 gpointer user_data)
598 {
599 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
600 GdkEvent* eventcopy = gdk_event_copy(event);
601
602 ((GdkEventButton*)eventcopy)->window = gtk_widget_get_window(xw->widget_osr);
603 gtk_main_do_event(eventcopy); //TODO this will leak events. they should be deallocated later
604 return TRUE; //dont propagate this event furter
605 }
606
607
608 GIRepository *girepository ;
609 DEFUN( "xwgir-require-namespace",Fxwgir_require_namespace, Sxwgir_require_namespace, 2,2,0,
610 doc: /*require a namespace. must be done for all namespaces we want to use, before using other xwgir functions.*/)
611 (Lisp_Object lnamespace, Lisp_Object lnamespace_version)
612 {
613 char* namespace = SDATA(lnamespace);
614 char* namespace_version = SDATA(lnamespace_version);
615 GError *error = NULL;
616
617 girepository = g_irepository_get_default();
618 g_irepository_require(girepository, namespace, namespace_version, 0, &error);
619 if (error) {
620 g_error("ERROR: %s\n", error->message);
621 return Qnil;
622 }
623 return Qt;
624 }
625
626 GtkWidget* xwgir_create(char* class, char* namespace){
627 //TODO this is more or less the same as xwgir-call-method, so should be refactored
628 //create a gtk widget, given its name
629 //find the constructor
630 //call it
631 //also figure out how to pass args
632
633 GError *error = NULL;
634 GIArgument return_value;
635
636 GIObjectInfo* obj_info = g_irepository_find_by_name(girepository, namespace, class);
637 GIFunctionInfo* f_info = g_object_info_find_method (obj_info, "new");
638 g_function_info_invoke(f_info,
639 NULL, 0,
640 NULL, 0,
641 &return_value,
642 NULL);
643 return return_value.v_pointer;
644
645 }
646
647 int
648 xwgir_convert_lisp_to_gir_arg(GIArgument* giarg,
649 GIArgInfo* arginfo,
650 Lisp_Object lisparg )
651 {
652
653 GITypeTag tag;
654 gboolean is_pointer;
655 gboolean is_enum;
656 tag = g_type_info_get_tag (g_arg_info_get_type (arginfo));
657
658 switch (tag)
659 {
660 case GI_TYPE_TAG_BOOLEAN:
661 giarg->v_boolean = XFASTINT(lisparg);
662 break;
663 case GI_TYPE_TAG_INT8:
664 giarg->v_int8 = XFASTINT(lisparg);
665 break;
666 case GI_TYPE_TAG_UINT8:
667 giarg->v_uint8 = XFASTINT(lisparg);
668 break;
669 case GI_TYPE_TAG_INT16:
670 giarg->v_int16 = XFASTINT(lisparg);
671 break;
672 case GI_TYPE_TAG_UINT16:
673 giarg->v_uint16 = XFASTINT(lisparg);
674 break;
675 case GI_TYPE_TAG_INT32:
676 giarg->v_int32 = XFASTINT(lisparg);
677 break;
678 case GI_TYPE_TAG_UINT32:
679 giarg->v_uint32 = XFASTINT(lisparg);
680 break;
681
682 case GI_TYPE_TAG_INT64:
683 giarg->v_int64 = XFASTINT(lisparg);
684 break;
685 case GI_TYPE_TAG_UINT64:
686 giarg->v_uint64 = XFASTINT(lisparg);
687 break;
688
689
690 case GI_TYPE_TAG_FLOAT:
691 giarg->v_float = XFLOAT_DATA(lisparg);
692 break;
693
694 case GI_TYPE_TAG_DOUBLE:
695 giarg->v_double = XFLOAT_DATA(lisparg);
696 break;
697
698 case GI_TYPE_TAG_UTF8:
699 case GI_TYPE_TAG_FILENAME:
700 //giarg->v_string = SDATA(lisparg);
701 giarg->v_pointer = SDATA(lisparg);
702 break;
703
704 case GI_TYPE_TAG_ARRAY:
705 case GI_TYPE_TAG_GLIST:
706 case GI_TYPE_TAG_GSLIST:
707 case GI_TYPE_TAG_GHASH:
708 case GI_TYPE_TAG_ERROR:
709 case GI_TYPE_TAG_INTERFACE:
710 case GI_TYPE_TAG_VOID:
711 case GI_TYPE_TAG_UNICHAR:
712 case GI_TYPE_TAG_GTYPE:
713 //?? i dont know how to handle these yet TODO
714 printf("failed in my lisp to gir arg conversion duties. sob!\n");
715 return -1;
716 break;
717 }
718 return 0;
719 }
720
721 DEFUN ("xwgir-call-method", Fxwgir_call_method, Sxwgir_call_method, 3, 3, 0,
722 doc: /* call xwidget object method.*/)
723 (Lisp_Object xwidget, Lisp_Object method, Lisp_Object arguments)
724 {
725 GError *error = NULL;
726 GIArgument return_value;
727 GIArgument in_args[20];
728
729
730 struct xwidget* xw;
731 if(!XXWIDGETP(xwidget)) {printf("ERROR not an xwidget\n"); return Qnil;};
732 if(Qnil == xwidget) {printf("ERROR xwidget nil\n"); return Qnil;};
733 xw = XXWIDGET(xwidget);
734 if(NULL == xw) printf("ERROR xw is 0\n");
735 char* namespace = SDATA(Fcar(Fget(xw->type, Qcxwgir_class)));
736 //we need the concrete widget, which happens in 2 ways depending on OSR or not TODO
737 GtkWidget* widget = NULL;
738 if(NULL == xw->widget_osr) {
739 widget = xwidget_view_lookup (xw, XWINDOW(FRAME_SELECTED_WINDOW (SELECTED_FRAME ()))) -> widget;
740 } else {
741 widget = xw->widget_osr;
742 }
743
744 //char* class = SDATA(SYMBOL_NAME(xw->type)); //this works but is unflexible
745 //figure out the class from the widget instead
746 /* printf("type class: %s %s\n", G_OBJECT_TYPE_NAME(widget), G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(widget))); */
747 /* char* class = G_OBJECT_TYPE_NAME(widget); //gives "GtkButton"(I want "Button") */
748 /* class += strlen(namespace); //TODO check for corresponding api method. but this seems to work. */
749
750 char* class = SDATA(Fcar(Fcdr(Fget(xw->type, Qcxwgir_class))));
751
752 GIObjectInfo* obj_info = g_irepository_find_by_name(girepository, namespace, class);
753 GIFunctionInfo* f_info = g_object_info_find_method (obj_info, SDATA(method));
754
755 //loop over args, convert from lisp to primitive type, given arg introspection data
756 //TODO g_callable_info_get_n_args(f_info) should match
757 int argscount = XFASTINT(Flength(arguments));
758 if(argscount != g_callable_info_get_n_args(f_info)){
759 printf("xwgir call method arg count doesn match! \n");
760 return Qnil;
761 }
762 int i;
763 for (i = 1; i < argscount + 1; ++i)
764 {
765 xwgir_convert_lisp_to_gir_arg(&in_args[i], g_callable_info_get_arg(f_info, i - 1), Fnth(i - 1, arguments));
766 }
767
768 in_args[0].v_pointer = widget;
769 if(g_function_info_invoke(f_info,
770 in_args, argscount + 1,
771 NULL, 0,
772 &return_value,
773 &error)) {
774 //g_error("ERROR: %s\n", error->message);
775 printf("invokation error\n");
776 return Qnil;
777 }
778 return Qt;
779 }
780
781
782
783
784 int xwidget_view_index=0;
785
786 /* initializes and does initial placement of an xwidget view on screen */
787 struct xwidget_view*
788 xwidget_init_view (struct xwidget *xww,
789 struct glyph_string *s,
790 int x, int y)
791 {
792 //TODO temp code replace with lisp list
793 struct xwidget_view *xv;
794 GdkColor color;
795
796 do{
797 if(xwidget_view_index < MAX_XWIDGETS)
798 xwidget_view_index++;
799 else
800 xwidget_view_index=0;
801
802 xv = &xwidget_views[xwidget_view_index];
803 }while( xv->initialized == 1); //TODO yeah this can infloop if there are MAX_WIDGETS on-screen
804
805 xv->initialized = 1;
806 xv->w = s->w;
807 xv->model = xww;
808
809 //widget creation
810 if(EQ(xww->type, Qbutton))
811 {
812 xv->widget = gtk_button_new_with_label (XSTRING(xww->title)->data);
813 g_signal_connect (G_OBJECT (xv->widget), "clicked",
814 G_CALLBACK (buttonclick_handler), xww); //the model rather than the view
815 } else if (EQ(xww->type, Qtoggle)) {
816 xv->widget = gtk_toggle_button_new_with_label (XSTRING(xww->title)->data);
817 //xv->widget = gtk_entry_new ();//temp hack to experiment with key propagation TODO entry widget is useful for testing
818 } else if (EQ(xww->type, Qsocket)) {
819 xv->widget = gtk_socket_new ();
820 g_signal_connect_after(xv->widget, "plug-added", G_CALLBACK(xwidget_plug_added), "plug added");
821 g_signal_connect_after(xv->widget, "plug-removed", G_CALLBACK(xwidget_plug_removed), "plug removed");
822 //TODO these doesnt help
823 gtk_widget_add_events(xv->widget, GDK_KEY_PRESS);
824 gtk_widget_add_events(xv->widget, GDK_KEY_RELEASE);
825 } else if (EQ(xww->type, Qslider)) {
826 xv->widget =
827 //gtk_hscale_new (GTK_ADJUSTMENT(gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 10.0, 10.0)));
828 gtk_hscale_new_with_range ( 0.0, 100.0, 10.0);
829 gtk_scale_set_draw_value (GTK_SCALE (xv->widget), FALSE); //i think its emacs role to show text and stuff, so disable the widgets own text
830 xv->handler_id = g_signal_connect_after(xv->widget, "value-changed", G_CALLBACK(xwidget_slider_changed), "slider changed");
831 } else if (EQ(xww->type, Qcairo)) {
832 //Cairo view
833 //uhm cairo is differentish in gtk 3.
834 //gdk_cairo_create (gtk_widget_get_window (FRAME_GTK_WIDGET (s->f)));
835 #ifdef HAVE_GOOCANVAS
836 xv->widget = goo_canvas_new();
837 GooCanvasItem *root, *rect_item, *text_item;
838 goo_canvas_set_bounds (GOO_CANVAS (xv->widget), 0, 0, 1000, 1000);
839 root = goo_canvas_get_root_item (GOO_CANVAS (xv->widget));
840 rect_item = goo_canvas_rect_new (root, 100, 100, 400, 400,
841 "line-width", 10.0,
842 "radius-x", 20.0,
843 "radius-y", 10.0,
844 "stroke-color", "yellow",
845 "fill-color", "red",
846 NULL);
847
848 text_item = goo_canvas_text_new (root, "Hello World", 300, 300, -1,
849 GTK_ANCHOR_CENTER,
850 "font", "Sans 24",
851 NULL);
852 goo_canvas_item_rotate (text_item, 45, 300, 300);
853
854 #endif
855 #ifdef HAVE_CLUTTER
856 xv->widget = gtk_clutter_embed_new ();;
857 ClutterActor *stage = NULL;
858 stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED ( xv->widget));
859 ClutterColor stage_color = { 0xaa, 0xaa, 0xaa, 0xff }; /* Black */
860 clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color);
861
862 ClutterActor * texture = clutter_cairo_texture_new (1000, 1000);
863 clutter_container_add_actor(stage, texture);
864 clutter_actor_set_position(texture, 0,0);
865 clutter_actor_show(texture);
866
867 cairo_t *cr;
868 cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (texture));
869
870 /* draw on the context */
871 RsvgHandle *h = rsvg_handle_new_from_file ("/tmp/tst.svg",
872 NULL);
873
874 rsvg_handle_render_cairo(h, cr);
875 cairo_destroy (cr);
876
877 /* Show the stage: */
878 clutter_actor_show (stage);
879 #endif
880 } else if (EQ(xww->type, Qwebkit_osr)||EQ(xww->type, Qsocket_osr)) {
881 #ifdef HAVE_WEBKIT_OSR
882 xv->widget = gtk_drawing_area_new();
883 gtk_widget_set_app_paintable ( xv->widget, TRUE); //because expose event handling
884 gtk_widget_add_events(xv->widget,
885 GDK_BUTTON_PRESS_MASK
886 | GDK_BUTTON_RELEASE_MASK
887 | GDK_POINTER_MOTION_MASK);
888 g_signal_connect (G_OBJECT ( xv->widget), "draw",
889 G_CALLBACK (xwidget_osr_draw_callback), NULL);
890 g_signal_connect (G_OBJECT ( xv->widget), "button-press-event",
891 G_CALLBACK (xwidget_osr_button_callback), NULL);
892 g_signal_connect (G_OBJECT ( xv->widget), "button-release-event",
893 G_CALLBACK (xwidget_osr_button_callback), NULL);
894 g_signal_connect (G_OBJECT ( xv->widget), "motion-notify-event",
895 G_CALLBACK (xwidget_osr_button_callback), NULL);
896 /* g_signal_connect (G_OBJECT ( xv->widget), "key-press-event", */
897 /* G_CALLBACK (xwidget_osr_button_callback), NULL); */
898 /* g_signal_connect (G_OBJECT ( xv->widget), "key-release-event", */
899 /* G_CALLBACK (xwidget_osr_button_callback), NULL); */
900
901 #endif
902
903
904 } else {
905 //here we have run out of hard coded symbols, we will now attempt to create
906 //a widget dynamically
907 //TODO
908 // - support OSR
909 // - support constructor args
910 // - support signals
911 // - check that the argument widget type actually exists
912 printf("xwgir symbol %s %s %s:\n",SDATA(SYMBOL_NAME(xww->type)), SDATA(Fcar(Fcdr(Fget(xww->type, Qcxwgir_class)))), SDATA(Fcar(Fget(xww->type, Qcxwgir_class))));
913 //xv->widget = xwgir_create ("Button");
914 Fcar(Fget(xww->type, Qcxwgir_class));
915 xv->widget = xwgir_create( SDATA(Fcar(Fcdr(Fget(xww->type, Qcxwgir_class)))),
916 SDATA(Fcar(Fget(xww->type, Qcxwgir_class))));
917
918 }
919
920 //else return NULL;
921
922 //widget realization
923 //make container widget 1st, and put the actual widget inside the container
924 //later, drawing should crop container window if necessary to handle case where xwidget
925 //is partially obscured by other emacs windows
926 //other containers than gtk_fixed where explored, but gtk_fixed had the most predictable behaviour so far.
927 xv->emacswindow = GTK_CONTAINER (FRAME_GTK_WIDGET (s->f));
928 xv->widgetwindow = GTK_CONTAINER (gtk_fixed_new ());
929 gtk_widget_set_has_window(GTK_WIDGET ( xv->widgetwindow), TRUE);
930 gtk_container_add (xv->widgetwindow, xv->widget);
931
932 //store some xwidget data in the gtk widgets
933 g_object_set_data (G_OBJECT (xv->widget), XG_FRAME_DATA, (gpointer) (s->f)); //the emacs frame
934 g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET, (gpointer) (xww)); //the xwidget
935 g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET_VIEW, (gpointer) (xv)); //the xwidget
936 g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET, (gpointer) (xww)); //the xwidget window
937 g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET_VIEW, (gpointer) (xv)); //the xwidget window
938
939
940 gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xww->width, xww->height);
941 gtk_widget_set_size_request (GTK_WIDGET (xv->widgetwindow), xww->width, xww->height);
942 gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), GTK_WIDGET (xv->widgetwindow), x, y);
943 xv->x = x; xv->y = y;
944 gtk_widget_show_all (GTK_WIDGET (xv->widgetwindow));
945
946 //widgettype specific initialization only possible after realization
947 if (EQ(xww->type, Qsocket)) {
948 printf ("xwid:%d socket id:%x %d\n",
949 xww,
950 gtk_socket_get_id (GTK_SOCKET (xv->widget)),
951 gtk_socket_get_id (GTK_SOCKET (xv->widget)));
952 send_xembed_ready_event (xww,
953 gtk_socket_get_id (GTK_SOCKET (xv->widget)));
954 //gtk_widget_realize(xw->widget);
955 }
956 return xv;
957 }
958
959
960 void
961 x_draw_xwidget_glyph_string (struct glyph_string *s)
962 {
963 /*
964 this method is called by the redisplay engine and places the xwidget on screen.
965 moving and clipping is done here. also view init.
966
967 */
968 int box_line_hwidth = eabs (s->face->box_line_width);
969 int box_line_vwidth = max (s->face->box_line_width, 0);
970 int height = s->height;
971 struct xwidget *xww = s->xwidget;
972 struct xwidget_view *xv = xwidget_view_lookup(xww, (s->w));
973 int clip_right; int clip_bottom; int clip_top; int clip_left;
974
975 int x = s->x;
976 int y = s->y + (s->height / 2) - (xww->height / 2);
977 int moved=0;
978
979 if (xv == NULL || xv->initialized == 0){
980 /* Views must be initialized once(only once).
981 We do it here in the display loop because there is no other time to know things like
982 window placement etc.
983 */
984 printf ("xv init for xw %d\n", xww);
985 xv = xwidget_init_view (xww, s, x, y);
986 }
987
988 //calculate clipping, which is used for all manner of onscreen xwidget views
989 //each widget border can get clipped by other emacs objects so there are four clipping variables
990 clip_right = min (xww->width, WINDOW_RIGHT_EDGE_X (s->w) - x - WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH(s->w) - WINDOW_RIGHT_FRINGE_WIDTH(s->w));
991 clip_left = max (0, WINDOW_LEFT_EDGE_X (s->w) - x + WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH(s->w) + WINDOW_LEFT_FRINGE_WIDTH(s->w));
992
993 clip_bottom = min (xww->height, WINDOW_BOTTOM_EDGE_Y (s->w) - WINDOW_MODE_LINE_HEIGHT (s->w) - y);
994 clip_top = max(0, WINDOW_TOP_EDGE_Y(s->w) -y );
995
996 //we are conserned with movement of the onscreen area. the area might sit still when the widget actually moves
997 //this happens when an emacs window border moves across a widget window
998 //so, if any corner of the outer widget clippng window moves, that counts as movement here, even
999 //if it looks like no movement happens because the widget sits still inside the clipping area.
1000 //the widget can also move inside the clipping area, which happens later
1001 moved = (xv->x + xv->clip_left != x+clip_left)
1002 || ((xv->y + xv->clip_top)!= (y+clip_top));
1003 if(moved) printf ("lxwidget moved: id:%d (%d,%d)->(%d,%d) y+clip_top:%d\n", xww, xv->x, xv->y, x, y, y + clip_top);
1004 else
1005 printf ("lxwidget DIDNT move: id:%d (%d,%d)->(%d,%d) y+clip_top:%d\n", xww, xv->x, xv->y, x, y, y + clip_top);
1006 xv->x = x;
1007 xv->y = y;
1008 if (moved) //has it moved?
1009 {
1010 if (1)//!xwidget_hidden(xv)) //hidden equals not being seen during redisplay
1011 {
1012 //TODO should be possible to use xwidget_show_view here
1013 gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)),
1014 GTK_WIDGET (xv->widgetwindow),
1015 x + clip_left, y + clip_top);
1016 }
1017 }
1018 //clip the widget window if some parts happen to be outside drawable area
1019 //an emacs window is not a gtk window, a gtk window covers the entire frame
1020 //cliping might have changed even if we havent actualy moved, we try figure out when we need to reclip for real
1021 if((xv->clip_right != clip_right)
1022 || (xv->clip_bottom != clip_bottom)
1023 || (xv->clip_top != clip_top)
1024 || (xv->clip_left != clip_left)){
1025 gtk_widget_set_size_request (GTK_WIDGET (xv->widgetwindow), clip_right + clip_left, clip_bottom + clip_top);
1026 gtk_fixed_move(GTK_FIXED(xv->widgetwindow), xv->widget, -clip_left, -clip_top);
1027 printf("reclip %d %d -> %d %d clip_top:%d clip_left:%d\n",xv->clip_right, xv->clip_bottom, clip_right, clip_bottom, clip_top , clip_left);
1028
1029
1030 xv->clip_right = clip_right; xv->clip_bottom = clip_bottom; xv->clip_top = clip_top;xv->clip_left = clip_left;
1031 }
1032 //if emacs wants to repaint the area where the widget lives, queue a redraw
1033 //TODO it seems its possible to get out of sync with emacs redraws so emacs bg sometimes shows up instead of xwidget
1034 //its just a visual glitch though
1035 if (!xwidget_hidden(xv)){
1036 gtk_widget_queue_draw (GTK_WIDGET(xv->widgetwindow));
1037 gtk_widget_queue_draw (xv->widget);
1038 }
1039 }
1040
1041
1042 #ifdef HAVE_WEBKIT_OSR
1043
1044 //FUGLY macro that checks WEBKIT_IS_WEB_VIEW(xw->widget_osr) first
1045 #define WEBKIT_FN_INIT() \
1046 struct xwidget* xw; \
1047 if(!XXWIDGETP(xwidget)) {printf("ERROR not an xwidget\n"); return Qnil;}; \
1048 if(Qnil == xwidget) {printf("ERROR xwidget nil\n"); return Qnil;}; \
1049 xw = XXWIDGET(xwidget); \
1050 if(NULL == xw) printf("ERROR xw is 0\n"); \
1051 if((NULL == xw->widget_osr) || !WEBKIT_IS_WEB_VIEW(xw->widget_osr)){ \
1052 printf("ERROR xw->widget_osr does not hold a webkit instance\n");\
1053 return Qnil;\
1054 };
1055
1056
1057 DEFUN ("xwidget-webkit-goto-uri", Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri,
1058 2, 2, 0,
1059 doc: /* webkit goto uri.*/)
1060 (Lisp_Object xwidget, Lisp_Object uri)
1061 {
1062 WEBKIT_FN_INIT();
1063 webkit_web_view_load_uri ( WEBKIT_WEB_VIEW(xw->widget_osr), SDATA(uri));
1064 return Qnil;
1065 }
1066
1067
1068 DEFUN ("xwidget-webkit-execute-script", Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script,
1069 2, 2, 0,
1070 doc: /* webkit exec js.*/)
1071 (Lisp_Object xwidget, Lisp_Object script)
1072 {
1073 WEBKIT_FN_INIT();
1074 webkit_web_view_execute_script( WEBKIT_WEB_VIEW(xw->widget_osr), SDATA(script));
1075 return Qnil;
1076 }
1077
1078 DEFUN ("xwidget-webkit-get-title", Fxwidget_webkit_get_title, Sxwidget_webkit_get_title,
1079 1, 1, 0,
1080 doc: /* webkit get title. can be used to work around exec method lacks return val*/)
1081 (Lisp_Object xwidget)
1082 {
1083 //TODO support multibyte strings
1084 WEBKIT_FN_INIT();
1085 const gchar* str=webkit_web_view_get_title( WEBKIT_WEB_VIEW(xw->widget_osr));
1086 //return make_string_from_bytes(str, wcslen((const wchar_t *)str), strlen(str));
1087 if(str == 0){
1088 //TODO maybe return Qnil instead. I suppose webkit returns nullpointer when doc is not properly loaded or something
1089 printf("xwidget-webkit-get-title null webkit title\n");
1090 return build_string("");
1091 }
1092 return build_string(str);
1093 }
1094
1095 //TODO missnamed
1096 DEFUN("xwidget-disable-plugin-for-mime", Fxwidget_disable_plugin_for_mime , Sxwidget_disable_plugin_for_mime,
1097 1,1,0, doc: /* */)
1098 (Lisp_Object mime)
1099 {
1100 WebKitWebPlugin *wp = webkit_web_plugin_database_get_plugin_for_mimetype
1101 (webkit_get_web_plugin_database(), SDATA(mime));
1102 if(wp == NULL) return Qnil;
1103 if(webkit_web_plugin_get_enabled (wp)){
1104 webkit_web_plugin_set_enabled (wp, FALSE);
1105 return Qt;
1106 }
1107 return Qnil;
1108 }
1109
1110
1111 //attempting a workaround for a webkit offscreen bug
1112 //TODO verify its still needed
1113 void
1114 gtk_window_get_position (GtkWindow *window,
1115 gint *root_x,
1116 gint *root_y)
1117 {
1118 printf("my getsize\n");
1119 *root_x = 0;
1120 *root_y = 0;
1121 }
1122
1123 void
1124 xwidget_webkit_dom_dump(WebKitDOMNode* parent)
1125 {
1126 WebKitDOMNodeList* list;
1127 int i;
1128 int length;
1129 WebKitDOMNode* attribute;
1130 WebKitDOMNamedNodeMap* attrs;
1131 WebKitDOMNode* child;
1132 printf("node:%d type:%d name:%s content:%s\n",
1133 parent,
1134 webkit_dom_node_get_node_type(parent),//1 element 3 text 8 comment 2 attribute
1135 webkit_dom_node_get_local_name(parent),
1136 webkit_dom_node_get_text_content(parent));
1137
1138 if(webkit_dom_node_has_attributes(parent)){
1139 attrs = webkit_dom_node_get_attributes(parent);
1140
1141 length = webkit_dom_named_node_map_get_length(attrs);
1142 for (int i = 0; i < length; i++) {
1143 attribute = webkit_dom_named_node_map_item(attrs,i);
1144 printf(" attr node:%d type:%d name:%s content:%s\n",
1145 attribute,
1146 webkit_dom_node_get_node_type(attribute),//1 element 3 text 8 comment
1147 webkit_dom_node_get_local_name(attribute),
1148 webkit_dom_node_get_text_content(attribute));
1149 }
1150 }
1151 list = webkit_dom_node_get_child_nodes(parent);
1152 length = webkit_dom_node_list_get_length(list);
1153
1154 for (int i = 0; i < length; i++) {
1155 child = webkit_dom_node_list_item(list, i);
1156 //if(webkit_dom_node_has_child_nodes(child))
1157 xwidget_webkit_dom_dump(child);
1158 }
1159 }
1160
1161
1162 DEFUN ("xwidget-webkit-dom-dump", Fxwidget_webkit_dom_dump, Sxwidget_webkit_dom_dump,
1163 1, 1, 0,
1164 doc: /* webkit dom dump*/)
1165 (Lisp_Object xwidget)
1166 {
1167 WEBKIT_FN_INIT();
1168 xwidget_webkit_dom_dump(WEBKIT_DOM_NODE(webkit_web_view_get_dom_document( WEBKIT_WEB_VIEW(xw->widget_osr))));
1169 return Qnil;
1170 }
1171
1172
1173
1174 #endif
1175
1176
1177
1178
1179
1180 DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0, doc:
1181 /* resize xwidgets*/)
1182 (Lisp_Object xwidget, Lisp_Object new_width, Lisp_Object new_height)
1183 {
1184 struct xwidget* xw = XXWIDGET(xwidget);
1185 struct xwidget_view *xv;
1186 int w, h;
1187
1188 CHECK_NUMBER (new_width);
1189 CHECK_NUMBER (new_height);
1190 w = XFASTINT (new_width);
1191 h = XFASTINT (new_height);
1192
1193
1194 printf("resize xwidget %d (%d,%d)->(%d,%d)\n",xw, xw->width,xw->height,w,h);
1195 xw->width=w;
1196 xw->height=h;
1197 //if theres a osr resize it 1st
1198 if(xw->widget_osr){
1199 printf("resize xwidget_osr\n");
1200 //gtk_container_set_resize_mode ( GTK_WINDOW(xw->widgetwindow_osr), GTK_RESIZE_QUEUE);
1201 //gtk_container_set_resize_mode ( GTK_WINDOW(xw->widget_osr), GTK_RESIZE_QUEUE);
1202
1203
1204 //gtk_layout_set_size (GTK_LAYOUT (xw->widgetwindow_osr), xw->width, xw->height);
1205 gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height); //minimum size
1206 //gtk_window_resize( GTK_WINDOW(xw->widget_osr), xw->width, xw->height);
1207 gtk_window_resize( GTK_WINDOW(xw->widgetwindow_osr), xw->width, xw->height);
1208 gtk_container_resize_children ( GTK_WINDOW(xw->widgetwindow_osr));
1209
1210 }
1211
1212 for (int i = 0; i < MAX_XWIDGETS; i++) //TODO MVC refactor lazy linear search
1213 {
1214 xv = &xwidget_views[i];
1215 if(xv->initialized && xv->model == xw){
1216 gtk_layout_set_size (GTK_LAYOUT (xv->widgetwindow), xw->width, xw->height);
1217 gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width, xw->height);
1218 }
1219 }
1220
1221 return Qnil;
1222 }
1223
1224 DEFUN ("xwidget-size-request", Fxwidget_size_request, Sxwidget_size_request, 1, 1, 0, doc:
1225 /* desired size (TODO crashes if arg not osr widget)*/)
1226 (Lisp_Object xwidget)
1227 {
1228 GtkRequisition requisition;
1229 Lisp_Object rv;
1230 gtk_widget_size_request(XXWIDGET(xwidget)->widget_osr, &requisition);
1231 rv = Qnil;
1232 rv = Fcons (make_number(requisition.height), rv);
1233 rv = Fcons (make_number(requisition.width), rv);
1234 return rv;
1235
1236 }
1237
1238 DEFUN ("xwidgetp", Fxwidgetp, Sxwidgetp, 1, 1, 0,
1239 doc: /* Return t if OBJECT is a xwidget. */)
1240 (Lisp_Object object)
1241 {
1242 return XWIDGETP (object) ? Qt : Qnil;
1243 }
1244
1245 DEFUN("xwidget-info", Fxwidget_info , Sxwidget_info, 1,1,0, doc: /* get xwidget props */)
1246 (Lisp_Object xwidget)
1247 {
1248 Lisp_Object info;
1249 struct xwidget* xw = XXWIDGET(xwidget);
1250
1251 info = Fmake_vector (make_number (4), Qnil);
1252 XSETSYMBOL (XVECTOR (info)->contents[0], xw->type);
1253 XSETSTRING (XVECTOR (info)->contents[1], xw->title);
1254 XSETINT (XVECTOR (info)->contents[2], xw->width);
1255 XSETINT (XVECTOR (info)->contents[3], xw->height);
1256
1257
1258 return info;
1259 }
1260
1261
1262 DEFUN("xwidget-view-info", Fxwidget_view_info , Sxwidget_view_info, 2,2,0, doc: /* get xwidget view props */)
1263 (Lisp_Object xwidget, Lisp_Object window)
1264 {
1265 struct xwidget* xw = XXWIDGET(xwidget);
1266 struct xwidget_view* xv = xwidget_view_lookup(xw, XWINDOW(window));
1267
1268 Lisp_Object info;
1269
1270 info = Fmake_vector (make_number (6), Qnil);
1271 XVECTOR (info)->contents[0] = make_number(xv->x);
1272 XVECTOR (info)->contents[1] = make_number(xv->y);
1273 XVECTOR (info)->contents[2] = make_number(xv->clip_right);
1274 XVECTOR (info)->contents[3] = make_number(xv->clip_bottom);
1275 XVECTOR (info)->contents[4] = make_number(xv->clip_top);
1276 XVECTOR (info)->contents[5] = make_number(xv->clip_left);
1277
1278 return info;
1279 }
1280
1281 DEFUN ("xwidget-send-keyboard-event", Fxwidget_send_keyboard_event, Sxwidget_send_keyboard_event, 2, 2, 0, doc:/* synthesize a kbd event for a xwidget. */
1282 )
1283 (Lisp_Object xwidget, Lisp_Object keydescriptor)
1284 {
1285 //TODO this code crashes for offscreen widgets and ive tried many different strategies
1286 //int keyval = 0x058; //X
1287 int keyval = XFASTINT(keydescriptor); //X
1288 char *keystring = "";
1289 GdkKeymapKey* keys;
1290 gint n_keys;
1291 GdkDeviceManager* manager;
1292 struct xwidget *xw;
1293 GtkWidget* widget;
1294 GdkEventKey* ev;
1295 Lisp_Object window;
1296 //popup_activated_flag = 1; //TODO just a hack
1297 gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), keyval, &keys, &n_keys);
1298
1299 xw = XXWIDGET(xwidget);
1300
1301 ev = (GdkEventKey*)gdk_event_new(GDK_KEY_PRESS);
1302
1303
1304 //todo what about windowless widgets?
1305
1306 window = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
1307
1308
1309 //TODO maybe we also need to special case sockets by picking up the plug rather than the socket
1310 if(xw->widget_osr)
1311 widget = xw->widget_osr;
1312 else
1313 widget = xwidget_view_lookup(xw, XWINDOW(window))->widget;
1314
1315 ev->window = gtk_widget_get_window(widget);
1316 gtk_widget_grab_focus(widget);
1317 ev->send_event = FALSE;
1318
1319 ev->hardware_keycode = keys[0].keycode;
1320 ev->group = keys[0].group;
1321
1322 ev->keyval = keyval;
1323 ev->time = GDK_CURRENT_TIME;
1324
1325 //ev->device = gdk_device_get_core_pointer();
1326 manager = gdk_display_get_device_manager(gdk_window_get_display(ev->window));
1327 gdk_event_set_device ((GdkEvent*)ev, gdk_device_manager_get_client_pointer(manager));
1328 gdk_event_put((GdkEvent*)ev);
1329 //g_signal_emit_by_name(ev->window,"key-press-event", ev);
1330
1331 ev->type = GDK_KEY_RELEASE;
1332 gdk_event_put((GdkEvent*)ev);
1333 //g_signal_emit_by_name(ev->window,"key-release-event", ev);
1334 //gtk_main_do_event(ev);
1335
1336 //TODO
1337 //if I delete the event the receiving component eventually crashes.
1338 //it ough TDTRT since event_put is supposed to copy the event
1339 //so probably this leaks events now
1340 //gdk_event_free((GdkEvent*)ev);
1341
1342 return Qnil;
1343 }
1344
1345
1346
1347 DEFUN("xwidget-delete-zombies", Fxwidget_delete_zombies , Sxwidget_delete_zombies, 0,0,0, doc: /* */)
1348 (void)
1349 {
1350 /*
1351 - remove all views with window gone
1352
1353 TODO
1354 - remove all xwidgets with buffer gone
1355 - remove all views with xw gone
1356
1357 */
1358 struct xwidget_view* xv = NULL;
1359 Lisp_Object w;
1360 for (int i = 0; i < MAX_XWIDGETS; i++){
1361 xv = &xwidget_views[i];
1362 XSETWINDOW(w, xv->w);
1363 if(xv->initialized && (! (WINDOW_LIVE_P(w)))){
1364
1365 gtk_widget_destroy(GTK_WIDGET(xv->widgetwindow));
1366 xv->initialized = 0;
1367 }
1368 }
1369 }
1370
1371
1372 DEFUN ("xwidget-plist", Fxwidget_plist, Sxwidget_plist,
1373 1, 1, 0,
1374 doc: /* Return the plist of XWIDGET. */)
1375 (register Lisp_Object xwidget)
1376 {
1377 //CHECK_XWIDGET (xwidget); //todo
1378 return XXWIDGET (xwidget)->plist;
1379 }
1380
1381 DEFUN ("xwidget-buffer", Fxwidget_buffer, Sxwidget_buffer,
1382 1, 1, 0,
1383 doc: /* Return the buffer of XWIDGET. */)
1384 (register Lisp_Object xwidget)
1385 {
1386 //CHECK_XWIDGET (xwidget); //todo
1387 return XXWIDGET (xwidget)->buffer;
1388 }
1389
1390 DEFUN ("set-xwidget-plist", Fset_xwidget_plist, Sset_xwidget_plist,
1391 2, 2, 0,
1392 doc: /* Replace the plist of XWIDGET with PLIST. Returns PLIST. */)
1393 (register Lisp_Object xwidget, Lisp_Object plist)
1394 {
1395 //CHECK_XWIDGET (xwidget); //todo
1396 CHECK_LIST (plist);
1397
1398 XXWIDGET (xwidget)->plist = plist;
1399 return plist;
1400 }
1401
1402
1403
1404 void
1405 syms_of_xwidget (void)
1406 {
1407 int i;
1408
1409 defsubr (&Smake_xwidget);
1410 defsubr (&Sxwidgetp);
1411 defsubr (&Sxwidget_info);
1412 defsubr (&Sxwidget_view_info);
1413 defsubr (&Sxwidget_resize);
1414
1415 #ifdef HAVE_WEBKIT_OSR
1416 defsubr (&Sxwidget_webkit_goto_uri);
1417 defsubr (&Sxwidget_webkit_execute_script);
1418 defsubr (&Sxwidget_webkit_get_title);
1419 DEFSYM (Qwebkit_osr ,"webkit-osr");
1420 #endif
1421
1422 defsubr (&Sxwgir_call_method );
1423 defsubr (&Sxwgir_require_namespace);
1424 defsubr (&Sxwidget_size_request );
1425 defsubr (&Sxwidget_delete_zombies);
1426 defsubr (&Sxwidget_disable_plugin_for_mime);
1427
1428 defsubr (&Sxwidget_send_keyboard_event);
1429 defsubr (&Sxwidget_webkit_dom_dump);
1430 defsubr (&Sxwidget_plist);
1431 defsubr (&Sxwidget_buffer);
1432 defsubr (&Sset_xwidget_plist);
1433
1434 DEFSYM (Qxwidget ,"xwidget");
1435
1436 DEFSYM (Qcxwidget ,":xwidget");
1437 DEFSYM (Qcxwgir_class ,":xwgir-class");
1438 DEFSYM (Qtitle ,":title");
1439
1440 DEFSYM (Qbutton, "Button"); //changed to match the gtk class because xwgir(experimental and not really needed)
1441 DEFSYM (Qtoggle, "ToggleButton");
1442 DEFSYM (Qslider, "slider");
1443 DEFSYM (Qsocket, "socket");
1444 DEFSYM (Qsocket_osr, "socket-osr");
1445 DEFSYM (Qcairo, "cairo");
1446
1447 DEFSYM (QCplist, ":plist");
1448
1449 DEFVAR_LISP ("xwidget-alist", Vxwidget_alist, doc: /*xwidgets list*/);
1450 Vxwidget_alist = Qnil;
1451 DEFVAR_LISP ("xwidget-view-alist", Vxwidget_view_alist, doc: /*xwidget views list*/);
1452 Vxwidget_alist = Qnil;
1453
1454 Fprovide (intern ("xwidget-internal"), Qnil);
1455
1456 // for (i = 0; i < MAX_XWIDGETS; i++)
1457 //xwidgets[i].initialized = 0;
1458 }
1459
1460
1461 /* Value is non-zero if OBJECT is a valid Lisp xwidget specification. A
1462 valid xwidget specification is a list whose car is the symbol
1463 `xwidget', and whose rest is a property list. The property list must
1464 contain a value for key `:type'. That value must be the name of a
1465 supported xwidget type. The rest of the property list depends on the
1466 xwidget type. */
1467
1468 int
1469 valid_xwidget_p (Lisp_Object object)
1470 {
1471 int valid_p = 0;
1472
1473 if (XWIDGETP (object))
1474 {
1475 /* Lisp_Object tem; */
1476
1477 /* for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem)) */
1478 /* if (EQ (XCAR (tem), QCtype)) */
1479 /* { */
1480 /* tem = XCDR (tem); */
1481 /* if (CONSP (tem) && SYMBOLP (XCAR (tem))) */
1482 /* { */
1483 /* struct xwidget_type *type; */
1484 /* type = lookup_xwidget_type (XCAR (tem)); */
1485 /* if (type) */
1486 /* valid_p = type->valid_p (object); */
1487 /* } */
1488
1489 /* break; */
1490 /* } */
1491 //never mind type support for now
1492 valid_p = 1;
1493 }
1494
1495 return valid_p;
1496 }
1497
1498
1499
1500 /* find a value associated with key in spec */
1501 Lisp_Object
1502 xwidget_spec_value ( Lisp_Object spec, Lisp_Object key,
1503 int *found)
1504 {
1505 Lisp_Object tail;
1506
1507 eassert (valid_xwidget_p (spec));
1508
1509 for (tail = XCDR (spec);
1510 CONSP (tail) && CONSP (XCDR (tail)); tail = XCDR (XCDR (tail)))
1511 {
1512 if (EQ (XCAR (tail), key))
1513 {
1514 if (found)
1515 *found = 1;
1516 return XCAR (XCDR (tail));
1517 }
1518 }
1519
1520 if (found)
1521 *found = 0;
1522 return Qnil;
1523 }
1524
1525
1526 void
1527 xwidget_view_delete_all_in_window (struct window *w)
1528 {
1529 struct xwidget_view* xv = NULL;
1530 for (int i = 0; i < MAX_XWIDGETS; i++){
1531 xv = &xwidget_views[i];
1532 if(xv->initialized && xv->w == w){
1533 gtk_widget_destroy(GTK_WIDGET(xv->widgetwindow));
1534 xv->initialized = 0;
1535 }
1536 }
1537 }
1538
1539
1540
1541 struct xwidget_view*
1542 xwidget_view_lookup (struct xwidget* xw, struct window *w)
1543 {
1544 struct xwidget_view* xv = NULL;
1545 for (int i = 0; i < MAX_XWIDGETS; i++){
1546 xv = &xwidget_views[i];
1547 if (xv->initialized && (xv->model == xw) && (xv->w == w))
1548 return xv;
1549 }
1550 return NULL; /* we didnt find a matching view */
1551 }
1552
1553 struct xwidget*
1554 lookup_xwidget (Lisp_Object spec)
1555 {
1556 /* When a xwidget lisp spec is found initialize the C struct that is used in the C code.
1557 This is done by redisplay so values change if the spec changes.
1558 So, take special care of one-shot events
1559
1560 TODO remove xwidget init from display spec. simply store an xwidget reference only and set
1561 size etc when creating the xwidget, which should happen before insertion into buffer
1562 */
1563 int found = 0, found1 = 0, found2 = 0;
1564 Lisp_Object value;
1565 struct xwidget *xw;
1566
1567 value = xwidget_spec_value (spec, Qcxwidget, &found1);
1568 xw = XXWIDGET(value);
1569
1570 /* value = xwidget_spec_value (spec, QCtype, &found); */
1571 /* xw->type = SYMBOLP (value) ? value : Qbutton; //default to button */
1572 /* value = xwidget_spec_value (spec, Qtitle, &found2); */
1573 /* xw->title = STRINGP (value) ? (char *) SDATA (value) : "?"; //funky cast FIXME TODO */
1574
1575 /* value = xwidget_spec_value (spec, QCheight, NULL); */
1576 /* xw->height = INTEGERP (value) ? XFASTINT (value) : 50; */
1577 /* value = xwidget_spec_value (spec, QCwidth, NULL); */
1578 /* xw->width = INTEGERP (value) ? XFASTINT (value) : 50; */
1579
1580 /* value = xwidget_spec_value (spec, QCplist, NULL); */
1581 /* xw->plist = value; */
1582 /* coordinates are not known here */
1583 printf ("lookup_xwidget xwidget_id:%d type:%d found:%d %d %d title:'%s' (%d,%d)\n", xw,
1584 xw->type, found, found1, found2, xw->title, xw->height, xw->width);
1585
1586 //assert_valid_xwidget_id (id, "lookup_xwidget");
1587 return xw;
1588 }
1589
1590 /*set up detection of touched xwidget*/
1591 void
1592 xwidget_start_redisplay (void)
1593 {
1594 int i;
1595 for (i = 0; i < MAX_XWIDGETS; i++)
1596 xwidget_views[i].redisplayed = 0;
1597
1598 }
1599
1600 /* the xwidget was touched during redisplay, so it isnt a candidate for hiding*/
1601 void
1602 xwidget_touch (struct xwidget_view *xv)
1603 {
1604 xv->redisplayed = 1;
1605 }
1606
1607 int
1608 xwidget_touched (struct xwidget_view *xv)
1609 {
1610 return xv->redisplayed;
1611 }
1612
1613 /* redisplay has ended, now we should hide untouched xwidgets
1614 */
1615 void
1616 xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix)
1617 {
1618
1619 int i;
1620 struct xwidget *xw;
1621 int area;
1622
1623
1624 xwidget_start_redisplay ();
1625 //iterate desired glyph matrix of window here, hide gtk widgets
1626 //not in the desired matrix.
1627
1628 //this only takes care of xwidgets in active windows.
1629 //if a window goes away from screen xwidget views wust be deleted
1630
1631 // dump_glyph_matrix(matrix, 2);
1632 for (i = 0; i < matrix->nrows; ++i)
1633 {
1634 // dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs);
1635 struct glyph_row *row;
1636 row = MATRIX_ROW (matrix, i);
1637 if (row->enabled_p != 0)
1638 {
1639 for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
1640 {
1641 struct glyph *glyph = row->glyphs[area];
1642 struct glyph *glyph_end = glyph + row->used[area];
1643 for (; glyph < glyph_end; ++glyph)
1644 {
1645 if (glyph->type == XWIDGET_GLYPH)
1646 {
1647 /*
1648 the only call to xwidget_end_redisplay is in dispnew
1649 xwidget_end_redisplay(w->current_matrix);
1650 */
1651 xwidget_touch (xwidget_view_lookup(glyph->u.xwidget,
1652 w));
1653 }
1654 }
1655 }
1656 }
1657 }
1658
1659 for (i = 0; i < MAX_XWIDGETS; i++)
1660 {
1661 struct xwidget_view* xv = &xwidget_views[i];
1662
1663 //"touched" is only meaningful for the current window, so disregard other views
1664 if (xv->initialized && ( xv->w == w))
1665 {
1666 if (xwidget_touched(xv))
1667 xwidget_show_view (xv);
1668 else
1669 xwidget_hide_view (xv);
1670 }
1671 }
1672 }
1673
1674
1675 #endif