summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.in10
-rw-r--r--src/dispextern.h32
-rw-r--r--src/dispnew.c19
-rw-r--r--src/emacs.c6
-rw-r--r--src/emacsgtkfixed.c123
-rw-r--r--src/keyboard.c22
-rw-r--r--src/lisp.h6
-rw-r--r--src/print.c11
-rw-r--r--src/termhooks.h5
-rw-r--r--src/window.c7
-rw-r--r--src/xdisp.c248
-rw-r--r--src/xterm.c22
-rw-r--r--src/xwidget.c1302
-rw-r--r--src/xwidget.h110
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