From ea113b66ba333a891d6653f1ab34c95b8a52b536 Mon Sep 17 00:00:00 2001 From: Joakim Verona Date: Fri, 18 Jun 2010 15:32:32 +0200 Subject: [PATCH] initial move from git to bzr --- lisp/xwidget-test.el | 108 +++++++ lisp/xwidget.el | 45 +++ src/Makefile.in | 2 + src/dispextern.h | 30 +- src/dispnew.c | 5 + src/emacs.c | 3 + src/frame.h | 4 + src/gtkutil.c | 6 +- src/insdel.c | 3 + src/keyboard.c | 15 +- src/termhooks.h | 2 + src/window.c | 2 + src/xdisp.c | 236 ++++++++++++++- src/xfns.c | 7 +- src/xterm.c | 30 +- src/xwidget.c | 808 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/xwidget.h | 61 ++++ 17 files changed, 1350 insertions(+), 17 deletions(-) create mode 100644 lisp/xwidget-test.el create mode 100644 lisp/xwidget.el create mode 100644 src/xwidget.c create mode 100644 src/xwidget.h diff --git a/lisp/xwidget-test.el b/lisp/xwidget-test.el new file mode 100644 index 00000000000..29c98684df1 --- /dev/null +++ b/lisp/xwidget-test.el @@ -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" 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 ) +(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" "-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) \ No newline at end of file diff --git a/lisp/xwidget.el b/lisp/xwidget.el new file mode 100644 index 00000000000..ef200048f59 --- /dev/null +++ b/lisp/xwidget.el @@ -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) diff --git a/src/Makefile.in b/src/Makefile.in index b2fec7eb085..578173747c9 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -337,8 +337,10 @@ obj= dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \ process.o callproc.o \ region-cache.o sound.o atimer.o \ doprnt.o strftime.o intervals.o textprop.o composite.o md5.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 \ diff --git a/src/dispextern.h b/src/dispextern.h index f0d14c0e487..d1724adca01 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -24,7 +24,6 @@ along with GNU Emacs. If not, see . */ #define DISPEXTERN_H_INCLUDED #ifdef HAVE_X_WINDOWS - #include #ifdef USE_X_TOOLKIT #include @@ -113,7 +112,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 @@ -281,7 +280,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 }; @@ -331,7 +333,7 @@ struct glyph /* Which kind of glyph this is---character, image etc. Value should be an enumerator of type enum glyph_type. */ - unsigned type : 2; + unsigned type : 3; /* 1 means this glyph was produced from multibyte text. Zero means it was produced from unibyte text, i.e. charsets aren't @@ -415,6 +417,8 @@ struct glyph /* Image ID for image glyphs (type == IMAGE_GLYPH). */ unsigned img_id; + unsigned xwidget_id; + /* Sub-structure for type == STRETCH_GLYPH. */ struct { @@ -1262,6 +1266,8 @@ struct glyph_string /* Image, if any. */ struct image *img; + int xwidget_id; + /* Slice */ struct glyph_slice slice; @@ -1912,7 +1918,9 @@ enum display_element_type IT_TRUNCATION, /* Continuation glyphs. See the comment for IT_TRUNCATION. */ - IT_CONTINUATION + IT_CONTINUATION, + + IT_XWIDGET }; @@ -1961,6 +1969,7 @@ enum it_method { GET_FROM_C_STRING, GET_FROM_IMAGE, GET_FROM_STRETCH, + GET_FROM_XWIDGET, NUM_IT_METHODS }; @@ -2162,6 +2171,12 @@ struct it struct { Lisp_Object object; } stretch; + /* method == GET_FROM_XWIDGET */ + struct { + Lisp_Object object; + int xwidget_lalala; + } xwidget; + } u; /* current text and display positions. */ @@ -2275,6 +2290,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; @@ -3334,3 +3353,4 @@ extern Lisp_Object x_default_parameter P_ ((struct frame *, Lisp_Object, /* arch-tag: c65c475f-1c1e-4534-8795-990b8509fd65 (do not change this comment) */ + diff --git a/src/dispnew.c b/src/dispnew.c index a8ba1995435..e1c537e877c 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -3638,6 +3638,7 @@ update_single_window (w, 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. */ @@ -4000,6 +4001,10 @@ update_window (w, 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; diff --git a/src/emacs.c b/src/emacs.c index 7e778e2e5fd..33e982ef066 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -54,6 +54,8 @@ along with GNU Emacs. If not, see . */ #include "buffer.h" #include "window.h" +#include "xwidget.h" + #include "systty.h" #include "blockinput.h" #include "syssignal.h" @@ -1642,6 +1644,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 (); diff --git a/src/frame.h b/src/frame.h index 887d47eff21..b0d338be5a6 100644 --- a/src/frame.h +++ b/src/frame.h @@ -500,6 +500,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) diff --git a/src/gtkutil.c b/src/gtkutil.c index c8800817b68..f77669c419d 100644 --- a/src/gtkutil.c +++ b/src/gtkutil.c @@ -754,6 +754,10 @@ xg_pix_to_gcolor (w, pixel, c) /* Create and set up the GTK widgets for frame F. Return 0 if creation failed, non-zero otherwise. */ + + + + int xg_create_frame_widgets (f) FRAME_PTR f; @@ -775,7 +779,7 @@ xg_create_frame_widgets (f) xg_set_screen (wtop, f); wvbox = gtk_vbox_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 || ! wfixed) { diff --git a/src/insdel.c b/src/insdel.c index 2b00de88711..a4363e8b1fe 100644 --- a/src/insdel.c +++ b/src/insdel.c @@ -28,6 +28,7 @@ along with GNU Emacs. If not, see . */ #include "window.h" #include "blockinput.h" #include "region-cache.h" +#include "xwidget.h" #ifndef NULL #define NULL 0 @@ -2001,6 +2002,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) diff --git a/src/keyboard.c b/src/keyboard.c index 63372d600e3..ddb81ff0237 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -485,6 +485,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 */ @@ -4161,7 +4162,7 @@ kbd_buffer_get_event (kbp, used_mouse_menu, end_time) 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; @@ -6060,6 +6061,8 @@ make_lispy_event (event) return apply_modifiers (event->modifiers, event->arg); return event->arg; + + case USER_SIGNAL_EVENT: /* A user signal. */ { @@ -6078,6 +6081,11 @@ make_lispy_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, @@ -11729,6 +11737,11 @@ syms_of_keyboard () 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); diff --git a/src/termhooks.h b/src/termhooks.h index 2b4011627c8..311917df4d0 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -208,6 +208,8 @@ enum event_kind /* Non-key system events (e.g. application menu events) */ , NS_NONKEY_EVENT #endif + /* events generated by xwidgets*/ + , XWIDGET_EVENT }; diff --git a/src/window.c b/src/window.c index c105e37c462..193f7eecd0e 100644 --- a/src/window.c +++ b/src/window.c @@ -51,6 +51,7 @@ along with GNU Emacs. If not, see . */ #include "nsterm.h" #endif +#include "xwidget.h" Lisp_Object Qwindowp, Qwindow_live_p, Qwindow_configuration_p; Lisp_Object Qdisplay_buffer; @@ -3666,6 +3667,7 @@ selected window before each command. */) SET_PT (new_point); } + xwidget_invalidate(); windows_or_buffers_changed++; return window; } diff --git a/src/xdisp.c b/src/xdisp.c index c8043308ec8..7e1869bc963 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -247,6 +247,7 @@ along with GNU Emacs. If not, see . */ #include "fontset.h" #include "blockinput.h" + #ifdef HAVE_X_WINDOWS #include "xterm.h" #endif @@ -262,6 +263,8 @@ along with GNU Emacs. If not, see . */ #include "font.h" +#include "xwidget.h" + #ifndef FRAME_X_OUTPUT #define FRAME_X_OUTPUT(f) ((f)->output_data.x) #endif @@ -1045,6 +1048,7 @@ static int next_element_from_c_string P_ ((struct it *)); static int next_element_from_buffer P_ ((struct it *)); static int next_element_from_composition P_ ((struct it *)); static int next_element_from_image P_ ((struct it *)); +static int next_element_from_xwidget P_ ((struct it *)); static int next_element_from_stretch P_ ((struct it *)); static void load_overlay_strings P_ ((struct it *, int)); static int init_from_display_pos P_ ((struct it *, struct window *, @@ -4075,6 +4079,7 @@ handle_display_prop (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) @@ -4180,6 +4185,7 @@ handle_single_display_spec (it, spec, object, overlay, position, 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. */ @@ -4464,11 +4470,22 @@ handle_single_display_spec (it, spec, object, overlay, position, 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) { @@ -4509,8 +4526,20 @@ handle_single_display_spec (it, spec, object, overlay, position, 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); @@ -4574,7 +4603,8 @@ single_display_spec_intangible_p (prop) return (CONSP (prop) && (EQ (XCAR (prop), Qimage) - || EQ (XCAR (prop), Qspace))); + || EQ (XCAR (prop), Qspace) + || XWIDGETP(prop))); } @@ -5246,6 +5276,10 @@ push_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; @@ -5325,6 +5359,9 @@ pop_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; @@ -5846,7 +5883,8 @@ static int (* get_next_element[NUM_IT_METHODS]) P_ ((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) @@ -6504,6 +6542,7 @@ set_iterator_to_next (it, 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. */ @@ -6766,6 +6805,19 @@ next_element_from_image (it) return 1; } +/* im not sure about this FIXME JAVE*/ +static int +next_element_from_xwidget (it) + 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 @@ -11793,6 +11845,7 @@ static void redisplay_internal (preserve_echo_area) int preserve_echo_area; { + struct window *w = XWINDOW (selected_window); struct frame *f; int pause; @@ -11808,6 +11861,9 @@ redisplay_internal (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 @@ -12509,6 +12565,9 @@ redisplay_internal (preserve_echo_area) end_of_redisplay: unbind_to (count, Qnil); RESUME_POLLING; + //xwidget_end_redisplay(); + + printf("<<<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"); + } } @@ -20614,6 +20694,13 @@ calc_pixel_width_or_height (res, it, prop, font, width_p, align_to) 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)) { @@ -21070,6 +21157,20 @@ fill_image_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. @@ -21423,6 +21524,20 @@ compute_overhangs_and_x (s, x, 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 @@ -21551,11 +21666,14 @@ compute_overhangs_and_x (s, x, backward_p) BUILD_STRETCH_GLYPH_STRING (START, END, HEAD, TAIL, \ HL, X, LAST_X); \ break; \ - \ case IMAGE_GLYPH: \ 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; \ \ default: \ abort (); \ @@ -22170,6 +22288,112 @@ produce_image_glyph (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 @@ -23237,6 +23461,8 @@ x_produce_glyphs (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); /* Accumulate dimensions. Note: can't assume that it->descent > 0 because this isn't true for images with `:ascent 100'. */ diff --git a/src/xfns.c b/src/xfns.c index d19914e8dec..9072dabf355 100644 --- a/src/xfns.c +++ b/src/xfns.c @@ -3047,7 +3047,7 @@ unwind_create_frame (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; } @@ -3285,8 +3285,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 diff --git a/src/xterm.c b/src/xterm.c index f195c4fbbd5..519ece2a2d3 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -69,6 +69,7 @@ along with GNU Emacs. If not, see . */ #include "coding.h" #include "frame.h" #include "dispextern.h" +#include "xwidget.h" #include "fontset.h" #include "termhooks.h" #include "termopts.h" @@ -2419,7 +2420,7 @@ x_draw_image_foreground_1 (s, pixmap) /* Draw part of the background of glyph string S. X, Y, W, and H give the rectangle to draw. */ -static void + void x_draw_glyph_string_bg_rect (s, x, y, w, h) struct glyph_string *s; int x, y, w, h; @@ -2645,6 +2646,7 @@ x_draw_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. */ @@ -2702,6 +2704,11 @@ x_draw_glyph_string (s) x_draw_image_glyph_string (s); break; + case XWIDGET_GLYPH: + x_draw_glyph_string_background (s, 0); + x_draw_xwidget_glyph_string (s); + break; + case STRETCH_GLYPH: x_draw_stretch_glyph_string (s); break; @@ -5889,6 +5896,21 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) EVENT_INIT (inev.ie); 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. */ @@ -6377,11 +6399,15 @@ handle_one_xevent (dpyinfo, eventp, finish, hold_quit) 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 diff --git a/src/xwidget.c b/src/xwidget.c new file mode 100644 index 00000000000..6e6ae466b4d --- /dev/null +++ b/src/xwidget.c @@ -0,0 +1,808 @@ +#include + +#include + +#include + +#ifdef HAVE_X_WINDOWS + +#include "lisp.h" +#include "blockinput.h" +#include "syssignal.h" + +#include "xterm.h" +#include + +#ifndef makedev +#include +#endif /* makedev */ + +#ifdef BSD_SYSTEM +#include +#endif /* ! defined (BSD_SYSTEM) */ + +#include "systime.h" + +#ifndef INCLUDED_FCNTL +#include +#endif +#include +#include +#include +#include + +#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 +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "gtkutil.h" +#include "font.h" +#endif + +#include +#include + +#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_resize_internal; +Lisp_Object Qxwidget_send_keyboard_event; + +extern Lisp_Object QCdata, QCtype; +extern Lisp_Object QCwidth, QCheight; + + + + + + +static void +buttonclick_handler (GtkWidget * widget, gpointer data) +{ + struct xwidget *xw = (struct xwidget *) data; + Lisp_Object frame; + printf ("button clicked xw:%d id:%d\n", xw, xw->id); + + struct input_event event; + EVENT_INIT (event); + event.kind = XWIDGET_EVENT; + + FRAME_PTR f = + (FRAME_PTR) g_object_get_data (G_OBJECT (xw->widget), XG_FRAME_DATA); + 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); + +} + + +void +xwidget_init (struct xwidget *xw, struct glyph_string *s, int x, int y) +{ + xw->initialized = 1; + xw->id = s->xwidget_id; + xw->hidden = 0; + + //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 (); + 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 + // mk container widget 1st, and put the widget inside + //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)); + 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)); + + //a bit inconsistent, but the rest of emacs stores stuff in the widgets, + //like frame data. in my case it might as well reside in the xwidget struct i think + g_object_set_data (G_OBJECT (xw->widget), XG_FRAME_DATA, (gpointer) (s->f)); + + //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))); + break; + } +} + +void +xwidget_draw_phantom (struct xwidget *xw, int x, int y, int clipx, int clipy, + struct glyph_string *s) +{ + //we cant always get real widgets, so here we try to fetch a snapshot of + //the real xwidget and paint that as a phantom image. if that fails, we + //get an even simpler phantom(grey rectangle currently) + + //this annoyingly doesnt work for gtk_sockets(but gtk_plug then? TODO research (probably doesnt work)) + //another way is composition: http://ktown.kde.org/~fredrik/composite_howto.html + //but XCopyArea() might be sufficient for our needs here + + + GdkPixmap *xw_snapshot = gtk_widget_get_snapshot (xw->widget, NULL); + GdkGC *gdkgc = gdk_gc_new (xw_snapshot); + + //currently a phanotm gets a line drawn across it to denote phantomness + //dimming or such would be more elegant + gdk_draw_line (xw_snapshot, gdkgc, 0, 0, xw->width, xw->height); + gdk_draw_drawable (gtk_widget_get_window (s->f->gwfixed), //convert to GdkWindow from gtkWindow + gdkgc, xw_snapshot, 0, 0, x, y, clipx, clipy); +} + + + +void +x_draw_xwidget_glyph_string (s) + struct glyph_string *s; +{ + 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; + Pixmap pixmap = None; + + int drawing_in_selected_window = (XWINDOW (FRAME_SELECTED_WINDOW (s->f))) == (s->w); + + // 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); + struct xwidget *xw = &xwidgets[s->xwidget_id]; + + int x = s->x; + int y = s->y + (s->height / 2) - (xw->height / 2); + int doingsocket = 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 + int clipx = min (xw->width, WINDOW_RIGHT_EDGE_X (s->w) - x); + int 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) + { + if ((xw->x != x) || (xw->y != y)) //has it moved? + { + printf ("xwidget moved: id:%d (%d,%d)->(%d,%d)\n", xw->id, xw->x, xw->y, x, y); + } + else + { + } + if (xw->hidden == 0) //hidden equals not being seen in the live window + { + gtk_fixed_move (GTK_FIXED (s->f->gwfixed), + GTK_WIDGET (xw->widgetwindow), x, y); + //adjust size of the widget window if some parts happen to be outside drawable area + //that is, we should clip + //an emacs window is not a gtk window, a gtk window covers the entire frame + gtk_widget_set_size_request (GTK_WIDGET (xw->widgetwindow), clipx, + clipy); + } + else + { + //xwidget is hidden, hide it offscreen somewhere, still realized, so we may snapshot it + //gtk_fixed_move(GTK_FIXED(s->f->gwfixed),GTK_WIDGET(xw->widgetwindow) ,10000,10000); + } + //xw is (aparently) supposed to refer to the *live* instance of the xwidget + xw->x = x; + xw->y = y; + + + } + else + { + //ok, we are painting the xwidgets in non-selected window + + //so draw a phantom + xwidget_draw_phantom (xw, x, y, clipx, clipy, s); + + } + +} + + + + +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. */ + ) + (xwidget_id, window_id) + Lisp_Object xwidget_id, window_id; +{ + struct xwidget *xw; + int xid = XFASTINT (xwidget_id); + xw = &xwidgets[xid]; + int iwindow_id = XFASTINT (window_id); + 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: + /* tell existing embed xwidget to steal other window id. */ + ) + (xwidget_id, new_width, new_height) + Lisp_Object xwidget_id, new_width, new_height; +{ + struct xwidget *xw; + int xid = XFASTINT (xwidget_id); + xw = &xwidgets[xid]; + int w = XFASTINT (new_width); + int h = XFASTINT (new_height); + 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; +} + + + +//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. */ + ) + (xwidget_id, kbd_grab) + Lisp_Object xwidget_id, kbd_grab; +{ + struct xwidget *xw; + int xid = XFASTINT (xwidget_id); + xw = &xwidgets[xid]; + int kbd_flag = XFASTINT (kbd_grab); + 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 (f, destination_window, keycode, keypress, modifiers) + struct frame *f; + Window destination_window; + int keypress; +{ + + 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_ROOT_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 + +DEFUN ("xwidget-send-keyboard-event", Fxwidget_send_keyboard_event, Sxwidget_send_keyboard_event, 2, 2, 0, doc:/* synthesize a kbd event for a xwidget. */ + ) + (xwidget_id, keydescriptor) + Lisp_Object xwidget_id, keydescriptor; +{ + int keyval; + char *keystring = ""; + + struct xwidget *xw; + int xwid = XFASTINT (xwidget_id); + xw = &xwidgets[xwid]; + + FRAME_PTR 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 + GdkWindow *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 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 () +{ + 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_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 (object) + 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); +} + +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); +} + + +Lisp_Object +xwidget_spec_value (spec, key, found) + Lisp_Object spec, 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 (spec) + Lisp_Object spec; +{ + + int found = 0, found1 = 0, found2 = 0; + Lisp_Object value; + value = xwidget_spec_value (spec, Qxwidget_id, &found1); + int id = INTEGERP (value) ? XFASTINT (value) : 0; //id 0 by default, but id must be unique so this is dumb + + struct xwidget *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 () +{ + 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; +} + +/* 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) +{ + //dont change anything if minibuffer is selected this redisplay + //this is mostly a workaround to reduce the phantoming of xwidgets + if( (XWINDOW (FRAME_MINIBUF_WINDOW (SELECTED_FRAME()))) == + (XWINDOW (FRAME_SELECTED_WINDOW (SELECTED_FRAME())))) + return; + + int i; + struct xwidget *xw; + region_modified = 0; + xwidget_start_redisplay (); + //iterate desired glyph matrix of "live" window here, hide gtk widgets + //not in the desired matrix. + int area; + //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 (xw->redisplayed) + xwidget_show (xw); + else + xwidget_hide (xw); + } + } + +} + +/* some type of modification was made to the buffers*/ +void +xwidget_modify_region () +{ + 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 () +{ + 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 index 00000000000..acceb720108 --- /dev/null +++ b/src/xwidget.h @@ -0,0 +1,61 @@ +void x_draw_xwidget_glyph_string P_ ((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 + +/* +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; +}; + + +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) 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); -- 2.11.4.GIT