src/config.in
autom4te.cache
makefile
-TAGS
*~
/README.W32
/bin/
/site-lisp/
-/leim/ja-dic/
+*.o
+*.elc
+.bzr
+*#
\ No newline at end of file
--- /dev/null
+-*-org-*-
+* Xwidgets
+
+This is an experimental branch to enable embedding of GTK widgets
+inside an Emacs window. The Emacs abstraction is called an Xwidget,
+for eXternal widget, and also in reference to the Xembed protocoll.
+
+There is a demo file called xwidget-test.el which shows some of the
+possibilities. There are some screnshots at the emacswiki.
+
+Currently its possible to insert buttons, sliders, xembed widgets, and
+webkit in the buffer. It works similar to the support for images in
+Emacs. Adding more types of widgets should be fairly straightforward,
+but will require adapter code for each type.
+
+A difference from images is that xwidgets live their own life. You
+create them with an api, get a reference, and tie them to a particular
+buffer with a display spec.
+
+Each xwidget can have several views. In MVC terms, an xwidget is the
+model, and an xwidget-view is a view of the xwidget in a particular
+Emacs window.
+
+The xwidget code attempts to keep the visual appearance of the views
+in sync with through an Observer pattern implementation. This is
+necessary to support the Emacs window paradigm.
+
+** building
+bzr co bzr+ssh://bzr.savannah.gnu.org/emacs/xwidget/
+#or:
+#git clone https://github.com/jave/xwidget-emacs.git
+#the below compiler flags shouldn't be strictly necessary
+export CFLAGS=" -g"
+./configure --with-xwidgets --enable-asserts --with-x-toolkit=gtk3
+make -j4
+gdb -ex run src/emacs
+
+** try it out
+If you have GTK3 and gtk-webkit installed, you should be able to
+start the embedded webkit browser now:
+
+M-X xwidget-webkit-browse-url
+
+If that didnt work out try the minimal demonstration instead:
+
+(load-library "xwidget-test")
+(xwidget-demo-a-button)
+
+It looks unimpressive, but it's a gtk button inside an Emacs buffer!
+*** webkit hints
+If you got webkit working, great! Please note, though, that the
+current support is far from a full fledged browser. My focus is on
+delivering a component that can be used to build a full emacs based
+browser on. Since I implement a browse-url function you can get quite
+far just by:
+
+(setq browse-url-browser-function 'xwidget-webkit-browse-url)
+
+then all Emacs browser interface systems work to a degree.
+heres stuff I use currenly
+
+- m-x anything-surfraw interfaces to search engines
+- C-o in org mode opens links inside org
+- m-x ffap opens links anywhere in a buffer
+- m-x gtk-lookup-symbol searches gtk docs
+- m-x bookmark-jump
+etc..
+
+I'll add more examples as I go along.
+
+However theres lots of support missing, see TODO list for
+information. Briefly:
+- download handling
+- keyboard field navigation
+- isearch
+- history
+- sites that use flash. I dont really care about this issue so its
+unlikely to be fixed. Just a heads up.
+
+** Stability
+Beginning with Summer 2011 I am now able to use Xwidget Emacs as my
+primary Emacs. That is good for the project and the stability of the
+code.
+
+At the time of writing I have 24 hour Emacs uptime with several
+embedded webkit browsers, Gnus, org-mode, tramp, etc. etc.
+
+That said, there are still many improvements that needs to be done,
+particularily in memory management. Expect xwidget emacs to leak
+heavily for now.
+
+** timeline for inclusion in trunk
+The Emacs 24 feature freeze is passed, so xwidgets won't probably be merged
+until Emacs 25. OTOH since I now use xwidget emacs as my primary
+emacs, I will merge from trunk much more often than in the past.
+
+** reporting bugs
+Emacs xwidgets uses the same tracker as mainline emacs, but a
+different package. To report a bug:
+M-x report-xwidget-bug
+
+
+browse bugs:
+http://debbugs.gnu.org/cgi/pkgreport.cgi?package=emacs-xwidgets
+** Thanks
+emacs-devel@gnu.org. There are very helpful people there. When I
+started the xwidget project I had no clue about the Emacs internals.
+
+* Brief overview of how xwidgets work
+Xwidgets work in one way like images in Emacs. You bind a display spec very
+similar to an image display spec to buffer contents. The display engine will
+notice the display spec and try to display the xwidget there. The display engine
+prepares space at the right place for the xwidget and so on for free, as long as
+we provide proper sizes and so on back to the redisplay engine.
+
+** Issues
+The problem is that Emacs cant actually draw the widgets, as it can with
+images. Emacs must notify GTK about where the widgets should be, and how they
+should be clipped and so on, and this information must be given to GTK
+synchronous with Emacs display changes. Ok, so why is that difficult then?
+
+- How do we know when a widget is NOT to be drawn? The only way I found so far
+ is having a flag for each xwdiget, that is reset before a redisplay. When an
+ xwidget is encountered during display, the flag is set. After redisplay,
+ iterate all xwidgets and hide those which hasnt been displayed.
+
+- The gtk socket type for embedding external applications is desirable
+ but presents a lot of difficulties of its own. One difficulty is
+ deciding which input events to forward, and when and how to do it.
+
+** placement and clipping
+the entire emacs frame is a gtk window. we use the fixed layout
+manager to place xwidgets on the frame. coordinates are supplied by
+the emacs display engine. widgets are placed inside an intermediate
+window, called the widgetwindow. the widgetwindows are placed on the
+emacs frame.
+
+this way was chosen to simplify clipping of the widgets against emacs
+window borders.
+
+
+** different strategies
+Integrating toolkit widgets(gtk in this case) and the emacs display
+engine is more difficult than your plain average gui application, and
+different strategies has been tested and will continue to be tested.
+
+There was a distinction between live xwidgets and
+phantom xwidgets, previous to the change to MVC.
+
+- the first aproach was to have the live xwidget on-screen, and move
+ them about. the phantoms were generated by snapshoting the live
+ xwidget.
+
+the drawback of that aproach was that the gtk toolkit is admirably
+lazy and doesnt draw the widget if its not actualy shown, meaning that
+the snapshots for the phantoms will show garbage.
+
+- the second aproach was to use composition support. that tells gtk
+ that the widget should be drawn in an off-screen buffer and drawn on
+ screen by the application.
+
+this has the primary advantage that the snapshot is always
+available, and enables the possibility of more eye-candy like drawing
+live and phantom widgets in different colors.
+
+the drawback is that its our own responsibility to handle drawing,
+which puts more of the display optimization burden on us.
+
+this is aproach worked so-so.
+
+- another aproach is to have both live and phantom widgets drawn
+ on-screen by proxy gtk objects. the live xwidget will be entirely
+ handled in an off-screen window, and the proxy objects will redirect
+ events there.
+
+- combine on-screen and off-screen aproaches. maybe composition is the
+ way to go for most cases, but on-screen xembeding is the way to go
+ for particular special cases, like showing video in a
+ window. off-screen rendering and whatnot, is not efficient in that
+ particular case, and the user will simply have to accept that the
+ phantom of a video widget isnt particularily beautiful.
+
+- The current and seemingly sanest aproach implements a MVC pattern.
+
+** Testing
+;;test like:
+;; cd /path/to/xwidgets-emacs-dir
+;; make all&& src/emacs -q --eval "(progn (load \"`pwd`/lisp/xwidget-test.el\") (xwidget-demo-basic))"
+
+** MVC and Xembedd
+The MVC approach appears to be at least in principle robust for plain gtk
+widgets. For the interesting case of gtk sockets which implements an
+xembed host widget that allows for embedding other applications inside
+an Emacs window, the story gets more complex.
+
+The problem is that xembed is designed to plug an application window
+inside a socket and thats it. You can't move a plug between
+sockets. I tried numerous hacks to get around this but there is
+nothing that works really well.
+
+Therefore the Emacs part of the code will only expose well-defined
+interfaces. cooperating applications will be able to use the interface
+in a well defined manner. The problem is that there is no known xembeddable
+application that implement the needed type of functionality, which is
+allowing for creating new windows on the fly that plug into new
+sockets.
+
+Therefore I will attempt to provide an external application that wraps
+another application and through hacks attempts to provide the needed
+multi view xembed function. That way Emacs is sane and the insanity
+contained.
+
+This app will work by providing a socket that an app plugs into. The
+socket window is copied efficiently by means of composition to a
+number of other windows, that are then plugged into the different
+Emacs sockets.
+** old notes from x_draw_xwidget_glyph_string
+
+ BUG it seems this method for some reason is called with bad s->x and s->y sometimes.
+ When this happens the xwidget doesnt move on screen as it should.
+ This might be because of x_scroll_run. Emacs decides to scroll the screen by blitting sometimes.
+ then emacs doesnt try to actualy call the paint routines, which means this here code will never
+ run so the xwidget wont know it has been moved.
+
+ Solved temporarily by never optimizing in try_window_reusing_current_matrix().
+
+ BUG the phantoming code doesnt work very well when the live xwidget is off screen.
+ you will get weirdo display artefacts. Composition ought to solve this, since that means the live window is
+ always available in an off-screen buffer. My current attempt at composition doesnt work properly however.
+
+ //allocation debugging. the correct values cant be expected to show upp immediately, but eventually they should get to be ok
+ // this is because we dont know when the container gets around to do layout
+ //GtkAllocation galloc;
+ //gtk_widget_get_allocation(GTK_WIDGET (xv->widgetwindow), &galloc);
+ //printf("allocation %d %d , %d %d\n", galloc.x,galloc.y,galloc.width,galloc.height);
+
+
+*** old notes about the old live/phantom scheme
+
+ //TODO:
+ // 1) always draw live xwidget in selected window
+ // (2) if there were no live instances of the xwidget in selected window, also draw it live)
+ // 3) if there was a live xwidget previously, now phantom it.
+
+ else
+ {
+ //ok, we are painting the xwidgets in non-selected window, so draw a phantom
+ //printf("draw phantom xwidget at:%d %d\n",x,y);
+ //xwidget_composite_draw_phantom (xw, x, y, clipx, clipy); //TODO MVC there will be very few cases of phantoming
+ }
+
+
+ atm this works as follows: only check if xwidgets are displayed in the
+ "selected window". if not, hide them or phantom them.
+
+ this means valid cases like xwidgets being displayed only once in
+ non-selected windows, does not work well. they should also be visible
+ in that case not phantomed.
+
+* ToDo:s
+** TODO webkit crash
+[2013-04-13 Sat] seems to crash a lot on http://www.dilbert.com
+Not always, but enough to be annoying.
+
+** TODO optimize drawing off large offscreen widgets
+Currently I just allocate as large an area as the offscreen webkit
+widget desires. This works well most of the time. But a HTML page
+might in principle be of infinite height so there are cases where this
+doesn't work too well.
+
+Heres a proposed strategy:
+- never grow the offscreen webkit over xwidget-webkit-max-height
+- allow for webkit to handle its own scrolling internally as well
+- be more clever about when you have more than one emacs window
+ showing the same webkit instance.
+- allow to grow the offscreen instance in steps rather than just
+ allocate the entire height at once
+
+** DONE again a trace
+ CLOSED: [2011-10-28 Fri 13:48]
+[2011-08-23 Tue]
+the hunch is that since I still hand-wave the view storage the array
+can get out of synchronous. so maybe switching to a lisp structure
+will help as it did for the model. Anyway, doesnt happen at all often.
+*** the trace
+(gdb) bt
+#0 0x0000000000685304 in xwidget_touch (xv=0x0) at xwidget.c:1225
+#1 0x00000000006853e7 in xwidget_end_redisplay (w=0x11b42ca0, matrix=
+ 0xff9bf40) at xwidget.c:1272
+#2 0x000000000041cc31 in update_window (w=0x11b42ca0, force_p=0)
+ at dispnew.c:3705
+#3 0x000000000041c0e5 in update_window_tree (w=0x11b42ca0, force_p=0)
+ at dispnew.c:3331
+#4 0x000000000041be8b in update_frame (f=0x1682a50, force_p=0,
+ inhibit_hairy_id_p=0) at dispnew.c:3258
+#5 0x000000000045066f in redisplay_internal () at xdisp.c:12931
+#6 0x000000000044e210 in redisplay () at xdisp.c:12110
+#7 0x0000000000567e65 in read_char (commandflag=1, nmaps=7, maps=
+ 0x7fffffffc040, prev_event=12708226, used_mouse_menu=0x7fffffffc254,
+ end_time=0x0) at keyboard.c:2447
+#8 0x000000000057613c in read_key_sequence (keybuf=0x7fffffffc4a0, bufsize=
+ 30, prompt=12708226, dont_downcase_last=0, can_return_switch_frame=1,
+ fix_current_buffer=1) at keyboard.c:9299
+#9 0x0000000000565d45 in command_loop_1 () at keyboard.c:1448
+#10 0x0000000000601008 in internal_condition_case (bfun=
+ 0x565962 <command_loop_1>, handlers=12760466, hfun=0x565259 <cmd_error>)
+ at eval.c:1490
+#11 0x0000000000565659 in command_loop_2 (ignore=12708226) at keyboard.c:1159
+#12 0x0000000000600992 in internal_catch (tag=12873826, func=
+---Type <return> to continue, or q <return> to quit---
+ 0x565633 <command_loop_2>, arg=12708226) at eval.c:1247
+#13 0x00000000005655bd in command_loop () at keyboard.c:1124
+#14 0x0000000000564da7 in recursive_edit_1 () at keyboard.c:759
+#15 0x0000000000564f43 in Frecursive_edit () at keyboard.c:823
+#16 0x000000000060444f in Ffuncall (nargs=1, args=0x7fffffffca20)
+ at eval.c:2986
+#17 0x00000000006507f8 in exec_byte_code (bytestr=145172929, vector=145179445,
+ maxdepth=116, args_template=12708226, nargs=0, args=0x0) at bytecode.c:785
+#18 0x0000000000604eec in funcall_lambda (fun=140575909, nargs=2, arg_vector=
+ 0x7fffffffcfe8) at eval.c:3220
+#19 0x000000000060467e in Ffuncall (nargs=3, args=0x7fffffffcfe0)
+ at eval.c:3038
+#20 0x00000000006035fc in Fapply (nargs=2, args=0x7fffffffd0b0) at eval.c:2494
+#21 0x0000000000603b43 in apply1 (fn=12874242, arg=301666310) at eval.c:2732
+#22 0x00000000005feb25 in call_debugger (arg=301666310) at eval.c:220
+#23 0x0000000000601ca9 in maybe_call_debugger (conditions=9431542, sig=
+ 12761282, data=301666742) at eval.c:1893
+#24 0x0000000000601785 in Fsignal (error_symbol=12761282, data=301666742)
+ at eval.c:1714
+#25 0x0000000000601898 in xsignal (error_symbol=12761282, data=301666742)
+ at eval.c:1749
+#26 0x0000000000601926 in xsignal2 (error_symbol=12761282, arg1=102756373,
+ arg2=0) at eval.c:1770
+---Type <return> to continue, or q <return> to quit---
+#27 0x0000000000604d6e in funcall_lambda (fun=102756373, nargs=0, arg_vector=
+ 0x7fffffffd398) at eval.c:3189
+#28 0x000000000060467e in Ffuncall (nargs=1, args=0x7fffffffd390)
+ at eval.c:3038
+#29 0x00000000006507f8 in exec_byte_code (bytestr=54783137, vector=109656229,
+ maxdepth=12, args_template=12708226, nargs=0, args=0x0) at bytecode.c:785
+#30 0x0000000000604eec in funcall_lambda (fun=109656517, nargs=0, arg_vector=
+ 0x7fffffffd890) at eval.c:3220
+#31 0x000000000060467e in Ffuncall (nargs=1, args=0x7fffffffd888)
+ at eval.c:3038
+#32 0x0000000000603b08 in apply1 (fn=109656517, arg=12708226) at eval.c:2725
+#33 0x00000000005fc8c9 in Fcall_interactively (function=109656517, record_flag=
+ 12708226, keys=12754549) at callint.c:379
+#34 0x00000000006044c2 in Ffuncall (nargs=4, args=0x7fffffffdc60)
+ at eval.c:2996
+#35 0x0000000000603c57 in call3 (fn=12893554, arg1=109656517, arg2=12708226,
+ arg3=12708226) at eval.c:2789
+#36 0x00000000005784cd in Fcommand_execute (cmd=109656517, record_flag=
+ 12708226, keys=12708226, special=12708226) at keyboard.c:10290
+#37 0x00000000005661fb in command_loop_1 () at keyboard.c:1575
+#38 0x0000000000601008 in internal_condition_case (bfun=
+ 0x565962 <command_loop_1>, handlers=12760466, hfun=0x565259 <cmd_error>)
+ at eval.c:1490
+---Type <return> to continue, or q <return> to quit---
+#39 0x0000000000565659 in command_loop_2 (ignore=12708226) at keyboard.c:1159
+#40 0x0000000000600992 in internal_catch (tag=12756258, func=
+ 0x565633 <command_loop_2>, arg=12708226) at eval.c:1247
+#41 0x000000000056560c in command_loop () at keyboard.c:1138
+#42 0x0000000000564da7 in recursive_edit_1 () at keyboard.c:759
+#43 0x0000000000564f43 in Frecursive_edit () at keyboard.c:823
+#44 0x0000000000563052 in main (argc=1, argv=0x7fffffffe678) at emacs.c:1711
+
+Lisp Backtrace:
+"recursive-edit" (0xffffca28)
+"debug" (0xffffcfe8)
+"image-bol" (0xffffd398)
+0x68939c0 PVEC_COMPILED
+"call-interactively" (0xffffdc68)
+(gdb)
+
+
+** DONE new annoying trace
+ CLOSED: [2011-08-13 Sat 16:16]
+maybe related to scroll inhibiting or cursor inhibiting code.
+It appears actually to be related to GLYPH_DEBUG=1. this flag is no
+longer needed.
+*** the trace
+Breakpoint 1, abort () at emacs.c:383
+383 kill (getpid (), SIGABRT);
+Missing separate debuginfos, use: debuginfo-install hunspell-1.2.15-2.fc15.x86_64 nss-mdns-0.10-9.fc15.x86_64
+(gdb)
+(gdb)
+(gdb) bt
+#0 abort () at emacs.c:383
+#1 0x0000000000418f01 in matrix_row (matrix=0xac29400, row=-1)
+ at dispnew.c:1477
+#2 0x000000000046e113 in draw_glyphs (w=0x18235c0, x=198, row=0xa3af100, area=
+ TEXT_AREA, start=17, end=18, hl=DRAW_CURSOR, overlaps=0) at xdisp.c:22550
+#3 0x000000000047869f in draw_phys_cursor_glyph (w=0x18235c0, row=0xa3af100,
+ hl=DRAW_CURSOR) at xdisp.c:24882
+#4 0x00000000005083bb in x_draw_window_cursor (w=0x18235c0, glyph_row=
+ 0xa3af100, x=180, y=361, cursor_type=0, cursor_width=1, on_p=1, active_p=1)
+ at xterm.c:7440
+#5 0x00000000004790cd in display_and_set_cursor (w=0x18235c0, on=1, hpos=17,
+ vpos=19, x=180, y=361) at xdisp.c:25098
+#6 0x00000000004fa31f in x_update_window_end (w=0x18235c0, cursor_on_p=1,
+ mouse_face_overwritten_p=0) at xterm.c:644
+#7 0x000000000041ccb9 in update_window (w=0x18235c0, force_p=0)
+ at dispnew.c:3694
+#8 0x000000000041c165 in update_window_tree (w=0x18235c0, force_p=0)
+ at dispnew.c:3331
+#9 0x000000000041beee in update_frame (f=0x1658460, force_p=0,
+ inhibit_hairy_id_p=0) at dispnew.c:3258
+#10 0x0000000000450a2e in redisplay_internal () at xdisp.c:12983
+#11 0x000000000044e2a6 in redisplay () at xdisp.c:12099
+#12 0x000000000056a60d in read_char (commandflag=1, nmaps=6, maps=
+
+** DONE allow xwidgets to report their size
+ CLOSED: [2011-07-19 Tue 14:26]
+now we just hard code sizes. but webkit widgets for instance can
+report sizes that suit the content. support that.
+** DONE BUG xwidget view ghosts
+ CLOSED: [2013-04-05 Fri 23:35]
+(havent seen this in quite a while)
+- xwidget-webkit-browse-url somewhere
+- split window.
+now theres 2 webkit views
+- c-x 1
+now theres 2 views but one is a ghost!
+one should have been deleted when its window died but that didnt work
+for some reason here.
+
+- m-x xwidget-cleanup
+
+the ghost goes away because we killed explicitly but this is just a workaround.
+
+xwidget_view_delete_all_in_window(w); in delete-window-internal is not sufficient.
+delete-other-windows-internal
+delete_all_subwindows
+unshow_buffer
+
+Added cleanup those window configuration hook which works in practice
+but feels kludgy.
+
+*** code looks like this
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defun xwidget-cleanup ()
+ "Delete zombie xwidgets."
+ ;;its still pretty easy to trigger bugs with xwidgets.
+ ;;this function tries to implement a workaround
+ (interactive)
+ (xwidget-delete-zombies) ;;kill xviews who should have been deleted but stull linger
+ (redraw-display);;redraw display otherwise ghost of zombies will remain to haunt the screen
+ )
+
+
+
+;;this is a workaround because I cant find the right place to put it in C
+;;seems to work well in practice though
+(add-hook 'window-configuration-change-hook 'xwidget-cleanup)
+
+*** but it ought rather to work like this
+xwidget-delete-zombies should be called from C after window
+configuration has changed but before redisplay. redisplay should not
+be called.
+
+
+** DONE BUG annoying backtrace
+ CLOSED: [2011-07-19 Tue 14:28]
+(this no longer seems to happen even under heavy usage. seems merging
+from trunk helped. lots were happening in redisplay at this time in trunk.)
+
+sadly happens a lot.
+- happens even with no initialized xwidgets
+- + row->glyphs[area][i].face_id
+or similar code, so row is invalid for some reason.
+xwidgets currently disable some redisplay opimizations so it might be
+an actual emacs bug manifesting without optimizations.
+
+*** bt 1
+ /* Compute the width of this line. */
+ row->pixel_width = row->x;
+ for (i = 0; i < row->used[TEXT_AREA]; ++i)
+ row->pixel_width += row->glyphs[TEXT_AREA][i].pixel_width;
+
+(gdb) bt
+#0 0x000000000045c340 in compute_line_metrics (it=0x7fffffff8a20)
+ at xdisp.c:17549
+#1 0x00000000004603da in display_line (it=0x7fffffff8a20) at xdisp.c:18792
+#2 0x0000000000457646 in try_window (window=23403045, pos=..., flags=1)
+ at xdisp.c:15399
+#3 0x00000000004559c9 in redisplay_window (window=23403045, just_this_one_p=0)
+ at xdisp.c:14944
+#4 0x0000000000450247 in redisplay_window_0 (window=23403045) at xdisp.c:13152
+#5 0x00000000005fdcd9 in internal_condition_case_1 (bfun=
+ 0x450208 <redisplay_window_0>, arg=23403045, handlers=12691046, hfun=
+ 0x4501d9 <redisplay_window_error>) at eval.c:1538
+#6 0x00000000004501ba in redisplay_windows (window=23403045) at xdisp.c:13132
+#7 0x000000000044f19c in redisplay_internal () at xdisp.c:12706
+#8 0x000000000044f9f2 in redisplay_preserve_echo_area (from_where=7)
+ at xdisp.c:12964
+#9 0x0000000000568525 in swallow_events (do_display=1) at keyboard.c:4197
+#10 0x0000000000422554 in sit_for (timeout=40, reading=1, do_display=1)
+ at dispnew.c:5963
+#11 0x000000000056512c in read_char (commandflag=1, nmaps=8, maps=
+ 0x7fffffffd3f0, prev_event=12720514, used_mouse_menu=0x7fffffffd604,
+ end_time=0x0) at keyboard.c:2689
+#12 0x0000000000572c59 in read_key_sequence (keybuf=0x7fffffffd850, bufsize=
+ 30, prompt=12720514, dont_downcase_last=0, can_return_switch_frame=1,
+---Type <return> to continue, or q <return> to quit---
+ fix_current_buffer=1) at keyboard.c:9291
+#13 0x0000000000562897 in command_loop_1 () at keyboard.c:1446
+#14 0x00000000005fdb52 in internal_condition_case (bfun=
+ 0x5624b4 <command_loop_1>, handlers=12772898, hfun=0x561dab <cmd_error>)
+ at eval.c:1493
+#15 0x00000000005621ab in command_loop_2 (ignore=12720514) at keyboard.c:1157
+#16 0x00000000005fd4ce in internal_catch (tag=12768770, func=
+ 0x562185 <command_loop_2>, arg=12720514) at eval.c:1247
+#17 0x000000000056215e in command_loop () at keyboard.c:1136
+#18 0x00000000005618f9 in recursive_edit_1 () at keyboard.c:757
+#19 0x0000000000561a95 in Frecursive_edit () at keyboard.c:821
+#20 0x000000000055fba2 in main (argc=1, argv=0x7fffffffe188) at emacs.c:1704
+
+
+*** bt 2
+
+** DONE Examine using XComposite rather than GTK off-screen
+ rendering. This would make xembed widgets work much better. This
+ would probably be rathter difficult, but could open up other
+ interesting possibilities for Emacs. There is an early attempt in
+ xwidget.c, but the X call to redirect to offscreen rendering fails
+ for unknown reasons.
+
+ the attempt was further worked on, and the xlib calls replaced with
+ gdk calls, this works better.
+
+ In the end I abandoned this aproach. Xwidget-osr is the new aproach.
+
+** TODO make the keyboard event code propagation code work.
+There is an attempt to provide an api to send keyboard events to an
+xwidget, but it doesnt currently work very well.
+
+*** TODO try gtk event creation instead
+since that works fine in the webkit osr code.
+but, oh no, that didn't work for some reason.
+the widgets seems to receive the event but then the embedded widgets
+hangs.
+
+http://kegel.com/gtk/button.c
+
+*** TODO examine some library to synthesize events
+xdotool
+xte xautomation
+crikey
+libxdo
+
+*** TODO webkit raw keyboard event escape
+c-c tab could send a raw tab to the webkit instance.
+** DONE remove the special-case for when the minibuffer is
+ active. I added some code to reduce the annoying problem display artefacts
+ when making the minibuffer the selected window. This made xwidgets in the
+ buffer go grey or black whenever one did m-x to activate the minibuffer. The
+ coded tried to handle the minibuffer as a special case. That simply wasnt a
+ good idea. Special-casing will never work properly. It is much better to spend
+ time finding solutions that work acceptably in the general case.
+
+** DONE disable emacs cursor drawing on top of an active xwidget.
+ This ought to be rather simple and should improve the visuals a lot.
+
+** TODO improve the xwidgets programming interface
+so its less of hand-waving affair. This shouldnt be too hard, but I
+ have deliberatley not spent any time on it, since getting the
+ visuals right is much harder. Anyway, I sort of think the interface
+ should be somewhat like it is, except symbols is used instead of
+ integers.
+*** DONE use symbols for xwidget types rather than ints
+ CLOSED: [2011-06-27 Mon 12:52]
+
+
+*** TODO better lisp based structure for xwidgets
+the lisp interface woud be like this:
+- make-xwidget returns an xwidget object, similar to a process
+ object. this object is used when creating the display spec(instead of
+ the user defined id now used)
+
+the data structure would be something like this:
+- a "process" like aproach to create the xwidgets. xwidgets are
+ coupled to buffers, somewhat like processes, except a buffer can
+ hold several xwidgets
+- an xwidget has a plist to hold the model, like a process
+- an xwidget has an assoc list of xwidget views
+
+there are some things that arent clear:
+- an xwidget doesnt necessarily need to be coupled to a buffer but it
+ seems to be the clearest model. xwidgets would be buffer local
+- xwidget-views are by necessity coupled to a emacs window so it might
+ be better to store them window locally rather than in an assoc
+ coupled to the xwidget model
+- for some gtk widgets that resist an mvc approach, like the webkit
+ widgets, special operations are needed, similar to the old phantom
+ widgets aproach. so we need to differentiate live and phantom
+ instances for these troublesome widgets and let lisp manage all the trickery.
+
+stuff that needs to work:
+- do something for all views of a xwidget(resize, value change)
+- do something for all xw-views in an emacs window(deletion etc)
+- lookup xw-view for xwidget in emacs window(during redisplay)
+(- do something for all siblings of a xw-view. not atm)
+
+*** DONE xwidget creation interface
+ CLOSED: [2011-07-18 Mon 01:59]
+xwidgets are a little bit like emacs processes but also a little bit
+like emacs images. Therefore its not perfectly obvious how to handle
+creation. Currently I just use hardcoded identifiers. the real scheme
+needs to be something else.
+
+Heres a tentative approach:
+- xwidget-create returns a xwidget object, like process creation
+ functions. the xwidget will be largely uninitialized until
+ discovered by redisplay. an xw belongs to a buffer
+- xwidget-insert inserts the xwidget in a buffer. when discovered by
+ redisplay it will be initialized and a xwidget-view allocated
+- an event will be emitted when initialization is finished when
+ relevant like for sockets
+
+the problem with this aproach is that its not really legal to reuse
+xwidget objects by writing several display specs who reference the
+same xwidget. It could presumably be done but it would just become
+weird for no real benefit. the big preblem is that the display spec
+decides the on-screen size, and its not sane to have xwidget views
+with different sizes. therefore such display specs would need to be
+catched and dissallowed. Except it is hard because AFAIK the specs
+don't have an identity as such. A flag in the structure could be set
+by lookup so the first display attempt would win. but then you can't
+rewrite the spec to change the size. hmmm. A third approach would be
+to just allow the 1st spec refering an xw during a redisplay to take
+effect, the rest are signaled as errors. this wouldnt be too bad.
+
+the other aproach would be to work more like images:
+
+- write the display spec with all information needed to create the
+ xwidget.
+- retrieve the xwidget objet from the spec with an xwidget-at-point function. It
+ can be uninitalized which client code must handle. Unlike
+ asynchronous process creation we dont get back a handle, because
+ there is none yet.
+- emitted event on initialization, when needed. Many widgets don't
+ need this. for instance, a button sends an event when pressed. but
+ you can't press it unless its on screen, and then its initialized
+ properly.
+
+This approach seemed good, but how do I know which instance
+generates an event if I cant set the id beforehand?
+
+so, therefore, the first two aproach is used.
+
+
+*** DONE xwidget creation interface actually
+ CLOSED: [2011-07-18 Mon 01:59]
+conclusion of above ramblings:
+- should be similar to make-text-button
+- don't init from display spec, instead during make-xwidget call
+*** TODO callbacks would be nice
+but they need to be handled initially with events for technical
+reasons. C code can't call Lisp easily. The event handler can call the
+callback though.
+
+** TODO more documentation
+There should be user docs, and xwidget contributor docs. The current README
+is all contributor docs there is now, apart from the code.
+
+
+
+** CANCELLED look into more ways of displaying xwidgets, like binding them to a
+ CLOSED: [2011-07-05 Tue 11:34]
+window rather than a point in a buffer. This was suggested by Chidong.
+This would be a useful addition to Emacs in itself, and would avoid nearly all
+display issues. I still think the general case is more interesting, but this
+special case should also be added. The xwidget would then be bound to
+replace the view of a particular window, and it would only show in
+that window.
+
+I got the webkit xwidget to work well enough so I dont see the need
+for this now, except for sockets and I think it can better be dealt
+with at the lisp level.
+
+** DONE MVC mode for xwidgets
+ CLOSED: [2011-06-27 Mon 12:53]
+It appears unfruitful to chase using the same display mode for all
+types of xwidgets. Composition is fun but not robust the way I
+tried to do it.
+
+Instead there should be a set of MVC xwidgets. Each on-screen instance
+of an MVC widget would be a real GTK widget. The instances would
+communciate state using signals.
+
+There are drawbacks. There is no inbuilt support for MVC in GTK, so we
+have to roll our own, which is tedious if not much work for the few
+cases.
+
+MVC for xembedded application will need support from the applications
+themselves. Inkscape supports multiple views to the same document,
+other programs don't. In practice it might not be a big drawback.
+
+
+*** DONE figure out what to do with the multiple frames case.
+ CLOSED: [2011-06-27 Mon 12:52]
+This should be easier to solve with MVC.
+Surprisingly, this just worked!
+*** DONE how to propagate changes in views to other views?
+ CLOSED: [2011-06-27 Mon 12:53]
+I used gtk signals, the implementation for sliders works well!
+
+** TODO canvas support
+heres an interesting comparision of gtk canvases
+http://live.gnome.org/ProjectRidley/CanvasOverview
+
+ATM there are small hardcoded demos in the code, these should be
+removed and replaced with working xwgir counterparts.
+*** goocanvas
+goocanvas is a gtk canvas implemented using cairo. investigate.
+
+pros:
+- it has a MVC model aproach out of the box which is nice.
+
+http://developer.gnome.org/goocanvas/unstable/goocanvas-model-view-canvas.html
+
+export CFLAGS="`pkg-config --cflags goocanvas` -DHAVE_GOOCANVAS"
+export LDFLAGS=`pkg-config --libs goocanvas`
+./configure
+make
+
+I made a hello goo world xwidget so seems doable.
+I wanted to load a SVG which wasnt immediately straightforward, so I
+tried clutter. but it turns out the exact same strategy could be used
+with goocanvas.
+
+*** clutter
+maybe clutter can be used as a canvas?
+pros:
+- seems to have a lot of traction atm. many examples
+- potentialy fast and cool vector graphics
+cons:
+- no out of the box MVC support, but seems doable. no worse than the
+ other home brew mvc support I have in xwidgets
+(media-explorer in an application that employes the MVC pattern)
+
+http://www.openismus.com/documents/clutter_tutorial/0.9/docs/tutorial/html/sec-stage-widget.html
+
+there is also cool stuff like this:
+http://gitorious.org/webkit-clutter/webkit-clutter which is an webkit actor for
+clutter! hmmmmm.
+
+I want to render svg. aparently:
+ librsvg rsvg_handle_render_cairo(h, cr);
+ ClutterCairoTexture
+ Clutter
+
+export CFLAGS="`pkg-config --cflags clutter-gtk-1.0` -DHAVE_CLUTTER"
+export LDFLAGS=`pkg-config --libs clutter-gtk-1.0`
+./configure
+make
+
+compiles but I get:
+Gtk-ERROR **: GTK+ 2.x symbols detected. Using GTK+ 2.x and GTK+ 3 in
+the same process is not supported
+
+export CFLAGS="`pkg-config --cflags clutter-gtk-0.10` -DHAVE_CLUTTER"
+export LDFLAGS=`pkg-config --libs clutter-gtk-0.10`
+./configure
+make
+
+
+*** webkit html 5
+expose the DOM to lisp or something. The webkit xwidget works pretty
+well now, so this might be the way ahead.
+** DONE mvc code crashes after a while
+ CLOSED: [2011-07-12 Tue 18:52]
+seemingly only when compiling with optimizations.
+I have no idea why.
+
+Doesn't seem to happen after some code cleanups.
+** DONE xwidget-resize-at
+ CLOSED: [2011-07-19 Tue 14:28]
+reimplement so display spec is not involved
+** DONE display spec validation
+ CLOSED: [2011-07-19 Tue 14:44]
+it is an error to reuse xwidgets in several buffers or in the same
+buffer. how do we catch these errors?
+- showing the same xwidget twice in a buffer is no more wrong than
+ showing in several emacs windows, just conceptually wrong, so ignore
+ this case for now
+- xwidgets now store a reference to the buffer they were created in,
+ so use that to invalidate xwidget references in oher buffers. but
+ thats not really an error either
+- xwidgets should now be proper lisp objects so you dont delete them
+ you await their garbage collection. so therefore there can never be
+ invalid display specs
+
+so turned out this got solved by using proper lisp objects for
+xwidgets. yay!
+
+** DONE clipping of controllers
+ CLOSED: [2011-07-05 Tue 11:33]
+
+Emacs uses a big GTK window and does its own clipping against Emacs
+windows inside this area. So, in order to layout gtk widgets in emacs
+windows we must clip thim ourselves.
+
+The following method worked well for a long time:
+- make a gtk widget, say a button, xw
+- make a clipping area, of type gtkfixed(many types have been tested)
+- put the clip area in the main emacs gtk window
+- figure out clip area changes during emacs redisplay
+
+the only weirdness was that one has to tell gtk the clip area has a
+window in order to get clipping. This is weird because all gtkwidgets
+are windows in a sense and a window is almost by definition also a
+clipping area.
+
+Anyway, in GTK3 the gtk_widget_set_has_window(GTK_WIDGET (
+xv->widgetwindow), TRUE); call is ignored.
+
+The gtkeventbox which is documented to have its own window doesnt work
+either.
+
+http://www.lanedo.com/~carlos/gtk3-doc/chap-drawing-model.html
+
+anyway clipping is rather complicated but seems to finally work okay.
+
+*** DONE subclass my own clipping widget
+ CLOSED: [2011-07-04 Mon 16:55]
+http://www.lanedo.com/~carlos/gtk3-doc/GtkWidget.html#gtk-widget-set-has-window
+mentions that it has_window can only be called inside a widget
+implementation.
+
+this wasnt really the issue. allocation was the problem
+*** DONE try scrolled window
+ CLOSED: [2011-07-01 Fri 10:56]
+clipping does in fact work with
+gtk_scrolled_window_add_with_viewport (xv->widgetwindow, xv->widget);
+!!
+
+I get unwanted scrollbars in the widget though.
+
+ gtk_scrolled_window_set_policy ( xv->widgetwindow,
+ GTK_POLICY_NEVER, GTK_POLICY_NEVER);
+
+stops clipping from working!
+
+
+*** DONE try viewport
+ CLOSED: [2011-07-01 Fri 10:56]
+gtkviewport is used in scrolled window so in order to remove
+scrollbars it should be possible to use viewport directly. however,
+viewport ignores size requests. or rather the container does.
+
+
+*** DONE debug allocation
+ CLOSED: [2011-07-04 Mon 16:56]
+the container determines how much size to allocate to child widgets.
+
+ GtkAllocation galloc;
+ gtk_widget_get_allocation(GTK_WIDGET (xv->widgetwindow), &galloc);
+ printf("allocation %d %d , %d %d\n", galloc.x,galloc.y,galloc.width,galloc.height);
+
+after my clipping attemp shows that my size request is ignored! this
+might be logical, since the container provided by emacs is a
+gtkfixed. gtkfixed might choose to heed the widgets size desires and
+allocate the entire widget size. but we want clipping!
+
+since i cant reasonably expect to change the emacs main container, i
+can maybe overide the setallocation method in gwfixed, and adjust
+allocation to clipping if its an xwidget asking for allocation.
+
+**** DONE subclass gtkfixed
+ CLOSED: [2011-07-04 Mon 16:56]
+possibly i need to subclass gtkfixed and override
+#+begin_src C
+ void gtk_widget_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+#+end_src
+http://developer.gnome.org/gobject/stable/howto-gobject.html
+
+turns out emacs already does this for gtk3 according to jan D:
+>>For GTK3, Emacs already subclasses GtkFixed, see emacsgtkfixed.[ch].
+
+- widgets may not be underallocated, aparently
+http://mail.gnome.org/archives/commits-list/2011-April/msg10950.html
+
+- how to call base class method/chain up
+http://developer.gnome.org/gobject/stable/howto-gobject-chainup.html
+
+- the allocation modification could happen in the container or the
+ child. it feels more apropiate in the container
+
+it is however unexpectedy inconvenient to modify allocation because
+the needed data is private to the base class. to overcome this:
+
+ - run base class method 1st.
+ - then, iterate all children, and modify allocation for xwidget
+ children only. x y will then be set.
+
+JanD pointed out the GTK3 port already has its own subclass, so I
+modified that one.
+
+*** DONE clip top
+ CLOSED: [2011-07-05 Tue 11:30]
+there are four controller edges that potentialy need clipping. I begun
+with right and bottom edges. clipping them is just a matter of setting
+the right size of the widgetwindow and also ensure it gets the right
+allocation from the container.
+
+clipping top (and left) is not equally straightforward. I'm using a
+viewport now and scroll it the amount that needs to be clipped.
+however, the viewport is sensitive to changes in allocation, which
+makes it harder to use the allocation workarounds.
+
+see:
+- gtk_widget_set_size_request
+- gtkscrolledwindow
+
+I returned to using a simple gtkfixed for the widgetwindow. with
+allocation hack and set_has_window it works. Idea prefer not to have
+the allocatien hack and it wasnt needed it gtk3 only gtk2. needs
+further investigation.
+
+** various code cleanups
+There are many cleanups necessary before any hope of inclusion in
+Emacs trunk. To begin with, the part of the patch that touches other
+parts of emacs must be very clean.
+*** DONE use FRAME_GTK_WIDGET (f)
+ CLOSED: [2011-07-20 Wed 20:02]
+rather than gwfixed.
+
+*** DONE support configure
+ CLOSED: [2011-07-12 Tue 18:48]
+*** DONE ifdef all xwidget code
+ CLOSED: [2011-08-13 Sat 16:19]
+so you can reliably disable the code at compiletime
+** DONE translate clicks
+ CLOSED: [2011-07-03 Sun 22:12]
+on onscreen webkit peer to offscreen
+
+maybe
+http://developer.gnome.org/gdk/stable/gdk-Windows.html#GdkWindow-from-embedder
+
+turned out to be not so hard, captured events, copied them and
+forwarded them offscreen!
+
+** CANCELLED investigate gdk_window_redirect_to_drawable
+ CLOSED: [2013-04-05 Fri 23:37]
+(cancelled this, the current approach seems okay)
+http://developer.gnome.org/gdk/stable/gdk-Windows.html#gdk-offscreen-window-set-embedder
+maybe could be used in place of my own copy hacks? to work it must
+support a chain of redirects, which seems unlikely. the benefit would
+be that I dont have to spend time optimizing redrawing.
+
+
+** DONE remove xwidget_views when emacs window is deleted
+ CLOSED: [2011-07-05 Tue 11:29]
+removing xwidget views when an Emacs window closes is not reliable.
+
+- switching buffers in a window seems to hide the corresponding
+ xwidget-views properly, but they might as well be deleted.
+
+- patching delete-window-internal could be used to delete the xwidget-views
+this seems to work
+
+
+** browser xwidget
+although embedding a browser is not my primary concern many are
+interested in this. some suitable browser component needs to be found
+supporting gtk.
+
+*** DONE webkit
+ CLOSED: [2011-07-03 Sun 22:13]
+there is a webkit gtk port. there is no obvious mvc support.
+http://live.gnome.org/WebKitGtk
+http://webkitgtk.org/
+
+it might be possible to keep a set of webxits in artificial
+synchronisation by recursive deep copy of the DOM from one webkit to
+another. This will be error prone at best though. Another way might be
+to just use bitmap copy of the "live"instance to the "phantom"
+instances. the problem of transfering the live view remains though.
+
+export CFLAGS="`pkg-config --cflags webkit-1.0` -DHAVE_WEBKIT -g"
+export LDFLAGS=`pkg-config --libs webkit-1.0`
+./configure
+make
+
+**** off screen rendering
+export CFLAGS="`pkg-config --cflags webkit-1.0` -DHAVE_WEBKIT_OSR -g"
+export LDFLAGS=`pkg-config --libs webkit-1.0`
+./configure
+make
+
+works a little bit but i get errors like:
+
+(emacs:8362): GLib-GObject-WARNING **: invalid cast from `GdkOffscreenWindow' to `GdkDrawableImplX11'
+
+set a breakpoint in g_log, backtrace seems to indicate
+webkitViewportAttributesRecompute is the offender.
+
+maybe try gtk3 variants?
+#+begin_src sh
+ export CFLAGS="`pkg-config --cflags webkitgtk-3.0 ` -DHAVE_WEBKIT_OSR "
+ export LDFLAGS=`pkg-config --libs webkitgtk-3.0 `
+ ./configure --with-x-toolkit=gtk3
+ make
+#+end_src
+crash in gtk_window_get_size instead. great.
+
+http://gtkplus-p3.0.sourcearchive.com/documentation/2.91.5-0ubuntu1/testoffscreenwindow_8c-source.html
+
+after many attempts, the basic issue remains. for some reason the
+offscreen widget isnt ok when I want to snapshot it, so i simply get
+emptiness. the surface is only ok sometimes.
+
+here is a useful debugging snippets:
+#+begin_src C
+ // debugging redraw:
+ // - the bg colors always change, so theres no error in signal handling
+ // - i get this error now and then:
+ //(emacs:7109): GLib-GObject-WARNING **: invalid cast from `GdkOffscreenWindow' to `GdkDrawableImplX11'
+ // seems to happen in webkit actually. see README
+
+ if(0){ //redraw debug hack. helped a lot in fact. use the with alpha painter below also
+ cairo_set_source_rgb(cr, osr_dbg_color, 1.0, 0.2);
+ cairo_rectangle(cr, 0,0, xw->width, xw->height);
+ cairo_fill(cr);
+ osr_dbg_color+=0.1;
+ if(osr_dbg_color>1.0)
+ osr_dbg_color=0.0;
+
+ }
+#+end_src
+you need to terminate drawing like this:
+#+begin_src C
+ //cairo_set_source_surface (cr, src_pixmap, 0,0);
+ //cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+
+ //cairo_paint_with_alpha (cr, 1.0);
+ //cairo_paint(cr);
+#+end_src
+
+the snippets change background color on oach redraw.
+
+**** on-screen rendering to separate window
+an alternative might be to open a separate window and snapshot it. the
+idea is that whatever oddness webkit does so that offscreen rendering
+doesnt work, doesnt happen on-screen. the window could be opened
+somewhere not in the way.
+
+*** CANCELLED firefox
+ CLOSED: [2011-07-03 Sun 22:13]
+http://www-archive.mozilla.org/unix/gtk-embedding.html
+seems to be severly bitrotted
+
+heres a newer aproach
+http://hg.mozilla.org/incubator/embedding/file/29ac0fe51754/gtk/tests/test.cpp
+
+while webkit clearly has the best traction as an embedded, the
+offscreen rendering issues makes it interesting to see what ff brings
+to the table.
+
+turned out webkit has as good offscreen support as anyone, see I went
+with that in the end.
+
+
+*** DONE text field support
+ CLOSED: [2011-07-20 Wed 20:05]
+Emacs captures all keyboard events so text field support isn't super
+straightforward.
+
+**** propagate keyboard events
+I have some old hacks for this and they are not good.
+**** use the DOM model
+expose document.activeElement to lisp. This is potentially more
+interesting than just forwarding keyboard events.
+
+webkit_web_view_get_dom_document ()
+
+this is hard it seems. an idea might be to hack elisp support for swig
+to machine generate the bindings.
+**** DONE inject javascript
+ CLOSED: [2011-07-03 Sun 22:50]
+webkit_web_view_execute_script ()
+
+this works now:
+(xwidget-webkit-execute-script 5 "document.activeElement.value='test'")
+
+so it should be possible to do some interesting stuff.
+execute-script does however not return anything at the interface level
+so satisfaction is not total:
+
+http://markmail.org/message/4yowmdgras73z3x5
+
+maybe
+https://launchpad.net/gnome-seed
+
+or this funny hack:
+<jave> im trying to understand how to interact via javascript to an embedded
+ webkit gtk instance [23:38]
+<jave> i use webkit_web_view_execute_script() which is nice but doesnt return
+ a value, by design aparently [23:39]
+<jave> any hints?
+<lucian> jave: afaik, webkit still doesn't have full gobject bindings [23:48]
+<lucian> jave: you can hack it up by making the JS modify the title, and read
+ the title from gtk-side
+<jave> lucian: that was a pretty cool idea!
+
+
+*** webkit_web_view_load_string ()
+I would like preview of html in a buffer rather than from uri.
+
+
+
+*** DONE simple xwidget-webkit wrapper
+ CLOSED: [2011-07-22 Fri 11:01]
+so that it could be used for actual browsing :)
+I dont want to reinvent too many wheels so i'd like to use existing
+emacs facilities here possible. use bindings similar to w3m(or info)
+
+- m-x xwidget-webkit starts a session
+- 'g' goes to a url
+- use bookmark-jump i suppose. I mostly use org for bookmarks myself
+- browse-url support so webkit can be the default browser
+- some way of getting around the quirky keyboard interaction since
+ xwidgets dont receive keyboard events because I hawe no idea how to
+ do that in a sane way
+
+... and one can of course go on bikeshedding forever. lets keep it
+simple and extensible, and compatible with other Emacs packages.
+
+the really cool ideas would need Emacs DOM integration, which is not
+easy.
+
+** webkit related
+*** TODO webkit support webkit signals
+
+**** DONE particularly document-load-finished
+ CLOSED: [2011-08-01 Mon 22:34]
+http://webkitgtk.org/reference/webkitgtk-webkitwebview.html#WebKitWebView-document-load-finished
+because one might need tell set a title and sizes and things when it loads.
+**** TODO event bug
+Debugger entered--Lisp error: (error "Two bases given in one event")
+
+hapens sometimes with xwidget events. appears to be when the
+originating xwidget is offscreen so that the event doesn't get caught
+by the correct emacs event map.
+
+maybe I need to set the originating window in the event structure.
+ event.frame_or_window = Qnil; //frame; //how to get the frame here? //TODO i store it in the xwidget now
+
+since its an offscreen xwidget the buffer local keymap isnt the right
+place for the handler. some global map should be used.
+
+onscreen widgets don't have the same issue.
+
+anyway, seems it'll turn out like this:
+- xwidget-osr stores a callback and user data
+- the event is an implementation detail only and get caught in the
+ topmost event map
+- the event map calls the callback in the xw with the right args.
+
+we need the event handler at some level because we can't call lisp
+asynchronously.
+
+**** TODO navigation signal
+**** TODO new window signal
+*** TODO console messages
+http://webkitgtk.org/reference/webkitgtk-webkitwebview.html#WebKitWebView-console-message
+http://getfirebug.com/wiki/index.php/Console_API#console.count.28.5Btitle.5D.29
+because maybe we can make a simple JS REPL that way.
+ (xwidget-webkit-execute-script ( xwidget-webkit-last-session)
+ "console.log('hello')")
+prints hello to stdout but theres no way to catch stdout from webkit I
+think other than receiving the signal.
+
+*** TODO webkit flashkiller by default
+while its possible to support plugins in the webkit xwidget, flash has
+issues on 64 bit, and slows down emacs to a halt with off screen
+rendering, and of course is not free software. its in the way for real
+world usage even if its interesting to watch flash animations inside
+emacs. which should be achieved with Gnash or other free software
+instead.
+
+http://stackoverflow.com/questions/4885513/prevent-flash-in-cocoa-webview
+
+simply use this api:
+http://webkitgtk.org/reference/WebKitWebPluginDatabase.html
+
+theres an implementation now but it's not robust enough webkit often
+crashes taking emacs with it.
+
+*** TODO webkit downloads
+when clicking a download link in Webkit Emacs should take over and handle it
+from there. Probably need signals. There are Emacs libraries to
+download things, with wget etc. an url.el facility should be made.
+"download-requested"
+*** TODO webkit alt-text not handled
+XKCD use image-title to display a cartoon comment. These mysteriously
+don't work ATM. Other mouseovers work though. Maybe webkit tries to
+open a new window or something, which wont work.
+
+*** TODO webkit isearch in webkit buffers
+have a look at how docview solves it
+webkit_web_view_search_text ()
+*** TODO webkit relative references doesn't work
+because we handle scrolling in a non-standard way. It does
+work sort of when theres a html frameset and webkit scrolls by itself.
+
+internal links (page.html#section) do not work
+see xwidget-webkit-show-named-element
+
+also did some webkit signal work for this.
+
+now it actually works! except for I need to know the Y coordinate of
+the element to navigate to, and that can either be by "name" or "id"
+attribute, currently "id" works.
+
+
+
+*** TODO webkit width adjustment handling issue
+since there are so many levels of clipping and whatnot in xwidgets
+sizing issues are difficult.
+
+- an xwidget is told how large it can be by emacs. thats the end of
+ it. if the xwidget thinks otherwise it will be clipped.
+- but emacs can ask the xwidget how large it wants to be. it can then
+ resize the reserved area and inform the xwidget thusly.
+
+That should have been enough. but webkit never reports less than what
+it already has. So currently a webkit view will only growth and not
+adjust to smaller sizes.
+
+This is not a big problem in practice but is still annoying.
+
+to see the problem surface to http://www.slashdot.org
+- xwidget-webkit-adjust-size
+- xwidget-webkit-adjust-size-to-content
+
+and then compare by resizing in Epiphany, which is also webkit based.
+
+**** TODO try putting webkit osr inside a scrolling window
+it seems webkit is supposed to behave differently while embedded in a
+scrolling window. This is a bit cumbersome because the container stack
+is already deep.
+*** TODO xwidget webkit allow loading from string from emacs
+*** DONE xwidget-webkit-last-session
+ CLOSED: [2011-08-01 Mon 22:38]
+was rather hurried. end result is that the lisp layer only really
+allows for one webkit session.
+*** TODO extract DOM to lisp
+then the SHR html renderer from Gnus could render the DOM as created
+by Webkit.
+
+made a simple oxperimental DOM tree traverser. It can be expanded to
+return a lisp representation, LDOM.
+
+in order to bring lisp and DOM closer together the LDOM can include a
+mapping to the originating DOM node. so, find a node in LDOM, and the
+cell maps to the original DOM. but since the LDOM is a copy it can get
+out of sync. DOM events might help.
+*** DONE C-X b in other buffer from webkit
+ CLOSED: [2011-08-12 Fri 22:20]
+bafflingly resets the webkit view to the top. Maybe the window
+reconfiguration hook code? further mystification is added because it
+only seems to happen with ido mode enabled.
+
+in comparison with image-mode which does the right thing, I discovered
+that image-mode has special code to handle scrolling. the browser mode
+and image mode has some similarities.
+
+I made some delegation code frrom webkit mode to image mode.
+*** TODO url-browse improvement
+sindikat: site.com and http://site.com should be equivalent (simple site.com
+ throws error)
+
+Yes, but its unclear at what level in Emacs to do this
+properly. I added a url-tidy function as a start.
+
+this should be further improved:
+- change the call to url-tidy so its a hook
+- provide a couple of demonstration hooks:
+ - url-tidy, which just prepends http://
+ - youtube which appends &html5=1 to urls looking like http://www.youtube.com/watch?v=DZdUgjEx_dQ
+ - history which logs all visited urls like a traditional browser
+
+*** TODO sindicat notes
+Here are some comments from user "sindikat" and my replies
+
+- http://ya.ru renders inadequatly (compare with any other browser) -
+ the search text-input is way below
+
+The problem is the size communication between Emacs and Webkit.
+
+- doing PageDown is endless; so if you do 100 PageDowns, you have to
+ do 100 PageUps to retun to the header of the page
+
+True, I hadn't noticed. Thanks.
+
+- http://linux.org.ru (just an example) renders incorrectly too - it
+ should stretch horizontally
+
+Size communication.
+
+- obviously, pointing of mouse over some link should change it to
+ pointing hand cursor
+
+Need to verify with some other webkit browser.
+
+- when you are somewhere on the middle of a long page, than go to some
+ other page, you are still in the middle, instead of being again on
+ the top
+
+This is because I inherit from Image view mode. I kind of like it so
+we can add an option for it.
+
+
+- changing dropdown menus cause flickering
+
+
+- string entering is incorrect - by default it enters the title of the
+ page, while it should be empty
+
+The cause is the lack of return value in the webkit evaluation
+API. Ive made some fixes.
+
+- internal links (page.html#section) do not work
+
+ ive added a rudimentary function "xwidget-webkit-show-named-element" for this
+
+- maybe it's a good idea to implement Conkeror or some other
+ keybindings, where you press 'f' then select the exact <input
+ type="text"> where you want to enter text, without using mouse,
+ etc.;
+
+Indeed, this would require better DOM integration.
+
+- pressing 'home' and 'end' puts nonsense into minibuffer
+
+Probably because the Image mode derivative is mostly a hack.
+fixed now I think.
+
+
+
+
+
+
+- implement search (emacs internal isearch obviously doesn't work)
+
+Either use the webkit search but that doesn't feel right. It would be
+better to expose the DOM and search that.
+
+- some sites intercept with keyboard; example -
+ http://www.artlebedev.ru/kovodstvo/business-lynch/2011/10/03/ uses
+ Ctrl+left/right/up/down to navigate between pages - this should be
+ implemented too
+
+Keyboard integration is the unloved step-child of xwidgets, unfortunately.
+
+
+
+** TODO xwidget image display spec compatibility
+some history: the first version of the xwidget display spec was
+the same as an image spec. This turned out not to be fantastic because
+an xwidget is both like a process and like an image. it has a separate
+existence from display. So now the xwidget display spec is just a
+pointer to a xwidget. But then some useful functionality in Emacs
+can't be reused for xwidget, in particular image-mode.
+
+Maybe a new image type could be added that was a wraper on an
+xwidget. Then image mode could be reused for webkit mode.
+
+I tried some adaptor code in xwidget.el so webkit mode now delegates
+to image mode but its a kludge.
+
+** socket related
+*** TODO some flickering during redisplay of sockets
+with gtk3 an size allocation workaround is used.
+this seems maybe to result in flickering sizewize y-axis with the
+xwidget socket type. The webkit xwidget doesn't seem similarily
+afflicted.
+
+the size allocation workaround works by 1st running the ordinary
+allocation then modifying the results. its done this way to minimize
+the copy paste index from the base class. it might be that the
+original allocation has a brief time window to show itself.
+
+tried to modify the allocation hack so it doesn't call allocate
+twice. this doesn't seem to help flicker at all aparently so the
+hypothesis falls. Maybe then a socket simply doesn't like being clipped
+by gtkfixed.
+
+*** TODO xwidget view reaping too agressive
+hide an emacs window for a while and return to it. the xwidget might
+get reaped and a new socket thus created.
+*** DONE try out OSR for sockets
+ CLOSED: [2011-07-25 Mon 21:30]
+
+didn't work too well in the inkscape case. it might be that some other
+bitmap copy method works better though.
+
+basically sockets doesn't like to be offscreen because they want their
+own gdk window.
+
+** DONE synchronise emacs background with xwidget color
+ CLOSED: [2011-08-11 Thu 11:04]
+fine-tuning to reduce flicker.
+
+isn't needed if emacs bg erase disabled
+
+** DONE xwidgets doesn't work during bootstrap all of a sudden
+ CLOSED: [2011-08-01 Mon 22:33]
+might be some annoying local issues with my install because it is not
+reliably reproducible. (went away during merges)
+
+** CANCELLED low impact xwidget based image viewer
+ CLOSED: [2013-04-05 Fri 23:38]
+(cancelled this because it no longer seems like a good idea)
+for instance to render SVG using webkit, or some other canvas.
+that way it would be possible to merge to trunk in stages.
+
+so, webkit could be used to display the SVG. the display spec for
+images would be used. multiple webkits would be used rather than
+offscreen rendering, so it would be GTK2 compatible.
+** DONE xwidget movement doesn't work all of a sudden
+ CLOSED: [2011-08-11 Thu 11:03]
+this used to work great. now it doesn't.
+
+suspects:
+- XCopyArea
+ - x_shift_glyphs_for_insert
+ - x_scroll_run. this is run by the try_window* functions, and
+ inhibiting them doesnt help. but also callid in scrolling_window.
+
+
+- try_window_reusing_current_matrix
+- I used to enable GLYPH_DEBUG which I currently don't. it disables
+ many optimisations. this was fixed.
+- lookup_xwidget then produce_xwidget_glyph gets called always but not
+x_draw_xwidget_glyph_string probably because of scroll optimization.
+movement detection could possibly be moved to produce_xwidget_glyph(not)
+
+no longer helps:
+(setq inhibit-try-window-id t)
+(setq inhibit-try-window-reusing t)
+
+workaround:
+(run-with-timer 1 1 'redraw-display)
+
+seems to work:
+inhibiting scrolling_window(). and this seem to be enough to restore the
+old behaviour, GLYPH_DEBUG doesn't seem needed.
+
+
+** DONE GLYPH_DEBUG doesn't work
+ CLOSED: [2011-08-08 Mon 17:30]
+was stupid accidental line removal that was hard to spot
+** TODO osc xwidget example
+a couple of xwidget sliders that control a csound/supercollider song with osc.
+so, for that to work we need slider callbacks to work. when a slider
+changes send an osc message. use ocssend:
+
+ oscsend localhost 7777 /sample/address iTfs 1 3.14 hello
+
+or better:
+http://delysid.org/emacs/osc.el
+
+sliders could be defined in csound comments or something to illustrate
+the point. or if real fanciness is desired parse the csound source
+with Semantic and provide a control buffer corresponding to the
+defined controls.
+
+
+
+Added: [2011-08-11 Thu 10:53]
+
+
+** DONE SEB
+ CLOSED: [2011-10-26 Wed 15:36]
+the SEB site does something funny so I can't insert text in
+fields. aparently document.activeElement.value doesn't work with framesets.
+
+seems to work using the ugly javascript in
+xwidget-webkit-activeelement-js
+
+** support downstreams
+http://aur.archlinux.org/packages.php?ID=53902
+http://gpo.zugaina.org/app-editors/emacs-xwidget/ChangeLog
+** DONE the proof of concept canvas code should be disabled by default.
+ CLOSED: [2011-10-12 Wed 23:03]
+** TODO advi
+active dvi viewer. investigate if it could be xwidgetified.
+advi supports embedding inside presentations.
+** cairo configuration support
+gtk3 brings in cairo on Fedora, but apparently not on all plattforms.
+pkg-config --cflags cairo
+** TODO splint
+splint -Demacs -DHAVE_CONFIG_H -I. -I/home/joakim/build_myprojs/emacsnew/emacs.bzr/xwidget.mint/src -I../lib -I/home/joakim/build_myprojs/emacsnew/emacs.bzr/xwidget.mint/src/../lib -DGSEAL_ENABLE -I/usr/include/gtk-3.0 -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/freetype2 -I/usr/include/alsa -I/usr/include/librsvg-2.0 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/cairo -I/usr/include/libpng12 -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/ImageMagick -I/usr/include/libxml2 -I/usr/include/dbus-1.0 -I/usr/lib64/dbus-1.0/include -DGSEAL_ENABLE -I/usr/include/webkit-3.0 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/gtk-3.0 -I/usr/include/libsoup-2.4 -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/pango-1.0 -I/usr/include/pixman-1 -I/usr/include/freetype2 -I/usr/include/libpng12 -I/usr/include/libxml2 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -DORBIT2=1 -I/usr/include/gconf/2 -I/usr/include/orbit-2.0 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/freetype2 xwidget.c
+
+** TODO 32 bit bug
+user reports that xwidgets segfaults on the 32 bit Mint distribution
+but not the 64 bit. Mint is an Ubuntu derivative. I got some
+VirtualBox images to test with.
+** DONE youtube
+ CLOSED: [2011-11-01 Tue 11:19]
+http://www.youtube.com/watch?v=DZdUgjEx_dQ&html5=1
+html5 makes it work without stupid flash plugins!
+** TODO clicking on an webkit xwidgets
+doesn't make the window active. this leads to problems.
+** DONE "g" should default to current url
+ CLOSED: [2011-11-03 Thu 22:25]
+"g" runs xwidget-webkit-browse-url which gets its interactive argument
+from browse-url-interactive-arg. this might need a new optional argument.
+
+http://test
+** TODO anything/helm support
+hook so anything/helm can filter browser history.
+** TODO new relative url code sometimes fail
+http://www.dilbert.com
+** TODO input field enhancements
+*** password field.
+was straightforward
+
+*** textarea
+less straightforward. I would like it to work like emacs-w3m, where a
+new editing buffer is opened. on c-c, the buffer is closed and the
+browser field updated. however, it's not immediately obvious how to
+store the reference to the field reliably.
+
+furthermore the current code doesn't seem to propagate linefeed
+properly to text areas.
+
+** DONE bug in current navigation handler
+ CLOSED: [2011-11-09 Wed 10:04]
+on www.dn.se
+Debugger entered--Lisp error: (args-out-of-range "http://platform.twitter.com/widgets/hub.html" 54 357)
+ match-string(1 "http://platform.twitter.com/widgets/hub.html")
+ xwidget-webkit-callback(48890368 navigation-policy-decision-requested)
+ xwidget-event-handler()
+ call-interactively(xwidget-event-handler nil nil)
+** TODO how to set the name of a webkit buffer?
+not obvious because, the buffer isn't created immediately and there is
+a callback that sets the buffer name automatically
+** TODO how to find next field in tab order?
+** TODO unique buffer names
+the webkit xwidgets renames the buffer after load but not uniquely so
+it sometimes fails.
+** TODO kill the offscreen webkit xwidgets when last view killed
+The offscreen xwidgets is currently kept around even if the xwidgets
+views are all gone. this is a general problem and it requires actions
+on the behalf of the application to resolve.
+
+In the case of webkit it is currently possible to get errors like these:
+
+Debugger entered--Lisp error: (error "Selecting deleted buffer")
+ xwidget-webkit-callback(60925380 navigation-policy-decision-requested)
+ xwidget-event-handler()
+ call-interactively(xwidget-event-handler nil nil)
+
+
+because the last view is gone and the offscreen widgets is still
+generating events.
+
+In the case of webkit it is okay to kill the offscreen widgets
+completely when the user kills the last view window because it would
+be unexpected by the user to see it pop up again. This is not true in
+the general case.
+
+** DONE xwidgets debugging log
+ CLOSED: [2012-01-23 Mon 14:32]
+currently theres a lot of debugging traces using "message" which is
+annoying. Instead put them in a separate trace buffer.
+(see xwidgetbuffer)
+** TODO make garbage collect work for xwidgets
+when an xwidget is removed from xwidget-alist, and there are no other
+references(mostly views) the xwidget should be garbage collected.
+
+special finalization would go into gc_sweep()
+** TODO embedding evince
+http://developer.gnome.org/libevview/3.2/libevview-ev-view.html
+would be useful for reading PDF:s and other document types.
+it would work the same way webkit embedding works.
+
+** TODO support gobject introspection
+https://live.gnome.org/GObjectIntrospection/
+supporting gobject introspection would mean that more gtk widgets
+could be tried out with less effort, and also that the build process
+and runtime support would be easier. The drawbacks are small: somewhat
+slower execution, and difficulty in providing elisp bindings for
+introspection.
+
+https://live.gnome.org/GObjectIntrospection/HowToWriteALanguageBinding
+
+http://developer.gnome.org/gi/unstable/gi-girepository.html
+http://developer.gnome.org/gi/unstable/gi-overview.html
+
+
+In order for GIR to work, it needs the namespace and class of a
+ widget. This is used to access the typelib file, which contains the
+ introspection data. The namespace and class is stored as a property
+ on the lisp symbol handle used by xwidgets to identify the widget
+ class.
+
+This snippet sets the needed :xwgir-class property, and calls the
+set_zoom_level method:
+
+M-x xwidget-webkit-browse-url RET www.emacswiki.org RET
+
+Then eval the following:
+
+;;load the webkit typelib
+(xwgir-require-namespace "WebKit" "2.0")
+
+;;provide the metadata needed so xwgir can work with the webkit-osr xwidget
+(put 'webkit-osr :xwgir-class '("WebKit" "WebView"))
+;;call the method
+(xwgir-call-method (xwidget-at 1) "set_zoom_level" '(3.0))
+
+It's also possible to create widgets dynamically, by using
+introspection to call a widget constructor(from xwidget-test.el):
+
+
+(defun xwgir-test ()
+ (interactive)
+ (xwgir-require-namespace "Gtk" "3.0")
+ (put 'color-selection :xwgir-class '("Gtk" "ColorSelection"))
+
+ (xwgir-demo-a-xwgir-button)
+ (xwgir-call-method (xwidget-at 1) "set_label" '( "xwgir set label!"))
+ )
+
+Current limitation:
+- Only 0 arg constructors are supported at the moment. Since xwidgets
+ defer construction, the args needs to be stored with the xwidget.
+
+- xwgir-call-method does indeed lisp to gobject conversion for the
+ arguments, but only some primitive types are supported atm.
+
+- next to no argument checking. If wrong type args are used with the
+ xwgir methods, emacs crashes.
+
+*** TODO xwgir create components with more advanced constructor
+so this opens up an entire new can of beans.
+
+explain by example:
+lets say we want to create agtkhscale on screen. its a slider.
+https://developer.gnome.org/gtk3/stable/GtkHScale.html
+we can already create buttons, so sliders shouldnt be much more
+advanced right? wrong.
+
+the simplest slider constructor looks like:
+GtkWidget * gtk_hscale_new
+(GtkAdjustment *adjustment);
+
+so in order to call it, we must be able to forward arguments to the
+constructor. this is almost already done, but we lack the ability to
+pass object instances, only simple types atm.
+
+we need to be able to create GtkAdjustment
+https://developer.gnome.org/gtk3/stable/GtkAdjustment.html
+
+this we can already almost do, because an xwidget is a gir object
+with some decorations. we also store the decorated gir object in an
+array, retrievable from lisp.
+
+In order for this to be usable in practice, we need some changes:
+- lightweight objects should be stored un-decorated. they have no
+ need for the entire graphical machinery of xwidgets
+- lightweight objects should be garbage collectable, but this is the
+ same for all the xwidget objects, and isnt really resolved atm.
+
+
+** DONE investigate gdk_offscreen_window_set_embedder()
+ CLOSED: [2013-04-06 Sat 10:45]
+https://developer.gnome.org/gdk/unstable/gdk-Windows.html
+
+,----
+| Offscreen windows are more general than composited windows, since they
+| allow not only to modify the rendering of the child window onto its
+| parent, but also to apply coordinate transformations.
+|
+| To integrate an offscreen window into a window hierarchy, one has to
+| call gdk_offscreen_window_set_embedder() and handle a number of
+| signals. The "pick-embedded-child" signal on the embedder window is
+| used to select an offscreen child at given coordinates, and the
+| "to-embedder" and "from-embedder" signals on the offscreen window are
+| used to translate coordinates between the embedder and the offscreen
+| window.
+|
+| For rendering an offscreen window onto its embedder, the contents of
+| the offscreen window are available as a pixmap, via
+| gdk_offscreen_window_get_pixmap().
+`----
+
+okay, [2013-04-03 Wed] I finally suceeded in this approach!
+it was pretty hard to make it work and currently works like this:
+- the on screen dravwing area is the embedder
+- you must implement "pick child"
+event forwarding is done automatically!
+
+BUT its not really super, because it only works well with a single
+embedder.
+
+perhaps the strategy could be refined:
+- the window frame would be the embedder for all xwidgets. (but what
+ about several frames then?)
+- in the from-embedder signal handler, which maps container coords to
+ embedded widget coords, find out which xw-view i clicked on, and
+ compute the coords.
+
+[2013-04-04 Thu] I had a strategy working for a xwgir button but not
+a webkit. set_embedded in the motion event handler for the xv. it
+even works for 2 frames! but not webkit :(
+
+[2013-04-05 Fri] it works for xwgir osr components, but not for
+webkit. Webkit retains the previous event forwarding system.
+
+Now it works like this:
+- the offscreen widget is created as before
+- the on-screen views also as before, painting and copying as before.
+- gdk_offscreen_window_set_embedder() is now used to embedd the
+ offscreen widget in the onscreen one, upon view creation
+- only one widget can embedd one other. This means that the embedding
+ widget must be switched between the onscreen ones. This is now done
+ in the mouse motion event handler.
+
+The above approach has been tested for xwgir created buttons and seems
+to work. it doesnt work for webkit, so the old scheme is preserved
+for webkit.
+** TODO investigate git-remote-bzr
],
[with_file_notification=$with_features])
+OPTION_DEFAULT_OFF([xwidgets],[enable use of some gtk widgets it Emacs buffers])
+
## For the times when you want to build Emacs but don't have
## a suitable makeinfo, and can live without the manuals.
dnl http://lists.gnu.org/archive/html/emacs-devel/2008-04/msg01844.html
term_header=gtkutil.h
fi
+
+HAVE_XWIDGETS=no
+HAVE_WEBKIT=no
+HAVE_GIR=no
+
+if test "${with_xwidgets}" != "no"; then
+ echo "xwidgets enabled, checking webkit, and others"
+ HAVE_XWIDGETS=yes
+ AC_DEFINE(HAVE_XWIDGETS, 1, [Define to 1 if you have xwidgets support.])
+#xwidgets
+#TODO
+# - enable only if gtk/gtk3 enabled
+# - webkit
+# - only webkit_osr is good so remove plain webkit laterish
+
+#webkit version for gtk3.
+ WEBKIT_REQUIRED=1.4.0
+ WEBKIT_MODULES="webkitgtk-3.0 >= $WEBKIT_REQUIRED"
+
+ if test "${with_gtk3}" = "yes"; then
+ PKG_CHECK_MODULES(WEBKIT, $WEBKIT_MODULES, HAVE_WEBKIT=yes, HAVE_WEBKIT=no)
+ if test $HAVE_WEBKIT = yes; then
+ AC_DEFINE(HAVE_WEBKIT_OSR, 1, [Define to 1 if you have webkit_osr support.])
+ fi
+ fi
+
+ GIR_REQUIRED=1.32.1
+ GIR_MODULES="gobject-introspection-1.0 >= $GIR_REQUIRED"
+ PKG_CHECK_MODULES(GIR, $GIR_MODULES, HAVE_GIR=yes, HAVE_GIR=no)
+ if test $HAVE_GIR = yes; then
+ AC_DEFINE(HAVE_GIR, 1, [Define to 1 if you have GIR support.])
+ fi
+
+
+fi
+
+
dnl D-Bus has been tested under GNU/Linux only. Must be adapted for
dnl other platforms.
HAVE_DBUS=no
case "$USE_X_TOOLKIT" in
MOTIF) TOOLKIT_LIBW="$MOTIF_LIBW" ;;
LUCID) TOOLKIT_LIBW="$LUCID_LIBW" ;;
- none) test "x$HAVE_GTK" = "xyes" && TOOLKIT_LIBW="$GTK_LIBS" ;;
+ none) test "x$HAVE_GTK" = "xyes" && TOOLKIT_LIBW="$GTK_LIBS -lXcomposite" ;;
esac
AC_SUBST(TOOLKIT_LIBW)
echo " Does Emacs directly use zlib? ${HAVE_ZLIB}"
echo " Does Emacs use toolkit scroll bars? ${USE_TOOLKIT_SCROLL_BARS}"
+
+echo " Does Emacs support Xwidgets? ${HAVE_XWIDGETS}"
+echo " Does xwidgets support webkit(requires gtk3)? ${HAVE_WEBKIT}"
+echo " Does xwidgets support gobject introspection? ${HAVE_GIR}"
echo
if test -n "${EMACSDATA}"; then
(desktop-auto-save-set-timer)
(setq inhibit-startup-screen t))))
-;; So we can restore vc-dir buffers.
-(autoload 'vc-dir-mode "vc-dir" nil t)
-
(provide 'desktop)
;;; desktop.el ends here
--- /dev/null
+* Emacs Parallel
+
+ Emacs Parallel is yet another library to simulate parallel
+ computations in Emacs (because it lacks threads support in Elisp).
+
+* STARTED HowTo
+
+ You can execute a simple function a retrive the result like this:
+ #+BEGIN_SRC emacs-lisp
+ (parallel-get-result (parallel-start (lambda () (* 42 42))))
+ ⇒ 1764
+ #+END_SRC
+
+ Though you won't benefit from the parallelism because
+ ~parallel-get-result~ is blocking, that is it waits for the function
+ to be executed.
+
+ So you can use define a callback to be called when the function is
+ finished:
+ #+BEGIN_SRC emacs-lisp
+ (parallel-start (lambda () (sleep-for 4.2) "Hello World")
+ :post-exec (lambda (results _status)
+ (message (first results))))
+ ⊣ Hello World
+ #+END_SRC
+
+ Here, why ~(first results)~ and not ~result~? Because you can send
+ data from the remote instance while it's running with
+ ~parallel-remote-send~:
+ #+BEGIN_SRC emacs-lisp
+ (parallel-start (lambda ()
+ (parallel-remote-send "Hello")
+ (sleep-for 4.2)
+ "World")
+ :post-exec (lambda (results _status)
+ (message "%s"
+ (mapconcat #'identity (reverse results) " "))))
+ ⊣ Hello World
+ #+END_SRC
+ As you may have noticed the results are pushed in a list, so the
+ first element is the result returned by the function called, the
+ second is the last piece of data send, and so on...
+
+ And of course you can execute some code when you receive data from
+ the remote instance:
+ #+BEGIN_SRC emacs-lisp
+ (parallel-start (lambda ()
+ (parallel-remote-send 42)
+ (sleep-for 4.2) ; heavy computation to compute PI
+ pi)
+ :on-event (lambda (data)
+ (message "Received %S" data)))
+ ⊣ Received 42
+ ⊣ Received 3.141592653589793
+ #+END_SRC
+
+ Because the function is executed in another Emacs instance (in Batch
+ Mode by default), the environment isn't the same. However you can
+ send some data with the ~env~ parameter:
+ #+BEGIN_SRC emacs-lisp
+ (let ((a 42)
+ (b 12))
+ (parallel-get-result (parallel-start (lambda (a b) (+ a b))
+ :env (list a b))))
+ ⇒ 54
+ #+END_SRC
+
+ By default, the remote Emacs instance is exited when the function is
+ executed, but you can keep it running with the
+ ~:continue-when-executed~ option and send new code to be executed
+ with ~parellel-send~.
+ #+BEGIN_SRC emacs-lisp
+ (let ((task (parallel-start (lambda () 42)
+ :continue-when-executed t)))
+ (sleep-for 4.2)
+ (parallel-send task (lambda () (setq parallel-continue-when-executed nil) 12))
+ (parallel-get-results task))
+ ⇒ (12 42)
+ #+END_SRC
+
+ As you can see, to stop the remote instance you have to set the
+ variable ~parallel-continue-when-executed~ to nil.
+
+* Modules
+
+** Parallel XWidget
+
+ [[http://www.emacswiki.org/emacs/EmacsXWidgets][Emacs XWidget]] is an experimental branch which permits to embed GTK+
+ widget inside Emacs buffers. For instance, it is possible to use it
+ to render an HTML page using the webkit engine within an Emacs
+ buffer.
+
+ With this module, you can configure your "main" Emacs to use
+ another one to render web pages.
+
+ Let's assume that you've cloned [[https://github.com/jave/xwidget-emacs][the Emacs XWidget repository]] in
+ ~$HOME/src/emacs-xwidget/~. Once you've compiled it, an Emacs
+ executable is available ~$HOME/src/emacs-xwidget/src/emacs~.
+
+ Configure ~parallel-xwidget~ to use it:
+ #+BEGIN_SRC emacs-lisp
+ (setq parallel-xwidget-config (list :emacs-path
+ (concat (getenv "HOME")
+ "/src/emacs-xwidget/src/emacs")))
+ #+END_SRC
+
+ Then configure your current Emacs to use it:
+ #+BEGIN_SRC emacs-lisp
+ (setq browse-url-browser-function 'parallel-xwidget-browse-url)
+ #+END_SRC
+
+ You can check it out with M-x browse-url RET google.com RET.
+
+* Tips & Tricks
+
+ If your windows manager is smart enough (like StumpwWM) you can use
+ it to move graphical windows (Emacs frames) in another desktop.
+
+ For example, I use this to move Emacs frames (with the title
+ "emacs-debug") to the group (aka desktop) 9:
+ #+BEGIN_SRC lisp
+ (define-frame-preference "9"
+ (0 nil t :title "emacs-debug"))
+ #+END_SRC
+
+ And this to specify the title of the frame:
+ #+BEGIN_SRC emacs-lisp
+ (parallel-start (lambda () 42)
+ :no-batch t
+ :emacs-args '("-T" "emacs-debug"))
+ #+END_SRC
+
+* TODO How does it work?
+
+* Known limitations
+
+ You can only send data to the remote (with the ~env~ parameter) or
+ from the remote (with ~parallel-send~ and ~parallel-remote-send~)
+ that have a printed representation (see [[info:elisp#Printed%20Representation][info:elisp#Printed
+ Representation]]).
+
+ So you can pass around numbers, symbols, strings, lists, vectors,
+ hash-table but you can't pass buffers, windows, frames...
+
+
+ It lacks documentation, tests and probably a clean API, but I'm
+ working on it!
--- /dev/null
+;; -*- mode: emacs-lisp; lexical-binding: t; -*-
+;;; parallel-remote.el ---
+
+;; Copyright (C) 2013 Grégoire Jadi
+
+;; Author: Grégoire Jadi <gregoire.jadi@gmail.com>
+
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of
+;; the License, or (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'cl)
+
+(defvar parallel-service nil)
+(defvar parallel-task-id nil)
+(defvar parallel-client nil)
+(defvar parallel--executed nil)
+(defvar parallel-continue-when-executed nil)
+
+(defun parallel-remote-send (data)
+ (process-send-string parallel-client
+ (format "%S " (cons parallel-task-id data))))
+
+(defun parallel-remote--init ()
+ (setq parallel-client (make-network-process :name "emacs-parallel"
+ :buffer nil
+ :server nil
+ :service parallel-service
+ :host "localhost"
+ :family 'ipv4))
+ (set-process-filter parallel-client #'parallel-remote--filter)
+ (parallel-remote-send 'code)
+ (when noninteractive ; Batch Mode
+ ;; The evaluation is done in the `parallel--filter' but in Batch
+ ;; Mode, Emacs doesn't wait for the input, it stops as soon as
+ ;; `parallel--init' has been executed.
+ (while (null parallel--executed)
+ (sleep-for 10)))) ; arbitrary chosen
+
+(defun parallel-remote--filter (_proc output)
+ (dolist (code (parallel--read-output output))
+ (parallel-remote-send
+ (if (or noninteractive
+ (not debug-on-error))
+ (condition-case err
+ (eval code)
+ (error err))
+ (eval code))))
+ (unless parallel-continue-when-executed
+ (setq parallel--executed t)
+ (kill-emacs)))
+
+(defun parallel--read-output (output)
+ "Read lisp forms from output and return them as a list."
+ (loop with output = (replace-regexp-in-string
+ "\\`[ \t\n]*" ""
+ (replace-regexp-in-string "[ \t\n]*\\'" "" output)) ; trim string
+ with start = 0
+ with end = (length output)
+ for ret = (read-from-string output start end)
+ for data = (first ret)
+ do (setq start (rest ret))
+ collect data
+ until (= start end)))
+
+(provide 'parallel-remote)
+
+;;; parallel-remote.el ends here
--- /dev/null
+;;; parallel-xwidget.el ---
+
+;; Copyright (C) 2013 Grégoire Jadi
+
+;; Author: Grégoire Jadi <gregoire.jadi@gmail.com>
+
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of
+;; the License, or (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'parallel)
+(require 'browse-url)
+
+(defgroup parallel-xwidget nil
+ "Browse the web in another emacs instance with XWidget."
+ :group 'emacs)
+
+(defvar parallel-xwidget--task nil)
+
+(defcustom parallel-xwidget-config nil
+ "Parallel configuration."
+ :type 'alist
+ :group 'parallel-xwidget)
+
+(defun parallel-xwidget--init ()
+ (setq parallel-xwidget--task
+ (parallel-start (lambda ()
+ (require 'xwidget))
+ :graphical t
+ :continue-when-executed t
+ :config parallel-xwidget-config)))
+
+(defun parallel-xwidget-browse-url (url &optional new-session)
+ "Browse URL in another Emacs instance."
+ (interactive (browse-url-interactive-arg "xwidget-webkit URL: "))
+ (unless (and parallel-xwidget--task
+ (eq 'run (parallel-status parallel-xwidget--task)))
+ (parallel-xwidget--init))
+ (parallel-send parallel-xwidget--task
+ (lambda (url new-session)
+ (xwidget-webkit-browse-url url new-session))
+ (url-tidy url) new-session))
+
+(provide 'parallel-xwidget)
+
+;;; parallel-xwidget.el ends here
--- /dev/null
+;; -*- lexical-binding: t; -*-
+;;; parallel.el ---
+
+;; Copyright (C) 2013 Grégoire Jadi
+
+;; Author: Grégoire Jadi <gregoire.jadi@gmail.com>
+
+;; This program is free software: you can redistribute it and/or
+;; modify it under the terms of the GNU General Public License as
+;; published by the Free Software Foundation, either version 3 of
+;; the License, or (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;;; Code:
+
+(require 'cl)
+(require 'parallel-remote)
+
+(defgroup parallel nil
+ "Execute stuff in parallel"
+ :group 'emacs)
+
+(defcustom parallel-sleep 0.05
+ "How many sec should we wait while polling."
+ :type 'number
+ :group 'parallel)
+
+(defcustom parallel-config nil
+ "Global config setting to use."
+ :type 'plist
+ :group 'parallel)
+
+(defvar parallel--server nil)
+(defvar parallel--tasks nil)
+(defvar parallel--tunnels nil)
+
+;; Declare external function
+(declare-function parallel-send "parallel-remote")
+
+(defun parallel-make-tunnel (username hostname)
+ (parallel--init-server)
+ (let ((tunnel (find-if (lambda (tun)
+ (and (string= username
+ (process-get tun 'username))
+ (string= hostname
+ (process-get tun 'hostname))))
+ parallel--tunnels)))
+ (unless tunnel
+ (setq tunnel (start-process "parallel-ssh" nil "ssh"
+ "-N" "-R" (format "0:localhost:%s"
+ (process-contact parallel--server :service))
+ (format "%s@%s" username hostname)))
+ (process-put tunnel 'username username)
+ (process-put tunnel 'hostname hostname)
+ (set-process-filter tunnel #'parallel--tunnel-filter)
+ (while (null (process-get tunnel 'service))
+ (sleep-for 0.01))
+ (push tunnel parallel--tunnels))
+ tunnel))
+
+(defun parallel-stop-tunnel (tunnel)
+ (setq parallel--tunnels (delq tunnel parallel--tunnels))
+ (delete-process tunnel))
+
+(defun parallel--tunnel-filter (proc output)
+ (if (string-match "\\([0-9]+\\)" output)
+ (process-put proc 'service (match-string 1 output))))
+
+(defmacro parallel--set-option (place config)
+ `(setf ,place (or ,place
+ (plist-get ,config ,(intern (format ":%s" (symbol-name place))))
+ (plist-get parallel-config ,(intern (format ":%s" (symbol-name place)))))))
+
+(defmacro parallel--set-options (config &rest options)
+ `(progn
+ ,@(loop for option in options
+ collect `(parallel--set-option ,option ,config))))
+
+(defun* parallel-start (exec-fun &key post-exec env timeout
+ emacs-path library-path emacs-args
+ graphical debug on-event continue-when-executed
+ username hostname hostport
+ config)
+ (parallel--init-server)
+
+ ;; Initialize parameters
+ (parallel--set-options config
+ post-exec
+ env
+ timeout
+ emacs-args
+ graphical
+ debug
+ on-event
+ continue-when-executed
+ username
+ hostname
+ hostport)
+
+ (setq emacs-path (or emacs-path
+ (plist-get config :emacs-path)
+ (plist-get parallel-config :emacs-path)
+ (expand-file-name invocation-name
+ invocation-directory))
+ library-path (or library-path
+ (plist-get config :library-path)
+ (plist-get parallel-config :library-path)
+ (locate-library "parallel-remote")))
+
+ (let ((task (parallel--new-task))
+ proc tunnel ssh-args)
+ (push task parallel--tasks)
+ (put task 'initialized nil)
+ (put task 'exec-fun exec-fun)
+ (put task 'env env)
+ (when (functionp post-exec)
+ (put task 'post-exec post-exec))
+ (when (functionp on-event)
+ (put task 'on-event on-event))
+ (put task 'results nil)
+ (put task 'status 'run)
+ (put task 'queue nil)
+
+ ;; We need to get the tunnel if it exists so we can send the right
+ ;; `service' to the remote.
+ (when (and username hostname)
+ (if hostport
+ (setq ssh-args (list "-R" (format "%s:localhost:%s" hostport
+ (process-contact parallel--server :service)))
+ tunnel t)
+ (setq tunnel (parallel-make-tunnel username hostname)
+ hostport (process-get tunnel 'service)))
+ (setq ssh-args (append
+ ssh-args
+ (if graphical (list "-X"))
+ (list (format "%s@%s" username hostname)))))
+ (setq emacs-args (remq nil
+ (list* "-Q" "-l" library-path
+ (if graphical nil "-batch")
+ "--eval" (format "(setq parallel-service '%S)"
+ (if tunnel
+ hostport
+ (process-contact parallel--server :service)))
+ "--eval" (format "(setq parallel-task-id '%S)" task)
+ "--eval" (format "(setq debug-on-error '%S)" debug)
+ "--eval" (format "(setq parallel-continue-when-executed '%S)" continue-when-executed)
+ "-f" "parallel-remote--init"
+ emacs-args)))
+
+ ;; Reformat emacs-args if we use a tunnel (escape string)
+ (when tunnel
+ (setq emacs-args (list (mapconcat (lambda (string)
+ (if (find ?' string)
+ (prin1-to-string string)
+ string))
+ emacs-args " "))))
+ (setq proc (apply #'start-process "parallel" nil
+ `(,@(when tunnel
+ (list* "ssh" ssh-args))
+ ,emacs-path
+ ,@emacs-args)))
+ (put task 'proc proc)
+ (set-process-sentinel (get task 'proc) #'parallel--sentinel)
+ (when timeout
+ (run-at-time timeout nil (lambda ()
+ (when (memq (parallel-status task)
+ '(run stop))
+ (parallel-stop task)))))
+ task))
+
+(defun parallel--new-task ()
+ "Generate a new task by enforcing a unique name."
+ (let ((symbol-name (make-temp-name "parallel-task-")))
+ (while (intern-soft symbol-name)
+ (setq symbol-name (make-temp-name "parallel-task-")))
+ (intern symbol-name)))
+
+(defun parallel--init-server ()
+ "Initialize `parallel--server'."
+ (when (or (null parallel--server)
+ (not (eq (process-status parallel--server)
+ 'listen)))
+ (setq parallel--server
+ (make-network-process :name "parallel-server"
+ :buffer nil
+ :server t
+ :host "localhost"
+ :service t
+ :family 'ipv4
+ :filter #'parallel--filter
+ :filter-multibyte t))))
+
+(defun parallel--get-task-process (proc)
+ "Return the task running the given PROC."
+ (find-if (lambda (task)
+ (eq (get task 'proc) proc))
+ parallel--tasks))
+
+(defun parallel--sentinel (proc _event)
+ "Sentinel to watch over the remote process.
+
+This function do the necessary cleanup when the remote process is
+finished."
+ (when (memq (process-status proc) '(exit signal))
+ (let* ((task (parallel--get-task-process proc))
+ (results (get task 'results))
+ (status (process-status proc)))
+ ;; 0 means that the remote process has terminated normally (no
+ ;; SIGNUM 0).
+ (if (zerop (process-exit-status proc))
+ (setq status 'success)
+ ;; on failure, push the exit-code or signal number on the
+ ;; results stack.
+ (push (process-exit-status proc) results))
+ (put task 'results results)
+ (put task 'status status)
+
+ (when (functionp (get task 'post-exec))
+ (funcall (get task 'post-exec)
+ results status))
+ (setq parallel--tasks (delq task parallel--tasks)))))
+
+(defun parallel--call-with-env (fun env)
+ "Return a string which can be READ/EVAL by the remote process
+to `funcall' FUN with ENV as arguments."
+ (format "(funcall (read %S) %s)"
+ (prin1-to-string fun)
+ (mapconcat (lambda (obj)
+ ;; We need to quote it because the remote
+ ;; process will READ/EVAL it.
+ (format "'%S" obj)) env " ")))
+
+(defun parallel--filter (connection output)
+ "Server filter used to retrieve the results send by the remote
+process and send the code to be executed by it."
+ (dolist (data (parallel--read-output output))
+ (parallel--process-output connection (first data) (rest data))))
+
+(defun parallel--process-output (connection task result)
+ (put task 'connection connection)
+ (cond ((and (not (get task 'initialized))
+ (eq result 'code))
+ (apply #'parallel-send
+ task
+ (get task 'exec-fun)
+ (get task 'env))
+ (let ((code nil))
+ (while (setq code (pop (get task 'queue)))
+ (apply #'parallel-send task (car code) (cdr code))))
+ (put task 'initialized t))
+ (t
+ (push result (get task 'results))
+ (if (functionp (get task 'on-event))
+ (funcall (get task 'on-event) result)))))
+
+(defun parallel-ready-p (task)
+ "Determine whether TASK is finished and if the results are
+available."
+ (memq (parallel-status task) '(success exit signal)))
+
+(defun parallel-get-result (task)
+ "Return the last result send by the remote call, that is the
+result returned by exec-fun."
+ (first (parallel-get-results task)))
+
+(defun parallel-get-results (task)
+ "Return all results send during the call of exec-fun."
+ (parallel-wait task)
+ (get task 'results))
+
+(defun parallel-success-p (task)
+ "Determine whether TASK has ended successfully."
+ (parallel-wait task)
+ (eq (parallel-status task) 'success))
+
+(defun parallel-status (task)
+ "Return TASK status."
+ (get task 'status))
+
+(defun parallel-wait (task)
+ "Wait for TASK."
+ (while (not (parallel-ready-p task))
+ (sleep-for parallel-sleep))
+ t) ; for REPL
+
+(defun parallel-stop (task)
+ "Stop TASK."
+ (delete-process (get task 'proc)))
+
+(defun parallel-send (task fun &rest env)
+ "Send FUN to be evaluated by TASK in ENV."
+ (let ((connection (get task 'connection)))
+ (if connection
+ (process-send-string
+ connection
+ (parallel--call-with-env fun env))
+ (push (cons fun env) (get task 'queue)))))
+
+(provide 'parallel)
+
+;;; parallel.el ends here
\f
;;; Start of automatically extracted autoloads.
\f
-;;;### (autoloads nil "ibuf-ext" "ibuf-ext.el" "85795a4045d20654599b73b88e8e1bc9")
+;;;### (autoloads nil "ibuf-ext" "ibuf-ext.el" "d06b2735a74954e0c6922a811de7608c")
;;; Generated autoloads from ibuf-ext.el
(autoload 'ibuffer-auto-mode "ibuf-ext" "\
;; functions allows them to be stand-alone commands, making it easier
;; to switch between browsers.
-(defun browse-url-interactive-arg (prompt)
+(defun browse-url-interactive-arg (prompt &optional default-url)
"Read a URL from the minibuffer, prompting with PROMPT.
If `transient-mark-mode' is non-nil and the mark is active,
it defaults to the current region, else to the URL at or before
"[\t\r\f\n ]+" ""
(buffer-substring-no-properties
(region-beginning) (region-end))))
- (browse-url-url-at-point)))
+ (browse-url-url-at-point)
+ default-url))
(not (eq (null browse-url-new-window-flag)
(null current-prefix-arg)))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Browser-independent commands
+(defun url-tidy (url)
+ "Tidy up URL as much as possible."
+ (if (equal 0 (string-match ".*://" url))
+ url
+ (concat "http://" url) ;;TODO guess more url forms, like mailto
+ ))
+
;; A generic command to call the current browse-url-browser-function
;;;###autoload
(interactive (browse-url-interactive-arg "URL: "))
(unless (called-interactively-p 'interactive)
(setq args (or args (list browse-url-new-window-flag))))
+ (setq url (url-tidy url))
(let ((process-environment (copy-sequence process-environment))
(function (or (and (string-match "\\`mailto:" url)
browse-url-mailto-function)
;; `c-set-fl-decl-start' for the detailed functionality.
(cons (c-set-fl-decl-start beg) end))
+(defvar c-standard-font-lock-fontify-region-function nil
+ "Standard value of `font-lock-fontify-region-function'")
+
(defun c-font-lock-fontify-region (beg end &optional verbose)
;; Effectively advice around `font-lock-fontify-region' which extends the
;; region (BEG END), for example, to avoid context fontification chopping
(setq new-region (funcall fn new-beg new-end))
(setq new-beg (car new-region) new-end (cdr new-region)))
c-before-context-fontification-functions))))
- (funcall (default-value 'font-lock-fontify-region-function)
+ (funcall c-standard-font-lock-fontify-region-function
new-beg new-end verbose)))
(defun c-after-font-lock-init ()
;; Put on `font-lock-mode-hook'. This function ensures our after-change
- ;; function will get executed before the font-lock one.
+ ;; function will get executed before the font-lock one. Amongst other
+ ;; things.
(remove-hook 'after-change-functions 'c-after-change t)
- (add-hook 'after-change-functions 'c-after-change nil t))
+ (add-hook 'after-change-functions 'c-after-change nil t)
+ (setq c-standard-font-lock-fontify-region-function
+ (default-value 'font-lock-fontify-region-function)))
(defun c-font-lock-init ()
"Set up the font-lock variables for using the font-lock support in CC Mode.
(defvar use-vc-backend) ;; dynamically bound
+;; Autoload cookie needed by desktop.el.
+;;;###autoload
(define-derived-mode vc-dir-mode special-mode "VC dir"
"Major mode for VC directory buffers.
Marking/Unmarking key bindings and actions:
--- /dev/null
+;;test like:
+;; cd /path/to/xwidgets-emacs-dir
+;; make all&& src/emacs -q --eval "(progn (load \"`pwd`/lisp/xwidget-test.el\") (xwidget-demo-basic))"
+
+
+;; you should see:
+;; - a gtk button
+;; - a gtk toggle button
+;; - a gtk slider button
+;; - an xembed window(using gtk_socket) showing another emacs instance
+;; - an xembed window(using gtk_socket) showing an uzbl web browser if its installed
+
+;;the widgets will move when you type in the buffer. good!
+
+;;there will be redrawing issues when widgets change rows, etc. bad!
+
+;;its currently difficult to give kbd focus to the xembedded emacs,
+;;but try evaling the following:
+
+;; (xwidget-set-keyboard-grab 3 1)
+
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; demo/test functions
+(require 'xwidget)
+
+(defmacro xwidget-demo (name &rest body)
+ `(defun ,(intern (concat "xwidget-demo-" name)) ()
+ (interactive)
+ (switch-to-buffer ,(format "*xwidget-demo-%s*" name))
+ (text-mode);;otherwise no local keymap
+ (insert "Some random text for xwidgets to be inserted in for demo purposes.\n")
+ ,@body))
+
+(xwidget-demo "a-button"
+ (xwidget-insert (point-min) 'Button "button" 60 50)
+ (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-toggle-button"
+ (xwidget-insert (point-min) 'ToggleButton "toggle" 60 50)
+ (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-big-button"
+ (xwidget-insert (point-min) 'Button "button" 400 500)
+ (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-socket"
+ (xwidget-insert (point-min) 'socket "socket" 500 500)
+ (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-socket-osr-broken"
+ (xwidget-insert (point-min) 'socket-osr "socket-osr" 500 500)
+ (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+
+(xwidget-demo "a-slider"
+ (xwidget-insert (point-min) 'slider "slider" 500 100)
+ (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-canvas"
+ (xwidget-insert (point-min) 'cairo "canvas" 1000 1000)
+ (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-webkit-broken"
+ (xwidget-insert (point-min) 'webkit "webkit" 1000 1000)
+ (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-webkit-osr"
+ (xwidget-insert (point-min) 'webkit-osr "webkit-osr" 1000 1000)
+ (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic)
+ (xwidget-webkit-goto-uri (xwidget-at 1) "http://www.fsf.org"))
+
+(xwidget-demo "a-xwgir"
+ (xwidget-insert (point-min) 'xwgir "xwgir" 1000 1000)
+ (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-xwgir-color-button"
+ (xwgir-require-namespace "Gtk" "3.0")
+ (put 'ColorButton :xwgir-class '("Gtk" "ColorSelection"))
+ (xwidget-insert (point-min) 'ColorButton "xwgir-color-button" 1000 1000)
+ (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-xwgir-button"
+ (xwgir-require-namespace "Gtk" "3.0")
+ (put 'xwgirButton :xwgir-class '("Gtk" "Button"))
+
+ (xwidget-insert (point-min) 'xwgirButton "xwgir label didnt work..." 700 700)
+ (xwgir-xwidget-call-method (xwidget-at 1) "set_label" '( "xwgir label worked!"))
+ (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-xwgir-check-button"
+ (xwgir-require-namespace "Gtk" "3.0")
+ (put 'xwgirCheckButton :xwgir-class '("Gtk" "CheckButton"))
+
+ (xwidget-insert (point-min) 'xwgirCheckButton "xwgir label didnt work..." 700 700)
+ (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-xwgir-hscale"
+ (xwgir-require-namespace "Gtk" "3.0")
+ (put 'xwgirHScale :xwgir-class '("Gtk" "HScale"))
+
+ (xwidget-insert (point-min) 'xwgirHScale "xwgir label didnt work..." 700 700)
+ (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+(xwidget-demo "a-xwgir-webkit"
+ (xwgir-require-namespace "WebKit" "3.0")
+ (put 'xwgirWebkit :xwgir-class '("WebKit" "WebView"))
+
+ (xwidget-insert (point-min) 'xwgirWebkit "xwgir webkit..." 700 700)
+ (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic))
+
+
+
+;; tentative testcase:
+;; (xwgir-require-namespace "WebKit" "3.0")
+
+;; (put 'webkit-osr :xwgir-class '("WebKit" "WebView"))
+;; (xwgir-call-method (xwidget-at 1) "set_zoom_level" '(3.0))
+
+;; (xwgir-require-namespace "Gtk" "3.0")
+;; (put 'color-selection :xwgir-class '("Gtk" "ColorSelection"))
+
+
+(xwidget-demo "basic"
+ (xwidget-insert (point-min) 'button "button" 40 50 )
+ (xwidget-insert 15 'toggle "toggle" 60 30 )
+ (xwidget-insert 30 'socket "emacs" 400 200 )
+ (xwidget-insert 20 'slider "slider" 100 50 )
+ (xwidget-insert 40 'socket "uzbl-core" 400 400 )
+ (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic)
+)
+
+
+;it doesnt seem gtk_socket_steal works very well. its deprecated.
+; xwininfo -int
+; then (xwidget-embed-steal 3 <winid>)
+(defun xwidget-demo-grab ()
+ (interactive)
+ (insert "0 <<< grabbed appp will appear here\n")
+ (xwidget-insert 1 1 3 "1" 1000 )
+ (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-grab)
+ )
+
+;ive basically found these xembeddable things:
+;openvrml
+;emacs
+;mplayer
+;surf
+;uzbl
+
+;try the openvrml:
+;/usr/libexec/openvrml-xembed 0 ~/Desktop/HelloWorld.wrl
+
+(defun xwidget-handler-demo-basic ()
+ (interactive)
+ (message "stuff happened to xwidget %S" last-input-event)
+ (let*
+ ((xwidget-event-type (nth 1 last-input-event))
+ (xwidget (nth 2 last-input-event)))
+ (cond ( (eq xwidget-event-type 'xembed-ready)
+ (let*
+ ((xembed-id (nth 3 last-input-event)))
+ (message "xembed ready event: %S xw-id:%s" xembed-id xwidget)
+ ;;will start emacs/uzbl in a xembed socket when its ready
+ (cond
+ (t;;(eq 3 xwidget)
+ (start-process "xembed" "*xembed*" "/var/lib/jenkins/jobs/emacs-xwidgets-automerge/workspace/src/emacs" "-q" "--parent-id" (number-to-string xembed-id) ) )
+;; ((eq 5 xwidget-id)
+;; (start-process "xembed2" "*xembed2*" "uzbl-core" "-s" (number-to-string xembed-id) "http://www.fsf.org" )
+ )
+
+ )
+ ))))
+
+
+
+(defun xwidget-handler-demo-grab ()
+ (interactive)
+ (message "stuff happened to xwidget %S" last-input-event)
+ (let*
+ ((xwidget-event-type (nth 2 last-input-event)))
+ (cond ( (eq xwidget-event-type 'xembed-ready)
+ (let*
+ ((xembed-id (nth 3 last-input-event)))
+ (message "xembed ready %S" xembed-id)
+ )
+ ))))
+(defun xwidget-dummy-hook ()
+ (message "xwidget dummy hook called"))
+
+; (xwidget-resize-hack 1 200 200)
+
+;(xwidget-demo-basic)
+
+(provide 'xwidget-test)
--- /dev/null
+;;; xwidget.el --- api functions for xwidgets
+;; see xwidget.c for more api functions
+
+
+;;; Commentary:
+;;
+
+;;TODO this breaks compilation when we dont have xwidgets
+;;(require 'xwidget-internal)
+
+;;TODO model after make-text-button instead!
+;;; Code:
+
+(eval-when-compile (require 'cl))
+(require 'reporter)
+
+(defun xwidget-insert (pos type title width height)
+ "Insert an xwidget at POS, given ID, TYPE, TITLE WIDTH and
+HEIGHT in the current buffer.
+
+Return ID
+
+see `make-xwidget' for types suitable for TYPE."
+ (goto-char pos)
+ (let ((id (make-xwidget (point) (point)
+ type title width height nil)))
+ (put-text-property (point) (+ 1 (point))
+ 'display (list 'xwidget ':xwidget id))
+ id))
+
+(defun xwidget-at (pos)
+ "Return xwidget at POS."
+ ;;TODO this function is a bit tedious because the C layer isnt well protected yet and
+ ;;xwidgetp aparently doesnt work yet
+ (let* ((disp (get-text-property pos 'display))
+ (xw (car (cdr (cdr disp)))))
+ ;;(if ( xwidgetp xw) xw nil)
+ (if (equal 'xwidget (car disp)) xw)))
+
+
+;; (defun xwidget-socket-handler ()
+;; "Create plug for socket. TODO."
+;; (interactive)
+;; (message "socket handler xwidget %S" last-input-event)
+;; (let*
+;; ((xwidget-event-type (nth 2 last-input-event))
+;; (xwidget-id (nth 1 last-input-event)))
+;; (cond ( (eq xwidget-event-type 'xembed-ready)
+;; (let*
+;; ((xembed-id (nth 3 last-input-event)))
+;; (message "xembed ready event: %S xw-id:%s" xembed-id xwidget-id)
+;; ;;TODO fetch process data from the xwidget. create it, store process info
+;; ;;will start emacs/uzbl in a xembed socket when its ready
+;; ;; (cond
+;; ;; ((eq 3 xwidget-id)
+;; ;; (start-process "xembed" "*xembed*" (format "%ssrc/emacs" default-directory) "-q" "--parent-id" (number-to-string xembed-id) ) )
+;; ;; ((eq 5 xwidget-id)
+;; ;; (start-process "xembed2" "*xembed2*" "uzbl-core" "-s" (number-to-string xembed-id) "http://www.fsf.org" ) )
+;; )))))
+
+(defun xwidget-display (xwidget)
+ "Force xwidget to be displayed to create a xwidget_view. Return
+the window displaying XWIDGET."
+ (let* ((buffer (xwidget-buffer xwidget))
+ (window (display-buffer buffer))
+ (frame (window-frame window)))
+ (set-frame-visible frame t)
+ (redisplay t)
+ window))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;; webkit support
+(require 'browse-url)
+(require 'image-mode);;for some image-mode alike functionality
+(require 'cl-macs);;for flet
+
+;;;###autoload
+(defun xwidget-webkit-browse-url (url &optional new-session)
+ "Ask xwidget-webkit to browse URL.
+NEW-SESSION specifies whether to create a new xwidget-webkit session. URL
+defaults to the string looking like a url around the cursor position."
+ (interactive (progn
+ (require 'browse-url)
+ (browse-url-interactive-arg "xwidget-webkit URL: "
+ ;;( xwidget-webkit-current-url)
+ )))
+ (when (stringp url)
+ (setq url (url-tidy url))
+ (if new-session
+ (xwidget-webkit-new-session url)
+ (xwidget-webkit-goto-url url))))
+
+
+;;shims for adapting image mode code to the webkit browser window
+(defun xwidget-image-display-size (spec &optional pixels frame)
+ "Image code adaptor. SPEC PIXELS FRAME like the corresponding `image-mode' fn."
+ (let ((xwi (xwidget-info (xwidget-at 1))))
+ (cons (aref xwi 2)
+ (aref xwi 3))))
+
+(defadvice image-display-size (around image-display-size-for-xwidget
+ (spec &optional pixels frame)
+ activate)
+ (if (eq (car spec) 'xwidget)
+ (setq ad-return-value (xwidget-image-display-size spec pixels frame))
+ ad-do-it))
+
+;;todo.
+;; - check that the webkit support is compiled in
+(defvar xwidget-webkit-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map "g" 'xwidget-webkit-browse-url)
+ (define-key map "a" 'xwidget-webkit-adjust-size-to-content)
+ (define-key map "b" 'xwidget-webkit-back )
+ (define-key map "r" 'xwidget-webkit-reload )
+ (define-key map "t" (lambda () (interactive) (message "o")) )
+ (define-key map "\C-m" 'xwidget-webkit-insert-string)
+ (define-key map "w" 'xwidget-webkit-current-url)
+
+ ;;similar to image mode bindings
+ (define-key map (kbd "SPC") 'image-scroll-up)
+ (define-key map (kbd "DEL") 'image-scroll-down)
+
+ (define-key map [remap scroll-up] 'image-scroll-up)
+ (define-key map [remap scroll-up-command] 'image-scroll-up)
+
+ (define-key map [remap scroll-down] 'image-scroll-down)
+ (define-key map [remap scroll-down-command] 'image-scroll-down)
+
+ (define-key map [remap forward-char] 'image-forward-hscroll)
+ (define-key map [remap backward-char] 'image-backward-hscroll)
+ (define-key map [remap right-char] 'image-forward-hscroll)
+ (define-key map [remap left-char] 'image-backward-hscroll)
+ (define-key map [remap previous-line] 'image-previous-line)
+ (define-key map [remap next-line] 'image-next-line)
+
+ (define-key map [remap move-beginning-of-line] 'image-bol)
+ (define-key map [remap move-end-of-line] 'image-eol)
+ (define-key map [remap beginning-of-buffer] 'image-bob)
+ (define-key map [remap end-of-buffer] 'image-eob)
+ map)
+ "Keymap for `xwidget-webkit-mode'.")
+
+;;the xwidget event needs to go into a higher level handler
+;;since the xwidget can generate an event even if its offscreen
+;;TODO this needs to use callbacks and consider different xw ev types
+(define-key (current-global-map) [xwidget-event] 'xwidget-event-handler)
+(defun xwidget-log ( &rest msg)
+ (let ( (buf (get-buffer-create "*xwidget-log*")))
+ (save-excursion
+ (buffer-disable-undo buf)
+ (set-buffer buf)
+ (insert (apply 'format msg))
+ (insert "\n"))))
+
+(defun xwidget-event-handler ()
+ "Receive xwidget event."
+ (interactive)
+ (xwidget-log "stuff happened to xwidget %S" last-input-event)
+ (let*
+ ((xwidget-event-type (nth 1 last-input-event))
+ (xwidget (nth 2 last-input-event))
+ ;(xwidget-callback (xwidget-get xwidget 'callback));;TODO stopped working for some reason
+ )
+ ;(funcall xwidget-callback xwidget xwidget-event-type)
+ (message "xw callback %s" xwidget)
+ (funcall 'xwidget-webkit-callback xwidget xwidget-event-type)))
+
+(defun xwidget-webkit-callback (xwidget xwidget-event-type)
+ (save-excursion
+ (cond ((buffer-live-p (xwidget-buffer xwidget))
+ (set-buffer (xwidget-buffer xwidget))
+ (let* ((strarg (nth 3 last-input-event)))
+ (cond ((eq xwidget-event-type 'document-load-finished)
+ (xwidget-log "webkit finished loading: '%s'" (xwidget-webkit-get-title xwidget))
+ (xwidget-adjust-size-to-content xwidget)
+ (rename-buffer (format "*xwidget webkit: %s *" (xwidget-webkit-get-title xwidget)))
+ (pop-to-buffer (current-buffer)))
+ ((eq xwidget-event-type 'navigation-policy-decision-requested)
+ (if (string-match ".*#\\(.*\\)" strarg)
+ (xwidget-webkit-show-id-or-named-element xwidget (match-string 1 strarg))))
+ (t (xwidget-log "unhandled event:%s" xwidget-event-type)))))
+ (t (xwidget-log "error: callback called for xwidget with dead buffer")))))
+
+(define-derived-mode xwidget-webkit-mode
+ special-mode "xwidget-webkit" "xwidget webkit view mode"
+ (setq buffer-read-only t)
+ ;; Keep track of [vh]scroll when switching buffers
+ (image-mode-setup-winprops))
+
+(defvar xwidget-webkit-last-session-buffer nil)
+
+(defun xwidget-webkit-last-session ()
+ "Last active webkit, or nil."
+ (if (buffer-live-p xwidget-webkit-last-session-buffer)
+ (with-current-buffer xwidget-webkit-last-session-buffer
+ (xwidget-at 1))
+ nil))
+
+(defun xwidget-webkit-current-session ()
+ "Either the webkit in the current buffer, or the last one used, which might be nil."
+ (if (xwidget-at 1)
+ (xwidget-at 1)
+ (xwidget-webkit-last-session)))
+
+(defun xwidget-adjust-size-to-content (xw)
+ "Resize XW to content."
+ ;;xwidgets doesnt support widgets that have their own opinions about size well yet
+ ;;this reads the desired size and resizes the emacs allocated area accordingly
+ (let ((size (xwidget-size-request xw)))
+ (xwidget-resize xw (car size) (cadr size))))
+
+
+(defvar xwidget-webkit-activeelement-js"
+function findactiveelement(doc){
+//alert(doc.activeElement.value);
+ if(doc.activeElement.value != undefined){
+ return doc.activeElement;
+ }else{
+ // recurse over the child documents:
+ var frames = doc.getElementsByTagName('frame');
+ for (var i = 0; i < frames.length; i++)
+ {
+ var d = frames[i].contentDocument;
+ var rv = findactiveelement(d);
+ if(rv != undefined){
+ return rv;
+ }
+ }
+ }
+ return undefined;
+};
+
+
+"
+
+ "javascript that finds the active element."
+ ;;yes its ugly. because:
+ ;; - there is aparently no way to find the active frame other than recursion
+ ;; - the js "for each" construct missbehaved on the "frames" collection
+ ;; - a window with no frameset still has frames.length == 1, but frames[0].document.activeElement != document.activeElement
+ ;;TODO the activeelement type needs to be examined, for iframe, etc. sucks.
+ )
+
+(defun xwidget-webkit-insert-string (xw str)
+ "Insert string in the active field in the webkit.
+Argument XW webkit.
+Argument STR string."
+ ;;read out the string in the field first and provide for edit
+ (interactive
+ (let* ((xww (xwidget-webkit-current-session))
+
+ (field-value
+ (progn
+ (xwidget-webkit-execute-script xww xwidget-webkit-activeelement-js)
+ (xwidget-webkit-execute-script-rv xww "findactiveelement(document).value;" )))
+ (field-type (xwidget-webkit-execute-script-rv xww "findactiveelement(document).type;" )))
+ (list xww
+ (cond ((equal "text" field-type)
+ (read-string "text:" field-value))
+ ((equal "password" field-type)
+ (read-passwd "password:" nil field-value))
+ ((equal "textarea" field-type)
+ (xwidget-webkit-begin-edit-textarea xww field-value))))))
+ (xwidget-webkit-execute-script xw (format "findactiveelement(document).value='%s'" str)))
+
+
+(defun xwidget-webkit-begin-edit-textarea (xw text)
+ (switch-to-buffer
+ (generate-new-buffer "textarea"))
+
+ (set (make-local-variable 'xwbl) xw)
+ (insert text))
+
+(defun xwidget-webkit-end-edit-textarea ()
+ (interactive)
+ (goto-char (point-min))
+ (while (search-forward "\n" nil t)
+ (replace-match "\\n" nil t))
+ (xwidget-webkit-execute-script xwbl (format "findactiveelement(document).value='%s'"
+ (buffer-substring (point-min) (point-max))))
+ ;;TODO convert linefeed to \n
+ )
+
+(defun xwidget-webkit-show-named-element (xw element-name)
+ "make named-element show. for instance an anchor."
+ (interactive (list (xwidget-webkit-current-session) (read-string "element name:")))
+ ;;TODO
+ ;; since an xwidget is an Emacs object, it is not trivial to do some things that are taken for granted in a normal browser.
+ ;; scrolling an anchor/named-element into view is one such thing.
+ ;; this function implements a proof-of-concept for this.
+ ;; problems remaining:
+ ;; - the selected window is scrolled but this is not always correct
+ ;; - this needs to be interfaced into browse-url somehow. the tricky part is that we need to do this in two steps:
+ ;; A: load the base url, wait for load signal to arrive B: navigate to the anchor when the base url is finished rendering
+
+ ;;this part figures out the Y coordinate of the element
+ (let ((y (string-to-number
+ (xwidget-webkit-execute-script-rv xw
+ (format "document.getElementsByName('%s')[0].getBoundingClientRect().top" element-name)
+ 0))))
+ ;;now we need to tell emacs to scroll the element into view.
+ (xwidget-log "scroll: %d" y)
+ (set-window-vscroll (selected-window) y t)))
+
+(defun xwidget-webkit-show-id-element (xw element-id)
+ "make id-element show. for instance an anchor."
+ (interactive (list (xwidget-webkit-current-session)
+ (read-string "element id:")))
+ (let ((y (string-to-number
+ (xwidget-webkit-execute-script-rv xw
+ (format "document.getElementById('%s').getBoundingClientRect().top" element-id)
+ 0))))
+ ;;now we need to tell emacs to scroll the element into view.
+ (xwidget-log "scroll: %d" y)
+ (set-window-vscroll (selected-window) y t)))
+
+(defun xwidget-webkit-show-id-or-named-element (xw element-id)
+ "make id-element show. for instance an anchor."
+ (interactive (list (xwidget-webkit-current-session)
+ (read-string "element id:")))
+ (let* ((y1 (string-to-number
+ (xwidget-webkit-execute-script-rv xw
+ (format "document.getElementsByName('%s')[0].getBoundingClientRect().top" element-id)
+ "0")))
+ (y2 (string-to-number
+ (xwidget-webkit-execute-script-rv xw
+ (format "document.getElementById('%s').getBoundingClientRect().top" element-id)
+ "0")))
+ (y3 (max y1 y2)))
+ ;;now we need to tell emacs to scroll the element into view.
+ (xwidget-log "scroll: %d" y3)
+ (set-window-vscroll (selected-window) y3 t)))
+
+(defun xwidget-webkit-adjust-size-to-content ()
+ "Adjust webkit to content size."
+ (interactive)
+ (xwidget-adjust-size-to-content (xwidget-webkit-current-session)))
+
+(defun xwidget-webkit-adjust-size (w h)
+ "Manualy set webkit size.
+Argument W width.
+Argument H height."
+ ;;TODO shouldnt be tied to the webkit xwidget
+ (interactive "nWidth:\nnHeight:\n")
+ (xwidget-resize ( xwidget-webkit-current-session) w h))
+
+(defun xwidget-webkit-fit-width ()
+ (interactive)
+ (xwidget-webkit-adjust-size (- (caddr (window-inside-pixel-edges))
+ (car (window-inside-pixel-edges)))
+ 1000))
+
+(defun xwidget-webkit-new-session (url)
+ "Create a new webkit session buffer with URL."
+ (let*
+ ((bufname (generate-new-buffer-name "*xwidget-webkit*"))
+ xw)
+ (setq xwidget-webkit-last-session-buffer (switch-to-buffer (get-buffer-create bufname)))
+ (insert " ")
+ (setq xw (xwidget-insert 1 'webkit-osr bufname 1000 1000))
+ (xwidget-put xw 'callback 'xwidget-webkit-callback)
+ (xwidget-webkit-mode)
+ (xwidget-webkit-goto-uri (xwidget-webkit-last-session) url )))
+
+
+(defun xwidget-webkit-goto-url (url)
+ "Goto URL."
+ (if (xwidget-webkit-current-session)
+ (progn
+ (xwidget-webkit-goto-uri (xwidget-webkit-current-session) url))
+ (xwidget-webkit-new-session url)))
+
+(defun xwidget-webkit-back ()
+ "Back in history."
+ (interactive)
+ (xwidget-webkit-execute-script (xwidget-webkit-current-session) "history.go(-1);"))
+
+(defun xwidget-webkit-reload ()
+ "Reload current url."
+ (interactive)
+ (xwidget-webkit-execute-script (xwidget-webkit-current-session) "history.go(0);"))
+
+(defun xwidget-webkit-current-url ()
+ "Get the webkit url. place it on kill ring."
+ (interactive)
+ (let* ((rv (xwidget-webkit-execute-script-rv (xwidget-webkit-current-session)
+ "document.URL"))
+ (url (kill-new (or rv ""))))
+ (message "url: %s" url )
+ url))
+
+(defun xwidget-webkit-execute-script-rv (xw script &optional default)
+ "same as xwidget-webkit-execute-script but also wraps an ugly hack to return a value"
+ ;;notice the fugly "title" hack. it is needed because the webkit api doesnt support returning values.
+ ;;this is a wrapper for the title hack so its easy to remove should webkit someday support JS return values
+ ;;or we find some other way to access the DOM
+
+ ;;reset webkit title. fugly.
+ (let* ((emptytag "titlecantbewhitespaceohthehorror")
+ title)
+ (xwidget-webkit-execute-script xw (format "document.title=\"%s\";" (or default emptytag)))
+ (xwidget-webkit-execute-script xw (format "document.title=%s;" script))
+ (setq title (xwidget-webkit-get-title xw))
+ (if (equal emptytag title)
+ (setq title ""))
+ (unless title
+ (setq title default))
+ title))
+
+
+;; use declare here?
+;; (declare-function xwidget-resize-internal "xwidget.c" )
+;; check-declare-function?
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defun xwidget-webkit-get-selection ()
+ (xwidget-webkit-execute-script-rv (xwidget-webkit-current-session)
+ "window.getSelection().toString();"))
+
+(defun xwidget-webkit-copy-selection-as-kill ()
+ (interactive)
+ (kill-new (xwidget-webkit-get-selection)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; xwidget plist management(similar to the process plist functions)
+
+(defun xwidget-get (xwidget propname)
+ "Return the value of XWIDGET' PROPNAME property.
+This is the last value stored with `(xwidget-put XWIDGET PROPNAME VALUE)'."
+ (plist-get (xwidget-plist xwidget) propname))
+
+(defun xwidget-put (xwidget propname value)
+ "Change XWIDGET' PROPNAME property to VALUE.
+It can be retrieved with `(xwidget-get XWIDGET PROPNAME)'."
+ (set-xwidget-plist xwidget
+ (plist-put (xwidget-plist xwidget) propname value)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun xwidget-delete-zombies ()
+ (dolist (xwidget-view xwidget-view-list)
+ (when (or (not (window-live-p (xwidget-view-window xwidget-view)))
+ (not (memq (xwidget-view-model xwidget-view)
+ xwidget-list)))
+ (delete-xwidget-view xwidget-view))))
+
+(defun xwidget-cleanup ()
+ "Delete zombie xwidgets."
+ ;;its still pretty easy to trigger bugs with xwidgets.
+ ;;this function tries to implement a workaround
+ (interactive)
+ ;; kill xviews who should have been deleted but stull linger
+ (xwidget-delete-zombies)
+ ;; redraw display otherwise ghost of zombies will remain to haunt the screen
+ (redraw-display))
+
+;;this is a workaround because I cant find the right place to put it in C
+;;seems to work well in practice though
+;;(add-hook 'window-configuration-change-hook 'xwidget-cleanup)
+(add-hook 'window-configuration-change-hook 'xwidget-delete-zombies)
+
+(defun xwidget-kill-buffer-query-function ()
+ "Ask beforek illing a buffer that has xwidgets."
+ (let ((xwidgets (get-buffer-xwidgets (current-buffer))))
+ (or (not xwidgets)
+ (not (memq t (mapcar 'xwidget-query-on-exit-flag xwidgets)))
+ (yes-or-no-p
+ (format "Buffer %S has xwidgets; kill it? "
+ (buffer-name (current-buffer)))))))
+
+(add-hook 'kill-buffer-query-functions 'xwidget-kill-buffer-query-function)
+
+;;killflash is sadly not reliable yet.
+(defvar xwidget-webkit-kill-flash-oneshot t)
+(defun xwidget-webkit-kill-flash ()
+ "Disable the flash plugin in webkit.
+This is needed because Flash is non-free and doesnt work reliably
+on 64 bit systems and offscreen rendering. Sadly not reliable
+yet, so deinstall Flash instead for now."
+ ;;you can only call this once or webkit crashes and takes emacs with it. odd.
+ (unless xwidget-webkit-kill-flash-oneshot
+ (xwidget-disable-plugin-for-mime "application/x-shockwave-flash")
+ (setq xwidget-webkit-kill-flash-oneshot t)))
+
+(xwidget-webkit-kill-flash)
+
+(defun report-xwidget-bug ()
+ "Report a bug in GNU Emacs about the XWidget branch.
+Prompts for bug subject. Leaves you in a mail buffer."
+ (interactive)
+ (let ((reporter-prompt-for-summary-p t))
+ (reporter-submit-bug-report "submit@debbugs.gnu.org" nil nil nil nil
+ (format "Package: emacs-xwidgets
+
+Please describee xactly whata ctions triggered the bug, and the
+precise symptoms of the bug. If you can, give a recipe starting
+from `emacs -Q'.
+
+If Emacs crashed, and you have the Emacs process in the gdb
+deubbger, please include the output from the following gdb
+commands:
+ `bt full' and `xbacktrace'.
+
+For information about debugging Emacs, please read the file
+%s" (expand-file-name "DEBUG" data-directory)))))
+
+(provide 'xwidget)
+
+;;; xwidget.el ends here
LANG=
export LANGUAGE LC_ALL LC_MESSAGES LANG
-## Remove unnecessary restrictions on file access.
-umask 022
+## Don't restrict access to any files.
+umask 0
update=yes
check=yes
Print $ as a scrollbar pointer.
end
+define xxwidget
+ if $argc == 1
+ xgetptr $arg0
+ else
+ xgetptr $
+ end
+ set $xw = (struct xwidget *) $ptr
+ print $xw
+ printf " Type: "
+ xprintsym $xw->type
+ echo \n
+ printf " Title: "
+ xgetptr $xw->title
+ set $title = (struct Lisp_String *) $ptr
+ xprintstr $title
+ echo \n
+end
+document xxwidget
+Print $ assuming it is a xwidget.
+end
+
define xpr
xtype
if $type == Lisp_Int0 || $type == Lisp_Int1
if $vec == PVEC_HASH_TABLE
xhashtable
end
+ if $vec == PVEC_XWIDGET
+ xxwidget
+ end
else
xvector
end
RSVG_LIBS= @RSVG_LIBS@
RSVG_CFLAGS= @RSVG_CFLAGS@
+WEBKIT_LIBS= @WEBKIT_LIBS@
+WEBKIT_CFLAGS= @WEBKIT_CFLAGS@
+
+GIR_LIBS= @GIR_LIBS@
+GIR_CFLAGS= @GIR_CFLAGS@
+
IMAGEMAGICK_LIBS= @IMAGEMAGICK_LIBS@
IMAGEMAGICK_CFLAGS= @IMAGEMAGICK_CFLAGS@
$(C_SWITCH_MACHINE) $(C_SWITCH_SYSTEM) $(C_SWITCH_X_SITE) \
$(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \
$(LIBXML2_CFLAGS) $(DBUS_CFLAGS) $(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) \
+ $(WEBKIT_CFLAGS) $(CLUTTER_CFLAGS) $(GIR_CFLAGS) \
$(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \
$(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
$(LIBGNUTLS_CFLAGS) $(GFILENOTIFY_CFLAGS) \
process.o gnutls.o callproc.o \
region-cache.o sound.o atimer.o \
doprnt.o intervals.o textprop.o composite.o xml.o $(NOTIFY_OBJ) \
+ xwidget.o \
profiler.o decompress.o \
$(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \
$(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ)
obj = $(base_obj) $(NS_OBJC_OBJ)
+xwidget.o: xwidget.c xwidget.h
## Object files used on some machine or other.
## These go in the DOC file on all machines in case they are needed.
## Some of them have no DOC entries, but it does no harm to have them
LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \
$(LIBX_OTHER) $(LIBSOUND) \
$(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_ACL) $(LIB_CLOCK_GETTIME) \
+ $(WEBKIT_LIBS) $(CLUTTER_LIBS) $(GIR_LIBS) \
$(LIB_EACCESS) $(LIB_FDATASYNC) $(LIB_TIMER_TIME) $(DBUS_LIBS) \
$(LIB_EXECINFO) $(XRANDR_LIBS) $(XINERAMA_LIBS) \
$(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \
#include "keymap.h"
#include "frame.h"
+#ifdef HAVE_XWIDGETS
+#include "xwidget.h"
+#endif /* HAVE_XWIDGETS */
+
struct buffer *current_buffer; /* The current buffer. */
/* First buffer in chain of all buffers (in reverse order of creation).
kill_buffer_processes (buffer);
UNGCPRO;
+#ifdef HAVE_XWIDGETS
+ GCPRO1 (buffer);
+ kill_buffer_xwidgets (buffer);
+ UNGCPRO;
+#endif /* HAVE_XWIDGETS */
/* Killing buffer processes may run sentinels which may have killed
our buffer. */
if (!BUFFER_LIVE_P (b))
IMAGE_GLYPH,
/* Glyph is a space of fractional width and/or height. */
- STRETCH_GLYPH
+ STRETCH_GLYPH,
+#ifdef HAVE_XWIDGETS
+ /* Glyph is an external widget drawn by the GUI toolkit. */
+ XWIDGET_GLYPH
+#endif
};
/* Image ID for image glyphs (type == IMAGE_GLYPH). */
int img_id;
+#ifdef HAVE_XWIDGETS
+ struct xwidget* xwidget;
+#endif
/* Sub-structure for type == STRETCH_GLYPH. */
struct
{
/* Image, if any. */
struct image *img;
+#ifdef HAVE_XWIDGETS
+ struct xwidget* xwidget;
+#endif
/* Slice */
struct glyph_slice slice;
IT_TRUNCATION,
/* Continuation glyphs. See the comment for IT_TRUNCATION. */
- IT_CONTINUATION
+ IT_CONTINUATION,
+
+#ifdef HAVE_XWIDGETS
+ IT_XWIDGET
+#endif
};
GET_FROM_C_STRING,
GET_FROM_IMAGE,
GET_FROM_STRETCH,
+#ifdef HAVE_XWIDGETS
+ GET_FROM_XWIDGET,
+#endif
NUM_IT_METHODS
};
struct {
Lisp_Object object;
} stretch;
+#ifdef HAVE_XWIDGETS
+ /* method == GET_FROM_XWIDGET */
+ struct {
+ Lisp_Object object;
+ struct xwidget* xwidget;
+ } xwidget;
+#endif
} u;
/* current text and display positions. */
/* If what == IT_IMAGE, the id of the image to display. */
ptrdiff_t image_id;
+#ifdef HAVE_XWIDGETS
+ /* If what == IT_XWIDGET*/
+ struct xwidget* xwidget;
+#endif
/* Values from `slice' property. */
struct it_slice slice;
You should have received a copy of the GNU General Public License
along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
-
#include <config.h>
#define DISPEXTERN_INLINE EXTERN_INLINE
#include TERM_HEADER
#endif /* HAVE_WINDOW_SYSTEM */
+#ifdef HAVE_XWIDGETS
+#include "xwidget.h"
+#endif
+
#include <errno.h>
#include <fpending.h>
PAUSED_P means that the update has been interrupted for
pending input. */
-static void
-add_frame_display_history (struct frame *f, bool paused_p)
+static void add_frame_display_history (struct frame *f, int paused_p)
{
char *buf;
void *ptr = f;
add_window_display_history (w, w->current_matrix->method, paused_p);
#endif
+#ifdef HAVE_XWIDGETS
+ xwidget_end_redisplay(w, w->current_matrix);
+#endif
clear_glyph_matrix (desired_matrix);
return paused_p;
break;
}
+#ifdef HAVE_XWIDGETS
+ //currently this is needed to detect xwidget movement reliably. or probably not.
+ //printf("scrolling_window\n");
+ return 0;
+#endif
+
/* Give up if some rows in the desired matrix are not enabled. */
if (!MATRIX_ROW (desired_matrix, i)->enabled_p)
return -1;
#include "buffer.h"
#include "window.h"
+#ifdef HAVE_XWIDGETS
+#include "xwidget.h"
+#endif
#include "systty.h"
#include "atimer.h"
#include "blockinput.h"
syms_of_xfns ();
syms_of_xmenu ();
syms_of_fontset ();
+#ifdef HAVE_XWIDGETS
+ syms_of_xwidget();
+#endif
syms_of_xsettings ();
#ifdef HAVE_X_SM
syms_of_xsmfns ();
#include "lisp.h"
#include "frame.h"
#include "xterm.h"
+#ifdef HAVE_XWIDGETS
+#include "xwidget.h"
+#endif
#include "emacsgtkfixed.h"
/* Silence a bogus diagnostic; see GNOME bug 683906. */
# pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#endif
-#define EMACS_TYPE_FIXED emacs_fixed_get_type ()
-#define EMACS_FIXED(obj) \
- G_TYPE_CHECK_INSTANCE_CAST (obj, EMACS_TYPE_FIXED, EmacsFixed)
+//#define EMACS_TYPE_FIXED emacs_fixed_get_type ()
+/* #define EMACS_FIXED(obj) \ */
+/* G_TYPE_CHECK_INSTANCE_CAST (obj, EMACS_TYPE_FIXED, EmacsFixed) */
typedef struct _EmacsFixed EmacsFixed;
typedef struct _EmacsFixedPrivate EmacsFixedPrivate;
typedef struct _EmacsFixedClass EmacsFixedClass;
-struct _EmacsFixed
-{
- GtkFixed container;
+/* struct _EmacsFixed */
+/* { */
+/* GtkFixed container; */
- /*< private >*/
- EmacsFixedPrivate *priv;
-};
+/* /\*< private >*\/ */
+/* EmacsFixedPrivate *priv; */
+/* }; */
-struct _EmacsFixedClass
-{
- GtkFixedClass parent_class;
-};
+/* struct _EmacsFixedClass */
+/* { */
+/* GtkFixedClass parent_class; */
+/* }; */
struct _EmacsFixedPrivate
{
static void emacs_fixed_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural);
-static GType emacs_fixed_get_type (void);
G_DEFINE_TYPE (EmacsFixed, emacs_fixed, GTK_TYPE_FIXED)
+#ifdef HAVE_XWIDGETS
+/* void aloc_callback(GtkWidget* child, GtkWidget* fixed){ */
+/* GtkAllocation child_allocation; */
+/* GtkRequisition child_requisition; */
+
+/* //TODO */
+/* // if child is an xwidget, find its clipping area and modify allocation */
+
+/* struct xwidget_view* xv = (struct xwidget_view*) g_object_get_data (G_OBJECT (child), XG_XWIDGET_VIEW); */
+/* printf("aloc callback %d %s\n", xv, gtk_widget_get_name(child)); */
+/* if(xv){ */
+/* printf(" allocation modification for xw\n"); */
+/* gtk_widget_get_allocation(child, &child_allocation); */
+/* child_allocation.width = xv->clip_right; */
+/* child_allocation.height = xv->clip_bottom - xv->clip_top; */
+/* gtk_widget_size_allocate (child, &child_allocation); */
+/* //TODO find a way to remove this feeble workaround */
+/* } */
+
+/* } */
+
+struct GtkFixedPrivateL
+{
+ GList *children;
+};
+
+static void emacs_fixed_gtk_widget_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation){
+ //for xwidgets
+
+
+ //TODO 1st call base class method
+ EmacsFixedClass *klass;
+ GtkWidgetClass *parent_class;
+ struct GtkFixedPrivateL* priv;
+ GtkFixedChild *child;
+ GtkAllocation child_allocation;
+ GtkRequisition child_requisition;
+ GList *children;
+ struct xwidget_view* xv;
+
+ // printf(" emacs_fixed_gtk_widget_size_allocate\n");
+ klass = EMACS_FIXED_GET_CLASS (widget);
+ parent_class = g_type_class_peek_parent (klass);
+ parent_class->size_allocate (widget, allocation);
+
+ priv = G_TYPE_INSTANCE_GET_PRIVATE (widget,
+ GTK_TYPE_FIXED,
+ struct GtkFixedPrivateL);
+ //fixed->priv = G_TYPE_INSTANCE_GET_PRIVATE (fixed, GTK_TYPE_FIXED, GtkFixedPrivate);
+ //then modify allocations
+ /* gtk_container_foreach (widget, */
+ /* aloc_callback, */
+ /* widget); */
+
+ //begin copy paste extravaganza!!!
+
+ //GtkFixed *fixed = GTK_FIXED (widget);
+ //GtkFixedPrivate *priv = fixed->priv;
+
+
+ gtk_widget_set_allocation (widget, allocation);
+
+ if (gtk_widget_get_has_window (widget))
+ {
+ if (gtk_widget_get_realized (widget))
+ gdk_window_move_resize (gtk_widget_get_window (widget),
+ allocation->x,
+ allocation->y,
+ allocation->width,
+ allocation->height);
+ }
+
+ for (children = priv->children;
+ children;
+ children = children->next)
+ {
+ child = children->data;
+
+ if (!gtk_widget_get_visible (child->widget))
+ continue;
+
+ gtk_widget_get_preferred_size (child->widget, &child_requisition, NULL);
+ child_allocation.x = child->x;
+ child_allocation.y = child->y;
+
+ if (!gtk_widget_get_has_window (widget))
+ {
+ child_allocation.x += allocation->x;
+ child_allocation.y += allocation->y;
+ }
+
+ child_allocation.width = child_requisition.width;
+ child_allocation.height = child_requisition.height;
+
+
+
+ xv = (struct xwidget_view*) g_object_get_data (G_OBJECT (child->widget), XG_XWIDGET_VIEW);
+ //printf("aloc callback %d %s\n", xv, gtk_widget_get_name(child));
+ if(xv){
+ //gtk_widget_get_allocation(child, &child_allocation);
+ child_allocation.width = xv->clip_right;
+ child_allocation.height = xv->clip_bottom - xv->clip_top;
+ //gtk_widget_size_allocate (child, &child_allocation);
+ //TODO find a way to remove this feeble workaround
+ // printf(" allocation internal modification for xw %d %d,%d\n",xv, child_allocation.width, child_allocation.height);
+
+ }
+ gtk_widget_size_allocate (child->widget, &child_allocation);
+
+ }
+
+}
+
+#endif /* HAVE_XWIDGETS */
+
static void
emacs_fixed_class_init (EmacsFixedClass *klass)
{
GtkWidgetClass *widget_class;
+ GtkFixedClass *fixed_class;
widget_class = (GtkWidgetClass*) klass;
+ fixed_class = (GtkFixedClass*) klass;
widget_class->get_preferred_width = emacs_fixed_get_preferred_width;
widget_class->get_preferred_height = emacs_fixed_get_preferred_height;
+#ifdef HAVE_XWIDGETS
+ widget_class->size_allocate = emacs_fixed_gtk_widget_size_allocate;
+#endif
g_type_class_add_private (klass, sizeof (EmacsFixedPrivate));
}
+static GType
+emacs_fixed_child_type (GtkFixed *container)
+{
+ return GTK_TYPE_WIDGET;
+}
+
static void
emacs_fixed_init (EmacsFixed *fixed)
{
G_BEGIN_DECLS
+struct frame;
+
+#define EMACS_TYPE_FIXED (emacs_fixed_get_type ())
+#define EMACS_FIXED(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EMACS_TYPE_FIXED, EmacsFixed))
+#define EMACS_FIXED_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EMACS_TYPE_FIXED, EmacsFixedClass))
+#define EMACS_IS_FIXED(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EMACS_TYPE_FIXED))
+#define EMACS_IS_FIXED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EMACS_TYPE_FIXED))
+#define EMACS_FIXED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EMACS_TYPE_FIXED, EmacsFixedClass))
+
+//typedef struct _EmacsFixed EmacsFixed;
+typedef struct _EmacsFixedPrivate EmacsFixedPrivate;
+typedef struct _EmacsFixedClass EmacsFixedClass;
+
+struct _EmacsFixed
+{
+ GtkFixed container;
+
+ /*< private >*/
+ EmacsFixedPrivate *priv;
+};
+
+
+struct _EmacsFixedClass
+{
+ GtkFixedClass parent_class;
+};
+
extern GtkWidget *emacs_fixed_new (struct frame *f);
+extern GType emacs_fixed_get_type (void);
G_END_DECLS
#ifdef HAVE_DBUS
static Lisp_Object Qdbus_event;
#endif
+#ifdef HAVE_XWIDGETS
+Lisp_Object Qxwidget_event;
+#endif
#ifdef USE_FILE_NOTIFY
static Lisp_Object Qfile_notify;
#endif /* USE_FILE_NOTIFY */
obj = make_lispy_event (event);
kbd_fetch_ptr = event + 1;
}
+#endif
+#ifdef HAVE_XWIDGETS
+ else if (event->kind == XWIDGET_EVENT)
+ {
+ obj = make_lispy_event (event);
+ kbd_fetch_ptr = event + 1;
+ }
+#endif
+#ifdef HAVE_INOTIFY
+ else if (event->kind == FILE_NOTIFY_EVENT)
+ {
+ obj = make_lispy_event (event);
+ kbd_fetch_ptr = event + 1;
+ }
#endif
else if (event->kind == CONFIG_CHANGED_EVENT)
{
}
#endif /* HAVE_DBUS */
+#ifdef HAVE_XWIDGETS
+ case XWIDGET_EVENT:
+ {
+ printf("cool, an xwidget event arrived in make_lispy_event!\n");
+ return Fcons (Qxwidget_event,event->arg);
+ }
+#endif /* HAVE_XWIDGETS */
+
+
#if defined HAVE_GFILENOTIFY || defined HAVE_INOTIFY
case FILE_NOTIFY_EVENT:
{
DEFSYM (Qdbus_event, "dbus-event");
#endif
+#ifdef HAVE_XWIDGETS
+ Qxwidget_event = intern ("xwidget-event");
+ staticpro (&Qxwidget_event);
+#endif /* HAVE_XWIDGETS */
#ifdef USE_FILE_NOTIFY
DEFSYM (Qfile_notify, "file-notify");
#endif /* USE_FILE_NOTIFY */
PVEC_WINDOW_CONFIGURATION,
PVEC_SUBR,
PVEC_OTHER,
+#ifdef HAVE_XWIDGETS
+ PVEC_XWIDGET,
+ PVEC_XWIDGET_VIEW,
+#endif
+
/* These should be last, check internal_equal to see why. */
PVEC_COMPILED,
PVEC_CHAR_TABLE,
#include "blockinput.h"
#include "termhooks.h" /* For struct terminal. */
#include "font.h"
-
+#ifdef HAVE_XWIDGETS
+#include "xwidget.h"
+#endif
Lisp_Object Qstandard_output;
static Lisp_Object Qtemp_buffer_setup_hook;
strout (XSUBR (obj)->symbol_name, -1, -1, printcharfun);
PRINTCHAR ('>');
}
+#ifdef HAVE_XWIDGETS
+ else if (XWIDGETP (obj))
+ {
+ strout ("#<xwidget ", -1, -1, printcharfun);
+ PRINTCHAR ('>');
+ }
+ else if (XWIDGET_VIEW_P (obj))
+ {
+ strout ("#<xwidget-view ", -1, -1, printcharfun);
+ PRINTCHAR ('>');
+ }
+#endif
else if (WINDOWP (obj))
{
void *ptr = XWINDOW (obj);
/* Non-key system events (e.g. application menu events) */
, NS_NONKEY_EVENT
#endif
-
+#ifdef HAVE_XWIDGETS
+ /* events generated by xwidgets*/
+ , XWIDGET_EVENT
+#endif
#ifdef USE_FILE_NOTIFY
/* File or directory was changed. */
, FILE_NOTIFY_EVENT
#ifdef MSDOS
#include "msdos.h"
#endif
+#ifdef HAVE_NS
+#include "nsterm.h"
+#endif
+#ifdef HAVE_XWIDGETS
+#include "xwidget.h"
+#endif
Lisp_Object Qwindowp, Qwindow_live_p;
static Lisp_Object Qwindow_valid_p;
/* Block input. */
block_input ();
+#ifdef HAVE_XWIDGETS
+ xwidget_view_delete_all_in_window(w);
+#endif
window_resize_apply (p, horflag);
/* If this window is referred to by the dpyinfo's mouse
#include TERM_HEADER
#endif /* HAVE_WINDOW_SYSTEM */
+#include "font.h"
+#ifdef HAVE_XWIDGETS
+#include "xwidget.h"
+#endif
#ifndef FRAME_X_OUTPUT
#define FRAME_X_OUTPUT(f) ((f)->output_data.x)
#endif
static int next_element_from_buffer (struct it *);
static int next_element_from_composition (struct it *);
static int next_element_from_image (struct it *);
+#ifdef HAVE_XWIDGETS
+static int next_element_from_xwidget(struct it *);
+#endif
static int next_element_from_stretch (struct it *);
static void load_overlay_strings (struct it *, ptrdiff_t);
static int init_from_display_pos (struct it *, struct window *,
if (CONSP (spec)
/* Simple specifications. */
&& !EQ (XCAR (spec), Qimage)
+#ifdef HAVE_XWIDGETS
+ && !EQ (XCAR (spec), Qxwidget)
+#endif
&& !EQ (XCAR (spec), Qspace)
&& !EQ (XCAR (spec), Qwhen)
&& !EQ (XCAR (spec), Qslice)
|| ((it ? FRAME_WINDOW_P (it->f) : frame_window_p)
&& valid_image_p (value))
#endif /* not HAVE_WINDOW_SYSTEM */
- || (CONSP (value) && EQ (XCAR (value), Qspace)));
+ || (CONSP (value) && EQ (XCAR (value), Qspace))
+#ifdef HAVE_XWIDGETS
+ || valid_xwidget_spec_p(value)
+#endif
+ );
if (valid_p && !display_replaced_p)
{
*position = it->position = start_pos;
retval = 1 + (it->area == TEXT_AREA);
}
+#ifdef HAVE_XWIDGETS
+ else if (valid_xwidget_spec_p(value))
+ {
+ //printf("handle_single_display_spec: im an xwidget!!\n");
+ it->what = IT_XWIDGET;
+ it->method = GET_FROM_XWIDGET;
+ it->position = start_pos;
+ it->object = NILP (object) ? it->w->contents : object;
+ *position = start_pos;
+
+ it->xwidget = lookup_xwidget(value);
+ }
+#endif
#ifdef HAVE_WINDOW_SYSTEM
else
{
case GET_FROM_STRETCH:
p->u.stretch.object = it->object;
break;
+#ifdef HAVE_XWIDGETS
+ case GET_FROM_XWIDGET:
+ p->u.xwidget.object = it->object;
+ break;
+#endif
}
p->position = position ? *position : it->position;
p->current = it->current;
it->object = p->u.image.object;
it->slice = p->u.image.slice;
break;
+#ifdef HAVE_XWIDGETS
+ case GET_FROM_XWIDGET:
+ it->object = p->u.xwidget.object;
+ break;
+#endif
case GET_FROM_STRETCH:
it->object = p->u.stretch.object;
break;
next_element_from_c_string,
next_element_from_image,
next_element_from_stretch
+#ifdef HAVE_XWIDGETS
+ ,next_element_from_xwidget
+#endif
};
#define GET_NEXT_DISPLAY_ELEMENT(it) (*get_next_element[(it)->method]) (it)
case GET_FROM_IMAGE:
case GET_FROM_STRETCH:
+#ifdef HAVE_XWIDGETS
+ case GET_FROM_XWIDGET:
+
/* The position etc with which we have to proceed are on
the stack. The position may be at the end of a string,
if the `display' property takes up the whole string. */
if (it->method == GET_FROM_STRING)
goto consider_string_end;
break;
-
+#endif
default:
/* There are no other methods defined, so this should be a bug. */
emacs_abort ();
return 1;
}
+#ifdef HAVE_XWIDGETS
+/* im not sure about this FIXME JAVE*/
+static int
+next_element_from_xwidget (struct it *it)
+{
+ it->what = IT_XWIDGET;
+ //assert_valid_xwidget_id(it->xwidget_id,"next_element_from_xwidget");
+ //this is shaky because why do we set "what" if we dont set the other parts??
+ //printf("xwidget_id %d: in next_element_from_xwidget: FIXME \n", it->xwidget_id);
+ return 1;
+}
+#endif
+
/* Fill iterator IT with next display element from a stretch glyph
property. IT->object is the value of the text property. Value is
*w->desired_matrix->method = 0;
debug_method_add (w, "optimization 1");
#endif
+#if HAVE_XWIDGETS
+ //debug optimization movement issue
+ //w->desired_matrix->no_scrolling_p = 1;
+ //*w->desired_matrix->method = 0;
+ //debug_method_add (w, "optimization 1");
+#endif
+
#ifdef HAVE_WINDOW_SYSTEM
update_window_fringes (w, 0);
#endif
/* Initialize iterator and info to start at POS. */
start_display (&it, w, pos);
+
+
/* Display all lines of W. */
while (it.current_y < it.last_visible_y)
{
if (f->fonts_changed && !(flags & TRY_WINDOW_IGNORE_FONTS_CHANGE))
return 0;
}
+#ifdef HAVE_XWIDGETS_xxx
+ //currently this is needed to detect xwidget movement reliably. or probably not.
+ printf("try_window\n");
+ return 0;
+#endif
/* Don't let the cursor end in the scroll margins. */
if ((flags & TRY_WINDOW_CHECK_MARGINS)
return 0;
#endif
+#ifdef HAVE_XWIDGETS_xxx
+ //currently this is needed to detect xwidget movement reliably. or probably not.
+ printf("try_window_reusing_current_matrix\n");
+ return 0;
+#endif
+
+
if (/* This function doesn't handle terminal frames. */
!FRAME_WINDOW_P (f)
/* Don't try to reuse the display if windows have been split
return 0;
#endif
+#ifdef HAVE_XWIDGETS_xxx
+ //maybe needed for proper xwidget movement
+ printf("try_window_id\n");
+ return -1;
+#endif
+
+
/* This is handy for debugging. */
#if 0
#define GIVE_UP(X) \
glyph->left_box_line_p,
glyph->right_box_line_p);
}
+#ifdef HAVE_XWIDGETS
+ else if (glyph->type == XWIDGET_GLYPH)
+ {
+ fprintf (stderr,
+ " %5d %4c %6d %c %3d 0x%05x %c %4d %1.1d%1.1d\n",
+ glyph - row->glyphs[TEXT_AREA],
+ 'X',
+ glyph->charpos,
+ (BUFFERP (glyph->object)
+ ? 'B'
+ : (STRINGP (glyph->object)
+ ? 'S'
+ : '-')),
+ glyph->pixel_width,
+ glyph->u.xwidget,
+ '.',
+ glyph->face_id,
+ glyph->left_box_line_p,
+ glyph->right_box_line_p);
+
+ // printf("dump xwidget glyph\n");
+ }
+#endif
}
return OK_PIXELS (width_p ? img->width : img->height);
}
+#ifdef HAVE_XWIDGETS
+ if (FRAME_WINDOW_P (it->f) && valid_xwidget_spec_p (prop))
+ {
+ printf("calc_pixel_width_or_height: return dummy size FIXME\n");
+ return OK_PIXELS (width_p ? 100 : 100);
+ }
+#endif
#endif
if (EQ (car, Qplus) || EQ (car, Qminus))
{
s->ybase += s->first_glyph->voffset;
}
-
+#ifdef HAVE_XWIDGETS
+static void
+fill_xwidget_glyph_string (struct glyph_string *s)
+{
+ eassert (s->first_glyph->type == XWIDGET_GLYPH);
+ printf("fill_xwidget_glyph_string: width:%d \n",s->first_glyph->pixel_width);
+ s->face = FACE_FROM_ID (s->f, s->first_glyph->face_id);
+ s->font = s->face->font;
+ s->width = s->first_glyph->pixel_width;
+ s->ybase += s->first_glyph->voffset;
+ s->xwidget = s->first_glyph->u.xwidget;
+ //assert_valid_xwidget_id ( s->xwidget, "fill_xwidget_glyph_string");
+}
+#endif
/* Fill glyph string S from a sequence of stretch glyphs.
START is the index of the first glyph to consider,
} \
while (0)
+#ifdef HAVE_XWIDGETS
+#define BUILD_XWIDGET_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ do \
+ { \
+ printf("BUILD_XWIDGET_GLYPH_STRING\n"); \
+ s = (struct glyph_string *) alloca (sizeof *s); \
+ INIT_GLYPH_STRING (s, NULL, w, row, area, START, HL); \
+ fill_xwidget_glyph_string (s); \
+ append_glyph_string (&HEAD, &TAIL, s); \
+ ++START; \
+ s->x = (X); \
+ } \
+ while (0)
+#endif
+
/* Add a glyph string for a sequence of character glyphs to the list
of strings between HEAD and TAIL. START is the index of the first
to allocate glyph strings (because draw_glyphs can be called
asynchronously). */
-#define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X) \
+#define BUILD_GLYPH_STRINGS_1(START, END, HEAD, TAIL, HL, X, LAST_X) \
do \
{ \
HEAD = TAIL = NULL; \
case IMAGE_GLYPH: \
BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
- break; \
- \
+ break;
+
+#define BUILD_GLYPH_STRINGS_XW(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ case XWIDGET_GLYPH: \
+ BUILD_XWIDGET_GLYPH_STRING (START, END, HEAD, TAIL, \
+ HL, X, LAST_X); \
+ break;
+
+#define BUILD_GLYPH_STRINGS_2(START, END, HEAD, TAIL, HL, X, LAST_X) \
case GLYPHLESS_GLYPH: \
BUILD_GLYPHLESS_GLYPH_STRING (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
} while (0)
+#ifdef HAVE_XWIDGETS
+#define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X) \
+BUILD_GLYPH_STRINGS_1(START, END, HEAD, TAIL, HL, X, LAST_X) \
+BUILD_GLYPH_STRINGS_XW(START, END, HEAD, TAIL, HL, X, LAST_X) \
+BUILD_GLYPH_STRINGS_2(START, END, HEAD, TAIL, HL, X, LAST_X)
+#else
+#define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X) \
+BUILD_GLYPH_STRINGS_1(START, END, HEAD, TAIL, HL, X, LAST_X) \
+BUILD_GLYPH_STRINGS_2(START, END, HEAD, TAIL, HL, X, LAST_X)
+#endif
+
+
/* Draw glyphs between START and END in AREA of ROW on window W,
starting at x-position X. X is relative to AREA in W. HL is a
face-override with the following meaning:
}
}
+#ifdef HAVE_XWIDGETS
+static void
+produce_xwidget_glyph (struct it *it)
+{
+ struct xwidget* xw;
+ struct face *face;
+ int glyph_ascent, crop;
+ printf("produce_xwidget_glyph:\n");
+ eassert (it->what == IT_XWIDGET);
+
+ face = FACE_FROM_ID (it->f, it->face_id);
+ eassert (face);
+ /* Make sure X resources of the face is loaded. */
+ PREPARE_FACE_FOR_DISPLAY (it->f, face);
+
+ xw = it->xwidget;
+ it->ascent = it->phys_ascent = glyph_ascent = xw->height/2;
+ it->descent = xw->height/2;
+ it->phys_descent = it->descent;
+ it->pixel_width = xw->width;
+ /* It's quite possible for images to have an ascent greater than
+ their height, so don't get confused in that case. */
+ if (it->descent < 0)
+ it->descent = 0;
+
+ it->nglyphs = 1;
+
+ if (face->box != FACE_NO_BOX)
+ {
+ if (face->box_line_width > 0)
+ {
+ it->ascent += face->box_line_width;
+ it->descent += face->box_line_width;
+ }
+
+ if (it->start_of_box_run_p)
+ it->pixel_width += eabs (face->box_line_width);
+ it->pixel_width += eabs (face->box_line_width);
+ }
+
+ take_vertical_position_into_account (it);
+
+ /* Automatically crop wide image glyphs at right edge so we can
+ draw the cursor on same display row. */
+ if ((crop = it->pixel_width - (it->last_visible_x - it->current_x), crop > 0)
+ && (it->hpos == 0 || it->pixel_width > it->last_visible_x / 4))
+ {
+ it->pixel_width -= crop;
+ }
+
+ if (it->glyph_row)
+ {
+ struct glyph *glyph;
+ enum glyph_row_area area = it->area;
+
+ glyph = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+ if (glyph < it->glyph_row->glyphs[area + 1])
+ {
+ glyph->charpos = CHARPOS (it->position);
+ glyph->object = it->object;
+ glyph->pixel_width = it->pixel_width;
+ glyph->ascent = glyph_ascent;
+ glyph->descent = it->descent;
+ glyph->voffset = it->voffset;
+ glyph->type = XWIDGET_GLYPH;
+
+ glyph->multibyte_p = it->multibyte_p;
+ glyph->left_box_line_p = it->start_of_box_run_p;
+ glyph->right_box_line_p = it->end_of_box_run_p;
+ glyph->overlaps_vertically_p = 0;
+ glyph->padding_p = 0;
+ glyph->glyph_not_available_p = 0;
+ glyph->face_id = it->face_id;
+ glyph->u.xwidget = it->xwidget;
+ //assert_valid_xwidget_id(glyph->u.xwidget_id,"produce_xwidget_glyph");
+ glyph->font_type = FONT_TYPE_UNKNOWN;
+ ++it->glyph_row->used[area];
+ }
+ else
+ IT_EXPAND_MATRIX_WIDTH (it, area);
+ }
+}
+#endif
/* Append a stretch glyph to IT->glyph_row. OBJECT is the source
of the glyph, WIDTH and HEIGHT are the width and height of the
produce_image_glyph (it);
else if (it->what == IT_STRETCH)
produce_stretch_glyph (it);
-
+#ifdef HAVE_XWIDGETS
+ else if (it->what == IT_XWIDGET)
+ produce_xwidget_glyph (it);
+#endif
done:
/* Accumulate dimensions. Note: can't assume that it->descent > 0
because this isn't true for images with `:ascent 100'. */
/* Use normal cursor if not blinked off. */
if (!w->cursor_off_p)
{
+
+#ifdef HAVE_XWIDGETS
+ if (glyph != NULL && glyph->type == XWIDGET_GLYPH){
+ //printf("attempt xwidget cursor avoidance in get_window_cursor_type\n");
+ return NO_CURSOR;
+ }
+#endif
if (glyph != NULL && glyph->type == IMAGE_GLYPH)
{
if (cursor_type == FILLED_BOX_CURSOR)
#include "coding.h"
#include "frame.h"
#include "dispextern.h"
+#ifdef HAVE_XWIDGETS
+#include "xwidget.h"
+#endif
#include "fontset.h"
#include "termhooks.h"
#include "termopts.h"
case IMAGE_GLYPH:
x_draw_image_glyph_string (s);
break;
-
+#ifdef HAVE_XWIDGETS
+ case XWIDGET_GLYPH:
+ //erase xwidget background
+ //x_draw_glyph_string_background (s, 0);
+ x_draw_xwidget_glyph_string (s);
+ break;
+#endif
case STRETCH_GLYPH:
x_draw_stretch_glyph_string (s);
break;
cursor_glyph = get_phys_cursor_glyph (w);
if (cursor_glyph == NULL)
return;
-
+#ifdef HAVE_XWIDGETS
+ if (cursor_glyph->type == XWIDGET_GLYPH){
+ printf("tried avoiding xwidget cursor\n");
+ return; //experimental avoidance of cursor on xwidget
+ }
+#endif
/* If on an image, draw like a normal cursor. That's usually better
visible than drawing a bar, esp. if the image is large so that
the bar might not be in the window. */
https://bugzilla.gnome.org/show_bug.cgi?id=563627. */
id = g_log_set_handler ("GLib", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL
| G_LOG_FLAG_RECURSION, my_log_handler, NULL);
+#ifdef HAVE_CLUTTER
+ gtk_clutter_init (&argc, &argv2);
+#else
/* NULL window -> events for all windows go to our function.
Call before gtk_init so Gtk+ event filters comes after our. */
/* gtk_init does set_locale. Fix locale before and after. */
fixup_locale ();
gtk_init (&argc, &argv2);
+#endif
fixup_locale ();
g_log_remove_handler ("GLib", id);
--- /dev/null
+#include <config.h>
+#ifdef HAVE_XWIDGETS
+
+#include <signal.h>
+
+#include <stdio.h>
+#include <setjmp.h>
+#ifdef HAVE_X_WINDOWS
+
+#include "lisp.h"
+#include "blockinput.h"
+#include "syssignal.h"
+
+#include "xterm.h"
+#include <X11/cursorfont.h>
+
+#ifndef makedev
+#include <sys/types.h>
+#endif /* makedev */
+
+#ifdef BSD_SYSTEM
+#include <sys/ioctl.h>
+#endif /* ! defined (BSD_SYSTEM) */
+
+#include "systime.h"
+
+#ifndef INCLUDED_FCNTL
+#include <fcntl.h>
+#endif
+#include <ctype.h>
+#include <errno.h>
+#include <setjmp.h>
+#include <sys/stat.h>
+
+#include "charset.h"
+#include "character.h"
+#include "coding.h"
+#include "ccl.h"
+#include "frame.h"
+#include "dispextern.h"
+#include "fontset.h"
+#include "termhooks.h"
+#include "termopts.h"
+#include "termchar.h"
+#include "emacs-icon.h"
+#include "disptab.h"
+#include "buffer.h"
+#include "window.h"
+#include "keyboard.h"
+#include "intervals.h"
+#include "process.h"
+#include "atimer.h"
+#include "keymap.h"
+
+
+#ifdef USE_X_TOOLKIT
+#include <X11/Shell.h>
+#endif
+#include <X11/extensions/Xcomposite.h>
+#include <X11/extensions/Xrender.h>
+#include <cairo.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "gtkutil.h"
+#include "font.h"
+#endif /* HAVE_X_WINDOWS */
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+#ifdef HAVE_GTK3
+//for gtk3; sockets and plugs
+#include <gtk/gtkx.h>
+#include "emacsgtkfixed.h"
+#endif
+
+#include <wchar.h>
+
+#ifdef HAVE_WEBKIT_OSR
+#include <webkit/webkitwebview.h>
+#include <webkit/webkitwebplugindatabase.h>
+#include <webkit/webkitwebplugin.h>
+#include <webkit/webkitglobals.h>
+#include <webkit/webkitwebnavigationaction.h>
+#include <webkit/webkitdownload.h>
+#include <webkit/webkitwebpolicydecision.h>
+#endif
+
+//for GIR
+#include <girepository.h>
+
+#include "xwidget.h"
+
+//TODO embryo of lisp allocators for xwidgets
+//TODO xwidget* should be Lisp_xwidget*
+struct xwidget*
+allocate_xwidget (void)
+{
+ return ALLOCATE_PSEUDOVECTOR (struct xwidget, height, PVEC_XWIDGET);
+}
+
+//TODO xwidget_view* should be Lisp_xwidget_view*
+struct xwidget_view*
+allocate_xwidget_view (void)
+{
+ return ALLOCATE_PSEUDOVECTOR (struct xwidget_view, redisplayed, PVEC_XWIDGET_VIEW);
+}
+#define XSETXWIDGET(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET))
+#define XSETXWIDGET_VIEW(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW))
+
+Lisp_Object Qxwidget;
+Lisp_Object QCxwidget;
+Lisp_Object QCtitle;
+Lisp_Object Qxwidget_set_keyboard_grab;
+Lisp_Object Qxwidget_embed_steal_window;
+Lisp_Object Qxwidget_info;
+Lisp_Object Qxwidget_resize;
+Lisp_Object Qxwidget_send_keyboard_event;
+Lisp_Object QCxwgir_class;
+Lisp_Object Qbutton, Qtoggle, Qslider, Qsocket, Qsocket_osr, Qcairo, Qxwgir,
+ Qwebkit_osr, QCplist;
+Lisp_Object Qxwidgetp, Qxwidget_view_p;
+
+
+extern Lisp_Object QCtype;
+extern Lisp_Object QCwidth, QCheight;
+
+struct xwidget_view* xwidget_view_lookup(struct xwidget* xw, struct window *w);
+Lisp_Object xwidget_spec_value ( Lisp_Object spec, Lisp_Object key, int *found);
+gboolean offscreen_damage_event (GtkWidget *widget, GdkEvent *event, gpointer data);
+void webkit_osr_document_load_finished_callback (WebKitWebView *webkitwebview,
+ WebKitWebFrame *arg1,
+ gpointer user_data);
+gboolean webkit_osr_download_callback (WebKitWebView *webkitwebview,
+ WebKitDownload *arg1,
+ gpointer data);
+
+gboolean webkit_osr_mime_type_policy_typedecision_requested_callback(WebKitWebView *webView,
+ WebKitWebFrame *frame,
+ WebKitNetworkRequest *request,
+ gchar *mimetype,
+ WebKitWebPolicyDecision *policy_decision,
+ gpointer user_data);
+
+gboolean webkit_osr_new_window_policy_decision_requested_callback(WebKitWebView *webView,
+ WebKitWebFrame *frame,
+ WebKitNetworkRequest *request,
+ WebKitWebNavigationAction *navigation_action,
+ WebKitWebPolicyDecision *policy_decision,
+ gpointer user_data);
+
+
+gboolean webkit_osr_navigation_policy_decision_requested_callback(WebKitWebView *webView,
+ WebKitWebFrame *frame,
+ WebKitNetworkRequest *request,
+ WebKitWebNavigationAction *navigation_action,
+ WebKitWebPolicyDecision *policy_decision,
+ gpointer user_data);
+
+GtkWidget* xwgir_create(char* class, char* namespace);
+static void
+send_xembed_ready_event (struct xwidget* xw, int xembedid);
+DEFUN ("make-xwidget", Fmake_xwidget, Smake_xwidget, 7, 8, 0,
+ doc: /* Make an xwidget from BEG to END of TYPE.
+
+If BUFFER is nil it uses the current buffer. If BUFFER is a string and
+no such buffer exists, it is created.
+
+TYPE is a symbol which can take one of the following values:
+- Button
+- ToggleButton
+- slider
+- socket
+- socket-osr
+- cairo
+*/
+ )
+ (Lisp_Object beg, Lisp_Object end,
+ Lisp_Object type,
+ Lisp_Object title,
+ Lisp_Object width, Lisp_Object height,
+ Lisp_Object data,
+ Lisp_Object buffer)
+{
+ //should work a bit like "make-button"(make-button BEG END &rest PROPERTIES)
+ // arg "type" and fwd should be keyword args eventually
+ //(make-xwidget 3 3 'button "oei" 31 31 nil)
+ //(xwidget-info (car xwidget-list))
+ struct xwidget* xw = allocate_xwidget();
+ Lisp_Object val;
+ xw->type = type;
+ xw->title = title;
+ if (NILP (buffer))
+ buffer = Fcurrent_buffer(); // no need to gcpro because Fcurrent_buffer doesn't call Feval/eval_sub.
+ else
+ buffer = Fget_buffer_create (buffer);
+ xw->buffer = buffer;
+
+ xw->height = XFASTINT(height);
+ xw->width = XFASTINT(width);
+ xw->kill_without_query = 0;
+ XSETXWIDGET (val, xw); // set the vectorlike_header of VAL with the correct value
+ Vxwidget_list = Fcons (val, Vxwidget_list);
+ xw->widgetwindow_osr = NULL;
+ xw->widget_osr = NULL;
+ xw->plist = Qnil;
+
+
+#ifdef HAVE_WEBKIT_OSR
+ /* DIY mvc. widget is rendered offscreen,
+ later bitmap copied to the views.
+ */
+ if (EQ(xw->type, Qwebkit_osr)||
+ EQ(xw->type, Qsocket_osr)||
+ (!NILP (Fget(xw->type, QCxwgir_class)))) {
+ block_input();
+ xw->widgetwindow_osr = gtk_offscreen_window_new ();
+ gtk_window_resize(GTK_WINDOW(xw->widgetwindow_osr), xw->width, xw->height);
+
+ if (EQ(xw->type, Qwebkit_osr))
+ xw->widget_osr = webkit_web_view_new();
+ if(EQ(xw->type, Qsocket_osr))
+ xw->widget_osr = gtk_socket_new();
+ if(!NILP (Fget(xw->type, QCxwgir_class)))
+ xw->widget_osr = xwgir_create(SDATA(Fcar(Fcdr(Fget(xw->type, QCxwgir_class)))),
+ SDATA(Fcar(Fget(xw->type, QCxwgir_class))));
+
+ gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height);
+ gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr), xw->widget_osr);
+
+ gtk_widget_show (xw->widget_osr);
+ gtk_widget_show (xw->widgetwindow_osr);
+
+ /* store some xwidget data in the gtk widgets for convenient retrieval in the event handlers. */
+ g_object_set_data (G_OBJECT (xw->widget_osr), XG_XWIDGET, (gpointer) (xw));
+ g_object_set_data (G_OBJECT (xw->widgetwindow_osr), XG_XWIDGET, (gpointer) (xw));
+
+ /* signals */
+ if (EQ(xw->type, Qwebkit_osr)) {
+ g_signal_connect (G_OBJECT (xw->widget_osr),
+ "document-load-finished",
+ G_CALLBACK (webkit_osr_document_load_finished_callback),
+ xw);
+
+ g_signal_connect (G_OBJECT (xw->widget_osr),
+ "download-requested",
+ G_CALLBACK (webkit_osr_download_callback),
+ xw);
+
+ g_signal_connect (G_OBJECT (xw->widget_osr),
+ "mime-type-policy-decision-requested",
+ G_CALLBACK (webkit_osr_mime_type_policy_typedecision_requested_callback),
+ xw);
+
+ g_signal_connect (G_OBJECT (xw->widget_osr),
+ "new-window-policy-decision-requested",
+ G_CALLBACK (webkit_osr_new_window_policy_decision_requested_callback),
+ xw);
+
+ g_signal_connect (G_OBJECT (xw->widget_osr),
+ "navigation-policy-decision-requested",
+ G_CALLBACK (webkit_osr_navigation_policy_decision_requested_callback),
+ xw);
+ }
+
+ if (EQ(xw->type, Qsocket_osr)) {
+ send_xembed_ready_event (xw, gtk_socket_get_id (GTK_SOCKET (xw->widget_osr)));
+ //gtk_widget_realize(xw->widget);
+ }
+
+
+ unblock_input();
+
+ }
+#endif /* HAVE_WEBKIT_OSR */
+
+ return val;
+}
+
+DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets, Sget_buffer_xwidgets, 1, 1, 0,
+ doc: /* Return the xwidgets associated with BUFFER.
+BUFFER may be a buffer or the name of one.
+ */
+ )
+ (Lisp_Object buffer)
+{
+ Lisp_Object xw, tail, xw_list;
+
+ if (NILP (buffer)) return Qnil;
+ buffer = Fget_buffer (buffer);
+ if (NILP (buffer)) return Qnil;
+
+ xw_list = Qnil;
+
+ for (tail = Vxwidget_list; CONSP (tail); tail = XCDR (tail))
+ {
+ xw = XCAR (tail);
+ if (XWIDGETP (xw) && EQ (Fxwidget_buffer (xw), buffer))
+ xw_list = Fcons (xw, xw_list);
+ }
+ return xw_list;
+}
+
+int
+xwidget_hidden(struct xwidget_view *xv)
+{
+ return xv->hidden;
+}
+
+
+static void
+buttonclick_handler (GtkWidget * widget, gpointer data)
+{
+ Lisp_Object xwidget_view, xwidget;
+ XSETXWIDGET_VIEW (xwidget_view, (struct xwidget_view *) data);
+ xwidget = Fxwidget_view_model (xwidget_view);
+
+ struct input_event event;
+ Lisp_Object frame = Fwindow_frame (Fxwidget_view_window (xwidget_view));
+ struct frame *f = XFRAME (frame);
+ printf ("button clicked xw:%d '%s'\n", XXWIDGET (xwidget), XXWIDGET (xwidget)->title);
+
+ EVENT_INIT (event);
+ event.kind = XWIDGET_EVENT;
+
+ event.frame_or_window = frame;
+
+ event.arg = Qnil;
+ event.arg = Fcons (xwidget, event.arg);
+ event.arg = Fcons (intern ("buttonclick"), event.arg);
+
+ kbd_buffer_store_event (&event);
+}
+
+
+static void
+send_xembed_ready_event (struct xwidget* xw, int xembedid)
+{
+ Lisp_Object xw_lo;
+ XSETXWIDGET(xw_lo, xw);
+ struct input_event event;
+ EVENT_INIT (event);
+ event.kind = XWIDGET_EVENT;
+ event.frame_or_window = Qnil; //frame; //how to get the frame here? //TODO i store it in the xwidget now
+
+ event.arg = Qnil;
+ event.arg = Fcons (make_number (xembedid), event.arg);
+ event.arg = Fcons (xw_lo, event.arg);
+ event.arg = Fcons (intern ("xembed-ready"), event.arg);
+
+
+ kbd_buffer_store_event (&event);
+
+}
+
+void
+xwidget_show_view (struct xwidget_view *xv)
+{
+ xv->hidden = 0;
+ gtk_widget_show(xv->widgetwindow);
+ gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow, xv->x + xv->clip_left, xv->y + xv->clip_top); //TODO refactor
+}
+
+
+/* hide an xvidget view */
+void
+xwidget_hide_view (struct xwidget_view *xv)
+{
+ xv->hidden = 1;
+ //gtk_widget_hide(xw->widgetwindow);
+ gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow,
+ 10000, 10000);
+}
+
+
+void
+xwidget_plug_added(GtkSocket *socket,
+ gpointer user_data)
+{
+ //hmm this doesnt seem to get called for foreign windows
+ printf("xwidget_plug_added\n");
+}
+
+gboolean
+xwidget_plug_removed(GtkSocket *socket,
+ gpointer user_data)
+{
+ printf("xwidget_plug_removed\n");
+ return TRUE; /* dont run the default handler because that kills the socket and we want to reuse it*/
+}
+
+
+void
+xwidget_slider_changed (GtkRange *range,
+ gpointer user_data)
+{
+ //slider value changed. change value of siblings
+ //correspondingly. but remember that changing value will again
+ //trigger signal
+
+ //TODO MVC view storage wont be an array futureish so the loop needs to change eventually
+ //TODO MVC it would be nice if this code could be reusable but, alas, C is not a functional language
+ //issues are:
+ // - the type of the controllers value (double, boolean etc)
+ // - the getter and setter (but they can be func pointers)
+ // a behemoth macro is always an option.
+ double v=gtk_range_get_value(range);
+ struct xwidget_view* xvp = g_object_get_data (G_OBJECT (range), XG_XWIDGET_VIEW);
+ struct xwidget_view* xv;
+
+ printf("slider changed val:%f\n", v);
+
+ for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
+ {
+ if (XWIDGET_VIEW_P (XCAR (tail))) {
+ xv = XXWIDGET_VIEW (XCAR (tail));
+ if (EQ (xvp->model, xv->model)) {
+ //block sibling views signal handlers
+ g_signal_handler_block(xv->widget, xv->handler_id);
+
+ //set values of sibling views and unblock
+ gtk_range_set_value(GTK_RANGE(xv->widget), v);
+ g_signal_handler_unblock(xv->widget,xv->handler_id);
+ }
+ }
+ }
+}
+
+
+/* when the off-screen webkit master view changes this signal is called.
+ it copies the bitmap from the off-screen webkit instance */
+gboolean
+offscreen_damage_event (GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+ //TODO this is wrong! should just queu a redraw of onscreen widget
+ gtk_widget_queue_draw (GTK_WIDGET (data));
+ return FALSE;
+}
+
+void
+store_xwidget_event_string(struct xwidget* xw, char* eventname, const char* eventstr)
+{
+ //refactor attempt
+ struct input_event event;
+ Lisp_Object xwl;
+ XSETXWIDGET(xwl,xw);
+ EVENT_INIT (event);
+ event.kind = XWIDGET_EVENT;
+ event.frame_or_window = Qnil; //frame; //how to get the frame here? //TODO i store it in the xwidget now
+
+ event.arg = Qnil;
+ event.arg = Fcons (build_string(eventstr), event.arg); //string so dont intern
+ event.arg = Fcons (xwl, event.arg); //TODO
+ event.arg = Fcons (intern (eventname), event.arg);//interning should be ok
+ kbd_buffer_store_event (&event);
+
+}
+
+//TODO deprecated, use load-status
+void
+webkit_osr_document_load_finished_callback (WebKitWebView *webkitwebview,
+ WebKitWebFrame *arg1,
+ gpointer data)
+{
+ //TODO this event sending code should be refactored
+ // struct xwidget *xw = (struct xwidget *) data;
+ struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webkitwebview), XG_XWIDGET);
+ printf("webkit finished loading\n");
+
+ store_xwidget_event_string(xw,
+ "document-load-finished", "");
+}
+
+gboolean
+webkit_osr_download_callback (WebKitWebView *webkitwebview,
+ WebKitDownload *arg1,
+ gpointer data)
+{
+ //TODO this event sending code should be refactored
+ struct input_event event;
+ // struct xwidget *xw = (struct xwidget *) data;
+ struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webkitwebview), XG_XWIDGET);
+ printf("download requested %s\n", webkit_download_get_uri (arg1));
+
+
+ printf("webkit finished loading\n");
+
+ store_xwidget_event_string(xw, "download-requested", webkit_download_get_uri (arg1));
+
+ return FALSE;
+}
+
+gboolean
+webkit_osr_mime_type_policy_typedecision_requested_callback(WebKitWebView *webView,
+ WebKitWebFrame *frame,
+ WebKitNetworkRequest *request,
+ gchar *mimetype,
+ WebKitWebPolicyDecision *policy_decision,
+ gpointer user_data)
+{
+ printf("mime policy requested\n");
+ // this function makes webkit send a download signal for all unknown mime types
+ // TODO defer the decision to lisp, so that its possible to make Emacs handle text mime for instance
+ if(!webkit_web_view_can_show_mime_type(webView, mimetype)){
+ webkit_web_policy_decision_download (policy_decision);
+ return TRUE;
+ }else{
+ return FALSE;
+ }
+}
+
+
+gboolean
+webkit_osr_new_window_policy_decision_requested_callback(WebKitWebView *webView,
+ WebKitWebFrame *frame,
+ WebKitNetworkRequest *request,
+ WebKitWebNavigationAction *navigation_action,
+ WebKitWebPolicyDecision *policy_decision,
+ gpointer user_data)
+{
+ struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
+ printf("webkit_osr_new_window_policy_decision_requested_callback %s\n",
+ webkit_web_navigation_action_get_original_uri (navigation_action));
+
+ store_xwidget_event_string(xw, "new-window-policy-decision-requested", webkit_web_navigation_action_get_original_uri (navigation_action)
+ );
+ return FALSE;
+}
+
+gboolean
+webkit_osr_navigation_policy_decision_requested_callback(WebKitWebView *webView,
+ WebKitWebFrame *frame,
+ WebKitNetworkRequest *request,
+ WebKitWebNavigationAction *navigation_action,
+ WebKitWebPolicyDecision *policy_decision,
+ gpointer user_data)
+{
+ struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
+ printf("webkit_osr_navigation_policy_decision_requested_callback %s\n",
+ webkit_web_navigation_action_get_original_uri (navigation_action));
+ store_xwidget_event_string(xw, "navigation-policy-decision-requested", webkit_web_navigation_action_get_original_uri (navigation_action)
+ );
+ return FALSE;
+}
+
+//for gtk3 offscreen rendered widgets
+gboolean
+xwidget_osr_draw_callback (GtkWidget *widget, cairo_t *cr, gpointer data)
+{
+ struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
+ struct xwidget_view* xv = (struct xwidget_view*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET_VIEW);
+
+ cairo_rectangle(cr, 0,0, xv->clip_right, xv->clip_bottom);//xw->width, xw->height);
+ cairo_clip(cr);
+
+ gtk_widget_draw (xw->widget_osr, cr);
+
+ return FALSE;
+}
+
+GtkWidget* xwgir_create_debug;
+
+
+
+gboolean
+xwidget_osr_event_forward (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ /* copy events that arrive at the outer widget to the offscreen widget */
+ struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
+ GdkEvent* eventcopy = gdk_event_copy(event);
+ //GdkEvent* eventcopy = gdk_event_new(GDK_BUTTON_PRESS);
+
+
+ //((GdkEventAny*)eventcopy)->window = gtk_widget_get_window(xw->widget_osr);
+ //eventcopy->any.window = gtk_widget_get_window(GTK_WIDGET (xw->widgetwindow_osr));
+ //((GdkEventAny*)eventcopy)->window = gtk_widget_get_window(xwgir_create_debug);
+ eventcopy->any.window = gtk_widget_get_window(xw->widget_osr);//gtk_widget_get_window(xwgir_create_debug);
+ //eventcopy->any.window = gtk_button_get_event_window(GTK_BUTTON(xw->widget_osr));//gtk_widget_get_window(xwgir_create_debug);
+ //eventcopy->button.x=200; eventcopy->button.y=200;
+ //event->button.button = GDK_BUTTON_PRIMARY; //debug
+
+ //eventcopy->any.window = xw->widgetwindow_osr;//gtk_widget_get_window(xwgir_create_debug);
+ /* eventcopy->any.send_event = TRUE; */
+ /* eventcopy->button.time = GDK_CURRENT_TIME; */
+ /* eventcopy->button.device = event->button.device; */
+
+
+ printf("xwidget_osr_event_forward redirect event to window:%d\n", ((GdkEventAny*)eventcopy)->window);
+ printf("A type:%d x:%f y:%f \n", event->type, event->button.x, event->button.y);
+ printf("B type:%d x:%f y:%f \n", eventcopy->type, eventcopy->button.x, eventcopy->button.y);
+ //gtk_button_get_event_window(xwgir_create_debug);
+ gtk_main_do_event(eventcopy); //TODO this will leak events. they should be deallocated later, perhaps in xwgir_event_callback
+ //printf("gtk_widget_event:%d\n",gtk_widget_event(xw->widget_osr, eventcopy));
+ //gdk_event_put(eventcopy);
+ //gdk_event_queue_append(eventcopy);
+ //gdk_event_free(eventcopy);
+ return TRUE; //dont propagate this event furter
+ //return FALSE; //dont propagate this event furter
+}
+
+GIRepository *girepository ;
+DEFUN( "xwgir-require-namespace",Fxwgir_require_namespace, Sxwgir_require_namespace, 2,2,0,
+ doc: /*require a namespace. must be done for all namespaces we want to use, before using other xwgir functions.*/)
+ (Lisp_Object lnamespace, Lisp_Object lnamespace_version)
+{
+ char* namespace = SDATA(lnamespace);
+ char* namespace_version = SDATA(lnamespace_version);
+ GError *error = NULL;
+
+ girepository = g_irepository_get_default();
+ g_irepository_require(girepository, namespace, namespace_version, 0, &error);
+ if (error) {
+ g_error("ERROR: %s\n", error->message);
+ return Qnil;
+ }
+ return Qt;
+}
+
+GtkWidget* xwgir_create(char* class, char* namespace){
+ //TODO this is more or less the same as xwgir-call-method, so should be refactored
+ //create a gtk widget, given its name
+ //find the constructor
+ //call it
+ //also figure out how to pass args
+
+ GError *error = NULL;
+ GIArgument return_value;
+
+ GIObjectInfo* obj_info = g_irepository_find_by_name(girepository, namespace, class);
+ GIFunctionInfo* f_info = g_object_info_find_method (obj_info, "new");
+ g_function_info_invoke(f_info,
+ NULL, 0,
+ NULL, 0,
+ &return_value,
+ NULL);
+ xwgir_create_debug = return_value.v_pointer;
+ return return_value.v_pointer;
+
+}
+
+int
+xwgir_convert_lisp_to_gir_arg(GIArgument* giarg,
+ GIArgInfo* arginfo,
+ Lisp_Object lisparg )
+{
+
+ GITypeTag tag;
+ gboolean is_pointer;
+ gboolean is_enum;
+ tag = g_type_info_get_tag (g_arg_info_get_type (arginfo));
+
+ switch (tag)
+ {
+ case GI_TYPE_TAG_BOOLEAN:
+ giarg->v_boolean = XFASTINT(lisparg);
+ break;
+ case GI_TYPE_TAG_INT8:
+ giarg->v_int8 = XFASTINT(lisparg);
+ break;
+ case GI_TYPE_TAG_UINT8:
+ giarg->v_uint8 = XFASTINT(lisparg);
+ break;
+ case GI_TYPE_TAG_INT16:
+ giarg->v_int16 = XFASTINT(lisparg);
+ break;
+ case GI_TYPE_TAG_UINT16:
+ giarg->v_uint16 = XFASTINT(lisparg);
+ break;
+ case GI_TYPE_TAG_INT32:
+ giarg->v_int32 = XFASTINT(lisparg);
+ break;
+ case GI_TYPE_TAG_UINT32:
+ giarg->v_uint32 = XFASTINT(lisparg);
+ break;
+
+ case GI_TYPE_TAG_INT64:
+ giarg->v_int64 = XFASTINT(lisparg);
+ break;
+ case GI_TYPE_TAG_UINT64:
+ giarg->v_uint64 = XFASTINT(lisparg);
+ break;
+
+
+ case GI_TYPE_TAG_FLOAT:
+ giarg->v_float = XFLOAT_DATA(lisparg);
+ break;
+
+ case GI_TYPE_TAG_DOUBLE:
+ giarg->v_double = XFLOAT_DATA(lisparg);
+ break;
+
+ case GI_TYPE_TAG_UTF8:
+ case GI_TYPE_TAG_FILENAME:
+ //giarg->v_string = SDATA(lisparg);
+ giarg->v_pointer = SDATA(lisparg);
+ break;
+
+ case GI_TYPE_TAG_ARRAY:
+ case GI_TYPE_TAG_GLIST:
+ case GI_TYPE_TAG_GSLIST:
+ case GI_TYPE_TAG_GHASH:
+ case GI_TYPE_TAG_ERROR:
+ case GI_TYPE_TAG_INTERFACE:
+ case GI_TYPE_TAG_VOID:
+ case GI_TYPE_TAG_UNICHAR:
+ case GI_TYPE_TAG_GTYPE:
+ //?? i dont know how to handle these yet TODO
+ printf("failed in my lisp to gir arg conversion duties. sob!\n");
+ return -1;
+ break;
+ }
+ return 0;
+}
+
+#if 0
+void
+refactor_attempt(){
+ //this methhod should be called from xwgir-xwidget-call-method and from xwgir xwidget construction
+ char* class = SDATA(Fcar(Fcdr(Fget(xw->type, QCxwgir_class))));
+
+ GIObjectInfo* obj_info = g_irepository_find_by_name(girepository, namespace, class);
+ GIFunctionInfo* f_info = g_object_info_find_method (obj_info, SDATA(method));
+
+ //loop over args, convert from lisp to primitive type, given arg introspection data
+ //TODO g_callable_info_get_n_args(f_info) should match
+ int argscount = XFASTINT(Flength(arguments));
+ if(argscount != g_callable_info_get_n_args(f_info)){
+ printf("xwgir call method arg count doesn match! \n");
+ return Qnil;
+ }
+ int i;
+ for (i = 1; i < argscount + 1; ++i)
+ {
+ xwgir_convert_lisp_to_gir_arg(&in_args[i], g_callable_info_get_arg(f_info, i - 1), Fnth(i - 1, arguments));
+ }
+
+ in_args[0].v_pointer = widget;
+ if(g_function_info_invoke(f_info,
+ in_args, argscount + 1,
+ NULL, 0,
+ &return_value,
+ &error)) {
+ //g_error("ERROR: %s\n", error->message);
+ printf("invokation error\n");
+ return Qnil;
+ }
+ return Qt;
+}
+#endif /* 0 */
+
+DEFUN ("xwgir-xwidget-call-method", Fxwgir_xwidget_call_method, Sxwgir_xwidget_call_method, 3, 3, 0,
+ doc: /* call xwidget object method.*/)
+ (Lisp_Object xwidget, Lisp_Object method, Lisp_Object arguments)
+{
+ CHECK_XWIDGET (xwidget);
+ GError *error = NULL;
+ GIArgument return_value;
+ GIArgument in_args[20];
+
+
+ struct xwidget* xw;
+ if (NILP (xwidget)) { printf("ERROR xwidget nil\n"); return Qnil; };
+ xw = XXWIDGET(xwidget);
+ if(NULL == xw) printf("ERROR xw is 0\n");
+ char* namespace = SDATA(Fcar(Fget(xw->type, QCxwgir_class)));
+ //we need the concrete widget, which happens in 2 ways depending on OSR or not TODO
+ GtkWidget* widget = NULL;
+ if(NULL == xw->widget_osr) {
+ widget = xwidget_view_lookup (xw, XWINDOW(FRAME_SELECTED_WINDOW (SELECTED_FRAME ()))) -> widget;
+ } else {
+ widget = xw->widget_osr;
+ }
+
+ //char* class = SDATA(SYMBOL_NAME(xw->type)); //this works but is unflexible
+ //figure out the class from the widget instead
+ /* printf("type class: %s %s\n", G_OBJECT_TYPE_NAME(widget), G_OBJECT_CLASS_NAME(G_OBJECT_GET_CLASS(widget))); */
+ /* char* class = G_OBJECT_TYPE_NAME(widget); //gives "GtkButton"(I want "Button") */
+ /* class += strlen(namespace); //TODO check for corresponding api method. but this seems to work. */
+
+ char* class = SDATA(Fcar(Fcdr(Fget(xw->type, QCxwgir_class))));
+
+ GIObjectInfo* obj_info = g_irepository_find_by_name(girepository, namespace, class);
+ GIFunctionInfo* f_info = g_object_info_find_method (obj_info, SDATA(method));
+
+ //loop over args, convert from lisp to primitive type, given arg introspection data
+ //TODO g_callable_info_get_n_args(f_info) should match
+ int argscount = XFASTINT(Flength(arguments));
+ if(argscount != g_callable_info_get_n_args(f_info)){
+ printf("xwgir call method arg count doesn match! \n");
+ return Qnil;
+ }
+ int i;
+ Lisp_Object n;
+ for (i = 1; i < argscount + 1; ++i)
+ {
+ XSETFASTINT (n, i - 1);
+ xwgir_convert_lisp_to_gir_arg(&in_args[i], g_callable_info_get_arg(f_info, i - 1), Fnth(n, arguments));
+ }
+
+ in_args[0].v_pointer = widget;
+ if(g_function_info_invoke(f_info,
+ in_args, argscount + 1,
+ NULL, 0,
+ &return_value,
+ &error)) {
+ //g_error("ERROR: %s\n", error->message);
+ printf("invokation error\n");
+ return Qnil;
+ }
+ return Qt;
+}
+
+ void
+to_child (GtkWidget *bin,
+ double widget_x,
+ double widget_y,
+ double *x_out,
+ double *y_out)
+{
+ *x_out = widget_x;
+ *y_out = widget_y;
+}
+
+
+GdkWindow *
+offscreen_pick_embedded_child (GdkWindow *window,
+ double x,
+ double y,
+ gpointer *data)
+{
+ //in this simple case we assume the window contains a single widget. easy.
+ //but then we get the problem that the widget cant be embedded in several windows
+ return gtk_widget_get_window (GTK_WIDGET (data));
+}
+
+void
+offscreen_to_embedder (GdkWindow *window,
+ gdouble offscreen_x,
+ gdouble offscreen_y,
+ gpointer embedder_x,
+ gpointer embedder_y,
+ gpointer data)
+{
+ * (gdouble *) embedder_x = offscreen_x;
+ * (gdouble *) embedder_y = offscreen_y;
+}
+
+void
+offscreen_from_embedder (GdkWindow *window,
+ gdouble embedder_x,
+ gdouble embedder_y,
+ gpointer offscreen_x,
+ gpointer offscreen_y,
+ gpointer user_data)
+{
+ * (gdouble *) offscreen_x = embedder_x;
+ * (gdouble *) offscreen_y = embedder_y;
+}
+
+gboolean
+xwidget_osr_event_set_embedder (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer data)
+{
+ struct xwidget_view *xv = (struct xwidget_view *) data;
+ struct xwidget *xww = XXWIDGET (xv->model);
+ printf("gdk_offscreen_window_set_embedder %d %d\n",
+ GDK_IS_WINDOW(gtk_widget_get_window (xww->widget_osr)),
+ GDK_IS_WINDOW(gtk_widget_get_window (GTK_WIDGET (xv->widget))));
+ gdk_offscreen_window_set_embedder (gtk_widget_get_window (xww->widgetwindow_osr),
+ gtk_widget_get_window (xv->widget));
+}
+
+
+/* initializes and does initial placement of an xwidget view on screen */
+struct xwidget_view*
+xwidget_init_view (struct xwidget *xww,
+ struct glyph_string *s,
+ int x, int y)
+{
+ struct xwidget_view *xv = allocate_xwidget_view();
+ Lisp_Object val;
+ GdkColor color;
+
+ XSETXWIDGET_VIEW (val, xv) ;
+ Vxwidget_view_list = Fcons (val, Vxwidget_view_list);
+
+ XSETWINDOW(xv->w, s->w);
+ XSETXWIDGET(xv->model, xww);
+
+ //widget creation
+ if(EQ(xww->type, Qbutton))
+ {
+ xv->widget = gtk_button_new_with_label (XSTRING(xww->title)->data);
+ g_signal_connect (G_OBJECT (xv->widget), "clicked",
+ G_CALLBACK (buttonclick_handler), xv); // the view rather than the model
+ } else if (EQ(xww->type, Qtoggle)) {
+ xv->widget = gtk_toggle_button_new_with_label (XSTRING(xww->title)->data);
+ //xv->widget = gtk_entry_new ();//temp hack to experiment with key propagation TODO entry widget is useful for testing
+ } else if (EQ(xww->type, Qsocket)) {
+ xv->widget = gtk_socket_new ();
+ g_signal_connect_after(xv->widget, "plug-added", G_CALLBACK(xwidget_plug_added), "plug added");
+ g_signal_connect_after(xv->widget, "plug-removed", G_CALLBACK(xwidget_plug_removed), "plug removed");
+ //TODO these doesnt help
+ gtk_widget_add_events(xv->widget, GDK_KEY_PRESS);
+ gtk_widget_add_events(xv->widget, GDK_KEY_RELEASE);
+ } else if (EQ(xww->type, Qslider)) {
+ xv->widget =
+ //gtk_hscale_new (GTK_ADJUSTMENT(gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 10.0, 10.0)));
+ gtk_hscale_new_with_range ( 0.0, 100.0, 10.0);
+ 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
+ xv->handler_id = g_signal_connect_after(xv->widget, "value-changed", G_CALLBACK(xwidget_slider_changed), "slider changed");
+ } else if (EQ(xww->type, Qcairo)) {
+ //Cairo view
+ //uhm cairo is differentish in gtk 3.
+ //gdk_cairo_create (gtk_widget_get_window (FRAME_GTK_WIDGET (s->f)));
+ xv->widget = gtk_drawing_area_new();
+ g_signal_connect (G_OBJECT ( xv->widget), "draw",
+ G_CALLBACK (xwidget_osr_draw_callback), NULL);
+
+ } else if (EQ(xww->type, Qwebkit_osr)||
+ EQ(xww->type, Qsocket_osr)||
+ (!NILP (Fget(xww->type, QCxwgir_class))))//xwgir widgets are OSR
+ {
+ printf("osr init:%s\n",SDATA(SYMBOL_NAME(xww->type)));
+ xv->widget = gtk_drawing_area_new();
+ gtk_widget_set_app_paintable ( xv->widget, TRUE); //because expose event handling
+ gtk_widget_add_events(xv->widget, GDK_ALL_EVENTS_MASK);
+
+ /* Draw the view on damage-event */
+ g_signal_connect (G_OBJECT (xww->widgetwindow_osr), "damage-event",
+ G_CALLBACK (offscreen_damage_event), xv->widget);
+
+ if (EQ(xww->type, Qwebkit_osr)){
+ /* ///xwgir debug */
+ /* //forward events. this isnt compatible with the set_embedded strategy */
+ g_signal_connect (G_OBJECT ( xv->widget), "button-press-event",
+ G_CALLBACK (xwidget_osr_event_forward), NULL);
+ g_signal_connect (G_OBJECT ( xv->widget), "button-release-event",
+ G_CALLBACK (xwidget_osr_event_forward), NULL);
+ g_signal_connect (G_OBJECT ( xv->widget), "motion-notify-event",
+ G_CALLBACK (xwidget_osr_event_forward), NULL);
+ }else{
+ //xwgir debug , orthogonal to forwarding
+ g_signal_connect (G_OBJECT (xv->widget), "enter-notify-event",
+ G_CALLBACK (xwidget_osr_event_set_embedder), xv);
+ }
+
+ //draw
+ g_signal_connect (G_OBJECT (xv->widget), "draw",
+ G_CALLBACK (xwidget_osr_draw_callback), NULL);
+
+ }
+ //else return NULL;
+
+ //widget realization
+ //make container widget 1st, and put the actual widget inside the container
+ //later, drawing should crop container window if necessary to handle case where xwidget
+ //is partially obscured by other emacs windows
+ //other containers than gtk_fixed where explored, but gtk_fixed had the most predictable behaviour so far.
+ xv->emacswindow = FRAME_GTK_WIDGET (s->f);
+ xv->widgetwindow = gtk_fixed_new ();
+ gtk_widget_set_has_window(xv->widgetwindow, TRUE);
+ gtk_container_add (GTK_CONTAINER (xv->widgetwindow), xv->widget);
+
+ //store some xwidget data in the gtk widgets
+ g_object_set_data (G_OBJECT (xv->widget), XG_FRAME_DATA, (gpointer) (s->f)); //the emacs frame
+ g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET, (gpointer) (xww)); //the xwidget
+ g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET_VIEW, (gpointer) (xv)); //the xwidget
+ g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET, (gpointer) (xww)); //the xwidget window
+ g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET_VIEW, (gpointer) (xv)); //the xwidget window
+
+
+ gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xww->width, xww->height);
+ gtk_widget_set_size_request (xv->widgetwindow, xww->width, xww->height);
+ gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), xv->widgetwindow, x, y);
+ xv->x = x; xv->y = y;
+ gtk_widget_show_all (xv->widgetwindow);
+
+
+
+ //widgettype specific initialization only possible after realization
+ if (EQ(xww->type, Qsocket)) {
+ printf ("xwid:%d socket id:%x %d\n",
+ xww,
+ gtk_socket_get_id (GTK_SOCKET (xv->widget)),
+ gtk_socket_get_id (GTK_SOCKET (xv->widget)));
+ send_xembed_ready_event (xww,
+ gtk_socket_get_id (GTK_SOCKET (xv->widget)));
+ //gtk_widget_realize(xw->widget);
+ }
+
+ //////////////////////////////////////////////////////////////
+ // xwgir debug
+ if (//EQ(xww->type, Qwebkit_osr)|| //TODO should be able to choose compile time which method to use with webkit
+ EQ(xww->type, Qsocket_osr)||
+ (!NILP (Fget(xww->type, QCxwgir_class))))//xwgir widgets are OSR
+ {
+ printf("gdk_offscreen_window_set_embedder %d %d\n",
+ GDK_IS_WINDOW(gtk_widget_get_window (xww->widget_osr)),
+ GDK_IS_WINDOW(gtk_widget_get_window (GTK_WIDGET (xv->widget))));
+ // set_embedder needs to be called after xv->widget realization
+ gdk_offscreen_window_set_embedder (gtk_widget_get_window (xww->widgetwindow_osr),
+ gtk_widget_get_window (xv->widget));
+ g_signal_connect (gtk_widget_get_window (xv->widget), "pick-embedded-child",
+ G_CALLBACK (offscreen_pick_embedded_child), xww->widgetwindow_osr);
+
+ g_signal_connect (gtk_widget_get_window (xww->widgetwindow_osr), "from-embedder",
+ G_CALLBACK (offscreen_from_embedder), NULL);
+ g_signal_connect (gtk_widget_get_window (xww->widgetwindow_osr), "to-embedder",
+ G_CALLBACK (offscreen_to_embedder), NULL);
+ }
+ ////////////////////////////////////////
+
+ return xv;
+}
+
+
+void
+x_draw_xwidget_glyph_string (struct glyph_string *s)
+{
+ /*
+ this method is called by the redisplay engine and places the xwidget on screen.
+ moving and clipping is done here. also view init.
+
+ */
+ int box_line_hwidth = eabs (s->face->box_line_width);
+ int box_line_vwidth = max (s->face->box_line_width, 0);
+ int height = s->height;
+ struct xwidget *xww = s->xwidget;
+ struct xwidget_view *xv = xwidget_view_lookup(xww, s->w);
+ int clip_right; int clip_bottom; int clip_top; int clip_left;
+
+ int x = s->x;
+ int y = s->y + (s->height / 2) - (xww->height / 2);
+ int moved=0;
+
+ /* We do it here in the display loop because there is no other
+ time to know things like window placement etc.
+ */
+ printf ("xv init for xw %d\n", xww);
+ xv = xwidget_init_view (xww, s, x, y);
+
+ //calculate clipping, which is used for all manner of onscreen xwidget views
+ //each widget border can get clipped by other emacs objects so there are four clipping variables
+ 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));
+ 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));
+
+ clip_bottom = min (xww->height, WINDOW_BOTTOM_EDGE_Y (s->w) - WINDOW_MODE_LINE_HEIGHT (s->w) - y);
+ clip_top = max(0, WINDOW_TOP_EDGE_Y(s->w) -y );
+
+ //we are conserned with movement of the onscreen area. the area might sit still when the widget actually moves
+ //this happens when an emacs window border moves across a widget window
+ //so, if any corner of the outer widget clippng window moves, that counts as movement here, even
+ //if it looks like no movement happens because the widget sits still inside the clipping area.
+ //the widget can also move inside the clipping area, which happens later
+ moved = (xv->x + xv->clip_left != x+clip_left)
+ || ((xv->y + xv->clip_top)!= (y+clip_top));
+ 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);
+ else
+ 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);
+ xv->x = x;
+ xv->y = y;
+ if (moved) //has it moved?
+ {
+ if (1)//!xwidget_hidden(xv)) //hidden equals not being seen during redisplay
+ {
+ //TODO should be possible to use xwidget_show_view here
+ gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)),
+ xv->widgetwindow,
+ x + clip_left, y + clip_top);
+ }
+ }
+ //clip the widget window if some parts happen to be outside drawable area
+ //an emacs window is not a gtk window, a gtk window covers the entire frame
+ //cliping might have changed even if we havent actualy moved, we try figure out when we need to reclip for real
+ if((xv->clip_right != clip_right)
+ || (xv->clip_bottom != clip_bottom)
+ || (xv->clip_top != clip_top)
+ || (xv->clip_left != clip_left)){
+ gtk_widget_set_size_request (xv->widgetwindow, clip_right + clip_left, clip_bottom + clip_top);
+ gtk_fixed_move(GTK_FIXED(xv->widgetwindow), xv->widget, -clip_left, -clip_top);
+ 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);
+
+
+ xv->clip_right = clip_right; xv->clip_bottom = clip_bottom; xv->clip_top = clip_top;xv->clip_left = clip_left;
+ }
+ //if emacs wants to repaint the area where the widget lives, queue a redraw
+ //TODO it seems its possible to get out of sync with emacs redraws so emacs bg sometimes shows up instead of xwidget
+ //its just a visual glitch though
+ if (!xwidget_hidden(xv)){
+ gtk_widget_queue_draw (xv->widgetwindow);
+ gtk_widget_queue_draw (xv->widget);
+ }
+}
+
+
+#ifdef HAVE_WEBKIT_OSR
+
+//FUGLY macro that checks WEBKIT_IS_WEB_VIEW(xw->widget_osr) first
+#define WEBKIT_FN_INIT() \
+ struct xwidget* xw; \
+ CHECK_XWIDGET (xwidget); \
+ if(NILP (xwidget)) {printf("ERROR xwidget nil\n"); return Qnil;}; \
+ xw = XXWIDGET(xwidget); \
+ if(NULL == xw) printf("ERROR xw is 0\n"); \
+ if((NULL == xw->widget_osr) || !WEBKIT_IS_WEB_VIEW(xw->widget_osr)){ \
+ printf("ERROR xw->widget_osr does not hold a webkit instance\n");\
+ return Qnil;\
+ };
+
+
+DEFUN ("xwidget-webkit-goto-uri", Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri,
+ 2, 2, 0,
+ doc: /* webkit goto uri.*/)
+ (Lisp_Object xwidget, Lisp_Object uri)
+{
+ WEBKIT_FN_INIT();
+ webkit_web_view_load_uri ( WEBKIT_WEB_VIEW(xw->widget_osr), SDATA(uri));
+ return Qnil;
+}
+
+
+DEFUN ("xwidget-webkit-execute-script", Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script,
+ 2, 2, 0,
+ doc: /* webkit exec js.*/)
+ (Lisp_Object xwidget, Lisp_Object script)
+{
+ WEBKIT_FN_INIT();
+ webkit_web_view_execute_script( WEBKIT_WEB_VIEW(xw->widget_osr), SDATA(script));
+ return Qnil;
+}
+
+DEFUN ("xwidget-webkit-get-title", Fxwidget_webkit_get_title, Sxwidget_webkit_get_title,
+ 1, 1, 0,
+ doc: /* webkit get title. can be used to work around exec method lacks return val*/)
+ (Lisp_Object xwidget)
+{
+ //TODO support multibyte strings
+ WEBKIT_FN_INIT();
+ const gchar* str=webkit_web_view_get_title( WEBKIT_WEB_VIEW(xw->widget_osr));
+ //return make_string_from_bytes(str, wcslen((const wchar_t *)str), strlen(str));
+ if(str == 0){
+ //TODO maybe return Qnil instead. I suppose webkit returns nullpointer when doc is not properly loaded or something
+ printf("xwidget-webkit-get-title null webkit title\n");
+ return build_string("");
+ }
+ return build_string(str);
+}
+
+//TODO missnamed
+DEFUN("xwidget-disable-plugin-for-mime", Fxwidget_disable_plugin_for_mime , Sxwidget_disable_plugin_for_mime,
+ 1,1,0, doc: /* */)
+ (Lisp_Object mime)
+{
+ WebKitWebPlugin *wp = webkit_web_plugin_database_get_plugin_for_mimetype
+ (webkit_get_web_plugin_database(), SDATA(mime));
+ if(wp == NULL) return Qnil;
+ if(webkit_web_plugin_get_enabled (wp)){
+ webkit_web_plugin_set_enabled (wp, FALSE);
+ return Qt;
+ }
+ return Qnil;
+}
+
+
+void
+xwidget_webkit_dom_dump(WebKitDOMNode* parent)
+{
+ WebKitDOMNodeList* list;
+ int i;
+ int length;
+ WebKitDOMNode* attribute;
+ WebKitDOMNamedNodeMap* attrs;
+ WebKitDOMNode* child;
+ printf("node:%d type:%d name:%s content:%s\n",
+ parent,
+ webkit_dom_node_get_node_type(parent),//1 element 3 text 8 comment 2 attribute
+ webkit_dom_node_get_local_name(parent),
+ webkit_dom_node_get_text_content(parent));
+
+ if(webkit_dom_node_has_attributes(parent)){
+ attrs = webkit_dom_node_get_attributes(parent);
+
+ length = webkit_dom_named_node_map_get_length(attrs);
+ for (int i = 0; i < length; i++) {
+ attribute = webkit_dom_named_node_map_item(attrs,i);
+ printf(" attr node:%d type:%d name:%s content:%s\n",
+ attribute,
+ webkit_dom_node_get_node_type(attribute),//1 element 3 text 8 comment
+ webkit_dom_node_get_local_name(attribute),
+ webkit_dom_node_get_text_content(attribute));
+ }
+ }
+ list = webkit_dom_node_get_child_nodes(parent);
+ length = webkit_dom_node_list_get_length(list);
+
+ for (int i = 0; i < length; i++) {
+ child = webkit_dom_node_list_item(list, i);
+ //if(webkit_dom_node_has_child_nodes(child))
+ xwidget_webkit_dom_dump(child);
+ }
+}
+
+
+DEFUN ("xwidget-webkit-dom-dump", Fxwidget_webkit_dom_dump, Sxwidget_webkit_dom_dump,
+ 1, 1, 0,
+ doc: /* webkit dom dump*/)
+ (Lisp_Object xwidget)
+{
+ WEBKIT_FN_INIT();
+ xwidget_webkit_dom_dump(WEBKIT_DOM_NODE(webkit_web_view_get_dom_document( WEBKIT_WEB_VIEW(xw->widget_osr))));
+ return Qnil;
+}
+
+
+
+#endif /* HAVE_WEBKIT_OSR */
+
+
+
+
+
+DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0, doc:
+ /* resize xwidgets*/)
+ (Lisp_Object xwidget, Lisp_Object new_width, Lisp_Object new_height)
+{
+ CHECK_XWIDGET (xwidget);
+ struct xwidget* xw = XXWIDGET(xwidget);
+ struct xwidget_view *xv;
+ int w, h;
+
+ CHECK_NUMBER (new_width);
+ CHECK_NUMBER (new_height);
+ w = XFASTINT (new_width);
+ h = XFASTINT (new_height);
+
+
+ printf("resize xwidget %d (%d,%d)->(%d,%d)\n",xw, xw->width,xw->height,w,h);
+ xw->width=w;
+ xw->height=h;
+ //if theres a osr resize it 1st
+ if(xw->widget_osr){
+ printf("resize xwidget_osr\n");
+ //gtk_container_set_resize_mode ( GTK_WINDOW(xw->widgetwindow_osr), GTK_RESIZE_QUEUE);
+ //gtk_container_set_resize_mode ( GTK_WINDOW(xw->widget_osr), GTK_RESIZE_QUEUE);
+
+
+ //gtk_layout_set_size (GTK_LAYOUT (xw->widgetwindow_osr), xw->width, xw->height);
+ gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height); //minimum size
+ //gtk_window_resize( GTK_WINDOW(xw->widget_osr), xw->width, xw->height);
+ gtk_window_resize( GTK_WINDOW(xw->widgetwindow_osr), xw->width, xw->height);
+ //gtk_container_resize_children ( GTK_WINDOW(xw->widgetwindow_osr));
+ gtk_container_resize_children (GTK_CONTAINER(xw->widgetwindow_osr));
+
+ }
+
+ for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail)) //TODO MVC refactor lazy linear search
+ {
+ if (XWIDGET_VIEW_P (XCAR (tail))) {
+ xv = XXWIDGET_VIEW (XCAR (tail));
+ if(XXWIDGET (xv->model) == xw) {
+ gtk_layout_set_size (GTK_LAYOUT (xv->widgetwindow), xw->width, xw->height);
+ gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width, xw->height);
+ }
+ }
+ }
+
+ return Qnil;
+}
+
+DEFUN ("xwidget-size-request", Fxwidget_size_request, Sxwidget_size_request, 1, 1, 0, doc:
+ /* desired size (TODO crashes if arg not osr widget)*/)
+ (Lisp_Object xwidget)
+{
+ CHECK_XWIDGET (xwidget);
+ GtkRequisition requisition;
+ Lisp_Object rv;
+ gtk_widget_size_request(XXWIDGET(xwidget)->widget_osr, &requisition);
+ rv = Qnil;
+ rv = Fcons (make_number(requisition.height), rv);
+ rv = Fcons (make_number(requisition.width), rv);
+ return rv;
+
+}
+
+DEFUN ("xwidgetp", Fxwidgetp, Sxwidgetp, 1, 1, 0,
+ doc: /* Return t if OBJECT is a xwidget. */)
+ (Lisp_Object object)
+{
+ return XWIDGETP (object) ? Qt : Qnil;
+}
+
+DEFUN ("xwidget-view-p", Fxwidget_view_p, Sxwidget_view_p, 1, 1, 0,
+ doc: /* Return t if OBJECT is a xwidget-view. */)
+ (Lisp_Object object)
+{
+ return XWIDGET_VIEW_P (object) ? Qt : Qnil;
+}
+
+DEFUN ("xwidget-info", Fxwidget_info , Sxwidget_info, 1,1,0, doc: /* get xwidget props */)
+ (Lisp_Object xwidget)
+{
+ CHECK_XWIDGET (xwidget);
+ Lisp_Object info, n;
+ struct xwidget* xw = XXWIDGET(xwidget);
+
+ info = Fmake_vector (make_number (4), Qnil);
+ ASET (info, 0, xw->type);
+ ASET (info, 1, xw->title);
+ XSETFASTINT(n, xw->width);
+ ASET (info, 2, n);
+ XSETFASTINT(n, xw->height);
+ ASET (info, 3, n);
+
+ return info;
+}
+
+DEFUN ("xwidget-view-info", Fxwidget_view_info , Sxwidget_view_info, 1, 1, 0, doc: /* get xwidget view props */)
+ (Lisp_Object xwidget_view)
+{
+ CHECK_XWIDGET_VIEW (xwidget_view);
+ struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
+ Lisp_Object info;
+
+ info = Fmake_vector (make_number (6), Qnil);
+ ASET (info, 0, make_number(xv->x));
+ ASET (info, 1, make_number(xv->y));
+ ASET (info, 2, make_number(xv->clip_right));
+ ASET (info, 3, make_number(xv->clip_bottom));
+ ASET (info, 4, make_number(xv->clip_top));
+ ASET (info, 5, make_number(xv->clip_left));
+
+ return info;
+}
+
+DEFUN ("xwidget-view-model", Fxwidget_view_model, Sxwidget_view_model,
+ 1, 1, 0,
+ doc: /* get xwidget view model */)
+ (Lisp_Object xwidget_view)
+{
+ CHECK_XWIDGET_VIEW (xwidget_view);
+ return XXWIDGET_VIEW (xwidget_view)->model;
+}
+
+DEFUN ("xwidget-view-window", Fxwidget_view_window, Sxwidget_view_window,
+ 1, 1, 0,
+ doc: /* get xwidget view window */)
+ (Lisp_Object xwidget_view)
+{
+ CHECK_XWIDGET_VIEW (xwidget_view);
+ return XXWIDGET_VIEW (xwidget_view)->w;
+}
+
+DEFUN ("xwidget-send-keyboard-event", Fxwidget_send_keyboard_event, Sxwidget_send_keyboard_event, 2, 2, 0, doc:/* synthesize a kbd event for a xwidget. */
+ )
+ (Lisp_Object xwidget, Lisp_Object keydescriptor)
+{
+ //TODO this code crashes for offscreen widgets and ive tried many different strategies
+ //int keyval = 0x058; //X
+ int keyval = XFASTINT(keydescriptor); //X
+ char *keystring = "";
+ GdkKeymapKey* keys;
+ gint n_keys;
+ GdkDeviceManager* manager;
+ struct xwidget *xw;
+ GtkWidget* widget;
+ GdkEventKey* ev;
+ Lisp_Object window;
+ //popup_activated_flag = 1; //TODO just a hack
+ gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), keyval, &keys, &n_keys);
+
+ xw = XXWIDGET(xwidget);
+
+ ev = (GdkEventKey*)gdk_event_new(GDK_KEY_PRESS);
+
+
+ //todo what about windowless widgets?
+
+ window = FRAME_SELECTED_WINDOW (SELECTED_FRAME ());
+
+
+ //TODO maybe we also need to special case sockets by picking up the plug rather than the socket
+ if(xw->widget_osr)
+ widget = xw->widget_osr;
+ else
+ widget = xwidget_view_lookup(xw, XWINDOW(window))->widget;
+
+ ev->window = gtk_widget_get_window(widget);
+ gtk_widget_grab_focus(widget);
+ ev->send_event = FALSE;
+
+ ev->hardware_keycode = keys[0].keycode;
+ ev->group = keys[0].group;
+
+ ev->keyval = keyval;
+ ev->time = GDK_CURRENT_TIME;
+
+ //ev->device = gdk_device_get_core_pointer();
+ manager = gdk_display_get_device_manager(gdk_window_get_display(ev->window));
+ gdk_event_set_device ((GdkEvent*)ev, gdk_device_manager_get_client_pointer(manager));
+ gdk_event_put((GdkEvent*)ev);
+ //g_signal_emit_by_name(ev->window,"key-press-event", ev);
+
+ ev->type = GDK_KEY_RELEASE;
+ gdk_event_put((GdkEvent*)ev);
+ //g_signal_emit_by_name(ev->window,"key-release-event", ev);
+ //gtk_main_do_event(ev);
+
+ //TODO
+ //if I delete the event the receiving component eventually crashes.
+ //it ough TDTRT since event_put is supposed to copy the event
+ //so probably this leaks events now
+ //gdk_event_free((GdkEvent*)ev);
+
+ return Qnil;
+}
+
+DEFUN ("delete-xwidget-view", Fdelete_xwidget_view, Sdelete_xwidget_view,
+ 1, 1, 0,
+ doc: /* Delete the XWIDGET-VIEW. */)
+ (Lisp_Object xwidget_view)
+{
+ CHECK_XWIDGET_VIEW (xwidget_view);
+ struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
+ gtk_widget_destroy(xv->widgetwindow);
+ Vxwidget_view_list = Fdelq (xwidget_view, Vxwidget_view_list);
+}
+
+DEFUN ("xwidget-view-lookup", Fxwidget_view_lookup, Sxwidget_view_lookup,
+ 1, 2, 0,
+ doc: /* Return the xwidget-view associated to XWIDGET in
+WINDOW if specified, otherwise it uses the selected window. */)
+ (Lisp_Object xwidget, Lisp_Object window)
+{
+ CHECK_XWIDGET (xwidget);
+
+ if (NILP (window))
+ window = Fselected_window();
+ CHECK_WINDOW (window);
+
+ for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
+ {
+ Lisp_Object xwidget_view = XCAR (tail);
+ if (EQ (Fxwidget_view_model (xwidget_view), xwidget)
+ && EQ (Fxwidget_view_window (xwidget_view), window))
+ return xwidget_view;
+ }
+
+ return Qnil;
+}
+
+DEFUN ("set-frame-visible", Fset_frame_visible, Sset_frame_visible,
+ 2, 2, 0,
+ doc: /* HACKY */)
+ (Lisp_Object frame, Lisp_Object flag)
+{
+ CHECK_FRAME (frame);
+ struct frame *f = XFRAME (frame);
+ SET_FRAME_VISIBLE (f, !NILP (flag));
+ return flag;
+}
+
+DEFUN ("xwidget-plist", Fxwidget_plist, Sxwidget_plist,
+ 1, 1, 0,
+ doc: /* Return the plist of XWIDGET. */)
+ (register Lisp_Object xwidget)
+{
+ CHECK_XWIDGET (xwidget);
+ return XXWIDGET (xwidget)->plist;
+}
+
+DEFUN ("xwidget-buffer", Fxwidget_buffer, Sxwidget_buffer,
+ 1, 1, 0,
+ doc: /* Return the buffer of XWIDGET. */)
+ (register Lisp_Object xwidget)
+{
+ CHECK_XWIDGET (xwidget);
+ return XXWIDGET (xwidget)->buffer;
+}
+
+DEFUN ("set-xwidget-plist", Fset_xwidget_plist, Sset_xwidget_plist,
+ 2, 2, 0,
+ doc: /* Replace the plist of XWIDGET with PLIST. Returns PLIST. */)
+ (register Lisp_Object xwidget, Lisp_Object plist)
+{
+ CHECK_XWIDGET (xwidget);
+ CHECK_LIST (plist);
+
+ XXWIDGET (xwidget)->plist = plist;
+ return plist;
+}
+
+DEFUN ("set-xwidget-query-on-exit-flag",
+ Fset_xwidget_query_on_exit_flag, Sset_xwidget_query_on_exit_flag,
+ 2, 2, 0,
+ doc: /* Specify if query is needed for XWIDGET when Emacs is
+exited. If the second argument FLAG is non-nil, Emacs will query the
+user before exiting or killing a buffer if XWIDGET is running. This
+function returns FLAG. */)
+ (Lisp_Object xwidget, Lisp_Object flag)
+{
+ CHECK_XWIDGET (xwidget);
+ XXWIDGET (xwidget)->kill_without_query = NILP (flag);
+ return flag;
+}
+
+DEFUN ("xwidget-query-on-exit-flag",
+ Fxwidget_query_on_exit_flag, Sxwidget_query_on_exit_flag,
+ 1, 1, 0,
+ doc: /* Return the current value of query-on-exit flag for XWIDGET. */)
+ (Lisp_Object xwidget)
+{
+ CHECK_XWIDGET (xwidget);
+ return (XXWIDGET (xwidget)->kill_without_query ? Qnil : Qt);
+}
+
+void
+syms_of_xwidget (void)
+{
+ int i;
+
+ defsubr (&Smake_xwidget);
+ defsubr (&Sxwidgetp);
+ DEFSYM (Qxwidgetp, "xwidgetp");
+ defsubr (&Sxwidget_view_p);
+ DEFSYM (Qxwidget_view_p, "xwidget-view-p");
+ defsubr (&Sxwidget_info);
+ defsubr (&Sxwidget_view_info);
+ defsubr (&Sxwidget_resize);
+ defsubr (&Sget_buffer_xwidgets);
+ defsubr (&Sxwidget_view_model);
+ defsubr (&Sxwidget_view_window);
+ defsubr (&Sxwidget_view_lookup);
+ defsubr (&Sxwidget_query_on_exit_flag);
+ defsubr (&Sset_xwidget_query_on_exit_flag);
+ defsubr (&Sset_frame_visible);
+
+#ifdef HAVE_WEBKIT_OSR
+ defsubr (&Sxwidget_webkit_goto_uri);
+ defsubr (&Sxwidget_webkit_execute_script);
+ defsubr (&Sxwidget_webkit_get_title);
+ DEFSYM (Qwebkit_osr ,"webkit-osr");
+#endif
+
+ defsubr (&Sxwgir_xwidget_call_method );
+ defsubr (&Sxwgir_require_namespace);
+ defsubr (&Sxwidget_size_request );
+ defsubr (&Sdelete_xwidget_view);
+ defsubr (&Sxwidget_disable_plugin_for_mime);
+
+ defsubr (&Sxwidget_send_keyboard_event);
+ defsubr (&Sxwidget_webkit_dom_dump);
+ defsubr (&Sxwidget_plist);
+ defsubr (&Sxwidget_buffer);
+ defsubr (&Sset_xwidget_plist);
+
+ DEFSYM (Qxwidget, "xwidget");
+
+ DEFSYM (QCxwidget, ":xwidget");
+ DEFSYM (QCxwgir_class, ":xwgir-class");
+ DEFSYM (QCtitle, ":title");
+
+ /* Do not forget to update the docstring of make-xwidget if you add
+ new types. */
+ DEFSYM (Qbutton, "Button"); //changed to match the gtk class because xwgir(experimental and not really needed)
+ DEFSYM (Qtoggle, "ToggleButton");
+ DEFSYM (Qslider, "slider");
+ DEFSYM (Qsocket, "socket");
+ DEFSYM (Qsocket_osr, "socket-osr");
+ DEFSYM (Qcairo, "cairo");
+
+ DEFSYM (QCplist, ":plist");
+
+ DEFVAR_LISP ("xwidget-list", Vxwidget_list, doc: /*xwidgets list*/);
+ Vxwidget_list = Qnil;
+
+ DEFVAR_LISP ("xwidget-view-list", Vxwidget_view_list, doc: /*xwidget views list*/);
+ Vxwidget_view_list = Qnil;
+
+ Fprovide (intern ("xwidget-internal"), Qnil);
+
+}
+
+
+/* Value is non-zero if OBJECT is a valid Lisp xwidget specification. A
+ valid xwidget specification is a list whose car is the symbol
+ `xwidget', and whose rest is a property list. The property list must
+ contain a value for key `:type'. That value must be the name of a
+ supported xwidget type. The rest of the property list depends on the
+ xwidget type. */
+
+int
+valid_xwidget_spec_p (Lisp_Object object)
+{
+ int valid_p = 0;
+
+ if (CONSP (object) && EQ (XCAR (object), Qxwidget))
+ {
+ /* Lisp_Object tem; */
+
+ /* for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem)) */
+ /* if (EQ (XCAR (tem), QCtype)) */
+ /* { */
+ /* tem = XCDR (tem); */
+ /* if (CONSP (tem) && SYMBOLP (XCAR (tem))) */
+ /* { */
+ /* struct xwidget_type *type; */
+ /* type = lookup_xwidget_type (XCAR (tem)); */
+ /* if (type) */
+ /* valid_p = type->valid_p (object); */
+ /* } */
+
+ /* break; */
+ /* } */
+ //never mind type support for now
+ valid_p = 1;
+ }
+
+ return valid_p;
+}
+
+
+
+/* find a value associated with key in spec */
+Lisp_Object
+xwidget_spec_value ( Lisp_Object spec, Lisp_Object key,
+ int *found)
+{
+ Lisp_Object tail;
+
+ eassert (valid_xwidget_spec_p (spec));
+
+ for (tail = XCDR (spec);
+ CONSP (tail) && CONSP (XCDR (tail)); tail = XCDR (XCDR (tail)))
+ {
+ if (EQ (XCAR (tail), key))
+ {
+ if (found)
+ *found = 1;
+ return XCAR (XCDR (tail));
+ }
+ }
+
+ if (found)
+ *found = 0;
+ return Qnil;
+}
+
+
+void
+xwidget_view_delete_all_in_window (struct window *w)
+{
+ struct xwidget_view* xv = NULL;
+ for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
+ {
+ if (XWIDGET_VIEW_P (XCAR (tail))) {
+ xv = XXWIDGET_VIEW (XCAR (tail));
+ if(XWINDOW (xv->w) == w) {
+ gtk_widget_destroy(xv->widgetwindow);
+ Vxwidget_view_list = Fdelq (XCAR (tail), Vxwidget_view_list);
+ }
+ }
+ }
+}
+
+struct xwidget_view*
+xwidget_view_lookup (struct xwidget* xw, struct window *w)
+{
+ Lisp_Object xwidget, window, ret;
+ XSETXWIDGET (xwidget, xw);
+ XSETWINDOW (window, w);
+
+ ret = Fxwidget_view_lookup (xwidget, window);
+
+ return EQ (ret, Qnil) ? NULL : XXWIDGET_VIEW (ret);
+}
+
+struct xwidget*
+lookup_xwidget (Lisp_Object spec)
+{
+ /* When a xwidget lisp spec is found initialize the C struct that is used in the C code.
+ This is done by redisplay so values change if the spec changes.
+ So, take special care of one-shot events
+
+ TODO remove xwidget init from display spec. simply store an xwidget reference only and set
+ size etc when creating the xwidget, which should happen before insertion into buffer
+ */
+ int found = 0, found1 = 0, found2 = 0;
+ Lisp_Object value;
+ struct xwidget *xw;
+
+ value = xwidget_spec_value (spec, QCxwidget, &found1);
+ xw = XXWIDGET(value);
+
+ /* value = xwidget_spec_value (spec, QCtype, &found); */
+ /* xw->type = SYMBOLP (value) ? value : Qbutton; //default to button */
+ /* value = xwidget_spec_value (spec, QCtitle, &found2); */
+ /* xw->title = STRINGP (value) ? (char *) SDATA (value) : "?"; //funky cast FIXME TODO */
+
+ /* value = xwidget_spec_value (spec, QCheight, NULL); */
+ /* xw->height = INTEGERP (value) ? XFASTINT (value) : 50; */
+ /* value = xwidget_spec_value (spec, QCwidth, NULL); */
+ /* xw->width = INTEGERP (value) ? XFASTINT (value) : 50; */
+
+ /* value = xwidget_spec_value (spec, QCplist, NULL); */
+ /* xw->plist = value; */
+ /* coordinates are not known here */
+ printf ("lookup_xwidget xwidget_id:%d type:%d found:%d %d %d title:'%s' (%d,%d)\n", xw,
+ xw->type, found, found1, found2, xw->title, xw->height, xw->width);
+
+ //assert_valid_xwidget_id (id, "lookup_xwidget");
+ return xw;
+}
+
+/*set up detection of touched xwidget*/
+void
+xwidget_start_redisplay (void)
+{
+ for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
+ {
+ if (XWIDGET_VIEW_P (XCAR (tail)))
+ XXWIDGET_VIEW (XCAR (tail))->redisplayed = 0;
+ }
+}
+
+/* the xwidget was touched during redisplay, so it isnt a candidate for hiding*/
+void
+xwidget_touch (struct xwidget_view *xv)
+{
+ xv->redisplayed = 1;
+}
+
+int
+xwidget_touched (struct xwidget_view *xv)
+{
+ return xv->redisplayed;
+}
+
+/* redisplay has ended, now we should hide untouched xwidgets
+*/
+void
+xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix)
+{
+
+ int i;
+ struct xwidget *xw;
+ int area;
+
+
+ xwidget_start_redisplay ();
+ //iterate desired glyph matrix of window here, hide gtk widgets
+ //not in the desired matrix.
+
+ //this only takes care of xwidgets in active windows.
+ //if a window goes away from screen xwidget views wust be deleted
+
+ // dump_glyph_matrix(matrix, 2);
+ for (i = 0; i < matrix->nrows; ++i)
+ {
+ // dump_glyph_row (MATRIX_ROW (matrix, i), i, glyphs);
+ struct glyph_row *row;
+ row = MATRIX_ROW (matrix, i);
+ if (row->enabled_p != 0)
+ {
+ for (area = LEFT_MARGIN_AREA; area < LAST_AREA; ++area)
+ {
+ struct glyph *glyph = row->glyphs[area];
+ struct glyph *glyph_end = glyph + row->used[area];
+ for (; glyph < glyph_end; ++glyph)
+ {
+ if (glyph->type == XWIDGET_GLYPH)
+ {
+ /*
+ the only call to xwidget_end_redisplay is in dispnew
+ xwidget_end_redisplay(w->current_matrix);
+ */
+ xwidget_touch (xwidget_view_lookup(glyph->u.xwidget,
+ w));
+ }
+ }
+ }
+ }
+ }
+
+ for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
+ {
+ if (XWIDGET_VIEW_P (XCAR (tail))) {
+ struct xwidget_view* xv = XXWIDGET_VIEW (XCAR (tail));
+
+ //"touched" is only meaningful for the current window, so disregard other views
+ if (XWINDOW (xv->w) == w) {
+ if (xwidget_touched(xv))
+ xwidget_show_view (xv);
+ else
+ xwidget_hide_view (xv);
+ }
+ }
+ }
+}
+
+/* Kill all xwidget in BUFFER. */
+void
+kill_buffer_xwidgets (Lisp_Object buffer)
+{
+ Lisp_Object tail, xwidget;
+ for (tail = Fget_buffer_xwidgets (buffer); CONSP (tail); tail = XCDR (tail))
+ {
+ xwidget = XCAR (tail);
+ Vxwidget_list = Fdelq (xwidget, Vxwidget_list);
+ /* TODO free the GTK things in xw */
+ {
+ CHECK_XWIDGET (xwidget);
+ struct xwidget *xw = XXWIDGET (xwidget);
+ if (xw->widget_osr && xw->widgetwindow_osr)
+ {
+ gtk_widget_destroy(xw->widget_osr);
+ gtk_widget_destroy(xw->widgetwindow_osr);
+ }
+ }
+ }
+}
+
+#endif /* HAVE_XWIDGETS */
--- /dev/null
+#ifndef XWIDGET_H_INCLUDED
+#define XWIDGET_H_INCLUDED
+
+void x_draw_xwidget_glyph_string (struct glyph_string *s);
+void syms_of_xwidget ();
+
+extern Lisp_Object Qxwidget;
+
+
+int valid_xwidget_spec_p (Lisp_Object object) ;
+
+#include <gtk/gtk.h>
+
+
+/*
+each xwidget instance/model is described by this struct.
+
+lisp pseudovector.
+
+
+ */
+struct xwidget{
+ struct vectorlike_header header;
+ Lisp_Object plist;//auxilliary data
+ Lisp_Object type;//the widget type
+ Lisp_Object buffer; //buffer where xwidget lives
+ Lisp_Object title;//a title that is used for button labels for instance
+
+ //here ends the lisp part.
+ //"height" is the marker field
+ int height;
+ int width;
+
+ //for offscreen widgets, unused if not osr
+ GtkWidget* widget_osr;
+ GtkWidget* widgetwindow_osr;
+ /* Non-nil means kill silently if Emacs is exited. */
+ unsigned int kill_without_query : 1;
+
+};
+
+
+//struct for each xwidget view
+struct xwidget_view {
+ struct vectorlike_header header;
+ Lisp_Object model;
+ Lisp_Object w;
+
+ //here ends the lisp part.
+ //"redisplayed" is the marker field
+ int redisplayed; //if touched by redisplay
+
+ int hidden;//if the "live" instance isnt drawn
+
+ GtkWidget* widget;
+ GtkWidget* widgetwindow;
+ GtkWidget* emacswindow;
+ int x; int y;
+ int clip_right; int clip_bottom; int clip_top; int clip_left;
+
+
+ long handler_id;
+};
+
+/* Test for xwidget pseudovector*/
+#define XWIDGETP(x) PSEUDOVECTORP (x, PVEC_XWIDGET)
+#define XXWIDGET(a) (eassert (XWIDGETP(a)), \
+ (struct xwidget *) XUNTAG(a, Lisp_Vectorlike))
+
+#define CHECK_XWIDGET(x) \
+ CHECK_TYPE (XWIDGETP (x), Qxwidgetp, x)
+
+/* Test for xwidget_view pseudovector */
+#define XWIDGET_VIEW_P(x) PSEUDOVECTORP (x, PVEC_XWIDGET_VIEW)
+#define XXWIDGET_VIEW(a) (eassert (XWIDGET_VIEW_P(a)), \
+ (struct xwidget_view *) XUNTAG(a, Lisp_Vectorlike))
+
+#define CHECK_XWIDGET_VIEW(x) \
+ CHECK_TYPE (XWIDGET_VIEW_P (x), Qxwidget_view_p, x)
+
+struct xwidget_type
+{
+ /* A symbol uniquely identifying the xwidget type, */
+ Lisp_Object *type;
+
+ /* Check that SPEC is a valid image specification for the given
+ image type. Value is non-zero if SPEC is valid. */
+ int (* valid_p) (Lisp_Object spec);
+
+ /* Next in list of all supported image types. */
+ struct xwidget_type *next;
+};
+
+static struct xwidget_type *lookup_xwidget_type (Lisp_Object symbol);
+
+struct xwidget* xwidget_from_id(int id);
+
+//extern int xwidget_owns_kbd;
+
+void xwidget_start_redisplay();
+void xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix);
+
+void xwidget_touch (struct xwidget_view *xw);
+
+//void assert_valid_xwidget_id(int id,char *str);
+
+struct xwidget* lookup_xwidget (Lisp_Object spec);
+#define XG_XWIDGET "emacs_xwidget"
+#define XG_XWIDGET_VIEW "emacs_xwidget_view"
+void xwidget_view_delete_all_in_window( struct window *w );
+
+void kill_buffer_xwidgets (Lisp_Object buffer);
+#endif /* XWIDGET_H_INCLUDED */
--- /dev/null
+;; -*- lexical-binding: t; -*-
+
+(require 'cl)
+(require 'xwidget)
+(require 'xwidget-test)
+(require 'parallel)
+
+(defvar xwidget-parallel-config (list :emacs-path (expand-file-name
+ "~/packages/xwidget-build/src/emacs")))
+
+(defmacro xwidget-deftest (name types &rest body)
+ (declare (indent defun))
+ (if (null types)
+ `(ert-deftest ,(intern (format "%s" name)) ()
+ (let ((parallel-config xwidget-parallel-config))
+ ,@body))
+ `(progn
+ ,@(loop for type in types
+ collect
+ `(ert-deftest ,(intern (format "%s-%s" name type)) ()
+ (let ((parallel-config xwidget-parallel-config)
+ (type ',type)
+ (title ,(symbol-name type)))
+ ,@body))))))
+
+(xwidget-deftest xwidget-make-xwidget (Button ToggleButton slider socket cairo)
+ (let* ((beg 1)
+ (end 1)
+ (width 100)
+ (height 100)
+ (data nil)
+ (proc (parallel-start
+ (lambda (beg end type title width height data)
+ (require 'xwidget)
+ (require 'cl)
+ (with-temp-buffer
+ (insert ?\0)
+ (let* ((buffer (current-buffer))
+ (xwidget (make-xwidget beg end type title width height data buffer)))
+ (set-xwidget-query-on-exit-flag xwidget nil)
+ (parallel-remote-send (coerce (xwidget-info xwidget) 'list))
+ (parallel-remote-send (buffer-name buffer))
+ (buffer-name (xwidget-buffer xwidget)))))
+ :env (list beg end type title width height data)))
+ (results (parallel-get-results proc)))
+ (should (parallel-success-p proc))
+ (when (parallel-success-p proc)
+ (destructuring-bind (xwidget-buffer temp-buffer xwidget-info)
+ results
+ (should (equal (list type title width height)
+ xwidget-info))
+ (should (equal temp-buffer xwidget-buffer))))))
+
+(xwidget-deftest xwidget-query-on-exit-flag ()
+ (should (equal '(nil t)
+ (parallel-get-results
+ (parallel-start (lambda ()
+ (require 'xwidget)
+ (let ((xwidget (make-xwidget 1 1 'Button "Button" 100 100 nil)))
+ (parallel-remote-send (xwidget-query-on-exit-flag xwidget))
+ (set-xwidget-query-on-exit-flag xwidget nil)
+ (xwidget-query-on-exit-flag xwidget))))))))
+
+(xwidget-deftest xwidget-query-on-exit-flag (Button ToggleButton slider socket cairo)
+ (should (parallel-get-result
+ (parallel-start (lambda (type title)
+ (require 'xwidget)
+ (with-temp-buffer
+ (let ((xwidget (make-xwidget 1 1 type title 10 10 nil)))
+ (set-xwidget-query-on-exit-flag xwidget nil)
+ (xwidgetp xwidget))))
+ :env (list type title)))))
+
+(xwidget-deftest xwidget-CHECK_XWIDGET ()
+ (should (equal (parallel-get-result
+ (parallel-start (lambda ()
+ (require 'xwidget)
+ (xwidget-info nil))))
+ '(wrong-type-argument xwidgetp nil)))
+ (should (equal (parallel-get-result
+ (parallel-start (lambda ()
+ (require 'xwidget)
+ (xwidget-view-info nil))))
+ '(wrong-type-argument xwidget-view-p nil))))
+
+(xwidget-deftest xwidget-view-p (Button ToggleButton slider socket cairo)
+ (should (parallel-get-result
+ (parallel-start (lambda (type title)
+ (require 'xwidget)
+ (with-temp-buffer
+ (insert ?\0)
+ (let* ((xwidget (xwidget-insert 1 type title 100 100))
+ (window (xwidget-display xwidget)))
+ (set-xwidget-query-on-exit-flag xwidget nil)
+ (xwidget-view-p
+ (xwidget-view-lookup xwidget window)))))
+ :env (list type title)
+ :graphical t
+ :emacs-args '("-T" "emacs-debug")))))
+
+(defun xwidget-interactive-tests ()
+ "Interactively test Button ToggleButton and slider.
+
+Start Emacs instances and try to insert the xwidget."
+ (interactive)
+ (flet ((test-xwidget (type)
+ (parallel-get-result
+ (parallel-start (lambda ()
+ (require 'xwidget)
+ (with-temp-buffer
+ (insert ?\0)
+ (set-xwidget-query-on-exit-flag
+ (xwidget-insert 1 type (format "%s" type) 100 100) nil)
+ (display-buffer (current-buffer))
+ (cons type (or (y-or-n-p (format "Do you see a %s?" type)) 'failed))))
+ :graphical t
+ :debug t
+ :config xwidget-parallel-config))))
+ (message "%S" (mapcar #'test-xwidget '(Button ToggleButton slider)))))
+
+(provide 'xwidget-tests)