]> code.delx.au - gnu-emacs/blob - src/xwidget.c
Merge branch 'master' into xwidget
[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 /* HAVE_X_WINDOWS */
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 #include <wchar.h>
83
84 #ifdef HAVE_WEBKIT_OSR
85 #include <webkit/webkitwebview.h>
86 #include <webkit/webkitwebplugindatabase.h>
87 #include <webkit/webkitwebplugin.h>
88 #include <webkit/webkitglobals.h>
89 #include <webkit/webkitwebnavigationaction.h>
90 #include <webkit/webkitdownload.h>
91 #include <webkit/webkitwebpolicydecision.h>
92 #endif
93
94 //for GIR
95 #include <girepository.h>
96
97 #include "xwidget.h"
98
99 //TODO embryo of lisp allocators for xwidgets
100 //TODO xwidget* should be Lisp_xwidget*
101 struct xwidget*
102 allocate_xwidget (void)
103 {
104 return ALLOCATE_PSEUDOVECTOR (struct xwidget, height, PVEC_XWIDGET);
105 }
106
107 //TODO xwidget_view* should be Lisp_xwidget_view*
108 struct xwidget_view*
109 allocate_xwidget_view (void)
110 {
111 return ALLOCATE_PSEUDOVECTOR (struct xwidget_view, redisplayed, PVEC_XWIDGET_VIEW);
112 }
113 #define XSETXWIDGET(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET))
114 #define XSETXWIDGET_VIEW(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW))
115
116 Lisp_Object Qxwidget;
117 Lisp_Object QCxwidget;
118 Lisp_Object QCtitle;
119 Lisp_Object Qxwidget_set_keyboard_grab;
120 Lisp_Object Qxwidget_embed_steal_window;
121 Lisp_Object Qxwidget_info;
122 Lisp_Object Qxwidget_resize;
123 Lisp_Object Qxwidget_send_keyboard_event;
124 Lisp_Object QCxwgir_class;
125 Lisp_Object Qbutton, Qtoggle, Qslider, Qsocket, Qsocket_osr, Qcairo, Qxwgir,
126 Qwebkit_osr, QCplist;
127 Lisp_Object Qxwidgetp, Qxwidget_view_p;
128
129
130 extern Lisp_Object QCtype;
131 extern Lisp_Object QCwidth, QCheight;
132
133 struct xwidget_view* xwidget_view_lookup(struct xwidget* xw, struct window *w);
134 Lisp_Object xwidget_spec_value ( Lisp_Object spec, Lisp_Object key, int *found);
135 gboolean offscreen_damage_event (GtkWidget *widget, GdkEvent *event, gpointer data);
136 void webkit_osr_document_load_finished_callback (WebKitWebView *webkitwebview,
137 WebKitWebFrame *arg1,
138 gpointer user_data);
139 gboolean webkit_osr_download_callback (WebKitWebView *webkitwebview,
140 WebKitDownload *arg1,
141 gpointer data);
142
143 gboolean webkit_osr_mime_type_policy_typedecision_requested_callback(WebKitWebView *webView,
144 WebKitWebFrame *frame,
145 WebKitNetworkRequest *request,
146 gchar *mimetype,
147 WebKitWebPolicyDecision *policy_decision,
148 gpointer user_data);
149
150 gboolean webkit_osr_new_window_policy_decision_requested_callback(WebKitWebView *webView,
151 WebKitWebFrame *frame,
152 WebKitNetworkRequest *request,
153 WebKitWebNavigationAction *navigation_action,
154 WebKitWebPolicyDecision *policy_decision,
155 gpointer user_data);
156
157
158 gboolean webkit_osr_navigation_policy_decision_requested_callback(WebKitWebView *webView,
159 WebKitWebFrame *frame,
160 WebKitNetworkRequest *request,
161 WebKitWebNavigationAction *navigation_action,
162 WebKitWebPolicyDecision *policy_decision,
163 gpointer user_data);
164
165 GtkWidget* xwgir_create(char* class, char* namespace);
166 static void
167 send_xembed_ready_event (struct xwidget* xw, int xembedid);
168 DEFUN ("make-xwidget", Fmake_xwidget, Smake_xwidget, 7, 8, 0,
169 doc: /* Make an xwidget from BEG to END of TYPE.
170
171 If BUFFER is nil it uses the current buffer. If BUFFER is a string and
172 no such buffer exists, it is created.
173
174 TYPE is a symbol which can take one of the following values:
175 - Button
176 - ToggleButton
177 - slider
178 - socket
179 - socket-osr
180 - cairo
181 */
182 )
183 (Lisp_Object beg, Lisp_Object end,
184 Lisp_Object type,
185 Lisp_Object title,
186 Lisp_Object width, Lisp_Object height,
187 Lisp_Object data,
188 Lisp_Object buffer)
189 {
190 //should work a bit like "make-button"(make-button BEG END &rest PROPERTIES)
191 // arg "type" and fwd should be keyword args eventually
192 //(make-xwidget 3 3 'button "oei" 31 31 nil)
193 //(xwidget-info (car xwidget-list))
194 struct xwidget* xw = allocate_xwidget();
195 Lisp_Object val;
196 xw->type = type;
197 xw->title = title;
198 if (NILP (buffer))
199 buffer = Fcurrent_buffer(); // no need to gcpro because Fcurrent_buffer doesn't call Feval/eval_sub.
200 else
201 buffer = Fget_buffer_create (buffer);
202 xw->buffer = buffer;
203
204 xw->height = XFASTINT(height);
205 xw->width = XFASTINT(width);
206 xw->kill_without_query = 0;
207 XSETXWIDGET (val, xw); // set the vectorlike_header of VAL with the correct value
208 Vxwidget_list = Fcons (val, Vxwidget_list);
209 xw->widgetwindow_osr = NULL;
210 xw->widget_osr = NULL;
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 EQ(xw->type, Qsocket_osr)||
220 (!NILP (Fget(xw->type, QCxwgir_class)))) {
221 block_input();
222 xw->widgetwindow_osr = gtk_offscreen_window_new ();
223 gtk_window_resize(GTK_WINDOW(xw->widgetwindow_osr), xw->width, xw->height);
224
225 if (EQ(xw->type, Qwebkit_osr))
226 xw->widget_osr = webkit_web_view_new();
227 if(EQ(xw->type, Qsocket_osr))
228 xw->widget_osr = gtk_socket_new();
229 if(!NILP (Fget(xw->type, QCxwgir_class)))
230 xw->widget_osr = xwgir_create(SDATA(Fcar(Fcdr(Fget(xw->type, QCxwgir_class)))),
231 SDATA(Fcar(Fget(xw->type, QCxwgir_class))));
232
233 gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height);
234 gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr), xw->widget_osr);
235
236 gtk_widget_show (xw->widget_osr);
237 gtk_widget_show (xw->widgetwindow_osr);
238
239 /* store some xwidget data in the gtk widgets for convenient retrieval in the event handlers. */
240 g_object_set_data (G_OBJECT (xw->widget_osr), XG_XWIDGET, (gpointer) (xw));
241 g_object_set_data (G_OBJECT (xw->widgetwindow_osr), XG_XWIDGET, (gpointer) (xw));
242
243 /* signals */
244 if (EQ(xw->type, Qwebkit_osr)) {
245 g_signal_connect (G_OBJECT (xw->widget_osr),
246 "document-load-finished",
247 G_CALLBACK (webkit_osr_document_load_finished_callback),
248 xw);
249
250 g_signal_connect (G_OBJECT (xw->widget_osr),
251 "download-requested",
252 G_CALLBACK (webkit_osr_download_callback),
253 xw);
254
255 g_signal_connect (G_OBJECT (xw->widget_osr),
256 "mime-type-policy-decision-requested",
257 G_CALLBACK (webkit_osr_mime_type_policy_typedecision_requested_callback),
258 xw);
259
260 g_signal_connect (G_OBJECT (xw->widget_osr),
261 "new-window-policy-decision-requested",
262 G_CALLBACK (webkit_osr_new_window_policy_decision_requested_callback),
263 xw);
264
265 g_signal_connect (G_OBJECT (xw->widget_osr),
266 "navigation-policy-decision-requested",
267 G_CALLBACK (webkit_osr_navigation_policy_decision_requested_callback),
268 xw);
269 }
270
271 if (EQ(xw->type, Qsocket_osr)) {
272 send_xembed_ready_event (xw, gtk_socket_get_id (GTK_SOCKET (xw->widget_osr)));
273 //gtk_widget_realize(xw->widget);
274 }
275
276
277 unblock_input();
278
279 }
280 #endif /* HAVE_WEBKIT_OSR */
281
282 return val;
283 }
284
285 DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets, Sget_buffer_xwidgets, 1, 1, 0,
286 doc: /* Return a list of xwidgets associated with BUFFER.
287 BUFFER may be a buffer or the name of one.
288 */
289 )
290 (Lisp_Object buffer)
291 {
292 Lisp_Object xw, tail, xw_list;
293
294 if (NILP (buffer)) return Qnil;
295 buffer = Fget_buffer (buffer);
296 if (NILP (buffer)) return Qnil;
297
298 xw_list = Qnil;
299
300 for (tail = Vxwidget_list; CONSP (tail); tail = XCDR (tail))
301 {
302 xw = XCAR (tail);
303 if (XWIDGETP (xw) && EQ (Fxwidget_buffer (xw), buffer))
304 xw_list = Fcons (xw, xw_list);
305 }
306 return xw_list;
307 }
308
309 int
310 xwidget_hidden(struct xwidget_view *xv)
311 {
312 return xv->hidden;
313 }
314
315
316 static void
317 buttonclick_handler (GtkWidget * widget, gpointer data)
318 {
319 Lisp_Object xwidget_view, xwidget;
320 XSETXWIDGET_VIEW (xwidget_view, (struct xwidget_view *) data);
321 xwidget = Fxwidget_view_model (xwidget_view);
322
323 struct input_event event;
324 Lisp_Object frame = Fwindow_frame (Fxwidget_view_window (xwidget_view));
325 struct frame *f = XFRAME (frame);
326 printf ("button clicked xw:%d '%s'\n", XXWIDGET (xwidget), XXWIDGET (xwidget)->title);
327
328 EVENT_INIT (event);
329 event.kind = XWIDGET_EVENT;
330
331 event.frame_or_window = frame;
332
333 event.arg = Qnil;
334 event.arg = Fcons (xwidget, event.arg);
335 event.arg = Fcons (intern ("buttonclick"), event.arg);
336
337 kbd_buffer_store_event (&event);
338 }
339
340
341 static void
342 send_xembed_ready_event (struct xwidget* xw, int xembedid)
343 {
344 Lisp_Object xw_lo;
345 XSETXWIDGET(xw_lo, xw);
346 struct input_event event;
347 EVENT_INIT (event);
348 event.kind = XWIDGET_EVENT;
349 event.frame_or_window = Qnil; //frame; //how to get the frame here? //TODO i store it in the xwidget now
350
351 event.arg = Qnil;
352 event.arg = Fcons (make_number (xembedid), event.arg);
353 event.arg = Fcons (xw_lo, event.arg);
354 event.arg = Fcons (intern ("xembed-ready"), event.arg);
355
356
357 kbd_buffer_store_event (&event);
358
359 }
360
361 void
362 xwidget_show_view (struct xwidget_view *xv)
363 {
364 xv->hidden = 0;
365 gtk_widget_show(xv->widgetwindow);
366 gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow, xv->x + xv->clip_left, xv->y + xv->clip_top); //TODO refactor
367 }
368
369
370 /* hide an xvidget view */
371 void
372 xwidget_hide_view (struct xwidget_view *xv)
373 {
374 xv->hidden = 1;
375 //gtk_widget_hide(xw->widgetwindow);
376 gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow,
377 10000, 10000);
378 }
379
380
381 void
382 xwidget_plug_added(GtkSocket *socket,
383 gpointer user_data)
384 {
385 //hmm this doesnt seem to get called for foreign windows
386 printf("xwidget_plug_added\n");
387 }
388
389 gboolean
390 xwidget_plug_removed(GtkSocket *socket,
391 gpointer user_data)
392 {
393 printf("xwidget_plug_removed\n");
394 return TRUE; /* dont run the default handler because that kills the socket and we want to reuse it*/
395 }
396
397
398 void
399 xwidget_slider_changed (GtkRange *range,
400 gpointer user_data)
401 {
402 //slider value changed. change value of siblings
403 //correspondingly. but remember that changing value will again
404 //trigger signal
405
406 //TODO MVC view storage wont be an array futureish so the loop needs to change eventually
407 //TODO MVC it would be nice if this code could be reusable but, alas, C is not a functional language
408 //issues are:
409 // - the type of the controllers value (double, boolean etc)
410 // - the getter and setter (but they can be func pointers)
411 // a behemoth macro is always an option.
412 double v=gtk_range_get_value(range);
413 struct xwidget_view* xvp = g_object_get_data (G_OBJECT (range), XG_XWIDGET_VIEW);
414 struct xwidget_view* xv;
415
416 printf("slider changed val:%f\n", v);
417
418 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
419 {
420 if (XWIDGET_VIEW_P (XCAR (tail))) {
421 xv = XXWIDGET_VIEW (XCAR (tail));
422 if (EQ (xvp->model, xv->model)) {
423 //block sibling views signal handlers
424 g_signal_handler_block(xv->widget, xv->handler_id);
425
426 //set values of sibling views and unblock
427 gtk_range_set_value(GTK_RANGE(xv->widget), v);
428 g_signal_handler_unblock(xv->widget,xv->handler_id);
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 offscreen_damage_event (GtkWidget *widget, GdkEvent *event, gpointer data)
439 {
440 //TODO this is wrong! should just queu a redraw of onscreen widget
441 gtk_widget_queue_draw (GTK_WIDGET (data));
442 return FALSE;
443 }
444
445 void
446 store_xwidget_event_string(struct xwidget* xw, char* eventname, const char* eventstr)
447 {
448 //refactor attempt
449 struct input_event event;
450 Lisp_Object xwl;
451 XSETXWIDGET(xwl,xw);
452 EVENT_INIT (event);
453 event.kind = XWIDGET_EVENT;
454 event.frame_or_window = Qnil; //frame; //how to get the frame here? //TODO i store it in the xwidget now
455
456 event.arg = Qnil;
457 event.arg = Fcons (build_string(eventstr), event.arg); //string so dont intern
458 event.arg = Fcons (xwl, event.arg); //TODO
459 event.arg = Fcons (intern (eventname), event.arg);//interning should be ok
460 kbd_buffer_store_event (&event);
461
462 }
463
464 //TODO deprecated, use load-status
465 void
466 webkit_osr_document_load_finished_callback (WebKitWebView *webkitwebview,
467 WebKitWebFrame *arg1,
468 gpointer data)
469 {
470 //TODO this event sending code should be refactored
471 // struct xwidget *xw = (struct xwidget *) data;
472 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webkitwebview), XG_XWIDGET);
473 printf("webkit finished loading\n");
474
475 store_xwidget_event_string(xw,
476 "document-load-finished", "");
477 }
478
479 gboolean
480 webkit_osr_download_callback (WebKitWebView *webkitwebview,
481 WebKitDownload *arg1,
482 gpointer data)
483 {
484 //TODO this event sending code should be refactored
485 struct input_event event;
486 // struct xwidget *xw = (struct xwidget *) data;
487 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webkitwebview), XG_XWIDGET);
488 printf("download requested %s\n", webkit_download_get_uri (arg1));
489
490
491 printf("webkit finished loading\n");
492
493 store_xwidget_event_string(xw, "download-requested", webkit_download_get_uri (arg1));
494
495 return FALSE;
496 }
497
498 gboolean
499 webkit_osr_mime_type_policy_typedecision_requested_callback(WebKitWebView *webView,
500 WebKitWebFrame *frame,
501 WebKitNetworkRequest *request,
502 gchar *mimetype,
503 WebKitWebPolicyDecision *policy_decision,
504 gpointer user_data)
505 {
506 printf("mime policy requested\n");
507 // this function makes webkit send a download signal for all unknown mime types
508 // TODO defer the decision to lisp, so that its possible to make Emacs handle text mime for instance
509 if(!webkit_web_view_can_show_mime_type(webView, mimetype)){
510 webkit_web_policy_decision_download (policy_decision);
511 return TRUE;
512 }else{
513 return FALSE;
514 }
515 }
516
517
518 gboolean
519 webkit_osr_new_window_policy_decision_requested_callback(WebKitWebView *webView,
520 WebKitWebFrame *frame,
521 WebKitNetworkRequest *request,
522 WebKitWebNavigationAction *navigation_action,
523 WebKitWebPolicyDecision *policy_decision,
524 gpointer user_data)
525 {
526 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
527 printf("webkit_osr_new_window_policy_decision_requested_callback %s\n",
528 webkit_web_navigation_action_get_original_uri (navigation_action));
529
530 store_xwidget_event_string(xw, "new-window-policy-decision-requested", webkit_web_navigation_action_get_original_uri (navigation_action)
531 );
532 return FALSE;
533 }
534
535 gboolean
536 webkit_osr_navigation_policy_decision_requested_callback(WebKitWebView *webView,
537 WebKitWebFrame *frame,
538 WebKitNetworkRequest *request,
539 WebKitWebNavigationAction *navigation_action,
540 WebKitWebPolicyDecision *policy_decision,
541 gpointer user_data)
542 {
543 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
544 printf("webkit_osr_navigation_policy_decision_requested_callback %s\n",
545 webkit_web_navigation_action_get_original_uri (navigation_action));
546 store_xwidget_event_string(xw, "navigation-policy-decision-requested", webkit_web_navigation_action_get_original_uri (navigation_action)
547 );
548 return FALSE;
549 }
550
551 //for gtk3 offscreen rendered widgets
552 gboolean
553 xwidget_osr_draw_callback (GtkWidget *widget, cairo_t *cr, gpointer data)
554 {
555 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
556 struct xwidget_view* xv = (struct xwidget_view*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET_VIEW);
557
558 cairo_rectangle(cr, 0,0, xv->clip_right, xv->clip_bottom);//xw->width, xw->height);
559 cairo_clip(cr);
560
561 gtk_widget_draw (xw->widget_osr, cr);
562
563 return FALSE;
564 }
565
566 GtkWidget* xwgir_create_debug;
567
568
569
570 gboolean
571 xwidget_osr_event_forward (GtkWidget *widget,
572 GdkEvent *event,
573 gpointer user_data)
574 {
575 /* copy events that arrive at the outer widget to the offscreen widget */
576 struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
577 GdkEvent* eventcopy = gdk_event_copy(event);
578 //GdkEvent* eventcopy = gdk_event_new(GDK_BUTTON_PRESS);
579
580
581 //((GdkEventAny*)eventcopy)->window = gtk_widget_get_window(xw->widget_osr);
582 //eventcopy->any.window = gtk_widget_get_window(GTK_WIDGET (xw->widgetwindow_osr));
583 //((GdkEventAny*)eventcopy)->window = gtk_widget_get_window(xwgir_create_debug);
584 eventcopy->any.window = gtk_widget_get_window(xw->widget_osr);//gtk_widget_get_window(xwgir_create_debug);
585 //eventcopy->any.window = gtk_button_get_event_window(GTK_BUTTON(xw->widget_osr));//gtk_widget_get_window(xwgir_create_debug);
586 //eventcopy->button.x=200; eventcopy->button.y=200;
587 //event->button.button = GDK_BUTTON_PRIMARY; //debug
588
589 //eventcopy->any.window = xw->widgetwindow_osr;//gtk_widget_get_window(xwgir_create_debug);
590 /* eventcopy->any.send_event = TRUE; */
591 /* eventcopy->button.time = GDK_CURRENT_TIME; */
592 /* eventcopy->button.device = event->button.device; */
593
594
595 printf("xwidget_osr_event_forward redirect event to window:%d\n", ((GdkEventAny*)eventcopy)->window);
596 printf("A type:%d x:%f y:%f \n", event->type, event->button.x, event->button.y);
597 printf("B type:%d x:%f y:%f \n", eventcopy->type, eventcopy->button.x, eventcopy->button.y);
598 //gtk_button_get_event_window(xwgir_create_debug);
599 gtk_main_do_event(eventcopy); //TODO this will leak events. they should be deallocated later, perhaps in xwgir_event_callback
600 //printf("gtk_widget_event:%d\n",gtk_widget_event(xw->widget_osr, eventcopy));
601 //gdk_event_put(eventcopy);
602 //gdk_event_queue_append(eventcopy);
603 //gdk_event_free(eventcopy);
604 return TRUE; //dont propagate this event furter
605 //return FALSE; //dont propagate this event furter
606 }
607
608 GIRepository *girepository ;
609
610 DEFUN ("xwgir-require-namespace", Fxwgir_require_namespace, Sxwgir_require_namespace, 2,2,0,
611 doc: /* Require a GObject Introspection namespace.
612 This must be done for all namespaces we want to use, before using other xwgir functions.*/)
613 (Lisp_Object lnamespace, Lisp_Object lnamespace_version)
614 {
615 char* namespace = SDATA(lnamespace);
616 char* namespace_version = SDATA(lnamespace_version);
617 GError *error = NULL;
618
619 girepository = g_irepository_get_default();
620 g_irepository_require(girepository, namespace, namespace_version, 0, &error);
621 if (error) {
622 g_error("ERROR: %s\n", error->message);
623 return Qnil;
624 }
625 return Qt;
626 }
627
628 GtkWidget* xwgir_create(char* class, char* namespace){
629 //TODO this is more or less the same as xwgir-call-method, so should be refactored
630 //create a gtk widget, given its name
631 //find the constructor
632 //call it
633 //also figure out how to pass args
634
635 GError *error = NULL;
636 GIArgument return_value;
637
638 GIObjectInfo* obj_info = g_irepository_find_by_name(girepository, namespace, class);
639 GIFunctionInfo* f_info = g_object_info_find_method (obj_info, "new");
640 g_function_info_invoke(f_info,
641 NULL, 0,
642 NULL, 0,
643 &return_value,
644 NULL);
645 xwgir_create_debug = return_value.v_pointer;
646 return return_value.v_pointer;
647
648 }
649
650 int
651 xwgir_convert_lisp_to_gir_arg(GIArgument* giarg,
652 GIArgInfo* arginfo,
653 Lisp_Object lisparg )
654 {
655
656 GITypeTag tag;
657 gboolean is_pointer;
658 gboolean is_enum;
659 tag = g_type_info_get_tag (g_arg_info_get_type (arginfo));
660
661 switch (tag)
662 {
663 case GI_TYPE_TAG_BOOLEAN:
664 giarg->v_boolean = XFASTINT(lisparg);
665 break;
666 case GI_TYPE_TAG_INT8:
667 giarg->v_int8 = XFASTINT(lisparg);
668 break;
669 case GI_TYPE_TAG_UINT8:
670 giarg->v_uint8 = XFASTINT(lisparg);
671 break;
672 case GI_TYPE_TAG_INT16:
673 giarg->v_int16 = XFASTINT(lisparg);
674 break;
675 case GI_TYPE_TAG_UINT16:
676 giarg->v_uint16 = XFASTINT(lisparg);
677 break;
678 case GI_TYPE_TAG_INT32:
679 giarg->v_int32 = XFASTINT(lisparg);
680 break;
681 case GI_TYPE_TAG_UINT32:
682 giarg->v_uint32 = XFASTINT(lisparg);
683 break;
684
685 case GI_TYPE_TAG_INT64:
686 giarg->v_int64 = XFASTINT(lisparg);
687 break;
688 case GI_TYPE_TAG_UINT64:
689 giarg->v_uint64 = XFASTINT(lisparg);
690 break;
691
692
693 case GI_TYPE_TAG_FLOAT:
694 giarg->v_float = XFLOAT_DATA(lisparg);
695 break;
696
697 case GI_TYPE_TAG_DOUBLE:
698 giarg->v_double = XFLOAT_DATA(lisparg);
699 break;
700
701 case GI_TYPE_TAG_UTF8:
702 case GI_TYPE_TAG_FILENAME:
703 //giarg->v_string = SDATA(lisparg);
704 giarg->v_pointer = SDATA(lisparg);
705 break;
706
707 case GI_TYPE_TAG_ARRAY:
708 case GI_TYPE_TAG_GLIST:
709 case GI_TYPE_TAG_GSLIST:
710 case GI_TYPE_TAG_GHASH:
711 case GI_TYPE_TAG_ERROR:
712 case GI_TYPE_TAG_INTERFACE:
713 case GI_TYPE_TAG_VOID:
714 case GI_TYPE_TAG_UNICHAR:
715 case GI_TYPE_TAG_GTYPE:
716 //?? i dont know how to handle these yet TODO
717 printf("failed in my lisp to gir arg conversion duties. sob!\n");
718 return -1;
719 break;
720 }
721 return 0;
722 }
723
724 #if 0
725 void
726 refactor_attempt(){
727 //this methhod should be called from xwgir-xwidget-call-method and from xwgir xwidget construction
728 char* class = SDATA(Fcar(Fcdr(Fget(xw->type, QCxwgir_class))));
729
730 GIObjectInfo* obj_info = g_irepository_find_by_name(girepository, namespace, class);
731 GIFunctionInfo* f_info = g_object_info_find_method (obj_info, SDATA(method));
732
733 //loop over args, convert from lisp to primitive type, given arg introspection data
734 //TODO g_callable_info_get_n_args(f_info) should match
735 int argscount = XFASTINT(Flength(arguments));
736 if(argscount != g_callable_info_get_n_args(f_info)){
737 printf("xwgir call method arg count doesn match! \n");
738 return Qnil;
739 }
740 int i;
741 for (i = 1; i < argscount + 1; ++i)
742 {
743 xwgir_convert_lisp_to_gir_arg(&in_args[i], g_callable_info_get_arg(f_info, i - 1), Fnth(i - 1, arguments));
744 }
745
746 in_args[0].v_pointer = widget;
747 if(g_function_info_invoke(f_info,
748 in_args, argscount + 1,
749 NULL, 0,
750 &return_value,
751 &error)) {
752 //g_error("ERROR: %s\n", error->message);
753 printf("invokation error\n");
754 return Qnil;
755 }
756 return Qt;
757 }
758 #endif /* 0 */
759
760 DEFUN ("xwgir-xwidget-call-method", Fxwgir_xwidget_call_method, Sxwgir_xwidget_call_method, 3, 3, 0,
761 doc: /* Call Xwidget object method using GObject Introspection.
762 XWIDGET is the xwidget instance to act upon.
763 METHOD is the Gobject intrsopsection method name.
764 ARGUMENTS is a list of arguments for the call. They will be converted to GObject types from Lisp types.
765 */)
766 (Lisp_Object xwidget, Lisp_Object method, Lisp_Object arguments)
767 {
768 CHECK_XWIDGET (xwidget);
769 GError *error = NULL;
770 GIArgument return_value;
771 GIArgument in_args[20];
772
773
774 struct xwidget* xw;
775 if (NILP (xwidget)) { printf("ERROR xwidget nil\n"); return Qnil; };
776 xw = XXWIDGET(xwidget);
777 if(NULL == xw) printf("ERROR xw is 0\n");
778 char* namespace = SDATA(Fcar(Fget(xw->type, QCxwgir_class)));
779 //we need the concrete widget, which happens in 2 ways depending on OSR or not TODO
780 GtkWidget* widget = NULL;
781 if(NULL == xw->widget_osr) {
782 widget = xwidget_view_lookup (xw, XWINDOW(FRAME_SELECTED_WINDOW (SELECTED_FRAME ()))) -> widget;
783 } else {
784 widget = xw->widget_osr;
785 }
786
787 //char* class = SDATA(SYMBOL_NAME(xw->type)); //this works but is unflexible
788 //figure out the class from the widget instead
789 /* printf("type class: %s %s\n", G_OBJECT_TYPE_NAME(widget), G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(widget))); */
790 /* char* class = G_OBJECT_TYPE_NAME(widget); //gives "GtkButton"(I want "Button") */
791 /* class += strlen(namespace); //TODO check for corresponding api method. but this seems to work. */
792
793 char* class = SDATA(Fcar(Fcdr(Fget(xw->type, QCxwgir_class))));
794
795 GIObjectInfo* obj_info = g_irepository_find_by_name(girepository, namespace, class);
796 GIFunctionInfo* f_info = g_object_info_find_method (obj_info, SDATA(method));
797
798 //loop over args, convert from lisp to primitive type, given arg introspection data
799 //TODO g_callable_info_get_n_args(f_info) should match
800 int argscount = XFASTINT(Flength(arguments));
801 if(argscount != g_callable_info_get_n_args(f_info)){
802 printf("xwgir call method arg count doesn match! \n");
803 return Qnil;
804 }
805 int i;
806 Lisp_Object n;
807 for (i = 1; i < argscount + 1; ++i)
808 {
809 XSETFASTINT (n, i - 1);
810 xwgir_convert_lisp_to_gir_arg(&in_args[i], g_callable_info_get_arg(f_info, i - 1), Fnth(n, arguments));
811 }
812
813 in_args[0].v_pointer = widget;
814 if(g_function_info_invoke(f_info,
815 in_args, argscount + 1,
816 NULL, 0,
817 &return_value,
818 &error)) {
819 //g_error("ERROR: %s\n", error->message);
820 printf("invokation error\n");
821 return Qnil;
822 }
823 return Qt;
824 }
825
826 void
827 to_child (GtkWidget *bin,
828 double widget_x,
829 double widget_y,
830 double *x_out,
831 double *y_out)
832 {
833 *x_out = widget_x;
834 *y_out = widget_y;
835 }
836
837
838 GdkWindow *
839 offscreen_pick_embedded_child (GdkWindow *window,
840 double x,
841 double y,
842 gpointer *data)
843 {
844 //in this simple case we assume the window contains a single widget. easy.
845 //but then we get the problem that the widget cant be embedded in several windows
846 return gtk_widget_get_window (GTK_WIDGET (data));
847 }
848
849 void
850 offscreen_to_embedder (GdkWindow *window,
851 gdouble offscreen_x,
852 gdouble offscreen_y,
853 gpointer embedder_x,
854 gpointer embedder_y,
855 gpointer data)
856 {
857 * (gdouble *) embedder_x = offscreen_x;
858 * (gdouble *) embedder_y = offscreen_y;
859 }
860
861 void
862 offscreen_from_embedder (GdkWindow *window,
863 gdouble embedder_x,
864 gdouble embedder_y,
865 gpointer offscreen_x,
866 gpointer offscreen_y,
867 gpointer user_data)
868 {
869 * (gdouble *) offscreen_x = embedder_x;
870 * (gdouble *) offscreen_y = embedder_y;
871 }
872
873 gboolean
874 xwidget_osr_event_set_embedder (GtkWidget *widget,
875 GdkEvent *event,
876 gpointer data)
877 {
878 struct xwidget_view *xv = (struct xwidget_view *) data;
879 struct xwidget *xww = XXWIDGET (xv->model);
880 printf("gdk_offscreen_window_set_embedder %d %d\n",
881 GDK_IS_WINDOW(gtk_widget_get_window (xww->widget_osr)),
882 GDK_IS_WINDOW(gtk_widget_get_window (GTK_WIDGET (xv->widget))));
883 gdk_offscreen_window_set_embedder (gtk_widget_get_window (xww->widgetwindow_osr),
884 gtk_widget_get_window (xv->widget));
885 }
886
887
888 /* initializes and does initial placement of an xwidget view on screen */
889 struct xwidget_view*
890 xwidget_init_view (struct xwidget *xww,
891 struct glyph_string *s,
892 int x, int y)
893 {
894 struct xwidget_view *xv = allocate_xwidget_view();
895 Lisp_Object val;
896 GdkColor color;
897
898 XSETXWIDGET_VIEW (val, xv) ;
899 Vxwidget_view_list = Fcons (val, Vxwidget_view_list);
900
901 XSETWINDOW(xv->w, s->w);
902 XSETXWIDGET(xv->model, xww);
903
904 //widget creation
905 if(EQ(xww->type, Qbutton))
906 {
907 xv->widget = gtk_button_new_with_label (XSTRING(xww->title)->data);
908 g_signal_connect (G_OBJECT (xv->widget), "clicked",
909 G_CALLBACK (buttonclick_handler), xv); // the view rather than the model
910 } else if (EQ(xww->type, Qtoggle)) {
911 xv->widget = gtk_toggle_button_new_with_label (XSTRING(xww->title)->data);
912 //xv->widget = gtk_entry_new ();//temp hack to experiment with key propagation TODO entry widget is useful for testing
913 } else if (EQ(xww->type, Qsocket)) {
914 xv->widget = gtk_socket_new ();
915 g_signal_connect_after(xv->widget, "plug-added", G_CALLBACK(xwidget_plug_added), "plug added");
916 g_signal_connect_after(xv->widget, "plug-removed", G_CALLBACK(xwidget_plug_removed), "plug removed");
917 //TODO these doesnt help
918 gtk_widget_add_events(xv->widget, GDK_KEY_PRESS);
919 gtk_widget_add_events(xv->widget, GDK_KEY_RELEASE);
920 } else if (EQ(xww->type, Qslider)) {
921 xv->widget =
922 //gtk_hscale_new (GTK_ADJUSTMENT(gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 10.0, 10.0)));
923 gtk_hscale_new_with_range ( 0.0, 100.0, 10.0);
924 gtk_scale_set_draw_value (GTK_SCALE (xv->widget), FALSE); //i think its emacs role to show text and stuff, so disable the widgets own text
925 xv->handler_id = g_signal_connect_after(xv->widget, "value-changed", G_CALLBACK(xwidget_slider_changed), "slider changed");
926 } else if (EQ(xww->type, Qcairo)) {
927 //Cairo view
928 //uhm cairo is differentish in gtk 3.
929 //gdk_cairo_create (gtk_widget_get_window (FRAME_GTK_WIDGET (s->f)));
930 xv->widget = gtk_drawing_area_new();
931 g_signal_connect (G_OBJECT ( xv->widget), "draw",
932 G_CALLBACK (xwidget_osr_draw_callback), NULL);
933
934 } else if (EQ(xww->type, Qwebkit_osr)||
935 EQ(xww->type, Qsocket_osr)||
936 (!NILP (Fget(xww->type, QCxwgir_class))))//xwgir widgets are OSR
937 {
938 printf("osr init:%s\n",SDATA(SYMBOL_NAME(xww->type)));
939 xv->widget = gtk_drawing_area_new();
940 gtk_widget_set_app_paintable ( xv->widget, TRUE); //because expose event handling
941 gtk_widget_add_events(xv->widget, GDK_ALL_EVENTS_MASK);
942
943 /* Draw the view on damage-event */
944 g_signal_connect (G_OBJECT (xww->widgetwindow_osr), "damage-event",
945 G_CALLBACK (offscreen_damage_event), xv->widget);
946
947 if (EQ(xww->type, Qwebkit_osr)){
948 /* ///xwgir debug */
949 /* //forward events. this isnt compatible with the set_embedded strategy */
950 g_signal_connect (G_OBJECT ( xv->widget), "button-press-event",
951 G_CALLBACK (xwidget_osr_event_forward), NULL);
952 g_signal_connect (G_OBJECT ( xv->widget), "button-release-event",
953 G_CALLBACK (xwidget_osr_event_forward), NULL);
954 g_signal_connect (G_OBJECT ( xv->widget), "motion-notify-event",
955 G_CALLBACK (xwidget_osr_event_forward), NULL);
956 }else{
957 //xwgir debug , orthogonal to forwarding
958 g_signal_connect (G_OBJECT (xv->widget), "enter-notify-event",
959 G_CALLBACK (xwidget_osr_event_set_embedder), xv);
960 }
961
962 //draw
963 g_signal_connect (G_OBJECT (xv->widget), "draw",
964 G_CALLBACK (xwidget_osr_draw_callback), NULL);
965
966 }
967 //else return NULL;
968
969 //widget realization
970 //make container widget 1st, and put the actual widget inside the container
971 //later, drawing should crop container window if necessary to handle case where xwidget
972 //is partially obscured by other emacs windows
973 //other containers than gtk_fixed where explored, but gtk_fixed had the most predictable behaviour so far.
974 xv->emacswindow = FRAME_GTK_WIDGET (s->f);
975 xv->widgetwindow = gtk_fixed_new ();
976 gtk_widget_set_has_window(xv->widgetwindow, TRUE);
977 gtk_container_add (GTK_CONTAINER (xv->widgetwindow), xv->widget);
978
979 //store some xwidget data in the gtk widgets
980 g_object_set_data (G_OBJECT (xv->widget), XG_FRAME_DATA, (gpointer) (s->f)); //the emacs frame
981 g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET, (gpointer) (xww)); //the xwidget
982 g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET_VIEW, (gpointer) (xv)); //the xwidget
983 g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET, (gpointer) (xww)); //the xwidget window
984 g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET_VIEW, (gpointer) (xv)); //the xwidget window
985
986
987 gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xww->width, xww->height);
988 gtk_widget_set_size_request (xv->widgetwindow, xww->width, xww->height);
989 gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), xv->widgetwindow, x, y);
990 xv->x = x; xv->y = y;
991 gtk_widget_show_all (xv->widgetwindow);
992
993
994
995 //widgettype specific initialization only possible after realization
996 if (EQ(xww->type, Qsocket)) {
997 printf ("xwid:%d socket id:%x %d\n",
998 xww,
999 gtk_socket_get_id (GTK_SOCKET (xv->widget)),
1000 gtk_socket_get_id (GTK_SOCKET (xv->widget)));
1001 send_xembed_ready_event (xww,
1002 gtk_socket_get_id (GTK_SOCKET (xv->widget)));
1003 //gtk_widget_realize(xw->widget);
1004 }
1005
1006 //////////////////////////////////////////////////////////////
1007 // xwgir debug
1008 if (//EQ(xww->type, Qwebkit_osr)|| //TODO should be able to choose compile time which method to use with webkit
1009 EQ(xww->type, Qsocket_osr)||
1010 (!NILP (Fget(xww->type, QCxwgir_class))))//xwgir widgets are OSR
1011 {
1012 printf("gdk_offscreen_window_set_embedder %d %d\n",
1013 GDK_IS_WINDOW(gtk_widget_get_window (xww->widget_osr)),
1014 GDK_IS_WINDOW(gtk_widget_get_window (GTK_WIDGET (xv->widget))));
1015 // set_embedder needs to be called after xv->widget realization
1016 gdk_offscreen_window_set_embedder (gtk_widget_get_window (xww->widgetwindow_osr),
1017 gtk_widget_get_window (xv->widget));
1018 g_signal_connect (gtk_widget_get_window (xv->widget), "pick-embedded-child",
1019 G_CALLBACK (offscreen_pick_embedded_child), xww->widgetwindow_osr);
1020
1021 g_signal_connect (gtk_widget_get_window (xww->widgetwindow_osr), "from-embedder",
1022 G_CALLBACK (offscreen_from_embedder), NULL);
1023 g_signal_connect (gtk_widget_get_window (xww->widgetwindow_osr), "to-embedder",
1024 G_CALLBACK (offscreen_to_embedder), NULL);
1025 }
1026 ////////////////////////////////////////
1027
1028 return xv;
1029 }
1030
1031
1032 void
1033 x_draw_xwidget_glyph_string (struct glyph_string *s)
1034 {
1035 /*
1036 this method is called by the redisplay engine and places the xwidget on screen.
1037 moving and clipping is done here. also view init.
1038
1039 */
1040 int box_line_hwidth = eabs (s->face->box_line_width);
1041 int box_line_vwidth = max (s->face->box_line_width, 0);
1042 int height = s->height;
1043 struct xwidget *xww = s->xwidget;
1044 struct xwidget_view *xv = xwidget_view_lookup(xww, s->w);
1045 int clip_right; int clip_bottom; int clip_top; int clip_left;
1046
1047 int x = s->x;
1048 int y = s->y + (s->height / 2) - (xww->height / 2);
1049 int moved=0;
1050
1051 /* We do it here in the display loop because there is no other
1052 time to know things like window placement etc.
1053 */
1054 printf ("xv init for xw %d\n", xww);
1055 xv = xwidget_init_view (xww, s, x, y);
1056
1057 //calculate clipping, which is used for all manner of onscreen xwidget views
1058 //each widget border can get clipped by other emacs objects so there are four clipping variables
1059 clip_right = min (xww->width, WINDOW_RIGHT_EDGE_X (s->w) - x - WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH(s->w) - WINDOW_RIGHT_FRINGE_WIDTH(s->w));
1060 clip_left = max (0, WINDOW_LEFT_EDGE_X (s->w) - x + WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH(s->w) + WINDOW_LEFT_FRINGE_WIDTH(s->w));
1061
1062 clip_bottom = min (xww->height, WINDOW_BOTTOM_EDGE_Y (s->w) - WINDOW_MODE_LINE_HEIGHT (s->w) - y);
1063 clip_top = max(0, WINDOW_TOP_EDGE_Y(s->w) -y );
1064
1065 //we are conserned with movement of the onscreen area. the area might sit still when the widget actually moves
1066 //this happens when an emacs window border moves across a widget window
1067 //so, if any corner of the outer widget clippng window moves, that counts as movement here, even
1068 //if it looks like no movement happens because the widget sits still inside the clipping area.
1069 //the widget can also move inside the clipping area, which happens later
1070 moved = (xv->x + xv->clip_left != x+clip_left)
1071 || ((xv->y + xv->clip_top)!= (y+clip_top));
1072 if(moved) printf ("lxwidget moved: id:%d (%d,%d)->(%d,%d) y+clip_top:%d\n", xww, xv->x, xv->y, x, y, y + clip_top);
1073 else
1074 printf ("lxwidget DIDNT move: id:%d (%d,%d)->(%d,%d) y+clip_top:%d\n", xww, xv->x, xv->y, x, y, y + clip_top);
1075 xv->x = x;
1076 xv->y = y;
1077 if (moved) //has it moved?
1078 {
1079 if (1)//!xwidget_hidden(xv)) //hidden equals not being seen during redisplay
1080 {
1081 //TODO should be possible to use xwidget_show_view here
1082 gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)),
1083 xv->widgetwindow,
1084 x + clip_left, y + clip_top);
1085 }
1086 }
1087 //clip the widget window if some parts happen to be outside drawable area
1088 //an emacs window is not a gtk window, a gtk window covers the entire frame
1089 //cliping might have changed even if we havent actualy moved, we try figure out when we need to reclip for real
1090 if((xv->clip_right != clip_right)
1091 || (xv->clip_bottom != clip_bottom)
1092 || (xv->clip_top != clip_top)
1093 || (xv->clip_left != clip_left)){
1094 gtk_widget_set_size_request (xv->widgetwindow, clip_right + clip_left, clip_bottom + clip_top);
1095 gtk_fixed_move(GTK_FIXED(xv->widgetwindow), xv->widget, -clip_left, -clip_top);
1096 printf("reclip %d %d -> %d %d clip_top:%d clip_left:%d\n",xv->clip_right, xv->clip_bottom, clip_right, clip_bottom, clip_top , clip_left);
1097
1098
1099 xv->clip_right = clip_right; xv->clip_bottom = clip_bottom; xv->clip_top = clip_top;xv->clip_left = clip_left;
1100 }
1101 //if emacs wants to repaint the area where the widget lives, queue a redraw
1102 //TODO it seems its possible to get out of sync with emacs redraws so emacs bg sometimes shows up instead of xwidget
1103 //its just a visual glitch though
1104 if (!xwidget_hidden(xv)){
1105 gtk_widget_queue_draw (xv->widgetwindow);
1106 gtk_widget_queue_draw (xv->widget);
1107 }
1108 }
1109
1110
1111 #ifdef HAVE_WEBKIT_OSR
1112
1113 //FUGLY macro that checks WEBKIT_IS_WEB_VIEW(xw->widget_osr) first
1114 #define WEBKIT_FN_INIT() \
1115 struct xwidget* xw; \
1116 CHECK_XWIDGET (xwidget); \
1117 if(NILP (xwidget)) {printf("ERROR xwidget nil\n"); return Qnil;}; \
1118 xw = XXWIDGET(xwidget); \
1119 if(NULL == xw) printf("ERROR xw is 0\n"); \
1120 if((NULL == xw->widget_osr) || !WEBKIT_IS_WEB_VIEW(xw->widget_osr)){ \
1121 printf("ERROR xw->widget_osr does not hold a webkit instance\n");\
1122 return Qnil;\
1123 };
1124
1125
1126 DEFUN ("xwidget-webkit-goto-uri", Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri,
1127 2, 2, 0,
1128 doc: /* Make the webkit instance referenced by XWIDGET browse URI. */)
1129 (Lisp_Object xwidget, Lisp_Object uri)
1130 {
1131 WEBKIT_FN_INIT();
1132 webkit_web_view_load_uri ( WEBKIT_WEB_VIEW(xw->widget_osr), SDATA(uri));
1133 return Qnil;
1134 }
1135
1136
1137 DEFUN ("xwidget-webkit-execute-script", Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script,
1138 2, 2, 0,
1139 doc: /* webkit exec js.*/)
1140 (Lisp_Object xwidget, Lisp_Object script)
1141 {
1142 WEBKIT_FN_INIT();
1143 webkit_web_view_execute_script( WEBKIT_WEB_VIEW(xw->widget_osr), SDATA(script));
1144 return Qnil;
1145 }
1146
1147 DEFUN ("xwidget-webkit-get-title", Fxwidget_webkit_get_title, Sxwidget_webkit_get_title,
1148 1, 1, 0,
1149 doc: /* Get the title from the Webkit instance in XWIDGET.
1150 This can be used to work around the lack of a return value from the exec method.
1151 */)
1152 (Lisp_Object xwidget)
1153 {
1154 //TODO support multibyte strings
1155 WEBKIT_FN_INIT();
1156 const gchar* str=webkit_web_view_get_title( WEBKIT_WEB_VIEW(xw->widget_osr));
1157 //return make_string_from_bytes(str, wcslen((const wchar_t *)str), strlen(str));
1158 if(str == 0){
1159 //TODO maybe return Qnil instead. I suppose webkit returns nullpointer when doc is not properly loaded or something
1160 printf("xwidget-webkit-get-title null webkit title\n");
1161 return build_string("");
1162 }
1163 return build_string(str);
1164 }
1165
1166 //TODO missnamed
1167 DEFUN("xwidget-disable-plugin-for-mime", Fxwidget_disable_plugin_for_mime , Sxwidget_disable_plugin_for_mime,
1168 1,1,0, doc: /* */)
1169 (Lisp_Object mime)
1170 {
1171 WebKitWebPlugin *wp = webkit_web_plugin_database_get_plugin_for_mimetype
1172 (webkit_get_web_plugin_database(), SDATA(mime));
1173 if(wp == NULL) return Qnil;
1174 if(webkit_web_plugin_get_enabled (wp)){
1175 webkit_web_plugin_set_enabled (wp, FALSE);
1176 return Qt;
1177 }
1178 return Qnil;
1179 }
1180
1181
1182 void
1183 xwidget_webkit_dom_dump(WebKitDOMNode* parent)
1184 {
1185 WebKitDOMNodeList* list;
1186 int i;
1187 int length;
1188 WebKitDOMNode* attribute;
1189 WebKitDOMNamedNodeMap* attrs;
1190 WebKitDOMNode* child;
1191 printf("node:%d type:%d name:%s content:%s\n",
1192 parent,
1193 webkit_dom_node_get_node_type(parent),//1 element 3 text 8 comment 2 attribute
1194 webkit_dom_node_get_local_name(parent),
1195 webkit_dom_node_get_text_content(parent));
1196
1197 if(webkit_dom_node_has_attributes(parent)){
1198 attrs = webkit_dom_node_get_attributes(parent);
1199
1200 length = webkit_dom_named_node_map_get_length(attrs);
1201 for (int i = 0; i < length; i++) {
1202 attribute = webkit_dom_named_node_map_item(attrs,i);
1203 printf(" attr node:%d type:%d name:%s content:%s\n",
1204 attribute,
1205 webkit_dom_node_get_node_type(attribute),//1 element 3 text 8 comment
1206 webkit_dom_node_get_local_name(attribute),
1207 webkit_dom_node_get_text_content(attribute));
1208 }
1209 }
1210 list = webkit_dom_node_get_child_nodes(parent);
1211 length = webkit_dom_node_list_get_length(list);
1212
1213 for (int i = 0; i < length; i++) {
1214 child = webkit_dom_node_list_item(list, i);
1215 //if(webkit_dom_node_has_child_nodes(child))
1216 xwidget_webkit_dom_dump(child);
1217 }
1218 }
1219
1220
1221 DEFUN ("xwidget-webkit-dom-dump", Fxwidget_webkit_dom_dump, Sxwidget_webkit_dom_dump,
1222 1, 1, 0,
1223 doc: /*Dump the DOM contained in the webkit instance in XWIDGET.*/)
1224 (Lisp_Object xwidget)
1225 {
1226 WEBKIT_FN_INIT();
1227 xwidget_webkit_dom_dump(WEBKIT_DOM_NODE(webkit_web_view_get_dom_document( WEBKIT_WEB_VIEW(xw->widget_osr))));
1228 return Qnil;
1229 }
1230
1231
1232
1233 #endif /* HAVE_WEBKIT_OSR */
1234
1235
1236
1237
1238
1239 DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0, doc:
1240 /* Resize XWIDGET.
1241 NEW_WIDTH NEW_HEIGHT defines the new size.)
1242 */)
1243 (Lisp_Object xwidget, Lisp_Object new_width, Lisp_Object new_height)
1244 {
1245 CHECK_XWIDGET (xwidget);
1246 struct xwidget* xw = XXWIDGET(xwidget);
1247 struct xwidget_view *xv;
1248 int w, h;
1249
1250 CHECK_NUMBER (new_width);
1251 CHECK_NUMBER (new_height);
1252 w = XFASTINT (new_width);
1253 h = XFASTINT (new_height);
1254
1255
1256 printf("resize xwidget %d (%d,%d)->(%d,%d)\n",xw, xw->width,xw->height,w,h);
1257 xw->width=w;
1258 xw->height=h;
1259 //if theres a osr resize it 1st
1260 if(xw->widget_osr){
1261 printf("resize xwidget_osr\n");
1262 //gtk_container_set_resize_mode ( GTK_WINDOW(xw->widgetwindow_osr), GTK_RESIZE_QUEUE);
1263 //gtk_container_set_resize_mode ( GTK_WINDOW(xw->widget_osr), GTK_RESIZE_QUEUE);
1264
1265
1266 //gtk_layout_set_size (GTK_LAYOUT (xw->widgetwindow_osr), xw->width, xw->height);
1267 gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height); //minimum size
1268 //gtk_window_resize( GTK_WINDOW(xw->widget_osr), xw->width, xw->height);
1269 gtk_window_resize( GTK_WINDOW(xw->widgetwindow_osr), xw->width, xw->height);
1270 //gtk_container_resize_children ( GTK_WINDOW(xw->widgetwindow_osr));
1271 gtk_container_resize_children (GTK_CONTAINER(xw->widgetwindow_osr));
1272
1273 }
1274
1275 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail)) //TODO MVC refactor lazy linear search
1276 {
1277 if (XWIDGET_VIEW_P (XCAR (tail))) {
1278 xv = XXWIDGET_VIEW (XCAR (tail));
1279 if(XXWIDGET (xv->model) == xw) {
1280 gtk_layout_set_size (GTK_LAYOUT (xv->widgetwindow), xw->width, xw->height);
1281 gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width, xw->height);
1282 }
1283 }
1284 }
1285
1286 return Qnil;
1287 }
1288
1289 DEFUN ("xwidget-size-request", Fxwidget_size_request, Sxwidget_size_request, 1, 1, 0, doc:
1290 - /* Desired size of the XWIDGET.
1291
1292 This can be used to read the xwidget desired size, and resizes the Emacs allocated area accordingly.
1293
1294 (TODO crashes if arg not osr widget)*/)
1295 (Lisp_Object xwidget)
1296 {
1297 CHECK_XWIDGET (xwidget);
1298 GtkRequisition requisition;
1299 Lisp_Object rv;
1300 gtk_widget_size_request(XXWIDGET(xwidget)->widget_osr, &requisition);
1301 rv = Qnil;
1302 rv = Fcons (make_number(requisition.height), rv);
1303 rv = Fcons (make_number(requisition.width), rv);
1304 return rv;
1305
1306 }
1307
1308 DEFUN ("xwidgetp", Fxwidgetp, Sxwidgetp, 1, 1, 0,
1309 doc: /* Return t if OBJECT is a xwidget. */)
1310 (Lisp_Object object)
1311 {
1312 return XWIDGETP (object) ? Qt : Qnil;
1313 }
1314
1315 DEFUN ("xwidget-view-p", Fxwidget_view_p, Sxwidget_view_p, 1, 1, 0,
1316 doc: /* Return t if OBJECT is a xwidget-view. */)
1317 (Lisp_Object object)
1318 {
1319 return XWIDGET_VIEW_P (object) ? Qt : Qnil;
1320 }
1321
1322 DEFUN ("xwidget-info", Fxwidget_info , Sxwidget_info, 1,1,0,
1323 doc: /* Get XWIDGET properties.
1324 Currently type, title, width, height.*/)
1325 (Lisp_Object xwidget)
1326 {
1327 CHECK_XWIDGET (xwidget);
1328 Lisp_Object info, n;
1329 struct xwidget* xw = XXWIDGET(xwidget);
1330
1331 info = Fmake_vector (make_number (4), Qnil);
1332 ASET (info, 0, xw->type);
1333 ASET (info, 1, xw->title);
1334 XSETFASTINT(n, xw->width);
1335 ASET (info, 2, n);
1336 XSETFASTINT(n, xw->height);
1337 ASET (info, 3, n);
1338
1339 return info;
1340 }
1341
1342 DEFUN ("xwidget-view-info", Fxwidget_view_info , Sxwidget_view_info, 1, 1, 0, doc:
1343 /* Get XWIDGET-VIEW properties.
1344 Currently x,y clip right, clip bottom, clip top, clip left*/)
1345 (Lisp_Object xwidget_view)
1346 {
1347 CHECK_XWIDGET_VIEW (xwidget_view);
1348 struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
1349 Lisp_Object info;
1350
1351 info = Fmake_vector (make_number (6), Qnil);
1352 ASET (info, 0, make_number(xv->x));
1353 ASET (info, 1, make_number(xv->y));
1354 ASET (info, 2, make_number(xv->clip_right));
1355 ASET (info, 3, make_number(xv->clip_bottom));
1356 ASET (info, 4, make_number(xv->clip_top));
1357 ASET (info, 5, make_number(xv->clip_left));
1358
1359 return info;
1360 }
1361
1362 DEFUN ("xwidget-view-model", Fxwidget_view_model, Sxwidget_view_model,
1363 1, 1, 0,
1364 doc: /* Get XWIDGET-VIEW model. */)
1365 (Lisp_Object xwidget_view)
1366 {
1367 CHECK_XWIDGET_VIEW (xwidget_view);
1368 return XXWIDGET_VIEW (xwidget_view)->model;
1369 }
1370
1371 DEFUN ("xwidget-view-window", Fxwidget_view_window, Sxwidget_view_window,
1372 1, 1, 0,
1373 doc: /* Get XWIDGET-VIEW window. */)
1374 (Lisp_Object xwidget_view)
1375 {
1376 CHECK_XWIDGET_VIEW (xwidget_view);
1377 return XXWIDGET_VIEW (xwidget_view)->w;
1378 }
1379
1380 DEFUN ("xwidget-send-keyboard-event", Fxwidget_send_keyboard_event, Sxwidget_send_keyboard_event, 2, 2, 0,
1381 doc:/* Synthesize a kbd event for XWIDGET. TODO crashes atm.. */
1382 )
1383 (Lisp_Object xwidget, Lisp_Object keydescriptor)
1384 {
1385 //TODO this code crashes for offscreen widgets and ive tried many different strategies
1386 //int keyval = 0x058; //X
1387 int keyval = XFASTINT(keydescriptor); //X
1388 char *keystring = "";
1389 GdkKeymapKey* keys;
1390 gint n_keys;
1391 GdkDeviceManager* manager;
1392 struct xwidget *xw;
1393 GtkWidget* widget;
1394 GdkEventKey* ev;
1395 Lisp_Object window;
1396 //popup_activated_flag = 1; //TODO just a hack
1397 gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), keyval, &keys, &n_keys);
1398
1399 xw = XXWIDGET(xwidget);
1400
1401 ev = (GdkEventKey*)gdk_event_new(GDK_KEY_PRESS);
1402
1403
1404 //todo what about windowless widgets?
1405
1406 window = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
1407
1408
1409 //TODO maybe we also need to special case sockets by picking up the plug rather than the socket
1410 if(xw->widget_osr)
1411 widget = xw->widget_osr;
1412 else
1413 widget = xwidget_view_lookup(xw, XWINDOW(window))->widget;
1414
1415 ev->window = gtk_widget_get_window(widget);
1416 gtk_widget_grab_focus(widget);
1417 ev->send_event = FALSE;
1418
1419 ev->hardware_keycode = keys[0].keycode;
1420 ev->group = keys[0].group;
1421
1422 ev->keyval = keyval;
1423 ev->time = GDK_CURRENT_TIME;
1424
1425 //ev->device = gdk_device_get_core_pointer();
1426 manager = gdk_display_get_device_manager(gdk_window_get_display(ev->window));
1427 gdk_event_set_device ((GdkEvent*)ev, gdk_device_manager_get_client_pointer(manager));
1428 gdk_event_put((GdkEvent*)ev);
1429 //g_signal_emit_by_name(ev->window,"key-press-event", ev);
1430
1431 ev->type = GDK_KEY_RELEASE;
1432 gdk_event_put((GdkEvent*)ev);
1433 //g_signal_emit_by_name(ev->window,"key-release-event", ev);
1434 //gtk_main_do_event(ev);
1435
1436 //TODO
1437 //if I delete the event the receiving component eventually crashes.
1438 //it ough TDTRT since event_put is supposed to copy the event
1439 //so probably this leaks events now
1440 //gdk_event_free((GdkEvent*)ev);
1441
1442 return Qnil;
1443 }
1444
1445 DEFUN ("delete-xwidget-view", Fdelete_xwidget_view, Sdelete_xwidget_view,
1446 1, 1, 0,
1447 doc: /* Delete the XWIDGET-VIEW. */)
1448 (Lisp_Object xwidget_view)
1449 {
1450 CHECK_XWIDGET_VIEW (xwidget_view);
1451 struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
1452 gtk_widget_destroy(xv->widgetwindow);
1453 Vxwidget_view_list = Fdelq (xwidget_view, Vxwidget_view_list);
1454 }
1455
1456 DEFUN ("xwidget-view-lookup", Fxwidget_view_lookup, Sxwidget_view_lookup,
1457 1, 2, 0,
1458 doc: /* Return the xwidget-view associated to XWIDGET in
1459 WINDOW if specified, otherwise it uses the selected window. */)
1460 (Lisp_Object xwidget, Lisp_Object window)
1461 {
1462 CHECK_XWIDGET (xwidget);
1463
1464 if (NILP (window))
1465 window = Fselected_window();
1466 CHECK_WINDOW (window);
1467
1468 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
1469 {
1470 Lisp_Object xwidget_view = XCAR (tail);
1471 if (EQ (Fxwidget_view_model (xwidget_view), xwidget)
1472 && EQ (Fxwidget_view_window (xwidget_view), window))
1473 return xwidget_view;
1474 }
1475
1476 return Qnil;
1477 }
1478
1479 DEFUN ("set-frame-visible", Fset_frame_visible, Sset_frame_visible,
1480 2, 2, 0,
1481 doc: /* HACKY */)
1482 (Lisp_Object frame, Lisp_Object flag)
1483 {
1484 CHECK_FRAME (frame);
1485 struct frame *f = XFRAME (frame);
1486 SET_FRAME_VISIBLE (f, !NILP (flag));
1487 return flag;
1488 }
1489
1490 DEFUN ("xwidget-plist", Fxwidget_plist, Sxwidget_plist,
1491 1, 1, 0,
1492 doc: /* Return the plist of XWIDGET. */)
1493 (register Lisp_Object xwidget)
1494 {
1495 CHECK_XWIDGET (xwidget);
1496 return XXWIDGET (xwidget)->plist;
1497 }
1498
1499 DEFUN ("xwidget-buffer", Fxwidget_buffer, Sxwidget_buffer,
1500 1, 1, 0,
1501 doc: /* Return the buffer of XWIDGET. */)
1502 (register Lisp_Object xwidget)
1503 {
1504 CHECK_XWIDGET (xwidget);
1505 return XXWIDGET (xwidget)->buffer;
1506 }
1507
1508 DEFUN ("set-xwidget-plist", Fset_xwidget_plist, Sset_xwidget_plist,
1509 2, 2, 0,
1510 doc: /* Replace the plist of XWIDGET with PLIST. Returns PLIST. */)
1511 (register Lisp_Object xwidget, Lisp_Object plist)
1512 {
1513 CHECK_XWIDGET (xwidget);
1514 CHECK_LIST (plist);
1515
1516 XXWIDGET (xwidget)->plist = plist;
1517 return plist;
1518 }
1519
1520 DEFUN ("set-xwidget-query-on-exit-flag",
1521 Fset_xwidget_query_on_exit_flag, Sset_xwidget_query_on_exit_flag,
1522 2, 2, 0,
1523 doc: /* Specify if query is needed for XWIDGET when Emacs is
1524 exited. If the second argument FLAG is non-nil, Emacs will query the
1525 user before exiting or killing a buffer if XWIDGET is running. This
1526 function returns FLAG. */)
1527 (Lisp_Object xwidget, Lisp_Object flag)
1528 {
1529 CHECK_XWIDGET (xwidget);
1530 XXWIDGET (xwidget)->kill_without_query = NILP (flag);
1531 return flag;
1532 }
1533
1534 DEFUN ("xwidget-query-on-exit-flag",
1535 Fxwidget_query_on_exit_flag, Sxwidget_query_on_exit_flag,
1536 1, 1, 0,
1537 doc: /* Return the current value of query-on-exit flag for XWIDGET. */)
1538 (Lisp_Object xwidget)
1539 {
1540 CHECK_XWIDGET (xwidget);
1541 return (XXWIDGET (xwidget)->kill_without_query ? Qnil : Qt);
1542 }
1543
1544 void
1545 syms_of_xwidget (void)
1546 {
1547 int i;
1548
1549 defsubr (&Smake_xwidget);
1550 defsubr (&Sxwidgetp);
1551 DEFSYM (Qxwidgetp, "xwidgetp");
1552 defsubr (&Sxwidget_view_p);
1553 DEFSYM (Qxwidget_view_p, "xwidget-view-p");
1554 defsubr (&Sxwidget_info);
1555 defsubr (&Sxwidget_view_info);
1556 defsubr (&Sxwidget_resize);
1557 defsubr (&Sget_buffer_xwidgets);
1558 defsubr (&Sxwidget_view_model);
1559 defsubr (&Sxwidget_view_window);
1560 defsubr (&Sxwidget_view_lookup);
1561 defsubr (&Sxwidget_query_on_exit_flag);
1562 defsubr (&Sset_xwidget_query_on_exit_flag);
1563 defsubr (&Sset_frame_visible);
1564
1565 #ifdef HAVE_WEBKIT_OSR
1566 defsubr (&Sxwidget_webkit_goto_uri);
1567 defsubr (&Sxwidget_webkit_execute_script);
1568 defsubr (&Sxwidget_webkit_get_title);
1569 DEFSYM (Qwebkit_osr ,"webkit-osr");
1570 #endif
1571
1572 defsubr (&Sxwgir_xwidget_call_method );
1573 defsubr (&Sxwgir_require_namespace);
1574 defsubr (&Sxwidget_size_request );
1575 defsubr (&Sdelete_xwidget_view);
1576 defsubr (&Sxwidget_disable_plugin_for_mime);
1577
1578 defsubr (&Sxwidget_send_keyboard_event);
1579 defsubr (&Sxwidget_webkit_dom_dump);
1580 defsubr (&Sxwidget_plist);
1581 defsubr (&Sxwidget_buffer);
1582 defsubr (&Sset_xwidget_plist);
1583
1584 DEFSYM (Qxwidget, "xwidget");
1585
1586 DEFSYM (QCxwidget, ":xwidget");
1587 DEFSYM (QCxwgir_class, ":xwgir-class");
1588 DEFSYM (QCtitle, ":title");
1589
1590 /* Do not forget to update the docstring of make-xwidget if you add
1591 new types. */
1592 DEFSYM (Qbutton, "Button"); //changed to match the gtk class because xwgir(experimental and not really needed)
1593 DEFSYM (Qtoggle, "ToggleButton");
1594 DEFSYM (Qslider, "slider");
1595 DEFSYM (Qsocket, "socket");
1596 DEFSYM (Qsocket_osr, "socket-osr");
1597 DEFSYM (Qcairo, "cairo");
1598
1599 DEFSYM (QCplist, ":plist");
1600
1601 DEFVAR_LISP ("xwidget-list", Vxwidget_list, doc: /*xwidgets list*/);
1602 Vxwidget_list = Qnil;
1603
1604 DEFVAR_LISP ("xwidget-view-list", Vxwidget_view_list, doc: /*xwidget views list*/);
1605 Vxwidget_view_list = Qnil;
1606
1607 Fprovide (intern ("xwidget-internal"), Qnil);
1608
1609 }
1610
1611
1612 /* Value is non-zero if OBJECT is a valid Lisp xwidget specification. A
1613 valid xwidget specification is a list whose car is the symbol
1614 `xwidget', and whose rest is a property list. The property list must
1615 contain a value for key `:type'. That value must be the name of a
1616 supported xwidget type. The rest of the property list depends on the
1617 xwidget type. */
1618
1619 int
1620 valid_xwidget_spec_p (Lisp_Object object)
1621 {
1622 int valid_p = 0;
1623
1624 if (CONSP (object) && EQ (XCAR (object), Qxwidget))
1625 {
1626 /* Lisp_Object tem; */
1627
1628 /* for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem)) */
1629 /* if (EQ (XCAR (tem), QCtype)) */
1630 /* { */
1631 /* tem = XCDR (tem); */
1632 /* if (CONSP (tem) && SYMBOLP (XCAR (tem))) */
1633 /* { */
1634 /* struct xwidget_type *type; */
1635 /* type = lookup_xwidget_type (XCAR (tem)); */
1636 /* if (type) */
1637 /* valid_p = type->valid_p (object); */
1638 /* } */
1639
1640 /* break; */
1641 /* } */
1642 //never mind type support for now
1643 valid_p = 1;
1644 }
1645
1646 return valid_p;
1647 }
1648
1649
1650
1651 /* find a value associated with key in spec */
1652 Lisp_Object
1653 xwidget_spec_value ( Lisp_Object spec, Lisp_Object key,
1654 int *found)
1655 {
1656 Lisp_Object tail;
1657
1658 eassert (valid_xwidget_spec_p (spec));
1659
1660 for (tail = XCDR (spec);
1661 CONSP (tail) && CONSP (XCDR (tail)); tail = XCDR (XCDR (tail)))
1662 {
1663 if (EQ (XCAR (tail), key))
1664 {
1665 if (found)
1666 *found = 1;
1667 return XCAR (XCDR (tail));
1668 }
1669 }
1670
1671 if (found)
1672 *found = 0;
1673 return Qnil;
1674 }
1675
1676
1677 void
1678 xwidget_view_delete_all_in_window (struct window *w)
1679 {
1680 struct xwidget_view* xv = NULL;
1681 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
1682 {
1683 if (XWIDGET_VIEW_P (XCAR (tail))) {
1684 xv = XXWIDGET_VIEW (XCAR (tail));
1685 if(XWINDOW (xv->w) == w) {
1686 gtk_widget_destroy(xv->widgetwindow);
1687 Vxwidget_view_list = Fdelq (XCAR (tail), Vxwidget_view_list);
1688 }
1689 }
1690 }
1691 }
1692
1693 struct xwidget_view*
1694 xwidget_view_lookup (struct xwidget* xw, struct window *w)
1695 {
1696 Lisp_Object xwidget, window, ret;
1697 XSETXWIDGET (xwidget, xw);
1698 XSETWINDOW (window, w);
1699
1700 ret = Fxwidget_view_lookup (xwidget, window);
1701
1702 return EQ (ret, Qnil) ? NULL : XXWIDGET_VIEW (ret);
1703 }
1704
1705 struct xwidget*
1706 lookup_xwidget (Lisp_Object spec)
1707 {
1708 /* When a xwidget lisp spec is found initialize the C struct that is used in the C code.
1709 This is done by redisplay so values change if the spec changes.
1710 So, take special care of one-shot events
1711
1712 TODO remove xwidget init from display spec. simply store an xwidget reference only and set
1713 size etc when creating the xwidget, which should happen before insertion into buffer
1714 */
1715 int found = 0, found1 = 0, found2 = 0;
1716 Lisp_Object value;
1717 struct xwidget *xw;
1718
1719 value = xwidget_spec_value (spec, QCxwidget, &found1);
1720 xw = XXWIDGET(value);
1721
1722 /* value = xwidget_spec_value (spec, QCtype, &found); */
1723 /* xw->type = SYMBOLP (value) ? value : Qbutton; //default to button */
1724 /* value = xwidget_spec_value (spec, QCtitle, &found2); */
1725 /* xw->title = STRINGP (value) ? (char *) SDATA (value) : "?"; //funky cast FIXME TODO */
1726
1727 /* value = xwidget_spec_value (spec, QCheight, NULL); */
1728 /* xw->height = INTEGERP (value) ? XFASTINT (value) : 50; */
1729 /* value = xwidget_spec_value (spec, QCwidth, NULL); */
1730 /* xw->width = INTEGERP (value) ? XFASTINT (value) : 50; */
1731
1732 /* value = xwidget_spec_value (spec, QCplist, NULL); */
1733 /* xw->plist = value; */
1734 /* coordinates are not known here */
1735 printf ("lookup_xwidget xwidget_id:%d type:%d found:%d %d %d title:'%s' (%d,%d)\n", xw,
1736 xw->type, found, found1, found2, xw->title, xw->height, xw->width);
1737
1738 //assert_valid_xwidget_id (id, "lookup_xwidget");
1739 return xw;
1740 }
1741
1742 /*set up detection of touched xwidget*/
1743 void
1744 xwidget_start_redisplay (void)
1745 {
1746 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
1747 {
1748 if (XWIDGET_VIEW_P (XCAR (tail)))
1749 XXWIDGET_VIEW (XCAR (tail))->redisplayed = 0;
1750 }
1751 }
1752
1753 /* the xwidget was touched during redisplay, so it isnt a candidate for hiding*/
1754 void
1755 xwidget_touch (struct xwidget_view *xv)
1756 {
1757 xv->redisplayed = 1;
1758 }
1759
1760 int
1761 xwidget_touched (struct xwidget_view *xv)
1762 {
1763 return xv->redisplayed;
1764 }
1765
1766 /* redisplay has ended, now we should hide untouched xwidgets
1767 */
1768 void
1769 xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix)
1770 {
1771
1772 int i;
1773 struct xwidget *xw;
1774 int area;
1775
1776
1777 xwidget_start_redisplay ();
1778 //iterate desired glyph matrix of window here, hide gtk widgets
1779 //not in the desired matrix.
1780
1781 //this only takes care of xwidgets in active windows.
1782 //if a window goes away from screen xwidget views wust be deleted
1783
1784 // dump_glyph_matrix(matrix, 2);
1785 for (i = 0; i < matrix->nrows; ++i)
1786 {
1787 // dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs);
1788 struct glyph_row *row;
1789 row = MATRIX_ROW (matrix, i);
1790 if (row->enabled_p != 0)
1791 {
1792 for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
1793 {
1794 struct glyph *glyph = row->glyphs[area];
1795 struct glyph *glyph_end = glyph + row->used[area];
1796 for (; glyph < glyph_end; ++glyph)
1797 {
1798 if (glyph->type == XWIDGET_GLYPH)
1799 {
1800 /*
1801 the only call to xwidget_end_redisplay is in dispnew
1802 xwidget_end_redisplay(w->current_matrix);
1803 */
1804 xwidget_touch (xwidget_view_lookup(glyph->u.xwidget,
1805 w));
1806 }
1807 }
1808 }
1809 }
1810 }
1811
1812 for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
1813 {
1814 if (XWIDGET_VIEW_P (XCAR (tail))) {
1815 struct xwidget_view* xv = XXWIDGET_VIEW (XCAR (tail));
1816
1817 //"touched" is only meaningful for the current window, so disregard other views
1818 if (XWINDOW (xv->w) == w) {
1819 if (xwidget_touched(xv))
1820 xwidget_show_view (xv);
1821 else
1822 xwidget_hide_view (xv);
1823 }
1824 }
1825 }
1826 }
1827
1828 /* Kill all xwidget in BUFFER. */
1829 void
1830 kill_buffer_xwidgets (Lisp_Object buffer)
1831 {
1832 Lisp_Object tail, xwidget;
1833 for (tail = Fget_buffer_xwidgets (buffer); CONSP (tail); tail = XCDR (tail))
1834 {
1835 xwidget = XCAR (tail);
1836 Vxwidget_list = Fdelq (xwidget, Vxwidget_list);
1837 /* TODO free the GTK things in xw */
1838 {
1839 CHECK_XWIDGET (xwidget);
1840 struct xwidget *xw = XXWIDGET (xwidget);
1841 if (xw->widget_osr && xw->widgetwindow_osr)
1842 {
1843 gtk_widget_destroy(xw->widget_osr);
1844 gtk_widget_destroy(xw->widgetwindow_osr);
1845 }
1846 }
1847 }
1848 }
1849
1850 #endif /* HAVE_XWIDGETS */