Permalink
Browse files

minor cleanups and doc

  • Loading branch information...
1 parent 3343cf3 commit 4389ab5f16fec34c126d666ecbdbe7cd1cb7f595 joakim@verona.se committed Jul 10, 2011
Showing with 400 additions and 33 deletions.
  1. +102 −13 README.xwidget
  2. +32 −0 lisp/xwidget-screencast.el
  3. +229 −0 src/xwidget-attic.c
  4. +37 −20 src/xwidget.c
View
115 README.xwidget
@@ -198,20 +198,72 @@ stuff that needs to work:
- lookup xw-view for xwidget in emacs window(during redisplay)
(- do something for all siblings of a xw-view. not atm)
+*** TODO xwidget creation interface
+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
+ assynchronous 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.
+
+
+
** 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.
-** TODO look into more ways of displaying xwidgets, like binding them to a
+** 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]
@@ -298,10 +350,9 @@ make
** TODO mvc code crashes after a while
-seemingly only when compiling with optimizations
+seemingly only when compiling with optimizations.
+I have no idea why.
-** TODO delete xwidgets belonging to an emacs window
-when it closes
** TODO xwidget-resize-at
currently it rewrites the display spec. then it resizes the xwidget
views. maybe rewriting the spec should be sufficient, and changes to
@@ -349,7 +400,7 @@ webkitViewportAttributesRecompute is the offender.
maybe try gtk3 variants?
-export CFLAGS="`pkg-config --cflags webkitgtk-3.0 ` -DHAVE_WEBKIT_OSR -g"
+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
@@ -420,6 +471,8 @@ 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 ()
@@ -448,12 +501,32 @@ or this funny hack:
<jave> lucian: that was a pretty cool idea!
-**** webkit_web_view_load_string ()
+*** webkit_web_view_load_string ()
I would like preview of html in a buffer rather than from uri.
-** TODO clipping of controllers
+*** TODO simple xwidget-webkit wrapper
+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.
+
+** 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
@@ -478,6 +551,7 @@ 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]
@@ -555,7 +629,8 @@ the needed data is private to the base class. to overcome this:
JanD pointed out the GTK3 port already has its own subclass, so I
modified that one.
-*** TODO clip top
+*** 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
@@ -569,9 +644,20 @@ makes it harder to use the allocation workarounds.
see:
- gtk_widget_set_size_request
- gtkscrolledwindow
-** TODO use FRAME_GTK_WIDGET (f)
-rather than gwfixed
+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
+furthi investigation,
+
+** TODO 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.
+*** TODO use FRAME_GTK_WIDGET (f)
+rather than gwfixed.
+
+*** TODO support configure
** DONE translate clicks
CLOSED: [2011-07-03 Sun 22:12]
on onscreen webkit peer to offscreen
@@ -584,18 +670,21 @@ forwarded them offscreen!
** TODO investigate gdk_window_redirect_to_drawable
http://developer.gnome.org/gdk/stable/gdk-Windows.html#gdk-offscreen-window-set-embedder
-maybe control be used in place of my own copy hacks?
+maybe control 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.
-** TODO remove xwidget_views when emacs window is deleted
+** 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
** notes from x_draw_xwidget_glyph_string
View
32 lisp/xwidget-screencast.el
@@ -0,0 +1,32 @@
+;;(require 'screencast)
+(require 'xwidget)
+(defconst xwidget-screencast-webkit '("Hello, and welcome to a
+ short demo of the Emacs xwidget branch, and the Webkit
+ integration it provides." n
+ "Xwidgets are toolkit widgets that behave like images in an
+ Emacs buffer. Except they are actual widgets, so you can
+ interact with them." n
+ "There are several, but people seem to fancy the webkit the most so lets have a look!"
+ (insert "some text")
+ (xwidget-insert (point-min) 'webkit-osr "webkit-osr" 500 1000 5)
+ n
+ "Okay so thats an actual webkit instance in an Emacs buffer! " n
+ "Mouse-overs work" n
+ "Mouse-clicks work" n
+ (split-window-vertically)
+ "You can split the buffer and scroll the windows separately, as
+ usual in Emacs. This is however not so usual in the browser
+ world for some reason." n
+ "So, can you use the xwidget branch as your main Emacs instance?"n
+ "Not yet, its still not mature. There are many tricky issues
+ left. That being said, there are many simple tasks to help out
+ with also if you like!" ))
+
+
+(defun xwidget-screencast(&optional arg)
+ "Displays the screencast for xwidgets."
+ (interactive "P")
+ (apply (if arg
+ 'screencast-record
+ 'screencast)
+ xwidget-screencast-webkit "xvidgets" 1 ()))
View
229 src/xwidget-attic.c
@@ -0,0 +1,229 @@
+static int once = 0;
+
+int
+xwidget_has_composition(void){ //unused
+int event_base, error_base;
+Display* dpy = GDK_DISPLAY ();
+int i;
+ if(xwidget_query_composition_called)
+ return hasNamePixmap;
+ xwidget_query_composition_called = 1;
+
+ //do this once in an emacs session
+
+ if(gdk_display_supports_composite(gdk_display_get_default ())){
+ hasNamePixmap = 1;
+ }else{
+ return 0;
+ }
+ return 1;
+}
+
+
+
+
+
+void
+xwidget_end_composition(struct xwidget* w){ //unused
+ //XCompositeUnredirectWindow(); stop redirecting, should be called when the socket is destroyed
+}
+
+
+static gboolean
+xwidget_composite_draw_phantom(struct xwidget* xw,
+ int x, int y,
+ int clipx, int clipy)
+{
+ FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (xw->widget), XG_FRAME_DATA);
+ ////////////////////////////////////////////////////////////////
+ //Example 7. Composited windows
+ GdkRegion *region;
+ GtkWidget *child;
+ cairo_t *cr;
+ printf("xwidget_composite_draw_2 at:%d %d\n", x,y);
+ /* get our child (in this case, the event box) */
+ child = xw->widget; //gtk_bin_get_child (GTK_BIN (widget));
+ /* create a cairo context to draw to the emacs window */
+ // cr = gdk_cairo_create (gtk_widget_get_window (f->gwfixed));//GTK_WIDGET(xw->emacswindow));//xw->widgetwindow));//widget->window);
+ cr = gdk_cairo_create (gtk_widget_get_window (f->gwfixed));//GTK_WIDGET(xw->emacswindow));//));//widget->window);
+ /* the source data is the (composited) xwidget */
+ //cairo_move_to(cr, xw->x, xw->y);
+
+ cairo_rectangle(cr, x,y, clipx, clipy);
+ cairo_clip(cr);
+
+ cairo_set_source_rgb(cr,1.0,0,0);
+ cairo_rectangle(cr,x,y,xw->width,xw->height);
+ cairo_fill(cr);
+
+ gdk_cairo_set_source_pixmap (cr, child->window,
+ x,//child->allocation.x,
+ y//child->allocation.y
+ );
+ /* draw no more than our expose event intersects our child */
+ /* region = gdk_region_rectangle (&child->allocation);
+ gdk_region_intersect (region, event->region);
+ gdk_cairo_region (cr, region);
+ cairo_clip (cr); */
+ /* composite, with a 50% opacity */
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ //cairo_paint_with_alpha (cr, phantom ? 0.5 : 0);
+ cairo_paint_with_alpha (cr, 0.9);
+ //cairo_paint(cr);//transparency);
+ /* we're done */
+ cairo_destroy (cr);
+ return FALSE;
+}
+
+
+
+/*
+static gboolean
+xwidget_composite_draw(GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer data)
+{
+ struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
+ printf("xwidget_composite_draw %s\n", data);
+ xwidget_composite_draw_2(widget,
+ event,
+ data,
+ xw->x, xw->y, 0);
+ return FALSE;
+}
+*/
+
+
+static gboolean
+xwidget_composite_draw_widgetwindow(GtkWidget *widget,
+ GdkEventExpose *event,
+ gpointer data)
+{
+ struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
+ cairo_t *cr;
+ GdkPixmap *pixmap;
+ pixmap=xw->widget->window;
+ printf("xwidget_composite_draw_widgetwindow xw.id:%d xw.type:%d window:%d\n", xw->id,xw->type, gtk_widget_get_window (widget));
+ //if(xw->type!=3)//TODO this is just trial and terror to see if i can draw the live socket anywhere at all
+ cr = gdk_cairo_create (gtk_widget_get_window (widget));//GTK_LAYOUT (xw->widgetwindow)->bin_window);//
+ //else cr = gdk_cairo_create (gtk_widget_get_window (xw->emacswindow));
+ cairo_rectangle(cr, 0,0, xw->width, xw->height);
+ cairo_clip(cr);
+
+ cairo_set_source_rgb(cr,0,1.0,0);
+ cairo_rectangle(cr, 0,0, xw->width, xw->height);
+ cairo_fill(cr);
+ gdk_cairo_set_source_pixmap (cr, pixmap,
+ 0,0);
+
+ cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
+ cairo_paint_with_alpha (cr, 0.9);
+ //cairo_paint(cr);
+ cairo_destroy (cr);
+
+ return FALSE;
+}
+
+
+//type support nevermind for now
+
+/* /\* List of supported image types. Use define_image_type to add new */
+/* types. Use lookup_image_type to find a type for a given symbol. *\/ */
+
+/* static struct wxidget_type *wxidget_types; */
+
+/* /\* Look up xwidget type SYMBOL, and return a pointer to its xwidget_type */
+/* structure. Value is null if SYMBOL is not a known image type. *\/ */
+
+/* static INLINE struct xwidget_type *lookup_xwidget_type (Lisp_Object symbol) */
+/* { */
+/* struct xwidget_type *type; */
+
+/* for (type = xwidget_types; type; type = type->next) */
+/* if (EQ (symbol, *type->type)) */
+/* break; */
+
+/* return type; */
+/* } */
+
+
+////////////////////////////////////////////////////////////////
+
+/* delete the xwidget and its native widget peer(unused) */
+void xwidget_delete(struct xwidget* xw);
+
+
+void
+xwidget_delete (struct xwidget *xw)
+{
+ printf ("xwidget %d deleted\n", xw->id);
+ xw->initialized = 0;
+ gtk_widget_destroy (xw->widget);
+
+}
+
+
+/* redraw all xwidgets(unused) */
+void
+xwidget_invalidate (void)
+{
+ int i;
+ struct xwidget *xw;
+ printf ("invalidate ");
+ for (i = 0; i < MAX_XWIDGETS; i++)
+ {
+ xw = &xwidgets[i];
+ if (xw->initialized)
+ {
+ printf ("%d,", i);
+ gtk_widget_queue_draw_area (xw->widget, 0, 0, xw->width,
+ xw->height);
+ }
+ }
+ printf ("\n");
+}
+
+
+/* initializes the xwidget model */
+void
+xwidget_init_model (struct xwidget *xw,
+ struct glyph_string *s,
+ int x, int y)
+{
+ xw->id = s->xwidget_id;
+ xw->initialized = 1;
+}
+
+
+
+DEFUN ("xwidget-replug", Fxwidget_replug, Sxwidget_replug, 2, 2, 0,
+ doc: /* unplug from socket1 plug into socket2.*/
+ )
+ (Lisp_Object old_parent, Lisp_Object new_parent)
+{
+
+ struct xwidget *xw1;
+ struct xwidget *xw2;
+
+
+ GtkWidget* widget;
+ CHECK_NUMBER (old_parent);
+ CHECK_NUMBER (new_parent);
+
+ xw1 = &xwidgets[XFASTINT (old_parent)];
+ xw2 = &xwidgets[XFASTINT (new_parent)];
+
+
+ ///this wasnt thought through. we need the views rather than the model.
+ //so we need to map xw+w to xv
+
+ widget = xw1->widget->gtk_socket_get_plug_window ();
+
+ //the plug...
+ gtk_widget_ref(widget);//...gets an xtra ref to prevent garb, then it ...
+ gtk_container_remove(GTK_CONTAINER(xw1->widget), widget);//...is uplugged from old socket and...
+ gtk_container_add(GTK_CONTAINER(xw2->widget), widget);//...replugged in new socket...
+ gtk_widget_unref(widget);//...and lastly remove the ref
+
+ return Qnil;
+}
View
57 src/xwidget.c
@@ -90,8 +90,11 @@
#endif
+#include <wchar.h>
+
#ifdef HAVE_WEBKIT
#include <webkitgtk.h>
+
#endif
@@ -412,15 +415,10 @@ xwidget_osr_button_callback ( GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
{
- gdouble x, y;
struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
- GdkEventButton* eventcopy = gdk_event_copy(event);
- x = ((GdkEventButton*)event)->x;
- y = ((GdkEventButton*)event)->y;
-
- printf ("button callback %d %d\n",x,y);
+ GdkEvent* eventcopy = gdk_event_copy(event);
- eventcopy->window = gtk_widget_get_window(xw->widget_osr);
+ ((GdkEventButton*)eventcopy)->window = gtk_widget_get_window(xw->widget_osr);
gtk_main_do_event(eventcopy); //TODO this will leak events. they should be deallocated later
}
@@ -620,7 +618,7 @@ 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 clpping
+ moving and clipping is done here. also view init.
*/
int box_line_hwidth = eabs (s->face->box_line_width);
@@ -676,15 +674,15 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
|| (xv->clip_top != clip_top)
|| (xv->clip_left != clip_left)){
gtk_widget_set_size_request (GTK_WIDGET (xv->widgetwindow), clip_right + clip_left, clip_bottom + clip_top);
- gtk_fixed_put(GTK_FIXED(xv->widgetwindow), xv->widget, -clip_left, -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
if (!xwidget_hidden(xv)){
- gtk_widget_queue_draw (xv->widgetwindow);
+ gtk_widget_queue_draw (GTK_WIDGET(xv->widgetwindow));
gtk_widget_queue_draw (xv->widget);
}
}
@@ -730,7 +728,7 @@ DEFUN ("xwidget-webkit-get-title", Fxwidget_webkit_get_title, Sxwidget_webkit_g
{
//TODO support multibyte strings
const gchar* str=webkit_web_view_get_title( WEBKIT_WEB_VIEW(xid2xw(xwidget_id)->widget_osr));
- return make_string_from_bytes(str, wcslen(str), strlen(str));
+ return make_string_from_bytes(str, wcslen((const wchar_t *)str), strlen(str));
}
@@ -798,18 +796,37 @@ DEFUN("xwidget-info", Fxwidget_info , Sxwidget_info, 1,1,0, doc: /* get xwidget
struct xwidget *xw = xid2xw(xwidget_id);
Lisp_Object info;
- info = Fmake_vector (make_number (7), Qnil);
+ info = Fmake_vector (make_number (4), Qnil);
XVECTOR (info)->contents[0] = make_number(xw->id);
- XVECTOR (info)->contents[1] = make_number(xw->type);
- XVECTOR (info)->contents[2] = Qnil; //make_number(xw->x);
- XVECTOR (info)->contents[3] = Qnil;//make_number(xw->y);
- XVECTOR (info)->contents[4] = make_number(xw->width);
- XVECTOR (info)->contents[5] = make_number(xw->height);
- XVECTOR (info)->contents[6] = Qnil;//make_number(xw->hidden);
+ XVECTOR (info)->contents[1] = xw->type;
+ XVECTOR (info)->contents[2] = make_number(xw->width);
+ XVECTOR (info)->contents[3] = make_number(xw->height);
+
+
+ return info;
+}
+
+DEFUN("xwidget-view-info", Fxwidget_view_info , Sxwidget_view_info, 2,2,0, doc: /* get xwidget view props */)
+ (Lisp_Object xwidget_id, Lisp_Object window)
+{
+ struct xwidget *xw = xid2xw(xwidget_id);
+ struct xwidget_view* xv = xwidget_view_lookup(xw, XWINDOW(window));
+
+ Lisp_Object info;
+
+ info = Fmake_vector (make_number (6), Qnil);
+ XVECTOR (info)->contents[0] = make_number(xv->x);
+ XVECTOR (info)->contents[1] = make_number(xv->y);
+ XVECTOR (info)->contents[2] = make_number(xv->clip_right);
+ XVECTOR (info)->contents[3] = make_number(xv->clip_bottom);
+ XVECTOR (info)->contents[4] = make_number(xv->clip_top);
+ XVECTOR (info)->contents[5] = make_number(xv->clip_left);
return info;
}
+
+
//xterm.c listens to xwidget_owns_kbd and tries to not eat events when its set
int xwidget_owns_kbd = 0;
DEFUN ("xwidget-set-keyboard-grab", Fxwidget_set_keyboard_grab, Sxwidget_set_keyboard_grab, 2, 2, 0, doc: /* set unset kbd grab for xwidget. */
@@ -938,6 +955,7 @@ syms_of_xwidget (void)
defsubr (&Sxwidget_send_keyboard_event);
defsubr (&Sxwidget_embed_steal_window);
defsubr (&Sxwidget_info);
+ defsubr (&Sxwidget_view_info);
defsubr (&Sxwidget_resize_internal);
defsubr (&Sxwidget_embed_steal_window);
@@ -1050,12 +1068,11 @@ xwidget_from_id (int id)
void xwidget_view_delete_all_in_window( struct window *w )
{
- //xxx
struct xwidget_view* xv = NULL;
for (int i = 0; i < MAX_XWIDGETS; i++){
xv = &xwidget_views[i];
if(xv->w == w){
- gtk_widget_destroy(xv->widgetwindow);
+ gtk_widget_destroy(GTK_WIDGET(xv->widgetwindow));
}
}
}

0 comments on commit 4389ab5

Please sign in to comment.