1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-19 04:10:18 -08:00
emacs/README.xwidget
Grégoire Jadi e32984567a * lisp/xwidget.el (report-xwidget-bug): Add a function to submit a bug
with the proper address and pseudo-header.
* README.xwidget: Update the documentation to mention
`report-xwidget-bug'.
2013-06-13 09:42:41 +02:00

1730 lines
69 KiB
Org Mode

-*-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