diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.in | 10 | ||||
-rw-r--r-- | src/dispextern.h | 32 | ||||
-rw-r--r-- | src/dispnew.c | 19 | ||||
-rw-r--r-- | src/emacs.c | 6 | ||||
-rw-r--r-- | src/emacsgtkfixed.c | 123 | ||||
-rw-r--r-- | src/keyboard.c | 22 | ||||
-rw-r--r-- | src/lisp.h | 6 | ||||
-rw-r--r-- | src/print.c | 11 | ||||
-rw-r--r-- | src/termhooks.h | 5 | ||||
-rw-r--r-- | src/window.c | 7 | ||||
-rw-r--r-- | src/xdisp.c | 248 | ||||
-rw-r--r-- | src/xterm.c | 22 | ||||
-rw-r--r-- | src/xwidget.c | 1302 | ||||
-rw-r--r-- | src/xwidget.h | 110 |
14 files changed, 1905 insertions, 18 deletions
diff --git a/src/Makefile.in b/src/Makefile.in index 3be10c388c7..76101a68f1a 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -229,6 +229,12 @@ CFLAGS_SOUND= @CFLAGS_SOUND@ RSVG_LIBS= @RSVG_LIBS@ RSVG_CFLAGS= @RSVG_CFLAGS@ +CLUTTER_LIBS= @CLUTTER_LIBS@ +CLUTTER_CFLAGS= @CLUTTER_CFLAGS@ + +WEBKIT_LIBS= @WEBKIT_LIBS@ +WEBKIT_CFLAGS= @WEBKIT_CFLAGS@ + IMAGEMAGICK_LIBS= @IMAGEMAGICK_LIBS@ IMAGEMAGICK_CFLAGS= @IMAGEMAGICK_CFLAGS@ @@ -310,6 +316,7 @@ ALL_CFLAGS=-Demacs -DHAVE_CONFIG_H $(MYCPPFLAGS) -I. -I$(srcdir) \ $(C_SWITCH_MACHINE) $(C_SWITCH_SYSTEM) $(C_SWITCH_X_SITE) \ $(C_SWITCH_X_SYSTEM) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \ $(LIBXML2_CFLAGS) $(DBUS_CFLAGS) \ + $(WEBKIT_CFLAGS) $(CLUTTER_CFLAGS) \ $(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \ $(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) $(PROFILING_CFLAGS) \ $(LIBGNUTLS_CFLAGS) \ @@ -340,9 +347,11 @@ base_obj = dispnew.o frame.o scroll.o xdisp.o menu.o $(XMENU_OBJ) window.o \ process.o gnutls.o callproc.o \ region-cache.o sound.o atimer.o \ doprnt.o intervals.o textprop.o composite.o xml.o \ + xwidget.o \ $(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) obj = $(base_obj) $(NS_OBJC_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 of them have no DOC entries, but it does no harm to have them @@ -385,6 +394,7 @@ otherobj= $(TERMCAP_OBJ) $(PRE_ALLOC_OBJ) $(GMALLOC_OBJ) $(RALLOC_OBJ) \ ## with GCC, we might need LIB_GCC again after them. LIBES = $(LIBS) $(LIBX_BASE) $(LIBX_OTHER) $(LIBSOUND) \ $(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(DBUS_LIBS) \ + $(WEBKIT_LIBS) $(CLUTTER_LIBS) \ $(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) \ $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \ $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \ diff --git a/src/dispextern.h b/src/dispextern.h index 831803f58f4..1b2df45086c 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -290,7 +290,11 @@ enum glyph_type IMAGE_GLYPH, /* Glyph is a space of fractional width and/or height. */ - STRETCH_GLYPH + STRETCH_GLYPH, +#ifdef HAVE_XWIDGETS + /* Glyph is an external widget drawn by the GUI toolkit. */ + XWIDGET_GLYPH +#endif }; @@ -433,6 +437,9 @@ struct glyph /* Image ID for image glyphs (type == IMAGE_GLYPH). */ int img_id; +#ifdef HAVE_XWIDGETS + struct xwidget* xwidget; +#endif /* Sub-structure for type == STRETCH_GLYPH. */ struct { @@ -1299,6 +1306,9 @@ struct glyph_string /* Image, if any. */ struct image *img; +#ifdef HAVE_XWIDGETS + struct xwidget* xwidget; +#endif /* Slice */ struct glyph_slice slice; @@ -1983,7 +1993,11 @@ enum display_element_type IT_TRUNCATION, /* Continuation glyphs. See the comment for IT_TRUNCATION. */ - IT_CONTINUATION + IT_CONTINUATION, + +#ifdef HAVE_XWIDGETS + IT_XWIDGET +#endif }; @@ -2047,6 +2061,9 @@ enum it_method { GET_FROM_C_STRING, GET_FROM_IMAGE, GET_FROM_STRETCH, +#ifdef HAVE_XWIDGETS + GET_FROM_XWIDGET, +#endif NUM_IT_METHODS }; @@ -2260,6 +2277,13 @@ struct it struct { Lisp_Object object; } stretch; +#ifdef HAVE_XWIDGETS + /* method == GET_FROM_XWIDGET */ + struct { + Lisp_Object object; + struct xwidget* xwidget; + } xwidget; +#endif } u; /* current text and display positions. */ @@ -2382,6 +2406,10 @@ struct it /* If what == IT_IMAGE, the id of the image to display. */ ptrdiff_t image_id; +#ifdef HAVE_XWIDGETS + /* If what == IT_XWIDGET*/ + struct xwidget* xwidget; +#endif /* Values from `slice' property. */ struct it_slice slice; diff --git a/src/dispnew.c b/src/dispnew.c index 5c28d014819..abe09ed6a49 100644 --- a/src/dispnew.c +++ b/src/dispnew.c @@ -15,7 +15,6 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ - #include <config.h> #include <signal.h> #include <stdio.h> @@ -48,6 +47,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #include "xterm.h" #endif /* HAVE_X_WINDOWS */ + + #ifdef HAVE_NTGUI #include "w32term.h" #endif /* HAVE_NTGUI */ @@ -56,6 +57,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #include "nsterm.h" #endif +#ifdef HAVE_XWIDGETS +#include "xwidget.h" +#endif + /* Include systime.h after xterm.h to avoid double inclusion of time.h. */ #include "systime.h" @@ -289,8 +294,7 @@ add_window_display_history (struct window *w, const char *msg, int paused_p) PAUSED_P non-zero means that the update has been interrupted for pending input. */ -static void -add_frame_display_history (struct frame *f, int paused_p) +static void add_frame_display_history (struct frame *f, int paused_p) { char *buf; @@ -3696,6 +3700,9 @@ update_window (struct window *w, int force_p) add_window_display_history (w, w->current_matrix->method, paused_p); #endif +#ifdef HAVE_XWIDGETS + xwidget_end_redisplay(w, w->current_matrix); +#endif clear_glyph_matrix (desired_matrix); return paused_p; @@ -4288,6 +4295,12 @@ scrolling_window (struct window *w, int header_line_p) break; } +#ifdef HAVE_XWIDGETS + //currently this is needed to detect xwidget movement reliably. or probably not. + printf("scrolling_window\n"); + return 0; +#endif + /* Give up if some rows in the desired matrix are not enabled. */ if (!MATRIX_ROW (desired_matrix, i)->enabled_p) return -1; diff --git a/src/emacs.c b/src/emacs.c index ed4d9c49eb8..c766523b1c3 100644 --- a/src/emacs.c +++ b/src/emacs.c @@ -48,6 +48,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #include "buffer.h" #include "window.h" +#ifdef HAVE_XWIDGETS +#include "xwidget.h" +#endif #include "systty.h" #include "blockinput.h" #include "syssignal.h" @@ -1529,6 +1532,9 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem syms_of_xfns (); syms_of_xmenu (); syms_of_fontset (); +#ifdef HAVE_XWIDGETS + syms_of_xwidget(); +#endif syms_of_xsettings (); #ifdef HAVE_X_SM syms_of_xsmfns (); diff --git a/src/emacsgtkfixed.c b/src/emacsgtkfixed.c index 0b57e2cdf36..7b93319e978 100644 --- a/src/emacsgtkfixed.c +++ b/src/emacsgtkfixed.c @@ -27,7 +27,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #include "lisp.h" #include "frame.h" #include "xterm.h" - +#ifdef HAVE_XWIDGETS +#include "xwidget.h" +#endif struct _EmacsFixedPrivate { struct frame *f; @@ -42,6 +44,122 @@ static void emacs_fixed_get_preferred_height (GtkWidget *widget, gint *natural); G_DEFINE_TYPE (EmacsFixed, emacs_fixed, GTK_TYPE_FIXED) +#ifdef HAVE_XWIDGETS +/* void aloc_callback(GtkWidget* child, GtkWidget* fixed){ */ +/* GtkAllocation child_allocation; */ +/* GtkRequisition child_requisition; */ + +/* //TODO */ +/* // if child is an xwidget, find its clipping area and modify allocation */ + +/* struct xwidget_view* xv = (struct xwidget_view*) g_object_get_data (G_OBJECT (child), XG_XWIDGET_VIEW); */ +/* printf("aloc callback %d %s\n", xv, gtk_widget_get_name(child)); */ +/* if(xv){ */ +/* printf(" allocation modification for xw\n"); */ +/* gtk_widget_get_allocation(child, &child_allocation); */ +/* child_allocation.width = xv->clip_right; */ +/* child_allocation.height = xv->clip_bottom - xv->clip_top; */ +/* gtk_widget_size_allocate (child, &child_allocation); */ +/* //TODO find a way to remove this feeble workaround */ +/* } */ + +/* } */ + +struct GtkFixedPrivateL +{ + GList *children; +}; + +static void emacs_fixed_gtk_widget_size_allocate (GtkWidget *widget, + GtkAllocation *allocation){ + //for xwidgets + + + //TODO 1st call base class method + EmacsFixedClass *klass; + GtkWidgetClass *parent_class; + struct GtkFixedPrivateL* priv; + GtkFixedChild *child; + GtkAllocation child_allocation; + GtkRequisition child_requisition; + GList *children; + struct xwidget_view* xv; + + // printf(" emacs_fixed_gtk_widget_size_allocate\n"); + klass = EMACS_FIXED_GET_CLASS (widget); + parent_class = g_type_class_peek_parent (klass); + parent_class->size_allocate (widget, allocation); + + priv = G_TYPE_INSTANCE_GET_PRIVATE (widget, + GTK_TYPE_FIXED, + struct GtkFixedPrivateL); + //fixed->priv = G_TYPE_INSTANCE_GET_PRIVATE (fixed, GTK_TYPE_FIXED, GtkFixedPrivate); + //then modify allocations + /* gtk_container_foreach (widget, */ + /* aloc_callback, */ + /* widget); */ + + //begin copy paste extravaganza!!! + + //GtkFixed *fixed = GTK_FIXED (widget); + //GtkFixedPrivate *priv = fixed->priv; + + + gtk_widget_set_allocation (widget, allocation); + + if (gtk_widget_get_has_window (widget)) + { + if (gtk_widget_get_realized (widget)) + gdk_window_move_resize (gtk_widget_get_window (widget), + allocation->x, + allocation->y, + allocation->width, + allocation->height); + } + + for (children = priv->children; + children; + children = children->next) + { + child = children->data; + + if (!gtk_widget_get_visible (child->widget)) + continue; + + gtk_widget_get_preferred_size (child->widget, &child_requisition, NULL); + child_allocation.x = child->x; + child_allocation.y = child->y; + + if (!gtk_widget_get_has_window (widget)) + { + child_allocation.x += allocation->x; + child_allocation.y += allocation->y; + } + + child_allocation.width = child_requisition.width; + child_allocation.height = child_requisition.height; + + + + xv = (struct xwidget_view*) g_object_get_data (G_OBJECT (child->widget), XG_XWIDGET_VIEW); + //printf("aloc callback %d %s\n", xv, gtk_widget_get_name(child)); + if(xv){ + //gtk_widget_get_allocation(child, &child_allocation); + child_allocation.width = xv->clip_right; + child_allocation.height = xv->clip_bottom - xv->clip_top; + //gtk_widget_size_allocate (child, &child_allocation); + //TODO find a way to remove this feeble workaround + // printf(" allocation internal modification for xw %d %d,%d\n",xv, child_allocation.width, child_allocation.height); + + } + gtk_widget_size_allocate (child->widget, &child_allocation); + + } + +} + +#endif + static void emacs_fixed_class_init (EmacsFixedClass *klass) { @@ -53,6 +171,9 @@ emacs_fixed_class_init (EmacsFixedClass *klass) widget_class->get_preferred_width = emacs_fixed_get_preferred_width; widget_class->get_preferred_height = emacs_fixed_get_preferred_height; +#ifdef HAVE_XWIDGETS + widget_class->size_allocate = emacs_fixed_gtk_widget_size_allocate; +#endif g_type_class_add_private (klass, sizeof (EmacsFixedPrivate)); } diff --git a/src/keyboard.c b/src/keyboard.c index 51eac369e7c..8705c3cd65f 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -329,6 +329,9 @@ static Lisp_Object Qsave_session; #ifdef HAVE_DBUS static Lisp_Object Qdbus_event; #endif +#ifdef HAVE_XWIDGETS +Lisp_Object Qxwidget_event; +#endif static Lisp_Object Qconfig_changed_event; /* Lisp_Object Qmouse_movement; - also an event header */ @@ -4030,6 +4033,13 @@ kbd_buffer_get_event (KBOARD **kbp, kbd_fetch_ptr = event + 1; } #endif +#ifdef HAVE_XWIDGETS + else if (event->kind == XWIDGET_EVENT) + { + obj = make_lispy_event (event); + kbd_fetch_ptr = event + 1; + } +#endif else if (event->kind == CONFIG_CHANGED_EVENT) { obj = make_lispy_event (event); @@ -5925,7 +5935,13 @@ make_lispy_event (struct input_event *event) return Fcons (Qdbus_event, event->arg); } #endif /* HAVE_DBUS */ - +#ifdef HAVE_XWIDGETS + case XWIDGET_EVENT: + { + printf("cool, an xwidget event arrived in make_lispy_event!\n"); + return Fcons (Qxwidget_event,event->arg); + } +#endif case CONFIG_CHANGED_EVENT: return Fcons (Qconfig_changed_event, Fcons (event->arg, @@ -11543,6 +11559,10 @@ syms_of_keyboard (void) DEFSYM (Qdbus_event, "dbus-event"); #endif +#ifdef HAVE_XWIDGETS + Qxwidget_event = intern ("xwidget-event"); + staticpro (&Qxwidget_event); +#endif DEFSYM (QCenable, ":enable"); DEFSYM (QCvisible, ":visible"); DEFSYM (QChelp, ":help"); diff --git a/src/lisp.h b/src/lisp.h index 5c84bb8e06e..7936e6a6dec 100644 --- a/src/lisp.h +++ b/src/lisp.h @@ -405,7 +405,11 @@ enum pvec_type PVEC_SUB_CHAR_TABLE = 0x100000, PVEC_FONT = 0x200000, PVEC_OTHER = 0x400000, - PVEC_TYPE_MASK = 0x7ffe00 +#ifdef HAVE_XWIDGETS + PVEC_XWIDGET = 0x800000, + PVEC_XWIDGET_VIEW = 0x1000000, +#endif + PVEC_TYPE_MASK = 0x3fffe00 #if 0 /* This is used to make the value of PSEUDOVECTOR_FLAG available to GDB. It doesn't work on OS Alpha. Moved to a variable in diff --git a/src/print.c b/src/print.c index d67149a40ab..d15590a8880 100644 --- a/src/print.c +++ b/src/print.c @@ -36,7 +36,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #include "blockinput.h" #include "termhooks.h" /* For struct terminal. */ #include "font.h" - +#ifdef HAVE_XWIDGETS +#include "xwidget.h" +#endif Lisp_Object Qstandard_output; static Lisp_Object Qtemp_buffer_setup_hook; @@ -1763,6 +1765,13 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag strout (XSUBR (obj)->symbol_name, -1, -1, printcharfun); PRINTCHAR ('>'); } +#ifdef HAVE_XWIDGETS + else if (XXWIDGETP (obj)) + { + strout ("#<xwidget ", -1, -1, printcharfun); + PRINTCHAR ('>'); + } +#endif else if (WINDOWP (obj)) { strout ("#<window ", -1, -1, printcharfun); diff --git a/src/termhooks.h b/src/termhooks.h index 63d166b6418..a025e2798d9 100644 --- a/src/termhooks.h +++ b/src/termhooks.h @@ -205,7 +205,10 @@ enum event_kind /* Non-key system events (e.g. application menu events) */ , NS_NONKEY_EVENT #endif - +#ifdef HAVE_XWIDGETS + /* events generated by xwidgets*/ + , XWIDGET_EVENT +#endif }; /* If a struct input_event has a kind which is SELECTION_REQUEST_EVENT diff --git a/src/window.c b/src/window.c index e3850387a64..33361b5ac1d 100644 --- a/src/window.c +++ b/src/window.c @@ -49,7 +49,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #ifdef HAVE_NS #include "nsterm.h" #endif - +#ifdef HAVE_XWIDGETS +#include "xwidget.h" +#endif Lisp_Object Qwindowp, Qwindow_live_p; static Lisp_Object Qwindow_configuration_p, Qrecord_window_buffer; static Lisp_Object Qwindow_deletable_p, Qdelete_window, Qdisplay_buffer; @@ -3933,6 +3935,9 @@ when WINDOW is the only window on its frame. */) { /* Block input. */ BLOCK_INPUT; +#ifdef HAVE_XWIDGETS + xwidget_view_delete_all_in_window(w); +#endif window_resize_apply (p, horflag); windows_or_buffers_changed++; diff --git a/src/xdisp.c b/src/xdisp.c index d4b14793843..2aa0dee02b8 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -313,7 +313,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #endif #include "font.h" - +#ifdef HAVE_XWIDGETS +#include "xwidget.h" +#endif #ifndef FRAME_X_OUTPUT #define FRAME_X_OUTPUT(f) ((f)->output_data.x) #endif @@ -883,6 +885,9 @@ static int next_element_from_c_string (struct it *); static int next_element_from_buffer (struct it *); static int next_element_from_composition (struct it *); static int next_element_from_image (struct it *); +#ifdef HAVE_XWIDGETS +static int next_element_from_xwidget(struct it *); +#endif 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 *, @@ -4108,6 +4113,9 @@ handle_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, if (CONSP (spec) /* Simple specerties. */ && !EQ (XCAR (spec), Qimage) +#ifdef HAVE_XWIDGETS + && !EQ (XCAR (spec), Qxwidget) +#endif && !EQ (XCAR (spec), Qspace) && !EQ (XCAR (spec), Qwhen) && !EQ (XCAR (spec), Qslice) @@ -4526,7 +4534,11 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, || ((it ? FRAME_WINDOW_P (it->f) : frame_window_p) && valid_image_p (value)) #endif /* not HAVE_WINDOW_SYSTEM */ - || (CONSP (value) && EQ (XCAR (value), Qspace))); + || (CONSP (value) && EQ (XCAR (value), Qspace)) +#ifdef HAVE_XWIDGETS + || XWIDGETP(value) +#endif + ); if (valid_p && !display_replaced_p) { @@ -4600,6 +4612,19 @@ handle_single_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object, *position = it->position = start_pos; retval = 1 + (it->area == TEXT_AREA); } +#ifdef HAVE_XWIDGETS + 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 = lookup_xwidget(value); + } +#endif #ifdef HAVE_WINDOW_SYSTEM else { @@ -5315,6 +5340,11 @@ push_it (struct it *it, struct text_pos *position) case GET_FROM_STRETCH: p->u.stretch.object = it->object; break; +#ifdef HAVE_XWIDGETS + case GET_FROM_XWIDGET: + p->u.xwidget.object = it->object; + break; +#endif } p->position = position ? *position : it->position; p->current = it->current; @@ -5407,6 +5437,11 @@ pop_it (struct it *it) it->object = p->u.image.object; it->slice = p->u.image.slice; break; +#ifdef HAVE_XWIDGETS + case GET_FROM_XWIDGET: + it->object = p->u.xwidget.object; + break; +#endif case GET_FROM_STRETCH: it->object = p->u.stretch.object; break; @@ -6046,6 +6081,9 @@ static int (* get_next_element[NUM_IT_METHODS]) (struct it *it) = next_element_from_c_string, next_element_from_image, next_element_from_stretch +#ifdef HAVE_XWIDGETS + ,next_element_from_xwidget +#endif }; #define GET_NEXT_DISPLAY_ELEMENT(it) (*get_next_element[(it)->method]) (it) @@ -6845,6 +6883,9 @@ set_iterator_to_next (struct it *it, int reseat_p) case GET_FROM_IMAGE: case GET_FROM_STRETCH: +#ifdef HAVE_XWIDGETS + 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. */ @@ -6853,7 +6894,7 @@ set_iterator_to_next (struct it *it, int reseat_p) if (it->method == GET_FROM_STRING) goto consider_string_end; break; - +#endif default: /* There are no other methods defined, so this should be a bug. */ abort (); @@ -7271,6 +7312,19 @@ next_element_from_image (struct it *it) return 1; } +#ifdef HAVE_XWIDGETS +/* 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; +} +#endif + /* Fill iterator IT with next display element from a stretch glyph property. IT->object is the value of the text property. Value is @@ -12758,6 +12812,13 @@ redisplay_internal (void) *w->desired_matrix->method = 0; debug_method_add (w, "optimization 1"); #endif +#if HAVE_XWIDGETS + //debug optimization movement issue + //w->desired_matrix->no_scrolling_p = 1; + //*w->desired_matrix->method = 0; + //debug_method_add (w, "optimization 1"); +#endif + #ifdef HAVE_WINDOW_SYSTEM update_window_fringes (w, 0); #endif @@ -15626,6 +15687,8 @@ try_window (Lisp_Object window, struct text_pos pos, int flags) /* Initialize iterator and info to start at POS. */ start_display (&it, w, pos); + + /* Display all lines of W. */ while (it.current_y < it.last_visible_y) { @@ -15634,6 +15697,11 @@ try_window (Lisp_Object window, struct text_pos pos, int flags) if (fonts_changed_p && !(flags & TRY_WINDOW_IGNORE_FONTS_CHANGE)) return 0; } +#ifdef HAVE_XWIDGETS_xxx + //currently this is needed to detect xwidget movement reliably. or probably not. + printf("try_window\n"); + return 0; +#endif /* Don't let the cursor end in the scroll margins. */ if ((flags & TRY_WINDOW_CHECK_MARGINS) @@ -15727,6 +15795,13 @@ try_window_reusing_current_matrix (struct window *w) return 0; #endif +#ifdef HAVE_XWIDGETS_xxx + //currently this is needed to detect xwidget movement reliably. or probably not. + printf("try_window_reusing_current_matrix\n"); + return 0; +#endif + + if (/* This function doesn't handle terminal frames. */ !FRAME_WINDOW_P (f) /* Don't try to reuse the display if windows have been split @@ -16487,6 +16562,13 @@ try_window_id (struct window *w) return 0; #endif +#ifdef HAVE_XWIDGETS_xxx + //maybe needed for proper xwidget movement + printf("try_window_id\n"); + return -1; +#endif + + /* This is handy for debugging. */ #if 0 #define GIVE_UP(X) \ @@ -17310,6 +17392,29 @@ dump_glyph (struct glyph_row *row, struct glyph *glyph, int area) glyph->left_box_line_p, glyph->right_box_line_p); } +#ifdef HAVE_XWIDGETS + 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, + '.', + glyph->face_id, + glyph->left_box_line_p, + glyph->right_box_line_p); + + // printf("dump xwidget glyph\n"); + } +#endif } @@ -21431,6 +21536,13 @@ calc_pixel_width_or_height (double *res, struct it *it, Lisp_Object prop, return OK_PIXELS (width_p ? img->width : img->height); } +#ifdef HAVE_XWIDGETS + 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 #endif if (EQ (car, Qplus) || EQ (car, Qminus)) { @@ -21925,7 +22037,20 @@ fill_image_glyph_string (struct glyph_string *s) s->ybase += s->first_glyph->voffset; } - +#ifdef HAVE_XWIDGETS +static void +fill_xwidget_glyph_string (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 = s->first_glyph->u.xwidget; + //assert_valid_xwidget_id ( s->xwidget, "fill_xwidget_glyph_string"); +} +#endif /* Fill glyph string S from a sequence of stretch glyphs. START is the index of the first glyph to consider, @@ -22257,6 +22382,21 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p) } \ while (0) +#ifdef HAVE_XWIDGETS +#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) +#endif + /* 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 @@ -22411,6 +22551,11 @@ compute_overhangs_and_x (struct glyph_string *s, int x, int backward_p) BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL, \ HL, X, LAST_X); \ break; \ + case XWIDGET_GLYPH: \ + BUILD_XWIDGET_GLYPH_STRING (START, END, HEAD, TAIL, \ + HL, X, LAST_X); \ + break; \ + \ \ case GLYPHLESS_GLYPH: \ BUILD_GLYPHLESS_GLYPH_STRING (START, END, HEAD, TAIL, \ @@ -23022,6 +23167,89 @@ produce_image_glyph (struct it *it) } } +#ifdef HAVE_XWIDGETS +static void +produce_xwidget_glyph (struct it *it) +{ + struct xwidget* xw; + struct face *face; + int glyph_ascent, crop; + 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); + + xw = it->xwidget; + it->ascent = it->phys_ascent = glyph_ascent = xw->height/2; + it->descent = xw->height/2; + it->phys_descent = it->descent; + it->pixel_width = xw->width; + /* 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 = 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 = it->xwidget; + //assert_valid_xwidget_id(glyph->u.xwidget_id,"produce_xwidget_glyph"); + glyph->font_type = FONT_TYPE_UNKNOWN; + ++it->glyph_row->used[area]; + } + else + IT_EXPAND_MATRIX_WIDTH (it, area); + } +} +#endif /* 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 @@ -24233,7 +24461,10 @@ x_produce_glyphs (struct it *it) produce_image_glyph (it); else if (it->what == IT_STRETCH) produce_stretch_glyph (it); - +#ifdef HAVE_XWIDGETS + else if (it->what == IT_XWIDGET) + produce_xwidget_glyph (it); +#endif done: /* Accumulate dimensions. Note: can't assume that it->descent > 0 because this isn't true for images with `:ascent 100'. */ @@ -24594,6 +24825,13 @@ get_window_cursor_type (struct window *w, struct glyph *glyph, int *width, /* Use normal cursor if not blinked off. */ if (!w->cursor_off_p) { + +#ifdef HAVE_XWIDGETS + if (glyph != NULL && glyph->type == XWIDGET_GLYPH){ + //printf("attempt xwidget cursor avoidance in get_window_cursor_type\n"); + return NO_CURSOR; + } +#endif if (glyph != NULL && glyph->type == IMAGE_GLYPH) { if (cursor_type == FILLED_BOX_CURSOR) diff --git a/src/xterm.c b/src/xterm.c index 86393cf411f..40dbe540903 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -62,6 +62,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ #include "coding.h" #include "frame.h" #include "dispextern.h" +#ifdef HAVE_XWIDGETS +#include "xwidget.h" +#endif #include "fontset.h" #include "termhooks.h" #include "termopts.h" @@ -2712,7 +2715,13 @@ x_draw_glyph_string (struct glyph_string *s) case IMAGE_GLYPH: x_draw_image_glyph_string (s); break; - +#ifdef HAVE_XWIDGETS + case XWIDGET_GLYPH: + //erase xwidget background + //x_draw_glyph_string_background (s, 0); + x_draw_xwidget_glyph_string (s); + break; +#endif case STRETCH_GLYPH: x_draw_stretch_glyph_string (s); break; @@ -7283,7 +7292,12 @@ x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text cursor_glyph = get_phys_cursor_glyph (w); if (cursor_glyph == NULL) return; - +#ifdef HAVE_XWIDGETS + if (cursor_glyph->type == XWIDGET_GLYPH){ + printf("tried avoiding xwidget cursor\n"); + return; //experimental avoidance of cursor on xwidget + } +#endif /* 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. */ @@ -9916,7 +9930,11 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name) https://bugzilla.gnome.org/show_bug.cgi?id=563627. */ id = g_log_set_handler ("GLib", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION, my_log_handler, NULL); +#ifdef HAVE_CLUTTER + gtk_clutter_init (&argc, &argv2); +#else gtk_init (&argc, &argv2); +#endif g_log_remove_handler ("GLib", id); /* gtk_init does set_locale. We must fix locale after calling it. */ diff --git a/src/xwidget.c b/src/xwidget.c new file mode 100644 index 00000000000..6be377c8b90 --- /dev/null +++ b/src/xwidget.c @@ -0,0 +1,1302 @@ +#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> + +#ifdef HAVE_GTK3 +//for gtk3; sockets and plugs +#include <gtk/gtkx.h> +#include "emacsgtkfixed.h" +#endif + + + +#ifdef HAVE_GOOCANVAS +#include <goocanvas.h> +#endif + +#ifdef HAVE_CLUTTER +#include <librsvg/rsvg.h> +#include <clutter/clutter.h> +#include <clutter-gtk/clutter-gtk.h> +#endif + +#include <wchar.h> + +#ifdef HAVE_WEBKIT_OSR +#include <webkit/webkitwebview.h> +#include <webkit/webkitwebplugindatabase.h> +#include <webkit/webkitwebplugin.h> +#include <webkit/webkitglobals.h> +#endif + +#include "xwidget.h" + +//TODO should of course not be a hardcoded array but I can't be bothered atm +//just a fixed array of xwidgets for now +//would need to be hashtables or something + +#define MAX_XWIDGETS 100 +struct xwidget_view xwidget_views[MAX_XWIDGETS]; + +//TODO embryo of lisp allocators for xwidgets +//TODO xwidget* should be Lisp_xwidget* +struct xwidget* +allocate_xwidget (void) +{ + return ALLOCATE_PSEUDOVECTOR (struct xwidget, height, PVEC_XWIDGET); +} + +//TODO xwidget_view* should be Lisp_xwidget_view* +struct xwidget_view* +allocate_xwidget_view (void) +{ + return ALLOCATE_PSEUDOVECTOR (struct xwidget_view, redisplayed, PVEC_XWIDGET_VIEW); +} + + +Lisp_Object Qxwidget; +Lisp_Object Qcxwidget; +Lisp_Object Qtitle; +Lisp_Object Qxwidget_set_keyboard_grab; +Lisp_Object Qxwidget_embed_steal_window; +Lisp_Object Qxwidget_info; +Lisp_Object Qxwidget_resize; +Lisp_Object Qxwidget_send_keyboard_event; + +Lisp_Object Qbutton, Qtoggle, Qslider, Qsocket, Qsocket_osr, Qcairo, + Qwebkit_osr, QCplist; + + +extern Lisp_Object QCtype; +extern Lisp_Object QCwidth, QCheight; + +struct xwidget_view* xwidget_view_lookup(struct xwidget* xw, struct window *w); +Lisp_Object xwidget_spec_value ( Lisp_Object spec, Lisp_Object key, int *found); +gboolean webkit_osr_damage_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data) ; +gboolean webkit_osr_key_event_callback (GtkWidget *widget, GdkEventKey *event, gpointer data) ; +void webkit_osr_document_load_finished_callback (WebKitWebView *webkitwebview, + WebKitWebFrame *arg1, + gpointer user_data); + +DEFUN ("make-xwidget", Fmake_xwidget, Smake_xwidget, 7, 7, 0, + doc: /* xw */ + ) + (Lisp_Object beg, Lisp_Object end, + Lisp_Object type, + Lisp_Object title, + Lisp_Object width, Lisp_Object height, + Lisp_Object data) +{ + //should work a bit like "make-button"(make-button BEG END &rest PROPERTIES) + // arg "type" and fwd should be keyword args eventually + //(make-xwidget 3 3 'button "oei" 31 31 nil) + //(xwidget-info (car xwidget-alist)) + struct xwidget* xw = allocate_xwidget(); + Lisp_Object val; + struct gcpro gcpro1; + GCPRO1(xw); + XSETSYMBOL(xw->type, type); + XSETSTRING(xw->title, title); + //TODO buffer should be an optional argument not just assumed to be the current buffer + XSETBUFFER(xw->buffer, Fcurrent_buffer()); // conservatively gcpro xw since we call lisp + xw->height = XFASTINT(height); + xw->width = XFASTINT(width); + XSETPSEUDOVECTOR (val, xw, PVEC_XWIDGET); //?? dunno why i need this + Vxwidget_alist = Fcons ( val, Vxwidget_alist); + xw->widgetwindow_osr = NULL; + xw->widget_osr = NULL; + xw->plist = Qnil; + + +#ifdef HAVE_WEBKIT_OSR + /* DIY mvc. widget is rendered offscreen, + later bitmap copied to the views. + */ + if (EQ(xw->type, Qwebkit_osr)){ + printf("init webkit osr\n"); + BLOCK_INPUT; + xw->widgetwindow_osr = GTK_CONTAINER (gtk_offscreen_window_new ()); + gtk_window_resize( GTK_WINDOW(xw->widgetwindow_osr), xw->width, xw->height); + xw->widget_osr = webkit_web_view_new(); + + gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height); + gtk_container_add (xw->widgetwindow_osr, xw->widget_osr); + + gtk_widget_show_all (GTK_WIDGET (xw->widgetwindow_osr)); + + /* store some xwidget data in the gtk widgets for convenient retrieval in the event handlers. */ + g_object_set_data (G_OBJECT (xw->widget_osr), XG_XWIDGET, (gpointer) (xw)); + g_object_set_data (G_OBJECT (xw->widgetwindow_osr), XG_XWIDGET, (gpointer) (xw)); + /* signals */ + g_signal_connect (G_OBJECT ( xw->widgetwindow_osr), "damage-event", G_CALLBACK (webkit_osr_damage_event_callback), NULL); + + //TODO these were just a test hack + /* g_signal_connect (G_OBJECT ( xw->widget_osr), "key-press-event", G_CALLBACK (webkit_osr_key_event_callback), NULL); */ + /* g_signal_connect (G_OBJECT ( xw->widget_osr), "key-release-event", G_CALLBACK (webkit_osr_key_event_callback), NULL); */ + + g_signal_connect (G_OBJECT ( xw->widget_osr), + "document-load-finished", + G_CALLBACK (webkit_osr_document_load_finished_callback), + xw); + + webkit_web_view_load_uri(WEBKIT_WEB_VIEW(xw->widget_osr), "http://www.fsf.org"); + UNBLOCK_INPUT; + + } +#endif + if (EQ(xw->type, Qsocket_osr)){ + printf("init socket osr\n"); + BLOCK_INPUT; + xw->widgetwindow_osr = GTK_CONTAINER (gtk_offscreen_window_new ()); + gtk_window_resize( GTK_WINDOW(xw->widgetwindow_osr), xw->width, xw->height); + + //////////////////// + //xw->widget_osr = webkit_web_view_new(); + xw->widget_osr = gtk_socket_new(); + //g_signal_connect_after(xv->widget, "plug-added", G_CALLBACK(xwidget_plug_added), "plug added"); + //g_signal_connect_after(xv->widget, "plug-removed", G_CALLBACK(xwidget_plug_removed), "plug removed"); + /////////////////// + + gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height); + gtk_container_add (xw->widgetwindow_osr, xw->widget_osr); + + gtk_widget_show_all (GTK_WIDGET (xw->widgetwindow_osr)); + + /* store some xwidget data in the gtk widgets for convenient retrieval in the event handlers. */ + g_object_set_data (G_OBJECT (xw->widget_osr), XG_XWIDGET, (gpointer) (xw)); + g_object_set_data (G_OBJECT (xw->widgetwindow_osr), XG_XWIDGET, (gpointer) (xw)); + g_signal_connect (G_OBJECT ( xw->widgetwindow_osr), "damage-event", G_CALLBACK (webkit_osr_damage_event_callback), NULL); + + //webkit_web_view_load_uri(WEBKIT_WEB_VIEW(xw->widget_osr), "http://www.fsf.org"); + UNBLOCK_INPUT; + + } + + UNGCPRO; + return val; +} + +int +xwidget_hidden(struct xwidget_view *xv) +{ + return xv->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 = NULL;//(FRAME_PTR) g_object_get_data (G_OBJECT (xw->widget), XG_FRAME_DATA); //TODO + printf ("button clicked xw:%d '%s'\n", xw, xw->title); + + 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 ((Lisp_Object)xw, event.arg); //TODO send the actual xwidget object now instead + event.arg = Fcons (intern ("buttonclick"), event.arg); + + kbd_buffer_store_event (&event); + + +} + + +static void +send_xembed_ready_event (struct xwidget* xw, 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 ((Lisp_Object)xw, event.arg); //TODO + event.arg = Fcons (intern ("xembed-ready"), event.arg); + + + kbd_buffer_store_event (&event); + +} + +void +xwidget_show_view (struct xwidget_view *xv) +{ + xv->hidden = 0; + gtk_widget_show(GTK_WIDGET(xv->widgetwindow)); + gtk_fixed_move (GTK_FIXED (xv->emacswindow), GTK_WIDGET (xv->widgetwindow), xv->x + xv->clip_left, xv->y + xv->clip_top); //TODO refactor +} + + +/* hide an xvidget view */ +void +xwidget_hide_view (struct xwidget_view *xv) +{ + xv->hidden = 1; + //gtk_widget_hide(GTK_WIDGET(xw->widgetwindow)); + gtk_fixed_move (GTK_FIXED (xv->emacswindow), GTK_WIDGET (xv->widgetwindow), + 10000, 10000); +} + + +void xwidget_plug_added(GtkSocket *socket, + gpointer user_data) +{ + //hmm this doesnt seem to get called for foreign windows + printf("xwidget_plug_added\n"); +} + +gboolean xwidget_plug_removed(GtkSocket *socket, + gpointer user_data) +{ + printf("xwidget_plug_removed\n"); + return TRUE; /* dont run the default handler because that kills the socket and we want to reuse it*/ +} + + +void xwidget_slider_changed (GtkRange *range, + gpointer user_data) +{ + //slider value changed. change value of siblings + //correspondingly. but remember that changing value will again + //trigger signal + + //TODO MVC view storage wont be an array futureish so the loop needs to change eventually + //TODO MVC it would be nice if this code could be reusable but, alas, C is not a functional language + //issues are: + // - the type of the controllers value (double, boolean etc) + // - the getter and setter (but they can be func pointers) + // a behemoth macro is always an option. + double v=gtk_range_get_value(range); + struct xwidget_view* xvp = g_object_get_data (G_OBJECT (range), XG_XWIDGET_VIEW); + struct xwidget_view* xv; + + printf("slider changed val:%f\n", v); + + + //block sibling views signal handlers + for (int i = 0; i < MAX_XWIDGETS; i++) + { + xv = &xwidget_views[i]; + if(xv->initialized && xvp->model == xv->model){ + g_signal_handler_block( xv->widget,xv->handler_id); + } + } + //set values of sibling views and unblock + for (int i = 0; i < MAX_XWIDGETS; i++) + { + xv = &xwidget_views[i]; + if(xv->initialized && xvp->model == xv->model){ + gtk_range_set_value(GTK_RANGE(xv->widget), v); + g_signal_handler_unblock( xv->widget,xv->handler_id); + } + } + +} + + +/* when the off-screen webkit master view changes this signal is called. + it copies the bitmap from the off-screen webkit instance */ +gboolean webkit_osr_damage_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data) +{ + //TODO this is wrong! should just oueu a redraw of onscreen widget + struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET); + struct xwidget_view* xv; + //webkit_osr_redraw_child(xw, widget); + printf ("damage\n"); + for (int i = 0; i < MAX_XWIDGETS; i++)//todo mvc refactor + { + xv = &xwidget_views[i]; + if(xv->initialized && xv->model == xw){ + gtk_widget_queue_draw (xv->widget); //redraw all views, the master has changed + } + } + + return FALSE; +} + + + +gboolean webkit_osr_key_event_callback (GtkWidget *widget, GdkEventKey *event, gpointer data) +{ + printf("terminating a webkit osr keypress\n"); + //TRUE terminate the event here. no paren handlers will be called. but webkit then doesng get the event and it still crashes + //FALSE paren handlers will be called. webkit then gets the event and it still crashes + return TRUE; +} + + +void webkit_osr_document_load_finished_callback (WebKitWebView *webkitwebview, + WebKitWebFrame *arg1, + gpointer data) +{ + //TODO this event sending code should be refactored + struct input_event event; + // struct xwidget *xw = (struct xwidget *) data; + struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (webkitwebview), XG_XWIDGET); + printf("webkit finished loading\n"); + + 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 ((Lisp_Object)xw, event.arg); //TODO + event.arg = Fcons (intern ("document-load-finished"), event.arg); + + + kbd_buffer_store_event (&event); + +} + +//for gtk3 webkit_osr +gboolean +xwidget_osr_draw_callback (GtkWidget *widget, cairo_t *cr, gpointer data) +{ + struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET); + struct xwidget_view* xv = (struct xwidget_view*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET_VIEW); + + // printf("xwidget_osr_draw_callback gtk3 xw.id:%d xw.type:%d window:%d vis:%d\n", + // xw,xw->type, gtk_widget_get_window (widget), gtk_widget_get_visible (xw->widget_osr)); + + cairo_rectangle(cr, 0,0, xv->clip_right, xv->clip_bottom);//xw->width, xw->height); + cairo_clip(cr); + + gtk_widget_draw (xw->widget_osr, cr); + + + return FALSE; +} + + +gboolean +xwidget_osr_button_callback ( GtkWidget *widget, + GdkEvent *event, + gpointer user_data) +{ + struct xwidget* xw = (struct xwidget*) g_object_get_data (G_OBJECT (widget), XG_XWIDGET); + GdkEvent* eventcopy = gdk_event_copy(event); + + ((GdkEventButton*)eventcopy)->window = gtk_widget_get_window(xw->widget_osr); + gtk_main_do_event(eventcopy); //TODO this will leak events. they should be deallocated later + return TRUE; //dont propagate this event furter +} + +int xwidget_view_index=0; + +/* initializes and does initial placement of an xwidget view on screen */ +struct xwidget_view* +xwidget_init_view ( + struct xwidget *xww, + struct glyph_string *s, + int x, int y) +{ + //TODO temp code replace with lisp list + struct xwidget_view *xv; + GdkColor color; + + do{ + if(xwidget_view_index < MAX_XWIDGETS) + xwidget_view_index++; + else + xwidget_view_index=0; + + xv = &xwidget_views[xwidget_view_index]; + }while( xv->initialized == 1); //TODO yeah this can infloop if there are MAX_WIDGETS on-screen + + xv->initialized = 1; + xv->w = s->w; + xv->model = xww; + + //widget creation + if(EQ(xww->type, Qbutton)) + { + xv->widget = gtk_button_new_with_label (XSTRING(xww->title)->data); + g_signal_connect (G_OBJECT (xv->widget), "clicked", + G_CALLBACK (buttonclick_handler), xww); //the model rather than the view + } else if (EQ(xww->type, Qtoggle)) { + xv->widget = gtk_toggle_button_new_with_label (XSTRING(xww->title)->data); + //xv->widget = gtk_entry_new ();//temp hack to experiment with key propagation TODO entry widget is useful for testing + } else if (EQ(xww->type, Qsocket)) { + xv->widget = gtk_socket_new (); + g_signal_connect_after(xv->widget, "plug-added", G_CALLBACK(xwidget_plug_added), "plug added"); + g_signal_connect_after(xv->widget, "plug-removed", G_CALLBACK(xwidget_plug_removed), "plug removed"); + //TODO these doesnt help + gtk_widget_add_events(xv->widget, GDK_KEY_PRESS); + gtk_widget_add_events(xv->widget, GDK_KEY_RELEASE); + } else if (EQ(xww->type, Qslider)) { + xv->widget = + //gtk_hscale_new (GTK_ADJUSTMENT(gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 10.0, 10.0))); + gtk_hscale_new_with_range ( 0.0, 100.0, 10.0); + gtk_scale_set_draw_value (GTK_SCALE (xv->widget), FALSE); //i think its emacs role to show text and stuff, so disable the widgets own text + xv->handler_id = g_signal_connect_after(xv->widget, "value-changed", G_CALLBACK(xwidget_slider_changed), "slider changed"); + } else if (EQ(xww->type, Qcairo)) { + //Cairo view + //uhm cairo is differentish in gtk 3. + //gdk_cairo_create (gtk_widget_get_window (FRAME_GTK_WIDGET (s->f))); +#ifdef HAVE_GOOCANVAS + xv->widget = goo_canvas_new(); + GooCanvasItem *root, *rect_item, *text_item; + goo_canvas_set_bounds (GOO_CANVAS (xv->widget), 0, 0, 1000, 1000); + root = goo_canvas_get_root_item (GOO_CANVAS (xv->widget)); + rect_item = goo_canvas_rect_new (root, 100, 100, 400, 400, + "line-width", 10.0, + "radius-x", 20.0, + "radius-y", 10.0, + "stroke-color", "yellow", + "fill-color", "red", + NULL); + + text_item = goo_canvas_text_new (root, "Hello World", 300, 300, -1, + GTK_ANCHOR_CENTER, + "font", "Sans 24", + NULL); + goo_canvas_item_rotate (text_item, 45, 300, 300); + +#endif +#ifdef HAVE_CLUTTER + xv->widget = gtk_clutter_embed_new ();; + ClutterActor *stage = NULL; + stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED ( xv->widget)); + ClutterColor stage_color = { 0xaa, 0xaa, 0xaa, 0xff }; /* Black */ + clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); + + ClutterActor * texture = clutter_cairo_texture_new (1000, 1000); + clutter_container_add_actor(stage, texture); + clutter_actor_set_position(texture, 0,0); + clutter_actor_show(texture); + + cairo_t *cr; + cr = clutter_cairo_texture_create (CLUTTER_CAIRO_TEXTURE (texture)); + + /* draw on the context */ + RsvgHandle *h = rsvg_handle_new_from_file ("/tmp/tst.svg", + NULL); + + rsvg_handle_render_cairo(h, cr); + cairo_destroy (cr); + + /* Show the stage: */ + clutter_actor_show (stage); +#endif + } else if (EQ(xww->type, Qwebkit_osr)||EQ(xww->type, Qsocket_osr)) { +#ifdef HAVE_WEBKIT_OSR + xv->widget = gtk_drawing_area_new(); + gtk_widget_set_app_paintable ( xv->widget, TRUE); //because expose event handling + gtk_widget_add_events(xv->widget, + GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_POINTER_MOTION_MASK); + g_signal_connect (G_OBJECT ( xv->widget), "draw", + G_CALLBACK (xwidget_osr_draw_callback), NULL); + g_signal_connect (G_OBJECT ( xv->widget), "button-press-event", + G_CALLBACK (xwidget_osr_button_callback), NULL); + g_signal_connect (G_OBJECT ( xv->widget), "button-release-event", + G_CALLBACK (xwidget_osr_button_callback), NULL); + g_signal_connect (G_OBJECT ( xv->widget), "motion-notify-event", + G_CALLBACK (xwidget_osr_button_callback), NULL); + /* g_signal_connect (G_OBJECT ( xv->widget), "key-press-event", */ + /* G_CALLBACK (xwidget_osr_button_callback), NULL); */ + /* g_signal_connect (G_OBJECT ( xv->widget), "key-release-event", */ + /* G_CALLBACK (xwidget_osr_button_callback), NULL); */ + +#endif + + + } else return NULL; + + //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 + //other containers than gtk_fixed where explored, but gtk_fixed had the most predictable behaviour so far. + xv->emacswindow = GTK_CONTAINER (FRAME_GTK_WIDGET (s->f)); + xv->widgetwindow = GTK_CONTAINER (gtk_fixed_new ()); + gtk_widget_set_has_window(GTK_WIDGET ( xv->widgetwindow), TRUE); + gtk_container_add (xv->widgetwindow, xv->widget); + + //store some xwidget data in the gtk widgets + g_object_set_data (G_OBJECT (xv->widget), XG_FRAME_DATA, (gpointer) (s->f)); //the emacs frame + g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET, (gpointer) (xww)); //the xwidget + g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET_VIEW, (gpointer) (xv)); //the xwidget + g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET, (gpointer) (xww)); //the xwidget window + g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET_VIEW, (gpointer) (xv)); //the xwidget window + + + gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xww->width, xww->height); + gtk_widget_set_size_request (GTK_WIDGET (xv->widgetwindow), xww->width, xww->height); + gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), GTK_WIDGET (xv->widgetwindow), x, y); + xv->x = x; xv->y = y; + gtk_widget_show_all (GTK_WIDGET (xv->widgetwindow)); + + //widgettype specific initialization only possible after realization + if (EQ(xww->type, Qsocket)) { + printf ("xwid:%d socket id:%x %d\n", + xww, + gtk_socket_get_id (GTK_SOCKET (xv->widget)), + gtk_socket_get_id (GTK_SOCKET (xv->widget))); + send_xembed_ready_event (xww, + gtk_socket_get_id (GTK_SOCKET (xv->widget))); + //gtk_widget_realize(xw->widget); + } + return xv; +} + + +void +x_draw_xwidget_glyph_string (struct glyph_string *s) +{ + /* + this method is called by the redisplay engine and places the xwidget on screen. + moving and clipping is done here. also view init. + + */ + 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; + struct xwidget *xww = s->xwidget; + struct xwidget_view *xv = xwidget_view_lookup(xww, (s->w)); + int clip_right; int clip_bottom; int clip_top; int clip_left; + + int x = s->x; + int y = s->y + (s->height / 2) - (xww->height / 2); + int moved=0; + + if (xv == NULL || xv->initialized == 0){ + /* Views must be initialized once(only once). + We do it here in the display loop because there is no other time to know things like + window placement etc. + */ + printf ("xv init for xw %d\n", xww); + xv = xwidget_init_view (xww, s, x, y); + } + + //calculate clipping, which is used for all manner of onscreen xwidget views + //each widget border can get clipped by other emacs objects so there are four clipping variables + clip_right = min (xww->width, WINDOW_RIGHT_EDGE_X (s->w) - x - WINDOW_RIGHT_SCROLL_BAR_AREA_WIDTH(s->w) - WINDOW_RIGHT_FRINGE_WIDTH(s->w)); + clip_left = max (0, WINDOW_LEFT_EDGE_X (s->w) - x + WINDOW_LEFT_SCROLL_BAR_AREA_WIDTH(s->w) + WINDOW_LEFT_FRINGE_WIDTH(s->w)); + + clip_bottom = min (xww->height, WINDOW_BOTTOM_EDGE_Y (s->w) - WINDOW_MODE_LINE_HEIGHT (s->w) - y); + clip_top = max(0, WINDOW_TOP_EDGE_Y(s->w) -y ); + + //we are conserned with movement of the onscreen area. the area might sit still when the widget actually moves + //this happens when an emacs window border moves across a widget window + //so, if any corner of the outer widget clippng window moves, that counts as movement here, even + //if it looks like no movement happens because the widget sits still inside the clipping area. + //the widget can also move inside the clipping area, which happens later + moved = (xv->x + xv->clip_left != x+clip_left) + || ((xv->y + xv->clip_top)!= (y+clip_top)); + if(moved) printf ("lxwidget moved: id:%d (%d,%d)->(%d,%d) y+clip_top:%d\n", xww, xv->x, xv->y, x, y, y + clip_top); + else + printf ("lxwidget DIDNT move: id:%d (%d,%d)->(%d,%d) y+clip_top:%d\n", xww, xv->x, xv->y, x, y, y + clip_top); + xv->x = x; + xv->y = y; + if (moved) //has it moved? + { + if (1)//!xwidget_hidden(xv)) //hidden equals not being seen during redisplay + { + //TODO should be possible to use xwidget_show_view here + gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), + GTK_WIDGET (xv->widgetwindow), + x + clip_left, y + clip_top); + } + } + //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((xv->clip_right != clip_right) + || (xv->clip_bottom != clip_bottom) + || (xv->clip_top != clip_top) + || (xv->clip_left != clip_left)){ + gtk_widget_set_size_request (GTK_WIDGET (xv->widgetwindow), clip_right + clip_left, clip_bottom + clip_top); + gtk_fixed_move(GTK_FIXED(xv->widgetwindow), xv->widget, -clip_left, -clip_top); + printf("reclip %d %d -> %d %d clip_top:%d clip_left:%d\n",xv->clip_right, xv->clip_bottom, clip_right, clip_bottom, clip_top , clip_left); + + + xv->clip_right = clip_right; xv->clip_bottom = clip_bottom; xv->clip_top = clip_top;xv->clip_left = clip_left; + } + //if emacs wants to repaint the area where the widget lives, queue a redraw + //TODO it seems its possible to get out of sync with emacs redraws so emacs bg sometimes shows up instead of xwidget + //its just a visual glitch though + if (!xwidget_hidden(xv)){ + gtk_widget_queue_draw (GTK_WIDGET(xv->widgetwindow)); + gtk_widget_queue_draw (xv->widget); + } +} + + +#ifdef HAVE_WEBKIT_OSR +DEFUN ("xwidget-webkit-goto-uri", Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri, 2, 2, 0, + doc: /* webkit goto uri.*/ + ) + (Lisp_Object xwidget, Lisp_Object uri) +{ + struct xwidget* xw = XXWIDGET(xwidget); + webkit_web_view_load_uri ( WEBKIT_WEB_VIEW(xw->widget_osr), SDATA(uri)); + return Qnil; +} + +DEFUN ("xwidget-webkit-execute-script", Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script, 2, 2, 0, + doc: /* webkit exec js.*/ + ) + (Lisp_Object xwidget, Lisp_Object script) +{ + struct xwidget* xw = XXWIDGET(xwidget); + webkit_web_view_execute_script( WEBKIT_WEB_VIEW(xw->widget_osr), SDATA(script)); + return Qnil; +} + +DEFUN ("xwidget-webkit-get-title", Fxwidget_webkit_get_title, Sxwidget_webkit_get_title, 1, 1, 0, + doc: /* webkit get title. can be used to work around exec method lacks return val*/ + ) + (Lisp_Object xwidget) +{ + //TODO support multibyte strings + struct xwidget* xw = XXWIDGET(xwidget); + const gchar* str=webkit_web_view_get_title( WEBKIT_WEB_VIEW(xw->widget_osr)); + //return make_string_from_bytes(str, wcslen((const wchar_t *)str), strlen(str)); + if(str == 0){ + //TODO maybe return Qnil instead. I suppose webkit returns nullpointer when doc is not properly loaded or something + printf("xwidget-webkit-get-title null webkit title\n"); + return build_string(""); + } + return build_string(str); +} + +//TODO missnamed +DEFUN("xwidget-disable-plugin-for-mime", Fxwidget_disable_plugin_for_mime , Sxwidget_disable_plugin_for_mime, 1,1,0, doc: /* */) + (Lisp_Object mime) +{ + WebKitWebPlugin *wp = webkit_web_plugin_database_get_plugin_for_mimetype + (webkit_get_web_plugin_database(), SDATA(mime)); + if(wp == NULL) return Qnil; + if(webkit_web_plugin_get_enabled (wp)){ + webkit_web_plugin_set_enabled (wp, FALSE); + return Qt; + } + return Qnil; +} + + +//attempting a workaround for a webkit offscreen bug +//TODO verify its still needed +void gtk_window_get_position (GtkWindow *window, + gint *root_x, + gint *root_y){ + printf("my getsize\n"); + *root_x = 0; + *root_y = 0; +} + +void +xwidget_webkit_dom_dump(WebKitDOMNode* parent){ + WebKitDOMNodeList* list; + int i; + int length; + WebKitDOMNode* attribute; + WebKitDOMNamedNodeMap* attrs; + WebKitDOMNode* child; + printf("node:%d type:%d name:%s content:%s\n", + parent, + webkit_dom_node_get_node_type(parent),//1 element 3 text 8 comment 2 attribute + webkit_dom_node_get_local_name(parent), + webkit_dom_node_get_text_content(parent)); + + if(webkit_dom_node_has_attributes(parent)){ + attrs = webkit_dom_node_get_attributes(parent); + + length = webkit_dom_named_node_map_get_length(attrs); + for (int i = 0; i < length; i++) { + attribute = webkit_dom_named_node_map_item(attrs,i); + printf(" attr node:%d type:%d name:%s content:%s\n", + attribute, + webkit_dom_node_get_node_type(attribute),//1 element 3 text 8 comment + webkit_dom_node_get_local_name(attribute), + webkit_dom_node_get_text_content(attribute)); + } + } + list = webkit_dom_node_get_child_nodes(parent); + length = webkit_dom_node_list_get_length(list); + + for (int i = 0; i < length; i++) { + child = webkit_dom_node_list_item(list, i); + //if(webkit_dom_node_has_child_nodes(child)) + xwidget_webkit_dom_dump(child); + } +} + + +DEFUN ("xwidget-webkit-dom-dump", Fxwidget_webkit_dom_dump, Sxwidget_webkit_dom_dump, 1, 1, 0, + doc: /* webkit dom dump*/ + ) + (Lisp_Object xwidget) +{ + struct xwidget* xw = XXWIDGET(xwidget); + xwidget_webkit_dom_dump(WEBKIT_DOM_NODE(webkit_web_view_get_dom_document( WEBKIT_WEB_VIEW(xw->widget_osr)))); + return Qnil; +} + + + +#endif + + + + + +DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0, doc: + /* resize xwidgets*/) + (Lisp_Object xwidget, Lisp_Object new_width, Lisp_Object new_height) +{ + struct xwidget* xw = XXWIDGET(xwidget); + struct xwidget_view *xv; + int w, h; + + CHECK_NUMBER (new_width); + CHECK_NUMBER (new_height); + w = XFASTINT (new_width); + h = XFASTINT (new_height); + + + printf("resize xwidget %d (%d,%d)->(%d,%d)",xw, xw->width,xw->height,w,h); + xw->width=w; + xw->height=h; + //if theres a osr resize it 1st + if(xw->widget_osr){ + gtk_layout_set_size (GTK_LAYOUT (xw->widgetwindow_osr), xw->width, xw->height); + gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, xw->height); + } + + for (int i = 0; i < MAX_XWIDGETS; i++) //TODO MVC refactor lazy linear search + { + xv = &xwidget_views[i]; + if(xv->initialized && xv->model == xw){ + gtk_layout_set_size (GTK_LAYOUT (xv->widgetwindow), xw->width, xw->height); + gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width, xw->height); + } + } + + return Qnil; +} + +DEFUN ("xwidget-size-request", Fxwidget_size_request, Sxwidget_size_request, 1, 1, 0, doc: + /* desired size (TODO crashes if arg not osr widget)*/) + (Lisp_Object xwidget) +{ + GtkRequisition requisition; + Lisp_Object rv; + gtk_widget_size_request(XXWIDGET(xwidget)->widget_osr, &requisition); + rv = Qnil; + rv = Fcons (make_number(requisition.height), rv); + rv = Fcons (make_number(requisition.width), rv); + return rv; + +} + +DEFUN ("xwidgetp", Fxwidgetp, Sxwidgetp, 1, 1, 0, + doc: /* Return t if OBJECT is a xwidget. */) + (Lisp_Object object) +{ + return XWIDGETP (object) ? Qt : Qnil; +} + +DEFUN("xwidget-info", Fxwidget_info , Sxwidget_info, 1,1,0, doc: /* get xwidget props */) + (Lisp_Object xwidget) +{ + Lisp_Object info; + struct xwidget* xw = XXWIDGET(xwidget); + + info = Fmake_vector (make_number (4), Qnil); + XSETSYMBOL (XVECTOR (info)->contents[0], xw->type); + XSETSTRING (XVECTOR (info)->contents[1], xw->title); + XSETINT (XVECTOR (info)->contents[2], xw->width); + XSETINT (XVECTOR (info)->contents[3], xw->height); + + + return info; +} + + +DEFUN("xwidget-view-info", Fxwidget_view_info , Sxwidget_view_info, 2,2,0, doc: /* get xwidget view props */) + (Lisp_Object xwidget, Lisp_Object window) +{ + struct xwidget* xw = XXWIDGET(xwidget); + struct xwidget_view* xv = xwidget_view_lookup(xw, XWINDOW(window)); + + Lisp_Object info; + + info = Fmake_vector (make_number (6), Qnil); + XVECTOR (info)->contents[0] = make_number(xv->x); + XVECTOR (info)->contents[1] = make_number(xv->y); + XVECTOR (info)->contents[2] = make_number(xv->clip_right); + XVECTOR (info)->contents[3] = make_number(xv->clip_bottom); + XVECTOR (info)->contents[4] = make_number(xv->clip_top); + XVECTOR (info)->contents[5] = make_number(xv->clip_left); + + return info; +} + +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, Lisp_Object keydescriptor) +{ + //TODO this code crashes for offscreen widgets and ive tried many different strategies + //int keyval = 0x058; //X + int keyval = XFASTINT(keydescriptor); //X + char *keystring = ""; + GdkKeymapKey* keys; + gint n_keys; + GdkDeviceManager* manager; + struct xwidget *xw; + GtkWidget* widget; + GdkEventKey* ev; + Lisp_Object window; + //popup_activated_flag = 1; //TODO just a hack + gdk_keymap_get_entries_for_keyval(gdk_keymap_get_default(), keyval, &keys, &n_keys); + + xw = XXWIDGET(xwidget); + + ev = (GdkEventKey*)gdk_event_new(GDK_KEY_PRESS); + + + //todo what about windowless widgets? + + window = FRAME_SELECTED_WINDOW (SELECTED_FRAME ()); + + + //TODO maybe we also need to special case sockets by picking up the plug rather than the socket + if(xw->widget_osr) + widget = xw->widget_osr; + else + widget = xwidget_view_lookup(xw, XWINDOW(window))->widget; + + ev->window = gtk_widget_get_window(widget); + gtk_widget_grab_focus(widget); + ev->send_event = FALSE; + + ev->hardware_keycode = keys[0].keycode; + ev->group = keys[0].group; + + ev->keyval = keyval; + ev->time = GDK_CURRENT_TIME; + + //ev->device = gdk_device_get_core_pointer(); + manager = gdk_display_get_device_manager(gdk_window_get_display(ev->window)); + gdk_event_set_device ((GdkEvent*)ev, gdk_device_manager_get_client_pointer(manager)); + gdk_event_put((GdkEvent*)ev); + //g_signal_emit_by_name(ev->window,"key-press-event", ev); + + ev->type = GDK_KEY_RELEASE; + gdk_event_put((GdkEvent*)ev); + //g_signal_emit_by_name(ev->window,"key-release-event", ev); + //gtk_main_do_event(ev); + + //TODO + //if I delete the event the receiving component eventually crashes. + //it ough TDTRT since event_put is supposed to copy the event + //so probably this leaks events now + //gdk_event_free((GdkEvent*)ev); + + return Qnil; +} + + + +DEFUN("xwidget-delete-zombies", Fxwidget_delete_zombies , Sxwidget_delete_zombies, 0,0,0, doc: /* */) + (void) +{ + /* + - remove all views with window gone + + TODO + - remove all xwidgets with buffer gone + - remove all views with xw gone + + */ + struct xwidget_view* xv = NULL; + Lisp_Object w; + for (int i = 0; i < MAX_XWIDGETS; i++){ + xv = &xwidget_views[i]; + XSETWINDOW(w, xv->w); + if(xv->initialized && (! (WINDOW_LIVE_P(w)))){ + + gtk_widget_destroy(GTK_WIDGET(xv->widgetwindow)); + xv->initialized = 0; + } + } +} + + +DEFUN ("xwidget-plist", Fxwidget_plist, Sxwidget_plist, + 1, 1, 0, + doc: /* Return the plist of XWIDGET. */) + (register Lisp_Object xwidget) +{ + //CHECK_XWIDGET (xwidget); //todo + return XXWIDGET (xwidget)->plist; +} + +DEFUN ("xwidget-buffer", Fxwidget_buffer, Sxwidget_buffer, + 1, 1, 0, + doc: /* Return the buffer of XWIDGET. */) + (register Lisp_Object xwidget) +{ + //CHECK_XWIDGET (xwidget); //todo + return XXWIDGET (xwidget)->buffer; +} + +DEFUN ("set-xwidget-plist", Fset_xwidget_plist, Sset_xwidget_plist, + 2, 2, 0, + doc: /* Replace the plist of XWIDGET with PLIST. Returns PLIST. */) + (register Lisp_Object xwidget, Lisp_Object plist) +{ + //CHECK_XWIDGET (xwidget); //todo + CHECK_LIST (plist); + + XXWIDGET (xwidget)->plist = plist; + return plist; +} + + + +void +syms_of_xwidget (void) +{ + int i; + + defsubr (&Smake_xwidget); + defsubr (&Sxwidgetp); + defsubr (&Sxwidget_info); + defsubr (&Sxwidget_view_info); + defsubr (&Sxwidget_resize); + +#ifdef HAVE_WEBKIT_OSR + defsubr (&Sxwidget_webkit_goto_uri); + defsubr (&Sxwidget_webkit_execute_script); + defsubr (&Sxwidget_webkit_get_title); + DEFSYM (Qwebkit_osr ,"webkit-osr"); +#endif + + defsubr (&Sxwidget_size_request ); + defsubr (&Sxwidget_delete_zombies); + defsubr (&Sxwidget_disable_plugin_for_mime); + + defsubr (&Sxwidget_send_keyboard_event); + defsubr (&Sxwidget_webkit_dom_dump); + defsubr (&Sxwidget_plist); + defsubr (&Sxwidget_buffer); + defsubr (&Sset_xwidget_plist); + + DEFSYM (Qxwidget ,"xwidget"); + + DEFSYM (Qcxwidget ,":xwidget"); + DEFSYM (Qtitle ,":title"); + + DEFSYM (Qbutton, "button"); + DEFSYM (Qtoggle, "toggle"); + DEFSYM (Qslider, "slider"); + DEFSYM (Qsocket, "socket"); + DEFSYM (Qsocket_osr, "socket-osr"); + DEFSYM (Qcairo, "cairo"); + + DEFSYM (QCplist, ":plist"); + + DEFVAR_LISP ("xwidget-alist", Vxwidget_alist, doc: /*xwidgets list*/); + Vxwidget_alist = Qnil; + DEFVAR_LISP ("xwidget-view-alist", Vxwidget_view_alist, doc: /*xwidget views list*/); + Vxwidget_alist = Qnil; + + 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; +} + + + +/* find a value associated with key in spec */ +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 xwidget_view_delete_all_in_window( struct window *w ) +{ + struct xwidget_view* xv = NULL; + for (int i = 0; i < MAX_XWIDGETS; i++){ + xv = &xwidget_views[i]; + if(xv->initialized && xv->w == w){ + gtk_widget_destroy(GTK_WIDGET(xv->widgetwindow)); + xv->initialized = 0; + } + } +} + + + +struct xwidget_view* xwidget_view_lookup(struct xwidget* xw, struct window *w){ + struct xwidget_view* xv = NULL; + for (int i = 0; i < MAX_XWIDGETS; i++){ + xv = &xwidget_views[i]; + if (xv->initialized && (xv->model == xw) && (xv->w == w)) + return xv; + } +} + +struct xwidget* +lookup_xwidget (Lisp_Object spec) +{ + /* When a xwidget lisp spec is found initialize the C struct that is used in the C code. + This is done by redisplay so values change if the spec changes. + So, take special care of one-shot events + + TODO remove xwidget init from display spec. simply store an xwidget reference only and set + size etc when creating the xwidget, which should happen before insertion into buffer + */ + int found = 0, found1 = 0, found2 = 0; + Lisp_Object value; + struct xwidget *xw; + + value = xwidget_spec_value (spec, Qcxwidget, &found1); + xw = XXWIDGET(value); + + /* value = xwidget_spec_value (spec, QCtype, &found); */ + /* xw->type = SYMBOLP (value) ? value : Qbutton; //default to button */ + /* value = xwidget_spec_value (spec, Qtitle, &found2); */ + /* xw->title = STRINGP (value) ? (char *) SDATA (value) : "?"; //funky cast FIXME TODO */ + + /* value = xwidget_spec_value (spec, QCheight, NULL); */ + /* xw->height = INTEGERP (value) ? XFASTINT (value) : 50; */ + /* value = xwidget_spec_value (spec, QCwidth, NULL); */ + /* xw->width = INTEGERP (value) ? XFASTINT (value) : 50; */ + + /* value = xwidget_spec_value (spec, QCplist, NULL); */ + /* xw->plist = value; */ + /* coordinates are not known here */ + printf ("lookup_xwidget xwidget_id:%d type:%d found:%d %d %d title:'%s' (%d,%d)\n", xw, + xw->type, found, found1, found2, xw->title, xw->height, xw->width); + + //assert_valid_xwidget_id (id, "lookup_xwidget"); + return xw; +} + +/*set up detection of touched xwidget*/ +void +xwidget_start_redisplay (void) +{ + int i; + for (i = 0; i < MAX_XWIDGETS; i++) + xwidget_views[i].redisplayed = 0; + +} + +/* the xwidget was touched during redisplay, so it isnt a candidate for hiding*/ +void +xwidget_touch (struct xwidget_view *xv) +{ + xv->redisplayed = 1; +} + +int +xwidget_touched (struct xwidget_view *xv) +{ + return xv->redisplayed; +} + +/* redisplay has ended, now we should hide untouched xwidgets +*/ +void +xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix) +{ + + int i; + struct xwidget *xw; + int area; + + + xwidget_start_redisplay (); + //iterate desired glyph matrix of window here, hide gtk widgets + //not in the desired matrix. + + //this only takes care of xwidgets in active windows. + //if a window goes away from screen xwidget views wust be deleted + + // 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) + { + /* + the only call to xwidget_end_redisplay is in dispnew + xwidget_end_redisplay(w->current_matrix); + */ + xwidget_touch (xwidget_view_lookup(glyph->u.xwidget, + w)); + } + } + } + } + } + + for (i = 0; i < MAX_XWIDGETS; i++) + { + struct xwidget_view* xv = &xwidget_views[i]; + + //"touched" is only meaningful for the current window, so disregard other views + if (xv->initialized && ( xv->w == w)) + { + if (xwidget_touched(xv)) + xwidget_show_view (xv); + else + xwidget_hide_view (xv); + } + } +} diff --git a/src/xwidget.h b/src/xwidget.h new file mode 100644 index 00000000000..e5cfe6de902 --- /dev/null +++ b/src/xwidget.h @@ -0,0 +1,110 @@ +#ifndef XWIDGET_H_INCLUDED +#define XWIDGET_H_INCLUDED + +void x_draw_xwidget_glyph_string (struct glyph_string *s); +void syms_of_xwidget (); + +extern Lisp_Object Qxwidget; + + +int valid_xwidget_p (Lisp_Object object) ; + +#include <gtk/gtk.h> + + +/* +each xwidget instance/model is described by this struct. + +lisp pseudovector. + + + */ +struct xwidget{ + struct vectorlike_header header; + Lisp_Object plist;//auxilliary data + Lisp_Object type;//the widget type + Lisp_Object buffer; //buffer where xwidget lives + Lisp_Object title;//a title that is used for button labels for instance + + //here ends the lisp part. + //"height" is the marker field + int height; + int width; + + //for offscreen widgets, unused if not osr + GtkWidget* widget_osr; + GtkContainer* widgetwindow_osr; + + //TODO these are WIP + + + +}; + + +//struct for each xwidget view +struct xwidget_view{ + struct vectorlike_header header; + struct xwidget* model; //TODO should be lisp + + + //here ends the lisp part. + //"redisplayed" is the marker field + int redisplayed; //if touched by redisplay + + + struct window *w; //TODO should be lisp + + int hidden;//if the "live" instance isnt drawn + + int initialized; + + GtkWidget* widget; + GtkContainer* widgetwindow; + GtkContainer* emacswindow; + int x; int y; + int clip_right; int clip_bottom; int clip_top; int clip_left; + + + long handler_id; +}; + + +/* Test for xwidget (xwidget . spec) (car must be the symbol xwidget)*/ +#define XWIDGETP(x) (CONSP (x) && EQ (XCAR (x), Qxwidget)) +/* Test for xwidget pseudovector*/ +#define XXWIDGETP(x) PSEUDOVECTORP (x, PVEC_XWIDGET) +#define XXWIDGET(a) (eassert (XWIDGETP(a)),(struct xwidget *) XPNTR(a)) + + +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 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 window *w, struct glyph_matrix *matrix); + +void xwidget_touch (struct xwidget_view *xw); + +//void assert_valid_xwidget_id(int id,char *str); + +struct xwidget* lookup_xwidget (Lisp_Object spec); +#define XG_XWIDGET "emacs_xwidget" +#define XG_XWIDGET_VIEW "emacs_xwidget_view" +void xwidget_view_delete_all_in_window( struct window *w ); +#endif |