summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2016-01-30 11:27:34 -0800
committerPaul Eggert <eggert@cs.ucla.edu>2016-01-30 11:27:34 -0800
commit82b089783e71b2aeef950eaecfe4cbc0735e64a2 (patch)
treea826c20768071bda95a69b2632718c1641c6d0cc /src
parentd27c8078ef766dae3587bc82b70128a70efaa223 (diff)
parentf7dc6d8b5bb318e02a4016d93f8b34de0716f4dc (diff)
downloademacs-82b089783e71b2aeef950eaecfe4cbc0735e64a2.tar.gz
emacs-82b089783e71b2aeef950eaecfe4cbc0735e64a2.tar.bz2
emacs-82b089783e71b2aeef950eaecfe4cbc0735e64a2.zip
-
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in9
-rw-r--r--src/buffer.c6
-rw-r--r--src/dispextern.h28
-rw-r--r--src/dispnew.c12
-rw-r--r--src/emacs.c6
-rw-r--r--src/emacsgtkfixed.c123
-rw-r--r--src/emacsgtkfixed.h20
-rw-r--r--src/keyboard.c18
-rw-r--r--src/lisp.h6
-rw-r--r--src/print.c16
-rw-r--r--src/termhooks.h5
-rw-r--r--src/window.c6
-rw-r--r--src/xdisp.c248
-rw-r--r--src/xterm.c14
-rw-r--r--src/xwidget.c1320
-rw-r--r--src/xwidget.h132
16 files changed, 1945 insertions, 24 deletions
diff --git a/src/Makefile.in b/src/Makefile.in
index defce62c529..b38e7d558b8 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -152,6 +152,9 @@ DBUS_LIBS = @DBUS_LIBS@
## dbusbind.o if HAVE_DBUS, else empty.
DBUS_OBJ = @DBUS_OBJ@
+## xwidgets.o if HAVE_XWIDGETS, else empty.
+XWIDGETS_OBJ = @XWIDGETS_OBJ@
+
LIB_EXECINFO=@LIB_EXECINFO@
SETTINGS_CFLAGS = @SETTINGS_CFLAGS@
@@ -220,6 +223,9 @@ CFLAGS_SOUND= @CFLAGS_SOUND@
RSVG_LIBS= @RSVG_LIBS@
RSVG_CFLAGS= @RSVG_CFLAGS@
+WEBKIT_LIBS= @WEBKIT_LIBS@
+WEBKIT_CFLAGS= @WEBKIT_CFLAGS@
+
CAIRO_LIBS= @CAIRO_LIBS@
CAIRO_CFLAGS= @CAIRO_CFLAGS@
@@ -359,6 +365,7 @@ ALL_CFLAGS=-Demacs $(MYCPPFLAGS) -I. -I$(srcdir) \
$(GNUSTEP_CFLAGS) $(CFLAGS_SOUND) $(RSVG_CFLAGS) $(IMAGEMAGICK_CFLAGS) \
$(PNG_CFLAGS) $(LIBXML2_CFLAGS) $(DBUS_CFLAGS) \
$(XRANDR_CFLAGS) $(XINERAMA_CFLAGS) $(XFIXES_CFLAGS) \
+ $(WEBKIT_CFLAGS) \
$(SETTINGS_CFLAGS) $(FREETYPE_CFLAGS) $(FONTCONFIG_CFLAGS) \
$(LIBOTF_CFLAGS) $(M17N_FLT_CFLAGS) $(DEPFLAGS) \
$(LIBGNUTLS_CFLAGS) $(NOTIFY_CFLAGS) $(CAIRO_CFLAGS) \
@@ -388,6 +395,7 @@ 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 $(NOTIFY_OBJ) \
+ $(XWIDGETS_OBJ) \
profiler.o decompress.o \
$(MSDOS_OBJ) $(MSDOS_X_OBJ) $(NS_OBJ) $(CYGWIN_OBJ) $(FONT_OBJ) \
$(W32_OBJ) $(WINDOW_SYSTEM_OBJ) $(XGSELOBJ)
@@ -468,6 +476,7 @@ lisp = $(addprefix ${lispsource}/,${shortlisp})
LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(LIBX_BASE) $(LIBIMAGE) \
$(LIBX_OTHER) $(LIBSOUND) \
$(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_ACL) $(LIB_CLOCK_GETTIME) \
+ $(WEBKIT_LIBS) \
$(LIB_EACCESS) $(LIB_FDATASYNC) $(LIB_TIMER_TIME) $(DBUS_LIBS) \
$(LIB_EXECINFO) $(XRANDR_LIBS) $(XINERAMA_LIBS) $(XFIXES_LIBS) \
$(LIBXML2_LIBS) $(LIBGPM) $(LIBRESOLV) $(LIBS_SYSTEM) $(CAIRO_LIBS) \
diff --git a/src/buffer.c b/src/buffer.c
index 4df77a181d6..51bbad78bbc 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -43,6 +43,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include "keymap.h"
#include "frame.h"
+#ifdef HAVE_XWIDGETS
+# include "xwidget.h"
+#endif
#ifdef WINDOWSNT
#include "w32heap.h" /* for mmap_* */
#endif
@@ -1747,6 +1750,9 @@ cleaning up all windows currently displaying the buffer to be killed. */)
kill_buffer_processes (buffer);
+#ifdef HAVE_XWIDGETS
+ kill_buffer_xwidgets (buffer);
+#endif
/* Killing buffer processes may run sentinels which may have killed
our buffer. */
if (!BUFFER_LIVE_P (b))
diff --git a/src/dispextern.h b/src/dispextern.h
index bb876f5af70..fad5bfd6f2f 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -348,6 +348,10 @@ enum glyph_type
/* Glyph is a space of fractional width and/or height. */
STRETCH_GLYPH
+#ifdef HAVE_XWIDGETS
+ /* Glyph is an external widget drawn by the GUI toolkit. */
+ ,XWIDGET_GLYPH
+#endif
};
@@ -499,6 +503,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
{
@@ -1350,6 +1357,9 @@ struct glyph_string
/* Image, if any. */
struct image *img;
+#ifdef HAVE_XWIDGETS
+ struct xwidget *xwidget;
+#endif
/* Slice */
struct glyph_slice slice;
@@ -2102,6 +2112,10 @@ enum display_element_type
/* Continuation glyphs. See the comment for IT_TRUNCATION. */
IT_CONTINUATION
+
+#ifdef HAVE_XWIDGETS
+ ,IT_XWIDGET
+#endif
};
@@ -2165,6 +2179,9 @@ enum it_method {
GET_FROM_C_STRING,
GET_FROM_IMAGE,
GET_FROM_STRETCH,
+#ifdef HAVE_XWIDGETS
+ GET_FROM_XWIDGET,
+#endif
NUM_IT_METHODS
};
@@ -2382,6 +2399,12 @@ struct it
struct {
Lisp_Object object;
} stretch;
+#ifdef HAVE_XWIDGETS
+ /* method == GET_FROM_XWIDGET */
+ struct {
+ Lisp_Object object;
+ } xwidget;
+#endif
} u;
/* Current text and display positions. */
@@ -2506,6 +2529,11 @@ 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 8d671f82e47..32c0dff9b92 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -44,6 +44,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include TERM_HEADER
#endif /* HAVE_WINDOW_SYSTEM */
+#ifdef HAVE_XWIDGETS
+# include "xwidget.h"
+#endif
+
#include <errno.h>
#include <fpending.h>
@@ -3543,6 +3547,9 @@ update_window (struct window *w, bool 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;
@@ -4116,6 +4123,11 @@ scrolling_window (struct window *w, bool header_line_p)
break;
}
+#ifdef HAVE_XWIDGETS
+ /* Currently this seems needed to detect xwidget movement reliably. */
+ return 0;
+#endif
+
/* Give up if some rows in the desired matrix are not enabled. */
if (! MATRIX_ROW_ENABLED_P (desired_matrix, i))
return -1;
diff --git a/src/emacs.c b/src/emacs.c
index aaf058e4a80..fcf048ca84b 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -66,6 +66,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 "atimer.h"
#include "blockinput.h"
#include "syssignal.h"
@@ -1492,6 +1495,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 cdcaf803ba5..08b840389c5 100644
--- a/src/emacsgtkfixed.c
+++ b/src/emacsgtkfixed.c
@@ -23,6 +23,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
#include "emacsgtkfixed.h"
/* Silence a bogus diagnostic; see GNOME bug 683906. */
@@ -31,27 +34,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
# pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#endif
-#define EMACS_TYPE_FIXED emacs_fixed_get_type ()
-#define EMACS_FIXED(obj) \
- G_TYPE_CHECK_INSTANCE_CAST (obj, EMACS_TYPE_FIXED, EmacsFixed)
-
typedef struct _EmacsFixed EmacsFixed;
typedef struct _EmacsFixedPrivate EmacsFixedPrivate;
typedef struct _EmacsFixedClass EmacsFixedClass;
-struct _EmacsFixed
-{
- GtkFixed container;
-
- /*< private >*/
- EmacsFixedPrivate *priv;
-};
-
-struct _EmacsFixedClass
-{
- GtkFixedClass parent_class;
-};
-
struct _EmacsFixedPrivate
{
struct frame *f;
@@ -64,9 +50,103 @@ static void emacs_fixed_get_preferred_width (GtkWidget *widget,
static void emacs_fixed_get_preferred_height (GtkWidget *widget,
gint *minimum,
gint *natural);
+
static GType emacs_fixed_get_type (void);
G_DEFINE_TYPE (EmacsFixed, emacs_fixed, GTK_TYPE_FIXED)
+static EmacsFixed *
+EMACS_FIXED (GtkWidget *widget)
+{
+ return G_TYPE_CHECK_INSTANCE_CAST (widget, emacs_fixed_get_type (),
+ EmacsFixed);
+}
+
+#ifdef HAVE_XWIDGETS
+
+static EmacsFixedClass *
+EMACS_FIXED_GET_CLASS (GtkWidget *widget)
+{
+ return G_TYPE_INSTANCE_GET_CLASS (widget, emacs_fixed_get_type (),
+ EmacsFixedClass);
+}
+
+struct GtkFixedPrivateL
+{
+ GList *children;
+};
+
+static void emacs_fixed_gtk_widget_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ // For xwidgets.
+
+ // This basically re-implements the base class method and adds an
+ // additional case for an xwidget view.
+
+ // It would be nicer if the bse class method could be called first,
+ // and the the xview modification only would remain here. It wasn't
+ // possible to solve it that way yet.
+ EmacsFixedClass *klass;
+ GtkWidgetClass *parent_class;
+ struct GtkFixedPrivateL* priv;
+
+ 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);
+
+ 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 (GList *children = priv->children; children; children = children->next)
+ {
+ GtkFixedChild *child = children->data;
+
+ if (!gtk_widget_get_visible (child->widget))
+ continue;
+
+ GtkRequisition child_requisition;
+ gtk_widget_get_preferred_size (child->widget, &child_requisition, NULL);
+
+ GtkAllocation child_allocation;
+ 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;
+
+ struct xwidget_view *xv
+ = g_object_get_data (G_OBJECT (child->widget), XG_XWIDGET_VIEW);
+ if (xv)
+ {
+ child_allocation.width = xv->clip_right;
+ child_allocation.height = xv->clip_bottom - xv->clip_top;
+ }
+
+ gtk_widget_size_allocate (child->widget, &child_allocation);
+ }
+}
+
+#endif /* HAVE_XWIDGETS */
+
static void
emacs_fixed_class_init (EmacsFixedClass *klass)
{
@@ -74,15 +154,20 @@ emacs_fixed_class_init (EmacsFixedClass *klass)
widget_class = (GtkWidgetClass*) 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));
}
+
static void
emacs_fixed_init (EmacsFixed *fixed)
{
- fixed->priv = G_TYPE_INSTANCE_GET_PRIVATE (fixed, EMACS_TYPE_FIXED,
+ fixed->priv = G_TYPE_INSTANCE_GET_PRIVATE (fixed, emacs_fixed_get_type (),
EmacsFixedPrivate);
fixed->priv->f = 0;
}
@@ -97,7 +182,7 @@ emacs_fixed_init (EmacsFixed *fixed)
GtkWidget*
emacs_fixed_new (struct frame *f)
{
- EmacsFixed *fixed = g_object_new (EMACS_TYPE_FIXED, NULL);
+ EmacsFixed *fixed = g_object_new (emacs_fixed_get_type (), NULL);
EmacsFixedPrivate *priv = fixed->priv;
priv->f = f;
return GTK_WIDGET (fixed);
diff --git a/src/emacsgtkfixed.h b/src/emacsgtkfixed.h
index 73280b83e57..378bd2b828c 100644
--- a/src/emacsgtkfixed.h
+++ b/src/emacsgtkfixed.h
@@ -27,6 +27,26 @@ struct frame;
G_BEGIN_DECLS
+struct frame;
+
+//typedef struct _EmacsFixed EmacsFixed;
+typedef struct _EmacsFixedPrivate EmacsFixedPrivate;
+typedef struct _EmacsFixedClass EmacsFixedClass;
+
+struct _EmacsFixed
+{
+ GtkFixed container;
+
+ /*< private >*/
+ EmacsFixedPrivate *priv;
+};
+
+
+struct _EmacsFixedClass
+{
+ GtkFixedClass parent_class;
+};
+
extern GtkWidget *emacs_fixed_new (struct frame *f);
G_END_DECLS
diff --git a/src/keyboard.c b/src/keyboard.c
index c8a9728e896..fe503b8ce56 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -4014,6 +4014,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->ie);
+ kbd_fetch_ptr = event + 1;
+ }
+#endif
else if (event->kind == CONFIG_CHANGED_EVENT)
{
obj = make_lispy_event (&event->ie);
@@ -5950,6 +5957,13 @@ make_lispy_event (struct input_event *event)
}
#endif /* HAVE_DBUS */
+#ifdef HAVE_XWIDGETS
+ case XWIDGET_EVENT:
+ {
+ return Fcons (Qxwidget_event,event->arg);
+ }
+#endif
+
#if defined HAVE_INOTIFY || defined HAVE_KQUEUE || defined HAVE_GFILENOTIFY
case FILE_NOTIFY_EVENT:
{
@@ -10956,6 +10970,10 @@ syms_of_keyboard (void)
DEFSYM (Qdbus_event, "dbus-event");
#endif
+#ifdef HAVE_XWIDGETS
+ DEFSYM (Qxwidget_event,"xwidget-event");
+#endif
+
#ifdef USE_FILE_NOTIFY
DEFSYM (Qfile_notify, "file-notify");
#endif /* USE_FILE_NOTIFY */
diff --git a/src/lisp.h b/src/lisp.h
index 02b8078a9fd..8aa034e9e57 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -799,6 +799,12 @@ enum pvec_type
PVEC_WINDOW_CONFIGURATION,
PVEC_SUBR,
PVEC_OTHER,
+
+#ifdef HAVE_XWIDGETS
+ PVEC_XWIDGET,
+ PVEC_XWIDGET_VIEW,
+#endif
+
/* These should be last, check internal_equal to see why. */
PVEC_COMPILED,
PVEC_CHAR_TABLE,
diff --git a/src/print.c b/src/print.c
index 269d8f250e2..4dd4e963093 100644
--- a/src/print.c
+++ b/src/print.c
@@ -33,6 +33,10 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include "intervals.h"
#include "blockinput.h"
+#ifdef HAVE_XWIDGETS
+# include "xwidget.h"
+#endif
+
#include <c-ctype.h>
#include <float.h>
#include <ftoastr.h>
@@ -1736,6 +1740,18 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag)
print_c_string (XSUBR (obj)->symbol_name, printcharfun);
printchar ('>', printcharfun);
}
+#ifdef HAVE_XWIDGETS
+ else if (XWIDGETP (obj))
+ {
+ print_c_string ("#<xwidget ", printcharfun);
+ printchar ('>', printcharfun);
+ }
+ else if (XWIDGET_VIEW_P (obj))
+ {
+ print_c_string ("#<xwidget ", printcharfun);
+ printchar ('>', printcharfun);
+ }
+#endif
else if (WINDOWP (obj))
{
int len = sprintf (buf, "#<window %"pI"d",
diff --git a/src/termhooks.h b/src/termhooks.h
index 29223757621..c183528ee84 100644
--- a/src/termhooks.h
+++ b/src/termhooks.h
@@ -239,6 +239,11 @@ enum event_kind
, NS_NONKEY_EVENT
#endif
+#ifdef HAVE_XWIDGETS
+ /* events generated by xwidgets*/
+ , XWIDGET_EVENT
+#endif
+
#ifdef USE_FILE_NOTIFY
/* File or directory was changed. */
, FILE_NOTIFY_EVENT
diff --git a/src/window.c b/src/window.c
index 4aeb8b39a70..add2de38d18 100644
--- a/src/window.c
+++ b/src/window.c
@@ -41,6 +41,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#ifdef MSDOS
#include "msdos.h"
#endif
+#ifdef HAVE_XWIDGETS
+# include "xwidget.h"
+#endif
static ptrdiff_t count_windows (struct window *);
static ptrdiff_t get_leaf_windows (struct window *, struct window **,
@@ -4368,6 +4371,9 @@ Signal an error 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);
/* If this window is referred to by the dpyinfo's mouse
highlight, invalidate that slot to be safe (Bug#9904). */
diff --git a/src/xdisp.c b/src/xdisp.c
index d730a0bf1b6..89385c0e172 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -318,6 +318,9 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include TERM_HEADER
#endif /* HAVE_WINDOW_SYSTEM */
+#ifdef HAVE_XWIDGETS
+# include "xwidget.h"
+#endif
#ifndef FRAME_X_OUTPUT
#define FRAME_X_OUTPUT(f) ((f)->output_data.x)
#endif
@@ -854,6 +857,9 @@ static bool next_element_from_buffer (struct it *);
static bool next_element_from_composition (struct it *);
static bool next_element_from_image (struct it *);
static bool next_element_from_stretch (struct it *);
+#ifdef HAVE_XWIDGETS
+static bool next_element_from_xwidget (struct it *);
+#endif
static void load_overlay_strings (struct it *, ptrdiff_t);
static bool get_next_display_element (struct it *);
static enum move_it_result
@@ -4690,6 +4696,9 @@ handle_display_spec (struct it *it, Lisp_Object spec, Lisp_Object object,
if (CONSP (spec)
/* Simple specifications. */
&& !EQ (XCAR (spec), Qimage)
+#ifdef HAVE_XWIDGETS
+ && !EQ (XCAR (spec), Qxwidget)
+#endif
&& !EQ (XCAR (spec), Qspace)
&& !EQ (XCAR (spec), Qwhen)
&& !EQ (XCAR (spec), Qslice)
@@ -5137,7 +5146,12 @@ 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
+ || ((it ? FRAME_WINDOW_P (it->f) : frame_window_p)
+ && valid_xwidget_spec_p (value))
+#endif
+ );
if (valid_p && display_replaced == 0)
{
@@ -5212,6 +5226,17 @@ 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 (valid_xwidget_spec_p(value))
+ {
+ it->what = IT_XWIDGET;
+ it->method = GET_FROM_XWIDGET;
+ it->position = start_pos;
+ it->object = NILP (object) ? it->w->contents : object;
+ *position = start_pos;
+ it->xwidget = lookup_xwidget(value);
+ }
+#endif
#ifdef HAVE_WINDOW_SYSTEM
else
{
@@ -5964,6 +5989,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
case GET_FROM_BUFFER:
case GET_FROM_DISPLAY_VECTOR:
case GET_FROM_STRING:
@@ -6065,6 +6095,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;
@@ -6739,7 +6774,10 @@ static next_element_function const get_next_element[NUM_IT_METHODS] =
next_element_from_string,
next_element_from_c_string,
next_element_from_image,
- next_element_from_stretch
+ next_element_from_stretch,
+#ifdef HAVE_XWIDGETS
+ next_element_from_xwidget,
+#endif
};
#define GET_NEXT_DISPLAY_ELEMENT(it) (*get_next_element[(it)->method]) (it)
@@ -7600,6 +7638,10 @@ set_iterator_to_next (struct it *it, bool reseat_p)
case GET_FROM_IMAGE:
case GET_FROM_STRETCH:
+#ifdef HAVE_XWIDGETS
+ case GET_FROM_XWIDGET:
+#endif
+
/* 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. */
@@ -8061,6 +8103,15 @@ next_element_from_image (struct it *it)
return true;
}
+#ifdef HAVE_XWIDGETS
+static bool
+next_element_from_xwidget (struct it *it)
+{
+ it->what = IT_XWIDGET;
+ return true;
+}
+#endif
+
/* Fill iterator IT with next display element from a stretch glyph
property. IT->object is the value of the text property. Value is
@@ -18793,6 +18844,28 @@ 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);
+
+ }
+#endif
}
@@ -24291,6 +24364,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_spec_p (prop))
+ {
+ // TODO: Don't return dummy size.
+ return OK_PIXELS (100);
+ }
+# endif
#endif
if (EQ (car, Qplus) || EQ (car, Qminus))
{
@@ -24796,6 +24876,18 @@ fill_image_glyph_string (struct glyph_string *s)
}
+#ifdef HAVE_XWIDGETS
+static void
+fill_xwidget_glyph_string (struct glyph_string *s)
+{
+ eassert (s->first_glyph->type == XWIDGET_GLYPH);
+ 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;
+}
+#endif
/* Fill glyph string S from a sequence of stretch glyphs.
START is the index of the first glyph to consider,
@@ -25181,6 +25273,20 @@ compute_overhangs_and_x (struct glyph_string *s, int x, bool backward_p)
} \
while (false)
+#ifdef HAVE_XWIDGETS
+#define BUILD_XWIDGET_GLYPH_STRING(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ do \
+ { \
+ s = 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 (false)
+#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
@@ -25302,7 +25408,7 @@ compute_overhangs_and_x (struct glyph_string *s, int x, bool backward_p)
to allocate glyph strings (because draw_glyphs can be called
asynchronously). */
-#define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X) \
+#define BUILD_GLYPH_STRINGS_1(START, END, HEAD, TAIL, HL, X, LAST_X) \
do \
{ \
HEAD = TAIL = NULL; \
@@ -25333,8 +25439,17 @@ compute_overhangs_and_x (struct glyph_string *s, int x, bool backward_p)
case IMAGE_GLYPH: \
BUILD_IMAGE_GLYPH_STRING (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
- break; \
- \
+ break;
+
+#ifdef HAVE_XWIDGETS
+# define BUILD_GLYPH_STRINGS_XW(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ case XWIDGET_GLYPH: \
+ BUILD_XWIDGET_GLYPH_STRING (START, END, HEAD, TAIL, \
+ HL, X, LAST_X); \
+ break;
+#endif
+
+#define BUILD_GLYPH_STRINGS_2(START, END, HEAD, TAIL, HL, X, LAST_X) \
case GLYPHLESS_GLYPH: \
BUILD_GLYPHLESS_GLYPH_STRING (START, END, HEAD, TAIL, \
HL, X, LAST_X); \
@@ -25353,6 +25468,18 @@ compute_overhangs_and_x (struct glyph_string *s, int x, bool backward_p)
} while (false)
+#ifdef HAVE_XWIDGETS
+# define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ BUILD_GLYPH_STRINGS_1(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ BUILD_GLYPH_STRINGS_XW(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ BUILD_GLYPH_STRINGS_2(START, END, HEAD, TAIL, HL, X, LAST_X)
+#else
+# define BUILD_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ BUILD_GLYPH_STRINGS_1(START, END, HEAD, TAIL, HL, X, LAST_X) \
+ BUILD_GLYPH_STRINGS_2(START, END, HEAD, TAIL, HL, X, LAST_X)
+#endif
+
+
/* Draw glyphs between START and END in AREA of ROW on window W,
starting at x-position X. X is relative to AREA in W. HL is a
face-override with the following meaning:
@@ -25991,6 +26118,109 @@ produce_image_glyph (struct it *it)
}
}
+#ifdef HAVE_XWIDGETS
+static void
+produce_xwidget_glyph (struct it *it)
+{
+ struct xwidget *xw;
+ int glyph_ascent, crop;
+ eassert (it->what == IT_XWIDGET);
+
+ struct face *face = FACE_FROM_ID (it->f, it->face_id);
+ eassert (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. */
+ crop = it->pixel_width - (it->last_visible_x - it->current_x);
+ if (crop > 0 && (it->hpos == 0 || it->pixel_width > it->last_visible_x / 4))
+ it->pixel_width -= crop;
+
+ if (it->glyph_row)
+ {
+ enum glyph_row_area area = it->area;
+ struct glyph *glyph
+ = it->glyph_row->glyphs[area] + it->glyph_row->used[area];
+
+ if (it->glyph_row->reversed_p)
+ {
+ struct glyph *g;
+
+ /* Make room for the new glyph. */
+ for (g = glyph - 1; g >= it->glyph_row->glyphs[it->area]; g--)
+ g[1] = *g;
+ glyph = it->glyph_row->glyphs[it->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->avoid_cursor_p = it->avoid_cursor_p;
+ glyph->multibyte_p = it->multibyte_p;
+ if (it->glyph_row->reversed_p && area == TEXT_AREA)
+ {
+ /* In R2L rows, the left and the right box edges need to be
+ drawn in reverse direction. */
+ glyph->right_box_line_p = it->start_of_box_run_p;
+ glyph->left_box_line_p = it->end_of_box_run_p;
+ }
+ else
+ {
+ 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;
+ glyph->font_type = FONT_TYPE_UNKNOWN;
+ if (it->bidi_p)
+ {
+ glyph->resolved_level = it->bidi_it.resolved_level;
+ eassert ((it->bidi_it.type & 7) == it->bidi_it.type);
+ glyph->bidi_type = it->bidi_it.type;
+ }
+ ++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
@@ -27401,6 +27631,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
@@ -27770,6 +28004,10 @@ 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)
+ 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 5a6d643bad4..44eed22d2ec 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 "composite.h"
#include "frame.h"
#include "dispextern.h"
+#ifdef HAVE_XWIDGETS
+# include "xwidget.h"
+#endif
#include "fontset.h"
#include "termhooks.h"
#include "termopts.h"
@@ -3511,6 +3514,12 @@ x_draw_glyph_string (struct glyph_string *s)
x_draw_image_glyph_string (s);
break;
+#ifdef HAVE_XWIDGETS
+ case XWIDGET_GLYPH:
+ x_draw_xwidget_glyph_string (s);
+ break;
+#endif
+
case STRETCH_GLYPH:
x_draw_stretch_glyph_string (s);
break;
@@ -8920,6 +8929,11 @@ x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text
if (cursor_glyph == NULL)
return;
+#ifdef HAVE_XWIDGETS
+ if (cursor_glyph->type == XWIDGET_GLYPH)
+ 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. */
diff --git a/src/xwidget.c b/src/xwidget.c
new file mode 100644
index 00000000000..ea5dea0f9fe
--- /dev/null
+++ b/src/xwidget.c
@@ -0,0 +1,1320 @@
+/* Support for embedding graphical components in a buffer.
+
+Copyright (C) 2011-2016 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+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>
+#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
+
+#ifdef BSD_SYSTEM
+# include <sys/ioctl.h>
+#endif
+
+#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 "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 /* HAVE_X_WINDOWS */
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+
+#include <gtk/gtkx.h>
+
+#include "emacsgtkfixed.h"
+
+#include <wchar.h>
+
+#include <webkit/webkitwebview.h>
+#include <webkit/webkitwebplugindatabase.h>
+#include <webkit/webkitwebplugin.h>
+#include <webkit/webkitglobals.h>
+#include <webkit/webkitwebnavigationaction.h>
+#include <webkit/webkitdownload.h>
+#include <webkit/webkitwebpolicydecision.h>
+
+#include "xwidget.h"
+
+static struct xwidget *
+allocate_xwidget (void)
+{
+ return ALLOCATE_PSEUDOVECTOR (struct xwidget, height, PVEC_XWIDGET);
+}
+
+static struct xwidget_view *
+allocate_xwidget_view (void)
+{
+ return ALLOCATE_PSEUDOVECTOR (struct xwidget_view, redisplayed,
+ PVEC_XWIDGET_VIEW);
+}
+
+#define XSETXWIDGET(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET))
+#define XSETXWIDGET_VIEW(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_XWIDGET_VIEW))
+
+static struct xwidget_view *xwidget_view_lookup (struct xwidget *,
+ struct window *);
+static void webkit_document_load_finished_cb (WebKitWebView *, WebKitWebFrame *,
+ gpointer);
+static gboolean webkit_download_cb (WebKitWebView *, WebKitDownload *, gpointer);
+
+static gboolean
+webkit_mime_type_policy_typedecision_requested_cb (WebKitWebView *,
+ WebKitWebFrame *,
+ WebKitNetworkRequest *,
+ gchar *,
+ WebKitWebPolicyDecision *,
+ gpointer);
+
+static gboolean
+webkit_new_window_policy_decision_requested_cb (WebKitWebView *,
+ WebKitWebFrame *,
+ WebKitNetworkRequest *,
+ WebKitWebNavigationAction *,
+ WebKitWebPolicyDecision *,
+ gpointer);
+
+static gboolean
+webkit_navigation_policy_decision_requested_cb (WebKitWebView *,
+ WebKitWebFrame *,
+ WebKitNetworkRequest *,
+ WebKitWebNavigationAction *,
+ WebKitWebPolicyDecision *,
+ gpointer);
+
+
+
+DEFUN ("make-xwidget",
+ Fmake_xwidget, Smake_xwidget,
+ 7, 8, 0,
+ doc: /* Make an xwidget from BEG to END of TYPE.
+If BUFFER is nil, use the current buffer.
+If BUFFER is a string and no such buffer exists, create it.
+TYPE is a symbol which can take one of the following values:
+
+- webkit_osr
+
+Returns the newly constructed xwidget, or nil if construction fails. */)
+ (Lisp_Object beg, Lisp_Object end,
+ Lisp_Object type,
+ Lisp_Object title,
+ Lisp_Object width, Lisp_Object height,
+ Lisp_Object arguments, Lisp_Object buffer)
+{
+ //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-list))
+ struct xwidget *xw = allocate_xwidget ();
+ Lisp_Object val;
+ xw->type = type;
+ xw->title = title;
+ if (NILP (buffer))
+ buffer = Fcurrent_buffer (); // no need to gcpro because
+ // Fcurrent_buffer doesn't
+ // call Feval/eval_sub.
+ else
+ buffer = Fget_buffer_create (buffer);
+ xw->buffer = buffer;
+
+ xw->height = XFASTINT (height);
+ xw->width = XFASTINT (width);
+ xw->kill_without_query = 0;
+ XSETXWIDGET (val, xw); // set the vectorlike_header of VAL
+ // with the correct value
+ Vxwidget_list = Fcons (val, Vxwidget_list);
+ xw->widgetwindow_osr = NULL;
+ xw->widget_osr = NULL;
+ xw->plist = Qnil;
+
+
+ if (EQ (xw->type, Qwebkit_osr))
+ {
+ block_input ();
+ xw->widgetwindow_osr = gtk_offscreen_window_new ();
+ gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
+ xw->height);
+ xw->widgetscrolledwindow_osr = NULL; //webkit osr is the
+ //only scrolled
+ //component atm
+
+ if (EQ (xw->type, Qwebkit_osr))
+ {
+ xw->widgetscrolledwindow_osr = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW
+ (xw->
+ widgetscrolledwindow_osr),
+ xw->height);
+ gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW
+ (xw->
+ widgetscrolledwindow_osr),
+ xw->width);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW
+ (xw->widgetscrolledwindow_osr),
+ GTK_POLICY_ALWAYS,
+ GTK_POLICY_ALWAYS);
+
+ xw->widget_osr = webkit_web_view_new ();
+ gtk_container_add (GTK_CONTAINER (xw->widgetscrolledwindow_osr),
+ GTK_WIDGET (WEBKIT_WEB_VIEW (xw->widget_osr)));
+ }
+
+ gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
+ xw->height);
+
+ if (EQ (xw->type, Qwebkit_osr))
+ {
+ gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
+ xw->widgetscrolledwindow_osr);
+ }
+ else
+ {
+ gtk_container_add (GTK_CONTAINER (xw->widgetwindow_osr),
+ xw->widget_osr);
+ }
+
+ gtk_widget_show (xw->widget_osr);
+ gtk_widget_show (xw->widgetwindow_osr);
+ gtk_widget_show (xw->widgetscrolledwindow_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 */
+ if (EQ (xw->type, Qwebkit_osr))
+ {
+ g_signal_connect (G_OBJECT (xw->widget_osr),
+ "document-load-finished",
+ G_CALLBACK (webkit_document_load_finished_cb), xw);
+
+ g_signal_connect (G_OBJECT (xw->widget_osr),
+ "download-requested",
+ G_CALLBACK (webkit_download_cb), xw);
+
+ g_signal_connect (G_OBJECT (xw->widget_osr),
+ "mime-type-policy-decision-requested",
+ G_CALLBACK
+ (webkit_mime_type_policy_typedecision_requested_cb),
+ xw);
+
+ g_signal_connect (G_OBJECT (xw->widget_osr),
+ "new-window-policy-decision-requested",
+ G_CALLBACK
+ (webkit_new_window_policy_decision_requested_cb),
+ xw);
+
+ g_signal_connect (G_OBJECT (xw->widget_osr),
+ "navigation-policy-decision-requested",
+ G_CALLBACK
+ (webkit_navigation_policy_decision_requested_cb),
+ xw);
+ }
+
+ unblock_input ();
+
+ }
+
+ return val;
+}
+
+DEFUN ("get-buffer-xwidgets", Fget_buffer_xwidgets, Sget_buffer_xwidgets,
+ 1, 1, 0,
+ doc: /* Return a list of xwidgets associated with BUFFER.
+BUFFER may be a buffer or the name of one. */)
+ (Lisp_Object buffer)
+{
+ Lisp_Object xw, tail, xw_list;
+
+ if (NILP (buffer))
+ return Qnil;
+ buffer = Fget_buffer (buffer);
+ if (NILP (buffer))
+ return Qnil;
+
+ xw_list = Qnil;
+
+ for (tail = Vxwidget_list; CONSP (tail); tail = XCDR (tail))
+ {
+ xw = XCAR (tail);
+ if (XWIDGETP (xw) && EQ (Fxwidget_buffer (xw), buffer))
+ xw_list = Fcons (xw, xw_list);
+ }
+ return xw_list;
+}
+
+static int
+xwidget_hidden (struct xwidget_view *xv)
+{
+ return xv->hidden;
+}
+
+
+
+static void
+xwidget_show_view (struct xwidget_view *xv)
+{
+ xv->hidden = 0;
+ gtk_widget_show (xv->widgetwindow);
+ gtk_fixed_move (GTK_FIXED (xv->emacswindow),
+ xv->widgetwindow,
+ xv->x + xv->clip_left,
+ xv->y + xv->clip_top);
+}
+
+
+/* Hide an xvidget view. */
+static void
+xwidget_hide_view (struct xwidget_view *xv)
+{
+ xv->hidden = 1;
+ gtk_fixed_move (GTK_FIXED (xv->emacswindow), xv->widgetwindow,
+ 10000, 10000);
+}
+
+
+
+/* When the off-screen webkit master view changes this signal is called.
+ It copies the bitmap from the off-screen instance. */
+static gboolean
+offscreen_damage_event (GtkWidget * widget, GdkEvent * event,
+ gpointer xv_widget)
+{
+ // Queue a redraw of onscreen widget.
+ // There is a guard against receiving an invalid widget,
+ // which should only happen if we failed to remove the
+ // specific signal handler for the damage event.
+ if (GTK_IS_WIDGET (xv_widget))
+ gtk_widget_queue_draw (GTK_WIDGET (xv_widget));
+ else
+ printf ("Warning, offscreen_damage_event received invalid xv pointer:%p\n",
+ (void *) xv_widget);
+
+ return FALSE;
+}
+
+static void
+store_xwidget_event_string (struct xwidget *xw, const char *eventname,
+ const char *eventstr)
+{
+ struct input_event event;
+ Lisp_Object xwl;
+ XSETXWIDGET (xwl, xw);
+ EVENT_INIT (event);
+ event.kind = XWIDGET_EVENT;
+ event.frame_or_window = Qnil;
+
+ event.arg = Qnil;
+ event.arg = Fcons (build_string (eventstr), event.arg);
+ event.arg = Fcons (xwl, event.arg);
+ event.arg = Fcons (intern (eventname), event.arg);
+ kbd_buffer_store_event (&event);
+
+}
+
+//TODO deprecated, use load-status
+void
+webkit_document_load_finished_cb (WebKitWebView * webkitwebview,
+ WebKitWebFrame * arg1,
+ gpointer data)
+{
+ struct xwidget *xw =
+ (struct xwidget *) g_object_get_data (G_OBJECT (webkitwebview),
+ XG_XWIDGET);
+
+ store_xwidget_event_string (xw, "document-load-finished", "");
+}
+
+gboolean
+webkit_download_cb (WebKitWebView * webkitwebview,
+ WebKitDownload * arg1,
+ gpointer data)
+{
+ struct xwidget *xw =
+ (struct xwidget *) g_object_get_data (G_OBJECT (webkitwebview),
+ XG_XWIDGET);
+ store_xwidget_event_string (xw, "download-requested",
+ webkit_download_get_uri (arg1));
+
+ return FALSE;
+}
+
+static gboolean
+webkit_mime_type_policy_typedecision_requested_cb (WebKitWebView *webView,
+ WebKitWebFrame *frame,
+ WebKitNetworkRequest * request,
+ gchar * mimetype,
+ WebKitWebPolicyDecision *policy_decision,
+ gpointer user_data)
+{
+ // This function makes webkit send a download signal for all unknown
+ // mime types. TODO Defer the decision to lisp, so that its possible
+ // to make Emacs handle teext mime for instance.xs
+ if (!webkit_web_view_can_show_mime_type (webView, mimetype))
+ {
+ webkit_web_policy_decision_download (policy_decision);
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+
+static gboolean
+webkit_new_window_policy_decision_requested_cb (WebKitWebView *webView,
+ WebKitWebFrame *frame,
+ WebKitNetworkRequest *request,
+ WebKitWebNavigationAction *navigation_action,
+ WebKitWebPolicyDecision *policy_decision,
+ gpointer user_data)
+{
+ struct xwidget *xw =
+ (struct xwidget *) g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
+ webkit_web_navigation_action_get_original_uri (navigation_action);
+
+ store_xwidget_event_string (xw, "new-window-policy-decision-requested",
+ webkit_web_navigation_action_get_original_uri
+ (navigation_action));
+ return FALSE;
+}
+
+static gboolean
+webkit_navigation_policy_decision_requested_cb (WebKitWebView *webView,
+ WebKitWebFrame *frame,
+ WebKitNetworkRequest *request,
+ WebKitWebNavigationAction *navigation_action,
+ WebKitWebPolicyDecision * policy_decision,
+ gpointer user_data)
+{
+ struct xwidget *xw =
+ (struct xwidget *) g_object_get_data (G_OBJECT (webView), XG_XWIDGET);
+ store_xwidget_event_string (xw, "navigation-policy-decision-requested",
+ webkit_web_navigation_action_get_original_uri
+ (navigation_action));
+ return FALSE;
+}
+
+// For gtk3 offscreen rendered widgets.
+static gboolean
+xwidget_osr_draw_cb (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);
+
+ cairo_rectangle (cr, 0, 0, xv->clip_right, xv->clip_bottom);
+ cairo_clip (cr);
+
+ if (xw->widgetscrolledwindow_osr != NULL)
+ gtk_widget_draw (xw->widgetscrolledwindow_osr, cr);
+ else
+ gtk_widget_draw (xw->widget_osr, cr);
+ return FALSE;
+}
+
+static gboolean
+xwidget_osr_event_forward (GtkWidget * widget,
+ GdkEvent * event,
+ gpointer user_data)
+{
+ /* Copy events that arrive at the outer widget to the offscreen widget. */
+ struct xwidget *xw =
+ (struct xwidget *) g_object_get_data (G_OBJECT (widget), XG_XWIDGET);
+ GdkEvent *eventcopy = gdk_event_copy (event);
+ eventcopy->any.window = gtk_widget_get_window (xw->widget_osr);
+
+ //TODO This might leak events. They should be deallocated later,
+ //perhaps in xwgir_event_cb
+ gtk_main_do_event (eventcopy);
+ return TRUE; //dont propagate this event furter
+}
+
+
+static gboolean
+xwidget_osr_event_set_embedder (GtkWidget * widget,
+ GdkEvent * event, gpointer data)
+{
+ struct xwidget_view *xv = (struct xwidget_view *) data;
+ struct xwidget *xww = XXWIDGET (xv->model);
+ gdk_offscreen_window_set_embedder (gtk_widget_get_window
+ (xww->widgetwindow_osr),
+ gtk_widget_get_window (xv->widget));
+ return FALSE;
+}
+
+
+/* Initializes and does initial placement of an xwidget view on screen. */
+static struct xwidget_view *
+xwidget_init_view (struct xwidget *xww,
+ struct glyph_string *s,
+ int x, int y)
+{
+ struct xwidget_view *xv = allocate_xwidget_view ();
+ Lisp_Object val;
+
+ XSETXWIDGET_VIEW (val, xv);
+ Vxwidget_view_list = Fcons (val, Vxwidget_view_list);
+
+ XSETWINDOW (xv->w, s->w);
+ XSETXWIDGET (xv->model, xww);
+
+ if (EQ (xww->type, Qwebkit_osr))
+ {
+ xv->widget = gtk_drawing_area_new ();
+ // Expose event handling.
+ gtk_widget_set_app_paintable (xv->widget, TRUE);
+ gtk_widget_add_events (xv->widget, GDK_ALL_EVENTS_MASK);
+
+ /* Draw the view on damage-event */
+ g_signal_connect (G_OBJECT (xww->widgetwindow_osr), "damage-event",
+ G_CALLBACK (offscreen_damage_event), xv->widget);
+
+ if (EQ (xww->type, Qwebkit_osr))
+ {
+ g_signal_connect (G_OBJECT (xv->widget), "button-press-event",
+ G_CALLBACK (xwidget_osr_event_forward), NULL);
+ g_signal_connect (G_OBJECT (xv->widget), "button-release-event",
+ G_CALLBACK (xwidget_osr_event_forward), NULL);
+ g_signal_connect (G_OBJECT (xv->widget), "motion-notify-event",
+ G_CALLBACK (xwidget_osr_event_forward), NULL);
+ }
+ else
+ {
+ // xwgir debug , orthogonal to forwarding
+ g_signal_connect (G_OBJECT (xv->widget), "enter-notify-event",
+ G_CALLBACK (xwidget_osr_event_set_embedder), xv);
+ }
+ g_signal_connect (G_OBJECT (xv->widget), "draw",
+ G_CALLBACK (xwidget_osr_draw_cb), 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 = FRAME_GTK_WIDGET (s->f);
+ xv->widgetwindow = gtk_fixed_new ();
+ gtk_widget_set_has_window (xv->widgetwindow, TRUE);
+ gtk_container_add (GTK_CONTAINER (xv->widgetwindow), xv->widget);
+
+ // Store some xwidget data in the gtk widgets.
+ // The emacs frame.
+ g_object_set_data (G_OBJECT (xv->widget), XG_FRAME_DATA, (gpointer) (s->f));
+ // The xwidget.
+ 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 window.
+ g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET, (gpointer) (xww));
+ // the xwidget view.
+ g_object_set_data (G_OBJECT (xv->widgetwindow), XG_XWIDGET_VIEW,
+ (gpointer) (xv));
+
+
+ gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xww->width,
+ xww->height);
+ gtk_widget_set_size_request (xv->widgetwindow, xww->width, xww->height);
+ gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), xv->widgetwindow, x, y);
+ xv->x = x;
+ xv->y = y;
+ gtk_widget_show_all (xv->widgetwindow);
+
+
+ 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
+ initialization.
+ */
+ 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;
+
+ /* We do initialization here in the display loop because there is no
+ other time to know things like window placement etc.
+ */
+ 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 clipping 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));
+ xv->x = x;
+ xv->y = y;
+ if (moved) // Has it moved?
+ {
+ gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)),
+ 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. Clipping 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 (xv->widgetwindow, clip_right + clip_left,
+ clip_bottom + clip_top);
+ gtk_fixed_move (GTK_FIXED (xv->widgetwindow), xv->widget, -clip_left,
+ -clip_top);
+
+ 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. It seems its possible to get out of sync with emacs
+ // redraws so emacs background sometimes shows up instead of the
+ // xwidgets background. It's just a visual glitch though.
+ if (!xwidget_hidden (xv))
+ {
+ gtk_widget_queue_draw (xv->widgetwindow);
+ gtk_widget_queue_draw (xv->widget);
+ }
+}
+
+
+// Macro that checks WEBKIT_IS_WEB_VIEW(xw->widget_osr) first
+#define WEBKIT_FN_INIT() \
+ struct xwidget* xw; \
+ CHECK_XWIDGET (xwidget); \
+ if (NILP (xwidget)) {printf("ERROR xwidget nil\n"); return Qnil;}; \
+ xw = XXWIDGET (xwidget); \
+ if (NULL == xw) printf("ERROR xw is 0\n"); \
+ if ((NULL == xw->widget_osr) || !WEBKIT_IS_WEB_VIEW(xw->widget_osr)){ \
+ printf ("ERROR xw->widget_osr does not hold a webkit instance\n");\
+ return Qnil;\
+ };
+
+
+DEFUN ("xwidget-webkit-goto-uri",
+ Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri,
+ 2, 2, 0,
+ doc: /* Make the xwidget webkit instance referenced by XWIDGET browse URI. */)
+ (Lisp_Object xwidget, Lisp_Object uri)
+{
+ WEBKIT_FN_INIT ();
+ CHECK_STRING (uri);
+ webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr), SSDATA (uri));
+ return Qnil;
+}
+
+
+DEFUN ("xwidget-webkit-execute-script",
+ Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script,
+ 2, 2, 0,
+ doc: /* Make the Webkit XWIDGET execute javascript SCRIPT. */)
+ (Lisp_Object xwidget, Lisp_Object script)
+{
+ WEBKIT_FN_INIT ();
+ CHECK_STRING (script);
+ webkit_web_view_execute_script (WEBKIT_WEB_VIEW (xw->widget_osr),
+ SSDATA (script));
+ return Qnil;
+}
+
+DEFUN ("xwidget-webkit-get-title",
+ Fxwidget_webkit_get_title, Sxwidget_webkit_get_title,
+ 1, 1, 0,
+ doc: /* Return the title from the Webkit instance in XWIDGET.
+This can be used to work around the lack of a return value from the
+exec method. */ )
+ (Lisp_Object xwidget)
+{
+ // TODO support multibyte strings
+ WEBKIT_FN_INIT ();
+ const gchar *str =
+ webkit_web_view_get_title (WEBKIT_WEB_VIEW (xw->widget_osr));
+ if (str == 0)
+ {
+ // TODO maybe return Qnil instead. I suppose webkit returns
+ // nullpointer when doc is not properly loaded or something
+ return build_string ("");
+ }
+ return build_string (str);
+}
+
+DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
+ doc: /* Resize XWIDGET. NEW_WIDTH, NEW_HEIGHT define the new size. */ )
+ (Lisp_Object xwidget, Lisp_Object new_width, Lisp_Object new_height)
+{
+ CHECK_XWIDGET (xwidget);
+ 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);
+
+ xw->width = w;
+ xw->height = h;
+ // If there is a offscreen widget resize it 1st.
+ if (xw->widget_osr)
+ {
+ gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr),
+ xw->width, xw->height); //minimum size
+ gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
+ xw->height);
+ gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW
+ (xw->
+ widgetscrolledwindow_osr),
+ xw->height);
+ gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW
+ (xw->
+ widgetscrolledwindow_osr),
+ xw->width);
+
+ gtk_container_resize_children (GTK_CONTAINER (xw->widgetwindow_osr));
+
+ }
+
+ for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
+ {
+ if (XWIDGET_VIEW_P (XCAR (tail)))
+ {
+ xv = XXWIDGET_VIEW (XCAR (tail));
+ if (XXWIDGET (xv->model) == xw)
+ gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width,
+ xw->height);
+ }
+ }
+
+ return Qnil;
+}
+
+
+
+DEFUN ("xwidget-set-adjustment",
+ Fxwidget_set_adjustment, Sxwidget_set_adjustment, 4, 4, 0,
+ doc: /* Set native scrolling for XWIDGET.
+AXIS can be 'vertical or 'horizontal.
+If RELATIVE is t, scroll relative, otherwise absolutely.
+VALUE is the amount to scroll, either relatively or absolutely. */)
+ (Lisp_Object xwidget, Lisp_Object axis, Lisp_Object relative,
+ Lisp_Object value)
+{
+ CHECK_XWIDGET (xwidget);
+ struct xwidget *xw = XXWIDGET (xwidget);
+ GtkAdjustment *adjustment;
+ float final_value = 0.0;
+
+ adjustment =
+ gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
+ (xw->widgetscrolledwindow_osr));
+ if (EQ (Qvertical, axis))
+ {
+ adjustment =
+ gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW
+ (xw->widgetscrolledwindow_osr));
+ }
+ if (EQ (Qhorizontal, axis))
+ {
+ adjustment =
+ gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW
+ (xw->widgetscrolledwindow_osr));
+ }
+
+ if (EQ (Qt, relative))
+ {
+ final_value = gtk_adjustment_get_value (adjustment) + XFASTINT (value);
+ }
+ else
+ {
+ final_value = 0.0 + XFASTINT (value);
+ }
+
+ gtk_adjustment_set_value (adjustment, final_value);
+
+ return Qnil;
+}
+
+
+DEFUN ("xwidget-size-request",
+ Fxwidget_size_request, Sxwidget_size_request,
+ 1, 1, 0,
+ doc: /* Return the desired size of the XWIDGET.
+This can be used to read the xwidget desired size, and resizes the
+Emacs allocated area accordingly. */)
+ (Lisp_Object xwidget)
+{
+ CHECK_XWIDGET (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 an xwidget. */)
+ (Lisp_Object object)
+{
+ return XWIDGETP (object) ? Qt : Qnil;
+}
+
+DEFUN ("xwidget-view-p",
+ Fxwidget_view_p, Sxwidget_view_p,
+ 1, 1, 0,
+ doc: /* Return t if OBJECT is an xwidget-view. */)
+ (Lisp_Object object)
+{
+ return XWIDGET_VIEW_P (object) ? Qt : Qnil;
+}
+
+DEFUN ("xwidget-info",
+ Fxwidget_info, Sxwidget_info,
+ 1, 1, 0,
+ doc: /* Return XWIDGET properties in a vector.
+Currently [TYPE TITLE WIDTH HEIGHT]. */)
+ (Lisp_Object xwidget)
+{
+ CHECK_XWIDGET (xwidget);
+ Lisp_Object info, n;
+ struct xwidget *xw = XXWIDGET (xwidget);
+
+ info = Fmake_vector (make_number (4), Qnil);
+ ASET (info, 0, xw->type);
+ ASET (info, 1, xw->title);
+ XSETFASTINT (n, xw->width);
+ ASET (info, 2, n);
+ XSETFASTINT (n, xw->height);
+ ASET (info, 3, n);
+
+ return info;
+}
+
+DEFUN ("xwidget-view-info",
+ Fxwidget_view_info, Sxwidget_view_info,
+ 1, 1, 0,
+ doc: /* Return properties of XWIDGET-VIEW in a vector.
+Currently [X Y CLIP_RIGHT CLIP_BOTTOM CLIP_TOP CLIP_LEFT]. */)
+ (Lisp_Object xwidget_view)
+{
+ CHECK_XWIDGET_VIEW (xwidget_view);
+ struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
+ Lisp_Object info;
+
+ info = Fmake_vector (make_number (6), Qnil);
+ ASET (info, 0, make_number (xv->x));
+ ASET (info, 1, make_number (xv->y));
+ ASET (info, 2, make_number (xv->clip_right));
+ ASET (info, 3, make_number (xv->clip_bottom));
+ ASET (info, 4, make_number (xv->clip_top));
+ ASET (info, 5, make_number (xv->clip_left));
+
+ return info;
+}
+
+DEFUN ("xwidget-view-model",
+ Fxwidget_view_model, Sxwidget_view_model,
+ 1, 1, 0,
+ doc: /* Return the model associated with XWIDGET-VIEW. */)
+ (Lisp_Object xwidget_view)
+{
+ CHECK_XWIDGET_VIEW (xwidget_view);
+ return XXWIDGET_VIEW (xwidget_view)->model;
+}
+
+DEFUN ("xwidget-view-window",
+ Fxwidget_view_window, Sxwidget_view_window,
+ 1, 1, 0,
+ doc: /* Return the window of XWIDGET-VIEW. */)
+ (Lisp_Object xwidget_view)
+{
+ CHECK_XWIDGET_VIEW (xwidget_view);
+ return XXWIDGET_VIEW (xwidget_view)->w;
+}
+
+
+DEFUN ("delete-xwidget-view",
+ Fdelete_xwidget_view, Sdelete_xwidget_view,
+ 1, 1, 0,
+ doc: /* Delete the XWIDGET-VIEW. */)
+ (Lisp_Object xwidget_view)
+{
+ CHECK_XWIDGET_VIEW (xwidget_view);
+ struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view);
+ gtk_widget_destroy (xv->widgetwindow);
+ Vxwidget_view_list = Fdelq (xwidget_view, Vxwidget_view_list);
+ // xv->model still has signals pointing to the view. There can be
+ // several views. Find the matching signals and delete them all.
+ g_signal_handlers_disconnect_matched (XXWIDGET (xv->model)->widgetwindow_osr,
+ G_SIGNAL_MATCH_DATA,
+ 0, 0, 0, 0,
+ xv->widget);
+ return Qnil;
+}
+
+DEFUN ("xwidget-view-lookup",
+ Fxwidget_view_lookup, Sxwidget_view_lookup,
+ 1, 2, 0,
+ doc: /* Return the xwidget-view associated with XWIDGET in WINDOW.
+If WINDOW is unspecified or nil, use the selected window.
+Return nil if no association is found. */)
+ (Lisp_Object xwidget, Lisp_Object window)
+{
+ CHECK_XWIDGET (xwidget);
+
+ if (NILP (window))
+ window = Fselected_window ();
+ CHECK_WINDOW (window);
+
+ for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
+ tail = XCDR (tail))
+ {
+ Lisp_Object xwidget_view = XCAR (tail);
+ if (EQ (Fxwidget_view_model (xwidget_view), xwidget)
+ && EQ (Fxwidget_view_window (xwidget_view), window))
+ return xwidget_view;
+ }
+
+ return Qnil;
+}
+
+DEFUN ("xwidget-plist",
+ Fxwidget_plist, Sxwidget_plist,
+ 1, 1, 0,
+ doc: /* Return the plist of XWIDGET. */)
+ (register Lisp_Object xwidget)
+{
+ CHECK_XWIDGET (xwidget);
+ 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);
+ 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);
+ CHECK_LIST (plist);
+
+ XXWIDGET (xwidget)->plist = plist;
+ return plist;
+}
+
+DEFUN ("set-xwidget-query-on-exit-flag",
+ Fset_xwidget_query_on_exit_flag, Sset_xwidget_query_on_exit_flag,
+ 2, 2, 0,
+ doc: /* Specify if query is needed for XWIDGET when Emacs is exited.
+If the second argument FLAG is non-nil, Emacs will query the user before
+exiting or killing a buffer if XWIDGET is running.
+This function returns FLAG. */)
+ (Lisp_Object xwidget, Lisp_Object flag)
+{
+ CHECK_XWIDGET (xwidget);
+ XXWIDGET (xwidget)->kill_without_query = NILP (flag);
+ return flag;
+}
+
+DEFUN ("xwidget-query-on-exit-flag",
+ Fxwidget_query_on_exit_flag, Sxwidget_query_on_exit_flag,
+ 1, 1, 0,
+ doc: /* Return the current value of the query-on-exit flag for XWIDGET. */)
+ (Lisp_Object xwidget)
+{
+ CHECK_XWIDGET (xwidget);
+ return (XXWIDGET (xwidget)->kill_without_query ? Qnil : Qt);
+}
+
+void
+syms_of_xwidget (void)
+{
+
+ defsubr (&Smake_xwidget);
+ defsubr (&Sxwidgetp);
+ DEFSYM (Qxwidgetp, "xwidgetp");
+ defsubr (&Sxwidget_view_p);
+ DEFSYM (Qxwidget_view_p, "xwidget-view-p");
+ defsubr (&Sxwidget_info);
+ defsubr (&Sxwidget_view_info);
+ defsubr (&Sxwidget_resize);
+ defsubr (&Sget_buffer_xwidgets);
+ defsubr (&Sxwidget_view_model);
+ defsubr (&Sxwidget_view_window);
+ defsubr (&Sxwidget_view_lookup);
+ defsubr (&Sxwidget_query_on_exit_flag);
+ defsubr (&Sset_xwidget_query_on_exit_flag);
+
+ defsubr (&Sxwidget_webkit_goto_uri);
+ defsubr (&Sxwidget_webkit_execute_script);
+ defsubr (&Sxwidget_webkit_get_title);
+ DEFSYM (Qwebkit_osr, "webkit-osr");
+
+ defsubr (&Sxwidget_size_request);
+ defsubr (&Sdelete_xwidget_view);
+
+ defsubr (&Sxwidget_plist);
+ defsubr (&Sxwidget_buffer);
+ defsubr (&Sset_xwidget_plist);
+
+ defsubr (&Sxwidget_set_adjustment);
+
+ DEFSYM (Qxwidget, "xwidget");
+
+ DEFSYM (QCxwidget, ":xwidget");
+ DEFSYM (QCtitle, ":title");
+
+ /* Do not forget to update the docstring of make-xwidget if you add
+ new types. */
+
+ DEFSYM (Qvertical, "vertical");
+ DEFSYM (Qhorizontal, "horizontal");
+
+ DEFSYM (QCplist, ":plist");
+
+ DEFVAR_LISP ("xwidget-list", Vxwidget_list,
+ doc: /* xwidgets list. */);
+ Vxwidget_list = Qnil;
+
+ DEFVAR_LISP ("xwidget-view-list", Vxwidget_view_list,
+ doc: /* xwidget views list. */);
+ Vxwidget_view_list = Qnil;
+
+ Fprovide (intern ("xwidget-internal"), Qnil);
+
+}
+
+
+/* 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. */
+
+bool
+valid_xwidget_spec_p (Lisp_Object object)
+{
+ int valid_p = false;
+
+ if (CONSP (object) && EQ (XCAR (object), Qxwidget))
+ valid_p = true;
+
+ return valid_p;
+}
+
+
+
+/* Find a value associated with key in spec. */
+static Lisp_Object
+xwidget_spec_value (Lisp_Object spec, Lisp_Object key, int *found)
+{
+ Lisp_Object tail;
+
+ eassert (valid_xwidget_spec_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 (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
+ tail = XCDR (tail))
+ {
+ if (XWIDGET_VIEW_P (XCAR (tail)))
+ {
+ xv = XXWIDGET_VIEW (XCAR (tail));
+ if (XWINDOW (xv->w) == w)
+ {
+ Fdelete_xwidget_view (XCAR (tail));
+ }
+ }
+ }
+}
+
+static struct xwidget_view *
+xwidget_view_lookup (struct xwidget *xw, struct window *w)
+{
+ Lisp_Object xwidget, window, ret;
+ XSETXWIDGET (xwidget, xw);
+ XSETWINDOW (window, w);
+
+ ret = Fxwidget_view_lookup (xwidget, window);
+
+ return EQ (ret, Qnil) ? NULL : XXWIDGET_VIEW (ret);
+}
+
+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.
+ */
+ int found = 0;
+ Lisp_Object value;
+ struct xwidget *xw;
+
+ value = xwidget_spec_value (spec, QCxwidget, &found);
+ xw = XXWIDGET (value);
+
+ return xw;
+}
+
+/* Set up detection of touched xwidget */
+static void
+xwidget_start_redisplay (void)
+{
+ for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
+ tail = XCDR (tail))
+ {
+ if (XWIDGET_VIEW_P (XCAR (tail)))
+ XXWIDGET_VIEW (XCAR (tail))->redisplayed = 0;
+ }
+}
+
+/* The xwidget was touched during redisplay, so it isn't a candidate
+ for hiding. */
+static void
+xwidget_touch (struct xwidget_view *xv)
+{
+ xv->redisplayed = 1;
+}
+
+static 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;
+ 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 (Lisp_Object tail = Vxwidget_view_list; CONSP (tail);
+ tail = XCDR (tail))
+ {
+ if (XWIDGET_VIEW_P (XCAR (tail)))
+ {
+ struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail));
+
+ // "touched" is only meaningful for the current window, so
+ // disregard other views.
+ if (XWINDOW (xv->w) == w)
+ {
+ if (xwidget_touched (xv))
+ xwidget_show_view (xv);
+ else
+ xwidget_hide_view (xv);
+ }
+ }
+ }
+}
+
+/* Kill all xwidget in BUFFER. */
+void
+kill_buffer_xwidgets (Lisp_Object buffer)
+{
+ Lisp_Object tail, xwidget;
+ for (tail = Fget_buffer_xwidgets (buffer); CONSP (tail); tail = XCDR (tail))
+ {
+ xwidget = XCAR (tail);
+ Vxwidget_list = Fdelq (xwidget, Vxwidget_list);
+ /* TODO free the GTK things in xw */
+ {
+ CHECK_XWIDGET (xwidget);
+ struct xwidget *xw = XXWIDGET (xwidget);
+ if (xw->widget_osr && xw->widgetwindow_osr)
+ {
+ gtk_widget_destroy (xw->widget_osr);
+ gtk_widget_destroy (xw->widgetwindow_osr);
+ }
+ }
+ }
+}
diff --git a/src/xwidget.h b/src/xwidget.h
new file mode 100644
index 00000000000..fdcf40d8cbb
--- /dev/null
+++ b/src/xwidget.h
@@ -0,0 +1,132 @@
+/* Support for embedding graphical components in a buffer.
+
+Copyright (C) 2011-2016 Free Software Foundation, Inc.
+
+This file is part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+GNU Emacs is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+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/>. */
+
+#ifndef XWIDGET_H_INCLUDED
+#define XWIDGET_H_INCLUDED
+
+void x_draw_xwidget_glyph_string (struct glyph_string *s);
+void syms_of_xwidget (void);
+
+//extern Lisp_Object Qxwidget;
+
+
+bool valid_xwidget_spec_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;
+ GtkWidget *widgetwindow_osr;
+ //this is used if the widget (webkit) is to be wrapped in a scrolled window,
+ GtkWidget *widgetscrolledwindow_osr;
+ /* Non-nil means kill silently if Emacs is exited. */
+ unsigned int kill_without_query:1;
+
+};
+
+
+//struct for each xwidget view
+struct xwidget_view
+{
+ struct vectorlike_header header;
+ Lisp_Object model;
+ Lisp_Object w;
+
+ //here ends the lisp part.
+ //"redisplayed" is the marker field
+ int redisplayed; //if touched by redisplay
+
+ int hidden; //if the "live" instance isnt drawn
+
+ GtkWidget *widget;
+ GtkWidget *widgetwindow;
+ GtkWidget *emacswindow;
+ int x;
+ int y;
+ int clip_right;
+ int clip_bottom;
+ int clip_top;
+ int clip_left;
+
+
+ long handler_id;
+};
+
+/* Test for xwidget pseudovector*/
+#define XWIDGETP(x) PSEUDOVECTORP (x, PVEC_XWIDGET)
+#define XXWIDGET(a) (eassert (XWIDGETP(a)), \
+ (struct xwidget *) XUNTAG(a, Lisp_Vectorlike))
+
+#define CHECK_XWIDGET(x) \
+ CHECK_TYPE (XWIDGETP (x), Qxwidgetp, x)
+
+/* Test for xwidget_view pseudovector */
+#define XWIDGET_VIEW_P(x) PSEUDOVECTORP (x, PVEC_XWIDGET_VIEW)
+#define XXWIDGET_VIEW(a) (eassert (XWIDGET_VIEW_P(a)), \
+ (struct xwidget_view *) XUNTAG(a, Lisp_Vectorlike))
+
+#define CHECK_XWIDGET_VIEW(x) \
+ CHECK_TYPE (XWIDGET_VIEW_P (x), Qxwidget_view_p, x)
+
+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;
+};
+
+
+struct xwidget *xwidget_from_id (int id);
+
+void xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix);
+
+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);
+
+void kill_buffer_xwidgets (Lisp_Object buffer);
+#endif /* XWIDGET_H_INCLUDED */