]> code.delx.au - gnu-emacs/commitdiff
merge from upstream. currently seems to have bitroted and i get segfaults
authorJoakim Verona <joakim@verona.se>
Sat, 5 Feb 2011 10:23:09 +0000 (11:23 +0100)
committerJoakim Verona <joakim@verona.se>
Sat, 5 Feb 2011 10:23:09 +0000 (11:23 +0100)
20 files changed:
README.xwidget [new file with mode: 0644]
configure
configure.in
lisp/xwidget-test.el [new file with mode: 0644]
lisp/xwidget.el [new file with mode: 0644]
src/Makefile.in
src/dispextern.h
src/dispnew.c
src/emacs.c
src/frame.h
src/gtkutil.c
src/insdel.c
src/keyboard.c
src/termhooks.h
src/window.c
src/xdisp.c
src/xfns.c
src/xterm.c
src/xwidget.c [new file with mode: 0644]
src/xwidget.h [new file with mode: 0644]

diff --git a/README.xwidget b/README.xwidget
new file mode 100644 (file)
index 0000000..ce5828c
--- /dev/null
@@ -0,0 +1,190 @@
+* 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, and xembed widgets
+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. Also, xwidgets exists in only one copy,
+where a plain image can be shown in several windows. The xwidget code
+tries to handle this by essentialy making a screen capture of the
+widget and displaying those in the non-active windows, and the live
+widget in the active window. The current snapshot code doesnt work if
+the live xwidget is off-screen. This seems to be solveable by using
+the XComposite interface, but that doesnt currently work.
+
+The current state is that one window, one frame, showing many xwidgets
+is a nice demo. One frame, many windows, will have lots of display
+glitches. Many frames, many windows, will work even worse.
+
+
+* 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
+synchonous 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. 
+
+- In the general case, there can only be one xwidget, and several views of
+  it. There is one live view, and several phantom views. The live view is defined
+  to be in the currently selected window. All other views are phantom views. 
+
+  Even this simple rule is difficult to implement in practice because Emacs
+  display is clever and optimized. It is often difficult to know that a xwdiget
+  hasnt actually been displayed after a redisplay.
+
+- phantom views of xwidgets are thankfully not so hard because gtk
+  supports snapshoting of many widget types. Snapshoting doesnt seem
+  to work if the live widget is offscreen. This might be solvable with
+  xcomposite, but attempts have so far failed.
+
+- 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.
+
+- The case of showing an xwidget in several frames is not solved at all
+  currently. This would mean moving the live xwidget between frames when the
+  selected window moves. The gtk widget will need to be reparented between
+  windows, which seems fragile. 
+
+** 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.
+
+** xwidget phantom views in particular
+The general aproach so far has been to have a "live" xwidget moved
+around in the emacs window. when the selected window changes, the live
+xwidget is moved there. the possibly other views of the xwidget are
+called "phantoms" and are snapshoted from the live xwidget.
+
+This turned out to be difficult and a lot of different aproaches has
+been tried. The current, somewhat promising, aproach is to enable
+composition for the xwidgets gtk widget peer. This enables renedering
+of the widget to offscreen backing store. snapshoting then becomes
+more robus, because otherwise snapshoting is dependent on the live
+xwidget being on-screen, which isnt necesarily the case.
+
+on the other hand, compositing introduces other issues. the live
+xwidget isnt drawn automatically at all any more, so we need our own
+expose handler to deal with drawing. this in turn enables us to toy
+with transparency and such.
+
+** 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 will probably always be a distinction between live xwidgets and
+phantom xwidgets. how this distinction is realized has and will
+change.
+
+- 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 the currently tried aproach and it works so-so at the moment.
+
+- 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.
+
+This aproach seems promising, but complicated.
+
+- 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.
+
+* ToDo:s
+
+** 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.
+
+** 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.
+
+** 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  figure out what to do with the multiple frames case. 
+I havent spent any time at all on this.
+
+** 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.
+
+** 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
+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.
+
index f236975106092cd95c315fb7734c28abc98e1930..7ea4d3a040db5fbeb11e93dccf5065207ab0221e 100755 (executable)
--- a/configure
+++ b/configure
@@ -17164,7 +17164,7 @@ TOOLKIT_LIBW=
 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
 
 
index 58e445b98a64d7460ed01e0ad9ff91f71a36895f..6fd9c76530e277633b0f1369cafc109de2eb000c 100644 (file)
@@ -3190,7 +3190,7 @@ TOOLKIT_LIBW=
 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)
 
diff --git a/lisp/xwidget-test.el b/lisp/xwidget-test.el
new file mode 100644 (file)
index 0000000..4d1760e
--- /dev/null
@@ -0,0 +1,108 @@
+;;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 functions
+(require 'xwidget)
+
+(defun xwidget-demo-basic ()
+  (interactive)
+  (insert "xwidgetdemo<<< a button. another button\n")
+  (xwidget-insert (point-min)  1 "button" 40  50  1)
+  (xwidget-insert          15  2 "toggle" 60  30  2)
+  (xwidget-insert          30  3 "emacs"  400 200 3)
+  (xwidget-insert          20  4 "slider" 100 50  4)
+  (xwidget-insert          40  3 "uzbl-core"   400 400 5)
+  (define-key (current-local-map) [xwidget-event] 'xwidget-handler-demo-basic)
+)
+
+
+(defun xwidget-demo-single ()
+  (interactive)
+  (insert "xwidgetdemo<<< a button. another button\n")
+  (xwidget-insert (point-min) 1 "1" 200 300 1)
+  (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 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 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  %S" xembed-id)
+              ;;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-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)
diff --git a/lisp/xwidget.el b/lisp/xwidget.el
new file mode 100644 (file)
index 0000000..ef20004
--- /dev/null
@@ -0,0 +1,45 @@
+;; xwidget.el - api functions for xwidgets
+;;  see xwidget.c for more api functions
+
+(require 'xwidget-internal)
+
+
+(defun xwidget-insert (pos type title width height  &optional id)
+ "Insert an xwidget at POS, given ID, TYPE, TITLE WIDTH and HEIGHT.
+Return ID
+ID will be made optional, but it isnt implemented yet!
+
+currently interface is lame:
+ :type 1=button, 2=toggle btn, 3=xembed socket(id will be printed to stdout)
+ obviously these should be symbols
+
+ :xwidget-id 1, MUST be unique and < 100 !
+ if slightly wrong, emacs WILL CRASH
+
+These issues are of course fixable but I will continue to
+hand-wave issues like these until the hard parts are solved.
+"
+  (goto-char pos)
+  (put-text-property (point) (+ 1 (point)) 'display (list 'xwidget ':xwidget-id id ':type type ':title title ':width width ':height height))
+  id)
+
+
+(defun xwidget-resize-at (pos width height)
+  "Resize xwidget at postion POS to WIDTH and HEIGHT."
+  (let*
+      ((xwidget-prop (cdr (get-text-property pos 'display)))
+       (id (plist-get  xwidget-prop ':xwidget-id)))
+    (setq xwidget-prop (plist-put xwidget-prop ':width width))
+    (setq xwidget-prop (plist-put xwidget-prop  ':height height))
+          
+    (put-text-property pos (+ 1 pos) 'display (cons 'xwidget xwidget-prop))
+    (message "prop %s" xwidget-prop)
+    (message "id %d w %d  h %d" id width height)
+    (xwidget-resize-internal id width height)
+  ))
+
+;; use declare here?
+;; (declare-function xwidget-resize-internal "xwidget.c" )
+;; check-declare-function?
+
+(provide 'xwidget)
index 98b4c981482b62063f07a73803158cecb355577a..a79139023142b038d00be9bafae19cc4a6788ad5 100644 (file)
@@ -354,8 +354,10 @@ obj=    dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \
        process.o gnutls.o callproc.o \
        region-cache.o sound.o atimer.o \
        doprnt.o intervals.o textprop.o composite.o md5.o xml.o \
+       xwidget.o \
        $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_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_MACHINE_OBJECTS = dosfns.o msdos.o \
index 26e0bb61f17ca0a991daf14ea9f9ec5110691787..3e5d47c4855e245f1ac7a124ca49d8ac6e293ad7 100644 (file)
@@ -23,7 +23,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #define DISPEXTERN_H_INCLUDED
 
 #ifdef HAVE_X_WINDOWS
-
 #include <X11/Xlib.h>
 #ifdef USE_X_TOOLKIT
 #include <X11/Intrinsic.h>
@@ -119,7 +118,7 @@ enum window_part
 
 /* If GLYPH_DEBUG is non-zero, additional checks are activated.  Turn
    it off by defining the macro GLYPH_DEBUG to zero.  */
-
+#define GLYPH_DEBUG 1
 #ifndef GLYPH_DEBUG
 #define GLYPH_DEBUG 0
 #endif
@@ -290,7 +289,10 @@ enum glyph_type
   IMAGE_GLYPH,
 
   /* Glyph is a space of fractional width and/or height.  */
-  STRETCH_GLYPH
+  STRETCH_GLYPH,
+
+  /* Glyph is an external widget drawn by the GUI toolkit.   */
+  XWIDGET_GLYPH
 };
 
 
@@ -433,6 +435,8 @@ struct glyph
     /* Image ID for image glyphs (type == IMAGE_GLYPH).  */
     unsigned img_id;
 
+    unsigned xwidget_id;
+    
     /* Sub-structure for type == STRETCH_GLYPH.  */
     struct
     {
@@ -1301,6 +1305,8 @@ struct glyph_string
   /* Image, if any.  */
   struct image *img;
 
+  int xwidget_id;
+
   /* Slice */
   struct glyph_slice slice;
 
@@ -1954,7 +1960,9 @@ enum display_element_type
   IT_TRUNCATION,
 
   /* Continuation glyphs.  See the comment for IT_TRUNCATION.  */
-  IT_CONTINUATION
+  IT_CONTINUATION,
+
+  IT_XWIDGET
 };
 
 
@@ -2018,6 +2026,7 @@ enum it_method {
   GET_FROM_C_STRING,
   GET_FROM_IMAGE,
   GET_FROM_STRETCH,
+  GET_FROM_XWIDGET,
   NUM_IT_METHODS
 };
 
@@ -2225,6 +2234,12 @@ struct it
       struct {
        Lisp_Object object;
       } stretch;
+      /* method == GET_FROM_XWIDGET */
+      struct {
+       Lisp_Object object;
+        int xwidget_id;
+      } xwidget;
+
     } u;
 
     /* current text and display positions.  */
@@ -2344,6 +2359,10 @@ struct it
   /* If what == IT_IMAGE, the id of the image to display.  */
   int image_id;
 
+  /* If what == IT_XWIDGET*/
+  int xwidget_id;
+
+  
   /* Values from `slice' property.  */
   struct it_slice slice;
 
index 1aef70f1a5d748c984715f38d28808073736231e..4521d0a1a6bb5993414c96330e02788792e61120 100644 (file)
@@ -3417,6 +3417,7 @@ update_single_window (struct window *w, int force_p)
 {
   if (w->must_be_updated_p)
     {
+      printf("window %d must be updated\n");
       struct frame *f = XFRAME (WINDOW_FRAME (w));
 
       /* Record that this is not a frame-based redisplay.  */
@@ -3770,6 +3771,10 @@ update_window (struct window *w, int force_p)
   add_window_display_history (w, w->current_matrix->method, paused_p);
 #endif
 
+  
+  if ((XWINDOW(FRAME_SELECTED_WINDOW (SELECTED_FRAME()))) ==  (w))
+    xwidget_end_redisplay(w->current_matrix);
+  
   clear_glyph_matrix (desired_matrix);
 
   return paused_p;
index 53786b0adae7e92c2c551386fca8e35b6e3e5a2c..fdb9a15cf5fb81fe2125c665c59cd55cf73f01bf 100644 (file)
@@ -47,6 +47,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "buffer.h"
 #include "window.h"
 
+#include "xwidget.h"
+
 #include "systty.h"
 #include "blockinput.h"
 #include "syssignal.h"
@@ -1505,6 +1507,7 @@ main (int argc, char **argv)
       syms_of_xfns ();
       syms_of_xmenu ();
       syms_of_fontset ();
+      syms_of_xwidget();
       syms_of_xsettings ();
 #ifdef HAVE_X_SM
       syms_of_xsmfns ();
index 9687e39a9fcd27401bffefd1f627729eb9d9a4fc..b49e194133e6a910467b4f4e6fab8c6d640318fd 100644 (file)
@@ -498,6 +498,10 @@ struct frame
   /* All display backends seem to need these two pixel values. */
   unsigned long background_pixel;
   unsigned long foreground_pixel;
+
+  /* xwidgets need the gtk container to place gtk widgets*/
+  //GtkWidget *gwfixed;
+  void *gwfixed;//JAVE TODO i dont feel like fixing all compilation errors right now
 };
 
 #define FRAME_KBOARD(f) ((f)->terminal->kboard)
index 6367949a649c921fd0862228b779ca7e90cca20b..c0bc5fc82bf35d120486029baf57c06c09225dc8 100644 (file)
@@ -956,6 +956,10 @@ style_changed_cb (GObject *go,
 /* Create and set up the GTK widgets for frame F.
    Return 0 if creation failed, non-zero otherwise.  */
 
+
+
+
+
 int
 xg_create_frame_widgets (FRAME_PTR f)
 {
@@ -977,7 +981,7 @@ xg_create_frame_widgets (FRAME_PTR f)
 
   wvbox = gtk_vbox_new (FALSE, 0);
   whbox = gtk_hbox_new (FALSE, 0);
-  wfixed = gtk_fixed_new ();  /* Must have this to place scroll bars  */
+  f->gwfixed =  wfixed = gtk_fixed_new ();  /* Must have this to place scroll bars  */
 
   if (! wtop || ! wvbox || ! whbox || ! wfixed)
     {
index 8923a9e12e5dfb623df906af38fc43c3051dc269..7b8605b5babdc2cb170e2387d597ee2bf06b7490 100644 (file)
@@ -27,6 +27,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "window.h"
 #include "blockinput.h"
 #include "region-cache.h"
+#include "xwidget.h"
 
 #ifndef NULL
 #define NULL 0
@@ -1953,6 +1954,8 @@ void
 modify_region (struct buffer *buffer, EMACS_INT start, EMACS_INT end,
               int preserve_chars_modiff)
 {
+  //  printf("modify region\n");
+  xwidget_modify_region();
   struct buffer *old_buffer = current_buffer;
 
   if (buffer != old_buffer)
index d53321306db95d24933d4abd5c4afac20bb96fa9..35fef638d8fcaa7a24bcff36adbe455197e9dc85 100644 (file)
@@ -316,6 +316,7 @@ Lisp_Object Qsave_session;
 #ifdef HAVE_DBUS
 Lisp_Object Qdbus_event;
 #endif
+Lisp_Object Qxwidget_event;
 Lisp_Object Qconfig_changed_event;
 
 /* Lisp_Object Qmouse_movement; - also an event header */
@@ -3956,7 +3957,7 @@ kbd_buffer_get_event (KBOARD **kbp,
          kbd_fetch_ptr = event + 1;
        }
 #endif
-      else if (event->kind == CONFIG_CHANGED_EVENT)
+      else if (event->kind == CONFIG_CHANGED_EVENT || event->kind == XWIDGET_EVENT)
        {
          obj = make_lispy_event (event);
          kbd_fetch_ptr = event + 1;
@@ -5834,6 +5835,8 @@ make_lispy_event (struct input_event *event)
        return apply_modifiers (event->modifiers, event->arg);
       return event->arg;
 
+
+      
     case USER_SIGNAL_EVENT:
       /* A user signal.  */
       {
@@ -5852,6 +5855,11 @@ make_lispy_event (struct input_event *event)
        return Fcons (Qdbus_event, event->arg);
       }
 #endif /* HAVE_DBUS */
+    case XWIDGET_EVENT:
+      {
+        printf("cool, an xwidget event arrived in make_lispy_event!\n");
+        return  Fcons (Qxwidget_event,event->arg);
+      }
 
     case CONFIG_CHANGED_EVENT:
        return Fcons (Qconfig_changed_event,
@@ -11470,6 +11478,11 @@ syms_of_keyboard (void)
   staticpro (&Qdbus_event);
 #endif
 
+  Qxwidget_event = intern ("xwidget-event");
+  staticpro (&Qxwidget_event);
+
+  
+  Qmenu_enable = intern ("menu-enable");
   Qconfig_changed_event = intern_c_string ("config-changed-event");
   staticpro (&Qconfig_changed_event);
 
index b147f6ed0a1da2088fb48d3ce37eca80d24295b6..f41b1411b9a41d5b5205e4993db36c98983ceaa2 100644 (file)
@@ -203,6 +203,8 @@ enum event_kind
   /* Non-key system events (e.g. application menu events) */
   , NS_NONKEY_EVENT
 #endif
+     /* events generated by xwidgets*/
+   , XWIDGET_EVENT
 
 };
 
index 41eed893d6a90bb95e9bfdf0a4e1d6c6bd06a431..1a02a3b1cbb3ff4c2943fbebcfd7a23c0eefec95 100644 (file)
@@ -50,6 +50,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "nsterm.h"
 #endif
 
+#include "xwidget.h"
+
 Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p;
 Lisp_Object Qdisplay_buffer;
 Lisp_Object Qscroll_up, Qscroll_down, Qscroll_command;
@@ -3569,6 +3571,7 @@ select_window (Lisp_Object window, Lisp_Object norecord, int inhibit_point_swap)
       SET_PT (new_point);
   }
 
+  xwidget_invalidate();
   windows_or_buffers_changed++;
   return window;
 }
index adf0d1b874596e51a3ff7c8a29a851c20baa9c61..1c7a884862d79f529ac6a47a371689ec95a831a8 100644 (file)
@@ -310,6 +310,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "font.h"
 
+#include "xwidget.h"
+
 #ifndef FRAME_X_OUTPUT
 #define FRAME_X_OUTPUT(f) ((f)->output_data.x)
 #endif
@@ -850,6 +852,7 @@ static int next_element_from_c_string (struct it *);
 static int next_element_from_buffer (struct it *);
 static int next_element_from_composition (struct it *);
 static int next_element_from_image (struct it *);
+static int next_element_from_xwidget(struct it *);
 static int next_element_from_stretch (struct it *);
 static void load_overlay_strings (struct it *, EMACS_INT);
 static int init_from_display_pos (struct it *, struct window *,
@@ -3811,6 +3814,7 @@ handle_display_prop (struct it *it)
   if (CONSP (prop)
       /* Simple properties.  */
       && !EQ (XCAR (prop), Qimage)
+      && !EQ (XCAR (prop), Qxwidget)
       && !EQ (XCAR (prop), Qspace)
       && !EQ (XCAR (prop), Qwhen)
       && !EQ (XCAR (prop), Qslice)
@@ -3908,6 +3912,7 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
   Lisp_Object location, value;
   struct text_pos start_pos, save_pos;
   int valid_p;
+  //printf("handle_single_display_spec:\n");
 
   /* If SPEC is a list of the form `(when FORM . VALUE)', evaluate FORM.
      If the result is non-nil, use VALUE instead of SPEC.  */
@@ -4192,11 +4197,21 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
      LOCATION specifies where to display: `left-margin',
      `right-margin' or nil.  */
 
+  /*
+  printf("handle_single_display_spec xwidgetp:%d  imagep:%d spacep:%d display_replaced_before_p:%d stringp:%d\n",
+         XWIDGETP(value),
+         valid_image_p (value),
+         (CONSP (value) && EQ (XCAR (value), Qspace)),
+         display_replaced_before_p,
+         STRINGP (value));
+  */
   valid_p = (STRINGP (value)
 #ifdef HAVE_WINDOW_SYSTEM
              || (FRAME_WINDOW_P (it->f) && valid_image_p (value))
 #endif /* not HAVE_WINDOW_SYSTEM */
-             || (CONSP (value) && EQ (XCAR (value), Qspace)));
+             || (CONSP (value) && EQ (XCAR (value), Qspace))
+             || XWIDGETP(value)
+             );
 
   if (valid_p && !display_replaced_before_p)
     {
@@ -4237,8 +4252,20 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
          it->object = value;
          *position = it->position = start_pos;
        }
+      else if (XWIDGETP(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->buffer : object;
+         *position = start_pos;
+
+          it->xwidget_id=lookup_xwidget(value);
+          assert_valid_xwidget_id(it->xwidget_id,"handle_single_display_spec");
+       }      
 #ifdef HAVE_WINDOW_SYSTEM
-      else
+      else //if nothing else, its an image
        {
          it->what = IT_IMAGE;
          it->image_id = lookup_image (it->f, value);
@@ -4301,7 +4328,8 @@ single_display_spec_intangible_p (Lisp_Object prop)
 
   return (CONSP (prop)
          && (EQ (XCAR (prop), Qimage)
-             || EQ (XCAR (prop), Qspace)));
+             || EQ (XCAR (prop), Qspace)
+              || XWIDGETP(prop)));
 }
 
 
@@ -4954,6 +4982,10 @@ push_it (struct it *it)
     case GET_FROM_STRETCH:
       p->u.stretch.object = it->object;
       break;
+    case GET_FROM_XWIDGET:
+      p->u.xwidget.object = it->object;
+      break;
+      
     }
   p->position = it->position;
   p->current = it->current;
@@ -5031,6 +5063,9 @@ pop_it (struct it *it)
       it->object = p->u.image.object;
       it->slice = p->u.image.slice;
       break;
+    case GET_FROM_XWIDGET:
+      it->object = p->u.xwidget.object;
+      break;
     case GET_FROM_STRETCH:
       it->object = p->u.comp.object;
       break;
@@ -5539,7 +5574,8 @@ static int (* get_next_element[NUM_IT_METHODS]) (struct it *it) =
   next_element_from_string,
   next_element_from_c_string,
   next_element_from_image,
-  next_element_from_stretch
+  next_element_from_stretch,
+  next_element_from_xwidget
 };
 
 #define GET_NEXT_DISPLAY_ELEMENT(it) (*get_next_element[(it)->method]) (it)
@@ -6232,6 +6268,7 @@ set_iterator_to_next (struct it *it, int reseat_p)
 
     case GET_FROM_IMAGE:
     case GET_FROM_STRETCH:
+    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.  */
@@ -6482,6 +6519,18 @@ next_element_from_image (struct it *it)
   return 1;
 }
 
+/* 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;
+}
+
+
 
 /* Fill iterator IT with next display element from a stretch glyph
    property.  IT->object is the value of the text property.  Value is
@@ -11416,6 +11465,9 @@ redisplay_internal (int preserve_echo_area)
      frames.  Zero means, only selected_window is considered.  */
   int consider_all_windows_p;
 
+  printf(">>>>redisplay\n");
+  //  xwidget_start_redisplay();
+  
   TRACE ((stderr, "redisplay_internal %d\n", redisplaying_p));
 
   /* No redisplay if running in batch mode or frame is not yet fully
@@ -12119,6 +12171,9 @@ redisplay_internal (int preserve_echo_area)
  end_of_redisplay:
   unbind_to (count, Qnil);
   RESUME_POLLING;
+  //xwidget_end_redisplay();
+    
+  printf("<<<<redisplay\n");
 }
 
 
@@ -14573,6 +14628,11 @@ try_window_reusing_current_matrix (struct window *w)
   struct glyph_row *start_row;
   int start_vpos, min_y, max_y;
 
+  return 0;
+  //xwidgets doesnt like blit scrolling and stuff, try this for now
+  //should be optimized, perhaps by just inhibiting optimizations of windows containing xwidgets.
+  
+  
 #if GLYPH_DEBUG
   if (inhibit_try_window_reusing)
     return 0;
@@ -16165,6 +16225,27 @@ dump_glyph (row, glyph, area)
               glyph->left_box_line_p,
               glyph->right_box_line_p);
     }
+  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_id,
+              '.',
+              glyph->face_id,
+              glyph->left_box_line_p,
+              glyph->right_box_line_p);
+      
+      //      printf("dump xwidget glyph\n");
+    }
 }
 
 
@@ -20199,6 +20280,13 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop,
 
              return OK_PIXELS (width_p ? img->width : img->height);
            }
+
+         if (FRAME_WINDOW_P (it->f)
+             && valid_xwidget_p (prop))
+           {
+              printf("calc_pixel_width_or_height: return dummy size FIXME\n");
+              return OK_PIXELS (width_p ? 100 : 100);
+            }
 #endif
          if (EQ (car, Qplus) || EQ (car, Qminus))
            {
@@ -20695,6 +20783,20 @@ fill_image_glyph_string (struct glyph_string *s)
   s->ybase += s->first_glyph->voffset;
 }
 
+static void
+fill_xwidget_glyph_string (s)
+     struct glyph_string *s;
+{
+  xassert (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_id=s->first_glyph->u.xwidget_id;
+  assert_valid_xwidget_id(s->xwidget_id,"fill_xwidget_glyph_string");
+}
+
 
 /* Fill glyph string S from a sequence of stretch glyphs.
 
@@ -21029,6 +21131,20 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p)
        }                                                               \
      while (0)
 
+#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)
+
+
 
 /* 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
@@ -21184,6 +21300,11 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p)
              BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL,         \
                                        HL, X, LAST_X);                 \
              break;                                                    \
+            case XWIDGET_GLYPH:                                         \
+              BUILD_XWIDGET_GLYPH_STRING (START, END, HEAD, TAIL,       \
+                                          HL, X, LAST_X);               \
+              break;                                                    \
+                                                                       \
                                                                        \
            case GLYPHLESS_GLYPH:                                       \
              BUILD_GLYPHLESS_GLYPH_STRING (START, END, HEAD, TAIL,     \
@@ -21794,6 +21915,112 @@ produce_image_glyph (struct it *it)
     }
 }
 
+static void
+produce_xwidget_glyph (it)
+     struct it *it;
+{
+  //  struct image *img;
+  struct face *face;
+  int glyph_ascent, crop;
+  //  struct glyph_slice slice;
+
+  printf("produce_xwidget_glyph:\n");
+  xassert (it->what == IT_XWIDGET);
+
+  face = FACE_FROM_ID (it->f, it->face_id);
+  xassert (face);
+  /* Make sure X resources of the face is loaded.  */
+  PREPARE_FACE_FOR_DISPLAY (it->f, face);
+
+  /////////////////////////////////////////////
+  
+  //  img = IMAGE_FROM_ID (it->f, it->image_id);
+  //xassert (img);
+  /* Make sure X resources of the image is loaded.  */
+  //prepare_image_for_display (it->f, img);
+
+  struct xwidget* xw=xwidget_from_id(it->xwidget_id);
+  //xwidget_touch(xw);
+  
+  it->ascent = it->phys_ascent = glyph_ascent = xw->height/2;//image_ascent (img, face, &slice);
+  it->descent = xw->height/2;//slice.height - glyph_ascent;
+
+  //it->descent += img->vmargin;
+  //it->descent += img->vmargin;
+  it->phys_descent = it->descent;
+
+  it->pixel_width = xw->width;
+
+  //it->pixel_width += img->hmargin;
+  //it->pixel_width += img->hmargin;
+
+  /////////////////////////////////////////
+  
+  /* 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 = IMAGE_GLYPH;
+         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_id = it->xwidget_id;
+          assert_valid_xwidget_id(glyph->u.xwidget_id,"produce_xwidget_glyph");
+          //     glyph->slice = slice;
+         glyph->font_type = FONT_TYPE_UNKNOWN;
+         ++it->glyph_row->used[area];
+       }
+      else
+       IT_EXPAND_MATRIX_WIDTH (it, area);
+    }
+}
+
 
 /* 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
@@ -22962,6 +23189,8 @@ x_produce_glyphs (struct it *it)
     produce_image_glyph (it);
   else if (it->what == IT_STRETCH)
     produce_stretch_glyph (it);
+  else if (it->what == IT_XWIDGET)
+    produce_xwidget_glyph (it);
 
  done:
   /* Accumulate dimensions.  Note: can't assume that it->descent > 0
@@ -23323,6 +23552,11 @@ get_window_cursor_type (struct window *w, struct glyph *glyph, int *width,
   /* Use normal cursor if not blinked off.  */
   if (!w->cursor_off_p)
     {
+
+      if (glyph != NULL && glyph->type == XWIDGET_GLYPH){
+        printf("attempt xwidget cursor avoidance in get_window_cursor_type\n");
+        return NO_CURSOR;
+      }
       if (glyph != NULL && glyph->type == IMAGE_GLYPH)
        {
          if (cursor_type == FILLED_BOX_CURSOR)
index f8ac7c3f760247c718c11677fb3aee0490355729..7b80a071b9513bf33056333077b54194668abf27 100644 (file)
@@ -2954,7 +2954,7 @@ unwind_create_frame (Lisp_Object frame)
 #if GLYPH_DEBUG
       /* Check that reference counts are indeed correct.  */
       xassert (dpyinfo->reference_count == dpyinfo_refcount);
-      xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
+      //xassert (dpyinfo->image_cache->refcount == image_cache_refcount); //FIXME doesnt compilex
 #endif
       return Qt;
     }
@@ -3176,8 +3176,9 @@ This function is an internal primitive--use `make-frame' instead.  */)
   /* With FRAME_X_DISPLAY_INFO set up, this unwind-protect is safe.  */
   record_unwind_protect (unwind_create_frame, frame);
 #if GLYPH_DEBUG
-  image_cache_refcount = FRAME_IMAGE_CACHE (f)->refcount;
-  dpyinfo_refcount = dpyinfo->reference_count;
+  //JAVE TODO crashes 
+  //image_cache_refcount = FRAME_IMAGE_CACHE (f)->refcount;
+  //dpyinfo_refcount = dpyinfo->reference_count;
 #endif /* GLYPH_DEBUG */
 
   /* These colors will be set anyway later, but it's important
index 9261250790342afe18a33874bd971849ce5a2df9..b0cf6a6517134a17dadf139b465e2ac5d255bb19 100644 (file)
@@ -62,6 +62,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "coding.h"
 #include "frame.h"
 #include "dispextern.h"
+#include "xwidget.h"
 #include "fontset.h"
 #include "termhooks.h"
 #include "termopts.h"
@@ -2651,6 +2652,7 @@ x_draw_glyph_string (struct glyph_string *s)
 {
   int relief_drawn_p = 0;
 
+  //printf("x_draw_glyph_string: %d\n",s->first_glyph->type);
   /* If S draws into the background of its successors, draw the
      background of the successors first so that S can draw into it.
      This makes S->next use XDrawString instead of XDrawImageString.  */
@@ -2708,6 +2710,13 @@ x_draw_glyph_string (struct glyph_string *s)
       x_draw_image_glyph_string (s);
       break;
 
+    case XWIDGET_GLYPH:
+      //erase xwidget background
+      x_draw_glyph_string_background (s, 0);
+      //x_draw_xwidget_glyph_string draws phantom xwidgets only, live xwidgets are drawn in an expose handler
+      x_draw_xwidget_glyph_string (s);
+      break;
+
     case STRETCH_GLYPH:
       x_draw_stretch_glyph_string (s);
       break;
@@ -5796,6 +5805,21 @@ handle_one_xevent (struct x_display_info *dpyinfo, XEvent *eventp, int *finish,
   inev.ie.kind = NO_EVENT;
   inev.ie.arg = Qnil;
 
+          /*try to let events escape to xwidgets  if xwidget_owns_kbd. not as easy as it sounds...  */
+          if(xwidget_owns_kbd){
+            printf("xwidgets own events now!\n");
+            //according to xembed spec it seems like the toolkit is responsible for forwarding of events, so
+            //try to let gtk have the event now
+            *finish = 0;
+            
+            /*FINISH is X_EVENT_GOTO_OUT if caller should stop reading events.
+             *FINISH is zero if caller should continue reading events.
+             *FINISH is X_EVENT_DROP if event should not be passed to the toolkit.*/
+            goto OTHER;
+          }
+
+  
+  
   if (pending_event_wait.eventtype == event.type)
     pending_event_wait.eventtype = 0; /* Indicates we got it.  */
 
@@ -6283,11 +6307,15 @@ handle_one_xevent (struct x_display_info *dpyinfo, XEvent *eventp, int *finish,
          Lisp_Object c;
 
 #ifdef USE_GTK
+
           /* Don't pass keys to GTK.  A Tab will shift focus to the
              tool bar in GTK 2.4.  Keys will still go to menus and
              dialogs because in that case popup_activated is TRUE
-             (see above).  */
+             (see above).
+          */
           *finish = X_EVENT_DROP;
+          
+
 #endif
 
           event.xkey.state
@@ -7180,7 +7208,7 @@ x_draw_hollow_cursor (struct window *w, struct glyph_row *row)
   cursor_glyph = get_phys_cursor_glyph (w);
   if (cursor_glyph == NULL)
     return;
-
+  
   /* Compute frame-relative coordinates for phys cursor.  */
   get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h);
   wd = w->phys_cursor_width;
@@ -7221,7 +7249,11 @@ x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text
   cursor_glyph = get_phys_cursor_glyph (w);
   if (cursor_glyph == NULL)
     return;
-
+  if (cursor_glyph->type == XWIDGET_GLYPH){
+    printf("tried avoiding xwidget cursor\n");
+    return; //experimental avoidance of cursor on xwidget
+  }
+  
   /* 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.  */
@@ -10470,7 +10502,7 @@ static struct redisplay_interface x_redisplay_interface =
     x_write_glyphs,
     x_insert_glyphs,
     x_clear_end_of_line,
-    x_scroll_run,
+    x_scroll_run, //maybe xwidgets dont work too well with scrolling by blitting
     x_after_update_window_line,
     x_update_window_begin,
     x_update_window_end,
diff --git a/src/xwidget.c b/src/xwidget.c
new file mode 100644 (file)
index 0000000..547c899
--- /dev/null
@@ -0,0 +1,1005 @@
+#include <config.h>
+
+#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
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+#include "xwidget.h"
+
+//just a fixed array of xwidgets for now
+#define MAX_XWIDGETS 100
+struct xwidget xwidgets[MAX_XWIDGETS];
+
+static int once = 0;
+
+
+Lisp_Object Qxwidget;
+Lisp_Object Qxwidget_id;
+Lisp_Object Qtitle;
+Lisp_Object Qxwidget_set_keyboard_grab;
+Lisp_Object Qxwidget_embed_steal_window;
+Lisp_Object Qxwidget_info;
+Lisp_Object Qxwidget_resize_internal;
+Lisp_Object Qxwidget_send_keyboard_event;
+
+extern Lisp_Object QCdata, QCtype;
+extern Lisp_Object QCwidth, QCheight;
+
+
+#define XG_XWIDGET "emacs_xwidget"
+
+int
+xwidget_hidden(struct xwidget *xw)
+{
+  return  xw->hidden;
+}
+
+
+static void
+buttonclick_handler (GtkWidget * widget, gpointer data)
+{
+  struct xwidget *xw = (struct xwidget *) data;
+  struct input_event event;
+  Lisp_Object frame;
+  FRAME_PTR f = (FRAME_PTR) g_object_get_data (G_OBJECT (xw->widget), XG_FRAME_DATA);
+  printf ("button clicked xw:%d id:%d\n", xw, xw->id);
+
+  EVENT_INIT (event);
+  event.kind = XWIDGET_EVENT;
+
+  XSETFRAME (frame, f);
+
+  event.frame_or_window = Qnil;        //frame; //how to get the frame here?
+
+
+  event.arg = Qnil;
+  event.arg = Fcons (make_number (xw->id), event.arg);
+  event.arg = Fcons (intern ("buttonclick"), event.arg);
+
+  kbd_buffer_store_event (&event);
+
+
+}
+
+
+static void
+send_xembed_ready_event (int xwid, int xembedid)
+{
+  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 (intern ("xembed-ready"), event.arg);
+  event.arg = Fcons (make_number (xwid), event.arg);
+
+
+  kbd_buffer_store_event (&event);
+
+}
+
+int xwidget_query_composition_called = 0;
+int hasNamePixmap = 0;
+
+
+int
+xwidget_has_composition(void){
+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){
+  //XCompositeUnredirectWindow(); stop redirecting, should be called when the socket is destroyed
+}
+
+void
+xwidget_show (struct xwidget *xw)
+{
+  //printf("xwidget %d shown\n",xw->id);
+  xw->hidden = 0;
+  gtk_widget_show(GTK_WIDGET(xw->widgetwindow));
+  gtk_fixed_move (GTK_FIXED (xw->emacswindow), GTK_WIDGET (xw->widgetwindow),  xw->x, xw->y);
+}
+
+
+
+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;
+}  
+*/
+
+
+void xwidget_plug_added(GtkSocket *socket,
+                        gpointer   user_data)
+{
+  //hmm this doesnt seem to get called for foreign windows
+  printf("xwidget_plug_added\n");
+}
+
+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;
+}
+
+void
+xwidget_init (struct xwidget *xw, struct glyph_string *s, int x, int y)
+{
+  xw->initialized = 1;
+  xw->id = s->xwidget_id;
+  xwidget_show(xw);
+
+  //widget creation
+  switch (xw->type) 
+    {
+    case 1:
+      xw->widget = gtk_button_new_with_label (xw->title);
+      g_signal_connect (G_OBJECT (xw->widget), "clicked",
+                        G_CALLBACK (buttonclick_handler), xw);
+      break;
+    case 2:
+      xw->widget = gtk_toggle_button_new_with_label (xw->title);
+      break;
+    case 3:
+      xw->widget = gtk_socket_new ();
+      //gtk_widget_set_app_paintable (xw->widget, TRUE); //workaround for composited sockets
+      GdkColor color;
+      gdk_color_parse("blue",&color); //the blue color never seems to show up. something else draws a grey bg
+      gtk_widget_modify_bg(xw->widget, GTK_STATE_NORMAL, &color);
+      g_signal_connect_after(xw->widget, "plug-added", G_CALLBACK(xwidget_plug_added), "plug added");        
+      break;
+    case 4:
+      xw->widget =
+        gtk_hscale_new (GTK_ADJUSTMENT
+                        (gtk_adjustment_new (0, 0, 100, 1, 1, 0)));
+      gtk_scale_set_draw_value (GTK_SCALE (xw->widget), FALSE);        //i think its emacs role to show text and stuff, so disable the widgets own text
+    }
+  //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
+  xw->emacswindow = GTK_CONTAINER (s->f->gwfixed);
+  //xw->widgetwindow = GTK_CONTAINER (gtk_layout_new (NULL, NULL));
+  xw->widgetwindow = GTK_CONTAINER (gtk_offscreen_window_new ());
+  //xw->widgetwindow = GTK_CONTAINER (gtk_fixed_new ());  
+  //xw->widgetwindow = GTK_CONTAINER (gtk_event_box_new ());
+  gtk_widget_set_size_request (GTK_WIDGET (xw->widget), xw->width, xw->height);  
+  //gtk_layout_set_size (GTK_LAYOUT (xw->widgetwindow), xw->width, xw->height);
+  gtk_container_add (xw->widgetwindow, xw->widget);
+  gtk_widget_set_size_request (GTK_WIDGET (xw->widget), xw->width, xw->height);
+  //gtk_fixed_put (GTK_FIXED (s->f->gwfixed), GTK_WIDGET (xw->widgetwindow), x, y);
+  gtk_widget_show_all (GTK_WIDGET (xw->widgetwindow));
+
+  //store some xwidget data in the gtk widgets
+  g_object_set_data (G_OBJECT (xw->widget), XG_FRAME_DATA, (gpointer) (s->f)); //the emacs frame
+  g_object_set_data (G_OBJECT (xw->widget), XG_XWIDGET, (gpointer) (xw)); //the xwidget
+  g_object_set_data (G_OBJECT (xw->widgetwindow), XG_XWIDGET, (gpointer) (xw)); //the xwidget  
+
+  //this seems to enable xcomposition. later we need to paint ourselves somehow,
+  //since the widget is no longer responsible for painting itself
+  //if(xw->type!=3)  //im having trouble with compositing and sockets. hmmm.
+      //gdk_window_set_composited (xw->widget->window, TRUE);
+  //gdk_window_set_composited (GTK_LAYOUT (xw->widgetwindow)->bin_window, TRUE);  
+  gtk_widget_set_double_buffered (xw->widget,FALSE);
+  gtk_widget_set_double_buffered (xw->widgetwindow,FALSE);  
+  //gdk_window_set_composited (xw->widgetwindow, TRUE);  
+  //g_signal_connect_after(xw->widget, "expose-event", G_CALLBACK(xwidget_composite_draw), "widget exposed");
+  g_signal_connect_after(xw->widgetwindow, "expose-event", G_CALLBACK(xwidget_composite_draw_widgetwindow), "widgetwindow exposed");  
+  //  g_signal_connect_after(xw->widget, "damage-event", G_CALLBACK(xwidget_composite_draw), "damaged");  
+  
+  //widgettype specific initialization only possible after realization
+  switch (xw->type)
+    {
+    case 3:
+      printf ("socket id:%x %d\n",
+              gtk_socket_get_id (GTK_SOCKET (xw->widget)),
+              gtk_socket_get_id (GTK_SOCKET (xw->widget)));
+      send_xembed_ready_event (xw->id,
+                               gtk_socket_get_id (GTK_SOCKET (xw->widget)));
+      //gtk_widget_realize(xw->widget);
+      break;
+    }
+}
+
+
+void
+x_draw_xwidget_glyph_string (struct glyph_string *s)
+{
+  /*
+    this method is called by the redisplay engine and is supposed to put the xwidget on screen.
+
+    must handle both live xwidgets, and phantom xwidgets.
+
+    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 mightbe 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.
+
+
+   */
+  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;
+
+  int drawing_in_selected_window = (XWINDOW (FRAME_SELECTED_WINDOW (s->f))) == (s->w);
+  //TODO drawing_in_selected_window can be true for several windows if we have several frames.
+  //we also need to check that the xwidget is to be drawn inside a window on a frame where it originaly lives.
+  //otherwise draw a phantom, or maybe reparent the xwidget.
+
+  struct xwidget *xw = &xwidgets[s->xwidget_id];
+  int clipx; int clipy;
+
+  /*printf("x_draw_xwidget_glyph_string: id:%d %d %d  (%d,%d,%d,%d) selected win:%d\n",
+     s->xwidget_id, box_line_hwidth, box_line_vwidth,
+         s->x, s->y, s->height, s->width,
+         drawing_in_selected_window);*/
+
+  int x = s->x;
+  int y = s->y + (s->height / 2) - (xw->height / 2);
+  int doingsocket = 0;
+  int moved=0;
+  if (!xw->initialized)
+      xwidget_init (xw, s, x, y);
+
+  //calculate clip widht and height, which is used both for the xwidget
+  //and its phantom counterpart
+  clipx = min (xw->width, WINDOW_RIGHT_EDGE_X (s->w) - x - WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH(s->w) - WINDOW_RIGHT_FRINGE_WIDTH(s->w));
+  clipy = min (xw->height,
+               WINDOW_BOTTOM_EDGE_Y (s->w) - WINDOW_MODE_LINE_HEIGHT (s->w) - y);
+
+  //TODO:
+  // 1) always draw live xwidget in slected 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.
+  if (drawing_in_selected_window)
+    {
+      moved = (xw->x != x) || (xw->y != y);
+      if(moved)
+        printf ("live xwidget moved: id:%d (%d,%d)->(%d,%d)\n", xw->id, xw->x, xw->y, x, y);
+      //xw refers to the *live* instance of the xwidget, so only
+      //update coords when drawing in the selected window
+      xw->x = x;
+      xw->y = y;
+      if (moved)       //has it moved?
+        {
+          if (!xwidget_hidden(xw))     //hidden equals not being seen in the live window
+            {
+              gtk_fixed_move (GTK_FIXED (s->f->gwfixed),
+                              GTK_WIDGET (xw->widgetwindow), x, y);
+            }
+        }
+      //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((xw->clipx != clipx) || (xw->clipy != clipy))
+        gtk_widget_set_size_request (GTK_WIDGET (xw->widgetwindow),
+                                     clipx, clipy);
+      xw->clipx = clipx; xw->clipy = clipy;
+      //a live xwidget paints itself. when using composition, that
+      //happens through the expose handler for the xwidget
+      //if emacs wants to repaint the area where the widget lives, queue a redraw
+      if (!xwidget_hidden(xw))
+        gtk_widget_queue_draw (xw->widget);
+    }
+  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);
+    }
+}
+
+
+
+
+DEFUN ("xwidget-embed-steal-window", Fxwidget_embed_steal_window, Sxwidget_embed_steal_window, 2, 2, 0,
+       doc:    /* Tell existing embed xwidget to steal other window id. This is based on a deprecated method in GTK and doesnt work too well.*/
+       )
+  (Lisp_Object xwidget_id, Lisp_Object window_id)
+{
+  struct xwidget *xw;
+  int xid, iwindow_id;
+
+  CHECK_NUMBER (xwidget_id);
+  CHECK_NUMBER (window_id);
+  xid = XFASTINT (xwidget_id);
+  iwindow_id = XFASTINT (window_id);
+  xw = &xwidgets[xid];
+  printf ("  gtk_socket_add_id: %d %d\n", xid, iwindow_id);
+  //  gtk_socket_steal(GTK_SOCKET(xw->widget),iwindow_id);
+  //try adding proper gtk plugs instead, i never once had "steal" work
+  gtk_socket_add_id (GTK_SOCKET (xw->widget), iwindow_id);
+  //add_id annoyingly odesnt work either. the only working option
+  //seems to be clients that plug into the sockets, and so far only emacs and mplayer
+  //oenvrml
+  return Qnil;
+}
+
+
+DEFUN ("xwidget-resize-internal", Fxwidget_resize_internal, Sxwidget_resize_internal, 3, 3, 0, doc:
+       )
+  (Lisp_Object xwidget_id, Lisp_Object new_width, Lisp_Object new_height)
+{
+  struct xwidget *xw;
+  int xid, w, h;
+
+  CHECK_NUMBER (xwidget_id);
+  CHECK_NUMBER (new_width);
+  CHECK_NUMBER (new_height);
+  xid = XFASTINT (xwidget_id);
+  w = XFASTINT (new_width);
+  h = XFASTINT (new_height);
+  xw = &xwidgets[xid];
+
+  printf("resize xwidget %d (%d,%d)->(%d,%d)",xid,xw->width,xw->height,w,h);
+  xw->width=w;
+  xw->height=h;
+  gtk_layout_set_size (GTK_LAYOUT (xw->widgetwindow), xw->width, xw->height);
+  gtk_widget_set_size_request (GTK_WIDGET (xw->widget), xw->width,
+                               xw->height);
+  return Qnil;
+}
+
+
+
+DEFUN("xwidget-info", Fxwidget_info , Sxwidget_info, 1,1,0, doc: /* get xwidget props */)
+     (Lisp_Object xwidget_id)
+{
+  struct xwidget *xw = &xwidgets[XFASTINT (xwidget_id)];
+  Lisp_Object info;
+
+  info = Fmake_vector (make_number (7), Qnil);
+  XVECTOR (info)->contents[0] = make_number(xw->id);
+  XVECTOR (info)->contents[1] = make_number(xw->type);
+  XVECTOR (info)->contents[2] = make_number(xw->x);
+  XVECTOR (info)->contents[3] = make_number(xw->y);
+  XVECTOR (info)->contents[4] = make_number(xw->width);
+  XVECTOR (info)->contents[5] = make_number(xw->height);
+  XVECTOR (info)->contents[6] = make_number(xw->hidden);
+
+  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. */
+       )
+  (Lisp_Object xwidget_id, Lisp_Object kbd_grab)
+{
+  struct xwidget *xw;
+  int xid, kbd_flag;
+
+  CHECK_NUMBER (xwidget_id);
+  CHECK_NUMBER (kbd_grab);
+  xid = XFASTINT (xwidget_id);
+  kbd_flag = XFASTINT (kbd_grab);
+  xw = &xwidgets[xid];
+
+  printf ("kbd grab: %d %d\n", xid, kbd_flag);
+  if (kbd_flag)
+    {
+      //int rv=gtk_widget_activate(xw->widget); //ok, but how deactivate?
+      //printf("activation:%d\n",rv);
+      //      gtk_window_present(GTK_WINDOW(xw->widget));
+      //gtk_widget_grab_focus(xw->widget);
+      //      gtk_socket_windowing_update_active (xw->widget,1);
+      //      GDK_WINDOW_XWINDOW (GTK_WIDGET (socket)->window)
+      //FRAME_X_OUTPUT (f)->widget
+      //      gdk_keyboard_grab(xw->widget,TRUE,GDK_CURRENT_TIME);
+
+      /* GtkWidget *parent = gtk_widget_get_parent (xw->widget); */
+      /* GtkWidget *lastparent; */
+      /* for (lastparent = parent; parent = gtk_widget_get_parent (parent); */
+      /*      parent == NULL); */
+
+      /* gtk_container_set_focus_child (GTK_CONTAINER (lastparent), xw->widget); */
+
+      gtk_container_set_focus_child (GTK_CONTAINER (xw->widgetwindow), xw->widget);
+
+      xwidget_owns_kbd = TRUE;
+    }
+  else
+    {
+      xwidget_owns_kbd = FALSE;
+    }
+  /*
+    gdk_keyboard_grab(xw->widget,TRUE,GDK_CURRENT_TIME);
+    else
+    gdk_keyboard_ungrab(GDK_CURRENT_TIME);
+  */
+  return Qnil;
+}
+
+
+//lowlevel fn mostly cloned from xembed_send_message()
+void
+xwidget_key_send_message (struct frame *f,
+                          Window destination_window,
+                          int keycode, int keypress, int modifiers)
+{
+
+  XKeyEvent event;
+  //segfaults:
+  /* xwidget_key_send_message (f=0x0, destination_window=0, keycode=65, keypress=1,  */
+  /*     modifiers=0) at xwidget.c:332 */
+  /* 332          event.display = FRAME_X_DISPLAY (f); */
+
+  event.display = FRAME_X_DISPLAY (f);
+  event.window = destination_window;
+  event.root = FRAME_X_WINDOW (f);
+  event.subwindow = None;
+  event.time = CurrentTime;
+  event.x = 1;
+  event.y = 1;
+  event.x_root = 1;
+  event.y_root = 1;
+  event.same_screen = TRUE;
+
+  event.type = keypress ? KeyPress : KeyRelease;
+  event.keycode = keycode;
+  event.state = modifiers;
+
+  XSendEvent (event.display, event.window, TRUE, KeyPressMask,
+              (XEvent *) & event);
+}
+
+//using "accessible" interfaces seems expensive
+//pkg-config --cflags cspi-1.0
+//#include <at-spi-1.0/cspi/spi.h>
+
+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_id, Lisp_Object keydescriptor)
+{
+  int keyval;
+  char *keystring = "";
+  FRAME_PTR f;
+  struct xwidget *xw;
+  GdkWindow *window;
+  int xwid;
+  XID xid;
+
+  CHECK_NUMBER (xwidget_id);
+  xwid = XFASTINT (xwidget_id);
+  xw = &xwidgets[xwid];
+
+  f = (FRAME_PTR) g_object_get_data (G_OBJECT (xw->widget), XG_FRAME_DATA);
+
+  //GdkWindow* window=gtk_widget_get_window(xw->widget); //event winds up in emacs
+
+  //TODO assert xw is a gtk_socket or THIS WILL FAIL GLORIOUSLY
+  window = gtk_socket_get_plug_window (GTK_SOCKET (xw->widget));
+  //the event gets eaten somewhere.
+  //i suspect you just cant send an event to a child window and not have emacs eat it.
+  //but if this were true the event should pop to emacs right?
+
+
+  xid = gdk_x11_drawable_get_xid (window);
+
+  printf ("xwidget-send-keyboard-event %d %d\n", window, xid);
+
+  xwidget_key_send_message (f, xid, 38, 1, 0); //38 is 'a' HACK for now
+  xwidget_key_send_message (f, xid, 38, 0, 0);
+
+  return Qnil;
+}
+
+void
+syms_of_xwidget (void)
+{
+  int i;
+
+  Qxwidget_set_keyboard_grab = intern ("xwidget-set-keyboard-grab");
+  staticpro (&Qxwidget_set_keyboard_grab);
+  defsubr (&Sxwidget_set_keyboard_grab);
+
+  Qxwidget_send_keyboard_event = intern ("xwidget-send-keyboard-event");
+  staticpro (&Qxwidget_send_keyboard_event);
+  defsubr (&Sxwidget_send_keyboard_event);
+
+  Qxwidget_embed_steal_window = intern ("xwidget-embed-steal-window");
+  staticpro (&Qxwidget_embed_steal_window);
+  defsubr (&Sxwidget_embed_steal_window);
+
+  Qxwidget_info = intern ("xwidget-info");
+  staticpro (&Qxwidget_info);
+  defsubr (&Sxwidget_info);
+
+  Qxwidget_resize_internal = intern ("xwidget-resize-internal");
+  staticpro (&Qxwidget_resize_internal);
+  defsubr (&Sxwidget_resize_internal);
+
+
+  Qxwidget_embed_steal_window = intern ("xwidget-embed-steal-window");
+  staticpro (&Qxwidget_embed_steal_window);
+  defsubr (&Sxwidget_embed_steal_window);
+
+
+  Qxwidget = intern ("xwidget");
+  staticpro (&Qxwidget);
+
+  Qxwidget_id = intern (":xwidget-id");
+  staticpro (&Qxwidget_id);
+
+  Qtitle = intern (":title");
+  staticpro (&Qtitle);
+
+  Fprovide (intern ("xwidget-internal"), Qnil);
+
+  for (i = 0; i < MAX_XWIDGETS; i++)
+    xwidgets[i].initialized = 0;
+}
+
+
+/* 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_p (Lisp_Object object)
+{
+  int valid_p = 0;
+
+  if (XWIDGETP (object))
+    {
+      /* 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;
+}
+
+//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; */
+/* } */
+
+
+/* hidden means not being seen in the "live" window.
+   a phantom might be seen somewhere though */
+void
+xwidget_hide (struct xwidget *xw)
+{
+  //printf("xwidget %d hidden\n",xw->id);
+  xw->hidden = 1;
+  //gtk_widget_hide(GTK_WIDGET(xw->widgetwindow));
+  gtk_fixed_move (GTK_FIXED (xw->emacswindow), GTK_WIDGET (xw->widgetwindow),
+                  10000, 10000);
+}
+
+
+
+
+Lisp_Object
+xwidget_spec_value (
+                    Lisp_Object spec, Lisp_Object  key,
+                    int *found)
+{
+  Lisp_Object tail;
+
+  xassert (valid_xwidget_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
+assert_valid_xwidget_id (int id, char *str)
+{
+  if (id < 0 || id > MAX_XWIDGETS)
+    {
+      printf ("broken xwidgetid:%d %s\n", id, str);
+      abort ();
+    }
+}
+
+struct xwidget *
+xwidget_from_id (int id)
+{
+  assert_valid_xwidget_id (id, "xwidget_from_id");
+  return &xwidgets[id];
+}
+
+int
+lookup_xwidget (Lisp_Object  spec)
+{
+
+  int found = 0, found1 = 0, found2 = 0;
+  Lisp_Object value;
+  int id;
+  struct xwidget *xw;
+
+  value = xwidget_spec_value (spec, Qxwidget_id, &found1);
+  id = INTEGERP (value) ? XFASTINT (value) : 0;        //id 0 by default, but id must be unique so this is dumb
+
+  xw = &xwidgets[id];
+  value = xwidget_spec_value (spec, QCtype, &found);
+  xw->type = INTEGERP (value) ? XFASTINT (value) : 1;  //default to button
+  value = xwidget_spec_value (spec, Qtitle, &found2);
+  xw->title = STRINGP (value) ? (char *) SDATA (value) : "?";  //funky cast FIXME
+
+  value = xwidget_spec_value (spec, QCheight, NULL);
+  xw->height = INTEGERP (value) ? XFASTINT (value) : 50;       //ok
+  value = xwidget_spec_value (spec, QCwidth, NULL);
+  xw->width = INTEGERP (value) ? XFASTINT (value) : 50;        //ok
+
+
+  printf ("xwidget_id:%d type:%d found:%d %d %d title:%s (%d,%d)\n", id,
+          xw->type, found, found1, found2, xw->title, xw->height, xw->width);
+
+
+  assert_valid_xwidget_id (id, "lookup_xwidget");
+
+  return id;
+}
+
+//////////////////////////////////
+int region_modified = 0;
+
+/*set up detection of touched xwidget*/
+void
+xwidget_start_redisplay (void)
+{
+  int i;
+  for (i = 0; i < MAX_XWIDGETS; i++)
+    xwidgets[i].redisplayed = 0;
+
+}
+
+/* the xwidget was touched during redisplay, so it isnt a candidate for hiding*/
+void
+xwidget_touch (struct xwidget *xw)
+{
+  //printf("touch xwidget %d\n", xw->id);
+  xw->redisplayed = 1;
+}
+
+int
+xwidget_touched (struct xwidget *xw)
+{
+  return  xw->redisplayed;
+}
+
+/* redisplay has ended, now we should hide untouched xwidgets
+
+   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.
+
+*/
+void
+xwidget_end_redisplay (struct glyph_matrix *matrix)
+{
+  int i;
+  struct xwidget *xw;
+  int area;
+
+  //dont change anything if minibuffer is selected this redisplay
+  //this is mostly a workaround to reduce the phantoming of xwidgets
+  // this is special case handling and it doesnt work too well.
+  /* if( (XWINDOW (FRAME_MINIBUF_WINDOW (SELECTED_FRAME()))) == */
+  /*     (XWINDOW (FRAME_SELECTED_WINDOW (SELECTED_FRAME())))) */
+  /*   return;  */
+
+  region_modified = 0;
+  xwidget_start_redisplay ();
+  //iterate desired glyph matrix of "live" window here, hide gtk widgets
+  //not in the desired matrix.
+
+  //the current scheme will fail on the case of several buffers showing xwidgets
+
+  //  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)
+                    {
+                      //printf("(%d)",glyph->u.xwidget_id);
+                      //here the id sometimes sucks, so maybe the desired glyph matrix isnt ready here?
+                      //also, it appears the desired matrix is not the entire window, but only the changed part. wtf?
+                      int id = glyph->u.xwidget_id;
+                      if (id < 0 || id > MAX_XWIDGETS)
+                        {
+                          printf
+                            ("glyph matrix contains crap, abort xwidget handling and wait for better times\n ");
+                          //dump_glyph_matrix(matrix, 2);
+                          return;
+                        }
+                      else
+                        {
+                          // printf("row %d not enabled\n", i);
+                        }
+                      xwidget_touch (&xwidgets[glyph->u.xwidget_id]);
+                    }
+                }
+            }
+        }
+    }
+
+  for (i = 0; i < MAX_XWIDGETS; i++)
+    {
+      xw = &xwidgets[i];
+      if (xw->initialized)
+        {
+          if (xwidget_touched(xw))
+            xwidget_show (xw);
+          else
+            xwidget_hide (xw);
+        }
+    }
+}
+
+/* some type of modification was made to the buffers*/
+void
+xwidget_modify_region (void)
+{
+  region_modified = 1;
+}
+
+////////////////////////////////////////////////////////////////
+
+/* delete the xwidget and its native widget peer */
+void
+xwidget_delete (struct xwidget *xw)
+{
+  printf ("xwidget %d deleted\n", xw->id);
+  xw->initialized = 0;
+  gtk_widget_destroy (xw->widget);
+
+}
+
+
+
+
+/* redraw all xwidgets */
+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");
+}
diff --git a/src/xwidget.h b/src/xwidget.h
new file mode 100644 (file)
index 0000000..3852103
--- /dev/null
@@ -0,0 +1,62 @@
+void x_draw_xwidget_glyph_string (struct glyph_string *s);
+void syms_of_xwidget ();
+
+extern Lisp_Object Qxwidget;
+/* Test for xwidget (xwidget . spec)  (car must be the symbol xwidget)*/
+#define XWIDGETP(x) (CONSP (x) && EQ (XCAR (x), Qxwidget))
+
+int valid_xwidget_p (Lisp_Object object) ;
+
+#include <gtk/gtk.h>
+
+/*
+each xwidget instance is described by this struct.
+ */
+struct xwidget{
+  int id;
+  int type;
+  int hidden;
+  GtkWidget* widget;
+  GtkContainer* widgetwindow;
+
+  char* title;
+  int initialized;
+  int height;
+  int width;
+  int x; int y;
+  Lisp_Object message_hook;
+  int redisplayed;
+  GtkContainer* emacswindow;
+  int clipx; int clipy;
+};
+
+
+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 INLINE 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 glyph_matrix* matrix);
+void xwidget_modify_region();
+
+void xwidget_touch(struct xwidget* xw);
+void xwidget_delete(struct xwidget* xw);
+void assert_valid_xwidget_id(int id,char *str);