summaryrefslogtreecommitdiff
path: root/src/xwidget.c
diff options
context:
space:
mode:
authorJoakim Verona <joakim@verona.se>2016-01-19 20:27:12 +0100
committerJoakim Verona <joakim@verona.se>2016-01-19 20:58:22 +0100
commit7c1f66a94bf236a427606ef537b4629a48a1665b (patch)
tree8661f512f7bcf35bfb1e7d915e5b6ef8df6229d8 /src/xwidget.c
parent663d379bbc2fde5e9bded157365e9d48ea01c027 (diff)
downloademacs-7c1f66a94bf236a427606ef537b4629a48a1665b.tar.gz
Support for the new Xwidget feature.
* configure.ac: (HAVE_XWIDGETS, WIDGET_OBJ, EMACS_CONFIG_FEATURES): * xterm.c (x_draw_glyph_string, x_draw_bar_cursor): * xdisp.c: (handle_display_spec, handle_single_display_spec, push_it) (pop_it, set_iterator_to_next, dump_glyph) (calc_pixel_width_or_height, fill_xwidget_glyph_string) (BUILD_XWIDGET_GLYPH_STRING, BUILD_GLYPH_STRINGS) (produce_xwidget_glyph, x_produce_glyphs) (get_window_cursor_type): * window.c (Fdelete_window_internal): * termhooks.h (e): * print.c (print_object): * lisp.h (ptrdiff_t): * keyboard.c (kbd_buffer_get_event, make_lispy_event) (syms_of_keyboard): * emacs.c (main): * dispnew.c (update_window, scrolling_window): * dispextern.h (g, i): * Makefile.in (XWIDGETS_OBJ, WEBKIT_CFLAGS, WEBKIT_LIBS) (GIR_LIBS, ALL_CFLAGS, base_obj, LIBES): * keyboard.c (kbd_buffer_get_event): * emacsgtkfixed.c (emacs_fixed_gtk_widget_size_allocate) (emacs_fixed_class_init): Add case for an xwidget view. * xwidget.c, xwidget.h, xwidget.el: New files for xwidgets Co-authored-by: Grégoire Jadi <daimrod@gmail.com> Various improvements to the Xwidget feature. * xwidgets.c: * emacsgtkfixed.c: * xwidget.el:
Diffstat (limited to 'src/xwidget.c')
-rw-r--r--src/xwidget.c1332
1 files changed, 1332 insertions, 0 deletions
diff --git a/src/xwidget.c b/src/xwidget.c
new file mode 100644
index 00000000000..74319e1667d
--- /dev/null
+++ b/src/xwidget.c
@@ -0,0 +1,1332 @@
+/* Support for embedding graphical components in a buffer.
+
+Copyright (C) 2011-2015 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))
+
+struct xwidget_view *xwidget_view_lookup (struct xwidget *, struct window *);
+Lisp_Object xwidget_spec_value (Lisp_Object , Lisp_Object , int *);
+gboolean offscreen_damage_event (GtkWidget * , GdkEvent * , gpointer );
+void webkit_document_load_finished_cb (WebKitWebView *, WebKitWebFrame *,
+ gpointer );
+gboolean webkit_download_cb (WebKitWebView *, WebKitDownload *, gpointer);
+
+gboolean
+webkit_mime_type_policy_typedecision_requested_cb (WebKitWebView *,
+ WebKitWebFrame *,
+ WebKitNetworkRequest *,
+ gchar *,
+ WebKitWebPolicyDecision *,
+ gpointer);
+
+gboolean
+webkit_new_window_policy_decision_requested_cb (WebKitWebView *,
+ WebKitWebFrame *,
+ WebKitNetworkRequest *,
+ WebKitWebNavigationAction *,
+ WebKitWebPolicyDecision *,
+ gpointer);
+
+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 it uses the current
+buffer. If BUFFER is a string and no such
+buffer exists, it is created.
+
+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. */
+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;
+}
+
+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;
+ }
+}
+
+
+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;
+}
+
+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: /* Returns 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 defines 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 a 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 a 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 specified, otherwise it uses 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
+queries 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 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);
+
+#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 (&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. */
+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));
+ }
+ }
+ }
+}
+
+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*/
+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. */
+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);
+ }
+ }
+ }
+}