4429 lines
164 KiB
Diff
4429 lines
164 KiB
Diff
diff -up thunderbird-60.5.0/widget/gtk/GtkCompositorWidget.cpp.wayland thunderbird-60.5.0/widget/gtk/GtkCompositorWidget.cpp
|
|
--- thunderbird-60.5.0/widget/gtk/GtkCompositorWidget.cpp.wayland 2019-01-22 20:44:04.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/GtkCompositorWidget.cpp 2019-02-05 14:26:16.973316654 +0100
|
|
@@ -38,7 +38,9 @@ GtkCompositorWidget::GtkCompositorWidget
|
|
|
|
// Grab the window's visual and depth
|
|
XWindowAttributes windowAttrs;
|
|
- XGetWindowAttributes(mXDisplay, mXWindow, &windowAttrs);
|
|
+ if (!XGetWindowAttributes(mXDisplay, mXWindow, &windowAttrs)) {
|
|
+ NS_WARNING("GtkCompositorWidget(): XGetWindowAttributes() failed!");
|
|
+ }
|
|
|
|
Visual* visual = windowAttrs.visual;
|
|
int depth = windowAttrs.depth;
|
|
diff -up thunderbird-60.5.0/widget/gtk/moz.build.wayland thunderbird-60.5.0/widget/gtk/moz.build
|
|
--- thunderbird-60.5.0/widget/gtk/moz.build.wayland 2019-01-22 20:44:04.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/moz.build 2019-02-05 14:26:16.974316651 +0100
|
|
@@ -99,6 +99,7 @@ if CONFIG['MOZ_X11']:
|
|
if CONFIG['MOZ_WAYLAND']:
|
|
UNIFIED_SOURCES += [
|
|
'nsClipboardWayland.cpp',
|
|
+ 'nsWaylandDisplay.cpp',
|
|
'WindowSurfaceWayland.cpp',
|
|
]
|
|
|
|
@@ -123,6 +124,7 @@ include('/ipc/chromium/chromium-config.m
|
|
FINAL_LIBRARY = 'xul'
|
|
|
|
LOCAL_INCLUDES += [
|
|
+ '/layout/base',
|
|
'/layout/generic',
|
|
'/layout/xul',
|
|
'/other-licenses/atk-1.0',
|
|
diff -up thunderbird-60.5.0/widget/gtk/mozcontainer.cpp.wayland thunderbird-60.5.0/widget/gtk/mozcontainer.cpp
|
|
--- thunderbird-60.5.0/widget/gtk/mozcontainer.cpp.wayland 2019-01-22 20:44:04.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/mozcontainer.cpp 2019-02-05 15:09:24.116970135 +0100
|
|
@@ -1,4 +1,4 @@
|
|
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
*/
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
@@ -7,9 +7,10 @@
|
|
|
|
#include "mozcontainer.h"
|
|
#include <gtk/gtk.h>
|
|
-#ifdef MOZ_WAYLAND
|
|
#include <gdk/gdkx.h>
|
|
-#include <gdk/gdkwayland.h>
|
|
+#ifdef MOZ_WAYLAND
|
|
+#include "nsWaylandDisplay.h"
|
|
+#include <wayland-egl.h>
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <dlfcn.h>
|
|
@@ -19,12 +20,20 @@
|
|
#include "maiRedundantObjectFactory.h"
|
|
#endif
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
+using namespace mozilla;
|
|
+using namespace mozilla::widget;
|
|
+#endif
|
|
+
|
|
/* init methods */
|
|
static void moz_container_class_init(MozContainerClass *klass);
|
|
static void moz_container_init(MozContainer *container);
|
|
|
|
/* widget class methods */
|
|
static void moz_container_map(GtkWidget *widget);
|
|
+#if defined(MOZ_WAYLAND)
|
|
+static gboolean moz_container_map_wayland(GtkWidget *widget, GdkEventAny *event);
|
|
+#endif
|
|
static void moz_container_unmap(GtkWidget *widget);
|
|
static void moz_container_realize(GtkWidget *widget);
|
|
static void moz_container_size_allocate(GtkWidget *widget,
|
|
@@ -114,29 +123,6 @@ void moz_container_put(MozContainer *con
|
|
gtk_widget_set_parent(child_widget, GTK_WIDGET(container));
|
|
}
|
|
|
|
-void moz_container_move(MozContainer *container, GtkWidget *child_widget,
|
|
- gint x, gint y, gint width, gint height) {
|
|
- MozContainerChild *child;
|
|
- GtkAllocation new_allocation;
|
|
-
|
|
- child = moz_container_get_child(container, child_widget);
|
|
-
|
|
- child->x = x;
|
|
- child->y = y;
|
|
-
|
|
- new_allocation.x = x;
|
|
- new_allocation.y = y;
|
|
- new_allocation.width = width;
|
|
- new_allocation.height = height;
|
|
-
|
|
- /* printf("moz_container_move %p %p will allocate to %d %d %d %d\n",
|
|
- (void *)container, (void *)child_widget,
|
|
- new_allocation.x, new_allocation.y,
|
|
- new_allocation.width, new_allocation.height); */
|
|
-
|
|
- gtk_widget_size_allocate(child_widget, &new_allocation);
|
|
-}
|
|
-
|
|
/* static methods */
|
|
|
|
void moz_container_class_init(MozContainerClass *klass) {
|
|
@@ -146,6 +132,11 @@ void moz_container_class_init(MozContain
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
|
|
|
|
widget_class->map = moz_container_map;
|
|
+#if defined(MOZ_WAYLAND)
|
|
+ if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
|
|
+ widget_class->map_event = moz_container_map_wayland;
|
|
+ }
|
|
+#endif
|
|
widget_class->unmap = moz_container_unmap;
|
|
widget_class->realize = moz_container_realize;
|
|
widget_class->size_allocate = moz_container_size_allocate;
|
|
@@ -155,109 +146,81 @@ void moz_container_class_init(MozContain
|
|
container_class->add = moz_container_add;
|
|
}
|
|
|
|
-#if defined(MOZ_WAYLAND)
|
|
-static void registry_handle_global(void *data, struct wl_registry *registry,
|
|
- uint32_t name, const char *interface,
|
|
- uint32_t version) {
|
|
- MozContainer *container = MOZ_CONTAINER(data);
|
|
- if (strcmp(interface, "wl_subcompositor") == 0) {
|
|
- container->subcompositor = static_cast<wl_subcompositor *>(
|
|
- wl_registry_bind(registry, name, &wl_subcompositor_interface, 1));
|
|
- }
|
|
-}
|
|
-
|
|
-static void registry_handle_global_remove(void *data,
|
|
- struct wl_registry *registry,
|
|
- uint32_t name) {}
|
|
-
|
|
-static const struct wl_registry_listener registry_listener = {
|
|
- registry_handle_global, registry_handle_global_remove};
|
|
-#endif
|
|
-
|
|
void moz_container_init(MozContainer *container) {
|
|
gtk_widget_set_can_focus(GTK_WIDGET(container), TRUE);
|
|
gtk_container_set_resize_mode(GTK_CONTAINER(container), GTK_RESIZE_IMMEDIATE);
|
|
gtk_widget_set_redraw_on_allocate(GTK_WIDGET(container), FALSE);
|
|
|
|
#if defined(MOZ_WAYLAND)
|
|
- {
|
|
- GdkDisplay *gdk_display = gtk_widget_get_display(GTK_WIDGET(container));
|
|
- if (GDK_IS_WAYLAND_DISPLAY(gdk_display)) {
|
|
- // Available as of GTK 3.8+
|
|
- static auto sGdkWaylandDisplayGetWlDisplay =
|
|
- (wl_display * (*)(GdkDisplay *))
|
|
- dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
|
|
-
|
|
- wl_display *display = sGdkWaylandDisplayGetWlDisplay(gdk_display);
|
|
- wl_registry *registry = wl_display_get_registry(display);
|
|
- wl_registry_add_listener(registry, ®istry_listener, container);
|
|
- wl_display_dispatch(display);
|
|
- wl_display_roundtrip(display);
|
|
- }
|
|
- }
|
|
+ container->surface = nullptr;
|
|
+ container->subsurface = nullptr;
|
|
+ container->eglwindow = nullptr;
|
|
+ container->frame_callback_handler = nullptr;
|
|
+ // We can draw to x11 window any time.
|
|
+ container->ready_to_draw = GDK_IS_X11_DISPLAY(gdk_display_get_default());
|
|
+ container->surface_needs_clear = true;
|
|
#endif
|
|
}
|
|
|
|
#if defined(MOZ_WAYLAND)
|
|
-/* We want to draw to GdkWindow owned by mContainer from Compositor thread but
|
|
- * Gtk+ can be used in main thread only. So we create wayland wl_surface
|
|
- * and attach it as an overlay to GdkWindow.
|
|
- *
|
|
- * see gtk_clutter_embed_ensure_subsurface() at gtk-clutter-embed.c
|
|
- * for reference.
|
|
- */
|
|
-static gboolean moz_container_map_surface(MozContainer *container) {
|
|
- // Available as of GTK 3.8+
|
|
- static auto sGdkWaylandDisplayGetWlCompositor =
|
|
- (wl_compositor * (*)(GdkDisplay *))
|
|
- dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_compositor");
|
|
+static wl_surface *moz_container_get_gtk_container_surface(
|
|
+ MozContainer *container) {
|
|
static auto sGdkWaylandWindowGetWlSurface = (wl_surface * (*)(GdkWindow *))
|
|
dlsym(RTLD_DEFAULT, "gdk_wayland_window_get_wl_surface");
|
|
|
|
- GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(container));
|
|
- if (GDK_IS_X11_DISPLAY(display)) return false;
|
|
+ GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
|
|
+ return sGdkWaylandWindowGetWlSurface(window);
|
|
+}
|
|
|
|
- if (container->subsurface && container->surface) return true;
|
|
+static void frame_callback_handler(void *data, struct wl_callback *callback,
|
|
+ uint32_t time) {
|
|
+ MozContainer *container = MOZ_CONTAINER(data);
|
|
+ g_clear_pointer(&container->frame_callback_handler, wl_callback_destroy);
|
|
+ container->ready_to_draw = true;
|
|
+}
|
|
|
|
- if (!container->surface) {
|
|
- struct wl_compositor *compositor;
|
|
- compositor = sGdkWaylandDisplayGetWlCompositor(display);
|
|
- container->surface = wl_compositor_create_surface(compositor);
|
|
- }
|
|
+static const struct wl_callback_listener frame_listener = {
|
|
+ frame_callback_handler};
|
|
|
|
- if (!container->subsurface) {
|
|
- GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
|
|
- wl_surface *gtk_surface = sGdkWaylandWindowGetWlSurface(window);
|
|
- if (!gtk_surface) {
|
|
- // We requested the underlying wl_surface too early when container
|
|
- // is not realized yet. We'll try again before first rendering
|
|
- // to mContainer.
|
|
- return false;
|
|
- }
|
|
+static gboolean moz_container_map_wayland(GtkWidget *widget, GdkEventAny *event) {
|
|
+ MozContainer* container = MOZ_CONTAINER(widget);
|
|
|
|
- container->subsurface = wl_subcompositor_get_subsurface(
|
|
- container->subcompositor, container->surface, gtk_surface);
|
|
- gint x, y;
|
|
- gdk_window_get_position(window, &x, &y);
|
|
- wl_subsurface_set_position(container->subsurface, x, y);
|
|
- wl_subsurface_set_desync(container->subsurface);
|
|
+ if (container->ready_to_draw || container->frame_callback_handler) {
|
|
+ return FALSE;
|
|
+ }
|
|
|
|
- // Route input to parent wl_surface owned by Gtk+ so we get input
|
|
- // events from Gtk+.
|
|
- GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(container));
|
|
- wl_compositor *compositor = sGdkWaylandDisplayGetWlCompositor(display);
|
|
- wl_region *region = wl_compositor_create_region(compositor);
|
|
- wl_surface_set_input_region(container->surface, region);
|
|
- wl_region_destroy(region);
|
|
+ wl_surface *gtk_container_surface =
|
|
+ moz_container_get_gtk_container_surface(container);
|
|
+
|
|
+ if (gtk_container_surface) {
|
|
+ container->frame_callback_handler = wl_surface_frame(gtk_container_surface);
|
|
+ wl_callback_add_listener(container->frame_callback_handler, &frame_listener,
|
|
+ container);
|
|
}
|
|
- return true;
|
|
+
|
|
+ return FALSE;
|
|
}
|
|
|
|
-static void moz_container_unmap_surface(MozContainer *container) {
|
|
+static void moz_container_unmap_wayland(MozContainer *container) {
|
|
g_clear_pointer(&container->subsurface, wl_subsurface_destroy);
|
|
g_clear_pointer(&container->surface, wl_surface_destroy);
|
|
+ g_clear_pointer(&container->frame_callback_handler, wl_callback_destroy);
|
|
+
|
|
+ container->surface_needs_clear = true;
|
|
+ container->ready_to_draw = false;
|
|
}
|
|
|
|
+static gint moz_container_get_scale(MozContainer *container) {
|
|
+ static auto sGdkWindowGetScaleFactorPtr = (gint(*)(GdkWindow *))dlsym(
|
|
+ RTLD_DEFAULT, "gdk_window_get_scale_factor");
|
|
+
|
|
+ if (sGdkWindowGetScaleFactorPtr) {
|
|
+ GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
|
|
+ return (*sGdkWindowGetScaleFactorPtr)(window);
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
#endif
|
|
|
|
void moz_container_map(GtkWidget *widget) {
|
|
@@ -283,7 +246,9 @@ void moz_container_map(GtkWidget *widget
|
|
if (gtk_widget_get_has_window(widget)) {
|
|
gdk_window_show(gtk_widget_get_window(widget));
|
|
#if defined(MOZ_WAYLAND)
|
|
- moz_container_map_surface(MOZ_CONTAINER(widget));
|
|
+ if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
|
|
+ moz_container_map_wayland(widget, nullptr);
|
|
+ }
|
|
#endif
|
|
}
|
|
}
|
|
@@ -296,7 +261,9 @@ void moz_container_unmap(GtkWidget *widg
|
|
if (gtk_widget_get_has_window(widget)) {
|
|
gdk_window_hide(gtk_widget_get_window(widget));
|
|
#if defined(MOZ_WAYLAND)
|
|
- moz_container_unmap_surface(MOZ_CONTAINER(widget));
|
|
+ if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
|
|
+ moz_container_unmap_wayland(MOZ_CONTAINER(widget));
|
|
+ }
|
|
#endif
|
|
}
|
|
}
|
|
@@ -485,13 +452,62 @@ static void moz_container_add(GtkContain
|
|
|
|
#ifdef MOZ_WAYLAND
|
|
struct wl_surface *moz_container_get_wl_surface(MozContainer *container) {
|
|
- if (!container->subsurface || !container->surface) {
|
|
+ if (!container->surface) {
|
|
+ if (!container->ready_to_draw) {
|
|
+ return nullptr;
|
|
+ }
|
|
+ GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(container));
|
|
+
|
|
+ // Available as of GTK 3.8+
|
|
+ static auto sGdkWaylandDisplayGetWlCompositor =
|
|
+ (wl_compositor * (*)(GdkDisplay *))
|
|
+ dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_compositor");
|
|
+ struct wl_compositor *compositor =
|
|
+ sGdkWaylandDisplayGetWlCompositor(display);
|
|
+ container->surface = wl_compositor_create_surface(compositor);
|
|
+
|
|
+ nsWaylandDisplay *waylandDisplay = WaylandDisplayGet(display);
|
|
+ container->subsurface = wl_subcompositor_get_subsurface(
|
|
+ waylandDisplay->GetSubcompositor(), container->surface,
|
|
+ moz_container_get_gtk_container_surface(container));
|
|
+ WaylandDisplayRelease(waylandDisplay);
|
|
+
|
|
GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
|
|
- if (!gdk_window_is_visible(window)) return nullptr;
|
|
+ gint x, y;
|
|
+ gdk_window_get_position(window, &x, &y);
|
|
+ wl_subsurface_set_position(container->subsurface, x, y);
|
|
+ wl_subsurface_set_desync(container->subsurface);
|
|
|
|
- moz_container_map_surface(container);
|
|
+ // Route input to parent wl_surface owned by Gtk+ so we get input
|
|
+ // events from Gtk+.
|
|
+ wl_region *region = wl_compositor_create_region(compositor);
|
|
+ wl_surface_set_input_region(container->surface, region);
|
|
+ wl_region_destroy(region);
|
|
+
|
|
+ wl_surface_set_buffer_scale(container->surface,
|
|
+ moz_container_get_scale(container));
|
|
}
|
|
|
|
return container->surface;
|
|
}
|
|
+
|
|
+struct wl_egl_window *moz_container_get_wl_egl_window(MozContainer *container) {
|
|
+ if (!container->eglwindow) {
|
|
+ wl_surface *surface = moz_container_get_wl_surface(container);
|
|
+ if (!surface) {
|
|
+ return nullptr;
|
|
+ }
|
|
+ }
|
|
+ return container->eglwindow;
|
|
+}
|
|
+
|
|
+gboolean moz_container_has_wl_egl_window(MozContainer *container) {
|
|
+ return container->eglwindow ? true : false;
|
|
+}
|
|
+
|
|
+gboolean moz_container_surface_needs_clear(MozContainer *container) {
|
|
+ gboolean state = container->surface_needs_clear;
|
|
+ container->surface_needs_clear = false;
|
|
+ return state;
|
|
+}
|
|
#endif
|
|
diff -up thunderbird-60.5.0/widget/gtk/mozcontainer.h.wayland thunderbird-60.5.0/widget/gtk/mozcontainer.h
|
|
--- thunderbird-60.5.0/widget/gtk/mozcontainer.h.wayland 2019-01-22 20:44:03.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/mozcontainer.h 2019-02-05 14:26:16.974316651 +0100
|
|
@@ -1,4 +1,4 @@
|
|
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
*/
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
@@ -63,7 +63,6 @@ typedef struct _MozContainerClass MozCon
|
|
* present in wayland-devel < 1.12
|
|
*/
|
|
#ifdef MOZ_WAYLAND
|
|
-struct wl_subcompositor;
|
|
struct wl_surface;
|
|
struct wl_subsurface;
|
|
#endif
|
|
@@ -73,9 +72,12 @@ struct _MozContainer {
|
|
GList *children;
|
|
|
|
#ifdef MOZ_WAYLAND
|
|
- struct wl_subcompositor *subcompositor;
|
|
struct wl_surface *surface;
|
|
struct wl_subsurface *subsurface;
|
|
+ struct wl_egl_window *eglwindow;
|
|
+ struct wl_callback *frame_callback_handler;
|
|
+ gboolean surface_needs_clear;
|
|
+ gboolean ready_to_draw;
|
|
#endif
|
|
};
|
|
|
|
@@ -87,11 +89,13 @@ GType moz_container_get_type(void);
|
|
GtkWidget *moz_container_new(void);
|
|
void moz_container_put(MozContainer *container, GtkWidget *child_widget, gint x,
|
|
gint y);
|
|
-void moz_container_move(MozContainer *container, GtkWidget *child_widget,
|
|
- gint x, gint y, gint width, gint height);
|
|
|
|
#ifdef MOZ_WAYLAND
|
|
struct wl_surface *moz_container_get_wl_surface(MozContainer *container);
|
|
+struct wl_egl_window *moz_container_get_wl_egl_window(MozContainer *container);
|
|
+
|
|
+gboolean moz_container_has_wl_egl_window(MozContainer *container);
|
|
+gboolean moz_container_surface_needs_clear(MozContainer *container);
|
|
#endif
|
|
|
|
#endif /* __MOZ_CONTAINER_H__ */
|
|
diff -up thunderbird-60.5.0/widget/gtk/mozgtk/mozgtk.c.wayland thunderbird-60.5.0/widget/gtk/mozgtk/mozgtk.c
|
|
--- thunderbird-60.5.0/widget/gtk/mozgtk/mozgtk.c.wayland 2019-01-22 20:44:04.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/mozgtk/mozgtk.c 2019-02-05 14:26:16.974316651 +0100
|
|
@@ -26,6 +26,7 @@ STUB(gdk_display_sync)
|
|
STUB(gdk_display_warp_pointer)
|
|
STUB(gdk_drag_context_get_actions)
|
|
STUB(gdk_drag_context_get_dest_window)
|
|
+STUB(gdk_drag_context_get_source_window)
|
|
STUB(gdk_drag_context_list_targets)
|
|
STUB(gdk_drag_status)
|
|
STUB(gdk_error_trap_pop)
|
|
@@ -55,6 +56,7 @@ STUB(gdk_pointer_grab)
|
|
STUB(gdk_pointer_ungrab)
|
|
STUB(gdk_property_change)
|
|
STUB(gdk_property_get)
|
|
+STUB(gdk_property_delete)
|
|
STUB(gdk_screen_get_default)
|
|
STUB(gdk_screen_get_display)
|
|
STUB(gdk_screen_get_font_options)
|
|
@@ -136,6 +138,8 @@ STUB(gdk_x11_get_xatom_by_name)
|
|
STUB(gdk_x11_get_xatom_by_name_for_display)
|
|
STUB(gdk_x11_lookup_xdisplay)
|
|
STUB(gdk_x11_screen_get_xscreen)
|
|
+STUB(gdk_x11_screen_get_screen_number)
|
|
+STUB(gdk_x11_screen_lookup_visual)
|
|
STUB(gdk_x11_screen_supports_net_wm_hint)
|
|
STUB(gdk_x11_visual_get_xvisual)
|
|
STUB(gdk_x11_window_foreign_new_for_display)
|
|
@@ -267,6 +271,7 @@ STUB(gtk_im_context_set_client_window)
|
|
STUB(gtk_im_context_set_cursor_location)
|
|
STUB(gtk_im_context_set_surrounding)
|
|
STUB(gtk_im_context_simple_new)
|
|
+STUB(gtk_im_multicontext_get_context_id)
|
|
STUB(gtk_im_multicontext_get_type)
|
|
STUB(gtk_im_multicontext_new)
|
|
STUB(gtk_info_bar_get_type)
|
|
@@ -411,6 +416,7 @@ STUB(gtk_table_get_type)
|
|
STUB(gtk_table_new)
|
|
STUB(gtk_target_list_add)
|
|
STUB(gtk_target_list_add_image_targets)
|
|
+STUB(gtk_target_list_add_text_targets)
|
|
STUB(gtk_target_list_new)
|
|
STUB(gtk_target_list_unref)
|
|
STUB(gtk_targets_include_image)
|
|
@@ -491,6 +497,7 @@ STUB(gtk_widget_unrealize)
|
|
STUB(gtk_window_deiconify)
|
|
STUB(gtk_window_fullscreen)
|
|
STUB(gtk_window_get_group)
|
|
+STUB(gtk_window_get_modal)
|
|
STUB(gtk_window_get_transient_for)
|
|
STUB(gtk_window_get_type)
|
|
STUB(gtk_window_get_type_hint)
|
|
diff -up thunderbird-60.5.0/widget/gtk/mozwayland/mozwayland.c.wayland thunderbird-60.5.0/widget/gtk/mozwayland/mozwayland.c
|
|
--- thunderbird-60.5.0/widget/gtk/mozwayland/mozwayland.c.wayland 2019-01-22 20:44:02.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/mozwayland/mozwayland.c 2019-02-05 14:26:16.974316651 +0100
|
|
@@ -1,14 +1,23 @@
|
|
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
*/
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
+#include <stdlib.h>
|
|
#include "mozilla/Types.h"
|
|
#include <gtk/gtk.h>
|
|
+#include <gtk/gtkx.h>
|
|
#include <gdk/gdkwayland.h>
|
|
|
|
+union wl_argument;
|
|
+
|
|
+/* Those strucures are just placeholders and will be replaced by
|
|
+ * real symbols from libwayland during run-time linking. We need to make
|
|
+ * them explicitly visible.
|
|
+ */
|
|
+#pragma GCC visibility push(default)
|
|
const struct wl_interface wl_buffer_interface;
|
|
const struct wl_interface wl_callback_interface;
|
|
const struct wl_interface wl_data_device_interface;
|
|
@@ -22,6 +31,7 @@ const struct wl_interface wl_seat_interf
|
|
const struct wl_interface wl_surface_interface;
|
|
const struct wl_interface wl_subsurface_interface;
|
|
const struct wl_interface wl_subcompositor_interface;
|
|
+#pragma GCC visibility pop
|
|
|
|
MOZ_EXPORT void wl_event_queue_destroy(struct wl_event_queue *queue) {}
|
|
|
|
@@ -75,6 +85,10 @@ MOZ_EXPORT const void *wl_proxy_get_list
|
|
return NULL;
|
|
}
|
|
|
|
+typedef int (*wl_dispatcher_func_t)(const void *, void *, uint32_t,
|
|
+ const struct wl_message *,
|
|
+ union wl_argument *);
|
|
+
|
|
MOZ_EXPORT int wl_proxy_add_dispatcher(struct wl_proxy *proxy,
|
|
wl_dispatcher_func_t dispatcher_func,
|
|
const void *dispatcher_data,
|
|
@@ -160,3 +174,13 @@ MOZ_EXPORT void wl_display_cancel_read(s
|
|
MOZ_EXPORT int wl_display_read_events(struct wl_display *display) { return -1; }
|
|
|
|
MOZ_EXPORT void wl_log_set_handler_client(wl_log_func_t handler) {}
|
|
+
|
|
+MOZ_EXPORT struct wl_egl_window *wl_egl_window_create(
|
|
+ struct wl_surface *surface, int width, int height) {
|
|
+ return NULL;
|
|
+}
|
|
+
|
|
+MOZ_EXPORT void wl_egl_window_destroy(struct wl_egl_window *egl_window) {}
|
|
+
|
|
+MOZ_EXPORT void wl_egl_window_resize(struct wl_egl_window *egl_window,
|
|
+ int width, int height, int dx, int dy) {}
|
|
diff -up thunderbird-60.5.0/widget/gtk/mozwayland/mozwayland.h.wayland thunderbird-60.5.0/widget/gtk/mozwayland/mozwayland.h
|
|
--- thunderbird-60.5.0/widget/gtk/mozwayland/mozwayland.h.wayland 2019-02-05 14:26:16.975316648 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/mozwayland/mozwayland.h 2019-02-05 14:26:16.975316648 +0100
|
|
@@ -0,0 +1,115 @@
|
|
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
+/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
+ */
|
|
+/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
+
|
|
+/* Wayland compatibility header, it makes Firefox build with
|
|
+ wayland-1.2 and Gtk+ 3.10.
|
|
+*/
|
|
+
|
|
+#ifndef __MozWayland_h_
|
|
+#define __MozWayland_h_
|
|
+
|
|
+#include "mozilla/Types.h"
|
|
+#include <gtk/gtk.h>
|
|
+#include <gdk/gdkwayland.h>
|
|
+
|
|
+#ifdef __cplusplus
|
|
+extern "C" {
|
|
+#endif
|
|
+
|
|
+MOZ_EXPORT int wl_display_roundtrip_queue(struct wl_display *display,
|
|
+ struct wl_event_queue *queue);
|
|
+MOZ_EXPORT uint32_t wl_proxy_get_version(struct wl_proxy *proxy);
|
|
+MOZ_EXPORT struct wl_proxy *wl_proxy_marshal_constructor(
|
|
+ struct wl_proxy *proxy, uint32_t opcode,
|
|
+ const struct wl_interface *interface, ...);
|
|
+
|
|
+/* We need implement some missing functions from wayland-client-protocol.h
|
|
+ */
|
|
+#ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM
|
|
+enum wl_data_device_manager_dnd_action {
|
|
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE = 0,
|
|
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY = 1,
|
|
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE = 2,
|
|
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4
|
|
+};
|
|
+#endif
|
|
+
|
|
+#ifndef WL_DATA_OFFER_SET_ACTIONS
|
|
+#define WL_DATA_OFFER_SET_ACTIONS 4
|
|
+
|
|
+struct moz_wl_data_offer_listener {
|
|
+ void (*offer)(void *data, struct wl_data_offer *wl_data_offer,
|
|
+ const char *mime_type);
|
|
+ void (*source_actions)(void *data, struct wl_data_offer *wl_data_offer,
|
|
+ uint32_t source_actions);
|
|
+ void (*action)(void *data, struct wl_data_offer *wl_data_offer,
|
|
+ uint32_t dnd_action);
|
|
+};
|
|
+
|
|
+static inline void wl_data_offer_set_actions(
|
|
+ struct wl_data_offer *wl_data_offer, uint32_t dnd_actions,
|
|
+ uint32_t preferred_action) {
|
|
+ wl_proxy_marshal((struct wl_proxy *)wl_data_offer, WL_DATA_OFFER_SET_ACTIONS,
|
|
+ dnd_actions, preferred_action);
|
|
+}
|
|
+#else
|
|
+typedef struct wl_data_offer_listener moz_wl_data_offer_listener;
|
|
+#endif
|
|
+
|
|
+#ifndef WL_SUBCOMPOSITOR_GET_SUBSURFACE
|
|
+#define WL_SUBCOMPOSITOR_GET_SUBSURFACE 1
|
|
+struct wl_subcompositor;
|
|
+
|
|
+// Emulate what mozilla header wrapper does - make the
|
|
+// wl_subcompositor_interface always visible.
|
|
+#pragma GCC visibility push(default)
|
|
+extern const struct wl_interface wl_subsurface_interface;
|
|
+extern const struct wl_interface wl_subcompositor_interface;
|
|
+#pragma GCC visibility pop
|
|
+
|
|
+#define WL_SUBSURFACE_DESTROY 0
|
|
+#define WL_SUBSURFACE_SET_POSITION 1
|
|
+#define WL_SUBSURFACE_PLACE_ABOVE 2
|
|
+#define WL_SUBSURFACE_PLACE_BELOW 3
|
|
+#define WL_SUBSURFACE_SET_SYNC 4
|
|
+#define WL_SUBSURFACE_SET_DESYNC 5
|
|
+
|
|
+static inline struct wl_subsurface *wl_subcompositor_get_subsurface(
|
|
+ struct wl_subcompositor *wl_subcompositor, struct wl_surface *surface,
|
|
+ struct wl_surface *parent) {
|
|
+ struct wl_proxy *id;
|
|
+
|
|
+ id = wl_proxy_marshal_constructor(
|
|
+ (struct wl_proxy *)wl_subcompositor, WL_SUBCOMPOSITOR_GET_SUBSURFACE,
|
|
+ &wl_subsurface_interface, NULL, surface, parent);
|
|
+
|
|
+ return (struct wl_subsurface *)id;
|
|
+}
|
|
+
|
|
+static inline void wl_subsurface_set_position(
|
|
+ struct wl_subsurface *wl_subsurface, int32_t x, int32_t y) {
|
|
+ wl_proxy_marshal((struct wl_proxy *)wl_subsurface, WL_SUBSURFACE_SET_POSITION,
|
|
+ x, y);
|
|
+}
|
|
+
|
|
+static inline void wl_subsurface_set_desync(
|
|
+ struct wl_subsurface *wl_subsurface) {
|
|
+ wl_proxy_marshal((struct wl_proxy *)wl_subsurface, WL_SUBSURFACE_SET_DESYNC);
|
|
+}
|
|
+
|
|
+static inline void wl_subsurface_destroy(struct wl_subsurface *wl_subsurface) {
|
|
+ wl_proxy_marshal((struct wl_proxy *)wl_subsurface, WL_SUBSURFACE_DESTROY);
|
|
+
|
|
+ wl_proxy_destroy((struct wl_proxy *)wl_subsurface);
|
|
+}
|
|
+#endif
|
|
+
|
|
+#ifdef __cplusplus
|
|
+}
|
|
+#endif
|
|
+
|
|
+#endif /* __MozWayland_h_ */
|
|
diff -up thunderbird-60.5.0/widget/gtk/nsClipboard.cpp.wayland thunderbird-60.5.0/widget/gtk/nsClipboard.cpp
|
|
--- thunderbird-60.5.0/widget/gtk/nsClipboard.cpp.wayland 2019-01-22 20:44:03.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/nsClipboard.cpp 2019-02-05 14:26:16.975316648 +0100
|
|
@@ -72,7 +72,7 @@ nsClipboard::~nsClipboard() {
|
|
}
|
|
}
|
|
|
|
-NS_IMPL_ISUPPORTS(nsClipboard, nsIClipboard)
|
|
+NS_IMPL_ISUPPORTS(nsClipboard, nsIClipboard, nsIObserver)
|
|
|
|
nsresult nsClipboard::Init(void) {
|
|
GdkDisplay *display = gdk_display_get_default();
|
|
diff -up thunderbird-60.5.0/widget/gtk/nsClipboardWayland.cpp.wayland thunderbird-60.5.0/widget/gtk/nsClipboardWayland.cpp
|
|
--- thunderbird-60.5.0/widget/gtk/nsClipboardWayland.cpp.wayland 2019-01-22 20:44:04.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/nsClipboardWayland.cpp 2019-02-05 14:26:16.975316648 +0100
|
|
@@ -1,4 +1,4 @@
|
|
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
*/
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
@@ -20,9 +20,11 @@
|
|
#include "nsImageToPixbuf.h"
|
|
#include "nsStringStream.h"
|
|
#include "nsIObserverService.h"
|
|
-#include "mozilla/Services.h"
|
|
#include "mozilla/RefPtr.h"
|
|
#include "mozilla/TimeStamp.h"
|
|
+#include "nsDragService.h"
|
|
+#include "mozwayland/mozwayland.h"
|
|
+#include "nsWaylandDisplay.h"
|
|
|
|
#include "imgIContainer.h"
|
|
|
|
@@ -31,15 +33,43 @@
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
-#include <gtk/gtk.h>
|
|
-#include <gdk/gdkwayland.h>
|
|
#include <errno.h>
|
|
|
|
-#include "wayland/gtk-primary-selection-client-protocol.h"
|
|
-
|
|
const char *nsRetrievalContextWayland::sTextMimeTypes[TEXT_MIME_TYPES_NUM] = {
|
|
"text/plain;charset=utf-8", "UTF8_STRING", "COMPOUND_TEXT"};
|
|
|
|
+static inline GdkDragAction wl_to_gdk_actions(uint32_t dnd_actions) {
|
|
+ GdkDragAction actions = GdkDragAction(0);
|
|
+
|
|
+ if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
|
|
+ actions = GdkDragAction(actions | GDK_ACTION_COPY);
|
|
+ if (dnd_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
|
|
+ actions = GdkDragAction(actions | GDK_ACTION_MOVE);
|
|
+
|
|
+ return actions;
|
|
+}
|
|
+
|
|
+static inline uint32_t gdk_to_wl_actions(GdkDragAction action) {
|
|
+ uint32_t dnd_actions = 0;
|
|
+
|
|
+ if (action & (GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_PRIVATE))
|
|
+ dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
|
|
+ if (action & GDK_ACTION_MOVE)
|
|
+ dnd_actions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
|
|
+
|
|
+ return dnd_actions;
|
|
+}
|
|
+
|
|
+static GtkWidget *get_gtk_widget_for_wl_surface(struct wl_surface *surface) {
|
|
+ GdkWindow *gdkParentWindow =
|
|
+ static_cast<GdkWindow *>(wl_surface_get_user_data(surface));
|
|
+
|
|
+ gpointer user_data = nullptr;
|
|
+ gdk_window_get_user_data(gdkParentWindow, &user_data);
|
|
+
|
|
+ return GTK_WIDGET(user_data);
|
|
+}
|
|
+
|
|
void DataOffer::AddMIMEType(const char *aMimeType) {
|
|
GdkAtom atom = gdk_atom_intern(aMimeType, FALSE);
|
|
mTargetMIMETypes.AppendElement(atom);
|
|
@@ -98,7 +128,7 @@ char *DataOffer::GetData(wl_display *aDi
|
|
|
|
GIOChannel *channel = g_io_channel_unix_new(pipe_fd[0]);
|
|
GError *error = nullptr;
|
|
- char *clipboardData;
|
|
+ char *clipboardData = nullptr;
|
|
|
|
g_io_channel_set_encoding(channel, nullptr, &error);
|
|
if (!error) {
|
|
@@ -138,31 +168,92 @@ bool WaylandDataOffer::RequestDataTransf
|
|
return false;
|
|
}
|
|
|
|
+void WaylandDataOffer::DragOfferAccept(const char *aMimeType, uint32_t aTime) {
|
|
+ wl_data_offer_accept(mWaylandDataOffer, aTime, aMimeType);
|
|
+}
|
|
+
|
|
+/* We follow logic of gdk_wayland_drag_context_commit_status()/gdkdnd-wayland.c
|
|
+ * here.
|
|
+ */
|
|
+void WaylandDataOffer::SetDragStatus(GdkDragAction aAction, uint32_t aTime) {
|
|
+ uint32_t dnd_actions = gdk_to_wl_actions(aAction);
|
|
+ uint32_t all_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY |
|
|
+ WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
|
|
+
|
|
+ wl_data_offer_set_actions(mWaylandDataOffer, all_actions, dnd_actions);
|
|
+
|
|
+ /* Workaround Wayland D&D architecture here. To get the data_device_drop()
|
|
+ signal (which routes to nsDragService::GetData() call) we need to
|
|
+ accept at least one mime type before data_device_leave().
|
|
+
|
|
+ Real wl_data_offer_accept() for actualy requested data mime type is
|
|
+ called from nsDragService::GetData().
|
|
+ */
|
|
+ if (mTargetMIMETypes[0]) {
|
|
+ wl_data_offer_accept(mWaylandDataOffer, aTime,
|
|
+ gdk_atom_name(mTargetMIMETypes[0]));
|
|
+ }
|
|
+}
|
|
+
|
|
+void WaylandDataOffer::SetSelectedDragAction(uint32_t aWaylandAction) {
|
|
+ mSelectedDragAction = aWaylandAction;
|
|
+}
|
|
+
|
|
+GdkDragAction WaylandDataOffer::GetSelectedDragAction() {
|
|
+ return wl_to_gdk_actions(mSelectedDragAction);
|
|
+}
|
|
+
|
|
+void WaylandDataOffer::SetAvailableDragActions(uint32_t aWaylandActions) {
|
|
+ mAvailableDragAction = aWaylandActions;
|
|
+}
|
|
+
|
|
+GdkDragAction WaylandDataOffer::GetAvailableDragActions() {
|
|
+ return wl_to_gdk_actions(mAvailableDragAction);
|
|
+}
|
|
+
|
|
static void data_offer_offer(void *data, struct wl_data_offer *wl_data_offer,
|
|
const char *type) {
|
|
auto *offer = static_cast<DataOffer *>(data);
|
|
offer->AddMIMEType(type);
|
|
}
|
|
|
|
+/* Advertise all available drag and drop actions from source.
|
|
+ * We don't use that but follow gdk_wayland_drag_context_commit_status()
|
|
+ * from gdkdnd-wayland.c here.
|
|
+ */
|
|
static void data_offer_source_actions(void *data,
|
|
struct wl_data_offer *wl_data_offer,
|
|
- uint32_t source_actions) {}
|
|
+ uint32_t source_actions) {
|
|
+ auto *offer = static_cast<WaylandDataOffer *>(data);
|
|
+ offer->SetAvailableDragActions(source_actions);
|
|
+}
|
|
|
|
+/* Advertise recently selected drag and drop action by compositor, based
|
|
+ * on source actions and user choice (key modifiers, etc.).
|
|
+ */
|
|
static void data_offer_action(void *data, struct wl_data_offer *wl_data_offer,
|
|
- uint32_t dnd_action) {}
|
|
+ uint32_t dnd_action) {
|
|
+ auto *offer = static_cast<WaylandDataOffer *>(data);
|
|
+ offer->SetSelectedDragAction(dnd_action);
|
|
+}
|
|
|
|
/* wl_data_offer callback description:
|
|
*
|
|
* data_offer_offer - Is called for each MIME type available at wl_data_offer.
|
|
- * data_offer_source_actions - Exposes all available D&D actions.
|
|
- * data_offer_action - Expose one actually selected D&D action.
|
|
+ * data_offer_source_actions - This event indicates the actions offered by
|
|
+ * the data source.
|
|
+ * data_offer_action - This event indicates the action selected by
|
|
+ * the compositor after matching the source/destination
|
|
+ * side actions.
|
|
*/
|
|
-static const struct wl_data_offer_listener data_offer_listener = {
|
|
+static const moz_wl_data_offer_listener data_offer_listener = {
|
|
data_offer_offer, data_offer_source_actions, data_offer_action};
|
|
|
|
WaylandDataOffer::WaylandDataOffer(wl_data_offer *aWaylandDataOffer)
|
|
: mWaylandDataOffer(aWaylandDataOffer) {
|
|
- wl_data_offer_add_listener(mWaylandDataOffer, &data_offer_listener, this);
|
|
+ wl_data_offer_add_listener(
|
|
+ mWaylandDataOffer, (struct wl_data_offer_listener *)&data_offer_listener,
|
|
+ this);
|
|
}
|
|
|
|
WaylandDataOffer::~WaylandDataOffer(void) {
|
|
@@ -207,20 +298,93 @@ PrimaryDataOffer::~PrimaryDataOffer(void
|
|
}
|
|
}
|
|
|
|
-void nsRetrievalContextWayland::RegisterDataOffer(
|
|
+NS_IMPL_ISUPPORTS(nsWaylandDragContext, nsISupports);
|
|
+
|
|
+nsWaylandDragContext::nsWaylandDragContext(WaylandDataOffer *aDataOffer,
|
|
+ wl_display *aDisplay)
|
|
+ : mDataOffer(aDataOffer),
|
|
+ mDisplay(aDisplay),
|
|
+ mTime(0),
|
|
+ mGtkWidget(nullptr),
|
|
+ mX(0),
|
|
+ mY(0) {}
|
|
+
|
|
+void nsWaylandDragContext::DropDataEnter(GtkWidget *aGtkWidget, uint32_t aTime,
|
|
+ nscoord aX, nscoord aY) {
|
|
+ mTime = aTime;
|
|
+ mGtkWidget = aGtkWidget;
|
|
+ mX = aX;
|
|
+ mY = aY;
|
|
+}
|
|
+
|
|
+void nsWaylandDragContext::DropMotion(uint32_t aTime, nscoord aX, nscoord aY) {
|
|
+ mTime = aTime;
|
|
+ mX = aX;
|
|
+ mY = aY;
|
|
+}
|
|
+
|
|
+void nsWaylandDragContext::GetLastDropInfo(uint32_t *aTime, nscoord *aX,
|
|
+ nscoord *aY) {
|
|
+ *aTime = mTime;
|
|
+ *aX = mX;
|
|
+ *aY = mY;
|
|
+}
|
|
+
|
|
+void nsWaylandDragContext::SetDragStatus(GdkDragAction aAction) {
|
|
+ mDataOffer->SetDragStatus(aAction, mTime);
|
|
+}
|
|
+
|
|
+GdkDragAction nsWaylandDragContext::GetSelectedDragAction() {
|
|
+ GdkDragAction gdkAction = mDataOffer->GetSelectedDragAction();
|
|
+
|
|
+ // We emulate gdk_drag_context_get_actions() here.
|
|
+ if (!gdkAction) {
|
|
+ gdkAction = mDataOffer->GetAvailableDragActions();
|
|
+ }
|
|
+
|
|
+ return gdkAction;
|
|
+}
|
|
+
|
|
+GList *nsWaylandDragContext::GetTargets() {
|
|
+ int targetNums;
|
|
+ GdkAtom *atoms = mDataOffer->GetTargets(&targetNums);
|
|
+
|
|
+ GList *targetList = nullptr;
|
|
+ for (int i = 0; i < targetNums; i++) {
|
|
+ targetList = g_list_append(targetList, GDK_ATOM_TO_POINTER(atoms[i]));
|
|
+ }
|
|
+
|
|
+ return targetList;
|
|
+}
|
|
+
|
|
+char *nsWaylandDragContext::GetData(const char *aMimeType,
|
|
+ uint32_t *aContentLength) {
|
|
+ mDataOffer->DragOfferAccept(aMimeType, mTime);
|
|
+ return mDataOffer->GetData(mDisplay, aMimeType, aContentLength);
|
|
+}
|
|
+
|
|
+void nsRetrievalContextWayland::RegisterNewDataOffer(
|
|
wl_data_offer *aWaylandDataOffer) {
|
|
DataOffer *dataOffer = static_cast<DataOffer *>(
|
|
g_hash_table_lookup(mActiveOffers, aWaylandDataOffer));
|
|
+ MOZ_ASSERT(
|
|
+ dataOffer == nullptr,
|
|
+ "Registered WaylandDataOffer already exists. Wayland protocol error?");
|
|
+
|
|
if (!dataOffer) {
|
|
dataOffer = new WaylandDataOffer(aWaylandDataOffer);
|
|
g_hash_table_insert(mActiveOffers, aWaylandDataOffer, dataOffer);
|
|
}
|
|
}
|
|
|
|
-void nsRetrievalContextWayland::RegisterDataOffer(
|
|
+void nsRetrievalContextWayland::RegisterNewDataOffer(
|
|
gtk_primary_selection_offer *aPrimaryDataOffer) {
|
|
DataOffer *dataOffer = static_cast<DataOffer *>(
|
|
g_hash_table_lookup(mActiveOffers, aPrimaryDataOffer));
|
|
+ MOZ_ASSERT(
|
|
+ dataOffer == nullptr,
|
|
+ "Registered PrimaryDataOffer already exists. Wayland protocol error?");
|
|
+
|
|
if (!dataOffer) {
|
|
dataOffer = new PrimaryDataOffer(aPrimaryDataOffer);
|
|
g_hash_table_insert(mActiveOffers, aPrimaryDataOffer, dataOffer);
|
|
@@ -229,21 +393,30 @@ void nsRetrievalContextWayland::Register
|
|
|
|
void nsRetrievalContextWayland::SetClipboardDataOffer(
|
|
wl_data_offer *aWaylandDataOffer) {
|
|
- DataOffer *dataOffer = static_cast<DataOffer *>(
|
|
- g_hash_table_lookup(mActiveOffers, aWaylandDataOffer));
|
|
- NS_ASSERTION(dataOffer, "We're missing clipboard data offer!");
|
|
- if (dataOffer) {
|
|
- g_hash_table_remove(mActiveOffers, aWaylandDataOffer);
|
|
- mClipboardOffer = dataOffer;
|
|
+ // Delete existing clipboard data offer
|
|
+ mClipboardOffer = nullptr;
|
|
+
|
|
+ // null aWaylandDataOffer indicates that our clipboard content
|
|
+ // is no longer valid and should be release.
|
|
+ if (aWaylandDataOffer != nullptr) {
|
|
+ DataOffer *dataOffer = static_cast<DataOffer *>(
|
|
+ g_hash_table_lookup(mActiveOffers, aWaylandDataOffer));
|
|
+ NS_ASSERTION(dataOffer, "We're missing stored clipboard data offer!");
|
|
+ if (dataOffer) {
|
|
+ g_hash_table_remove(mActiveOffers, aWaylandDataOffer);
|
|
+ mClipboardOffer = dataOffer;
|
|
+ }
|
|
}
|
|
}
|
|
|
|
void nsRetrievalContextWayland::SetPrimaryDataOffer(
|
|
gtk_primary_selection_offer *aPrimaryDataOffer) {
|
|
- if (aPrimaryDataOffer == nullptr) {
|
|
- // Release any primary offer we have.
|
|
- mPrimaryOffer = nullptr;
|
|
- } else {
|
|
+ // Release any primary offer we have.
|
|
+ mPrimaryOffer = nullptr;
|
|
+
|
|
+ // aPrimaryDataOffer can be null which means we lost
|
|
+ // the mouse selection.
|
|
+ if (aPrimaryDataOffer) {
|
|
DataOffer *dataOffer = static_cast<DataOffer *>(
|
|
g_hash_table_lookup(mActiveOffers, aPrimaryDataOffer));
|
|
NS_ASSERTION(dataOffer, "We're missing primary data offer!");
|
|
@@ -254,9 +427,26 @@ void nsRetrievalContextWayland::SetPrima
|
|
}
|
|
}
|
|
|
|
-void nsRetrievalContextWayland::ClearDataOffers(void) {
|
|
- if (mClipboardOffer) mClipboardOffer = nullptr;
|
|
- if (mPrimaryOffer) mPrimaryOffer = nullptr;
|
|
+void nsRetrievalContextWayland::AddDragAndDropDataOffer(
|
|
+ wl_data_offer *aDropDataOffer) {
|
|
+ // Remove any existing D&D contexts.
|
|
+ mDragContext = nullptr;
|
|
+
|
|
+ WaylandDataOffer *dataOffer = static_cast<WaylandDataOffer *>(
|
|
+ g_hash_table_lookup(mActiveOffers, aDropDataOffer));
|
|
+ NS_ASSERTION(dataOffer, "We're missing drag and drop data offer!");
|
|
+ if (dataOffer) {
|
|
+ g_hash_table_remove(mActiveOffers, aDropDataOffer);
|
|
+ mDragContext = new nsWaylandDragContext(dataOffer, mDisplay->GetDisplay());
|
|
+ }
|
|
+}
|
|
+
|
|
+nsWaylandDragContext *nsRetrievalContextWayland::GetDragContext(void) {
|
|
+ return mDragContext;
|
|
+}
|
|
+
|
|
+void nsRetrievalContextWayland::ClearDragAndDropDataOffer(void) {
|
|
+ mDragContext = nullptr;
|
|
}
|
|
|
|
// We have a new fresh data content.
|
|
@@ -266,7 +456,7 @@ static void data_device_data_offer(void
|
|
struct wl_data_offer *offer) {
|
|
nsRetrievalContextWayland *context =
|
|
static_cast<nsRetrievalContextWayland *>(data);
|
|
- context->RegisterDataOffer(offer);
|
|
+ context->RegisterNewDataOffer(offer);
|
|
}
|
|
|
|
// The new fresh data content is clipboard.
|
|
@@ -281,15 +471,65 @@ static void data_device_selection(void *
|
|
// The new fresh wayland data content is drag and drop.
|
|
static void data_device_enter(void *data, struct wl_data_device *data_device,
|
|
uint32_t time, struct wl_surface *surface,
|
|
- int32_t x, int32_t y,
|
|
- struct wl_data_offer *offer) {}
|
|
+ int32_t x_fixed, int32_t y_fixed,
|
|
+ struct wl_data_offer *offer) {
|
|
+ nsRetrievalContextWayland *context =
|
|
+ static_cast<nsRetrievalContextWayland *>(data);
|
|
+ context->AddDragAndDropDataOffer(offer);
|
|
+
|
|
+ nsWaylandDragContext *dragContext = context->GetDragContext();
|
|
+
|
|
+ GtkWidget *gtkWidget = get_gtk_widget_for_wl_surface(surface);
|
|
+ if (!gtkWidget) {
|
|
+ NS_WARNING("DragAndDrop: Unable to get GtkWidget for wl_surface!");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ LOGDRAG(("nsWindow data_device_enter for GtkWidget %p\n", (void *)gtkWidget));
|
|
+
|
|
+ dragContext->DropDataEnter(gtkWidget, time, wl_fixed_to_int(x_fixed),
|
|
+ wl_fixed_to_int(y_fixed));
|
|
+}
|
|
+
|
|
+static void data_device_leave(void *data, struct wl_data_device *data_device) {
|
|
+ nsRetrievalContextWayland *context =
|
|
+ static_cast<nsRetrievalContextWayland *>(data);
|
|
|
|
-static void data_device_leave(void *data, struct wl_data_device *data_device) {}
|
|
+ nsWaylandDragContext *dropContext = context->GetDragContext();
|
|
+ WindowDragLeaveHandler(dropContext->GetWidget());
|
|
+
|
|
+ context->ClearDragAndDropDataOffer();
|
|
+}
|
|
|
|
static void data_device_motion(void *data, struct wl_data_device *data_device,
|
|
- uint32_t time, int32_t x, int32_t y) {}
|
|
+ uint32_t time, int32_t x_fixed,
|
|
+ int32_t y_fixed) {
|
|
+ nsRetrievalContextWayland *context =
|
|
+ static_cast<nsRetrievalContextWayland *>(data);
|
|
+
|
|
+ nsWaylandDragContext *dropContext = context->GetDragContext();
|
|
|
|
-static void data_device_drop(void *data, struct wl_data_device *data_device) {}
|
|
+ nscoord x = wl_fixed_to_int(x_fixed);
|
|
+ nscoord y = wl_fixed_to_int(y_fixed);
|
|
+ dropContext->DropMotion(time, x, y);
|
|
+
|
|
+ WindowDragMotionHandler(dropContext->GetWidget(), nullptr, dropContext, x, y,
|
|
+ time);
|
|
+}
|
|
+
|
|
+static void data_device_drop(void *data, struct wl_data_device *data_device) {
|
|
+ nsRetrievalContextWayland *context =
|
|
+ static_cast<nsRetrievalContextWayland *>(data);
|
|
+
|
|
+ nsWaylandDragContext *dropContext = context->GetDragContext();
|
|
+
|
|
+ uint32_t time;
|
|
+ nscoord x, y;
|
|
+ dropContext->GetLastDropInfo(&time, &x, &y);
|
|
+
|
|
+ WindowDragDropHandler(dropContext->GetWidget(), nullptr, dropContext, x, y,
|
|
+ time);
|
|
+}
|
|
|
|
/* wl_data_device callback description:
|
|
*
|
|
@@ -323,7 +563,7 @@ static void primary_selection_data_offer
|
|
// create and add listener
|
|
nsRetrievalContextWayland *context =
|
|
static_cast<nsRetrievalContextWayland *>(data);
|
|
- context->RegisterDataOffer(gtk_primary_offer);
|
|
+ context->RegisterNewDataOffer(gtk_primary_offer);
|
|
}
|
|
|
|
static void primary_selection_selection(
|
|
@@ -335,6 +575,19 @@ static void primary_selection_selection(
|
|
context->SetPrimaryDataOffer(gtk_primary_offer);
|
|
}
|
|
|
|
+/* gtk_primary_selection_device callback description:
|
|
+ *
|
|
+ * primary_selection_data_offer - It's called when there's a new
|
|
+ * gtk_primary_selection_offer available. We need to
|
|
+ * attach gtk_primary_selection_offer_listener to it
|
|
+ * to get available MIME types.
|
|
+ *
|
|
+ * primary_selection_selection - It's called when the new
|
|
+ * gtk_primary_selection_offer is a primary selection
|
|
+ * content. It can be also called with
|
|
+ * gtk_primary_selection_offer = null which means
|
|
+ * there's no primary selection.
|
|
+ */
|
|
static const struct gtk_primary_selection_device_listener
|
|
primary_selection_device_listener = {
|
|
primary_selection_data_offer,
|
|
@@ -342,149 +595,29 @@ static const struct gtk_primary_selectio
|
|
};
|
|
|
|
bool nsRetrievalContextWayland::HasSelectionSupport(void) {
|
|
- return mPrimarySelectionDataDeviceManager != nullptr;
|
|
-}
|
|
-
|
|
-static void keyboard_handle_keymap(void *data, struct wl_keyboard *keyboard,
|
|
- uint32_t format, int fd, uint32_t size) {}
|
|
-
|
|
-static void keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
|
|
- uint32_t serial, struct wl_surface *surface,
|
|
- struct wl_array *keys) {}
|
|
-
|
|
-static void keyboard_handle_leave(void *data, struct wl_keyboard *keyboard,
|
|
- uint32_t serial, struct wl_surface *surface) {
|
|
- // We lost focus so our clipboard data are outdated
|
|
- nsRetrievalContextWayland *context =
|
|
- static_cast<nsRetrievalContextWayland *>(data);
|
|
-
|
|
- context->ClearDataOffers();
|
|
+ return mDisplay->GetPrimarySelectionDeviceManager() != nullptr;
|
|
}
|
|
|
|
-static void keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
|
|
- uint32_t serial, uint32_t time, uint32_t key,
|
|
- uint32_t state) {}
|
|
-
|
|
-static void keyboard_handle_modifiers(void *data, struct wl_keyboard *keyboard,
|
|
- uint32_t serial, uint32_t mods_depressed,
|
|
- uint32_t mods_latched,
|
|
- uint32_t mods_locked, uint32_t group) {}
|
|
-
|
|
-static const struct wl_keyboard_listener keyboard_listener = {
|
|
- keyboard_handle_keymap, keyboard_handle_enter, keyboard_handle_leave,
|
|
- keyboard_handle_key, keyboard_handle_modifiers,
|
|
-};
|
|
-
|
|
-void nsRetrievalContextWayland::ConfigureKeyboard(wl_seat_capability caps) {
|
|
- // ConfigureKeyboard() is called when wl_seat configuration is changed.
|
|
- // We look for the keyboard only, get it when is't available and release it
|
|
- // when it's lost (we don't have focus for instance).
|
|
- if (caps & WL_SEAT_CAPABILITY_KEYBOARD) {
|
|
- mKeyboard = wl_seat_get_keyboard(mSeat);
|
|
- wl_keyboard_add_listener(mKeyboard, &keyboard_listener, this);
|
|
- } else if (mKeyboard && !(caps & WL_SEAT_CAPABILITY_KEYBOARD)) {
|
|
- wl_keyboard_destroy(mKeyboard);
|
|
- mKeyboard = nullptr;
|
|
- }
|
|
-}
|
|
-
|
|
-static void seat_handle_capabilities(void *data, struct wl_seat *seat,
|
|
- unsigned int caps) {
|
|
- nsRetrievalContextWayland *context =
|
|
- static_cast<nsRetrievalContextWayland *>(data);
|
|
- context->ConfigureKeyboard((wl_seat_capability)caps);
|
|
-}
|
|
-
|
|
-static const struct wl_seat_listener seat_listener = {
|
|
- seat_handle_capabilities,
|
|
-};
|
|
-
|
|
-void nsRetrievalContextWayland::InitDataDeviceManager(wl_registry *registry,
|
|
- uint32_t id,
|
|
- uint32_t version) {
|
|
- int data_device_manager_version = MIN(version, 3);
|
|
- mDataDeviceManager = (wl_data_device_manager *)wl_registry_bind(
|
|
- registry, id, &wl_data_device_manager_interface,
|
|
- data_device_manager_version);
|
|
-}
|
|
-
|
|
-void nsRetrievalContextWayland::InitPrimarySelectionDataDeviceManager(
|
|
- wl_registry *registry, uint32_t id) {
|
|
- mPrimarySelectionDataDeviceManager =
|
|
- (gtk_primary_selection_device_manager *)wl_registry_bind(
|
|
- registry, id, >k_primary_selection_device_manager_interface, 1);
|
|
-}
|
|
-
|
|
-void nsRetrievalContextWayland::InitSeat(wl_registry *registry, uint32_t id,
|
|
- uint32_t version, void *data) {
|
|
- mSeat = (wl_seat *)wl_registry_bind(registry, id, &wl_seat_interface, 1);
|
|
- wl_seat_add_listener(mSeat, &seat_listener, data);
|
|
-}
|
|
-
|
|
-static void gdk_registry_handle_global(void *data, struct wl_registry *registry,
|
|
- uint32_t id, const char *interface,
|
|
- uint32_t version) {
|
|
- nsRetrievalContextWayland *context =
|
|
- static_cast<nsRetrievalContextWayland *>(data);
|
|
-
|
|
- if (strcmp(interface, "wl_data_device_manager") == 0) {
|
|
- context->InitDataDeviceManager(registry, id, version);
|
|
- } else if (strcmp(interface, "wl_seat") == 0) {
|
|
- context->InitSeat(registry, id, version, data);
|
|
- } else if (strcmp(interface, "gtk_primary_selection_device_manager") == 0) {
|
|
- context->InitPrimarySelectionDataDeviceManager(registry, id);
|
|
- }
|
|
-}
|
|
-
|
|
-static void gdk_registry_handle_global_remove(void *data,
|
|
- struct wl_registry *registry,
|
|
- uint32_t id) {}
|
|
-
|
|
-static const struct wl_registry_listener clipboard_registry_listener = {
|
|
- gdk_registry_handle_global, gdk_registry_handle_global_remove};
|
|
-
|
|
nsRetrievalContextWayland::nsRetrievalContextWayland(void)
|
|
: mInitialized(false),
|
|
- mSeat(nullptr),
|
|
- mDataDeviceManager(nullptr),
|
|
- mPrimarySelectionDataDeviceManager(nullptr),
|
|
- mKeyboard(nullptr),
|
|
+ mDisplay(WaylandDisplayGet()),
|
|
mActiveOffers(g_hash_table_new(NULL, NULL)),
|
|
mClipboardOffer(nullptr),
|
|
mPrimaryOffer(nullptr),
|
|
+ mDragContext(nullptr),
|
|
mClipboardRequestNumber(0),
|
|
mClipboardData(nullptr),
|
|
mClipboardDataLength(0) {
|
|
- // Available as of GTK 3.8+
|
|
- static auto sGdkWaylandDisplayGetWlDisplay = (wl_display * (*)(GdkDisplay *))
|
|
- dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
|
|
-
|
|
- mDisplay = sGdkWaylandDisplayGetWlDisplay(gdk_display_get_default());
|
|
- wl_registry_add_listener(wl_display_get_registry(mDisplay),
|
|
- &clipboard_registry_listener, this);
|
|
- // Call wl_display_roundtrip() twice to make sure all
|
|
- // callbacks are processed.
|
|
- wl_display_roundtrip(mDisplay);
|
|
- wl_display_roundtrip(mDisplay);
|
|
-
|
|
- // mSeat/mDataDeviceManager should be set now by
|
|
- // gdk_registry_handle_global() as a response to
|
|
- // wl_registry_add_listener() call.
|
|
- if (!mDataDeviceManager || !mSeat) return;
|
|
-
|
|
- wl_data_device *dataDevice =
|
|
- wl_data_device_manager_get_data_device(mDataDeviceManager, mSeat);
|
|
+ wl_data_device *dataDevice = wl_data_device_manager_get_data_device(
|
|
+ mDisplay->GetDataDeviceManager(), mDisplay->GetSeat());
|
|
wl_data_device_add_listener(dataDevice, &data_device_listener, this);
|
|
- // We have to call wl_display_roundtrip() twice otherwise data_offer_listener
|
|
- // may not be processed because it's called from data_device_data_offer
|
|
- // callback.
|
|
- wl_display_roundtrip(mDisplay);
|
|
- wl_display_roundtrip(mDisplay);
|
|
|
|
- if (mPrimarySelectionDataDeviceManager) {
|
|
+ gtk_primary_selection_device_manager *manager =
|
|
+ mDisplay->GetPrimarySelectionDeviceManager();
|
|
+ if (manager) {
|
|
gtk_primary_selection_device *primaryDataDevice =
|
|
- gtk_primary_selection_device_manager_get_device(
|
|
- mPrimarySelectionDataDeviceManager, mSeat);
|
|
+ gtk_primary_selection_device_manager_get_device(manager,
|
|
+ mDisplay->GetSeat());
|
|
gtk_primary_selection_device_add_listener(
|
|
primaryDataDevice, &primary_selection_device_listener, this);
|
|
}
|
|
@@ -492,8 +625,21 @@ nsRetrievalContextWayland::nsRetrievalCo
|
|
mInitialized = true;
|
|
}
|
|
|
|
+static gboolean offer_hash_remove(gpointer wl_offer, gpointer aDataOffer,
|
|
+ gpointer user_data) {
|
|
+#ifdef DEBUG
|
|
+ nsPrintfCString msg("nsRetrievalContextWayland(): leaked nsDataOffer %p\n",
|
|
+ aDataOffer);
|
|
+ NS_WARNING(msg.get());
|
|
+#endif
|
|
+ delete static_cast<DataOffer *>(aDataOffer);
|
|
+ return true;
|
|
+}
|
|
+
|
|
nsRetrievalContextWayland::~nsRetrievalContextWayland(void) {
|
|
+ g_hash_table_foreach_remove(mActiveOffers, offer_hash_remove, nullptr);
|
|
g_hash_table_destroy(mActiveOffers);
|
|
+ WaylandDisplayRelease(mDisplay);
|
|
}
|
|
|
|
GdkAtom *nsRetrievalContextWayland::GetTargets(int32_t aWhichClipboard,
|
|
@@ -533,12 +679,14 @@ static void wayland_clipboard_contents_r
|
|
void nsRetrievalContextWayland::TransferFastTrackClipboard(
|
|
int aClipboardRequestNumber, GtkSelectionData *aSelectionData) {
|
|
if (mClipboardRequestNumber == aClipboardRequestNumber) {
|
|
- mClipboardDataLength = gtk_selection_data_get_length(aSelectionData);
|
|
- if (mClipboardDataLength > 0) {
|
|
+ int dataLength = gtk_selection_data_get_length(aSelectionData);
|
|
+ if (dataLength > 0) {
|
|
+ mClipboardDataLength = dataLength;
|
|
mClipboardData = reinterpret_cast<char *>(
|
|
- g_malloc(sizeof(char) * mClipboardDataLength));
|
|
+ g_malloc(sizeof(char) * (mClipboardDataLength + 1)));
|
|
memcpy(mClipboardData, gtk_selection_data_get_data(aSelectionData),
|
|
sizeof(char) * mClipboardDataLength);
|
|
+ mClipboardData[mClipboardDataLength] = '\0';
|
|
}
|
|
} else {
|
|
NS_WARNING("Received obsoleted clipboard data!");
|
|
@@ -572,8 +720,8 @@ const char *nsRetrievalContextWayland::G
|
|
mClipboardData = nullptr;
|
|
mClipboardDataLength = 0;
|
|
} else {
|
|
- mClipboardData =
|
|
- dataOffer->GetData(mDisplay, aMimeType, &mClipboardDataLength);
|
|
+ mClipboardData = dataOffer->GetData(mDisplay->GetDisplay(), aMimeType,
|
|
+ &mClipboardDataLength);
|
|
}
|
|
}
|
|
|
|
@@ -588,7 +736,7 @@ const char *nsRetrievalContextWayland::G
|
|
(selection == GDK_SELECTION_PRIMARY) ? mPrimaryOffer : mClipboardOffer;
|
|
if (!dataOffer) return nullptr;
|
|
|
|
- for (unsigned int i = 0; i < sizeof(sTextMimeTypes); i++) {
|
|
+ for (unsigned int i = 0; i < TEXT_MIME_TYPES_NUM; i++) {
|
|
if (dataOffer->HasTarget(sTextMimeTypes[i])) {
|
|
uint32_t unused;
|
|
return GetClipboardData(sTextMimeTypes[i], aWhichClipboard, &unused);
|
|
diff -up thunderbird-60.5.0/widget/gtk/nsClipboardWayland.h.wayland thunderbird-60.5.0/widget/gtk/nsClipboardWayland.h
|
|
--- thunderbird-60.5.0/widget/gtk/nsClipboardWayland.h.wayland 2019-01-22 20:44:04.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/nsClipboardWayland.h 2019-02-05 14:26:16.975316648 +0100
|
|
@@ -1,4 +1,4 @@
|
|
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
*/
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
@@ -9,6 +9,7 @@
|
|
#define __nsClipboardWayland_h_
|
|
|
|
#include "nsIClipboard.h"
|
|
+#include "mozwayland/mozwayland.h"
|
|
#include "wayland/gtk-primary-selection-client-protocol.h"
|
|
|
|
#include <gtk/gtk.h>
|
|
@@ -32,31 +33,75 @@ class DataOffer {
|
|
private:
|
|
virtual bool RequestDataTransfer(const char* aMimeType, int fd) = 0;
|
|
|
|
+ protected:
|
|
nsTArray<GdkAtom> mTargetMIMETypes;
|
|
};
|
|
|
|
class WaylandDataOffer : public DataOffer {
|
|
public:
|
|
- WaylandDataOffer(wl_data_offer* aWaylandDataOffer);
|
|
+ explicit WaylandDataOffer(wl_data_offer* aWaylandDataOffer);
|
|
+
|
|
+ void DragOfferAccept(const char* aMimeType, uint32_t aTime);
|
|
+ void SetDragStatus(GdkDragAction aAction, uint32_t aTime);
|
|
+
|
|
+ GdkDragAction GetSelectedDragAction();
|
|
+ void SetSelectedDragAction(uint32_t aWaylandAction);
|
|
+
|
|
+ void SetAvailableDragActions(uint32_t aWaylandActions);
|
|
+ GdkDragAction GetAvailableDragActions();
|
|
|
|
- private:
|
|
virtual ~WaylandDataOffer();
|
|
+
|
|
+ private:
|
|
bool RequestDataTransfer(const char* aMimeType, int fd) override;
|
|
|
|
wl_data_offer* mWaylandDataOffer;
|
|
+ uint32_t mSelectedDragAction;
|
|
+ uint32_t mAvailableDragAction;
|
|
};
|
|
|
|
class PrimaryDataOffer : public DataOffer {
|
|
public:
|
|
- PrimaryDataOffer(gtk_primary_selection_offer* aPrimaryDataOffer);
|
|
+ explicit PrimaryDataOffer(gtk_primary_selection_offer* aPrimaryDataOffer);
|
|
+ void SetAvailableDragActions(uint32_t aWaylandActions){};
|
|
|
|
- private:
|
|
virtual ~PrimaryDataOffer();
|
|
+
|
|
+ private:
|
|
bool RequestDataTransfer(const char* aMimeType, int fd) override;
|
|
|
|
gtk_primary_selection_offer* mPrimaryDataOffer;
|
|
};
|
|
|
|
+class nsWaylandDragContext : public nsISupports {
|
|
+ NS_DECL_ISUPPORTS
|
|
+
|
|
+ public:
|
|
+ nsWaylandDragContext(WaylandDataOffer* aWaylandDataOffer,
|
|
+ wl_display* aDisplay);
|
|
+
|
|
+ void DropDataEnter(GtkWidget* aGtkWidget, uint32_t aTime, nscoord aX,
|
|
+ nscoord aY);
|
|
+ void DropMotion(uint32_t aTime, nscoord aX, nscoord aY);
|
|
+ void GetLastDropInfo(uint32_t* aTime, nscoord* aX, nscoord* aY);
|
|
+
|
|
+ void SetDragStatus(GdkDragAction action);
|
|
+ GdkDragAction GetSelectedDragAction();
|
|
+
|
|
+ GtkWidget* GetWidget() { return mGtkWidget; }
|
|
+ GList* GetTargets();
|
|
+ char* GetData(const char* aMimeType, uint32_t* aContentLength);
|
|
+
|
|
+ private:
|
|
+ virtual ~nsWaylandDragContext(){};
|
|
+
|
|
+ nsAutoPtr<WaylandDataOffer> mDataOffer;
|
|
+ wl_display* mDisplay;
|
|
+ uint32_t mTime;
|
|
+ GtkWidget* mGtkWidget;
|
|
+ nscoord mX, mY;
|
|
+};
|
|
+
|
|
class nsRetrievalContextWayland : public nsRetrievalContext {
|
|
public:
|
|
nsRetrievalContextWayland();
|
|
@@ -71,38 +116,30 @@ class nsRetrievalContextWayland : public
|
|
int* aTargetNum) override;
|
|
virtual bool HasSelectionSupport(void) override;
|
|
|
|
- void RegisterDataOffer(wl_data_offer* aWaylandDataOffer);
|
|
- void RegisterDataOffer(gtk_primary_selection_offer* aPrimaryDataOffer);
|
|
+ void RegisterNewDataOffer(wl_data_offer* aWaylandDataOffer);
|
|
+ void RegisterNewDataOffer(gtk_primary_selection_offer* aPrimaryDataOffer);
|
|
|
|
void SetClipboardDataOffer(wl_data_offer* aWaylandDataOffer);
|
|
void SetPrimaryDataOffer(gtk_primary_selection_offer* aPrimaryDataOffer);
|
|
+ void AddDragAndDropDataOffer(wl_data_offer* aWaylandDataOffer);
|
|
+ nsWaylandDragContext* GetDragContext();
|
|
|
|
- void ClearDataOffers();
|
|
+ void ClearDragAndDropDataOffer();
|
|
|
|
- void ConfigureKeyboard(wl_seat_capability caps);
|
|
void TransferFastTrackClipboard(int aClipboardRequestNumber,
|
|
GtkSelectionData* aSelectionData);
|
|
|
|
- void InitDataDeviceManager(wl_registry* registry, uint32_t id,
|
|
- uint32_t version);
|
|
- void InitPrimarySelectionDataDeviceManager(wl_registry* registry,
|
|
- uint32_t id);
|
|
- void InitSeat(wl_registry* registry, uint32_t id, uint32_t version,
|
|
- void* data);
|
|
virtual ~nsRetrievalContextWayland() override;
|
|
|
|
private:
|
|
bool mInitialized;
|
|
- wl_display* mDisplay;
|
|
- wl_seat* mSeat;
|
|
- wl_data_device_manager* mDataDeviceManager;
|
|
- gtk_primary_selection_device_manager* mPrimarySelectionDataDeviceManager;
|
|
- wl_keyboard* mKeyboard;
|
|
+ nsWaylandDisplay* mDisplay;
|
|
|
|
// Data offers provided by Wayland data device
|
|
GHashTable* mActiveOffers;
|
|
nsAutoPtr<DataOffer> mClipboardOffer;
|
|
nsAutoPtr<DataOffer> mPrimaryOffer;
|
|
+ RefPtr<nsWaylandDragContext> mDragContext;
|
|
|
|
int mClipboardRequestNumber;
|
|
char* mClipboardData;
|
|
diff -up thunderbird-60.5.0/widget/gtk/nsDragService.cpp.wayland thunderbird-60.5.0/widget/gtk/nsDragService.cpp
|
|
--- thunderbird-60.5.0/widget/gtk/nsDragService.cpp.wayland 2019-01-22 20:44:04.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/nsDragService.cpp 2019-02-05 14:26:16.976316645 +0100
|
|
@@ -1,5 +1,5 @@
|
|
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
-/* vim: set ts=4 et sw=4 tw=80: */
|
|
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
+/* vim: set ts=4 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
@@ -9,6 +9,7 @@
|
|
#include "nsIObserverService.h"
|
|
#include "nsWidgetsCID.h"
|
|
#include "nsWindow.h"
|
|
+#include "nsSystemInfo.h"
|
|
#include "nsIServiceManager.h"
|
|
#include "nsXPCOM.h"
|
|
#include "nsISupportsPrimitives.h"
|
|
@@ -34,7 +35,6 @@
|
|
#include "nsPresContext.h"
|
|
#include "nsIContent.h"
|
|
#include "nsIDocument.h"
|
|
-#include "nsISelection.h"
|
|
#include "nsViewManager.h"
|
|
#include "nsIFrame.h"
|
|
#include "nsGtkUtils.h"
|
|
@@ -43,10 +43,15 @@
|
|
#include "gfxPlatform.h"
|
|
#include "ScreenHelperGTK.h"
|
|
#include "nsArrayUtils.h"
|
|
+#ifdef MOZ_WAYLAND
|
|
+#include "nsClipboardWayland.h"
|
|
+#endif
|
|
|
|
using namespace mozilla;
|
|
using namespace mozilla::gfx;
|
|
|
|
+#define NS_SYSTEMINFO_CONTRACTID "@mozilla.org/system-info;1"
|
|
+
|
|
// This sets how opaque the drag image is
|
|
#define DRAG_IMAGE_ALPHA_LEVEL 0.5
|
|
|
|
@@ -68,6 +73,7 @@ static const char gMimeListType[] = "app
|
|
static const char gMozUrlType[] = "_NETSCAPE_URL";
|
|
static const char gTextUriListType[] = "text/uri-list";
|
|
static const char gTextPlainUTF8Type[] = "text/plain;charset=utf-8";
|
|
+static const char gXdndDirectSaveType[] = "XdndDirectSave0";
|
|
|
|
static void invisibleSourceDragBegin(GtkWidget *aWidget,
|
|
GdkDragContext *aContext, gpointer aData);
|
|
@@ -85,7 +91,15 @@ static void invisibleSourceDragDataGet(G
|
|
guint aInfo, guint32 aTime,
|
|
gpointer aData);
|
|
|
|
-nsDragService::nsDragService() : mScheduledTask(eDragTaskNone), mTaskSource(0) {
|
|
+nsDragService::nsDragService()
|
|
+ : mScheduledTask(eDragTaskNone),
|
|
+ mTaskSource(0)
|
|
+#ifdef MOZ_WAYLAND
|
|
+ ,
|
|
+ mPendingWaylandDragContext(nullptr),
|
|
+ mTargetWaylandDragContext(nullptr)
|
|
+#endif
|
|
+{
|
|
// We have to destroy the hidden widget before the event loop stops
|
|
// running.
|
|
nsCOMPtr<nsIObserverService> obsServ =
|
|
@@ -159,7 +173,7 @@ nsDragService::Observe(nsISupports *aSub
|
|
}
|
|
TargetResetData();
|
|
} else {
|
|
- NS_NOTREACHED("unexpected topic");
|
|
+ MOZ_ASSERT_UNREACHABLE("unexpected topic");
|
|
return NS_ERROR_UNEXPECTED;
|
|
}
|
|
|
|
@@ -457,6 +471,9 @@ nsDragService::EndDragSession(bool aDone
|
|
|
|
// We're done with the drag context.
|
|
mTargetDragContextForRemote = nullptr;
|
|
+#ifdef MOZ_WAYLAND
|
|
+ mTargetWaylandDragContextForRemote = nullptr;
|
|
+#endif
|
|
|
|
return nsBaseDragService::EndDragSession(aDoneDrag, aKeyModifiers);
|
|
}
|
|
@@ -550,6 +567,14 @@ nsDragService::GetNumDropItems(uint32_t
|
|
return NS_OK;
|
|
}
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
+ // TODO: Wayland implementation of text/uri-list.
|
|
+ if (!mTargetDragContext) {
|
|
+ *aNumItems = 1;
|
|
+ return NS_OK;
|
|
+ }
|
|
+#endif
|
|
+
|
|
bool isList = IsTargetContextList();
|
|
if (isList)
|
|
mSourceDataItems->GetLength(aNumItems);
|
|
@@ -907,9 +932,18 @@ nsDragService::IsDataFlavorSupported(con
|
|
}
|
|
|
|
// check the target context vs. this flavor, one at a time
|
|
- GList *tmp;
|
|
- for (tmp = gdk_drag_context_list_targets(mTargetDragContext); tmp;
|
|
- tmp = tmp->next) {
|
|
+ GList *tmp = nullptr;
|
|
+ if (mTargetDragContext) {
|
|
+ tmp = gdk_drag_context_list_targets(mTargetDragContext);
|
|
+ }
|
|
+#ifdef MOZ_WAYLAND
|
|
+ else if (mTargetWaylandDragContext) {
|
|
+ tmp = mTargetWaylandDragContext->GetTargets();
|
|
+ }
|
|
+ GList *tmp_head = tmp;
|
|
+#endif
|
|
+
|
|
+ for (; tmp; tmp = tmp->next) {
|
|
/* Bug 331198 */
|
|
GdkAtom atom = GDK_POINTER_TO_ATOM(tmp->data);
|
|
gchar *name = nullptr;
|
|
@@ -946,6 +980,15 @@ nsDragService::IsDataFlavorSupported(con
|
|
}
|
|
g_free(name);
|
|
}
|
|
+
|
|
+#ifdef MOZ_WAYLAND
|
|
+ // mTargetWaylandDragContext->GetTargets allocates the list
|
|
+ // so we need to free it here.
|
|
+ if (!mTargetDragContext && tmp_head) {
|
|
+ g_list_free(tmp_head);
|
|
+ }
|
|
+#endif
|
|
+
|
|
return NS_OK;
|
|
}
|
|
|
|
@@ -975,6 +1018,34 @@ void nsDragService::ReplyToDragMotion(Gd
|
|
gdk_drag_status(aDragContext, action, mTargetTime);
|
|
}
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
+void nsDragService::ReplyToDragMotion(nsWaylandDragContext *aDragContext) {
|
|
+ MOZ_LOG(sDragLm, LogLevel::Debug,
|
|
+ ("nsDragService::ReplyToDragMotion %d", mCanDrop));
|
|
+
|
|
+ GdkDragAction action = (GdkDragAction)0;
|
|
+ if (mCanDrop) {
|
|
+ // notify the dragger if we can drop
|
|
+ switch (mDragAction) {
|
|
+ case DRAGDROP_ACTION_COPY:
|
|
+ action = GDK_ACTION_COPY;
|
|
+ break;
|
|
+ case DRAGDROP_ACTION_LINK:
|
|
+ action = GDK_ACTION_LINK;
|
|
+ break;
|
|
+ case DRAGDROP_ACTION_NONE:
|
|
+ action = (GdkDragAction)0;
|
|
+ break;
|
|
+ default:
|
|
+ action = GDK_ACTION_MOVE;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ aDragContext->SetDragStatus(action);
|
|
+}
|
|
+#endif
|
|
+
|
|
void nsDragService::TargetDataReceived(GtkWidget *aWidget,
|
|
GdkDragContext *aContext, gint aX,
|
|
gint aY,
|
|
@@ -999,6 +1070,11 @@ void nsDragService::TargetDataReceived(G
|
|
bool nsDragService::IsTargetContextList(void) {
|
|
bool retval = false;
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
+ // TODO: We need a wayland implementation here.
|
|
+ if (!mTargetDragContext) return retval;
|
|
+#endif
|
|
+
|
|
// gMimeListType drags only work for drags within a single process. The
|
|
// gtk_drag_get_source_widget() function will return nullptr if the source
|
|
// of the drag is another app, so we use it to check if a gMimeListType
|
|
@@ -1032,17 +1108,27 @@ void nsDragService::GetTargetDragData(Gd
|
|
mTargetDragContext.get()));
|
|
// reset our target data areas
|
|
TargetResetData();
|
|
- gtk_drag_get_data(mTargetWidget, mTargetDragContext, aFlavor, mTargetTime);
|
|
|
|
- MOZ_LOG(sDragLm, LogLevel::Debug, ("about to start inner iteration."));
|
|
- PRTime entryTime = PR_Now();
|
|
- while (!mTargetDragDataReceived && mDoingDrag) {
|
|
- // check the number of iterations
|
|
- MOZ_LOG(sDragLm, LogLevel::Debug, ("doing iteration...\n"));
|
|
- PR_Sleep(20 * PR_TicksPerSecond() / 1000); /* sleep for 20 ms/iteration */
|
|
- if (PR_Now() - entryTime > NS_DND_TIMEOUT) break;
|
|
- gtk_main_iteration();
|
|
+ if (mTargetDragContext) {
|
|
+ gtk_drag_get_data(mTargetWidget, mTargetDragContext, aFlavor, mTargetTime);
|
|
+
|
|
+ MOZ_LOG(sDragLm, LogLevel::Debug, ("about to start inner iteration."));
|
|
+ PRTime entryTime = PR_Now();
|
|
+ while (!mTargetDragDataReceived && mDoingDrag) {
|
|
+ // check the number of iterations
|
|
+ MOZ_LOG(sDragLm, LogLevel::Debug, ("doing iteration...\n"));
|
|
+ PR_Sleep(20 * PR_TicksPerSecond() / 1000); /* sleep for 20 ms/iteration */
|
|
+ if (PR_Now() - entryTime > NS_DND_TIMEOUT) break;
|
|
+ gtk_main_iteration();
|
|
+ }
|
|
}
|
|
+#ifdef MOZ_WAYLAND
|
|
+ else {
|
|
+ mTargetDragData = mTargetWaylandDragContext->GetData(gdk_atom_name(aFlavor),
|
|
+ &mTargetDragDataLen);
|
|
+ mTargetDragDataReceived = true;
|
|
+ }
|
|
+#endif
|
|
MOZ_LOG(sDragLm, LogLevel::Debug, ("finished inner iteration\n"));
|
|
}
|
|
|
|
@@ -1218,6 +1304,10 @@ void nsDragService::SourceEndDragSession
|
|
// this just releases the list of data items that we provide
|
|
mSourceDataItems = nullptr;
|
|
|
|
+ // Remove this property, if it exists, to satisfy the Direct Save Protocol.
|
|
+ GdkAtom property = gdk_atom_intern(gXdndDirectSaveType, FALSE);
|
|
+ gdk_property_delete(gdk_drag_context_get_source_window(aContext), property);
|
|
+
|
|
if (!mDoingDrag || mScheduledTask == eDragTaskSourceEnd)
|
|
// EndDragSession() was already called on drop
|
|
// or SourceEndDragSession on drag-failed
|
|
@@ -1276,7 +1366,7 @@ void nsDragService::SourceEndDragSession
|
|
}
|
|
|
|
// Schedule the appropriate drag end dom events.
|
|
- Schedule(eDragTaskSourceEnd, nullptr, nullptr, LayoutDeviceIntPoint(), 0);
|
|
+ Schedule(eDragTaskSourceEnd, nullptr, nullptr, nullptr, LayoutDeviceIntPoint(), 0);
|
|
}
|
|
|
|
static void CreateUriList(nsIArray *items, gchar **text, gint *length) {
|
|
@@ -1585,11 +1675,11 @@ static void invisibleSourceDragEnd(GtkWi
|
|
// Gecko drag events are in flight. This helps event handlers that may not
|
|
// expect nested events, while accessing an event's dataTransfer for example.
|
|
|
|
-gboolean nsDragService::ScheduleMotionEvent(nsWindow *aWindow,
|
|
- GdkDragContext *aDragContext,
|
|
- LayoutDeviceIntPoint aWindowPoint,
|
|
- guint aTime) {
|
|
- if (mScheduledTask == eDragTaskMotion) {
|
|
+gboolean nsDragService::ScheduleMotionEvent(
|
|
+ nsWindow *aWindow, GdkDragContext *aDragContext,
|
|
+ nsWaylandDragContext *aWaylandDragContext,
|
|
+ LayoutDeviceIntPoint aWindowPoint, guint aTime) {
|
|
+ if (aDragContext && mScheduledTask == eDragTaskMotion) {
|
|
// The drag source has sent another motion message before we've
|
|
// replied to the previous. That shouldn't happen with Xdnd. The
|
|
// spec for Motif drags is less clear, but we'll just update the
|
|
@@ -1600,23 +1690,26 @@ gboolean nsDragService::ScheduleMotionEv
|
|
|
|
// Returning TRUE means we'll reply with a status message, unless we first
|
|
// get a leave.
|
|
- return Schedule(eDragTaskMotion, aWindow, aDragContext, aWindowPoint, aTime);
|
|
+ return Schedule(eDragTaskMotion, aWindow, aDragContext, aWaylandDragContext,
|
|
+ aWindowPoint, aTime);
|
|
}
|
|
|
|
void nsDragService::ScheduleLeaveEvent() {
|
|
// We don't know at this stage whether a drop signal will immediately
|
|
// follow. If the drop signal gets sent it will happen before we return
|
|
// to the main loop and the scheduled leave task will be replaced.
|
|
- if (!Schedule(eDragTaskLeave, nullptr, nullptr, LayoutDeviceIntPoint(), 0)) {
|
|
+ if (!Schedule(eDragTaskLeave, nullptr, nullptr, nullptr,
|
|
+ LayoutDeviceIntPoint(), 0)) {
|
|
NS_WARNING("Drag leave after drop");
|
|
}
|
|
}
|
|
|
|
-gboolean nsDragService::ScheduleDropEvent(nsWindow *aWindow,
|
|
- GdkDragContext *aDragContext,
|
|
- LayoutDeviceIntPoint aWindowPoint,
|
|
- guint aTime) {
|
|
- if (!Schedule(eDragTaskDrop, aWindow, aDragContext, aWindowPoint, aTime)) {
|
|
+gboolean nsDragService::ScheduleDropEvent(
|
|
+ nsWindow *aWindow, GdkDragContext *aDragContext,
|
|
+ nsWaylandDragContext *aWaylandDragContext,
|
|
+ LayoutDeviceIntPoint aWindowPoint, guint aTime) {
|
|
+ if (!Schedule(eDragTaskDrop, aWindow, aDragContext, aWaylandDragContext,
|
|
+ aWindowPoint, aTime)) {
|
|
NS_WARNING("Additional drag drop ignored");
|
|
return FALSE;
|
|
}
|
|
@@ -1629,6 +1722,7 @@ gboolean nsDragService::ScheduleDropEven
|
|
|
|
gboolean nsDragService::Schedule(DragTask aTask, nsWindow *aWindow,
|
|
GdkDragContext *aDragContext,
|
|
+ nsWaylandDragContext *aWaylandDragContext,
|
|
LayoutDeviceIntPoint aWindowPoint,
|
|
guint aTime) {
|
|
// If there is an existing leave or motion task scheduled, then that
|
|
@@ -1647,6 +1741,9 @@ gboolean nsDragService::Schedule(DragTas
|
|
mScheduledTask = aTask;
|
|
mPendingWindow = aWindow;
|
|
mPendingDragContext = aDragContext;
|
|
+#ifdef MOZ_WAYLAND
|
|
+ mPendingWaylandDragContext = aWaylandDragContext;
|
|
+#endif
|
|
mPendingWindowPoint = aWindowPoint;
|
|
mPendingTime = aTime;
|
|
|
|
@@ -1717,6 +1814,9 @@ gboolean nsDragService::RunScheduledTask
|
|
// succeeed.
|
|
mTargetWidget = mTargetWindow->GetMozContainerWidget();
|
|
mTargetDragContext.steal(mPendingDragContext);
|
|
+#ifdef MOZ_WAYLAND
|
|
+ mTargetWaylandDragContext = mPendingWaylandDragContext.forget();
|
|
+#endif
|
|
mTargetTime = mPendingTime;
|
|
|
|
// http://www.whatwg.org/specs/web-apps/current-work/multipage/dnd.html#drag-and-drop-processing-model
|
|
@@ -1748,10 +1848,20 @@ gboolean nsDragService::RunScheduledTask
|
|
if (task == eDragTaskMotion) {
|
|
if (TakeDragEventDispatchedToChildProcess()) {
|
|
mTargetDragContextForRemote = mTargetDragContext;
|
|
+#ifdef MOZ_WAYLAND
|
|
+ mTargetWaylandDragContextForRemote = mTargetWaylandDragContext;
|
|
+#endif
|
|
} else {
|
|
// Reply to tell the source whether we can drop and what
|
|
// action would be taken.
|
|
- ReplyToDragMotion(mTargetDragContext);
|
|
+ if (mTargetDragContext) {
|
|
+ ReplyToDragMotion(mTargetDragContext);
|
|
+ }
|
|
+#ifdef MOZ_WAYLAND
|
|
+ else if (mTargetWaylandDragContext) {
|
|
+ ReplyToDragMotion(mTargetWaylandDragContext);
|
|
+ }
|
|
+#endif
|
|
}
|
|
}
|
|
}
|
|
@@ -1762,8 +1872,10 @@ gboolean nsDragService::RunScheduledTask
|
|
// Perhaps we should set the del parameter to TRUE when the drag
|
|
// action is move, but we don't know whether the data was successfully
|
|
// transferred.
|
|
- gtk_drag_finish(mTargetDragContext, success,
|
|
- /* del = */ FALSE, mTargetTime);
|
|
+ if (mTargetDragContext) {
|
|
+ gtk_drag_finish(mTargetDragContext, success,
|
|
+ /* del = */ FALSE, mTargetTime);
|
|
+ }
|
|
|
|
// This drag is over, so clear out our reference to the previous
|
|
// window.
|
|
@@ -1776,6 +1888,9 @@ gboolean nsDragService::RunScheduledTask
|
|
// We're done with the drag context.
|
|
mTargetWidget = nullptr;
|
|
mTargetDragContext = nullptr;
|
|
+#ifdef MOZ_WAYLAND
|
|
+ mTargetWaylandDragContext = nullptr;
|
|
+#endif
|
|
|
|
// If we got another drag signal while running the sheduled task, that
|
|
// must have happened while running a nested event loop. Leave the task
|
|
@@ -1802,7 +1917,16 @@ void nsDragService::UpdateDragAction() {
|
|
|
|
// default is to do nothing
|
|
int action = nsIDragService::DRAGDROP_ACTION_NONE;
|
|
- GdkDragAction gdkAction = gdk_drag_context_get_actions(mTargetDragContext);
|
|
+ GdkDragAction gdkAction = GDK_ACTION_DEFAULT;
|
|
+ if (mTargetDragContext) {
|
|
+ gdkAction = gdk_drag_context_get_actions(mTargetDragContext);
|
|
+ }
|
|
+#ifdef MOZ_WAYLAND
|
|
+ else if (mTargetWaylandDragContext) {
|
|
+ // We got the selected D&D action from compositor on Wayland.
|
|
+ gdkAction = mTargetWaylandDragContext->GetSelectedDragAction();
|
|
+ }
|
|
+#endif
|
|
|
|
// set the default just in case nothing matches below
|
|
if (gdkAction & GDK_ACTION_DEFAULT)
|
|
@@ -1830,6 +1954,12 @@ nsDragService::UpdateDragEffect() {
|
|
ReplyToDragMotion(mTargetDragContextForRemote);
|
|
mTargetDragContextForRemote = nullptr;
|
|
}
|
|
+#ifdef MOZ_WAYLAND
|
|
+ else if (mTargetWaylandDragContextForRemote) {
|
|
+ ReplyToDragMotion(mTargetWaylandDragContextForRemote);
|
|
+ mTargetWaylandDragContextForRemote = nullptr;
|
|
+ }
|
|
+#endif
|
|
return NS_OK;
|
|
}
|
|
|
|
diff -up thunderbird-60.5.0/widget/gtk/nsDragService.h.wayland thunderbird-60.5.0/widget/gtk/nsDragService.h
|
|
--- thunderbird-60.5.0/widget/gtk/nsDragService.h.wayland 2019-01-22 20:44:03.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/nsDragService.h 2019-02-05 14:26:16.976316645 +0100
|
|
@@ -1,5 +1,5 @@
|
|
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
-/* vim: set ts=4 et sw=4 tw=80: */
|
|
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
+/* vim: set ts=4 et sw=2 tw=80: */
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
@@ -14,6 +14,7 @@
|
|
#include <gtk/gtk.h>
|
|
|
|
class nsWindow;
|
|
+class nsWaylandDragContext;
|
|
|
|
namespace mozilla {
|
|
namespace gfx {
|
|
@@ -91,10 +92,12 @@ class nsDragService final : public nsBas
|
|
guint aInfo, guint32 aTime);
|
|
|
|
gboolean ScheduleMotionEvent(nsWindow *aWindow, GdkDragContext *aDragContext,
|
|
+ nsWaylandDragContext *aPendingWaylandDragContext,
|
|
mozilla::LayoutDeviceIntPoint aWindowPoint,
|
|
guint aTime);
|
|
void ScheduleLeaveEvent();
|
|
gboolean ScheduleDropEvent(nsWindow *aWindow, GdkDragContext *aDragContext,
|
|
+ nsWaylandDragContext *aPendingWaylandDragContext,
|
|
mozilla::LayoutDeviceIntPoint aWindowPoint,
|
|
guint aTime);
|
|
|
|
@@ -111,6 +114,8 @@ class nsDragService final : public nsBas
|
|
void SourceDataGet(GtkWidget *widget, GdkDragContext *context,
|
|
GtkSelectionData *selection_data, guint32 aTime);
|
|
|
|
+ void SourceBeginDrag(GdkDragContext *aContext);
|
|
+
|
|
// set the drag icon during drag-begin
|
|
void SetDragIcon(GdkDragContext *aContext);
|
|
|
|
@@ -144,6 +149,9 @@ class nsDragService final : public nsBas
|
|
RefPtr<nsWindow> mPendingWindow;
|
|
mozilla::LayoutDeviceIntPoint mPendingWindowPoint;
|
|
nsCountedRef<GdkDragContext> mPendingDragContext;
|
|
+#ifdef MOZ_WAYLAND
|
|
+ RefPtr<nsWaylandDragContext> mPendingWaylandDragContext;
|
|
+#endif
|
|
guint mPendingTime;
|
|
|
|
// mTargetWindow and mTargetWindowPoint record the position of the last
|
|
@@ -155,9 +163,15 @@ class nsDragService final : public nsBas
|
|
// motion or drop events. mTime records the corresponding timestamp.
|
|
nsCountedRef<GtkWidget> mTargetWidget;
|
|
nsCountedRef<GdkDragContext> mTargetDragContext;
|
|
+#ifdef MOZ_WAYLAND
|
|
+ RefPtr<nsWaylandDragContext> mTargetWaylandDragContext;
|
|
+#endif
|
|
// mTargetDragContextForRemote is set while waiting for a reply from
|
|
// a child process.
|
|
nsCountedRef<GdkDragContext> mTargetDragContextForRemote;
|
|
+#ifdef MOZ_WAYLAND
|
|
+ RefPtr<nsWaylandDragContext> mTargetWaylandDragContextForRemote;
|
|
+#endif
|
|
guint mTargetTime;
|
|
|
|
// is it OK to drop on us?
|
|
@@ -196,6 +210,7 @@ class nsDragService final : public nsBas
|
|
|
|
gboolean Schedule(DragTask aTask, nsWindow *aWindow,
|
|
GdkDragContext *aDragContext,
|
|
+ nsWaylandDragContext *aPendingWaylandDragContext,
|
|
mozilla::LayoutDeviceIntPoint aWindowPoint, guint aTime);
|
|
|
|
// Callback for g_idle_add_full() to run mScheduledTask.
|
|
@@ -204,6 +219,9 @@ class nsDragService final : public nsBas
|
|
void UpdateDragAction();
|
|
void DispatchMotionEvents();
|
|
void ReplyToDragMotion(GdkDragContext *aDragContext);
|
|
+#ifdef MOZ_WAYLAND
|
|
+ void ReplyToDragMotion(nsWaylandDragContext *aDragContext);
|
|
+#endif
|
|
gboolean DispatchDropEvent();
|
|
static uint32_t GetCurrentModifiers();
|
|
};
|
|
diff -up thunderbird-60.5.0/widget/gtk/nsGtkKeyUtils.cpp.wayland thunderbird-60.5.0/widget/gtk/nsGtkKeyUtils.cpp
|
|
--- thunderbird-60.5.0/widget/gtk/nsGtkKeyUtils.cpp.wayland 2019-01-22 20:44:03.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/nsGtkKeyUtils.cpp 2019-02-05 14:26:16.976316645 +0100
|
|
@@ -1,4 +1,4 @@
|
|
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
*/
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
@@ -28,6 +28,10 @@
|
|
#include "mozilla/MouseEvents.h"
|
|
#include "mozilla/TextEvents.h"
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
+#include <sys/mman.h>
|
|
+#endif
|
|
+
|
|
namespace mozilla {
|
|
namespace widget {
|
|
|
|
@@ -200,7 +204,11 @@ void KeymapWrapper::Init() {
|
|
mModifierKeys.Clear();
|
|
memset(mModifierMasks, 0, sizeof(mModifierMasks));
|
|
|
|
- if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) InitBySystemSettings();
|
|
+ if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) InitBySystemSettingsX11();
|
|
+#ifdef MOZ_WAYLAND
|
|
+ else
|
|
+ InitBySystemSettingsWayland();
|
|
+#endif
|
|
|
|
gdk_window_add_filter(nullptr, FilterEvents, this);
|
|
|
|
@@ -276,9 +284,9 @@ void KeymapWrapper::InitXKBExtension() {
|
|
("%p InitXKBExtension, Succeeded", this));
|
|
}
|
|
|
|
-void KeymapWrapper::InitBySystemSettings() {
|
|
+void KeymapWrapper::InitBySystemSettingsX11() {
|
|
MOZ_LOG(gKeymapWrapperLog, LogLevel::Info,
|
|
- ("%p InitBySystemSettings, mGdkKeymap=%p", this, mGdkKeymap));
|
|
+ ("%p InitBySystemSettingsX11, mGdkKeymap=%p", this, mGdkKeymap));
|
|
|
|
Display* display = gdk_x11_display_get_xdisplay(gdk_display_get_default());
|
|
|
|
@@ -439,6 +447,163 @@ void KeymapWrapper::InitBySystemSettings
|
|
XFree(xkeymap);
|
|
}
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
+void KeymapWrapper::SetModifierMask(xkb_keymap* aKeymap,
|
|
+ ModifierIndex aModifierIndex,
|
|
+ const char* aModifierName) {
|
|
+ static auto sXkbKeymapModGetIndex =
|
|
+ (xkb_mod_index_t(*)(struct xkb_keymap*, const char*))dlsym(
|
|
+ RTLD_DEFAULT, "xkb_keymap_mod_get_index");
|
|
+
|
|
+ xkb_mod_index_t index = sXkbKeymapModGetIndex(aKeymap, aModifierName);
|
|
+ if (index != XKB_MOD_INVALID) {
|
|
+ mModifierMasks[aModifierIndex] = (1 << index);
|
|
+ }
|
|
+}
|
|
+
|
|
+void KeymapWrapper::SetModifierMasks(xkb_keymap* aKeymap) {
|
|
+ KeymapWrapper* keymapWrapper = GetInstance();
|
|
+
|
|
+ // This mapping is derived from get_xkb_modifiers() at gdkkeys-wayland.c
|
|
+ keymapWrapper->SetModifierMask(aKeymap, INDEX_NUM_LOCK, XKB_MOD_NAME_NUM);
|
|
+ keymapWrapper->SetModifierMask(aKeymap, INDEX_ALT, XKB_MOD_NAME_ALT);
|
|
+ keymapWrapper->SetModifierMask(aKeymap, INDEX_META, "Meta");
|
|
+ keymapWrapper->SetModifierMask(aKeymap, INDEX_SUPER, "Super");
|
|
+ keymapWrapper->SetModifierMask(aKeymap, INDEX_HYPER, "Hyper");
|
|
+
|
|
+ keymapWrapper->SetModifierMask(aKeymap, INDEX_SCROLL_LOCK, "ScrollLock");
|
|
+ keymapWrapper->SetModifierMask(aKeymap, INDEX_LEVEL3, "Level3");
|
|
+ keymapWrapper->SetModifierMask(aKeymap, INDEX_LEVEL5, "Level5");
|
|
+
|
|
+ MOZ_LOG(gKeymapWrapperLog, LogLevel::Info,
|
|
+ ("%p KeymapWrapper::SetModifierMasks, CapsLock=0x%X, NumLock=0x%X, "
|
|
+ "ScrollLock=0x%X, Level3=0x%X, Level5=0x%X, "
|
|
+ "Shift=0x%X, Ctrl=0x%X, Alt=0x%X, Meta=0x%X, Super=0x%X, Hyper=0x%X",
|
|
+ keymapWrapper, keymapWrapper->GetModifierMask(CAPS_LOCK),
|
|
+ keymapWrapper->GetModifierMask(NUM_LOCK),
|
|
+ keymapWrapper->GetModifierMask(SCROLL_LOCK),
|
|
+ keymapWrapper->GetModifierMask(LEVEL3),
|
|
+ keymapWrapper->GetModifierMask(LEVEL5),
|
|
+ keymapWrapper->GetModifierMask(SHIFT),
|
|
+ keymapWrapper->GetModifierMask(CTRL),
|
|
+ keymapWrapper->GetModifierMask(ALT),
|
|
+ keymapWrapper->GetModifierMask(META),
|
|
+ keymapWrapper->GetModifierMask(SUPER),
|
|
+ keymapWrapper->GetModifierMask(HYPER)));
|
|
+}
|
|
+
|
|
+/* This keymap routine is derived from weston-2.0.0/clients/simple-im.c
|
|
+ */
|
|
+static void keyboard_handle_keymap(void* data, struct wl_keyboard* wl_keyboard,
|
|
+ uint32_t format, int fd, uint32_t size) {
|
|
+ if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
|
|
+ close(fd);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ char* mapString = (char*)mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
|
|
+ if (mapString == MAP_FAILED) {
|
|
+ close(fd);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ static auto sXkbContextNew =
|
|
+ (struct xkb_context * (*)(enum xkb_context_flags))
|
|
+ dlsym(RTLD_DEFAULT, "xkb_context_new");
|
|
+ static auto sXkbKeymapNewFromString =
|
|
+ (struct xkb_keymap * (*)(struct xkb_context*, const char*,
|
|
+ enum xkb_keymap_format,
|
|
+ enum xkb_keymap_compile_flags))
|
|
+ dlsym(RTLD_DEFAULT, "xkb_keymap_new_from_string");
|
|
+
|
|
+ struct xkb_context* xkb_context = sXkbContextNew(XKB_CONTEXT_NO_FLAGS);
|
|
+ struct xkb_keymap* keymap =
|
|
+ sXkbKeymapNewFromString(xkb_context, mapString, XKB_KEYMAP_FORMAT_TEXT_V1,
|
|
+ XKB_KEYMAP_COMPILE_NO_FLAGS);
|
|
+
|
|
+ munmap(mapString, size);
|
|
+ close(fd);
|
|
+
|
|
+ if (!keymap) {
|
|
+ NS_WARNING("keyboard_handle_keymap(): Failed to compile keymap!\n");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ KeymapWrapper::SetModifierMasks(keymap);
|
|
+
|
|
+ static auto sXkbKeymapUnRef =
|
|
+ (void (*)(struct xkb_keymap*))dlsym(RTLD_DEFAULT, "xkb_keymap_unref");
|
|
+ sXkbKeymapUnRef(keymap);
|
|
+
|
|
+ static auto sXkbContextUnref =
|
|
+ (void (*)(struct xkb_context*))dlsym(RTLD_DEFAULT, "xkb_context_unref");
|
|
+ sXkbContextUnref(xkb_context);
|
|
+}
|
|
+
|
|
+static void keyboard_handle_enter(void* data, struct wl_keyboard* keyboard,
|
|
+ uint32_t serial, struct wl_surface* surface,
|
|
+ struct wl_array* keys) {}
|
|
+static void keyboard_handle_leave(void* data, struct wl_keyboard* keyboard,
|
|
+ uint32_t serial, struct wl_surface* surface) {
|
|
+}
|
|
+static void keyboard_handle_key(void* data, struct wl_keyboard* keyboard,
|
|
+ uint32_t serial, uint32_t time, uint32_t key,
|
|
+ uint32_t state) {}
|
|
+static void keyboard_handle_modifiers(void* data, struct wl_keyboard* keyboard,
|
|
+ uint32_t serial, uint32_t mods_depressed,
|
|
+ uint32_t mods_latched,
|
|
+ uint32_t mods_locked, uint32_t group) {}
|
|
+
|
|
+static const struct wl_keyboard_listener keyboard_listener = {
|
|
+ keyboard_handle_keymap, keyboard_handle_enter, keyboard_handle_leave,
|
|
+ keyboard_handle_key, keyboard_handle_modifiers,
|
|
+};
|
|
+
|
|
+static void seat_handle_capabilities(void* data, struct wl_seat* seat,
|
|
+ unsigned int caps) {
|
|
+ static wl_keyboard* keyboard = nullptr;
|
|
+
|
|
+ if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !keyboard) {
|
|
+ keyboard = wl_seat_get_keyboard(seat);
|
|
+ wl_keyboard_add_listener(keyboard, &keyboard_listener, nullptr);
|
|
+ } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && keyboard) {
|
|
+ wl_keyboard_destroy(keyboard);
|
|
+ keyboard = nullptr;
|
|
+ }
|
|
+}
|
|
+
|
|
+static const struct wl_seat_listener seat_listener = {
|
|
+ seat_handle_capabilities,
|
|
+};
|
|
+
|
|
+static void gdk_registry_handle_global(void* data, struct wl_registry* registry,
|
|
+ uint32_t id, const char* interface,
|
|
+ uint32_t version) {
|
|
+ if (strcmp(interface, "wl_seat") == 0) {
|
|
+ wl_seat* seat =
|
|
+ (wl_seat*)wl_registry_bind(registry, id, &wl_seat_interface, 1);
|
|
+ wl_seat_add_listener(seat, &seat_listener, data);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void gdk_registry_handle_global_remove(void* data,
|
|
+ struct wl_registry* registry,
|
|
+ uint32_t id) {}
|
|
+
|
|
+static const struct wl_registry_listener keyboard_registry_listener = {
|
|
+ gdk_registry_handle_global, gdk_registry_handle_global_remove};
|
|
+
|
|
+void KeymapWrapper::InitBySystemSettingsWayland() {
|
|
+ // Available as of GTK 3.8+
|
|
+ static auto sGdkWaylandDisplayGetWlDisplay = (wl_display * (*)(GdkDisplay*))
|
|
+ dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
|
|
+ wl_display* display =
|
|
+ sGdkWaylandDisplayGetWlDisplay(gdk_display_get_default());
|
|
+ wl_registry_add_listener(wl_display_get_registry(display),
|
|
+ &keyboard_registry_listener, this);
|
|
+}
|
|
+#endif
|
|
+
|
|
KeymapWrapper::~KeymapWrapper() {
|
|
gdk_window_remove_filter(nullptr, FilterEvents, this);
|
|
g_signal_handlers_disconnect_by_func(mGdkKeymap,
|
|
@@ -1473,6 +1638,14 @@ void KeymapWrapper::WillDispatchKeyboard
|
|
|
|
void KeymapWrapper::WillDispatchKeyboardEventInternal(
|
|
WidgetKeyboardEvent& aKeyEvent, GdkEventKey* aGdkKeyEvent) {
|
|
+ if (!aGdkKeyEvent) {
|
|
+ // If aGdkKeyEvent is nullptr, we're trying to dispatch a fake keyboard
|
|
+ // event in such case, we don't need to set alternative char codes.
|
|
+ // So, we don't need to do nothing here. This case is typically we're
|
|
+ // dispatching eKeyDown or eKeyUp event during composition.
|
|
+ return;
|
|
+ }
|
|
+
|
|
uint32_t charCode = GetCharCodeFor(aGdkKeyEvent);
|
|
if (!charCode) {
|
|
MOZ_LOG(gKeymapWrapperLog, LogLevel::Info,
|
|
diff -up thunderbird-60.5.0/widget/gtk/nsGtkKeyUtils.h.wayland thunderbird-60.5.0/widget/gtk/nsGtkKeyUtils.h
|
|
--- thunderbird-60.5.0/widget/gtk/nsGtkKeyUtils.h.wayland 2019-01-22 20:44:04.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/nsGtkKeyUtils.h 2019-02-05 14:26:16.976316645 +0100
|
|
@@ -1,4 +1,4 @@
|
|
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
*/
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
@@ -13,6 +13,10 @@
|
|
|
|
#include <gdk/gdk.h>
|
|
#include <X11/XKBlib.h>
|
|
+#ifdef MOZ_WAYLAND
|
|
+#include <gdk/gdkwayland.h>
|
|
+#include <xkbcommon/xkbcommon.h>
|
|
+#endif
|
|
|
|
namespace mozilla {
|
|
namespace widget {
|
|
@@ -145,6 +149,14 @@ class KeymapWrapper {
|
|
static void WillDispatchKeyboardEvent(WidgetKeyboardEvent& aKeyEvent,
|
|
GdkEventKey* aGdkKeyEvent);
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
+ /**
|
|
+ * Utility function to set all supported modifier masks
|
|
+ * from xkb_keymap. We call that from Wayland backend routines.
|
|
+ */
|
|
+ static void SetModifierMasks(xkb_keymap* aKeymap);
|
|
+#endif
|
|
+
|
|
/**
|
|
* Destroys the singleton KeymapWrapper instance, if it exists.
|
|
*/
|
|
@@ -168,7 +180,10 @@ class KeymapWrapper {
|
|
*/
|
|
void Init();
|
|
void InitXKBExtension();
|
|
- void InitBySystemSettings();
|
|
+ void InitBySystemSettingsX11();
|
|
+#ifdef MOZ_WAYLAND
|
|
+ void InitBySystemSettingsWayland();
|
|
+#endif
|
|
|
|
/**
|
|
* mModifierKeys stores each hardware key information.
|
|
@@ -360,6 +375,14 @@ class KeymapWrapper {
|
|
*/
|
|
void WillDispatchKeyboardEventInternal(WidgetKeyboardEvent& aKeyEvent,
|
|
GdkEventKey* aGdkKeyEvent);
|
|
+
|
|
+#ifdef MOZ_WAYLAND
|
|
+ /**
|
|
+ * Utility function to set Xkb modifier key mask.
|
|
+ */
|
|
+ void SetModifierMask(xkb_keymap* aKeymap, ModifierIndex aModifierIndex,
|
|
+ const char* aModifierName);
|
|
+#endif
|
|
};
|
|
|
|
} // namespace widget
|
|
diff -up thunderbird-60.5.0/widget/gtk/nsLookAndFeel.cpp.wayland thunderbird-60.5.0/widget/gtk/nsLookAndFeel.cpp
|
|
--- thunderbird-60.5.0/widget/gtk/nsLookAndFeel.cpp.wayland 2019-01-22 20:44:03.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/nsLookAndFeel.cpp 2019-02-05 14:26:16.977316642 +0100
|
|
@@ -1,4 +1,4 @@
|
|
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
*/
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
@@ -18,6 +18,7 @@
|
|
|
|
#include <fontconfig/fontconfig.h>
|
|
#include "gfxPlatformGtk.h"
|
|
+//#include "mozilla/FontPropertyTypes.h"
|
|
#include "ScreenHelperGTK.h"
|
|
|
|
#include "gtkdrawing.h"
|
|
@@ -31,7 +32,9 @@
|
|
#include <cairo-gobject.h>
|
|
#include "WidgetStyleCache.h"
|
|
#include "prenv.h"
|
|
+#include "nsCSSColorUtils.h"
|
|
|
|
+using namespace mozilla;
|
|
using mozilla::LookAndFeel;
|
|
|
|
#define GDK_COLOR_TO_NS_RGB(c) \
|
|
@@ -170,7 +173,7 @@ static bool GetBorderColors(GtkStyleCont
|
|
// GTK has an initial value of zero for border-widths, and so themes
|
|
// need to explicitly set border-widths to make borders visible.
|
|
GtkBorder border;
|
|
- gtk_style_context_get_border(aContext, GTK_STATE_FLAG_NORMAL, &border);
|
|
+ gtk_style_context_get_border(aContext, state, &border);
|
|
visible = border.top != 0 || border.right != 0 || border.bottom != 0 ||
|
|
border.left != 0;
|
|
}
|
|
@@ -199,6 +202,57 @@ static bool GetBorderColors(GtkStyleCont
|
|
return ret;
|
|
}
|
|
|
|
+// Finds ideal cell highlight colors used for unfocused+selected cells distinct
|
|
+// from both Highlight, used as focused+selected background, and the listbox
|
|
+// background which is assumed to be similar to -moz-field
|
|
+nsresult nsLookAndFeel::InitCellHighlightColors() {
|
|
+ // NS_SUFFICIENT_LUMINOSITY_DIFFERENCE is the a11y standard for text
|
|
+ // on a background. Use 20% of that standard since we have a background
|
|
+ // on top of another background
|
|
+ int32_t minLuminosityDifference = NS_SUFFICIENT_LUMINOSITY_DIFFERENCE / 5;
|
|
+ int32_t backLuminosityDifference =
|
|
+ NS_LUMINOSITY_DIFFERENCE(mMozWindowBackground, mMozFieldBackground);
|
|
+ if (backLuminosityDifference >= minLuminosityDifference) {
|
|
+ mMozCellHighlightBackground = mMozWindowBackground;
|
|
+ mMozCellHighlightText = mMozWindowText;
|
|
+ return NS_OK;
|
|
+ }
|
|
+
|
|
+ uint16_t hue, sat, luminance;
|
|
+ uint8_t alpha;
|
|
+ mMozCellHighlightBackground = mMozFieldBackground;
|
|
+ mMozCellHighlightText = mMozFieldText;
|
|
+
|
|
+ NS_RGB2HSV(mMozCellHighlightBackground, hue, sat, luminance, alpha);
|
|
+
|
|
+ uint16_t step = 30;
|
|
+ // Lighten the color if the color is very dark
|
|
+ if (luminance <= step) {
|
|
+ luminance += step;
|
|
+ }
|
|
+ // Darken it if it is very light
|
|
+ else if (luminance >= 255 - step) {
|
|
+ luminance -= step;
|
|
+ }
|
|
+ // Otherwise, compute what works best depending on the text luminance.
|
|
+ else {
|
|
+ uint16_t textHue, textSat, textLuminance;
|
|
+ uint8_t textAlpha;
|
|
+ NS_RGB2HSV(mMozCellHighlightText, textHue, textSat, textLuminance,
|
|
+ textAlpha);
|
|
+ // Text is darker than background, use a lighter shade
|
|
+ if (textLuminance < luminance) {
|
|
+ luminance += step;
|
|
+ }
|
|
+ // Otherwise, use a darker shade
|
|
+ else {
|
|
+ luminance -= step;
|
|
+ }
|
|
+ }
|
|
+ NS_HSV2RGB(mMozCellHighlightBackground, hue, sat, luminance, alpha);
|
|
+ return NS_OK;
|
|
+}
|
|
+
|
|
void nsLookAndFeel::NativeInit() { EnsureInit(); }
|
|
|
|
void nsLookAndFeel::RefreshImpl() {
|
|
@@ -248,7 +302,6 @@ nsresult nsLookAndFeel::NativeGetColor(C
|
|
case eColorID_IMESelectedRawTextBackground:
|
|
case eColorID_IMESelectedConvertedTextBackground:
|
|
case eColorID__moz_dragtargetzone:
|
|
- case eColorID__moz_cellhighlight:
|
|
case eColorID__moz_html_cellhighlight:
|
|
case eColorID_highlight: // preference selected item,
|
|
aColor = mTextSelectedBackground;
|
|
@@ -258,10 +311,15 @@ nsresult nsLookAndFeel::NativeGetColor(C
|
|
case eColorID_IMESelectedRawTextForeground:
|
|
case eColorID_IMESelectedConvertedTextForeground:
|
|
case eColorID_highlighttext:
|
|
- case eColorID__moz_cellhighlighttext:
|
|
case eColorID__moz_html_cellhighlighttext:
|
|
aColor = mTextSelectedText;
|
|
break;
|
|
+ case eColorID__moz_cellhighlight:
|
|
+ aColor = mMozCellHighlightBackground;
|
|
+ break;
|
|
+ case eColorID__moz_cellhighlighttext:
|
|
+ aColor = mMozCellHighlightText;
|
|
+ break;
|
|
case eColorID_Widget3DHighlight:
|
|
aColor = NS_RGB(0xa0, 0xa0, 0xa0);
|
|
break;
|
|
@@ -961,6 +1019,9 @@ void nsLookAndFeel::EnsureInit() {
|
|
mOddCellBackground = GDK_RGBA_TO_NS_RGBA(color);
|
|
gtk_style_context_restore(style);
|
|
|
|
+ // Compute cell highlight colors
|
|
+ InitCellHighlightColors();
|
|
+
|
|
// GtkFrame has a "border" subnode on which Adwaita draws the border.
|
|
// Some themes do not draw on this node but draw a border on the widget
|
|
// root node, so check the root node if no border is found on the border
|
|
diff -up thunderbird-60.5.0/widget/gtk/nsLookAndFeel.h.wayland thunderbird-60.5.0/widget/gtk/nsLookAndFeel.h
|
|
--- thunderbird-60.5.0/widget/gtk/nsLookAndFeel.h.wayland 2019-01-22 20:44:03.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/nsLookAndFeel.h 2019-02-05 14:26:16.977316642 +0100
|
|
@@ -1,4 +1,4 @@
|
|
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
*/
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
@@ -8,6 +8,7 @@
|
|
#ifndef __nsLookAndFeel
|
|
#define __nsLookAndFeel
|
|
|
|
+#include "X11UndefineNone.h"
|
|
#include "nsXPLookAndFeel.h"
|
|
#include "nsCOMPtr.h"
|
|
#include "gfxFont.h"
|
|
@@ -75,6 +76,8 @@ class nsLookAndFeel final : public nsXPL
|
|
nscolor mMozWindowActiveBorder;
|
|
nscolor mMozWindowInactiveBorder;
|
|
nscolor mMozWindowInactiveCaption;
|
|
+ nscolor mMozCellHighlightBackground;
|
|
+ nscolor mMozCellHighlightText;
|
|
nscolor mTextSelectedText;
|
|
nscolor mTextSelectedBackground;
|
|
nscolor mMozScrollbar;
|
|
@@ -89,6 +92,9 @@ class nsLookAndFeel final : public nsXPL
|
|
bool mInitialized;
|
|
|
|
void EnsureInit();
|
|
+
|
|
+ private:
|
|
+ nsresult InitCellHighlightColors();
|
|
};
|
|
|
|
#endif
|
|
diff -up thunderbird-60.5.0/widget/gtk/nsWaylandDisplay.cpp.wayland thunderbird-60.5.0/widget/gtk/nsWaylandDisplay.cpp
|
|
--- thunderbird-60.5.0/widget/gtk/nsWaylandDisplay.cpp.wayland 2019-02-05 14:26:16.977316642 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/nsWaylandDisplay.cpp 2019-02-05 14:26:16.977316642 +0100
|
|
@@ -0,0 +1,222 @@
|
|
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
+/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
+ */
|
|
+/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
+
|
|
+#include "nsWaylandDisplay.h"
|
|
+
|
|
+#include "base/message_loop.h" // for MessageLoop
|
|
+#include "base/task.h" // for NewRunnableMethod, etc
|
|
+#include "mozilla/StaticMutex.h"
|
|
+
|
|
+namespace mozilla {
|
|
+namespace widget {
|
|
+
|
|
+#define MAX_DISPLAY_CONNECTIONS 2
|
|
+
|
|
+static nsWaylandDisplay *gWaylandDisplays[MAX_DISPLAY_CONNECTIONS];
|
|
+static StaticMutex gWaylandDisplaysMutex;
|
|
+
|
|
+// Each thread which is using wayland connection (wl_display) has to operate
|
|
+// its own wl_event_queue. Main Firefox thread wl_event_queue is handled
|
|
+// by Gtk main loop, other threads/wl_event_queue has to be handled by us.
|
|
+//
|
|
+// nsWaylandDisplay is our interface to wayland compositor. It provides wayland
|
|
+// global objects as we need (wl_display, wl_shm) and operates wl_event_queue on
|
|
+// compositor (not the main) thread.
|
|
+static void WaylandDisplayLoop(wl_display *aDisplay);
|
|
+
|
|
+// Get WaylandDisplay for given wl_display and actual calling thread.
|
|
+static nsWaylandDisplay *WaylandDisplayGetLocked(wl_display *aDisplay,
|
|
+ const StaticMutexAutoLock &) {
|
|
+ for (auto &display : gWaylandDisplays) {
|
|
+ if (display && display->Matches(aDisplay)) {
|
|
+ NS_ADDREF(display);
|
|
+ return display;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ for (auto &display : gWaylandDisplays) {
|
|
+ if (display == nullptr) {
|
|
+ display = new nsWaylandDisplay(aDisplay);
|
|
+ NS_ADDREF(display);
|
|
+ return display;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ MOZ_CRASH("There's too many wayland display conections!");
|
|
+ return nullptr;
|
|
+}
|
|
+
|
|
+nsWaylandDisplay *WaylandDisplayGet(GdkDisplay *aGdkDisplay) {
|
|
+ if (!aGdkDisplay) {
|
|
+ aGdkDisplay = gdk_display_get_default();
|
|
+ }
|
|
+
|
|
+ // Available as of GTK 3.8+
|
|
+ static auto sGdkWaylandDisplayGetWlDisplay = (wl_display * (*)(GdkDisplay *))
|
|
+ dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
|
|
+
|
|
+ wl_display *display = sGdkWaylandDisplayGetWlDisplay(aGdkDisplay);
|
|
+
|
|
+ StaticMutexAutoLock lock(gWaylandDisplaysMutex);
|
|
+ return WaylandDisplayGetLocked(display, lock);
|
|
+}
|
|
+
|
|
+static bool WaylandDisplayReleaseLocked(nsWaylandDisplay *aDisplay,
|
|
+ const StaticMutexAutoLock &) {
|
|
+ for (auto &display : gWaylandDisplays) {
|
|
+ if (display == aDisplay) {
|
|
+ int rc = display->Release();
|
|
+ if (rc == 0) {
|
|
+ display = nullptr;
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ MOZ_ASSERT(false, "Missing nsWaylandDisplay for this thread!");
|
|
+ return false;
|
|
+}
|
|
+
|
|
+void WaylandDisplayRelease(nsWaylandDisplay *aDisplay) {
|
|
+ StaticMutexAutoLock lock(gWaylandDisplaysMutex);
|
|
+ WaylandDisplayReleaseLocked(aDisplay, lock);
|
|
+}
|
|
+
|
|
+static void WaylandDisplayLoopLocked(wl_display *aDisplay,
|
|
+ const StaticMutexAutoLock &) {
|
|
+ for (auto &display : gWaylandDisplays) {
|
|
+ if (display && display->Matches(aDisplay)) {
|
|
+ if (display->DisplayLoop()) {
|
|
+ MessageLoop::current()->PostDelayedTask(
|
|
+ NewRunnableFunction("WaylandDisplayLoop", &WaylandDisplayLoop,
|
|
+ aDisplay),
|
|
+ EVENT_LOOP_DELAY);
|
|
+ }
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static void WaylandDisplayLoop(wl_display *aDisplay) {
|
|
+ MOZ_ASSERT(!NS_IsMainThread());
|
|
+ StaticMutexAutoLock lock(gWaylandDisplaysMutex);
|
|
+ WaylandDisplayLoopLocked(aDisplay, lock);
|
|
+}
|
|
+
|
|
+void nsWaylandDisplay::SetShm(wl_shm *aShm) { mShm = aShm; }
|
|
+
|
|
+void nsWaylandDisplay::SetSubcompositor(wl_subcompositor *aSubcompositor) {
|
|
+ mSubcompositor = aSubcompositor;
|
|
+}
|
|
+
|
|
+void nsWaylandDisplay::SetDataDeviceManager(
|
|
+ wl_data_device_manager *aDataDeviceManager) {
|
|
+ mDataDeviceManager = aDataDeviceManager;
|
|
+}
|
|
+
|
|
+void nsWaylandDisplay::SetSeat(wl_seat *aSeat) { mSeat = aSeat; }
|
|
+
|
|
+void nsWaylandDisplay::SetPrimarySelectionDeviceManager(
|
|
+ gtk_primary_selection_device_manager *aPrimarySelectionDeviceManager) {
|
|
+ mPrimarySelectionDeviceManager = aPrimarySelectionDeviceManager;
|
|
+}
|
|
+
|
|
+static void global_registry_handler(void *data, wl_registry *registry,
|
|
+ uint32_t id, const char *interface,
|
|
+ uint32_t version) {
|
|
+ auto display = reinterpret_cast<nsWaylandDisplay *>(data);
|
|
+
|
|
+ if (strcmp(interface, "wl_shm") == 0) {
|
|
+ auto shm = static_cast<wl_shm *>(
|
|
+ wl_registry_bind(registry, id, &wl_shm_interface, 1));
|
|
+ wl_proxy_set_queue((struct wl_proxy *)shm, display->GetEventQueue());
|
|
+ display->SetShm(shm);
|
|
+ } else if (strcmp(interface, "wl_data_device_manager") == 0) {
|
|
+ int data_device_manager_version = MIN(version, 3);
|
|
+ auto data_device_manager = static_cast<wl_data_device_manager *>(
|
|
+ wl_registry_bind(registry, id, &wl_data_device_manager_interface,
|
|
+ data_device_manager_version));
|
|
+ wl_proxy_set_queue((struct wl_proxy *)data_device_manager,
|
|
+ display->GetEventQueue());
|
|
+ display->SetDataDeviceManager(data_device_manager);
|
|
+ } else if (strcmp(interface, "wl_seat") == 0) {
|
|
+ auto seat = static_cast<wl_seat *>(
|
|
+ wl_registry_bind(registry, id, &wl_seat_interface, 1));
|
|
+ wl_proxy_set_queue((struct wl_proxy *)seat, display->GetEventQueue());
|
|
+ display->SetSeat(seat);
|
|
+ } else if (strcmp(interface, "gtk_primary_selection_device_manager") == 0) {
|
|
+ auto primary_selection_device_manager =
|
|
+ static_cast<gtk_primary_selection_device_manager *>(wl_registry_bind(
|
|
+ registry, id, >k_primary_selection_device_manager_interface, 1));
|
|
+ wl_proxy_set_queue((struct wl_proxy *)primary_selection_device_manager,
|
|
+ display->GetEventQueue());
|
|
+ display->SetPrimarySelectionDeviceManager(primary_selection_device_manager);
|
|
+ } else if (strcmp(interface, "wl_subcompositor") == 0) {
|
|
+ auto subcompositor = static_cast<wl_subcompositor *>(
|
|
+ wl_registry_bind(registry, id, &wl_subcompositor_interface, 1));
|
|
+ wl_proxy_set_queue((struct wl_proxy *)subcompositor,
|
|
+ display->GetEventQueue());
|
|
+ display->SetSubcompositor(subcompositor);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void global_registry_remover(void *data, wl_registry *registry,
|
|
+ uint32_t id) {}
|
|
+
|
|
+static const struct wl_registry_listener registry_listener = {
|
|
+ global_registry_handler, global_registry_remover};
|
|
+
|
|
+bool nsWaylandDisplay::DisplayLoop() {
|
|
+ wl_display_dispatch_queue_pending(mDisplay, mEventQueue);
|
|
+ return true;
|
|
+}
|
|
+
|
|
+bool nsWaylandDisplay::Matches(wl_display *aDisplay) {
|
|
+ return mThreadId == PR_GetCurrentThread() && aDisplay == mDisplay;
|
|
+}
|
|
+
|
|
+NS_IMPL_ISUPPORTS(nsWaylandDisplay, nsISupports);
|
|
+
|
|
+nsWaylandDisplay::nsWaylandDisplay(wl_display *aDisplay)
|
|
+ : mThreadId(PR_GetCurrentThread()),
|
|
+ mDisplay(aDisplay),
|
|
+ mEventQueue(nullptr),
|
|
+ mDataDeviceManager(nullptr),
|
|
+ mSubcompositor(nullptr),
|
|
+ mSeat(nullptr),
|
|
+ mShm(nullptr),
|
|
+ mPrimarySelectionDeviceManager(nullptr) {
|
|
+ wl_registry *registry = wl_display_get_registry(mDisplay);
|
|
+ wl_registry_add_listener(registry, ®istry_listener, this);
|
|
+
|
|
+ if (NS_IsMainThread()) {
|
|
+ // Use default event queue in main thread operated by Gtk+.
|
|
+ mEventQueue = nullptr;
|
|
+ wl_display_roundtrip(mDisplay);
|
|
+ wl_display_roundtrip(mDisplay);
|
|
+ } else {
|
|
+ mEventQueue = wl_display_create_queue(mDisplay);
|
|
+ MessageLoop::current()->PostTask(NewRunnableFunction(
|
|
+ "WaylandDisplayLoop", &WaylandDisplayLoop, mDisplay));
|
|
+ wl_proxy_set_queue((struct wl_proxy *)registry, mEventQueue);
|
|
+ wl_display_roundtrip_queue(mDisplay, mEventQueue);
|
|
+ wl_display_roundtrip_queue(mDisplay, mEventQueue);
|
|
+ }
|
|
+}
|
|
+
|
|
+nsWaylandDisplay::~nsWaylandDisplay() {
|
|
+ MOZ_ASSERT(mThreadId == PR_GetCurrentThread());
|
|
+ // Owned by Gtk+, we don't need to release
|
|
+ mDisplay = nullptr;
|
|
+
|
|
+ if (mEventQueue) {
|
|
+ wl_event_queue_destroy(mEventQueue);
|
|
+ mEventQueue = nullptr;
|
|
+ }
|
|
+}
|
|
+
|
|
+} // namespace widget
|
|
+} // namespace mozilla
|
|
diff -up thunderbird-60.5.0/widget/gtk/nsWaylandDisplay.h.wayland thunderbird-60.5.0/widget/gtk/nsWaylandDisplay.h
|
|
--- thunderbird-60.5.0/widget/gtk/nsWaylandDisplay.h.wayland 2019-02-05 14:26:16.977316642 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/nsWaylandDisplay.h 2019-02-05 14:26:16.977316642 +0100
|
|
@@ -0,0 +1,72 @@
|
|
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
+/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
+ */
|
|
+/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
+
|
|
+#ifndef __MOZ_WAYLAND_REGISTRY_H__
|
|
+#define __MOZ_WAYLAND_REGISTRY_H__
|
|
+
|
|
+#include "nsISupports.h"
|
|
+#include "mozwayland/mozwayland.h"
|
|
+#include "wayland/gtk-primary-selection-client-protocol.h"
|
|
+
|
|
+namespace mozilla {
|
|
+namespace widget {
|
|
+
|
|
+// TODO: Bug 1467125 - We need to integrate wl_display_dispatch_queue_pending()
|
|
+// with compositor event loop.
|
|
+#define EVENT_LOOP_DELAY (1000 / 240)
|
|
+
|
|
+// Our general connection to Wayland display server,
|
|
+// holds our display connection and runs event loop.
|
|
+class nsWaylandDisplay : public nsISupports {
|
|
+ NS_DECL_THREADSAFE_ISUPPORTS
|
|
+
|
|
+ public:
|
|
+ explicit nsWaylandDisplay(wl_display* aDisplay);
|
|
+
|
|
+ bool DisplayLoop();
|
|
+ bool Matches(wl_display* aDisplay);
|
|
+
|
|
+ wl_display* GetDisplay() { return mDisplay; };
|
|
+ wl_event_queue* GetEventQueue() { return mEventQueue; };
|
|
+ wl_subcompositor* GetSubcompositor(void) { return mSubcompositor; };
|
|
+ wl_data_device_manager* GetDataDeviceManager(void) {
|
|
+ return mDataDeviceManager;
|
|
+ };
|
|
+ wl_seat* GetSeat(void) { return mSeat; };
|
|
+ wl_shm* GetShm(void) { return mShm; };
|
|
+ gtk_primary_selection_device_manager* GetPrimarySelectionDeviceManager(void) {
|
|
+ return mPrimarySelectionDeviceManager;
|
|
+ };
|
|
+
|
|
+ public:
|
|
+ void SetShm(wl_shm* aShm);
|
|
+ void SetSubcompositor(wl_subcompositor* aSubcompositor);
|
|
+ void SetDataDeviceManager(wl_data_device_manager* aDataDeviceManager);
|
|
+ void SetSeat(wl_seat* aSeat);
|
|
+ void SetPrimarySelectionDeviceManager(
|
|
+ gtk_primary_selection_device_manager* aPrimarySelectionDeviceManager);
|
|
+
|
|
+ private:
|
|
+ virtual ~nsWaylandDisplay();
|
|
+
|
|
+ PRThread* mThreadId;
|
|
+ wl_display* mDisplay;
|
|
+ wl_event_queue* mEventQueue;
|
|
+ wl_data_device_manager* mDataDeviceManager;
|
|
+ wl_subcompositor* mSubcompositor;
|
|
+ wl_seat* mSeat;
|
|
+ wl_shm* mShm;
|
|
+ gtk_primary_selection_device_manager* mPrimarySelectionDeviceManager;
|
|
+};
|
|
+
|
|
+nsWaylandDisplay* WaylandDisplayGet(GdkDisplay* aGdkDisplay = nullptr);
|
|
+void WaylandDisplayRelease(nsWaylandDisplay* aDisplay);
|
|
+
|
|
+} // namespace widget
|
|
+} // namespace mozilla
|
|
+
|
|
+#endif // __MOZ_WAYLAND_REGISTRY_H__
|
|
diff -up thunderbird-60.5.0/widget/gtk/nsWindow.cpp.wayland thunderbird-60.5.0/widget/gtk/nsWindow.cpp
|
|
--- thunderbird-60.5.0/widget/gtk/nsWindow.cpp.wayland 2019-01-22 20:44:03.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/nsWindow.cpp 2019-02-05 14:26:16.978316639 +0100
|
|
@@ -1,4 +1,4 @@
|
|
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
*/
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
@@ -18,6 +18,7 @@
|
|
#include "mozilla/TouchEvents.h"
|
|
#include "mozilla/UniquePtrExtensions.h"
|
|
#include "mozilla/WidgetUtils.h"
|
|
+#include "mozilla/dom/WheelEventBinding.h"
|
|
#include <algorithm>
|
|
|
|
#include "GeckoProfiler.h"
|
|
@@ -25,13 +26,15 @@
|
|
#include "prlink.h"
|
|
#include "nsGTKToolkit.h"
|
|
#include "nsIRollupListener.h"
|
|
-#include "nsIDOMNode.h"
|
|
+#include "nsINode.h"
|
|
|
|
#include "nsWidgetsCID.h"
|
|
#include "nsDragService.h"
|
|
#include "nsIWidgetListener.h"
|
|
#include "nsIScreenManager.h"
|
|
#include "SystemTimeConverter.h"
|
|
+#include "nsIPresShell.h"
|
|
+#include "nsViewManager.h"
|
|
|
|
#include "nsGtkKeyUtils.h"
|
|
#include "nsGtkCursors.h"
|
|
@@ -56,6 +59,7 @@
|
|
|
|
#if defined(MOZ_WAYLAND)
|
|
#include <gdk/gdkwayland.h>
|
|
+#include "nsView.h"
|
|
#endif
|
|
|
|
#include "nsGkAtoms.h"
|
|
@@ -116,6 +120,7 @@ using namespace mozilla::widget;
|
|
#include "mozilla/layers/CompositorThread.h"
|
|
|
|
#ifdef MOZ_X11
|
|
+#include "GLContextGLX.h" // for GLContextGLX::FindVisual()
|
|
#include "GtkCompositorWidget.h"
|
|
#include "gfxXlibSurface.h"
|
|
#include "WindowSurfaceX11Image.h"
|
|
@@ -129,8 +134,6 @@ using namespace mozilla::widget;
|
|
#include "nsShmImage.h"
|
|
#include "gtkdrawing.h"
|
|
|
|
-#include "nsIDOMWheelEvent.h"
|
|
-
|
|
#include "NativeKeyBindings.h"
|
|
|
|
#include <dlfcn.h>
|
|
@@ -140,6 +143,7 @@ using namespace mozilla::gfx;
|
|
using namespace mozilla::widget;
|
|
using namespace mozilla::layers;
|
|
using mozilla::gl::GLContext;
|
|
+using mozilla::gl::GLContextGLX;
|
|
|
|
// Don't put more than this many rects in the dirty region, just fluff
|
|
// out to the bounding-box if there are more
|
|
@@ -152,9 +156,12 @@ const gint kEvents =
|
|
#if GTK_CHECK_VERSION(3, 4, 0)
|
|
GDK_SMOOTH_SCROLL_MASK | GDK_TOUCH_MASK |
|
|
#endif
|
|
- GDK_SCROLL_MASK | GDK_POINTER_MOTION_MASK | GDK_PROPERTY_CHANGE_MASK;
|
|
+ GDK_SCROLL_MASK | GDK_POINTER_MOTION_MASK | GDK_PROPERTY_CHANGE_MASK |
|
|
+ GDK_FOCUS_CHANGE_MASK;
|
|
|
|
/* utility functions */
|
|
+static void theme_changed_cb(GtkSettings *settings, GParamSpec *pspec,
|
|
+ nsWindow *data);
|
|
static bool is_mouse_in_window(GdkWindow *aWindow, gdouble aMouseX,
|
|
gdouble aMouseY);
|
|
static nsWindow *get_window_for_gtk_widget(GtkWidget *widget);
|
|
@@ -196,8 +203,6 @@ static void hierarchy_changed_cb(GtkWidg
|
|
GtkWidget *previous_toplevel);
|
|
static gboolean window_state_event_cb(GtkWidget *widget,
|
|
GdkEventWindowState *event);
|
|
-static void theme_changed_cb(GtkSettings *settings, GParamSpec *pspec,
|
|
- nsWindow *data);
|
|
static void check_resize_cb(GtkContainer *container, gpointer user_data);
|
|
static void screen_composited_changed_cb(GdkScreen *screen, gpointer user_data);
|
|
static void widget_composited_changed_cb(GtkWidget *widget, gpointer user_data);
|
|
@@ -550,7 +555,7 @@ static GtkWidget *EnsureInvisibleContain
|
|
}
|
|
|
|
static void CheckDestroyInvisibleContainer() {
|
|
- NS_PRECONDITION(gInvisibleContainer, "oh, no");
|
|
+ MOZ_ASSERT(gInvisibleContainer, "oh, no");
|
|
|
|
if (!gdk_window_peek_children(gtk_widget_get_window(gInvisibleContainer))) {
|
|
// No children, so not in use.
|
|
@@ -639,9 +644,6 @@ void nsWindow::Destroy() {
|
|
|
|
ClearCachedResources();
|
|
|
|
- g_signal_handlers_disconnect_by_func(gtk_settings_get_default(),
|
|
- FuncToGpointer(theme_changed_cb), this);
|
|
-
|
|
nsIRollupListener *rollupListener = nsBaseWidget::GetActiveRollupListener();
|
|
if (rollupListener) {
|
|
nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
|
|
@@ -725,7 +727,7 @@ double nsWindow::GetDefaultScaleInternal
|
|
DesktopToLayoutDeviceScale nsWindow::GetDesktopToDeviceScale() {
|
|
#ifdef MOZ_WAYLAND
|
|
GdkDisplay *gdkDisplay = gdk_display_get_default();
|
|
- if (GDK_IS_WAYLAND_DISPLAY(gdkDisplay)) {
|
|
+ if (!GDK_IS_X11_DISPLAY(gdkDisplay)) {
|
|
return DesktopToLayoutDeviceScale(GdkScaleFactor());
|
|
}
|
|
#endif
|
|
@@ -735,8 +737,14 @@ DesktopToLayoutDeviceScale nsWindow::Get
|
|
}
|
|
|
|
void nsWindow::SetParent(nsIWidget *aNewParent) {
|
|
- if (mContainer || !mGdkWindow) {
|
|
- NS_NOTREACHED("nsWindow::SetParent called illegally");
|
|
+ if (!mGdkWindow) {
|
|
+ MOZ_ASSERT_UNREACHABLE("The native window has already been destroyed");
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (mContainer) {
|
|
+ // FIXME bug 1469183
|
|
+ NS_ERROR("nsWindow should not have a container here");
|
|
return;
|
|
}
|
|
|
|
@@ -774,7 +782,7 @@ void nsWindow::SetParent(nsIWidget *aNew
|
|
bool nsWindow::WidgetTypeSupportsAcceleration() { return !IsSmallPopup(); }
|
|
|
|
void nsWindow::ReparentNativeWidget(nsIWidget *aNewParent) {
|
|
- NS_PRECONDITION(aNewParent, "");
|
|
+ MOZ_ASSERT(aNewParent, "null widget");
|
|
NS_ASSERTION(!mIsDestroyed, "");
|
|
NS_ASSERTION(!static_cast<nsWindow *>(aNewParent)->mIsDestroyed, "");
|
|
|
|
@@ -1331,7 +1339,7 @@ LayoutDeviceIntRect nsWindow::GetClientB
|
|
}
|
|
|
|
void nsWindow::UpdateClientOffset() {
|
|
- AUTO_PROFILER_LABEL("nsWindow::UpdateClientOffset", GRAPHICS);
|
|
+ AUTO_PROFILER_LABEL("nsWindow::UpdateClientOffset", OTHER);
|
|
|
|
if (!mIsTopLevel || !mShell || !mIsX11Display ||
|
|
gtk_window_get_window_type(GTK_WINDOW(mShell)) == GTK_WINDOW_POPUP) {
|
|
@@ -1373,9 +1381,7 @@ LayoutDeviceIntPoint nsWindow::GetClient
|
|
}
|
|
|
|
gboolean nsWindow::OnPropertyNotifyEvent(GtkWidget *aWidget,
|
|
- GdkEventProperty *aEvent)
|
|
-
|
|
-{
|
|
+ GdkEventProperty *aEvent) {
|
|
if (aEvent->atom == gdk_atom_intern("_NET_FRAME_EXTENTS", FALSE)) {
|
|
UpdateClientOffset();
|
|
|
|
@@ -1820,6 +1826,9 @@ gboolean nsWindow::OnExposeEvent(cairo_t
|
|
|
|
// Windows that are not visible will be painted after they become visible.
|
|
if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel) return FALSE;
|
|
+#ifdef MOZ_WAYLAND
|
|
+ if (mContainer && !mContainer->ready_to_draw) return FALSE;
|
|
+#endif
|
|
|
|
nsIWidgetListener *listener = GetListener();
|
|
if (!listener) return FALSE;
|
|
@@ -3000,6 +3009,33 @@ void nsWindow::OnWindowStateEvent(GtkWid
|
|
}
|
|
// else the widget is a shell widget.
|
|
|
|
+ // The block below is a bit evil.
|
|
+ //
|
|
+ // When a window is resized before it is shown, gtk_window_resize() delays
|
|
+ // resizes until the window is shown. If gtk_window_state_event() sees a
|
|
+ // GDK_WINDOW_STATE_MAXIMIZED change [1] before the window is shown, then
|
|
+ // gtk_window_compute_configure_request_size() ignores the values from the
|
|
+ // resize [2]. See bug 1449166 for an example of how this could happen.
|
|
+ //
|
|
+ // [1] https://gitlab.gnome.org/GNOME/gtk/blob/3.22.30/gtk/gtkwindow.c#L7967
|
|
+ // [2] https://gitlab.gnome.org/GNOME/gtk/blob/3.22.30/gtk/gtkwindow.c#L9377
|
|
+ //
|
|
+ // In order to provide a sensible size for the window when the user exits
|
|
+ // maximized state, we hide the GDK_WINDOW_STATE_MAXIMIZED change from
|
|
+ // gtk_window_state_event() so as to trick GTK into using the values from
|
|
+ // gtk_window_resize() in its configure request.
|
|
+ //
|
|
+ // We instead notify gtk_window_state_event() of the maximized state change
|
|
+ // once the window is shown.
|
|
+ if (!mIsShown) {
|
|
+ aEvent->changed_mask = static_cast<GdkWindowState>(
|
|
+ aEvent->changed_mask & ~GDK_WINDOW_STATE_MAXIMIZED);
|
|
+ } else if (aEvent->changed_mask & GDK_WINDOW_STATE_WITHDRAWN &&
|
|
+ aEvent->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
|
|
+ aEvent->changed_mask = static_cast<GdkWindowState>(
|
|
+ aEvent->changed_mask | GDK_WINDOW_STATE_MAXIMIZED);
|
|
+ }
|
|
+
|
|
// We don't care about anything but changes in the maximized/icon/fullscreen
|
|
// states
|
|
if ((aEvent->changed_mask &
|
|
@@ -3075,6 +3111,7 @@ void nsWindow::OnDPIChanged() {
|
|
// Update menu's font size etc
|
|
presShell->ThemeChanged();
|
|
}
|
|
+ mWidgetListener->UIResolutionChanged();
|
|
}
|
|
}
|
|
|
|
@@ -3443,13 +3480,15 @@ nsresult nsWindow::Create(nsIWidget *aPa
|
|
gtk_style_context_has_class(style, "csd");
|
|
eventWidget = (drawToContainer) ? container : mShell;
|
|
|
|
- gtk_widget_add_events(eventWidget, kEvents);
|
|
- if (drawToContainer)
|
|
- gtk_widget_add_events(mShell, GDK_PROPERTY_CHANGE_MASK);
|
|
-
|
|
// Prevent GtkWindow from painting a background to avoid flickering.
|
|
gtk_widget_set_app_paintable(eventWidget, TRUE);
|
|
|
|
+ gtk_widget_add_events(eventWidget, kEvents);
|
|
+ if (drawToContainer) {
|
|
+ gtk_widget_add_events(mShell, GDK_PROPERTY_CHANGE_MASK);
|
|
+ gtk_widget_set_app_paintable(mShell, TRUE);
|
|
+ }
|
|
+
|
|
// If we draw to mContainer window then configure it now because
|
|
// gtk_container_add() realizes the child widget.
|
|
gtk_widget_set_has_window(container, drawToContainer);
|
|
@@ -3698,6 +3737,15 @@ nsresult nsWindow::Create(nsIWidget *aPa
|
|
mXDepth = gdk_visual_get_depth(gdkVisual);
|
|
|
|
mSurfaceProvider.Initialize(mXDisplay, mXWindow, mXVisual, mXDepth);
|
|
+
|
|
+ if (mIsTopLevel) {
|
|
+ // Set window manager hint to keep fullscreen windows composited.
|
|
+ //
|
|
+ // If the window were to get unredirected, there could be visible
|
|
+ // tearing because Gecko does not align its framebuffer updates with
|
|
+ // vblank.
|
|
+ SetCompositorHint(GTK_WIDGET_COMPOSIDED_ENABLED);
|
|
+ }
|
|
}
|
|
#ifdef MOZ_WAYLAND
|
|
else if (!mIsX11Display) {
|
|
@@ -3708,12 +3756,37 @@ nsresult nsWindow::Create(nsIWidget *aPa
|
|
return NS_OK;
|
|
}
|
|
|
|
+void nsWindow::RefreshWindowClass(void) {
|
|
+ if (mGtkWindowTypeName.IsEmpty() || mGtkWindowRoleName.IsEmpty()) return;
|
|
+
|
|
+ GdkWindow *gdkWindow = gtk_widget_get_window(mShell);
|
|
+ gdk_window_set_role(gdkWindow, mGtkWindowRoleName.get());
|
|
+
|
|
+#ifdef MOZ_X11
|
|
+ if (mIsX11Display) {
|
|
+ XClassHint *class_hint = XAllocClassHint();
|
|
+ if (!class_hint) {
|
|
+ return;
|
|
+ }
|
|
+ const char *res_class = gdk_get_program_class();
|
|
+ if (!res_class) return;
|
|
+
|
|
+ class_hint->res_name = const_cast<char *>(mGtkWindowTypeName.get());
|
|
+ class_hint->res_class = const_cast<char *>(res_class);
|
|
+
|
|
+ // Can't use gtk_window_set_wmclass() for this; it prints
|
|
+ // a warning & refuses to make the change.
|
|
+ GdkDisplay *display = gdk_display_get_default();
|
|
+ XSetClassHint(GDK_DISPLAY_XDISPLAY(display),
|
|
+ gdk_x11_window_get_xid(gdkWindow), class_hint);
|
|
+ XFree(class_hint);
|
|
+ }
|
|
+#endif /* MOZ_X11 */
|
|
+}
|
|
+
|
|
void nsWindow::SetWindowClass(const nsAString &xulWinType) {
|
|
if (!mShell) return;
|
|
|
|
- const char *res_class = gdk_get_program_class();
|
|
- if (!res_class) return;
|
|
-
|
|
char *res_name = ToNewCString(xulWinType);
|
|
if (!res_name) return;
|
|
|
|
@@ -3733,29 +3806,11 @@ void nsWindow::SetWindowClass(const nsAS
|
|
res_name[0] = toupper(res_name[0]);
|
|
if (!role) role = res_name;
|
|
|
|
- GdkWindow *gdkWindow = gtk_widget_get_window(mShell);
|
|
- gdk_window_set_role(gdkWindow, role);
|
|
-
|
|
-#ifdef MOZ_X11
|
|
- if (mIsX11Display) {
|
|
- XClassHint *class_hint = XAllocClassHint();
|
|
- if (!class_hint) {
|
|
- free(res_name);
|
|
- return;
|
|
- }
|
|
- class_hint->res_name = res_name;
|
|
- class_hint->res_class = const_cast<char *>(res_class);
|
|
-
|
|
- // Can't use gtk_window_set_wmclass() for this; it prints
|
|
- // a warning & refuses to make the change.
|
|
- GdkDisplay *display = gdk_display_get_default();
|
|
- XSetClassHint(GDK_DISPLAY_XDISPLAY(display),
|
|
- gdk_x11_window_get_xid(gdkWindow), class_hint);
|
|
- XFree(class_hint);
|
|
- }
|
|
-#endif /* MOZ_X11 */
|
|
-
|
|
+ mGtkWindowTypeName = res_name;
|
|
+ mGtkWindowRoleName = role;
|
|
free(res_name);
|
|
+
|
|
+ RefreshWindowClass();
|
|
}
|
|
|
|
void nsWindow::NativeResize() {
|
|
@@ -3820,6 +3875,8 @@ void nsWindow::NativeMoveResize() {
|
|
NativeShow(false);
|
|
}
|
|
NativeMove();
|
|
+
|
|
+ return;
|
|
}
|
|
|
|
GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mBounds.Size());
|
|
@@ -3832,6 +3889,8 @@ void nsWindow::NativeMoveResize() {
|
|
// x and y give the position of the window manager frame top-left.
|
|
gtk_window_move(GTK_WINDOW(mShell), topLeft.x, topLeft.y);
|
|
// This sets the client window size.
|
|
+ MOZ_ASSERT(size.width > 0 && size.height > 0,
|
|
+ "Can't resize window smaller than 1x1.");
|
|
gtk_window_resize(GTK_WINDOW(mShell), size.width, size.height);
|
|
} else if (mContainer) {
|
|
GtkAllocation allocation;
|
|
@@ -3877,6 +3936,16 @@ void nsWindow::NativeShow(bool aAction)
|
|
gdk_window_show_unraised(mGdkWindow);
|
|
}
|
|
} else {
|
|
+#ifdef MOZ_WAYLAND
|
|
+ if (mContainer && moz_container_has_wl_egl_window(mContainer)) {
|
|
+ // Because wl_egl_window is destroyed on moz_container_unmap(),
|
|
+ // the current compositor cannot use it anymore. To avoid crash,
|
|
+ // destroy the compositor & recreate a new compositor on next
|
|
+ // expose event.
|
|
+ DestroyLayerManager();
|
|
+ }
|
|
+#endif
|
|
+
|
|
if (mIsTopLevel) {
|
|
// Workaround window freezes on GTK versions before 3.21.2 by
|
|
// ensuring that configure events get dispatched to windows before
|
|
@@ -5436,9 +5505,10 @@ void nsWindow::InitDragEvent(WidgetDragE
|
|
KeymapWrapper::InitInputEvent(aEvent, modifierState);
|
|
}
|
|
|
|
-static gboolean drag_motion_event_cb(GtkWidget *aWidget,
|
|
- GdkDragContext *aDragContext, gint aX,
|
|
- gint aY, guint aTime, gpointer aData) {
|
|
+gboolean WindowDragMotionHandler(GtkWidget *aWidget,
|
|
+ GdkDragContext *aDragContext,
|
|
+ nsWaylandDragContext *aWaylandDragContext,
|
|
+ gint aX, gint aY, guint aTime) {
|
|
RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
|
|
if (!window) return FALSE;
|
|
|
|
@@ -5459,13 +5529,17 @@ static gboolean drag_motion_event_cb(Gtk
|
|
LayoutDeviceIntPoint point = window->GdkPointToDevicePixels({retx, rety});
|
|
|
|
RefPtr<nsDragService> dragService = nsDragService::GetInstance();
|
|
- return dragService->ScheduleMotionEvent(innerMostWindow, aDragContext, point,
|
|
- aTime);
|
|
+ return dragService->ScheduleMotionEvent(innerMostWindow, aDragContext,
|
|
+ aWaylandDragContext, point, aTime);
|
|
}
|
|
|
|
-static void drag_leave_event_cb(GtkWidget *aWidget,
|
|
- GdkDragContext *aDragContext, guint aTime,
|
|
- gpointer aData) {
|
|
+static gboolean drag_motion_event_cb(GtkWidget *aWidget,
|
|
+ GdkDragContext *aDragContext, gint aX,
|
|
+ gint aY, guint aTime, gpointer aData) {
|
|
+ return WindowDragMotionHandler(aWidget, aDragContext, nullptr, aX, aY, aTime);
|
|
+}
|
|
+
|
|
+void WindowDragLeaveHandler(GtkWidget *aWidget) {
|
|
RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
|
|
if (!window) return;
|
|
|
|
@@ -5495,9 +5569,15 @@ static void drag_leave_event_cb(GtkWidge
|
|
dragService->ScheduleLeaveEvent();
|
|
}
|
|
|
|
-static gboolean drag_drop_event_cb(GtkWidget *aWidget,
|
|
- GdkDragContext *aDragContext, gint aX,
|
|
- gint aY, guint aTime, gpointer aData) {
|
|
+static void drag_leave_event_cb(GtkWidget *aWidget,
|
|
+ GdkDragContext *aDragContext, guint aTime,
|
|
+ gpointer aData) {
|
|
+ WindowDragLeaveHandler(aWidget);
|
|
+}
|
|
+
|
|
+gboolean WindowDragDropHandler(GtkWidget *aWidget, GdkDragContext *aDragContext,
|
|
+ nsWaylandDragContext *aWaylandDragContext,
|
|
+ gint aX, gint aY, guint aTime) {
|
|
RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
|
|
if (!window) return FALSE;
|
|
|
|
@@ -5518,8 +5598,14 @@ static gboolean drag_drop_event_cb(GtkWi
|
|
LayoutDeviceIntPoint point = window->GdkPointToDevicePixels({retx, rety});
|
|
|
|
RefPtr<nsDragService> dragService = nsDragService::GetInstance();
|
|
- return dragService->ScheduleDropEvent(innerMostWindow, aDragContext, point,
|
|
- aTime);
|
|
+ return dragService->ScheduleDropEvent(innerMostWindow, aDragContext,
|
|
+ aWaylandDragContext, point, aTime);
|
|
+}
|
|
+
|
|
+static gboolean drag_drop_event_cb(GtkWidget *aWidget,
|
|
+ GdkDragContext *aDragContext, gint aX,
|
|
+ gint aY, guint aTime, gpointer aData) {
|
|
+ return WindowDragDropHandler(aWidget, aDragContext, nullptr, aX, aY, aTime);
|
|
}
|
|
|
|
static void drag_data_received_event_cb(GtkWidget *aWidget,
|
|
@@ -5877,11 +5963,6 @@ nsIWidget::LayerManager *nsWindow::GetLa
|
|
return mLayerManager;
|
|
}
|
|
|
|
- if (!mLayerManager && !IsComposited() &&
|
|
- eTransparencyTransparent == GetTransparencyMode()) {
|
|
- mLayerManager = CreateBasicLayerManager();
|
|
- }
|
|
-
|
|
return nsBaseWidget::GetLayerManager(aShadowManager, aBackendHint,
|
|
aPersistence);
|
|
}
|
|
@@ -5919,6 +6000,13 @@ void nsWindow::ClearCachedResources() {
|
|
* It works only for CSD decorated GtkWindow.
|
|
*/
|
|
void nsWindow::UpdateClientOffsetForCSDWindow() {
|
|
+ // We update window offset on X11 as the window position is calculated
|
|
+ // relatively to mShell. We don't do that on Wayland as our wl_subsurface
|
|
+ // is attached to mContainer and mShell is ignored.
|
|
+ if (!mIsX11Display) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
// _NET_FRAME_EXTENTS is not set on client decorated windows,
|
|
// so we need to read offset between mContainer and toplevel mShell
|
|
// window.
|
|
@@ -6005,6 +6093,15 @@ void nsWindow::SetDrawsInTitlebar(bool a
|
|
mNeedsShow = true;
|
|
NativeResize();
|
|
|
|
+ // Label mShell toplevel window so property_notify_event_cb callback
|
|
+ // can find its way home.
|
|
+ g_object_set_data(G_OBJECT(gtk_widget_get_window(mShell)), "nsWindow",
|
|
+ this);
|
|
+#ifdef MOZ_X11
|
|
+ SetCompositorHint(GTK_WIDGET_COMPOSIDED_ENABLED);
|
|
+#endif
|
|
+ RefreshWindowClass();
|
|
+
|
|
// When we use system titlebar setup managed by Gtk+ we also get
|
|
// _NET_FRAME_EXTENTS property for our toplevel window so we can't
|
|
// update the client offset it here.
|
|
@@ -6019,13 +6116,11 @@ void nsWindow::SetDrawsInTitlebar(bool a
|
|
}
|
|
|
|
gint nsWindow::GdkScaleFactor() {
|
|
-#if (MOZ_WIDGET_GTK >= 3)
|
|
// Available as of GTK 3.10+
|
|
static auto sGdkWindowGetScaleFactorPtr =
|
|
(gint(*)(GdkWindow *))dlsym(RTLD_DEFAULT, "gdk_window_get_scale_factor");
|
|
if (sGdkWindowGetScaleFactorPtr && mGdkWindow)
|
|
return (*sGdkWindowGetScaleFactorPtr)(mGdkWindow);
|
|
-#endif
|
|
return ScreenHelperGTK::GetGTKMonitorScaleFactor();
|
|
}
|
|
|
|
@@ -6287,6 +6382,8 @@ nsWindow::CSDSupportLevel nsWindow::GetS
|
|
// KDE Plasma
|
|
} else if (strstr(currentDesktop, "KDE") != nullptr) {
|
|
sCSDSupportLevel = CSD_SUPPORT_CLIENT;
|
|
+ } else if (strstr(currentDesktop, "Enlightenment") != nullptr) {
|
|
+ sCSDSupportLevel = CSD_SUPPORT_CLIENT;
|
|
} else if (strstr(currentDesktop, "LXDE") != nullptr) {
|
|
sCSDSupportLevel = CSD_SUPPORT_CLIENT;
|
|
} else if (strstr(currentDesktop, "openbox") != nullptr) {
|
|
@@ -6303,6 +6400,8 @@ nsWindow::CSDSupportLevel nsWindow::GetS
|
|
sCSDSupportLevel = CSD_SUPPORT_SYSTEM;
|
|
} else if (strstr(currentDesktop, "LXQt") != nullptr) {
|
|
sCSDSupportLevel = CSD_SUPPORT_SYSTEM;
|
|
+ } else if (strstr(currentDesktop, "Deepin") != nullptr) {
|
|
+ sCSDSupportLevel = CSD_SUPPORT_SYSTEM;
|
|
} else {
|
|
// Release or beta builds are not supposed to be broken
|
|
// so disable titlebar rendering on untested/unknown systems.
|
|
@@ -6351,34 +6450,19 @@ int32_t nsWindow::RoundsWidgetCoordinate
|
|
|
|
void nsWindow::GetCompositorWidgetInitData(
|
|
mozilla::widget::CompositorWidgetInitData *aInitData) {
|
|
+ // Make sure the window XID is propagated to X server, we can fail otherwise
|
|
+ // in GPU process (Bug 1401634).
|
|
+ if (mXDisplay && mXWindow != X11None) {
|
|
+ XFlush(mXDisplay);
|
|
+ }
|
|
+
|
|
*aInitData = mozilla::widget::GtkCompositorWidgetInitData(
|
|
(mXWindow != X11None) ? mXWindow : (uintptr_t) nullptr,
|
|
mXDisplay ? nsCString(XDisplayString(mXDisplay)) : nsCString(),
|
|
GetClientSize());
|
|
}
|
|
|
|
-bool nsWindow::IsComposited() const {
|
|
- if (!mGdkWindow) {
|
|
- NS_WARNING("nsWindow::HasARGBVisual called before realization!");
|
|
- return false;
|
|
- }
|
|
-
|
|
- GdkScreen *gdkScreen = gdk_screen_get_default();
|
|
- return gdk_screen_is_composited(gdkScreen) &&
|
|
- (gdk_window_get_visual(mGdkWindow) ==
|
|
- gdk_screen_get_rgba_visual(gdkScreen));
|
|
-}
|
|
-
|
|
#ifdef MOZ_WAYLAND
|
|
-wl_display *nsWindow::GetWaylandDisplay() {
|
|
- // Available as of GTK 3.8+
|
|
- static auto sGdkWaylandDisplayGetWlDisplay = (wl_display * (*)(GdkDisplay *))
|
|
- dlsym(RTLD_DEFAULT, "gdk_wayland_display_get_wl_display");
|
|
-
|
|
- GdkDisplay *gdkDisplay = gdk_display_get_default();
|
|
- return mIsX11Display ? nullptr : sGdkWaylandDisplayGetWlDisplay(gdkDisplay);
|
|
-}
|
|
-
|
|
wl_surface *nsWindow::GetWaylandSurface() {
|
|
if (mContainer)
|
|
return moz_container_get_wl_surface(MOZ_CONTAINER(mContainer));
|
|
@@ -6388,4 +6472,80 @@ wl_surface *nsWindow::GetWaylandSurface(
|
|
"drawing!");
|
|
return nullptr;
|
|
}
|
|
+
|
|
+bool nsWindow::WaylandSurfaceNeedsClear() {
|
|
+ if (mContainer) {
|
|
+ return moz_container_surface_needs_clear(MOZ_CONTAINER(mContainer));
|
|
+ }
|
|
+
|
|
+ NS_WARNING(
|
|
+ "nsWindow::WaylandSurfaceNeedsClear(): We don't have any mContainer!");
|
|
+ return false;
|
|
+}
|
|
#endif
|
|
+
|
|
+#ifdef MOZ_X11
|
|
+/* XApp progress support currently works by setting a property
|
|
+ * on a window with this Atom name. A supporting window manager
|
|
+ * will notice this and pass it along to whatever handling has
|
|
+ * been implemented on that end (e.g. passing it on to a taskbar
|
|
+ * widget.) There is no issue if WM support is lacking, this is
|
|
+ * simply ignored in that case.
|
|
+ *
|
|
+ * See https://github.com/linuxmint/xapps/blob/master/libxapp/xapp-gtk-window.c
|
|
+ * for further details.
|
|
+ */
|
|
+
|
|
+#define PROGRESS_HINT "_NET_WM_XAPP_PROGRESS"
|
|
+
|
|
+static void set_window_hint_cardinal(Window xid, const gchar *atom_name,
|
|
+ gulong cardinal) {
|
|
+ GdkDisplay *display;
|
|
+
|
|
+ display = gdk_display_get_default();
|
|
+
|
|
+ if (cardinal > 0) {
|
|
+ XChangeProperty(GDK_DISPLAY_XDISPLAY(display), xid,
|
|
+ gdk_x11_get_xatom_by_name_for_display(display, atom_name),
|
|
+ XA_CARDINAL, 32, PropModeReplace, (guchar *)&cardinal, 1);
|
|
+ } else {
|
|
+ XDeleteProperty(GDK_DISPLAY_XDISPLAY(display), xid,
|
|
+ gdk_x11_get_xatom_by_name_for_display(display, atom_name));
|
|
+ }
|
|
+}
|
|
+#endif // MOZ_X11
|
|
+
|
|
+void nsWindow::SetProgress(unsigned long progressPercent) {
|
|
+#ifdef MOZ_X11
|
|
+
|
|
+ if (!mIsX11Display) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (!mShell) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ progressPercent = MIN(progressPercent, 100);
|
|
+
|
|
+ set_window_hint_cardinal(GDK_WINDOW_XID(gtk_widget_get_window(mShell)),
|
|
+ PROGRESS_HINT, progressPercent);
|
|
+#endif // MOZ_X11
|
|
+}
|
|
+
|
|
+#ifdef MOZ_X11
|
|
+void nsWindow::SetCompositorHint(WindowComposeRequest aState) {
|
|
+ if (mIsX11Display &&
|
|
+ (!GetLayerManager() ||
|
|
+ GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_BASIC)) {
|
|
+ gulong value = aState;
|
|
+ GdkAtom cardinal_atom = gdk_x11_xatom_to_atom(XA_CARDINAL);
|
|
+ gdk_property_change(gtk_widget_get_window(mShell),
|
|
+ gdk_atom_intern("_NET_WM_BYPASS_COMPOSITOR", FALSE),
|
|
+ cardinal_atom,
|
|
+ 32, // format
|
|
+ GDK_PROP_MODE_REPLACE, (guchar *)&value, 1);
|
|
+ }
|
|
+}
|
|
+#endif
|
|
+
|
|
diff -up thunderbird-60.5.0/widget/gtk/nsWindow.h.wayland thunderbird-60.5.0/widget/gtk/nsWindow.h
|
|
--- thunderbird-60.5.0/widget/gtk/nsWindow.h.wayland 2019-01-22 20:44:03.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/nsWindow.h 2019-02-05 14:26:16.978316639 +0100
|
|
@@ -1,4 +1,4 @@
|
|
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim:expandtab:shiftwidth=4:tabstop=4:
|
|
*/
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
@@ -8,19 +8,8 @@
|
|
#ifndef __nsWindow_h__
|
|
#define __nsWindow_h__
|
|
|
|
-#include "mozcontainer.h"
|
|
-#include "mozilla/RefPtr.h"
|
|
-#include "mozilla/UniquePtr.h"
|
|
-#include "nsIDragService.h"
|
|
-#include "nsITimer.h"
|
|
-#include "nsGkAtoms.h"
|
|
-#include "nsRefPtrHashtable.h"
|
|
-
|
|
-#include "nsBaseWidget.h"
|
|
-#include "CompositorWidget.h"
|
|
#include <gdk/gdk.h>
|
|
#include <gtk/gtk.h>
|
|
-
|
|
#ifdef MOZ_X11
|
|
#include <gdk/gdkx.h>
|
|
#include "X11UndefineNone.h"
|
|
@@ -28,7 +17,16 @@
|
|
#ifdef MOZ_WAYLAND
|
|
#include <gdk/gdkwayland.h>
|
|
#endif
|
|
-
|
|
+#include "mozcontainer.h"
|
|
+#include "mozilla/RefPtr.h"
|
|
+#include "mozilla/UniquePtr.h"
|
|
+#include "nsIDragService.h"
|
|
+#include "nsITimer.h"
|
|
+#include "nsGkAtoms.h"
|
|
+#include "nsRefPtrHashtable.h"
|
|
+#include "nsIFrame.h"
|
|
+#include "nsBaseWidget.h"
|
|
+#include "CompositorWidget.h"
|
|
#include "mozilla/widget/WindowSurface.h"
|
|
#include "mozilla/widget/WindowSurfaceProvider.h"
|
|
|
|
@@ -66,6 +64,19 @@ extern mozilla::LazyLogModule gWidgetDra
|
|
|
|
#endif /* MOZ_LOGGING */
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
+class nsWaylandDragContext;
|
|
+
|
|
+gboolean WindowDragMotionHandler(GtkWidget* aWidget,
|
|
+ GdkDragContext* aDragContext,
|
|
+ nsWaylandDragContext* aWaylandDragContext,
|
|
+ gint aX, gint aY, guint aTime);
|
|
+gboolean WindowDragDropHandler(GtkWidget* aWidget, GdkDragContext* aDragContext,
|
|
+ nsWaylandDragContext* aWaylandDragContext,
|
|
+ gint aX, gint aY, guint aTime);
|
|
+void WindowDragLeaveHandler(GtkWidget* aWidget);
|
|
+#endif
|
|
+
|
|
class gfxPattern;
|
|
|
|
namespace mozilla {
|
|
@@ -77,6 +88,7 @@ class nsWindow final : public nsBaseWidg
|
|
public:
|
|
typedef mozilla::gfx::DrawTarget DrawTarget;
|
|
typedef mozilla::WidgetEventTime WidgetEventTime;
|
|
+ typedef mozilla::WidgetKeyboardEvent WidgetKeyboardEvent;
|
|
typedef mozilla::widget::PlatformCompositorWidgetDelegate
|
|
PlatformCompositorWidgetDelegate;
|
|
|
|
@@ -216,6 +228,8 @@ class nsWindow final : public nsBaseWidg
|
|
mozilla::gfx::DrawTarget* aDrawTarget,
|
|
LayoutDeviceIntRegion& aInvalidRegion) override;
|
|
|
|
+ void SetProgress(unsigned long progressPercent);
|
|
+
|
|
private:
|
|
void UpdateAlpha(mozilla::gfx::SourceSurface* aSourceSurface,
|
|
nsIntRect aBoundsRect);
|
|
@@ -335,6 +349,7 @@ class nsWindow final : public nsBaseWidg
|
|
#ifdef MOZ_WAYLAND
|
|
wl_display* GetWaylandDisplay();
|
|
wl_surface* GetWaylandSurface();
|
|
+ bool WaylandSurfaceNeedsClear();
|
|
#endif
|
|
virtual void GetCompositorWidgetInitData(
|
|
mozilla::widget::CompositorWidgetInitData* aInitData) override;
|
|
@@ -436,13 +451,23 @@ class nsWindow final : public nsBaseWidg
|
|
gint* aButton, gint* aRootX, gint* aRootY);
|
|
void ClearCachedResources();
|
|
nsIWidgetListener* GetListener();
|
|
- bool IsComposited() const;
|
|
|
|
void UpdateClientOffsetForCSDWindow();
|
|
|
|
nsWindow* GetTransientForWindowIfPopup();
|
|
bool IsHandlingTouchSequence(GdkEventSequence* aSequence);
|
|
|
|
+#ifdef MOZ_X11
|
|
+ typedef enum {GTK_WIDGET_COMPOSIDED_DEFAULT = 0,
|
|
+ GTK_WIDGET_COMPOSIDED_DISABLED = 1,
|
|
+ GTK_WIDGET_COMPOSIDED_ENABLED = 2} WindowComposeRequest;
|
|
+
|
|
+ void SetCompositorHint(WindowComposeRequest aState);
|
|
+#endif
|
|
+ nsCString mGtkWindowTypeName;
|
|
+ nsCString mGtkWindowRoleName;
|
|
+ void RefreshWindowClass();
|
|
+
|
|
GtkWidget* mShell;
|
|
MozContainer* mContainer;
|
|
GdkWindow* mGdkWindow;
|
|
diff -up thunderbird-60.5.0/widget/gtk/WindowSurfaceProvider.h.wayland thunderbird-60.5.0/widget/gtk/WindowSurfaceProvider.h
|
|
--- thunderbird-60.5.0/widget/gtk/WindowSurfaceProvider.h.wayland 2019-01-22 20:44:04.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/WindowSurfaceProvider.h 2019-02-05 14:26:16.978316639 +0100
|
|
@@ -1,4 +1,4 @@
|
|
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
@@ -17,6 +17,7 @@
|
|
#include <gdk/gdkwayland.h>
|
|
#endif
|
|
#include <X11/Xlib.h> // for Window, Display, Visual, etc.
|
|
+#include "X11UndefineNone.h"
|
|
|
|
class nsWindow;
|
|
|
|
@@ -70,6 +71,7 @@ class WindowSurfaceProvider final {
|
|
#ifdef MOZ_WAYLAND
|
|
nsWindow* mWidget;
|
|
#endif
|
|
+ bool mIsShaped;
|
|
};
|
|
|
|
} // namespace widget
|
|
diff -up thunderbird-60.5.0/widget/gtk/WindowSurfaceWayland.cpp.wayland thunderbird-60.5.0/widget/gtk/WindowSurfaceWayland.cpp
|
|
--- thunderbird-60.5.0/widget/gtk/WindowSurfaceWayland.cpp.wayland 2019-01-22 20:44:04.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/WindowSurfaceWayland.cpp 2019-02-05 14:26:16.979316635 +0100
|
|
@@ -1,27 +1,28 @@
|
|
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
+#include "nsWaylandDisplay.h"
|
|
#include "WindowSurfaceWayland.h"
|
|
|
|
-#include "base/message_loop.h" // for MessageLoop
|
|
-#include "base/task.h" // for NewRunnableMethod, etc
|
|
#include "nsPrintfCString.h"
|
|
#include "mozilla/gfx/2D.h"
|
|
#include "mozilla/gfx/Tools.h"
|
|
#include "gfxPlatform.h"
|
|
#include "mozcontainer.h"
|
|
-#include "nsCOMArray.h"
|
|
-#include "mozilla/StaticMutex.h"
|
|
+#include "nsTArray.h"
|
|
+#include "base/message_loop.h" // for MessageLoop
|
|
+#include "base/task.h" // for NewRunnableMethod, etc
|
|
|
|
-#include <gdk/gdkwayland.h>
|
|
#include <sys/mman.h>
|
|
-#include <assert.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
|
|
+namespace mozilla {
|
|
+namespace widget {
|
|
+
|
|
/*
|
|
Wayland multi-thread rendering scheme
|
|
|
|
@@ -131,188 +132,16 @@ handle to wayland compositor by WindowBa
|
|
(wl_buffer/wl_surface).
|
|
*/
|
|
|
|
-namespace mozilla {
|
|
-namespace widget {
|
|
-
|
|
#define BUFFER_BPP 4
|
|
-
|
|
-// TODO: How many rendering threads do we actualy handle?
|
|
-static nsCOMArray<nsWaylandDisplay> gWaylandDisplays;
|
|
-static StaticMutex gWaylandDisplaysMutex;
|
|
-
|
|
-// Each thread which is using wayland connection (wl_display) has to operate
|
|
-// its own wl_event_queue. Main Firefox thread wl_event_queue is handled
|
|
-// by Gtk main loop, other threads/wl_event_queue has to be handled by us.
|
|
-//
|
|
-// nsWaylandDisplay is our interface to wayland compositor. It provides wayland
|
|
-// global objects as we need (wl_display, wl_shm) and operates wl_event_queue on
|
|
-// compositor (not the main) thread.
|
|
-static nsWaylandDisplay *WaylandDisplayGet(wl_display *aDisplay);
|
|
-static void WaylandDisplayRelease(wl_display *aDisplay);
|
|
-static void WaylandDisplayLoop(wl_display *aDisplay);
|
|
-
|
|
-// TODO: is the 60pfs loop correct?
|
|
-#define EVENT_LOOP_DELAY (1000 / 60)
|
|
-
|
|
-// Get WaylandDisplay for given wl_display and actual calling thread.
|
|
-static nsWaylandDisplay *WaylandDisplayGetLocked(wl_display *aDisplay,
|
|
- const StaticMutexAutoLock &) {
|
|
- nsWaylandDisplay *waylandDisplay = nullptr;
|
|
-
|
|
- int len = gWaylandDisplays.Count();
|
|
- for (int i = 0; i < len; i++) {
|
|
- if (gWaylandDisplays[i]->Matches(aDisplay)) {
|
|
- waylandDisplay = gWaylandDisplays[i];
|
|
- break;
|
|
- }
|
|
- }
|
|
-
|
|
- if (!waylandDisplay) {
|
|
- waylandDisplay = new nsWaylandDisplay(aDisplay);
|
|
- gWaylandDisplays.AppendObject(waylandDisplay);
|
|
- }
|
|
-
|
|
- NS_ADDREF(waylandDisplay);
|
|
- return waylandDisplay;
|
|
-}
|
|
-
|
|
-static nsWaylandDisplay *WaylandDisplayGet(wl_display *aDisplay) {
|
|
- StaticMutexAutoLock lock(gWaylandDisplaysMutex);
|
|
- return WaylandDisplayGetLocked(aDisplay, lock);
|
|
-}
|
|
-
|
|
-static bool WaylandDisplayReleaseLocked(wl_display *aDisplay,
|
|
- const StaticMutexAutoLock &) {
|
|
- int len = gWaylandDisplays.Count();
|
|
- for (int i = 0; i < len; i++) {
|
|
- if (gWaylandDisplays[i]->Matches(aDisplay)) {
|
|
- int rc = gWaylandDisplays[i]->Release();
|
|
- // nsCOMArray::AppendObject()/RemoveObjectAt() also call
|
|
- // AddRef()/Release() so remove WaylandDisplay when ref count is 1.
|
|
- if (rc == 1) {
|
|
- gWaylandDisplays.RemoveObjectAt(i);
|
|
- }
|
|
- return true;
|
|
- }
|
|
- }
|
|
- MOZ_ASSERT(false, "Missing nsWaylandDisplay for this thread!");
|
|
- return false;
|
|
-}
|
|
-
|
|
-static void WaylandDisplayRelease(wl_display *aDisplay) {
|
|
- StaticMutexAutoLock lock(gWaylandDisplaysMutex);
|
|
- WaylandDisplayReleaseLocked(aDisplay, lock);
|
|
-}
|
|
-
|
|
-static void WaylandDisplayLoopLocked(wl_display *aDisplay,
|
|
- const StaticMutexAutoLock &) {
|
|
- int len = gWaylandDisplays.Count();
|
|
- for (int i = 0; i < len; i++) {
|
|
- if (gWaylandDisplays[i]->Matches(aDisplay)) {
|
|
- if (gWaylandDisplays[i]->DisplayLoop()) {
|
|
- MessageLoop::current()->PostDelayedTask(
|
|
- NewRunnableFunction("WaylandDisplayLoop", &WaylandDisplayLoop,
|
|
- aDisplay),
|
|
- EVENT_LOOP_DELAY);
|
|
- }
|
|
- break;
|
|
- }
|
|
- }
|
|
-}
|
|
-
|
|
-static void WaylandDisplayLoop(wl_display *aDisplay) {
|
|
- MOZ_ASSERT(!NS_IsMainThread());
|
|
- StaticMutexAutoLock lock(gWaylandDisplaysMutex);
|
|
- WaylandDisplayLoopLocked(aDisplay, lock);
|
|
-}
|
|
-
|
|
-static void global_registry_handler(void *data, wl_registry *registry,
|
|
- uint32_t id, const char *interface,
|
|
- uint32_t version) {
|
|
- if (strcmp(interface, "wl_shm") == 0) {
|
|
- auto interface = reinterpret_cast<nsWaylandDisplay *>(data);
|
|
- auto shm = static_cast<wl_shm *>(
|
|
- wl_registry_bind(registry, id, &wl_shm_interface, 1));
|
|
- wl_proxy_set_queue((struct wl_proxy *)shm, interface->GetEventQueue());
|
|
- interface->SetShm(shm);
|
|
- }
|
|
-}
|
|
-
|
|
-static void global_registry_remover(void *data, wl_registry *registry,
|
|
- uint32_t id) {}
|
|
-
|
|
-static const struct wl_registry_listener registry_listener = {
|
|
- global_registry_handler, global_registry_remover};
|
|
-
|
|
-wl_shm *nsWaylandDisplay::GetShm() {
|
|
- MOZ_ASSERT(mThreadId == PR_GetCurrentThread());
|
|
-
|
|
- if (!mShm) {
|
|
- // wl_shm is not provided by Gtk so we need to query wayland directly
|
|
- // See weston/simple-shm.c and create_display() for reference.
|
|
- wl_registry *registry = wl_display_get_registry(mDisplay);
|
|
- wl_registry_add_listener(registry, ®istry_listener, this);
|
|
-
|
|
- wl_proxy_set_queue((struct wl_proxy *)registry, mEventQueue);
|
|
- if (mEventQueue) {
|
|
- wl_display_roundtrip_queue(mDisplay, mEventQueue);
|
|
- } else {
|
|
- wl_display_roundtrip(mDisplay);
|
|
- }
|
|
-
|
|
- MOZ_RELEASE_ASSERT(mShm, "Wayland registry query failed!");
|
|
- }
|
|
-
|
|
- return (mShm);
|
|
-}
|
|
-
|
|
-bool nsWaylandDisplay::DisplayLoop() {
|
|
- wl_display_dispatch_queue_pending(mDisplay, mEventQueue);
|
|
- return true;
|
|
-}
|
|
-
|
|
-bool nsWaylandDisplay::Matches(wl_display *aDisplay) {
|
|
- return mThreadId == PR_GetCurrentThread() && aDisplay == mDisplay;
|
|
-}
|
|
-
|
|
-NS_IMPL_ISUPPORTS(nsWaylandDisplay, nsISupports);
|
|
-
|
|
-nsWaylandDisplay::nsWaylandDisplay(wl_display *aDisplay)
|
|
- : mThreadId(PR_GetCurrentThread())
|
|
- // gfx::SurfaceFormat::B8G8R8A8 is a basic Wayland format
|
|
- // and is always present.
|
|
- ,
|
|
- mFormat(gfx::SurfaceFormat::B8G8R8A8),
|
|
- mShm(nullptr),
|
|
- mDisplay(aDisplay) {
|
|
- if (NS_IsMainThread()) {
|
|
- // Use default event queue in main thread operated by Gtk+.
|
|
- mEventQueue = nullptr;
|
|
- } else {
|
|
- mEventQueue = wl_display_create_queue(mDisplay);
|
|
- MessageLoop::current()->PostTask(NewRunnableFunction(
|
|
- "WaylandDisplayLoop", &WaylandDisplayLoop, mDisplay));
|
|
- }
|
|
-}
|
|
-
|
|
-nsWaylandDisplay::~nsWaylandDisplay() {
|
|
- MOZ_ASSERT(mThreadId == PR_GetCurrentThread());
|
|
- // Owned by Gtk+, we don't need to release
|
|
- mDisplay = nullptr;
|
|
-
|
|
- if (mEventQueue) {
|
|
- wl_event_queue_destroy(mEventQueue);
|
|
- mEventQueue = nullptr;
|
|
- }
|
|
-}
|
|
+gfx::SurfaceFormat WindowBackBuffer::mFormat = gfx::SurfaceFormat::B8G8R8A8;
|
|
|
|
int WaylandShmPool::CreateTemporaryFile(int aSize) {
|
|
- const char *tmppath = getenv("XDG_RUNTIME_DIR");
|
|
+ const char* tmppath = getenv("XDG_RUNTIME_DIR");
|
|
MOZ_RELEASE_ASSERT(tmppath, "Missing XDG_RUNTIME_DIR env variable.");
|
|
|
|
nsPrintfCString tmpname("%s/mozilla-shared-XXXXXX", tmppath);
|
|
|
|
- char *filename;
|
|
+ char* filename;
|
|
int fd = -1;
|
|
int ret = 0;
|
|
|
|
@@ -353,7 +182,7 @@ int WaylandShmPool::CreateTemporaryFile(
|
|
return fd;
|
|
}
|
|
|
|
-WaylandShmPool::WaylandShmPool(nsWaylandDisplay *aWaylandDisplay, int aSize)
|
|
+WaylandShmPool::WaylandShmPool(nsWaylandDisplay* aWaylandDisplay, int aSize)
|
|
: mAllocatedSize(aSize) {
|
|
mShmPoolFd = CreateTemporaryFile(mAllocatedSize);
|
|
mImageData = mmap(nullptr, mAllocatedSize, PROT_READ | PROT_WRITE, MAP_SHARED,
|
|
@@ -365,7 +194,7 @@ WaylandShmPool::WaylandShmPool(nsWayland
|
|
wl_shm_create_pool(aWaylandDisplay->GetShm(), mShmPoolFd, mAllocatedSize);
|
|
|
|
// We set our queue to get mShmPool events at compositor thread.
|
|
- wl_proxy_set_queue((struct wl_proxy *)mShmPool,
|
|
+ wl_proxy_set_queue((struct wl_proxy*)mShmPool,
|
|
aWaylandDisplay->GetEventQueue());
|
|
}
|
|
|
|
@@ -394,7 +223,7 @@ bool WaylandShmPool::Resize(int aSize) {
|
|
return true;
|
|
}
|
|
|
|
-void WaylandShmPool::SetImageDataFromPool(class WaylandShmPool *aSourcePool,
|
|
+void WaylandShmPool::SetImageDataFromPool(class WaylandShmPool* aSourcePool,
|
|
int aImageDataSize) {
|
|
MOZ_ASSERT(mAllocatedSize >= aImageDataSize, "WaylandShmPool overflows!");
|
|
memcpy(mImageData, aSourcePool->GetImageData(), aImageDataSize);
|
|
@@ -406,8 +235,8 @@ WaylandShmPool::~WaylandShmPool() {
|
|
close(mShmPoolFd);
|
|
}
|
|
|
|
-static void buffer_release(void *data, wl_buffer *buffer) {
|
|
- auto surface = reinterpret_cast<WindowBackBuffer *>(data);
|
|
+static void buffer_release(void* data, wl_buffer* buffer) {
|
|
+ auto surface = reinterpret_cast<WindowBackBuffer*>(data);
|
|
surface->Detach();
|
|
}
|
|
|
|
@@ -422,7 +251,7 @@ void WindowBackBuffer::Create(int aWidth
|
|
mWaylandBuffer =
|
|
wl_shm_pool_create_buffer(mShmPool.GetShmPool(), 0, aWidth, aHeight,
|
|
aWidth * BUFFER_BPP, WL_SHM_FORMAT_ARGB8888);
|
|
- wl_proxy_set_queue((struct wl_proxy *)mWaylandBuffer,
|
|
+ wl_proxy_set_queue((struct wl_proxy*)mWaylandBuffer,
|
|
mWaylandDisplay->GetEventQueue());
|
|
wl_buffer_add_listener(mWaylandBuffer, &buffer_listener, this);
|
|
|
|
@@ -435,7 +264,11 @@ void WindowBackBuffer::Release() {
|
|
mWidth = mHeight = 0;
|
|
}
|
|
|
|
-WindowBackBuffer::WindowBackBuffer(nsWaylandDisplay *aWaylandDisplay,
|
|
+void WindowBackBuffer::Clear() {
|
|
+ memset(mShmPool.GetImageData(), 0, mHeight * mWidth * BUFFER_BPP);
|
|
+}
|
|
+
|
|
+WindowBackBuffer::WindowBackBuffer(nsWaylandDisplay* aWaylandDisplay,
|
|
int aWidth, int aHeight)
|
|
: mShmPool(aWaylandDisplay, aWidth * aHeight * BUFFER_BPP),
|
|
mWaylandBuffer(nullptr),
|
|
@@ -457,7 +290,7 @@ bool WindowBackBuffer::Resize(int aWidth
|
|
return (mWaylandBuffer != nullptr);
|
|
}
|
|
|
|
-void WindowBackBuffer::Attach(wl_surface *aSurface) {
|
|
+void WindowBackBuffer::Attach(wl_surface* aSurface) {
|
|
wl_surface_attach(aSurface, mWaylandBuffer, 0, 0);
|
|
wl_surface_commit(aSurface);
|
|
wl_display_flush(mWaylandDisplay->GetDisplay());
|
|
@@ -466,8 +299,8 @@ void WindowBackBuffer::Attach(wl_surface
|
|
|
|
void WindowBackBuffer::Detach() { mAttached = false; }
|
|
|
|
-bool WindowBackBuffer::SetImageDataFromBackBuffer(
|
|
- class WindowBackBuffer *aSourceBuffer) {
|
|
+bool WindowBackBuffer::SetImageDataFromBuffer(
|
|
+ class WindowBackBuffer* aSourceBuffer) {
|
|
if (!IsMatchingSize(aSourceBuffer)) {
|
|
Resize(aSourceBuffer->mWidth, aSourceBuffer->mHeight);
|
|
}
|
|
@@ -478,204 +311,381 @@ bool WindowBackBuffer::SetImageDataFromB
|
|
return true;
|
|
}
|
|
|
|
-already_AddRefed<gfx::DrawTarget> WindowBackBuffer::Lock(
|
|
- const LayoutDeviceIntRegion &aRegion) {
|
|
- gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect();
|
|
- gfx::IntSize lockSize(bounds.XMost(), bounds.YMost());
|
|
-
|
|
+already_AddRefed<gfx::DrawTarget> WindowBackBuffer::Lock() {
|
|
+ gfx::IntSize lockSize(mWidth, mHeight);
|
|
return gfxPlatform::CreateDrawTargetForData(
|
|
- static_cast<unsigned char *>(mShmPool.GetImageData()), lockSize,
|
|
- BUFFER_BPP * mWidth, mWaylandDisplay->GetSurfaceFormat());
|
|
+ static_cast<unsigned char*>(mShmPool.GetImageData()), lockSize,
|
|
+ BUFFER_BPP * mWidth, mFormat);
|
|
}
|
|
|
|
-static void frame_callback_handler(void *data, struct wl_callback *callback,
|
|
+static void frame_callback_handler(void* data, struct wl_callback* callback,
|
|
uint32_t time) {
|
|
- auto surface = reinterpret_cast<WindowSurfaceWayland *>(data);
|
|
+ auto surface = reinterpret_cast<WindowSurfaceWayland*>(data);
|
|
surface->FrameCallbackHandler();
|
|
}
|
|
|
|
static const struct wl_callback_listener frame_listener = {
|
|
frame_callback_handler};
|
|
|
|
-WindowSurfaceWayland::WindowSurfaceWayland(nsWindow *aWindow)
|
|
+WindowSurfaceWayland::WindowSurfaceWayland(nsWindow* aWindow)
|
|
: mWindow(aWindow),
|
|
- mWaylandDisplay(WaylandDisplayGet(aWindow->GetWaylandDisplay())),
|
|
- mFrontBuffer(nullptr),
|
|
- mBackBuffer(nullptr),
|
|
+ mWaylandDisplay(WaylandDisplayGet()),
|
|
+ mWaylandBuffer(nullptr),
|
|
mFrameCallback(nullptr),
|
|
- mFrameCallbackSurface(nullptr),
|
|
+ mLastCommittedSurface(nullptr),
|
|
mDisplayThreadMessageLoop(MessageLoop::current()),
|
|
- mDelayedCommit(false),
|
|
- mFullScreenDamage(false),
|
|
- mIsMainThread(NS_IsMainThread()) {}
|
|
+ mDelayedCommitHandle(nullptr),
|
|
+ mDrawToWaylandBufferDirectly(true),
|
|
+ mPendingCommit(false),
|
|
+ mWaylandBufferFullScreenDamage(false),
|
|
+ mIsMainThread(NS_IsMainThread()),
|
|
+ mNeedScaleFactorUpdate(true) {
|
|
+ for (int i = 0; i < BACK_BUFFER_NUM; i++) mBackupBuffer[i] = nullptr;
|
|
+}
|
|
|
|
WindowSurfaceWayland::~WindowSurfaceWayland() {
|
|
- delete mFrontBuffer;
|
|
- delete mBackBuffer;
|
|
+ if (mPendingCommit) {
|
|
+ NS_WARNING("Deleted WindowSurfaceWayland with a pending commit!");
|
|
+ }
|
|
+
|
|
+ if (mDelayedCommitHandle) {
|
|
+ // Delete reference to this to prevent WaylandBufferDelayCommitHandler()
|
|
+ // operate on released this. mDelayedCommitHandle itself will
|
|
+ // be released at WaylandBufferDelayCommitHandler().
|
|
+ *mDelayedCommitHandle = nullptr;
|
|
+ }
|
|
|
|
if (mFrameCallback) {
|
|
wl_callback_destroy(mFrameCallback);
|
|
}
|
|
|
|
+ delete mWaylandBuffer;
|
|
+
|
|
+ for (int i = 0; i < BACK_BUFFER_NUM; i++) {
|
|
+ if (mBackupBuffer[i]) {
|
|
+ delete mBackupBuffer[i];
|
|
+ }
|
|
+ }
|
|
+
|
|
if (!mIsMainThread) {
|
|
// We can be destroyed from main thread even though we was created/used
|
|
// in compositor thread. We have to unref/delete WaylandDisplay in
|
|
// compositor thread then and we can't use MessageLoop::current() here.
|
|
- mDisplayThreadMessageLoop->PostTask(
|
|
- NewRunnableFunction("WaylandDisplayRelease", &WaylandDisplayRelease,
|
|
- mWaylandDisplay->GetDisplay()));
|
|
+ mDisplayThreadMessageLoop->PostTask(NewRunnableFunction(
|
|
+ "WaylandDisplayRelease", &WaylandDisplayRelease, mWaylandDisplay));
|
|
} else {
|
|
- WaylandDisplayRelease(mWaylandDisplay->GetDisplay());
|
|
- }
|
|
-}
|
|
-
|
|
-void WindowSurfaceWayland::UpdateScaleFactor() {
|
|
- wl_surface *waylandSurface = mWindow->GetWaylandSurface();
|
|
- if (waylandSurface) {
|
|
- wl_surface_set_buffer_scale(waylandSurface, mWindow->GdkScaleFactor());
|
|
+ WaylandDisplayRelease(mWaylandDisplay);
|
|
}
|
|
}
|
|
|
|
-WindowBackBuffer *WindowSurfaceWayland::GetBufferToDraw(int aWidth,
|
|
- int aHeight) {
|
|
- if (!mFrontBuffer) {
|
|
- mFrontBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
|
|
- mBackBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
|
|
- return mFrontBuffer;
|
|
+WindowBackBuffer* WindowSurfaceWayland::GetWaylandBufferToDraw(int aWidth,
|
|
+ int aHeight) {
|
|
+ if (!mWaylandBuffer) {
|
|
+ mWaylandBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
|
|
+ return mWaylandBuffer;
|
|
}
|
|
|
|
- if (!mFrontBuffer->IsAttached()) {
|
|
- if (!mFrontBuffer->IsMatchingSize(aWidth, aHeight)) {
|
|
- mFrontBuffer->Resize(aWidth, aHeight);
|
|
+ if (!mWaylandBuffer->IsAttached()) {
|
|
+ if (!mWaylandBuffer->IsMatchingSize(aWidth, aHeight)) {
|
|
+ mWaylandBuffer->Resize(aWidth, aHeight);
|
|
// There's a chance that scale factor has been changed
|
|
// when buffer size changed
|
|
- UpdateScaleFactor();
|
|
+ mNeedScaleFactorUpdate = true;
|
|
+ }
|
|
+ return mWaylandBuffer;
|
|
+ }
|
|
+
|
|
+ MOZ_ASSERT(!mPendingCommit,
|
|
+ "Uncommitted buffer switch, screen artifacts ahead.");
|
|
+
|
|
+ // Front buffer is used by compositor, select a back buffer
|
|
+ int availableBuffer;
|
|
+ for (availableBuffer = 0; availableBuffer < BACK_BUFFER_NUM;
|
|
+ availableBuffer++) {
|
|
+ if (!mBackupBuffer[availableBuffer]) {
|
|
+ mBackupBuffer[availableBuffer] =
|
|
+ new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (!mBackupBuffer[availableBuffer]->IsAttached()) {
|
|
+ break;
|
|
}
|
|
- return mFrontBuffer;
|
|
}
|
|
|
|
- // Front buffer is used by compositor, draw to back buffer
|
|
- if (mBackBuffer->IsAttached()) {
|
|
+ if (MOZ_UNLIKELY(availableBuffer == BACK_BUFFER_NUM)) {
|
|
NS_WARNING("No drawing buffer available");
|
|
return nullptr;
|
|
}
|
|
|
|
- MOZ_ASSERT(!mDelayedCommit,
|
|
- "Uncommitted buffer switch, screen artifacts ahead.");
|
|
-
|
|
- WindowBackBuffer *tmp = mFrontBuffer;
|
|
- mFrontBuffer = mBackBuffer;
|
|
- mBackBuffer = tmp;
|
|
+ WindowBackBuffer* lastWaylandBuffer = mWaylandBuffer;
|
|
+ mWaylandBuffer = mBackupBuffer[availableBuffer];
|
|
+ mBackupBuffer[availableBuffer] = lastWaylandBuffer;
|
|
|
|
- if (mBackBuffer->IsMatchingSize(aWidth, aHeight)) {
|
|
+ if (lastWaylandBuffer->IsMatchingSize(aWidth, aHeight)) {
|
|
// Former front buffer has the same size as a requested one.
|
|
// Gecko may expect a content already drawn on screen so copy
|
|
// existing data to the new buffer.
|
|
- mFrontBuffer->SetImageDataFromBackBuffer(mBackBuffer);
|
|
+ mWaylandBuffer->SetImageDataFromBuffer(lastWaylandBuffer);
|
|
// When buffer switches we need to damage whole screen
|
|
// (https://bugzilla.redhat.com/show_bug.cgi?id=1418260)
|
|
- mFullScreenDamage = true;
|
|
+ mWaylandBufferFullScreenDamage = true;
|
|
} else {
|
|
// Former buffer has different size from the new request. Only resize
|
|
// the new buffer and leave gecko to render new whole content.
|
|
- mFrontBuffer->Resize(aWidth, aHeight);
|
|
+ mWaylandBuffer->Resize(aWidth, aHeight);
|
|
}
|
|
|
|
- return mFrontBuffer;
|
|
+ return mWaylandBuffer;
|
|
}
|
|
|
|
-already_AddRefed<gfx::DrawTarget> WindowSurfaceWayland::Lock(
|
|
- const LayoutDeviceIntRegion &aRegion) {
|
|
- MOZ_ASSERT(mIsMainThread == NS_IsMainThread());
|
|
-
|
|
- // We allocate back buffer to widget size but return only
|
|
- // portion requested by aRegion.
|
|
- LayoutDeviceIntRect rect = mWindow->GetBounds();
|
|
- WindowBackBuffer *buffer = GetBufferToDraw(rect.width, rect.height);
|
|
+already_AddRefed<gfx::DrawTarget> WindowSurfaceWayland::LockWaylandBuffer(
|
|
+ int aWidth, int aHeight, bool aClearBuffer) {
|
|
+ WindowBackBuffer* buffer = GetWaylandBufferToDraw(aWidth, aHeight);
|
|
if (!buffer) {
|
|
- NS_WARNING("No drawing buffer available");
|
|
+ NS_WARNING(
|
|
+ "WindowSurfaceWayland::LockWaylandBuffer(): No buffer available");
|
|
return nullptr;
|
|
}
|
|
|
|
- return buffer->Lock(aRegion);
|
|
+ if (aClearBuffer) {
|
|
+ buffer->Clear();
|
|
+ }
|
|
+
|
|
+ return buffer->Lock();
|
|
+}
|
|
+
|
|
+already_AddRefed<gfx::DrawTarget> WindowSurfaceWayland::LockImageSurface(
|
|
+ const gfx::IntSize& aLockSize) {
|
|
+ if (!mImageSurface || mImageSurface->CairoStatus() ||
|
|
+ !(aLockSize <= mImageSurface->GetSize())) {
|
|
+ mImageSurface = new gfxImageSurface(
|
|
+ aLockSize,
|
|
+ SurfaceFormatToImageFormat(WindowBackBuffer::GetSurfaceFormat()));
|
|
+ if (mImageSurface->CairoStatus()) {
|
|
+ return nullptr;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return gfxPlatform::CreateDrawTargetForData(
|
|
+ mImageSurface->Data(), mImageSurface->GetSize(), mImageSurface->Stride(),
|
|
+ WindowBackBuffer::GetSurfaceFormat());
|
|
}
|
|
|
|
-void WindowSurfaceWayland::Commit(const LayoutDeviceIntRegion &aInvalidRegion) {
|
|
+/*
|
|
+ There are some situations which can happen here:
|
|
+
|
|
+ A) Lock() is called to whole surface. In that case we don't need
|
|
+ to clip/buffer the drawing and we can return wl_buffer directly
|
|
+ for drawing.
|
|
+ - mWaylandBuffer is available - that's an ideal situation.
|
|
+ - mWaylandBuffer is locked by compositor - flip buffers and draw.
|
|
+ - if we can't flip buffers - go B)
|
|
+
|
|
+ B) Lock() is requested for part(s) of screen. We need to provide temporary
|
|
+ surface to draw into and copy result (clipped) to target wl_surface.
|
|
+ */
|
|
+already_AddRefed<gfx::DrawTarget> WindowSurfaceWayland::Lock(
|
|
+ const LayoutDeviceIntRegion& aRegion) {
|
|
MOZ_ASSERT(mIsMainThread == NS_IsMainThread());
|
|
|
|
- wl_surface *waylandSurface = mWindow->GetWaylandSurface();
|
|
+ LayoutDeviceIntRect screenRect = mWindow->GetBounds();
|
|
+ gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect();
|
|
+ gfx::IntSize lockSize(bounds.XMost(), bounds.YMost());
|
|
+
|
|
+ // Are we asked for entire nsWindow to draw?
|
|
+ mDrawToWaylandBufferDirectly =
|
|
+ (aRegion.GetNumRects() == 1 && bounds.x == 0 && bounds.y == 0 &&
|
|
+ lockSize.width == screenRect.width &&
|
|
+ lockSize.height == screenRect.height);
|
|
+
|
|
+ if (mDrawToWaylandBufferDirectly) {
|
|
+ RefPtr<gfx::DrawTarget> dt =
|
|
+ LockWaylandBuffer(screenRect.width, screenRect.height,
|
|
+ mWindow->WaylandSurfaceNeedsClear());
|
|
+ if (dt) {
|
|
+ return dt.forget();
|
|
+ }
|
|
+
|
|
+ // We don't have any front buffer available. Try indirect drawing
|
|
+ // to mImageSurface which is mirrored to front buffer at commit.
|
|
+ mDrawToWaylandBufferDirectly = false;
|
|
+ }
|
|
+
|
|
+ return LockImageSurface(lockSize);
|
|
+}
|
|
+
|
|
+bool WindowSurfaceWayland::CommitImageSurfaceToWaylandBuffer(
|
|
+ const LayoutDeviceIntRegion& aRegion) {
|
|
+ MOZ_ASSERT(!mDrawToWaylandBufferDirectly);
|
|
+
|
|
+ LayoutDeviceIntRect screenRect = mWindow->GetBounds();
|
|
+ gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect();
|
|
+
|
|
+ gfx::Rect rect(bounds);
|
|
+ if (rect.IsEmpty()) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ RefPtr<gfx::DrawTarget> dt = LockWaylandBuffer(
|
|
+ screenRect.width, screenRect.height, mWindow->WaylandSurfaceNeedsClear());
|
|
+ RefPtr<gfx::SourceSurface> surf =
|
|
+ gfx::Factory::CreateSourceSurfaceForCairoSurface(
|
|
+ mImageSurface->CairoSurface(), mImageSurface->GetSize(),
|
|
+ mImageSurface->Format());
|
|
+ if (!dt || !surf) {
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ uint32_t numRects = aRegion.GetNumRects();
|
|
+ if (numRects != 1) {
|
|
+ AutoTArray<IntRect, 32> rects;
|
|
+ rects.SetCapacity(numRects);
|
|
+ for (auto iter = aRegion.RectIter(); !iter.Done(); iter.Next()) {
|
|
+ rects.AppendElement(iter.Get().ToUnknownRect());
|
|
+ }
|
|
+ dt->PushDeviceSpaceClipRects(rects.Elements(), rects.Length());
|
|
+ }
|
|
+
|
|
+ dt->DrawSurface(surf, rect, rect);
|
|
+
|
|
+ if (numRects != 1) {
|
|
+ dt->PopClip();
|
|
+ }
|
|
+
|
|
+ return true;
|
|
+}
|
|
+
|
|
+static void WaylandBufferDelayCommitHandler(WindowSurfaceWayland** aSurface) {
|
|
+ if (*aSurface) {
|
|
+ (*aSurface)->DelayedCommitHandler();
|
|
+ } else {
|
|
+ // Referenced WindowSurfaceWayland is already deleted.
|
|
+ // Do nothing but just release the mDelayedCommitHandle allocated at
|
|
+ // WindowSurfaceWayland::CommitWaylandBuffer().
|
|
+ free(aSurface);
|
|
+ }
|
|
+}
|
|
+
|
|
+void WindowSurfaceWayland::CommitWaylandBuffer() {
|
|
+ MOZ_ASSERT(mPendingCommit, "Committing empty surface!");
|
|
+
|
|
+ wl_surface* waylandSurface = mWindow->GetWaylandSurface();
|
|
if (!waylandSurface) {
|
|
- // Target window is already destroyed - don't bother to render there.
|
|
+ // Target window is not created yet - delay the commit. This can happen only
|
|
+ // when the window is newly created and there's no active
|
|
+ // frame callback pending.
|
|
+ MOZ_ASSERT(!mFrameCallback || waylandSurface != mLastCommittedSurface,
|
|
+ "Missing wayland surface at frame callback!");
|
|
+
|
|
+ // Do nothing if there's already mDelayedCommitHandle pending.
|
|
+ if (!mDelayedCommitHandle) {
|
|
+ mDelayedCommitHandle = static_cast<WindowSurfaceWayland**>(
|
|
+ moz_xmalloc(sizeof(*mDelayedCommitHandle)));
|
|
+ *mDelayedCommitHandle = this;
|
|
+
|
|
+ MessageLoop::current()->PostDelayedTask(
|
|
+ NewRunnableFunction("WaylandBackBufferCommit",
|
|
+ &WaylandBufferDelayCommitHandler,
|
|
+ mDelayedCommitHandle),
|
|
+ EVENT_LOOP_DELAY);
|
|
+ }
|
|
return;
|
|
}
|
|
- wl_proxy_set_queue((struct wl_proxy *)waylandSurface,
|
|
+ wl_proxy_set_queue((struct wl_proxy*)waylandSurface,
|
|
mWaylandDisplay->GetEventQueue());
|
|
|
|
- if (mFullScreenDamage) {
|
|
+ // We have an active frame callback request so handle it.
|
|
+ if (mFrameCallback) {
|
|
+ if (waylandSurface == mLastCommittedSurface) {
|
|
+ // We have an active frame callback pending from our recent surface.
|
|
+ // It means we should defer the commit to FrameCallbackHandler().
|
|
+ return;
|
|
+ }
|
|
+ // If our stored wl_surface does not match the actual one it means the frame
|
|
+ // callback is no longer active and we should release it.
|
|
+ wl_callback_destroy(mFrameCallback);
|
|
+ mFrameCallback = nullptr;
|
|
+ mLastCommittedSurface = nullptr;
|
|
+ }
|
|
+
|
|
+ if (mWaylandBufferFullScreenDamage) {
|
|
LayoutDeviceIntRect rect = mWindow->GetBounds();
|
|
wl_surface_damage(waylandSurface, 0, 0, rect.width, rect.height);
|
|
- mFullScreenDamage = false;
|
|
+ mWaylandBufferFullScreenDamage = false;
|
|
} else {
|
|
- for (auto iter = aInvalidRegion.RectIter(); !iter.Done(); iter.Next()) {
|
|
- const mozilla::LayoutDeviceIntRect &r = iter.Get();
|
|
- wl_surface_damage(waylandSurface, r.x, r.y, r.width, r.height);
|
|
+ gint scaleFactor = mWindow->GdkScaleFactor();
|
|
+ for (auto iter = mWaylandBufferDamage.RectIter(); !iter.Done();
|
|
+ iter.Next()) {
|
|
+ const mozilla::LayoutDeviceIntRect& r = iter.Get();
|
|
+ // We need to remove the scale factor because the wl_surface_damage
|
|
+ // also multiplies by current scale factor.
|
|
+ wl_surface_damage(waylandSurface, r.x / scaleFactor, r.y / scaleFactor,
|
|
+ r.width / scaleFactor, r.height / scaleFactor);
|
|
}
|
|
}
|
|
|
|
- // Frame callback is always connected to actual wl_surface. When the surface
|
|
- // is unmapped/deleted the frame callback is never called. Unfortunatelly
|
|
- // we don't know if the frame callback is not going to be called.
|
|
- // But our mozcontainer code deletes wl_surface when the GdkWindow is hidden
|
|
- // creates a new one when is visible.
|
|
- if (mFrameCallback && mFrameCallbackSurface == waylandSurface) {
|
|
- // Do nothing here - we have a valid wl_surface and the buffer will be
|
|
- // commited to compositor in next frame callback event.
|
|
- mDelayedCommit = true;
|
|
- return;
|
|
- } else {
|
|
- if (mFrameCallback) {
|
|
- // Delete frame callback connected to obsoleted wl_surface.
|
|
- wl_callback_destroy(mFrameCallback);
|
|
- }
|
|
+ // Clear all back buffer damage as we're committing
|
|
+ // all requested regions.
|
|
+ mWaylandBufferDamage.SetEmpty();
|
|
|
|
- mFrameCallback = wl_surface_frame(waylandSurface);
|
|
- wl_callback_add_listener(mFrameCallback, &frame_listener, this);
|
|
- mFrameCallbackSurface = waylandSurface;
|
|
-
|
|
- // There's no pending frame callback so we can draw immediately
|
|
- // and create frame callback for possible subsequent drawing.
|
|
- mFrontBuffer->Attach(waylandSurface);
|
|
- mDelayedCommit = false;
|
|
+ mFrameCallback = wl_surface_frame(waylandSurface);
|
|
+ wl_callback_add_listener(mFrameCallback, &frame_listener, this);
|
|
+
|
|
+ if (mNeedScaleFactorUpdate || mLastCommittedSurface != waylandSurface) {
|
|
+ wl_surface_set_buffer_scale(waylandSurface, mWindow->GdkScaleFactor());
|
|
+ mNeedScaleFactorUpdate = false;
|
|
}
|
|
+
|
|
+ mWaylandBuffer->Attach(waylandSurface);
|
|
+ mLastCommittedSurface = waylandSurface;
|
|
+
|
|
+ // There's no pending commit, all changes are sent to compositor.
|
|
+ mPendingCommit = false;
|
|
+}
|
|
+
|
|
+void WindowSurfaceWayland::Commit(const LayoutDeviceIntRegion& aInvalidRegion) {
|
|
+ MOZ_ASSERT(mIsMainThread == NS_IsMainThread());
|
|
+
|
|
+ // We have new content at mImageSurface - copy data to mWaylandBuffer first.
|
|
+ if (!mDrawToWaylandBufferDirectly) {
|
|
+ CommitImageSurfaceToWaylandBuffer(aInvalidRegion);
|
|
+ }
|
|
+
|
|
+ // If we're not at fullscreen damage add drawing area from aInvalidRegion
|
|
+ if (!mWaylandBufferFullScreenDamage) {
|
|
+ mWaylandBufferDamage.OrWith(aInvalidRegion);
|
|
+ }
|
|
+
|
|
+ // We're ready to commit.
|
|
+ mPendingCommit = true;
|
|
+ CommitWaylandBuffer();
|
|
}
|
|
|
|
void WindowSurfaceWayland::FrameCallbackHandler() {
|
|
MOZ_ASSERT(mIsMainThread == NS_IsMainThread());
|
|
+ MOZ_ASSERT(mFrameCallback != nullptr,
|
|
+ "FrameCallbackHandler() called without valid frame callback!");
|
|
+ MOZ_ASSERT(mLastCommittedSurface != nullptr,
|
|
+ "FrameCallbackHandler() called without valid wl_surface!");
|
|
|
|
- if (mFrameCallback) {
|
|
- wl_callback_destroy(mFrameCallback);
|
|
- mFrameCallback = nullptr;
|
|
- mFrameCallbackSurface = nullptr;
|
|
+ wl_callback_destroy(mFrameCallback);
|
|
+ mFrameCallback = nullptr;
|
|
+
|
|
+ if (mPendingCommit) {
|
|
+ CommitWaylandBuffer();
|
|
}
|
|
+}
|
|
|
|
- if (mDelayedCommit) {
|
|
- wl_surface *waylandSurface = mWindow->GetWaylandSurface();
|
|
- if (!waylandSurface) {
|
|
- // Target window is already destroyed - don't bother to render there.
|
|
- NS_WARNING("No drawing buffer available");
|
|
- return;
|
|
- }
|
|
- wl_proxy_set_queue((struct wl_proxy *)waylandSurface,
|
|
- mWaylandDisplay->GetEventQueue());
|
|
+void WindowSurfaceWayland::DelayedCommitHandler() {
|
|
+ MOZ_ASSERT(mDelayedCommitHandle != nullptr, "Missing mDelayedCommitHandle!");
|
|
|
|
- // Send pending surface to compositor and register frame callback
|
|
- // for possible subsequent drawing.
|
|
- mFrameCallback = wl_surface_frame(waylandSurface);
|
|
- wl_callback_add_listener(mFrameCallback, &frame_listener, this);
|
|
- mFrameCallbackSurface = waylandSurface;
|
|
+ *mDelayedCommitHandle = nullptr;
|
|
+ free(mDelayedCommitHandle);
|
|
+ mDelayedCommitHandle = nullptr;
|
|
|
|
- mFrontBuffer->Attach(waylandSurface);
|
|
- mDelayedCommit = false;
|
|
+ if (mPendingCommit) {
|
|
+ CommitWaylandBuffer();
|
|
}
|
|
}
|
|
|
|
diff -up thunderbird-60.5.0/widget/gtk/WindowSurfaceWayland.h.wayland thunderbird-60.5.0/widget/gtk/WindowSurfaceWayland.h
|
|
--- thunderbird-60.5.0/widget/gtk/WindowSurfaceWayland.h.wayland 2019-01-22 20:44:03.000000000 +0100
|
|
+++ thunderbird-60.5.0/widget/gtk/WindowSurfaceWayland.h 2019-02-05 14:26:16.979316635 +0100
|
|
@@ -1,4 +1,4 @@
|
|
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
@@ -8,37 +8,14 @@
|
|
#define _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_WAYLAND_H
|
|
|
|
#include <prthread.h>
|
|
+#include "mozilla/gfx/Types.h"
|
|
+#include "nsWaylandDisplay.h"
|
|
+
|
|
+#define BACK_BUFFER_NUM 2
|
|
|
|
namespace mozilla {
|
|
namespace widget {
|
|
|
|
-// Our general connection to Wayland display server,
|
|
-// holds our display connection and runs event loop.
|
|
-class nsWaylandDisplay : public nsISupports {
|
|
- NS_DECL_THREADSAFE_ISUPPORTS
|
|
-
|
|
- public:
|
|
- nsWaylandDisplay(wl_display* aDisplay);
|
|
-
|
|
- wl_shm* GetShm();
|
|
- void SetShm(wl_shm* aShm) { mShm = aShm; };
|
|
-
|
|
- wl_display* GetDisplay() { return mDisplay; };
|
|
- wl_event_queue* GetEventQueue() { return mEventQueue; };
|
|
- gfx::SurfaceFormat GetSurfaceFormat() { return mFormat; };
|
|
- bool DisplayLoop();
|
|
- bool Matches(wl_display* aDisplay);
|
|
-
|
|
- private:
|
|
- virtual ~nsWaylandDisplay();
|
|
-
|
|
- PRThread* mThreadId;
|
|
- gfx::SurfaceFormat mFormat;
|
|
- wl_shm* mShm;
|
|
- wl_event_queue* mEventQueue;
|
|
- wl_display* mDisplay;
|
|
-};
|
|
-
|
|
// Allocates and owns shared memory for Wayland drawing surface
|
|
class WaylandShmPool {
|
|
public:
|
|
@@ -66,14 +43,15 @@ class WindowBackBuffer {
|
|
WindowBackBuffer(nsWaylandDisplay* aDisplay, int aWidth, int aHeight);
|
|
~WindowBackBuffer();
|
|
|
|
- already_AddRefed<gfx::DrawTarget> Lock(const LayoutDeviceIntRegion& aRegion);
|
|
+ already_AddRefed<gfx::DrawTarget> Lock();
|
|
|
|
void Attach(wl_surface* aSurface);
|
|
void Detach();
|
|
bool IsAttached() { return mAttached; }
|
|
|
|
+ void Clear();
|
|
bool Resize(int aWidth, int aHeight);
|
|
- bool SetImageDataFromBackBuffer(class WindowBackBuffer* aSourceBuffer);
|
|
+ bool SetImageDataFromBuffer(class WindowBackBuffer* aSourceBuffer);
|
|
|
|
bool IsMatchingSize(int aWidth, int aHeight) {
|
|
return aWidth == mWidth && aHeight == mHeight;
|
|
@@ -82,6 +60,8 @@ class WindowBackBuffer {
|
|
return aBuffer->mWidth == mWidth && aBuffer->mHeight == mHeight;
|
|
}
|
|
|
|
+ static gfx::SurfaceFormat GetSurfaceFormat() { return mFormat; }
|
|
+
|
|
private:
|
|
void Create(int aWidth, int aHeight);
|
|
void Release();
|
|
@@ -96,35 +76,48 @@ class WindowBackBuffer {
|
|
int mHeight;
|
|
bool mAttached;
|
|
nsWaylandDisplay* mWaylandDisplay;
|
|
+ static gfx::SurfaceFormat mFormat;
|
|
};
|
|
|
|
// WindowSurfaceWayland is an abstraction for wl_surface
|
|
// and related management
|
|
class WindowSurfaceWayland : public WindowSurface {
|
|
public:
|
|
- WindowSurfaceWayland(nsWindow* aWindow);
|
|
+ explicit WindowSurfaceWayland(nsWindow* aWindow);
|
|
~WindowSurfaceWayland();
|
|
|
|
already_AddRefed<gfx::DrawTarget> Lock(
|
|
const LayoutDeviceIntRegion& aRegion) override;
|
|
void Commit(const LayoutDeviceIntRegion& aInvalidRegion) final;
|
|
void FrameCallbackHandler();
|
|
+ void DelayedCommitHandler();
|
|
|
|
private:
|
|
- WindowBackBuffer* GetBufferToDraw(int aWidth, int aHeight);
|
|
- void UpdateScaleFactor();
|
|
+ WindowBackBuffer* GetWaylandBufferToDraw(int aWidth, int aHeight);
|
|
+
|
|
+ already_AddRefed<gfx::DrawTarget> LockWaylandBuffer(int aWidth, int aHeight,
|
|
+ bool aClearBuffer);
|
|
+ already_AddRefed<gfx::DrawTarget> LockImageSurface(
|
|
+ const gfx::IntSize& aLockSize);
|
|
+ bool CommitImageSurfaceToWaylandBuffer(const LayoutDeviceIntRegion& aRegion);
|
|
+ void CommitWaylandBuffer();
|
|
|
|
// TODO: Do we need to hold a reference to nsWindow object?
|
|
nsWindow* mWindow;
|
|
nsWaylandDisplay* mWaylandDisplay;
|
|
- WindowBackBuffer* mFrontBuffer;
|
|
- WindowBackBuffer* mBackBuffer;
|
|
+ WindowBackBuffer* mWaylandBuffer;
|
|
+ LayoutDeviceIntRegion mWaylandBufferDamage;
|
|
+ WindowBackBuffer* mBackupBuffer[BACK_BUFFER_NUM];
|
|
+ RefPtr<gfxImageSurface> mImageSurface;
|
|
wl_callback* mFrameCallback;
|
|
- wl_surface* mFrameCallbackSurface;
|
|
+ wl_surface* mLastCommittedSurface;
|
|
MessageLoop* mDisplayThreadMessageLoop;
|
|
- bool mDelayedCommit;
|
|
- bool mFullScreenDamage;
|
|
+ WindowSurfaceWayland** mDelayedCommitHandle;
|
|
+ bool mDrawToWaylandBufferDirectly;
|
|
+ bool mPendingCommit;
|
|
+ bool mWaylandBufferFullScreenDamage;
|
|
bool mIsMainThread;
|
|
+ bool mNeedScaleFactorUpdate;
|
|
};
|
|
|
|
} // namespace widget
|