EmacsFixed);
}
+#if defined HAVE_XWIDGETS && defined HAVE_PGTK
+
+static EmacsFixedClass *
+EMACS_FIXED_GET_CLASS (GtkWidget *widget)
+{
+ return G_TYPE_INSTANCE_GET_CLASS (widget, emacs_fixed_get_type (),
+ EmacsFixedClass);
+}
+
+struct GtkFixedPrivateL
+{
+ GList *children;
+};
+
+static void
+emacs_fixed_gtk_widget_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ /* For xwidgets.
+
+ This basically re-implements the base class method and adds an
+ additional case for an xwidget view.
+
+ It would be nicer if the bse class method could be called first,
+ and the xview modification only would remain here. It wasn't
+ possible to solve it that way yet. */
+ EmacsFixedClass *klass;
+ GtkWidgetClass *parent_class;
+ struct GtkFixedPrivateL *priv;
+
+ klass = EMACS_FIXED_GET_CLASS (widget);
+ parent_class = g_type_class_peek_parent (klass);
+ parent_class->size_allocate (widget, allocation);
+
+ priv = G_TYPE_INSTANCE_GET_PRIVATE (widget, GTK_TYPE_FIXED,
+ struct GtkFixedPrivateL);
+
+ gtk_widget_set_allocation (widget, allocation);
+
+ if (gtk_widget_get_has_window (widget))
+ {
+ if (gtk_widget_get_realized (widget))
+ gdk_window_move_resize (gtk_widget_get_window (widget),
+ allocation->x,
+ allocation->y,
+ allocation->width,
+ allocation->height);
+ }
+
+ for (GList *children = priv->children; children; children = children->next)
+ {
+ GtkFixedChild *child = children->data;
+
+ if (!gtk_widget_get_visible (child->widget))
+ continue;
+
+ GtkRequisition child_requisition;
+ gtk_widget_get_preferred_size (child->widget, &child_requisition, NULL);
+
+ GtkAllocation child_allocation;
+ child_allocation.x = child->x;
+ child_allocation.y = child->y;
+
+ if (!gtk_widget_get_has_window (widget))
+ {
+ child_allocation.x += allocation->x;
+ child_allocation.y += allocation->y;
+ }
+
+ child_allocation.width = child_requisition.width;
+ child_allocation.height = child_requisition.height;
+
+ struct xwidget_view *xv
+ = g_object_get_data (G_OBJECT (child->widget), XG_XWIDGET_VIEW);
+ if (xv)
+ {
+ child_allocation.width = xv->clip_right;
+ child_allocation.height = xv->clip_bottom - xv->clip_top;
+ }
+
+ gtk_widget_size_allocate (child->widget, &child_allocation);
+ }
+}
+
+#endif /* HAVE_XWIDGETS && HAVE_PGTK */
+
static void
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;
+#if defined HAVE_XWIDGETS && defined HAVE_PGTK
+ widget_class->size_allocate = emacs_fixed_gtk_widget_size_allocate;
+#endif
g_type_class_add_private (klass, sizeof (EmacsFixedPrivate));
}
block_input ();
+#ifdef HAVE_XWIDGETS
+ kill_frame_xwidget_views (f);
+#endif
free_frame_faces (f);
if (FRAME_X_OUTPUT (f)->scale_factor_atimer != NULL)
block_input ();
+#ifdef HAVE_XWIDGETS
+ /* "Copy" xwidget views in the area that will be scrolled. */
+ GtkWidget *tem, *parent = FRAME_GTK_WIDGET (f);
+ GList *children = gtk_container_get_children (GTK_CONTAINER (parent));
+ GList *iter;
+ struct xwidget_view *view;
+
+ for (iter = children; iter; iter = iter->next)
+ {
+ tem = iter->data;
+ view = g_object_get_data (G_OBJECT (tem), XG_XWIDGET_VIEW);
+
+ if (view && !view->hidden)
+ {
+ int window_y = view->y + view->clip_top;
+ int window_height = view->clip_bottom - view->clip_top;
+
+ Emacs_Rectangle r1, r2, result;
+ r1.x = w->pixel_left;
+ r1.y = from_y;
+ r1.width = w->pixel_width;
+ r1.height = height;
+ r2 = r1;
+ r2.y = window_y;
+ r2.height = window_height;
+
+ /* The window is offscreen, just unmap it. */
+ if (window_height == 0)
+ {
+ view->hidden = true;
+ gtk_widget_hide (tem);
+ continue;
+ }
+
+ bool intersects_p =
+ gui_intersect_rectangles (&r1, &r2, &result);
+
+ if (XWINDOW (view->w) == w && intersects_p)
+ {
+ int y = view->y + (to_y - from_y);
+ int text_area_x, text_area_y, text_area_width, text_area_height;
+ int clip_top, clip_bottom;
+
+ window_box (w, view->area, &text_area_x, &text_area_y,
+ &text_area_width, &text_area_height);
+
+ view->y = y;
+
+ clip_top = 0;
+ clip_bottom = XXWIDGET (view->model)->height;
+
+ if (y < text_area_y)
+ clip_top = text_area_y - y;
+
+ if ((y + clip_bottom) > (text_area_y + text_area_height))
+ {
+ clip_bottom -= (y + clip_bottom) - (text_area_y + text_area_height);
+ }
+
+ view->clip_top = clip_top;
+ view->clip_bottom = clip_bottom;
+
+ /* This means the view has moved offscreen. Unmap
+ it and hide it here. */
+ if ((view->clip_bottom - view->clip_top) <= 0)
+ {
+ view->hidden = true;
+ gtk_widget_hide (tem);
+ }
+ else
+ {
+ gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (f)),
+ tem, view->x + view->clip_left,
+ view->y + view->clip_top);
+ gtk_widget_set_size_request (tem, view->clip_right - view->clip_left,
+ view->clip_bottom - view->clip_top);
+ gtk_widget_queue_allocate (tem);
+ }
+ }
+ }
+ }
+
+ g_list_free (children);
+#endif
+
/* Cursor off. Will be switched on again in x_update_window_end. */
gui_clear_cursor (w);
return mod;
}
-static int
+int
pgtk_emacs_to_gtk_modifiers (struct pgtk_display_info *dpyinfo, int state)
{
int mod_ctrl;
#include <webkit2/webkit2.h>
#include <JavaScriptCore/JavaScript.h>
#include <cairo.h>
+#ifndef HAVE_PGTK
#include <X11/Xlib.h>
+#else
+#include <gtk/gtk.h>
+#endif
#ifdef HAVE_XINPUT2
#include <X11/extensions/XInput2.h>
#endif
static uint32_t xwidget_counter = 0;
#ifdef USE_GTK
+#ifdef HAVE_X_WINDOWS
static Lisp_Object x_window_to_xwv_map;
+#endif
static gboolean offscreen_damage_event (GtkWidget *, GdkEvent *, gpointer);
static void synthesize_focus_in_event (GtkWidget *);
static GdkDevice *find_suitable_keyboard (struct frame *);
gpointer);
#endif
+#ifdef HAVE_PGTK
+static int
+xw_forward_event_translate (GdkEvent *event, struct xwidget_view *xv,
+ struct xwidget *xw)
+{
+ GtkWidget *widget;
+ int new_x, new_y;
+
+ switch (event->type)
+ {
+ case GDK_BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ case GDK_2BUTTON_PRESS:
+ case GDK_3BUTTON_PRESS:
+ widget = find_widget_at_pos (xw->widgetwindow_osr,
+ lrint (event->button.x - xv->clip_left),
+ lrint (event->button.y - xv->clip_top),
+ &new_x, &new_y);
+ if (widget)
+ {
+ event->any.window = gtk_widget_get_window (widget);
+ event->button.x = new_x;
+ event->button.y = new_y;
+ return 1;
+ }
+ return 0;
+ case GDK_SCROLL:
+ widget = find_widget_at_pos (xw->widgetwindow_osr,
+ lrint (event->scroll.x - xv->clip_left),
+ lrint (event->scroll.y - xv->clip_top),
+ &new_x, &new_y);
+ if (widget)
+ {
+ event->any.window = gtk_widget_get_window (widget);
+ event->scroll.x = new_x;
+ event->scroll.y = new_y;
+ return 1;
+ }
+ return 0;
+ case GDK_MOTION_NOTIFY:
+ widget = find_widget_at_pos (xw->widgetwindow_osr,
+ lrint (event->motion.x - xv->clip_left),
+ lrint (event->motion.y - xv->clip_top),
+ &new_x, &new_y);
+ if (widget)
+ {
+ event->any.window = gtk_widget_get_window (widget);
+ event->motion.x = new_x;
+ event->motion.y = new_y;
+ return 1;
+ }
+ return 0;
+ case GDK_ENTER_NOTIFY:
+ case GDK_LEAVE_NOTIFY:
+ widget = find_widget_at_pos (xw->widgetwindow_osr,
+ lrint (event->crossing.x - xv->clip_left),
+ lrint (event->crossing.y - xv->clip_top),
+ &new_x, &new_y);
+ if (widget)
+ {
+ event->any.window = gtk_widget_get_window (widget);
+ event->crossing.x = new_x;
+ event->crossing.y = new_y;
+ return 1;
+ }
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+static gboolean
+xw_forward_event_from_view (GtkWidget *widget, GdkEvent *event,
+ gpointer user_data)
+{
+ struct xwidget_view *xv = user_data;
+ struct xwidget *xw = XXWIDGET (xv->model);
+ GdkEvent *eventcopy;
+ bool translated_p;
+
+ if (NILP (xw->buffer))
+ return TRUE;
+
+ eventcopy = gdk_event_copy (event);
+ translated_p = xw_forward_event_translate (eventcopy, xv, xw);
+ record_osr_embedder (xv);
+
+ g_object_ref (eventcopy->any.window);
+ if (translated_p)
+ gtk_main_do_event (eventcopy);
+ gdk_event_free (eventcopy);
+
+ /* Don't propagate this event further. */
+ return TRUE;
+}
+#endif
DEFUN ("make-xwidget",
Fmake_xwidget, Smake_xwidget,
# endif
xw->widgetwindow_osr = gtk_offscreen_window_new ();
-#ifndef HAVE_PGTK
gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width,
xw->height);
-#else
gtk_container_check_resize (GTK_CONTAINER (xw->widgetwindow_osr));
-#endif
if (EQ (xw->type, Qwebkit))
{
if (character < 32)
character += '_';
+#ifndef HAVE_PGTK
if (f)
modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f), modifiers);
else
modifiers = 0;
+#else
+ if (f)
+ modifiers = pgtk_emacs_to_gtk_modifiers (FRAME_DISPLAY_INFO (f), modifiers);
+ else
+ modifiers = 0;
+#endif
}
else if (SYMBOLP (event))
{
++off;
}
+#ifndef HAVE_PGTK
if (f)
modifiers = x_emacs_to_x_modifiers (FRAME_DISPLAY_INFO (f),
XFIXNUM (XCAR (XCDR (decoded))));
else
modifiers = 0;
+#else
+ if (f)
+ modifiers = pgtk_emacs_to_gtk_modifiers (FRAME_DISPLAY_INFO (f),
+ XFIXNUM (XCAR (XCDR (decoded))));
+ else
+ modifiers = 0;
+#endif
if (found)
keycode = off + 0xff00;
define_cursors (struct xwidget *xw, WebKitHitTestResult *res)
{
struct xwidget_view *xvw;
+#ifdef HAVE_PGTK
+ GdkWindow *wdesc;
+#endif
xw->hit_result = webkit_hit_test_result_get_context (res);
if (XXWIDGET (xvw->model) == xw)
{
xvw->cursor = cursor_for_hit (xw->hit_result, xvw->frame);
+#ifdef HAVE_X_WINDOWS
if (xvw->wdesc != None)
XDefineCursor (xvw->dpy, xvw->wdesc, xvw->cursor);
+#else
+ if (gtk_widget_get_realized (xvw->widget))
+ {
+ wdesc = gtk_widget_get_window (xvw->widget);
+ gdk_window_set_cursor (wdesc, xvw->cursor);
+ }
+#endif
}
}
}
return TRUE;
}
+#ifdef HAVE_X_WINDOWS
static void
xwidget_button_1 (struct xwidget_view *view,
gdk_event_free (xg_event);
}
+#endif /* HAVE_X_WINDOWS */
+
static void
synthesize_focus_in_event (GtkWidget *offscreen_window)
{
gdk_event_free (focus_event);
}
+#ifdef HAVE_X_WINDOWS
struct xwidget_view *
xwidget_view_from_window (Window wdesc)
{
return XXWIDGET_VIEW (xwv);
}
+#endif
static void
xwidget_show_view (struct xwidget_view *xv)
{
xv->hidden = false;
+#ifdef HAVE_X_WINDOWS
XMoveWindow (xv->dpy, xv->wdesc,
xv->x + xv->clip_left,
xv->y + xv->clip_top);
XMapWindow (xv->dpy, xv->wdesc);
XFlush (xv->dpy);
+#else
+ gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (xv->frame)),
+ xv->widget, xv->x + xv->clip_left,
+ xv->y + xv->clip_top);
+ gtk_widget_show_all (xv->widget);
+#endif
}
/* Hide an xwidget view. */
xwidget_hide_view (struct xwidget_view *xv)
{
xv->hidden = true;
+#ifdef HAVE_X_WINDOWS
XUnmapWindow (xv->dpy, xv->wdesc);
XFlush (xv->dpy);
+#else
+ gtk_widget_hide (xv->widget);
+#endif
}
+#ifndef HAVE_PGTK
static void
xv_do_draw (struct xwidget_view *xw, struct xwidget *w)
{
unblock_input ();
}
+#else
+static void
+xwidget_view_draw_cb (GtkWidget *widget, cairo_t *cr,
+ gpointer data)
+{
+ struct xwidget_view *view = data;
+ struct xwidget *w = XXWIDGET (view->model);
+ GtkOffscreenWindow *wnd;
+ cairo_surface_t *surface;
+
+ if (NILP (w->buffer))
+ return;
+
+ block_input ();
+ wnd = GTK_OFFSCREEN_WINDOW (w->widgetwindow_osr);
+ surface = gtk_offscreen_window_get_surface (wnd);
+
+ cairo_save (cr);
+ if (surface)
+ {
+ cairo_translate (cr, -view->clip_left,
+ -view->clip_top);
+ cairo_set_source_surface (cr, surface, 0, 0);
+ cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint (cr);
+ }
+ cairo_restore (cr);
+
+ unblock_input ();
+}
+#endif
/* When the off-screen webkit master view changes this signal is called.
It copies the bitmap from the off-screen instance. */
if (XWIDGET_VIEW_P (XCAR (tail)))
{
struct xwidget_view *view = XXWIDGET_VIEW (XCAR (tail));
-
+#ifdef HAVE_X_WINDOWS
if (view->wdesc && XXWIDGET (view->model) == xwidget)
xv_do_draw (view, XXWIDGET (view->model));
+#else
+ gtk_widget_queue_draw (view->widget);
+#endif
}
}
return FALSE;
}
+#ifdef HAVE_X_WINDOWS
void
xwidget_expose (struct xwidget_view *xv)
{
xv_do_draw (xv, xw);
}
+#endif
#endif /* USE_GTK */
void
XSETWINDOW (xv->w, s->w);
XSETXWIDGET (xv->model, xww);
-#ifdef USE_GTK
+#ifdef HAVE_X_WINDOWS
xv->dpy = FRAME_X_DISPLAY (s->f);
xv->x = x;
xv->clip_bottom = xww->height;
xv->wdesc = None;
+ xv->frame = s->f;
+ xv->cursor = cursor_for_hit (xww->hit_result, s->f);
+ xv->just_resized = false;
+#elif defined HAVE_PGTK
+ xv->dpyinfo = FRAME_DISPLAY_INFO (s->f);
+ xv->widget = gtk_drawing_area_new ();
+ gtk_widget_set_app_paintable (xv->widget, TRUE);
+ gtk_widget_add_events (xv->widget, GDK_ALL_EVENTS_MASK);
+ gtk_container_add (GTK_CONTAINER (FRAME_GTK_WIDGET (s->f)),
+ xv->widget);
+
+ g_signal_connect (xv->widget, "draw",
+ G_CALLBACK (xwidget_view_draw_cb), xv);
+ g_signal_connect (xv->widget, "event",
+ G_CALLBACK (xw_forward_event_from_view), xv);
+
+ g_object_set_data (G_OBJECT (xv->widget), XG_XWIDGET_VIEW, xv);
+
+ xv->x = x;
+ xv->y = y;
+
+ xv->clip_left = 0;
+ xv->clip_right = xww->width;
+ xv->clip_top = 0;
+ xv->clip_bottom = xww->height;
+
xv->frame = s->f;
xv->cursor = cursor_for_hit (xww->hit_result, s->f);
xv->just_resized = false;
bool moved = (xv->x + xv->clip_left != x + clip_left
|| xv->y + xv->clip_top != y + clip_top);
-#ifdef USE_GTK
+#ifdef HAVE_X_WINDOWS
bool wdesc_was_none = xv->wdesc == None;
#endif
xv->x = x;
xv->y = y;
-#ifdef USE_GTK
+#ifdef HAVE_X_WINDOWS
block_input ();
if (xv->wdesc == None)
{
moved = false;
}
#endif
+#ifdef HAVE_PGTK
+ block_input ();
+#endif
/* Has it moved? */
if (moved)
{
-#ifdef USE_GTK
+#ifdef HAVE_X_WINDOWS
XMoveResizeWindow (xv->dpy, xv->wdesc, x + clip_left, y + clip_top,
clip_right - clip_left, clip_bottom - clip_top);
XFlush (xv->dpy);
cairo_xlib_surface_set_size (xv->cr_surface, clip_right - clip_left,
clip_bottom - clip_top);
+#elif defined HAVE_PGTK
+ gtk_widget_set_size_request (xv->widget, clip_right - clip_left,
+ clip_bottom - clip_top);
+ gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (xv->frame)),
+ xv->widget, x + clip_left, y + clip_top);
+ gtk_widget_queue_allocate (xv->widget);
#elif defined NS_IMPL_COCOA
nsxwidget_move_view (xv, x + clip_left, y + clip_top);
#endif
|| xv->clip_top != clip_top || xv->clip_left != clip_left)
{
#ifdef USE_GTK
+#ifdef HAVE_X_WINDOWS
if (!wdesc_was_none && !moved)
{
if (clip_right - clip_left <= 0
cairo_xlib_surface_set_size (xv->cr_surface, clip_right - clip_left,
clip_bottom - clip_top);
}
+#else
+ gtk_widget_set_size_request (xv->widget, clip_right - clip_left,
+ clip_bottom - clip_top);
+ gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (xv->frame)),
+ xv->widget, x + clip_left, y + clip_top);
+#endif
#elif defined NS_IMPL_COCOA
nsxwidget_resize_view (xv, clip_right - clip_left,
clip_bottom - clip_top);
#endif
}
}
-#ifdef USE_GTK
+#ifdef HAVE_X_WINDOWS
else
{
XSetWindowBackground (xv->dpy, xv->wdesc,
#ifdef USE_GTK
struct xwidget *xw = XXWIDGET (xv->model);
GdkWindow *w;
-
+#ifdef HAVE_X_WINDOWS
if (xv->wdesc != None)
{
block_input ();
Fremhash (make_fixnum (xv->wdesc), x_window_to_xwv_map);
unblock_input ();
}
+#else
+ gtk_widget_destroy (xv->widget);
+#endif
if (xw->embedder_view == xv && !NILP (xw->buffer))
{
internal_xwidget_view_list = Qnil;
staticpro (&internal_xwidget_view_list);
-#ifdef USE_GTK
- x_window_to_xwv_map = CALLN (Fmake_hash_table, QCtest, Qeq);
+#ifdef HAVE_X_WINDOWS
+ x_window_to_xwv_map = CALLN (Fmake_hash_table, QCtest,); Qeq
staticpro (&x_window_to_xwv_map);
#endif
}
}
-#ifdef USE_GTK
+#ifdef HAVE_X_WINDOWS
void
lower_frame_xwidget_views (struct frame *f)
{
XLowerWindow (xv->dpy, xv->wdesc);
}
}
+#endif
void
kill_frame_xwidget_views (struct frame *f)
for (; CONSP (rem); rem = XCDR (rem))
Fdelete_xwidget_view (XCAR (rem));
}
-#endif
static void
kill_xwidget (struct xwidget *xw)