--- /dev/null
+* 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.
+
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
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)
--- /dev/null
+;;test like:
+;; cd /path/to/xwidgets-emacs-dir
+;; make all&& src/emacs -q --eval "(progn (load \"`pwd`/lisp/xwidget-test.el\") (xwidget-demo-basic))"
+
+
+;; you should see:
+;; - a gtk button
+;; - a gtk toggle button
+;; - a gtk slider button
+;; - an xembed window(using gtk_socket) showing another emacs instance
+;; - an xembed window(using gtk_socket) showing an uzbl web browser if its installed
+
+;;the widgets will move when you type in the buffer. good!
+
+;;there will be redrawing issues when widgets change rows, etc. bad!
+
+;;its currently difficult to give kbd focus to the xembedded emacs,
+;;but try evaling the following:
+
+;; (xwidget-set-keyboard-grab 3 1)
+
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; demo 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)
--- /dev/null
+;; 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)
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 \
#define DISPEXTERN_H_INCLUDED
#ifdef HAVE_X_WINDOWS
-
#include <X11/Xlib.h>
#ifdef USE_X_TOOLKIT
#include <X11/Intrinsic.h>
/* 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
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
};
/* Image ID for image glyphs (type == IMAGE_GLYPH). */
unsigned img_id;
+ unsigned xwidget_id;
+
/* Sub-structure for type == STRETCH_GLYPH. */
struct
{
/* Image, if any. */
struct image *img;
+ int xwidget_id;
+
/* Slice */
struct glyph_slice slice;
IT_TRUNCATION,
/* Continuation glyphs. See the comment for IT_TRUNCATION. */
- IT_CONTINUATION
+ IT_CONTINUATION,
+
+ IT_XWIDGET
};
GET_FROM_C_STRING,
GET_FROM_IMAGE,
GET_FROM_STRETCH,
+ GET_FROM_XWIDGET,
NUM_IT_METHODS
};
struct {
Lisp_Object object;
} stretch;
+ /* method == GET_FROM_XWIDGET */
+ struct {
+ Lisp_Object object;
+ int xwidget_id;
+ } xwidget;
+
} u;
/* current text and display positions. */
/* 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;
{
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. */
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;
#include "buffer.h"
#include "window.h"
+#include "xwidget.h"
+
#include "systty.h"
#include "blockinput.h"
#include "syssignal.h"
syms_of_xfns ();
syms_of_xmenu ();
syms_of_fontset ();
+ syms_of_xwidget();
syms_of_xsettings ();
#ifdef HAVE_X_SM
syms_of_xsmfns ();
/* 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)
/* 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)
{
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)
{
#include "window.h"
#include "blockinput.h"
#include "region-cache.h"
+#include "xwidget.h"
#ifndef NULL
#define NULL 0
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)
#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 */
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;
return apply_modifiers (event->modifiers, event->arg);
return event->arg;
+
+
case USER_SIGNAL_EVENT:
/* A user signal. */
{
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,
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);
/* Non-key system events (e.g. application menu events) */
, NS_NONKEY_EVENT
#endif
+ /* events generated by xwidgets*/
+ , XWIDGET_EVENT
};
#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;
SET_PT (new_point);
}
+ xwidget_invalidate();
windows_or_buffers_changed++;
return window;
}
#include "font.h"
+#include "xwidget.h"
+
#ifndef FRAME_X_OUTPUT
#define FRAME_X_OUTPUT(f) ((f)->output_data.x)
#endif
static int next_element_from_buffer (struct it *);
static int next_element_from_composition (struct it *);
static int next_element_from_image (struct it *);
+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 *,
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)
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. */
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)
{
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);
return (CONSP (prop)
&& (EQ (XCAR (prop), Qimage)
- || EQ (XCAR (prop), Qspace)));
+ || EQ (XCAR (prop), Qspace)
+ || XWIDGETP(prop)));
}
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;
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;
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)
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. */
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
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
end_of_redisplay:
unbind_to (count, Qnil);
RESUME_POLLING;
+ //xwidget_end_redisplay();
+
+ printf("<<<<redisplay\n");
}
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;
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");
+ }
}
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))
{
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.
} \
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
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, \
}
}
+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
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
/* 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)
#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;
}
/* 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
#include "coding.h"
#include "frame.h"
#include "dispextern.h"
+#include "xwidget.h"
#include "fontset.h"
#include "termhooks.h"
#include "termopts.h"
{
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. */
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;
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. */
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
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;
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. */
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,
--- /dev/null
+#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");
+}
--- /dev/null
+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);