summaryrefslogtreecommitdiff
path: root/src/xwidget.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xwidget.c')
-rw-r--r--src/xwidget.c260
1 files changed, 242 insertions, 18 deletions
diff --git a/src/xwidget.c b/src/xwidget.c
index 2486a2d4da8..b8c0b5e220d 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -23,20 +23,30 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
#include "lisp.h"
#include "blockinput.h"
+#include "dispextern.h"
#include "frame.h"
#include "keyboard.h"
#include "gtkutil.h"
+#include "termhooks.h"
+#include "window.h"
+/* Include xwidget bottom end headers. */
+#if defined (USE_GTK)
#include <webkit2/webkit2.h>
#include <JavaScriptCore/JavaScript.h>
+#elif defined (NS_IMPL_COCOA)
+#include "nsxwidget.h"
+#endif
/* Suppress GCC deprecation warnings starting in WebKitGTK+ 2.21.1 for
webkit_javascript_result_get_global_context and
webkit_javascript_result_get_value (Bug#33679).
FIXME: Use the JavaScriptCore GLib API instead, and remove this hack. */
+#if defined (USE_GTK)
#if WEBKIT_CHECK_VERSION (2, 21, 1) && GNUC_PREREQ (4, 2, 0)
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
+#endif
static struct xwidget *
allocate_xwidget (void)
@@ -55,6 +65,7 @@ allocate_xwidget_view (void)
static struct xwidget_view *xwidget_view_lookup (struct xwidget *,
struct window *);
+#if defined (USE_GTK)
static void webkit_view_load_changed_cb (WebKitWebView *,
WebKitLoadEvent,
gpointer);
@@ -68,6 +79,7 @@ webkit_decide_policy_cb (WebKitWebView *,
WebKitPolicyDecision *,
WebKitPolicyDecisionType,
gpointer);
+#endif
DEFUN ("make-xwidget",
@@ -85,8 +97,10 @@ Returns the newly constructed xwidget, or nil if construction fails. */)
Lisp_Object title, Lisp_Object width, Lisp_Object height,
Lisp_Object arguments, Lisp_Object buffer)
{
+#if defined (USE_GTK)
if (!xg_gtk_initialized)
error ("make-xwidget: GTK has not been initialized");
+#endif
CHECK_SYMBOL (type);
CHECK_FIXNAT (width);
CHECK_FIXNAT (height);
@@ -101,10 +115,11 @@ Returns the newly constructed xwidget, or nil if construction fails. */)
xw->kill_without_query = false;
XSETXWIDGET (val, xw);
Vxwidget_list = Fcons (val, Vxwidget_list);
- xw->widgetwindow_osr = NULL;
- xw->widget_osr = NULL;
xw->plist = Qnil;
+#if defined (USE_GTK)
+ xw->widgetwindow_osr = NULL;
+ xw->widget_osr = NULL;
if (EQ (xw->type, Qwebkit))
{
block_input ();
@@ -159,6 +174,9 @@ Returns the newly constructed xwidget, or nil if construction fails. */)
unblock_input ();
}
+#elif defined (NS_IMPL_COCOA)
+ nsxwidget_init (xw);
+#endif
return val;
}
@@ -194,6 +212,7 @@ xwidget_hidden (struct xwidget_view *xv)
return xv->hidden;
}
+#if defined (USE_GTK)
static void
xwidget_show_view (struct xwidget_view *xv)
{
@@ -227,13 +246,14 @@ offscreen_damage_event (GtkWidget *widget, GdkEvent *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",
- xv_widget);
+ message ("Warning, offscreen_damage_event received invalid xv pointer:%p\n",
+ xv_widget);
return FALSE;
}
+#endif /* USE_GTK */
-static void
+void
store_xwidget_event_string (struct xwidget *xw, const char *eventname,
const char *eventstr)
{
@@ -247,7 +267,27 @@ store_xwidget_event_string (struct xwidget *xw, const char *eventname,
kbd_buffer_store_event (&event);
}
-static void
+void
+store_xwidget_response_callback_event (struct xwidget *xw,
+ const char *url,
+ const char *mimetype,
+ const char *filename)
+{
+ struct input_event event;
+ Lisp_Object xwl;
+ XSETXWIDGET (xwl, xw);
+ EVENT_INIT (event);
+ event.kind = XWIDGET_EVENT;
+ event.frame_or_window = Qnil;
+ event.arg = list5 (intern ("response-callback"),
+ xwl,
+ build_string (url),
+ build_string (mimetype),
+ build_string (filename));
+ kbd_buffer_store_event (&event);
+}
+
+void
store_xwidget_js_callback_event (struct xwidget *xw,
Lisp_Object proc,
Lisp_Object argument)
@@ -263,6 +303,7 @@ store_xwidget_js_callback_event (struct xwidget *xw,
}
+#if defined (USE_GTK)
void
webkit_view_load_changed_cb (WebKitWebView *webkitwebview,
WebKitLoadEvent load_event,
@@ -520,6 +561,7 @@ xwidget_osr_event_set_embedder (GtkWidget *widget, GdkEvent *event,
gtk_widget_get_window (xv->widget));
return FALSE;
}
+#endif /* USE_GTK */
/* Initializes and does initial placement of an xwidget view on screen. */
@@ -529,8 +571,10 @@ xwidget_init_view (struct xwidget *xww,
int x, int y)
{
+#if defined (USE_GTK)
if (!xg_gtk_initialized)
error ("xwidget_init_view: GTK has not been initialized");
+#endif
struct xwidget_view *xv = allocate_xwidget_view ();
Lisp_Object val;
@@ -541,6 +585,7 @@ xwidget_init_view (struct xwidget *xww,
XSETWINDOW (xv->w, s->w);
XSETXWIDGET (xv->model, xww);
+#if defined (USE_GTK)
if (EQ (xww->type, Qwebkit))
{
xv->widget = gtk_drawing_area_new ();
@@ -598,6 +643,10 @@ xwidget_init_view (struct xwidget *xww,
xv->x = x;
xv->y = y;
gtk_widget_show_all (xv->widgetwindow);
+#elif defined (NS_IMPL_COCOA)
+ nsxwidget_init_view (xv, xww, s, x, y);
+ nsxwidget_resize_view(xv, xww->width, xww->height);
+#endif
return xv;
}
@@ -610,24 +659,59 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
initialization. */
struct xwidget *xww = s->xwidget;
struct xwidget_view *xv = xwidget_view_lookup (xww, s->w);
+ int text_area_x, text_area_y, text_area_width, text_area_height;
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 y = s->y;
/* Do initialization here in the display loop because there is no
other time to know things like window placement etc. Do not
create a new view if we have found one that is usable. */
+#if defined (USE_GTK)
if (!xv)
xv = xwidget_init_view (xww, s, x, y);
-
- int text_area_x, text_area_y, text_area_width, text_area_height;
+#elif defined (NS_IMPL_COCOA)
+ if (!xv)
+ {
+ /* Enforce 1 to 1, model and view for macOS Cocoa webkit2. */
+ if (xww->xv)
+ {
+ if (xwidget_hidden (xww->xv))
+ {
+ Lisp_Object xvl;
+ XSETXWIDGET_VIEW (xvl, xww->xv);
+ Fdelete_xwidget_view (xvl);
+ }
+ else
+ {
+ message ("You can't share an xwidget (webkit2) among windows.");
+ return;
+ }
+ }
+ xv = xwidget_init_view (xww, s, x, y);
+ }
+#endif
window_box (s->w, TEXT_AREA, &text_area_x, &text_area_y,
&text_area_width, &text_area_height);
+
+ /* Resize xwidget webkit if its container window size is changed in
+ some ways, for example, a buffer became hidden in small split
+ window, then it can appear front in merged whole window. */
+ if (EQ (xww->type, Qwebkit)
+ && (xww->width != text_area_width || xww->height != text_area_height))
+ {
+ Lisp_Object xwl;
+ XSETXWIDGET (xwl, xww);
+ Fxwidget_resize (xwl,
+ make_int (text_area_width),
+ make_int (text_area_height));
+ }
+
clip_left = max (0, text_area_x - x);
clip_right = max (clip_left,
min (xww->width, text_area_x + text_area_width - x));
@@ -650,8 +734,14 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
/* Has it moved? */
if (moved)
- gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)),
- xv->widgetwindow, x + clip_left, y + clip_top);
+ {
+#if defined (USE_GTK)
+ gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)),
+ xv->widgetwindow, x + clip_left, y + clip_top);
+#elif defined (NS_IMPL_COCOA)
+ nsxwidget_move_view (xv, x + clip_left, y + clip_top);
+#endif
+ }
/* Clip the widget window if some parts happen to be outside
drawable area. An Emacs window is not a gtk window. A gtk window
@@ -662,10 +752,16 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
|| xv->clip_bottom != clip_bottom
|| xv->clip_top != clip_top || xv->clip_left != clip_left)
{
+#if defined (USE_GTK)
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);
+#elif defined (NS_IMPL_COCOA)
+ nsxwidget_resize_view (xv, clip_right - clip_left,
+ clip_bottom - clip_top);
+ nsxwidget_move_widget_in_view (xv, -clip_left, -clip_top);
+#endif
xv->clip_right = clip_right;
xv->clip_bottom = clip_bottom;
@@ -679,21 +775,65 @@ x_draw_xwidget_glyph_string (struct glyph_string *s)
xwidgets background. It's just a visual glitch though. */
if (!xwidget_hidden (xv))
{
+#if defined (USE_GTK)
gtk_widget_queue_draw (xv->widgetwindow);
gtk_widget_queue_draw (xv->widget);
+#elif defined (NS_IMPL_COCOA)
+ nsxwidget_set_needsdisplay (xv);
+#endif
}
}
-/* Macro that checks WEBKIT_IS_WEB_VIEW (xw->widget_osr) first. */
+static bool
+xwidget_is_web_view (struct xwidget *xw)
+{
+#if defined (USE_GTK)
+ return xw->widget_osr != NULL && WEBKIT_IS_WEB_VIEW (xw->widget_osr);
+#elif defined (NS_IMPL_COCOA)
+ return nsxwidget_is_web_view (xw);
+#endif
+}
+
+/* Macro that checks xwidget hold webkit web view first. */
#define WEBKIT_FN_INIT() \
CHECK_XWIDGET (xwidget); \
struct xwidget *xw = XXWIDGET (xwidget); \
- if (!xw->widget_osr || !WEBKIT_IS_WEB_VIEW (xw->widget_osr)) \
+ if (!xwidget_is_web_view (xw)) \
{ \
- printf ("ERROR xw->widget_osr does not hold a webkit instance\n"); \
+ message ("ERROR xwidget does not hold a webkit instance\n"); \
return Qnil; \
}
+DEFUN ("xwidget-webkit-uri",
+ Fxwidget_webkit_uri, Sxwidget_webkit_uri,
+ 1, 1, 0,
+ doc: /* Get the current URL of XWIDGET webkit. */)
+ (Lisp_Object xwidget)
+{
+ WEBKIT_FN_INIT ();
+#if defined (USE_GTK)
+ WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+ return build_string (webkit_web_view_get_uri (wkwv));
+#elif defined (NS_IMPL_COCOA)
+ return nsxwidget_webkit_uri (xw);
+#endif
+}
+
+DEFUN ("xwidget-webkit-title",
+ Fxwidget_webkit_title, Sxwidget_webkit_title,
+ 1, 1, 0,
+ doc: /* Get the current title of XWIDGET webkit. */)
+ (Lisp_Object xwidget)
+{
+ WEBKIT_FN_INIT ();
+#if defined (USE_GTK)
+ WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+ return build_string (webkit_web_view_get_title (wkwv));
+#elif defined (NS_IMPL_COCOA)
+ return nsxwidget_webkit_title (xw);
+#endif
+}
+
DEFUN ("xwidget-webkit-goto-uri",
Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri,
2, 2, 0,
@@ -703,7 +843,32 @@ DEFUN ("xwidget-webkit-goto-uri",
WEBKIT_FN_INIT ();
CHECK_STRING (uri);
uri = ENCODE_FILE (uri);
+#if defined (USE_GTK)
webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr), SSDATA (uri));
+#elif defined (NS_IMPL_COCOA)
+ nsxwidget_webkit_goto_uri (xw, SSDATA (uri));
+#endif
+ return Qnil;
+}
+
+DEFUN ("xwidget-webkit-goto-history",
+ Fxwidget_webkit_goto_history, Sxwidget_webkit_goto_history,
+ 2, 2, 0,
+ doc: /* Make the XWIDGET webkit load REL-POS (-1, 0, 1) page in browse history. */)
+ (Lisp_Object xwidget, Lisp_Object rel_pos)
+{
+ WEBKIT_FN_INIT ();
+ CHECK_RANGED_INTEGER (rel_pos, -1, 1); /* -1, 0, 1 */
+#if defined (USE_GTK)
+ WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr);
+ switch (XFIXNAT (rel_pos)) {
+ case -1: webkit_web_view_go_back (wkwv); break;
+ case 0: webkit_web_view_reload (wkwv); break;
+ case 1: webkit_web_view_go_forward (wkwv); break;
+ }
+#elif defined (NS_IMPL_COCOA)
+ nsxwidget_webkit_goto_history (xw, XFIXNAT (rel_pos));
+#endif
return Qnil;
}
@@ -717,14 +882,19 @@ DEFUN ("xwidget-webkit-zoom",
if (FLOATP (factor))
{
double zoom_change = XFLOAT_DATA (factor);
+#if defined (USE_GTK)
webkit_web_view_set_zoom_level
(WEBKIT_WEB_VIEW (xw->widget_osr),
webkit_web_view_get_zoom_level
(WEBKIT_WEB_VIEW (xw->widget_osr)) + zoom_change);
+#elif defined (NS_IMPL_COCOA)
+ nsxwidget_webkit_zoom (xw, zoom_change);
+#endif
}
return Qnil;
}
+#if defined(USE_GTK)
/* Save script and fun in the script/callback save vector and return
its index. */
static ptrdiff_t
@@ -746,6 +916,7 @@ save_script_callback (struct xwidget *xw, Lisp_Object script, Lisp_Object fun)
ASET (cbs, idx, Fcons (make_mint_ptr (xlispstrdup (script)), fun));
return idx;
}
+#endif
DEFUN ("xwidget-webkit-execute-script",
Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script,
@@ -757,11 +928,15 @@ argument procedure FUN.*/)
{
WEBKIT_FN_INIT ();
CHECK_STRING (script);
- if (!NILP (fun) && !FUNCTIONP (fun))
+ /* FUN will not be garbage collected if it is defined with `defun'
+ instead of `lambda'. If it is garbage collected even though it
+ is `defun', we can counter by pinning the FUN's symbol. */
+ if (!NILP (fun) && !SYMBOLP (fun) && !NILP (Ffboundp (fun)))
wrong_type_argument (Qinvalid_function, fun);
script = ENCODE_SYSTEM (script);
+#if defined (USE_GTK)
/* Protect script and fun during GC. */
intptr_t idx = save_script_callback (xw, script, fun);
@@ -775,6 +950,9 @@ argument procedure FUN.*/)
NULL, /* cancelable */
webkit_javascript_finished_cb,
(gpointer) idx);
+#elif defined (NS_IMPL_COCOA)
+ nsxwidget_webkit_execute_script (xw, SSDATA (script), fun);
+#endif
return Qnil;
}
@@ -793,6 +971,7 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
xw->height = h;
/* If there is an offscreen widget resize it first. */
+#if defined (USE_GTK)
if (xw->widget_osr)
{
gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
@@ -801,6 +980,9 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width,
xw->height);
}
+#elif defined (NS_IMPL_COCOA)
+ nsxwidget_resize (xw);
+#endif
for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail))
{
@@ -808,8 +990,14 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0,
{
struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail));
if (XXWIDGET (xv->model) == xw)
+ {
+#if defined (USE_GTK)
gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width,
xw->height);
+#elif defined (NS_IMPL_COCOA)
+ nsxwidget_resize_view(xv, xw->width, xw->height);
+#endif
+ }
}
}
@@ -828,9 +1016,13 @@ Emacs allocated area accordingly. */)
(Lisp_Object xwidget)
{
CHECK_XWIDGET (xwidget);
+#if defined (USE_GTK)
GtkRequisition requisition;
gtk_widget_size_request (XXWIDGET (xwidget)->widget_osr, &requisition);
return list2i (requisition.width, requisition.height);
+#elif defined (NS_IMPL_COCOA)
+ return nsxwidget_get_size(XXWIDGET (xwidget));
+#endif
}
DEFUN ("xwidgetp",
@@ -907,14 +1099,19 @@ DEFUN ("delete-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);
+#if defined (USE_GTK)
+ gtk_widget_destroy (xv->widgetwindow);
/* 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);
+#elif defined (NS_IMPL_COCOA)
+ nsxwidget_delete_view (xv);
+#endif
+
return Qnil;
}
@@ -1020,7 +1217,10 @@ syms_of_xwidget (void)
defsubr (&Sxwidget_query_on_exit_flag);
defsubr (&Sset_xwidget_query_on_exit_flag);
+ defsubr (&Sxwidget_webkit_uri);
+ defsubr (&Sxwidget_webkit_title);
defsubr (&Sxwidget_webkit_goto_uri);
+ defsubr (&Sxwidget_webkit_goto_history);
defsubr (&Sxwidget_webkit_zoom);
defsubr (&Sxwidget_webkit_execute_script);
DEFSYM (Qwebkit, "webkit");
@@ -1191,11 +1391,19 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix)
xwidget_end_redisplay (w->current_matrix); */
struct xwidget_view *xv
= xwidget_view_lookup (glyph->u.xwidget, w);
+#if defined (USE_GTK)
/* FIXME: Is it safe to assume xwidget_view_lookup
always succeeds here? If so, this comment can be removed.
If not, the code probably needs fixing. */
eassume (xv);
xwidget_touch (xv);
+#elif defined (NS_IMPL_COCOA)
+ /* In NS xwidget, xv can be NULL for the second or
+ later views for a model, the result of 1 to 1
+ model view relation enforcement. */
+ if (xv)
+ xwidget_touch (xv);
+#endif
}
}
}
@@ -1212,9 +1420,21 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix)
if (XWINDOW (xv->w) == w)
{
if (xwidget_touched (xv))
- xwidget_show_view (xv);
+ {
+#if defined (USE_GTK)
+ xwidget_show_view (xv);
+#elif defined (NS_IMPL_COCOA)
+ nsxwidget_show_view (xv);
+#endif
+ }
else
- xwidget_hide_view (xv);
+ {
+#if defined (USE_GTK)
+ xwidget_hide_view (xv);
+#elif defined (NS_IMPL_COCOA)
+ nsxwidget_hide_view (xv);
+#endif
+ }
}
}
}
@@ -1233,6 +1453,7 @@ kill_buffer_xwidgets (Lisp_Object buffer)
{
CHECK_XWIDGET (xwidget);
struct xwidget *xw = XXWIDGET (xwidget);
+#if defined (USE_GTK)
if (xw->widget_osr && xw->widgetwindow_osr)
{
gtk_widget_destroy (xw->widget_osr);
@@ -1246,6 +1467,9 @@ kill_buffer_xwidgets (Lisp_Object buffer)
xfree (xmint_pointer (XCAR (cb)));
ASET (xw->script_callbacks, idx, Qnil);
}
+#elif defined (NS_IMPL_COCOA)
+ nsxwidget_kill (xw);
+#endif
}
}
}