2018-11-20 12:38:58 +00:00
|
|
|
diff -up thunderbird-60.3.0/widget/gtk/GtkCompositorWidget.cpp.wayland thunderbird-60.3.0/widget/gtk/GtkCompositorWidget.cpp
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/GtkCompositorWidget.cpp.wayland 2018-10-30 12:45:35.000000000 +0100
|
2018-11-21 18:35:56 +00:00
|
|
|
+++ thunderbird-60.3.0/widget/gtk/GtkCompositorWidget.cpp 2018-11-21 13:42:00.757025666 +0100
|
2018-11-20 12:38:58 +00:00
|
|
|
@@ -40,7 +40,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;
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -50,8 +52,7 @@ GtkCompositorWidget::GtkCompositorWidget
|
2018-11-20 12:38:58 +00:00
|
|
|
mXDisplay,
|
|
|
|
mXWindow,
|
|
|
|
visual,
|
|
|
|
- depth
|
|
|
|
- );
|
2018-11-21 18:35:56 +00:00
|
|
|
+ depth);
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
|
|
|
mClientSize = aInitData.InitialClientSize();
|
|
|
|
}
|
2018-11-21 18:35:56 +00:00
|
|
|
diff -up thunderbird-60.3.0/widget/gtk/moz.build.wayland thunderbird-60.3.0/widget/gtk/moz.build
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/moz.build.wayland 2018-10-30 12:45:35.000000000 +0100
|
|
|
|
+++ thunderbird-60.3.0/widget/gtk/moz.build 2018-11-21 13:42:00.757025666 +0100
|
|
|
|
@@ -123,6 +123,7 @@ include('/ipc/chromium/chromium-config.m
|
|
|
|
FINAL_LIBRARY = 'xul'
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
LOCAL_INCLUDES += [
|
|
|
|
+ '/layout/base',
|
|
|
|
'/layout/generic',
|
|
|
|
'/layout/xul',
|
|
|
|
'/other-licenses/atk-1.0',
|
|
|
|
diff -up thunderbird-60.3.0/widget/gtk/mozcontainer.cpp.wayland thunderbird-60.3.0/widget/gtk/mozcontainer.cpp
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/mozcontainer.cpp.wayland 2018-10-30 12:45:35.000000000 +0100
|
|
|
|
+++ thunderbird-60.3.0/widget/gtk/mozcontainer.cpp 2018-11-21 13:42:00.757025666 +0100
|
|
|
|
@@ -10,6 +10,7 @@
|
|
|
|
#ifdef MOZ_WAYLAND
|
|
|
|
#include <gdk/gdkx.h>
|
|
|
|
#include <gdk/gdkwayland.h>
|
|
|
|
+#include <wayland-egl.h>
|
|
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <dlfcn.h>
|
|
|
|
@@ -207,6 +208,12 @@ moz_container_init (MozContainer *contai
|
|
|
|
|
|
|
|
#if defined(MOZ_WAYLAND)
|
|
|
|
{
|
|
|
|
+ container->subcompositor = nullptr;
|
|
|
|
+ container->surface = nullptr;
|
|
|
|
+ container->subsurface = nullptr;
|
|
|
|
+ container->eglwindow = nullptr;
|
|
|
|
+ container->parent_surface_committed = false;
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
GdkDisplay *gdk_display = gtk_widget_get_display(GTK_WIDGET(container));
|
|
|
|
if (GDK_IS_WAYLAND_DISPLAY (gdk_display)) {
|
|
|
|
// Available as of GTK 3.8+
|
|
|
|
@@ -225,12 +232,21 @@ moz_container_init (MozContainer *contai
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
#if defined(MOZ_WAYLAND)
|
|
|
|
+static void
|
|
|
|
+moz_container_commited_handler(GdkFrameClock *clock, MozContainer *container)
|
2018-11-20 12:38:58 +00:00
|
|
|
+{
|
2018-11-21 18:35:56 +00:00
|
|
|
+ container->parent_surface_committed = true;
|
|
|
|
+ g_signal_handler_disconnect(clock,
|
|
|
|
+ container->parent_surface_committed_handler);
|
|
|
|
+ container->parent_surface_committed_handler = 0;
|
2018-11-20 12:38:58 +00:00
|
|
|
+}
|
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
/* 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.
|
|
|
|
+ * for reference.
|
|
|
|
*/
|
|
|
|
static gboolean
|
|
|
|
moz_container_map_surface(MozContainer *container)
|
|
|
|
@@ -242,6 +258,9 @@ moz_container_map_surface(MozContainer *
|
|
|
|
static auto sGdkWaylandWindowGetWlSurface =
|
|
|
|
(wl_surface *(*)(GdkWindow *))
|
|
|
|
dlsym(RTLD_DEFAULT, "gdk_wayland_window_get_wl_surface");
|
|
|
|
+ static auto sGdkWindowGetFrameClock =
|
|
|
|
+ (GdkFrameClock *(*)(GdkWindow *))
|
|
|
|
+ dlsym(RTLD_DEFAULT, "gdk_window_get_frame_clock");
|
|
|
|
|
|
|
|
GdkDisplay *display = gtk_widget_get_display(GTK_WIDGET(container));
|
|
|
|
if (GDK_IS_X11_DISPLAY(display))
|
|
|
|
@@ -250,6 +269,18 @@ moz_container_map_surface(MozContainer *
|
|
|
|
if (container->subsurface && container->surface)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
+ if (!container->parent_surface_committed) {
|
|
|
|
+ if (!container->parent_surface_committed_handler) {
|
|
|
|
+ GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
|
|
|
|
+ GdkFrameClock *clock = sGdkWindowGetFrameClock(window);
|
|
|
|
+ container->parent_surface_committed_handler =
|
|
|
|
+ g_signal_connect_after(clock, "after-paint",
|
|
|
|
+ G_CALLBACK(moz_container_commited_handler),
|
|
|
|
+ container);
|
|
|
|
+ }
|
2018-11-20 12:38:58 +00:00
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
if (!container->surface) {
|
|
|
|
struct wl_compositor *compositor;
|
|
|
|
compositor = sGdkWaylandDisplayGetWlCompositor(display);
|
|
|
|
@@ -289,8 +320,22 @@ moz_container_map_surface(MozContainer *
|
|
|
|
static void
|
|
|
|
moz_container_unmap_surface(MozContainer *container)
|
|
|
|
{
|
|
|
|
+ //g_clear_pointer(&container->eglwindow, wl_egl_window_destroy);
|
|
|
|
g_clear_pointer(&container->subsurface, wl_subsurface_destroy);
|
|
|
|
g_clear_pointer(&container->surface, wl_surface_destroy);
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ if (container->parent_surface_committed_handler) {
|
|
|
|
+ static auto sGdkWindowGetFrameClock =
|
|
|
|
+ (GdkFrameClock *(*)(GdkWindow *))
|
|
|
|
+ dlsym(RTLD_DEFAULT, "gdk_window_get_frame_clock");
|
|
|
|
+ GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(container));
|
|
|
|
+ GdkFrameClock *clock = sGdkWindowGetFrameClock(window);
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ g_signal_handler_disconnect(clock,
|
|
|
|
+ container->parent_surface_committed_handler);
|
|
|
|
+ container->parent_surface_committed_handler = 0;
|
2018-11-20 12:38:58 +00:00
|
|
|
+ }
|
2018-11-21 18:35:56 +00:00
|
|
|
+ container->parent_surface_committed = false;
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
#endif
|
|
|
|
@@ -555,8 +605,40 @@ moz_container_get_wl_surface(MozContaine
|
|
|
|
return nullptr;
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
moz_container_map_surface(container);
|
|
|
|
+ // Set the scale factor for the buffer right after we create it.
|
|
|
|
+ if (container->surface) {
|
|
|
|
+ static auto sGdkWindowGetScaleFactorPtr = (gint (*)(GdkWindow*))
|
|
|
|
+ dlsym(RTLD_DEFAULT, "gdk_window_get_scale_factor");
|
|
|
|
+ if (sGdkWindowGetScaleFactorPtr && window) {
|
|
|
|
+ gint scaleFactor = (*sGdkWindowGetScaleFactorPtr)(window);
|
|
|
|
+ wl_surface_set_buffer_scale(container->surface, scaleFactor);
|
2018-11-20 12:38:58 +00:00
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
}
|
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
return container->surface;
|
|
|
|
}
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+struct wl_egl_window *
|
|
|
|
+moz_container_get_wl_egl_window(MozContainer *container)
|
|
|
|
+{ /*
|
|
|
|
+ if (!container->eglwindow) {
|
|
|
|
+ struct wl_surface *wlsurf = moz_container_get_wl_surface(container);
|
|
|
|
+ if (!wlsurf)
|
|
|
|
+ return nullptr;
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(container));
|
|
|
|
+ container->eglwindow
|
|
|
|
+ = wl_egl_window_create(wlsurf,
|
|
|
|
+ gdk_window_get_width(window),
|
|
|
|
+ gdk_window_get_height(window));
|
2018-11-20 12:38:58 +00:00
|
|
|
+ }
|
2018-11-21 18:35:56 +00:00
|
|
|
+ return container->eglwindow;*/ return nullptr;
|
|
|
|
+}
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+gboolean
|
|
|
|
+moz_container_has_wl_egl_window(MozContainer *container)
|
|
|
|
+{
|
|
|
|
+ return container->eglwindow ? true : false;
|
|
|
|
+}
|
|
|
|
#endif
|
|
|
|
diff -up thunderbird-60.3.0/widget/gtk/mozcontainer.h.wayland thunderbird-60.3.0/widget/gtk/mozcontainer.h
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/mozcontainer.h.wayland 2018-10-30 12:45:34.000000000 +0100
|
|
|
|
+++ thunderbird-60.3.0/widget/gtk/mozcontainer.h 2018-11-21 13:42:00.757025666 +0100
|
|
|
|
@@ -72,6 +72,9 @@ struct _MozContainer
|
|
|
|
struct wl_subcompositor *subcompositor;
|
|
|
|
struct wl_surface *surface;
|
|
|
|
struct wl_subsurface *subsurface;
|
|
|
|
+ struct wl_egl_window *eglwindow;
|
|
|
|
+ gboolean parent_surface_committed;
|
|
|
|
+ gulong parent_surface_committed_handler;
|
|
|
|
#endif
|
|
|
|
};
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -95,6 +98,8 @@ void moz_container_move (
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
#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);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif /* __MOZ_CONTAINER_H__ */
|
|
|
|
diff -up thunderbird-60.3.0/widget/gtk/mozgtk/mozgtk.c.wayland thunderbird-60.3.0/widget/gtk/mozgtk/mozgtk.c
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/mozgtk/mozgtk.c.wayland 2018-10-30 12:45:35.000000000 +0100
|
|
|
|
+++ thunderbird-60.3.0/widget/gtk/mozgtk/mozgtk.c 2018-11-21 13:42:00.757025666 +0100
|
|
|
|
@@ -135,6 +135,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)
|
|
|
|
@@ -266,6 +268,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)
|
|
|
|
diff -up thunderbird-60.3.0/widget/gtk/mozwayland/mozwayland.c.wayland thunderbird-60.3.0/widget/gtk/mozwayland/mozwayland.c
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/mozwayland/mozwayland.c.wayland 2018-10-30 12:45:35.000000000 +0100
|
|
|
|
+++ thunderbird-60.3.0/widget/gtk/mozwayland/mozwayland.c 2018-11-21 13:42:00.758025661 +0100
|
|
|
|
@@ -271,3 +271,21 @@ wl_log_set_handler_client(wl_log_func_t
|
2018-11-20 12:38:58 +00:00
|
|
|
{
|
2018-11-21 18:35:56 +00:00
|
|
|
}
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
+MOZ_EXPORT struct wl_egl_window *
|
|
|
|
+wl_egl_window_create(struct wl_surface *surface,
|
|
|
|
+ int width, int height)
|
|
|
|
+{
|
|
|
|
+ return NULL;
|
|
|
|
+}
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+MOZ_EXPORT void
|
|
|
|
+wl_egl_window_destroy(struct wl_egl_window *egl_window)
|
|
|
|
+{
|
|
|
|
+}
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+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.3.0/widget/gtk/nsClipboard.cpp.wayland thunderbird-60.3.0/widget/gtk/nsClipboard.cpp
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/nsClipboard.cpp.wayland 2018-10-30 12:45:34.000000000 +0100
|
|
|
|
+++ thunderbird-60.3.0/widget/gtk/nsClipboard.cpp 2018-11-21 13:42:00.758025661 +0100
|
|
|
|
@@ -671,11 +671,9 @@ void ConvertHTMLtoUCS2(const char* data,
|
|
|
|
*unicodeData =
|
|
|
|
reinterpret_cast<char16_t*>
|
|
|
|
(moz_xmalloc((outUnicodeLen + sizeof('\0')) * sizeof(char16_t)));
|
|
|
|
- if (*unicodeData) {
|
|
|
|
- memcpy(*unicodeData, data + sizeof(char16_t),
|
|
|
|
- outUnicodeLen * sizeof(char16_t));
|
|
|
|
- (*unicodeData)[outUnicodeLen] = '\0';
|
|
|
|
- }
|
|
|
|
+ memcpy(*unicodeData, data + sizeof(char16_t),
|
|
|
|
+ outUnicodeLen * sizeof(char16_t));
|
|
|
|
+ (*unicodeData)[outUnicodeLen] = '\0';
|
|
|
|
} else if (charset.EqualsLiteral("UNKNOWN")) {
|
|
|
|
outUnicodeLen = 0;
|
|
|
|
return;
|
|
|
|
@@ -701,27 +699,25 @@ void ConvertHTMLtoUCS2(const char* data,
|
|
|
|
if (needed.value()) {
|
|
|
|
*unicodeData = reinterpret_cast<char16_t*>(
|
|
|
|
moz_xmalloc((needed.value() + 1) * sizeof(char16_t)));
|
|
|
|
- if (*unicodeData) {
|
|
|
|
- uint32_t result;
|
|
|
|
- size_t read;
|
|
|
|
- size_t written;
|
|
|
|
- bool hadErrors;
|
|
|
|
- Tie(result, read, written, hadErrors) =
|
|
|
|
- decoder->DecodeToUTF16(AsBytes(MakeSpan(data, dataLength)),
|
|
|
|
- MakeSpan(*unicodeData, needed.value()),
|
|
|
|
- true);
|
|
|
|
- MOZ_ASSERT(result == kInputEmpty);
|
|
|
|
- MOZ_ASSERT(read == size_t(dataLength));
|
|
|
|
- MOZ_ASSERT(written <= needed.value());
|
|
|
|
- Unused << hadErrors;
|
|
|
|
+ uint32_t result;
|
|
|
|
+ size_t read;
|
|
|
|
+ size_t written;
|
|
|
|
+ bool hadErrors;
|
|
|
|
+ Tie(result, read, written, hadErrors) =
|
|
|
|
+ decoder->DecodeToUTF16(AsBytes(MakeSpan(data, dataLength)),
|
|
|
|
+ MakeSpan(*unicodeData, needed.value()),
|
|
|
|
+ true);
|
|
|
|
+ MOZ_ASSERT(result == kInputEmpty);
|
|
|
|
+ MOZ_ASSERT(read == size_t(dataLength));
|
|
|
|
+ MOZ_ASSERT(written <= needed.value());
|
|
|
|
+ Unused << hadErrors;
|
|
|
|
#ifdef DEBUG_CLIPBOARD
|
|
|
|
- if (read != dataLength)
|
|
|
|
- printf("didn't consume all the bytes\n");
|
|
|
|
+ if (read != dataLength)
|
|
|
|
+ printf("didn't consume all the bytes\n");
|
|
|
|
#endif
|
|
|
|
- outUnicodeLen = written;
|
|
|
|
- // null terminate.
|
|
|
|
- (*unicodeData)[outUnicodeLen] = '\0';
|
|
|
|
- }
|
|
|
|
+ outUnicodeLen = written;
|
|
|
|
+ // null terminate.
|
|
|
|
+ (*unicodeData)[outUnicodeLen] = '\0';
|
|
|
|
} // if valid length
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
|
|
|
}
|
2018-11-21 18:35:56 +00:00
|
|
|
diff -up thunderbird-60.3.0/widget/gtk/nsClipboardWayland.cpp.wayland thunderbird-60.3.0/widget/gtk/nsClipboardWayland.cpp
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/nsClipboardWayland.cpp.wayland 2018-10-30 12:45:34.000000000 +0100
|
|
|
|
+++ thunderbird-60.3.0/widget/gtk/nsClipboardWayland.cpp 2018-11-21 13:42:00.758025661 +0100
|
|
|
|
@@ -23,6 +23,7 @@
|
|
|
|
#include "mozilla/Services.h"
|
|
|
|
#include "mozilla/RefPtr.h"
|
|
|
|
#include "mozilla/TimeStamp.h"
|
|
|
|
+#include "nsDragService.h"
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
#include "imgIContainer.h"
|
|
|
|
|
|
|
|
@@ -46,6 +47,44 @@ nsRetrievalContextWayland::sTextMimeType
|
|
|
|
"COMPOUND_TEXT"
|
|
|
|
};
|
|
|
|
|
|
|
|
+static inline GdkDragAction
|
|
|
|
+wl_to_gdk_actions(uint32_t dnd_actions)
|
2018-11-20 12:38:58 +00:00
|
|
|
+{
|
2018-11-21 18:35:56 +00:00
|
|
|
+ GdkDragAction actions = GdkDragAction(0);
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ 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);
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ return actions;
|
|
|
|
+}
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+static inline uint32_t
|
|
|
|
+gdk_to_wl_actions(GdkDragAction action)
|
|
|
|
+{
|
|
|
|
+ uint32_t dnd_actions = 0;
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ 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;
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ return dnd_actions;
|
|
|
|
+}
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+static GtkWidget*
|
|
|
|
+get_gtk_widget_for_wl_surface(struct wl_surface *surface)
|
|
|
|
+{
|
|
|
|
+ GdkWindow *gdkParentWindow =
|
|
|
|
+ static_cast<GdkWindow*>(wl_surface_get_user_data(surface));
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ gpointer user_data = nullptr;
|
|
|
|
+ gdk_window_get_user_data(gdkParentWindow, &user_data);
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ return GTK_WIDGET(user_data);
|
2018-11-20 12:38:58 +00:00
|
|
|
+}
|
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
void
|
|
|
|
DataOffer::AddMIMEType(const char *aMimeType)
|
2018-11-20 12:38:58 +00:00
|
|
|
{
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -114,7 +153,7 @@ DataOffer::GetData(wl_display* aDisplay,
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
GIOChannel *channel = g_io_channel_unix_new(pipe_fd[0]);
|
|
|
|
GError* error = nullptr;
|
|
|
|
- char* clipboardData;
|
|
|
|
+ char* clipboardData = nullptr;
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
g_io_channel_set_encoding(channel, nullptr, &error);
|
|
|
|
if (!error) {
|
|
|
|
@@ -155,6 +194,61 @@ WaylandDataOffer::RequestDataTransfer(co
|
|
|
|
return false;
|
|
|
|
}
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
+void
|
|
|
|
+WaylandDataOffer::DragOfferAccept(const char* aMimeType, uint32_t aTime)
|
|
|
|
+{
|
|
|
|
+ wl_data_offer_accept(mWaylandDataOffer, aTime, aMimeType);
|
|
|
|
+}
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+/* 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;
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ wl_data_offer_set_actions(mWaylandDataOffer, all_actions, dnd_actions);
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ /* 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().
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ 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]));
|
|
|
|
+ }
|
|
|
|
+}
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+void
|
|
|
|
+WaylandDataOffer::SetSelectedDragAction(uint32_t aWaylandAction)
|
|
|
|
+{
|
|
|
|
+ mSelectedDragAction = aWaylandAction;
|
|
|
|
+}
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+GdkDragAction
|
|
|
|
+WaylandDataOffer::GetSelectedDragAction()
|
|
|
|
+{
|
|
|
|
+ return wl_to_gdk_actions(mSelectedDragAction);
|
|
|
|
+}
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+void
|
|
|
|
+WaylandDataOffer::SetAvailableDragActions(uint32_t aWaylandActions)
|
|
|
|
+{
|
|
|
|
+ mAvailableDragAction = aWaylandActions;
|
|
|
|
+}
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+GdkDragAction
|
|
|
|
+WaylandDataOffer::GetAvailableDragActions()
|
2018-11-20 12:38:58 +00:00
|
|
|
+{
|
2018-11-21 18:35:56 +00:00
|
|
|
+ return wl_to_gdk_actions(mAvailableDragAction);
|
2018-11-20 12:38:58 +00:00
|
|
|
+}
|
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
static void
|
|
|
|
data_offer_offer (void *data,
|
|
|
|
struct wl_data_offer *wl_data_offer,
|
|
|
|
@@ -164,25 +258,39 @@ data_offer_offer (void *
|
|
|
|
offer->AddMIMEType(type);
|
|
|
|
}
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
+/* 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.
|
|
|
|
+ */
|
2018-11-20 12:38:58 +00:00
|
|
|
static void
|
2018-11-21 18:35:56 +00:00
|
|
|
data_offer_source_actions(void *data,
|
|
|
|
struct wl_data_offer *wl_data_offer,
|
|
|
|
uint32_t source_actions)
|
2018-11-20 12:38:58 +00:00
|
|
|
{
|
2018-11-21 18:35:56 +00:00
|
|
|
+ auto *offer = static_cast<WaylandDataOffer*>(data);
|
|
|
|
+ offer->SetAvailableDragActions(source_actions);
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
+/* 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)
|
|
|
|
{
|
|
|
|
+ auto *offer = static_cast<WaylandDataOffer*>(data);
|
|
|
|
+ offer->SetSelectedDragAction(dnd_action);
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
/* 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 = {
|
|
|
|
data_offer_offer,
|
|
|
|
@@ -246,12 +354,94 @@ PrimaryDataOffer::~PrimaryDataOffer(void
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
|
|
|
}
|
2018-11-21 18:35:56 +00:00
|
|
|
|
|
|
|
+NS_IMPL_ISUPPORTS(nsWaylandDragContext, nsISupports);
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+nsWaylandDragContext::nsWaylandDragContext(WaylandDataOffer* aDataOffer,
|
|
|
|
+ wl_display *aDisplay)
|
|
|
|
+ : mDataOffer(aDataOffer)
|
|
|
|
+ , mDisplay(aDisplay)
|
|
|
|
+ , mTime(0)
|
|
|
|
+ , mGtkWidget(nullptr)
|
|
|
|
+ , mX(0)
|
|
|
|
+ , mY(0)
|
|
|
|
+{
|
2018-11-20 12:38:58 +00:00
|
|
|
+}
|
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+void
|
|
|
|
+nsWaylandDragContext::DropDataEnter(GtkWidget* aGtkWidget, uint32_t aTime,
|
|
|
|
+ nscoord aX, nscoord aY)
|
2018-11-20 12:38:58 +00:00
|
|
|
+{
|
2018-11-21 18:35:56 +00:00
|
|
|
+ mTime = aTime;
|
|
|
|
+ mGtkWidget = aGtkWidget;
|
|
|
|
+ mX = aX;
|
|
|
|
+ mY = aY;
|
2018-11-20 12:38:58 +00:00
|
|
|
+}
|
2018-11-21 18:35:56 +00:00
|
|
|
+
|
|
|
|
void
|
|
|
|
-nsRetrievalContextWayland::RegisterDataOffer(wl_data_offer *aWaylandDataOffer)
|
|
|
|
+nsWaylandDragContext::DropMotion(uint32_t aTime, nscoord aX, nscoord aY)
|
2018-11-20 12:38:58 +00:00
|
|
|
+{
|
2018-11-21 18:35:56 +00:00
|
|
|
+ mTime = aTime;
|
|
|
|
+ mX = aX;
|
|
|
|
+ mY = aY;
|
2018-11-20 12:38:58 +00:00
|
|
|
+}
|
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+void
|
|
|
|
+nsWaylandDragContext::GetLastDropInfo(uint32_t *aTime, nscoord *aX, nscoord *aY)
|
2018-11-20 12:38:58 +00:00
|
|
|
+{
|
2018-11-21 18:35:56 +00:00
|
|
|
+ *aTime = mTime;
|
|
|
|
+ *aX = mX;
|
|
|
|
+ *aY = mY;
|
2018-11-20 12:38:58 +00:00
|
|
|
+}
|
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+void
|
|
|
|
+nsWaylandDragContext::SetDragStatus(GdkDragAction aAction)
|
2018-11-20 12:38:58 +00:00
|
|
|
+{
|
2018-11-21 18:35:56 +00:00
|
|
|
+ mDataOffer->SetDragStatus(aAction, mTime);
|
2018-11-20 12:38:58 +00:00
|
|
|
+}
|
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+GdkDragAction
|
|
|
|
+nsWaylandDragContext::GetSelectedDragAction()
|
2018-11-20 12:38:58 +00:00
|
|
|
+{
|
2018-11-21 18:35:56 +00:00
|
|
|
+ GdkDragAction gdkAction = mDataOffer->GetSelectedDragAction();
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ // We emulate gdk_drag_context_get_actions() here.
|
|
|
|
+ if (!gdkAction) {
|
|
|
|
+ gdkAction = mDataOffer->GetAvailableDragActions();
|
|
|
|
+ }
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ return gdkAction;
|
2018-11-20 12:38:58 +00:00
|
|
|
+}
|
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+GList*
|
|
|
|
+nsWaylandDragContext::GetTargets()
|
2018-11-20 12:38:58 +00:00
|
|
|
+{
|
2018-11-21 18:35:56 +00:00
|
|
|
+ int targetNums;
|
|
|
|
+ GdkAtom *atoms = mDataOffer->GetTargets(&targetNums);
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ GList* targetList = nullptr;
|
|
|
|
+ for (int i = 0; i < targetNums; i++) {
|
|
|
|
+ targetList = g_list_append(targetList, GDK_ATOM_TO_POINTER(atoms[i]));
|
|
|
|
+ }
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ return targetList;
|
2018-11-20 12:38:58 +00:00
|
|
|
+}
|
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+char*
|
|
|
|
+nsWaylandDragContext::GetData(const char* aMimeType, uint32_t* aContentLength)
|
2018-11-20 12:38:58 +00:00
|
|
|
+{
|
2018-11-21 18:35:56 +00:00
|
|
|
+ mDataOffer->DragOfferAccept(aMimeType, mTime);
|
|
|
|
+ return mDataOffer->GetData(mDisplay, aMimeType, aContentLength);
|
2018-11-20 12:38:58 +00:00
|
|
|
+}
|
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+void
|
|
|
|
+nsRetrievalContextWayland::RegisterNewDataOffer(wl_data_offer *aWaylandDataOffer)
|
2018-11-20 12:38:58 +00:00
|
|
|
{
|
2018-11-21 18:35:56 +00:00
|
|
|
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);
|
|
|
|
@@ -259,12 +449,15 @@ nsRetrievalContextWayland::RegisterDataO
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
-nsRetrievalContextWayland::RegisterDataOffer(
|
|
|
|
+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);
|
|
|
|
@@ -274,6 +467,9 @@ nsRetrievalContextWayland::RegisterDataO
|
|
|
|
void
|
|
|
|
nsRetrievalContextWayland::SetClipboardDataOffer(wl_data_offer *aWaylandDataOffer)
|
|
|
|
{
|
|
|
|
+ // Delete existing clipboard data offer
|
|
|
|
+ mClipboardOffer = nullptr;
|
|
|
|
+
|
|
|
|
DataOffer* dataOffer =
|
|
|
|
static_cast<DataOffer*>(g_hash_table_lookup(mActiveOffers,
|
|
|
|
aWaylandDataOffer));
|
|
|
|
@@ -288,10 +484,12 @@ 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));
|
|
|
|
@@ -304,12 +502,31 @@ nsRetrievalContextWayland::SetPrimaryDat
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
-nsRetrievalContextWayland::ClearDataOffers(void)
|
|
|
|
+nsRetrievalContextWayland::AddDragAndDropDataOffer(wl_data_offer *aDropDataOffer)
|
|
|
|
{
|
|
|
|
- if (mClipboardOffer)
|
|
|
|
- mClipboardOffer = nullptr;
|
|
|
|
- if (mPrimaryOffer)
|
|
|
|
- mPrimaryOffer = nullptr;
|
|
|
|
+ // 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);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+nsWaylandDragContext*
|
|
|
|
+nsRetrievalContextWayland::GetDragContext(void)
|
|
|
|
+{
|
|
|
|
+ return mDragContext;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void
|
|
|
|
+nsRetrievalContextWayland::ClearDragAndDropDataOffer(void)
|
|
|
|
+{
|
|
|
|
+ mDragContext = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have a new fresh data content.
|
|
|
|
@@ -321,7 +538,7 @@ data_device_data_offer (void
|
|
|
|
{
|
|
|
|
nsRetrievalContextWayland *context =
|
|
|
|
static_cast<nsRetrievalContextWayland*>(data);
|
|
|
|
- context->RegisterDataOffer(offer);
|
|
|
|
+ context->RegisterNewDataOffer(offer);
|
|
|
|
}
|
|
|
|
|
|
|
|
// The new fresh data content is clipboard.
|
|
|
|
@@ -341,31 +558,78 @@ data_device_enter (void
|
|
|
|
struct wl_data_device *data_device,
|
|
|
|
uint32_t time,
|
|
|
|
struct wl_surface *surface,
|
|
|
|
- int32_t x,
|
|
|
|
- int32_t y,
|
|
|
|
+ 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);
|
|
|
|
+
|
|
|
|
+ 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)
|
|
|
|
+ int32_t x_fixed,
|
|
|
|
+ int32_t y_fixed)
|
|
|
|
{
|
|
|
|
+ nsRetrievalContextWayland *context =
|
|
|
|
+ static_cast<nsRetrievalContextWayland*>(data);
|
|
|
|
+
|
|
|
|
+ nsWaylandDragContext* dropContext = context->GetDragContext();
|
|
|
|
+
|
|
|
|
+ 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:
|
|
|
|
@@ -405,7 +669,7 @@ primary_selection_data_offer (void
|
|
|
|
// create and add listener
|
|
|
|
nsRetrievalContextWayland *context =
|
|
|
|
static_cast<nsRetrievalContextWayland*>(data);
|
|
|
|
- context->RegisterDataOffer(gtk_primary_offer);
|
|
|
|
+ context->RegisterNewDataOffer(gtk_primary_offer);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
@@ -418,6 +682,18 @@ primary_selection_selection (void
|
|
|
|
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,
|
|
|
|
@@ -430,81 +706,6 @@ nsRetrievalContextWayland::HasSelectionS
|
|
|
|
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();
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
-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,
|
|
|
|
@@ -530,7 +731,6 @@ nsRetrievalContextWayland::InitSeat(wl_r
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
mSeat = (wl_seat*)wl_registry_bind(registry, id, &wl_seat_interface, 1);
|
|
|
|
- wl_seat_add_listener(mSeat, &seat_listener, data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
@@ -573,6 +773,7 @@ nsRetrievalContextWayland::nsRetrievalCo
|
|
|
|
, mActiveOffers(g_hash_table_new(NULL, NULL))
|
|
|
|
, mClipboardOffer(nullptr)
|
|
|
|
, mPrimaryOffer(nullptr)
|
|
|
|
+ , mDragContext(nullptr)
|
|
|
|
, mClipboardRequestNumber(0)
|
|
|
|
, mClipboardData(nullptr)
|
|
|
|
, mClipboardDataLength(0)
|
|
|
|
@@ -616,8 +817,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);
|
|
|
|
}
|
|
|
|
|
|
|
|
@@ -667,12 +881,14 @@ nsRetrievalContextWayland::TransferFastT
|
|
|
|
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!");
|
|
|
|
@@ -727,7 +943,7 @@ nsRetrievalContextWayland::GetClipboardT
|
|
|
|
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,
|
|
|
|
diff -up thunderbird-60.3.0/widget/gtk/nsClipboardWayland.h.wayland thunderbird-60.3.0/widget/gtk/nsClipboardWayland.h
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/nsClipboardWayland.h.wayland 2018-10-30 12:45:34.000000000 +0100
|
2018-11-21 18:35:56 +00:00
|
|
|
+++ thunderbird-60.3.0/widget/gtk/nsClipboardWayland.h 2018-11-21 13:42:00.759025657 +0100
|
2018-11-20 12:38:58 +00:00
|
|
|
@@ -32,6 +32,7 @@ public:
|
|
|
|
private:
|
|
|
|
virtual bool RequestDataTransfer(const char* aMimeType, int fd) = 0;
|
|
|
|
|
|
|
|
+protected:
|
|
|
|
nsTArray<GdkAtom> mTargetMIMETypes;
|
|
|
|
};
|
|
|
|
|
|
|
|
@@ -40,25 +41,66 @@ class WaylandDataOffer : public DataOffe
|
|
|
|
public:
|
|
|
|
WaylandDataOffer(wl_data_offer* aWaylandDataOffer);
|
|
|
|
|
|
|
|
-private:
|
|
|
|
+ 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();
|
|
|
|
+
|
|
|
|
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);
|
|
|
|
+ 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:
|
|
|
|
@@ -74,15 +116,16 @@ 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);
|
|
|
|
|
|
|
|
@@ -103,6 +146,7 @@ private:
|
|
|
|
GHashTable* mActiveOffers;
|
|
|
|
nsAutoPtr<DataOffer> mClipboardOffer;
|
|
|
|
nsAutoPtr<DataOffer> mPrimaryOffer;
|
|
|
|
+ RefPtr<nsWaylandDragContext> mDragContext;
|
|
|
|
|
|
|
|
int mClipboardRequestNumber;
|
|
|
|
char* mClipboardData;
|
|
|
|
diff -up thunderbird-60.3.0/widget/gtk/nsDragService.cpp.wayland thunderbird-60.3.0/widget/gtk/nsDragService.cpp
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/nsDragService.cpp.wayland 2018-10-30 12:45:35.000000000 +0100
|
2018-11-21 18:35:56 +00:00
|
|
|
+++ thunderbird-60.3.0/widget/gtk/nsDragService.cpp 2018-11-21 13:42:00.759025657 +0100
|
2018-11-20 12:38:58 +00:00
|
|
|
@@ -34,7 +34,6 @@
|
|
|
|
#include "nsPresContext.h"
|
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIDocument.h"
|
|
|
|
-#include "nsISelection.h"
|
|
|
|
#include "nsViewManager.h"
|
|
|
|
#include "nsIFrame.h"
|
|
|
|
#include "nsGtkUtils.h"
|
|
|
|
@@ -43,6 +42,9 @@
|
|
|
|
#include "gfxPlatform.h"
|
|
|
|
#include "ScreenHelperGTK.h"
|
|
|
|
#include "nsArrayUtils.h"
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
|
|
+#include "nsClipboardWayland.h"
|
|
|
|
+#endif
|
|
|
|
|
|
|
|
using namespace mozilla;
|
|
|
|
using namespace mozilla::gfx;
|
|
|
|
@@ -99,6 +101,10 @@ invisibleSourceDragDataGet(GtkWidget
|
|
|
|
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.
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -516,6 +522,9 @@ nsDragService::EndDragSession(bool aDone
|
2018-11-20 12:38:58 +00:00
|
|
|
|
|
|
|
// We're done with the drag context.
|
|
|
|
mTargetDragContextForRemote = nullptr;
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
|
|
+ mTargetWaylandDragContextForRemote = nullptr;
|
|
|
|
+#endif
|
|
|
|
|
|
|
|
return nsBaseDragService::EndDragSession(aDoneDrag, aKeyModifiers);
|
|
|
|
}
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -636,6 +645,14 @@ nsDragService::GetNumDropItems(uint32_t
|
2018-11-20 12:38:58 +00:00
|
|
|
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);
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -1027,9 +1044,18 @@ nsDragService::IsDataFlavorSupported(con
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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;
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -1074,6 +1100,15 @@ nsDragService::IsDataFlavorSupported(con
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -1105,6 +1140,36 @@ nsDragService::ReplyToDragMotion(GdkDrag
|
2018-11-20 12:38:58 +00:00
|
|
|
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,
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -1136,6 +1201,12 @@ nsDragService::IsTargetContextList(void)
|
2018-11-20 12:38:58 +00:00
|
|
|
{
|
|
|
|
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
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -1174,17 +1245,28 @@ nsDragService::GetTargetDragData(GdkAtom
|
2018-11-20 12:38:58 +00:00
|
|
|
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"));
|
|
|
|
}
|
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -1435,7 +1517,7 @@ nsDragService::SourceEndDragSession(GdkD
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Schedule the appropriate drag end dom events.
|
|
|
|
- Schedule(eDragTaskSourceEnd, nullptr, nullptr, LayoutDeviceIntPoint(), 0);
|
|
|
|
+ Schedule(eDragTaskSourceEnd, nullptr, nullptr, nullptr, LayoutDeviceIntPoint(), 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -1785,9 +1867,10 @@ invisibleSourceDragEnd(GtkWidget
|
2018-11-20 12:38:58 +00:00
|
|
|
gboolean
|
|
|
|
nsDragService::ScheduleMotionEvent(nsWindow *aWindow,
|
|
|
|
GdkDragContext *aDragContext,
|
|
|
|
+ nsWaylandDragContext *aWaylandDragContext,
|
|
|
|
LayoutDeviceIntPoint aWindowPoint, guint aTime)
|
|
|
|
{
|
|
|
|
- if (mScheduledTask == eDragTaskMotion) {
|
|
|
|
+ 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
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -1798,7 +1881,7 @@ nsDragService::ScheduleMotionEvent(nsWin
|
2018-11-20 12:38:58 +00:00
|
|
|
|
|
|
|
// Returning TRUE means we'll reply with a status message, unless we first
|
|
|
|
// get a leave.
|
|
|
|
- return Schedule(eDragTaskMotion, aWindow, aDragContext,
|
|
|
|
+ return Schedule(eDragTaskMotion, aWindow, aDragContext, aWaylandDragContext,
|
|
|
|
aWindowPoint, aTime);
|
|
|
|
}
|
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -1808,7 +1891,8 @@ nsDragService::ScheduleLeaveEvent()
|
2018-11-20 12:38:58 +00:00
|
|
|
// 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");
|
|
|
|
}
|
|
|
|
}
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -1816,10 +1900,11 @@ nsDragService::ScheduleLeaveEvent()
|
2018-11-20 12:38:58 +00:00
|
|
|
gboolean
|
|
|
|
nsDragService::ScheduleDropEvent(nsWindow *aWindow,
|
|
|
|
GdkDragContext *aDragContext,
|
|
|
|
+ nsWaylandDragContext *aWaylandDragContext,
|
|
|
|
LayoutDeviceIntPoint aWindowPoint, guint aTime)
|
|
|
|
{
|
|
|
|
if (!Schedule(eDragTaskDrop, aWindow,
|
|
|
|
- aDragContext, aWindowPoint, aTime)) {
|
|
|
|
+ aDragContext, aWaylandDragContext, aWindowPoint, aTime)) {
|
|
|
|
NS_WARNING("Additional drag drop ignored");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -1833,6 +1918,7 @@ nsDragService::ScheduleDropEvent(nsWindo
|
2018-11-20 12:38:58 +00:00
|
|
|
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
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -1851,6 +1937,9 @@ nsDragService::Schedule(DragTask aTask,
|
2018-11-20 12:38:58 +00:00
|
|
|
mScheduledTask = aTask;
|
|
|
|
mPendingWindow = aWindow;
|
|
|
|
mPendingDragContext = aDragContext;
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
|
|
+ mPendingWaylandDragContext = aWaylandDragContext;
|
|
|
|
+#endif
|
|
|
|
mPendingWindowPoint = aWindowPoint;
|
|
|
|
mPendingTime = aTime;
|
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -1927,6 +2016,9 @@ nsDragService::RunScheduledTask()
|
2018-11-20 12:38:58 +00:00
|
|
|
// 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
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -1958,10 +2050,20 @@ nsDragService::RunScheduledTask()
|
2018-11-20 12:38:58 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -1972,8 +2074,10 @@ nsDragService::RunScheduledTask()
|
2018-11-20 12:38:58 +00:00
|
|
|
// 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.
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -1986,6 +2090,9 @@ nsDragService::RunScheduledTask()
|
2018-11-20 12:38:58 +00:00
|
|
|
// 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
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -2015,7 +2122,16 @@ nsDragService::UpdateDragAction()
|
2018-11-20 12:38:58 +00:00
|
|
|
|
|
|
|
// 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)
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -2044,6 +2160,12 @@ nsDragService::UpdateDragEffect()
|
2018-11-20 12:38:58 +00:00
|
|
|
ReplyToDragMotion(mTargetDragContextForRemote);
|
|
|
|
mTargetDragContextForRemote = nullptr;
|
|
|
|
}
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
|
|
+ else if (mTargetWaylandDragContextForRemote) {
|
|
|
|
+ ReplyToDragMotion(mTargetWaylandDragContextForRemote);
|
|
|
|
+ mTargetWaylandDragContextForRemote = nullptr;
|
|
|
|
+ }
|
|
|
|
+#endif
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
diff -up thunderbird-60.3.0/widget/gtk/nsDragService.h.wayland thunderbird-60.3.0/widget/gtk/nsDragService.h
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/nsDragService.h.wayland 2018-10-30 12:45:37.000000000 +0100
|
2018-11-21 18:35:56 +00:00
|
|
|
+++ thunderbird-60.3.0/widget/gtk/nsDragService.h 2018-11-21 13:42:00.759025657 +0100
|
2018-11-20 12:38:58 +00:00
|
|
|
@@ -14,6 +14,7 @@
|
|
|
|
#include <gtk/gtk.h>
|
|
|
|
|
|
|
|
class nsWindow;
|
|
|
|
+class nsWaylandDragContext;
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace gfx {
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -98,11 +99,13 @@ public:
|
2018-11-20 12:38:58 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -158,6 +161,9 @@ private:
|
2018-11-20 12:38:58 +00:00
|
|
|
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
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -169,9 +175,15 @@ private:
|
2018-11-20 12:38:58 +00:00
|
|
|
// 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?
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -212,6 +224,7 @@ private:
|
2018-11-20 12:38:58 +00:00
|
|
|
|
|
|
|
gboolean Schedule(DragTask aTask, nsWindow *aWindow,
|
|
|
|
GdkDragContext *aDragContext,
|
|
|
|
+ nsWaylandDragContext* aPendingWaylandDragContext,
|
|
|
|
mozilla::LayoutDeviceIntPoint aWindowPoint, guint aTime);
|
|
|
|
|
|
|
|
// Callback for g_idle_add_full() to run mScheduledTask.
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -220,9 +233,11 @@ private:
|
2018-11-20 12:38:58 +00:00
|
|
|
void UpdateDragAction();
|
|
|
|
void DispatchMotionEvents();
|
|
|
|
void ReplyToDragMotion(GdkDragContext* aDragContext);
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
|
|
+ void ReplyToDragMotion(nsWaylandDragContext* aDragContext);
|
|
|
|
+#endif
|
|
|
|
gboolean DispatchDropEvent();
|
|
|
|
static uint32_t GetCurrentModifiers();
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif // nsDragService_h__
|
|
|
|
-
|
|
|
|
diff -up thunderbird-60.3.0/widget/gtk/nsGtkKeyUtils.cpp.wayland thunderbird-60.3.0/widget/gtk/nsGtkKeyUtils.cpp
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/nsGtkKeyUtils.cpp.wayland 2018-10-30 12:45:34.000000000 +0100
|
2018-11-21 18:35:56 +00:00
|
|
|
+++ thunderbird-60.3.0/widget/gtk/nsGtkKeyUtils.cpp 2018-11-21 13:42:00.760025653 +0100
|
2018-11-20 12:38:58 +00:00
|
|
|
@@ -28,6 +28,10 @@
|
|
|
|
#include "mozilla/MouseEvents.h"
|
|
|
|
#include "mozilla/TextEvents.h"
|
|
|
|
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
|
|
+#include <sys/mman.h>
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
namespace mozilla {
|
|
|
|
namespace widget {
|
|
|
|
|
|
|
|
@@ -195,7 +199,11 @@ KeymapWrapper::Init()
|
|
|
|
memset(mModifierMasks, 0, sizeof(mModifierMasks));
|
|
|
|
|
|
|
|
if (GDK_IS_X11_DISPLAY(gdk_display_get_default()))
|
|
|
|
- InitBySystemSettings();
|
|
|
|
+ InitBySystemSettingsX11();
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
|
|
+ else
|
|
|
|
+ InitBySystemSettingsWayland();
|
|
|
|
+#endif
|
|
|
|
|
|
|
|
gdk_window_add_filter(nullptr, FilterEvents, this);
|
|
|
|
|
|
|
|
@@ -275,10 +283,10 @@ KeymapWrapper::InitXKBExtension()
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
-KeymapWrapper::InitBySystemSettings()
|
|
|
|
+KeymapWrapper::InitBySystemSettingsX11()
|
|
|
|
{
|
|
|
|
MOZ_LOG(gKeymapWrapperLog, LogLevel::Info,
|
|
|
|
- ("%p InitBySystemSettings, mGdkKeymap=%p",
|
|
|
|
+ ("%p InitBySystemSettingsX11, mGdkKeymap=%p",
|
|
|
|
this, mGdkKeymap));
|
|
|
|
|
|
|
|
Display* display =
|
|
|
|
@@ -439,6 +447,208 @@ 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 = wl_seat_get_keyboard(seat);
|
|
|
|
+ wl_keyboard_add_listener(keyboard, &keyboard_listener, nullptr);
|
|
|
|
+ } else if (keyboard && !(caps & WL_SEAT_CAPABILITY_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);
|
|
|
|
+
|
|
|
|
+ // Call wl_display_roundtrip() twice to make sure all
|
|
|
|
+ // callbacks are processed.
|
|
|
|
+ wl_display_roundtrip(display);
|
|
|
|
+ wl_display_roundtrip(display);
|
|
|
|
+}
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
KeymapWrapper::~KeymapWrapper()
|
|
|
|
{
|
|
|
|
gdk_window_remove_filter(nullptr, FilterEvents, this);
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -1405,6 +1615,14 @@ void
|
2018-11-20 12:38:58 +00:00
|
|
|
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.3.0/widget/gtk/nsGtkKeyUtils.h.wayland thunderbird-60.3.0/widget/gtk/nsGtkKeyUtils.h
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/nsGtkKeyUtils.h.wayland 2018-10-30 12:45:34.000000000 +0100
|
2018-11-21 18:35:56 +00:00
|
|
|
+++ thunderbird-60.3.0/widget/gtk/nsGtkKeyUtils.h 2018-11-21 13:42:00.760025653 +0100
|
2018-11-20 12:38:58 +00:00
|
|
|
@@ -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 {
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -131,6 +135,7 @@ public:
|
2018-11-20 12:38:58 +00:00
|
|
|
* @param aKeyEvent It's an WidgetKeyboardEvent which needs to be
|
|
|
|
* initialized.
|
|
|
|
* @param aGdkKeyEvent A native GDK key event.
|
|
|
|
+ * @param aIsProcessedByIME true if aGdkKeyEvent is handled by IME.
|
|
|
|
*/
|
|
|
|
static void InitKeyEvent(WidgetKeyboardEvent& aKeyEvent,
|
2018-11-21 18:35:56 +00:00
|
|
|
GdkEventKey* aGdkKeyEvent);
|
|
|
|
@@ -148,6 +153,14 @@ public:
|
2018-11-20 12:38:58 +00:00
|
|
|
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.
|
|
|
|
*/
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -172,7 +185,10 @@ protected:
|
|
|
|
*/
|
|
|
|
void Init();
|
|
|
|
void InitXKBExtension();
|
|
|
|
- void InitBySystemSettings();
|
|
|
|
+ void InitBySystemSettingsX11();
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
|
|
+ void InitBySystemSettingsWayland();
|
|
|
|
+#endif
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
/**
|
|
|
|
* mModifierKeys stores each hardware key information.
|
|
|
|
@@ -374,6 +390,15 @@ protected:
|
|
|
|
*/
|
|
|
|
void WillDispatchKeyboardEventInternal(WidgetKeyboardEvent& aKeyEvent,
|
|
|
|
GdkEventKey* aGdkKeyEvent);
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+#ifdef MOZ_WAYLAND
|
|
|
|
+ /**
|
|
|
|
+ * Utility function to set Xkb modifier key mask.
|
|
|
|
+ */
|
|
|
|
+ void SetModifierMask(xkb_keymap *aKeymap,
|
|
|
|
+ ModifierIndex aModifierIndex,
|
|
|
|
+ const char* aModifierName);
|
|
|
|
+#endif
|
|
|
|
};
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
} // namespace widget
|
|
|
|
diff -up thunderbird-60.3.0/widget/gtk/nsLookAndFeel.cpp.wayland thunderbird-60.3.0/widget/gtk/nsLookAndFeel.cpp
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/nsLookAndFeel.cpp.wayland 2018-10-30 12:45:35.000000000 +0100
|
|
|
|
+++ thunderbird-60.3.0/widget/gtk/nsLookAndFeel.cpp 2018-11-21 13:42:00.760025653 +0100
|
|
|
|
@@ -31,7 +31,9 @@
|
|
|
|
#include <cairo-gobject.h>
|
|
|
|
#include "WidgetStyleCache.h"
|
|
|
|
#include "prenv.h"
|
|
|
|
+#include "nsCSSColorUtils.h"
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
+using namespace mozilla;
|
|
|
|
using mozilla::LookAndFeel;
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
#define GDK_COLOR_TO_NS_RGB(c) \
|
|
|
|
@@ -182,7 +184,7 @@ GetBorderColors(GtkStyleContext* aContex
|
|
|
|
// 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;
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -213,6 +215,58 @@ GetBorderColors(GtkStyleContext* aContex
|
|
|
|
return ret;
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
+// 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;
|
2018-11-20 12:38:58 +00:00
|
|
|
+ }
|
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ uint16_t hue, sat, luminance;
|
|
|
|
+ uint8_t alpha;
|
|
|
|
+ mMozCellHighlightBackground = mMozFieldBackground;
|
|
|
|
+ mMozCellHighlightText = mMozFieldText;
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ NS_RGB2HSV(mMozCellHighlightBackground, hue, sat, luminance, alpha);
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
+ 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;
|
|
|
|
+}
|
2018-11-20 12:38:58 +00:00
|
|
|
+
|
2018-11-21 18:35:56 +00:00
|
|
|
void
|
|
|
|
nsLookAndFeel::NativeInit()
|
2018-11-20 12:38:58 +00:00
|
|
|
{
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -269,7 +323,6 @@ nsLookAndFeel::NativeGetColor(ColorID aI
|
|
|
|
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;
|
|
|
|
@@ -279,10 +332,15 @@ nsLookAndFeel::NativeGetColor(ColorID aI
|
|
|
|
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;
|
|
|
|
@@ -1009,6 +1067,9 @@ nsLookAndFeel::EnsureInit()
|
|
|
|
mOddCellBackground = GDK_RGBA_TO_NS_RGBA(color);
|
|
|
|
gtk_style_context_restore(style);
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
+ // 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.3.0/widget/gtk/nsLookAndFeel.h.wayland thunderbird-60.3.0/widget/gtk/nsLookAndFeel.h
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/nsLookAndFeel.h.wayland 2018-10-30 12:45:35.000000000 +0100
|
|
|
|
+++ thunderbird-60.3.0/widget/gtk/nsLookAndFeel.h 2018-11-21 13:42:00.760025653 +0100
|
|
|
|
@@ -77,6 +77,8 @@ protected:
|
|
|
|
nscolor mMozWindowActiveBorder;
|
|
|
|
nscolor mMozWindowInactiveBorder;
|
|
|
|
nscolor mMozWindowInactiveCaption;
|
|
|
|
+ nscolor mMozCellHighlightBackground;
|
|
|
|
+ nscolor mMozCellHighlightText;
|
|
|
|
nscolor mTextSelectedText;
|
|
|
|
nscolor mTextSelectedBackground;
|
|
|
|
nscolor mMozScrollbar;
|
|
|
|
@@ -91,6 +93,9 @@ protected:
|
|
|
|
bool mInitialized;
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
void EnsureInit();
|
|
|
|
+
|
|
|
|
+private:
|
|
|
|
+ nsresult InitCellHighlightColors();
|
2018-11-20 12:38:58 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|
|
|
|
diff -up thunderbird-60.3.0/widget/gtk/nsPrintDialogGTK.cpp.wayland thunderbird-60.3.0/widget/gtk/nsPrintDialogGTK.cpp
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/nsPrintDialogGTK.cpp.wayland 2018-10-30 12:45:35.000000000 +0100
|
2018-11-21 18:35:56 +00:00
|
|
|
+++ thunderbird-60.3.0/widget/gtk/nsPrintDialogGTK.cpp 2018-11-21 13:45:42.405091067 +0100
|
2018-11-20 12:38:58 +00:00
|
|
|
@@ -24,7 +24,20 @@
|
|
|
|
#include "nsIBaseWindow.h"
|
|
|
|
#include "nsIDocShellTreeItem.h"
|
|
|
|
#include "nsIDocShell.h"
|
|
|
|
+#include "nsIGIOService.h"
|
|
|
|
#include "WidgetUtils.h"
|
|
|
|
+#include "nsIObserverService.h"
|
|
|
|
+
|
|
|
|
+// for gdk_x11_window_get_xid
|
|
|
|
+#include <gdk/gdkx.h>
|
|
|
|
+#include <sys/types.h>
|
|
|
|
+#include <sys/stat.h>
|
|
|
|
+#include <fcntl.h>
|
|
|
|
+#include <gio/gunixfdlist.h>
|
|
|
|
+
|
|
|
|
+// for dlsym
|
|
|
|
+#include <dlfcn.h>
|
|
|
|
+#include "MainThreadUtils.h"
|
|
|
|
|
|
|
|
using namespace mozilla;
|
|
|
|
using namespace mozilla::widget;
|
|
|
|
@@ -387,7 +400,7 @@ nsPrintDialogWidgetGTK::ExportHeaderFoot
|
|
|
|
nsresult
|
|
|
|
nsPrintDialogWidgetGTK::ImportSettings(nsIPrintSettings *aNSSettings)
|
|
|
|
{
|
|
|
|
- NS_PRECONDITION(aNSSettings, "aSettings must not be null");
|
|
|
|
+ MOZ_ASSERT(aNSSettings, "aSettings must not be null");
|
|
|
|
NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
nsCOMPtr<nsPrintSettingsGTK> aNSSettingsGTK(do_QueryInterface(aNSSettings));
|
|
|
|
@@ -416,7 +429,7 @@ nsPrintDialogWidgetGTK::ImportSettings(n
|
|
|
|
nsresult
|
|
|
|
nsPrintDialogWidgetGTK::ExportSettings(nsIPrintSettings *aNSSettings)
|
|
|
|
{
|
|
|
|
- NS_PRECONDITION(aNSSettings, "aSettings must not be null");
|
|
|
|
+ MOZ_ASSERT(aNSSettings, "aSettings must not be null");
|
|
|
|
NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE);
|
|
|
|
|
|
|
|
GtkPrintSettings* settings = gtk_print_unix_dialog_get_settings(GTK_PRINT_UNIX_DIALOG(dialog));
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -513,13 +526,521 @@ nsPrintDialogServiceGTK::Init()
|
2018-11-20 12:38:58 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
+// Used to obtain window handle. The portal use this handle
|
|
|
|
+// to ensure that print dialog is modal.
|
|
|
|
+typedef void (*WindowHandleExported) (GtkWindow *window,
|
|
|
|
+ const char *handle,
|
|
|
|
+ gpointer user_data);
|
|
|
|
+
|
|
|
|
+typedef void (*GtkWindowHandleExported) (GtkWindow *window,
|
|
|
|
+ const char *handle,
|
|
|
|
+ gpointer user_data);
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
|
|
+typedef struct {
|
|
|
|
+ GtkWindow *window;
|
|
|
|
+ WindowHandleExported callback;
|
|
|
|
+ gpointer user_data;
|
|
|
|
+} WaylandWindowHandleExportedData;
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+wayland_window_handle_exported (GdkWindow *window,
|
|
|
|
+ const char *wayland_handle_str,
|
|
|
|
+ gpointer user_data)
|
|
|
|
+{
|
|
|
|
+ WaylandWindowHandleExportedData *data =
|
|
|
|
+ static_cast<WaylandWindowHandleExportedData*>(user_data);
|
|
|
|
+ char *handle_str;
|
|
|
|
+
|
|
|
|
+ handle_str = g_strdup_printf ("wayland:%s", wayland_handle_str);
|
|
|
|
+ data->callback (data->window, handle_str, data->user_data);
|
|
|
|
+ g_free (handle_str);
|
|
|
|
+}
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+// Get window handle for the portal, taken from gtk/gtkwindow.c
|
|
|
|
+// (currently not exported)
|
|
|
|
+static gboolean
|
|
|
|
+window_export_handle(GtkWindow *window,
|
|
|
|
+ GtkWindowHandleExported callback,
|
|
|
|
+ gpointer user_data)
|
|
|
|
+{
|
|
|
|
+ if (GDK_IS_X11_DISPLAY(gtk_widget_get_display(GTK_WIDGET(window))))
|
|
|
|
+ {
|
|
|
|
+ GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(window));
|
|
|
|
+ char *handle_str;
|
|
|
|
+ guint32 xid = (guint32) gdk_x11_window_get_xid(gdk_window);
|
|
|
|
+
|
|
|
|
+ handle_str = g_strdup_printf("x11:%x", xid);
|
|
|
|
+ callback(window, handle_str, user_data);
|
|
|
|
+ g_free(handle_str);
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(window));
|
|
|
|
+ WaylandWindowHandleExportedData *data;
|
|
|
|
+
|
|
|
|
+ data = g_new0(WaylandWindowHandleExportedData, 1);
|
|
|
|
+ data->window = window;
|
|
|
|
+ data->callback = callback;
|
|
|
|
+ data->user_data = user_data;
|
|
|
|
+
|
|
|
|
+ static auto s_gdk_wayland_window_export_handle =
|
|
|
|
+ reinterpret_cast<gboolean (*)(GdkWindow*, GdkWaylandWindowExported,
|
|
|
|
+ gpointer, GDestroyNotify)>
|
|
|
|
+ (dlsym(RTLD_DEFAULT, "gdk_wayland_window_export_handle"));
|
|
|
|
+ if (!s_gdk_wayland_window_export_handle ||
|
|
|
|
+ !s_gdk_wayland_window_export_handle(gdk_window,
|
|
|
|
+ wayland_window_handle_exported,
|
|
|
|
+ data, g_free)) {
|
|
|
|
+ g_free (data);
|
|
|
|
+ return false;
|
|
|
|
+ } else {
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ g_warning("Couldn't export handle, unsupported windowing system");
|
|
|
|
+
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+/**
|
|
|
|
+ * Communication class with the GTK print portal handler
|
|
|
|
+ *
|
|
|
|
+ * To print document from flatpak we need to use print portal because
|
|
|
|
+ * printers are not directly accessible in the sandboxed environment.
|
|
|
|
+ *
|
|
|
|
+ * At first we request portal to show the print dialog to let user choose
|
|
|
|
+ * printer settings. We use DBUS interface for that (PreparePrint method).
|
|
|
|
+ *
|
|
|
|
+ * Next we force application to print to temporary file and after the writing
|
|
|
|
+ * to the file is finished we pass its file descriptor to the portal.
|
|
|
|
+ * Portal will pass duplicate of the file descriptor to the printer which
|
|
|
|
+ * user selected before (by DBUS Print method).
|
|
|
|
+ *
|
|
|
|
+ * Since DBUS communication is done async while nsPrintDialogServiceGTK::Show
|
|
|
|
+ * is expecting sync execution, we need to create a new GMainLoop during the
|
|
|
|
+ * print portal dialog is running. The loop is stopped after the dialog
|
|
|
|
+ * is closed.
|
|
|
|
+ */
|
|
|
|
+class nsFlatpakPrintPortal: public nsIObserver
|
|
|
|
+{
|
|
|
|
+ NS_DECL_ISUPPORTS
|
|
|
|
+ NS_DECL_NSIOBSERVER
|
|
|
|
+ public:
|
|
|
|
+ explicit nsFlatpakPrintPortal(nsPrintSettingsGTK* aPrintSettings);
|
|
|
|
+ nsresult PreparePrintRequest(GtkWindow* aWindow);
|
|
|
|
+ static void OnWindowExportHandleDone(GtkWindow *aWindow,
|
|
|
|
+ const char* aWindowHandleStr,
|
|
|
|
+ gpointer aUserData);
|
|
|
|
+ void PreparePrint(GtkWindow* aWindow, const char* aWindowHandleStr);
|
|
|
|
+ static void OnPreparePrintResponse(GDBusConnection *connection,
|
|
|
|
+ const char *sender_name,
|
|
|
|
+ const char *object_path,
|
|
|
|
+ const char *interface_name,
|
|
|
|
+ const char *signal_name,
|
|
|
|
+ GVariant *parameters,
|
|
|
|
+ gpointer data);
|
|
|
|
+ GtkPrintOperationResult GetResult();
|
|
|
|
+ private:
|
|
|
|
+ virtual ~nsFlatpakPrintPortal();
|
|
|
|
+ void FinishPrintDialog(GVariant* parameters);
|
|
|
|
+ nsCOMPtr<nsPrintSettingsGTK> mPrintAndPageSettings;
|
|
|
|
+ GDBusProxy* mProxy;
|
|
|
|
+ guint32 mToken;
|
|
|
|
+ GMainLoop* mLoop;
|
|
|
|
+ GtkPrintOperationResult mResult;
|
|
|
|
+ guint mResponseSignalId;
|
|
|
|
+ GtkWindow* mParentWindow;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+NS_IMPL_ISUPPORTS(nsFlatpakPrintPortal, nsIObserver)
|
|
|
|
+
|
|
|
|
+nsFlatpakPrintPortal::nsFlatpakPrintPortal(nsPrintSettingsGTK* aPrintSettings):
|
|
|
|
+ mPrintAndPageSettings(aPrintSettings),
|
|
|
|
+ mProxy(nullptr),
|
|
|
|
+ mLoop(nullptr),
|
|
|
|
+ mResponseSignalId(0),
|
|
|
|
+ mParentWindow(nullptr)
|
|
|
|
+{
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * Creates GDBusProxy, query for window handle and create a new GMainLoop.
|
|
|
|
+ *
|
|
|
|
+ * The GMainLoop is to be run from GetResult() and be quitted during
|
|
|
|
+ * FinishPrintDialog.
|
|
|
|
+ *
|
|
|
|
+ * @param aWindow toplevel application window which is used as parent of print
|
|
|
|
+ * dialog
|
|
|
|
+ */
|
|
|
|
+nsresult
|
|
|
|
+nsFlatpakPrintPortal::PreparePrintRequest(GtkWindow* aWindow)
|
|
|
|
+{
|
|
|
|
+ MOZ_ASSERT(aWindow, "aWindow must not be null");
|
|
|
|
+ MOZ_ASSERT(mPrintAndPageSettings, "mPrintAndPageSettings must not be null");
|
|
|
|
+
|
|
|
|
+ GError* error = nullptr;
|
|
|
|
+ mProxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
|
|
|
+ G_DBUS_PROXY_FLAGS_NONE,
|
|
|
|
+ nullptr,
|
|
|
|
+ "org.freedesktop.portal.Desktop",
|
|
|
|
+ "/org/freedesktop/portal/desktop",
|
|
|
|
+ "org.freedesktop.portal.Print",
|
|
|
|
+ nullptr,
|
|
|
|
+ &error);
|
|
|
|
+ if (mProxy == nullptr) {
|
|
|
|
+ NS_WARNING(nsPrintfCString("Unable to create dbus proxy: %s", error->message).get());
|
|
|
|
+ g_error_free(error);
|
|
|
|
+ return NS_ERROR_FAILURE;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // The window handler is returned async, we will continue by PreparePrint method
|
|
|
|
+ // when it is returned.
|
|
|
|
+ if (!window_export_handle(aWindow,
|
|
|
|
+ &nsFlatpakPrintPortal::OnWindowExportHandleDone, this)) {
|
|
|
|
+ NS_WARNING("Unable to get window handle for creating modal print dialog.");
|
|
|
|
+ return NS_ERROR_FAILURE;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ mLoop = g_main_loop_new (NULL, FALSE);
|
|
|
|
+ return NS_OK;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void
|
|
|
|
+nsFlatpakPrintPortal::OnWindowExportHandleDone(GtkWindow* aWindow,
|
|
|
|
+ const char* aWindowHandleStr,
|
|
|
|
+ gpointer aUserData)
|
|
|
|
+{
|
|
|
|
+ nsFlatpakPrintPortal* printPortal = static_cast<nsFlatpakPrintPortal*>(aUserData);
|
|
|
|
+ printPortal->PreparePrint(aWindow, aWindowHandleStr);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * Ask print portal to show the print dialog.
|
|
|
|
+ *
|
|
|
|
+ * Print and page settings and window handle are passed to the portal to prefill
|
|
|
|
+ * last used settings.
|
|
|
|
+ */
|
|
|
|
+void
|
|
|
|
+nsFlatpakPrintPortal::PreparePrint(GtkWindow* aWindow, const char* aWindowHandleStr)
|
|
|
|
+{
|
|
|
|
+ GtkPrintSettings* gtkSettings = mPrintAndPageSettings->GetGtkPrintSettings();
|
|
|
|
+ GtkPageSetup* pageSetup = mPrintAndPageSettings->GetGtkPageSetup();
|
|
|
|
+
|
|
|
|
+ // We need to remember GtkWindow to unexport window handle after it is
|
|
|
|
+ // no longer needed by the portal dialog (apply only on non-X11 sessions).
|
|
|
|
+ if (!GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
|
|
|
|
+ mParentWindow = aWindow;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ GVariantBuilder opt_builder;
|
|
|
|
+ g_variant_builder_init(&opt_builder, G_VARIANT_TYPE_VARDICT);
|
|
|
|
+ char* token = g_strdup_printf("mozilla%d", g_random_int_range (0, G_MAXINT));
|
|
|
|
+ g_variant_builder_add(&opt_builder, "{sv}", "handle_token",
|
|
|
|
+ g_variant_new_string(token));
|
|
|
|
+ g_free(token);
|
|
|
|
+ GVariant* options = g_variant_builder_end(&opt_builder);
|
|
|
|
+ static auto s_gtk_print_settings_to_gvariant =
|
|
|
|
+ reinterpret_cast<GVariant* (*)(GtkPrintSettings*)>
|
|
|
|
+ (dlsym(RTLD_DEFAULT, "gtk_print_settings_to_gvariant"));
|
|
|
|
+ static auto s_gtk_page_setup_to_gvariant =
|
|
|
|
+ reinterpret_cast<GVariant* (*)(GtkPageSetup *)>
|
|
|
|
+ (dlsym(RTLD_DEFAULT, "gtk_page_setup_to_gvariant"));
|
|
|
|
+ if (!s_gtk_print_settings_to_gvariant || !s_gtk_page_setup_to_gvariant) {
|
|
|
|
+ mResult = GTK_PRINT_OPERATION_RESULT_ERROR;
|
|
|
|
+ FinishPrintDialog(nullptr);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Get translated window title
|
|
|
|
+ nsCOMPtr<nsIStringBundleService> bundleSvc =
|
|
|
|
+ do_GetService(NS_STRINGBUNDLE_CONTRACTID);
|
|
|
|
+ nsCOMPtr<nsIStringBundle> printBundle;
|
|
|
|
+ bundleSvc->CreateBundle("chrome://global/locale/printdialog.properties",
|
|
|
|
+ getter_AddRefs(printBundle));
|
|
|
|
+ nsAutoString intlPrintTitle;
|
|
|
|
+ printBundle->GetStringFromName("printTitleGTK", intlPrintTitle);
|
|
|
|
+
|
|
|
|
+ GError* error = nullptr;
|
|
|
|
+ GVariant *ret = g_dbus_proxy_call_sync(mProxy,
|
|
|
|
+ "PreparePrint",
|
|
|
|
+ g_variant_new ("(ss@a{sv}@a{sv}@a{sv})",
|
|
|
|
+ aWindowHandleStr,
|
|
|
|
+ NS_ConvertUTF16toUTF8(intlPrintTitle).get(), // Title of the window
|
|
|
|
+ s_gtk_print_settings_to_gvariant(gtkSettings),
|
|
|
|
+ s_gtk_page_setup_to_gvariant(pageSetup),
|
|
|
|
+ options),
|
|
|
|
+ G_DBUS_CALL_FLAGS_NONE,
|
|
|
|
+ -1,
|
|
|
|
+ nullptr,
|
|
|
|
+ &error);
|
|
|
|
+ if (ret == nullptr) {
|
|
|
|
+ NS_WARNING(nsPrintfCString("Unable to call dbus proxy: %s", error->message).get());
|
|
|
|
+ g_error_free (error);
|
|
|
|
+ mResult = GTK_PRINT_OPERATION_RESULT_ERROR;
|
|
|
|
+ FinishPrintDialog(nullptr);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ const char* handle = nullptr;
|
|
|
|
+ g_variant_get (ret, "(&o)", &handle);
|
|
|
|
+ if (strcmp (aWindowHandleStr, handle) != 0)
|
|
|
|
+ {
|
|
|
|
+ aWindowHandleStr = g_strdup (handle);
|
|
|
|
+ if (mResponseSignalId) {
|
|
|
|
+ g_dbus_connection_signal_unsubscribe(
|
|
|
|
+ g_dbus_proxy_get_connection(G_DBUS_PROXY(mProxy)), mResponseSignalId);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ mResponseSignalId =
|
|
|
|
+ g_dbus_connection_signal_subscribe(
|
|
|
|
+ g_dbus_proxy_get_connection(G_DBUS_PROXY(mProxy)),
|
|
|
|
+ "org.freedesktop.portal.Desktop",
|
|
|
|
+ "org.freedesktop.portal.Request",
|
|
|
|
+ "Response",
|
|
|
|
+ aWindowHandleStr,
|
|
|
|
+ NULL,
|
|
|
|
+ G_DBUS_SIGNAL_FLAGS_NO_MATCH_RULE,
|
|
|
|
+ &nsFlatpakPrintPortal::OnPreparePrintResponse,
|
|
|
|
+ this, NULL);
|
|
|
|
+
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void
|
|
|
|
+nsFlatpakPrintPortal::OnPreparePrintResponse(GDBusConnection *connection,
|
|
|
|
+ const char *sender_name,
|
|
|
|
+ const char *object_path,
|
|
|
|
+ const char *interface_name,
|
|
|
|
+ const char *signal_name,
|
|
|
|
+ GVariant *parameters,
|
|
|
|
+ gpointer data)
|
|
|
|
+{
|
|
|
|
+ nsFlatpakPrintPortal* printPortal = static_cast<nsFlatpakPrintPortal*>(data);
|
|
|
|
+ printPortal->FinishPrintDialog(parameters);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * When the dialog is accepted, read print and page settings and token.
|
|
|
|
+ *
|
|
|
|
+ * Token is later used for printing portal as print operation identifier.
|
|
|
|
+ * Print and page settings are modified in-place and stored to
|
|
|
|
+ * mPrintAndPageSettings.
|
|
|
|
+ */
|
|
|
|
+void
|
|
|
|
+nsFlatpakPrintPortal::FinishPrintDialog(GVariant* parameters)
|
|
|
|
+{
|
|
|
|
+ // This ends GetResult() method
|
|
|
|
+ if (mLoop) {
|
|
|
|
+ g_main_loop_quit (mLoop);
|
|
|
|
+ mLoop = nullptr;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!parameters) {
|
|
|
|
+ // mResult should be already defined
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ guint32 response;
|
|
|
|
+ GVariant *options;
|
|
|
|
+
|
|
|
|
+ g_variant_get (parameters, "(u@a{sv})", &response, &options);
|
|
|
|
+ mResult = GTK_PRINT_OPERATION_RESULT_CANCEL;
|
|
|
|
+ if (response == 0) {
|
|
|
|
+ GVariant *v;
|
|
|
|
+
|
|
|
|
+ char *filename;
|
|
|
|
+ char *uri;
|
|
|
|
+ v = g_variant_lookup_value (options, "settings", G_VARIANT_TYPE_VARDICT);
|
|
|
|
+ static auto s_gtk_print_settings_new_from_gvariant =
|
|
|
|
+ reinterpret_cast<GtkPrintSettings* (*)(GVariant*)>
|
|
|
|
+ (dlsym(RTLD_DEFAULT, "gtk_print_settings_new_from_gvariant"));
|
|
|
|
+
|
|
|
|
+ GtkPrintSettings* printSettings = s_gtk_print_settings_new_from_gvariant(v);
|
|
|
|
+ g_variant_unref (v);
|
|
|
|
+
|
|
|
|
+ v = g_variant_lookup_value (options, "page-setup", G_VARIANT_TYPE_VARDICT);
|
|
|
|
+ static auto s_gtk_page_setup_new_from_gvariant =
|
|
|
|
+ reinterpret_cast<GtkPageSetup* (*)(GVariant*)>
|
|
|
|
+ (dlsym(RTLD_DEFAULT, "gtk_page_setup_new_from_gvariant"));
|
|
|
|
+ GtkPageSetup* pageSetup = s_gtk_page_setup_new_from_gvariant(v);
|
|
|
|
+ g_variant_unref (v);
|
|
|
|
+
|
|
|
|
+ g_variant_lookup (options, "token", "u", &mToken);
|
|
|
|
+
|
|
|
|
+ // Force printing to file because only filedescriptor of the file
|
|
|
|
+ // can be passed to portal
|
|
|
|
+ int fd = g_file_open_tmp("gtkprintXXXXXX", &filename, NULL);
|
|
|
|
+ uri = g_filename_to_uri(filename, NULL, NULL);
|
|
|
|
+ gtk_print_settings_set(printSettings, GTK_PRINT_SETTINGS_OUTPUT_URI, uri);
|
|
|
|
+ g_free (uri);
|
|
|
|
+ close (fd);
|
|
|
|
+
|
|
|
|
+ // Save native settings in the session object
|
|
|
|
+ mPrintAndPageSettings->SetGtkPrintSettings(printSettings);
|
|
|
|
+ mPrintAndPageSettings->SetGtkPageSetup(pageSetup);
|
|
|
|
+
|
|
|
|
+ // Portal consumes PDF file
|
|
|
|
+ mPrintAndPageSettings->SetOutputFormat(nsIPrintSettings::kOutputFormatPDF);
|
|
|
|
+
|
|
|
|
+ // We need to set to print to file
|
|
|
|
+ mPrintAndPageSettings->SetPrintToFile(true);
|
|
|
|
+
|
|
|
|
+ mResult = GTK_PRINT_OPERATION_RESULT_APPLY;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * Get result of the print dialog.
|
|
|
|
+ *
|
|
|
|
+ * This call blocks until FinishPrintDialog is called.
|
|
|
|
+ *
|
|
|
|
+ */
|
|
|
|
+GtkPrintOperationResult
|
|
|
|
+nsFlatpakPrintPortal::GetResult() {
|
|
|
|
+ // If the mLoop has not been initialized we haven't go thru PreparePrint method
|
|
|
|
+ if (!NS_IsMainThread() || !mLoop) {
|
|
|
|
+ return GTK_PRINT_OPERATION_RESULT_ERROR;
|
|
|
|
+ }
|
|
|
|
+ // Calling g_main_loop_run stops current code until g_main_loop_quit is called
|
|
|
|
+ g_main_loop_run(mLoop);
|
|
|
|
+
|
|
|
|
+ // Free resources we've allocated in order to show print dialog.
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
|
|
+ if (mParentWindow) {
|
|
|
|
+ GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(mParentWindow));
|
|
|
|
+ static auto s_gdk_wayland_window_unexport_handle =
|
|
|
|
+ reinterpret_cast<void (*)(GdkWindow*)>
|
|
|
|
+ (dlsym(RTLD_DEFAULT, "gdk_wayland_window_unexport_handle"));
|
|
|
|
+ if (s_gdk_wayland_window_unexport_handle) {
|
|
|
|
+ s_gdk_wayland_window_unexport_handle(gdk_window);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+#endif
|
|
|
|
+ return mResult;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * Send file descriptor of the file which contains document to the portal to
|
|
|
|
+ * finish the print operation.
|
|
|
|
+ */
|
|
|
|
+NS_IMETHODIMP
|
|
|
|
+nsFlatpakPrintPortal::Observe(nsISupports *aObject, const char * aTopic,
|
|
|
|
+ const char16_t * aData)
|
|
|
|
+{
|
|
|
|
+ // Check that written file match to the stored filename in case multiple
|
|
|
|
+ // print operations are in progress.
|
|
|
|
+ nsAutoString filenameStr;
|
|
|
|
+ mPrintAndPageSettings->GetToFileName(filenameStr);
|
|
|
|
+ if (!nsDependentString(aData).Equals(filenameStr)) {
|
|
|
|
+ // Different file is finished, not for this instance
|
|
|
|
+ return NS_OK;
|
|
|
|
+ }
|
|
|
|
+ int fd, idx;
|
|
|
|
+ fd = open(NS_ConvertUTF16toUTF8(filenameStr).get(), O_RDONLY|O_CLOEXEC);
|
|
|
|
+ static auto s_g_unix_fd_list_new =
|
|
|
|
+ reinterpret_cast<GUnixFDList* (*)(void)>
|
|
|
|
+ (dlsym(RTLD_DEFAULT, "g_unix_fd_list_new"));
|
|
|
|
+ NS_ASSERTION(s_g_unix_fd_list_new, "Cannot find g_unix_fd_list_new function.");
|
|
|
|
+
|
|
|
|
+ GUnixFDList *fd_list = s_g_unix_fd_list_new();
|
|
|
|
+ static auto s_g_unix_fd_list_append =
|
|
|
|
+ reinterpret_cast<gint (*)(GUnixFDList*, gint, GError**)>
|
|
|
|
+ (dlsym(RTLD_DEFAULT, "g_unix_fd_list_append"));
|
|
|
|
+ idx = s_g_unix_fd_list_append(fd_list, fd, NULL);
|
|
|
|
+ close(fd);
|
|
|
|
+
|
|
|
|
+ GVariantBuilder opt_builder;
|
|
|
|
+ g_variant_builder_init(&opt_builder, G_VARIANT_TYPE_VARDICT);
|
|
|
|
+ g_variant_builder_add(&opt_builder, "{sv}", "token",
|
|
|
|
+ g_variant_new_uint32(mToken));
|
|
|
|
+ g_dbus_proxy_call_with_unix_fd_list(
|
|
|
|
+ mProxy,
|
|
|
|
+ "Print",
|
|
|
|
+ g_variant_new("(ssh@a{sv})",
|
|
|
|
+ "", /* window */
|
|
|
|
+ "Print", /* title */
|
|
|
|
+ idx,
|
|
|
|
+ g_variant_builder_end(&opt_builder)),
|
|
|
|
+ G_DBUS_CALL_FLAGS_NONE,
|
|
|
|
+ -1,
|
|
|
|
+ fd_list,
|
|
|
|
+ NULL,
|
|
|
|
+ NULL, // TODO portal result cb function
|
|
|
|
+ nullptr); // data
|
|
|
|
+ g_object_unref(fd_list);
|
|
|
|
+
|
|
|
|
+ nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
|
|
|
+ // Let the nsFlatpakPrintPortal instance die
|
|
|
|
+ os->RemoveObserver(this, "print-to-file-finished");
|
|
|
|
+ return NS_OK;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+nsFlatpakPrintPortal::~nsFlatpakPrintPortal() {
|
|
|
|
+ if (mProxy) {
|
|
|
|
+ if (mResponseSignalId) {
|
|
|
|
+ g_dbus_connection_signal_unsubscribe(
|
|
|
|
+ g_dbus_proxy_get_connection(G_DBUS_PROXY(mProxy)), mResponseSignalId);
|
|
|
|
+ }
|
|
|
|
+ g_object_unref(mProxy);
|
|
|
|
+ }
|
|
|
|
+ if (mLoop)
|
|
|
|
+ g_main_loop_quit(mLoop);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsPrintDialogServiceGTK::Show(nsPIDOMWindowOuter *aParent,
|
|
|
|
nsIPrintSettings *aSettings,
|
|
|
|
nsIWebBrowserPrint *aWebBrowserPrint)
|
|
|
|
{
|
|
|
|
- NS_PRECONDITION(aParent, "aParent must not be null");
|
|
|
|
- NS_PRECONDITION(aSettings, "aSettings must not be null");
|
|
|
|
+ MOZ_ASSERT(aParent, "aParent must not be null");
|
|
|
|
+ MOZ_ASSERT(aSettings, "aSettings must not be null");
|
|
|
|
+
|
|
|
|
+ // Check for the flatpak portal first
|
|
|
|
+ nsCOMPtr<nsIGIOService> giovfs =
|
|
|
|
+ do_GetService(NS_GIOSERVICE_CONTRACTID);
|
2018-11-21 18:35:56 +00:00
|
|
|
+ bool shouldUsePortal = false;
|
2018-11-20 12:38:58 +00:00
|
|
|
+ if (shouldUsePortal && gtk_check_version(3, 22, 0) == nullptr) {
|
|
|
|
+ nsCOMPtr<nsIWidget> widget = WidgetUtils::DOMWindowToWidget(aParent);
|
|
|
|
+ NS_ASSERTION(widget, "Need a widget for dialog to be modal.");
|
|
|
|
+ GtkWindow* gtkParent = get_gtk_window_for_nsiwidget(widget);
|
|
|
|
+ NS_ASSERTION(gtkParent, "Need a GTK window for dialog to be modal.");
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ nsCOMPtr<nsPrintSettingsGTK> printSettingsGTK(do_QueryInterface(aSettings));
|
|
|
|
+ RefPtr<nsFlatpakPrintPortal> fpPrintPortal =
|
|
|
|
+ new nsFlatpakPrintPortal(printSettingsGTK);
|
|
|
|
+
|
|
|
|
+ nsresult rv = fpPrintPortal->PreparePrintRequest(gtkParent);
|
|
|
|
+ NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
+
|
|
|
|
+ // This blocks until nsFlatpakPrintPortal::FinishPrintDialog is called
|
|
|
|
+ GtkPrintOperationResult printDialogResult = fpPrintPortal->GetResult();
|
|
|
|
+
|
|
|
|
+ rv = NS_OK;
|
|
|
|
+ switch (printDialogResult) {
|
|
|
|
+ case GTK_PRINT_OPERATION_RESULT_APPLY:
|
|
|
|
+ {
|
|
|
|
+ nsCOMPtr<nsIObserver> observer = do_QueryInterface(fpPrintPortal);
|
|
|
|
+ nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
|
|
|
+ NS_ENSURE_STATE(os);
|
|
|
|
+ // Observer waits until notified that the file with the content
|
|
|
|
+ // to print has been written.
|
|
|
|
+ rv = os->AddObserver(observer, "print-to-file-finished", false);
|
|
|
|
+ NS_ENSURE_SUCCESS(rv, rv);
|
|
|
|
+ break;
|
|
|
|
+ }
|
2018-11-21 18:35:56 +00:00
|
|
|
+ case GTK_PRINT_OPERATION_RESULT_CANCEL:
|
|
|
|
+ rv = NS_ERROR_ABORT;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ NS_WARNING("Unexpected response");
|
|
|
|
+ rv = NS_ERROR_ABORT;
|
|
|
|
+ }
|
|
|
|
+ return rv;
|
|
|
|
+ }
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
nsPrintDialogWidgetGTK printDialog(aParent, aSettings);
|
|
|
|
nsresult rv = printDialog.ImportSettings(aSettings);
|
|
|
|
@@ -553,8 +1074,8 @@ NS_IMETHODIMP
|
|
|
|
nsPrintDialogServiceGTK::ShowPageSetup(nsPIDOMWindowOuter *aParent,
|
|
|
|
nsIPrintSettings *aNSSettings)
|
|
|
|
{
|
|
|
|
- NS_PRECONDITION(aParent, "aParent must not be null");
|
|
|
|
- NS_PRECONDITION(aNSSettings, "aSettings must not be null");
|
|
|
|
+ MOZ_ASSERT(aParent, "aParent must not be null");
|
|
|
|
+ MOZ_ASSERT(aNSSettings, "aSettings must not be null");
|
|
|
|
NS_ENSURE_TRUE(aNSSettings, NS_ERROR_FAILURE);
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
nsCOMPtr<nsIWidget> widget = WidgetUtils::DOMWindowToWidget(aParent);
|
2018-11-20 12:38:58 +00:00
|
|
|
diff -up thunderbird-60.3.0/widget/gtk/nsWindow.cpp.wayland thunderbird-60.3.0/widget/gtk/nsWindow.cpp
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/nsWindow.cpp.wayland 2018-10-30 12:45:35.000000000 +0100
|
2018-11-21 18:35:56 +00:00
|
|
|
+++ thunderbird-60.3.0/widget/gtk/nsWindow.cpp 2018-11-21 13:42:00.762025644 +0100
|
2018-11-20 12:38:58 +00:00
|
|
|
@@ -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,7 +26,7 @@
|
|
|
|
#include "prlink.h"
|
|
|
|
#include "nsGTKToolkit.h"
|
|
|
|
#include "nsIRollupListener.h"
|
|
|
|
-#include "nsIDOMNode.h"
|
|
|
|
+#include "nsINode.h"
|
|
|
|
|
|
|
|
#include "nsWidgetsCID.h"
|
|
|
|
#include "nsDragService.h"
|
|
|
|
@@ -56,6 +57,7 @@
|
|
|
|
|
|
|
|
#if defined(MOZ_WAYLAND)
|
|
|
|
#include <gdk/gdkwayland.h>
|
|
|
|
+#include "nsView.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "nsGkAtoms.h"
|
|
|
|
@@ -116,6 +118,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 +132,6 @@ using namespace mozilla::widget;
|
|
|
|
#include "nsShmImage.h"
|
|
|
|
#include "gtkdrawing.h"
|
|
|
|
|
|
|
|
-#include "nsIDOMWheelEvent.h"
|
|
|
|
-
|
|
|
|
#include "NativeKeyBindings.h"
|
|
|
|
|
|
|
|
#include <dlfcn.h>
|
|
|
|
@@ -140,6 +141,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
|
|
|
|
@@ -155,7 +157,8 @@ const gint kEvents = GDK_EXPOSURE_MASK |
|
|
|
|
#endif
|
|
|
|
GDK_SCROLL_MASK |
|
|
|
|
GDK_POINTER_MOTION_MASK |
|
|
|
|
- GDK_PROPERTY_CHANGE_MASK;
|
|
|
|
+ GDK_PROPERTY_CHANGE_MASK |
|
|
|
|
+ GDK_FOCUS_CHANGE_MASK;
|
|
|
|
|
|
|
|
/* utility functions */
|
|
|
|
static bool is_mouse_in_window(GdkWindow* aWindow,
|
|
|
|
@@ -210,7 +213,7 @@ static void hierarchy_changed_cb
|
|
|
|
GtkWidget *previous_toplevel);
|
|
|
|
static gboolean window_state_event_cb (GtkWidget *widget,
|
|
|
|
GdkEventWindowState *event);
|
|
|
|
-static void theme_changed_cb (GtkSettings *settings,
|
|
|
|
+static void settings_changed_cb (GtkSettings *settings,
|
|
|
|
GParamSpec *pspec,
|
|
|
|
nsWindow *data);
|
|
|
|
static void check_resize_cb (GtkContainer* container,
|
|
|
|
@@ -481,6 +484,8 @@ nsWindow::nsWindow()
|
|
|
|
mPendingConfigures = 0;
|
|
|
|
mCSDSupportLevel = CSD_SUPPORT_NONE;
|
|
|
|
mDrawInTitlebar = false;
|
|
|
|
+
|
|
|
|
+ mHasAlphaVisual = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsWindow::~nsWindow()
|
|
|
|
@@ -630,7 +635,7 @@ EnsureInvisibleContainer()
|
|
|
|
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.
|
|
|
|
@@ -731,7 +736,7 @@ nsWindow::Destroy()
|
|
|
|
ClearCachedResources();
|
|
|
|
|
|
|
|
g_signal_handlers_disconnect_by_func(gtk_settings_get_default(),
|
|
|
|
- FuncToGpointer(theme_changed_cb),
|
|
|
|
+ FuncToGpointer(settings_changed_cb),
|
|
|
|
this);
|
|
|
|
|
|
|
|
nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -841,8 +846,14 @@ nsWindow::GetDesktopToDeviceScale()
|
2018-11-20 12:38:58 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -886,7 +897,7 @@ nsWindow::WidgetTypeSupportsAcceleration
|
2018-11-20 12:38:58 +00:00
|
|
|
void
|
|
|
|
nsWindow::ReparentNativeWidget(nsIWidget* aNewParent)
|
|
|
|
{
|
|
|
|
- NS_PRECONDITION(aNewParent, "");
|
|
|
|
+ MOZ_ASSERT(aNewParent, "null widget");
|
|
|
|
NS_ASSERTION(!mIsDestroyed, "");
|
|
|
|
NS_ASSERTION(!static_cast<nsWindow*>(aNewParent)->mIsDestroyed, "");
|
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -1517,7 +1528,7 @@ nsWindow::GetClientBounds()
|
2018-11-20 12:38:58 +00:00
|
|
|
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) {
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -2057,6 +2068,12 @@ nsWindow::OnExposeEvent(cairo_t *cr)
|
2018-11-20 12:38:58 +00:00
|
|
|
if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
+#ifdef MOZ_WAYLAND
|
|
|
|
+ // Window does not have visible wl_surface yet.
|
|
|
|
+ if (!mIsX11Display && !GetWaylandSurface())
|
|
|
|
+ return FALSE;
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
nsIWidgetListener *listener = GetListener();
|
|
|
|
if (!listener)
|
|
|
|
return FALSE;
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -3318,6 +3335,33 @@ nsWindow::OnWindowStateEvent(GtkWidget *
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
|
|
|
// 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
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -3404,6 +3448,7 @@ nsWindow::OnDPIChanged()
|
2018-11-20 12:38:58 +00:00
|
|
|
// Update menu's font size etc
|
|
|
|
presShell->ThemeChanged();
|
|
|
|
}
|
|
|
|
+ mWidgetListener->UIResolutionChanged();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -3611,6 +3656,7 @@ nsWindow::Create(nsIWidget* aParent,
|
2018-11-20 12:38:58 +00:00
|
|
|
nsWindow *parentnsWindow = nullptr;
|
|
|
|
GtkWidget *eventWidget = nullptr;
|
|
|
|
bool drawToContainer = false;
|
2018-11-21 18:35:56 +00:00
|
|
|
+ bool useAlphaVisual = false;
|
2018-11-20 12:38:58 +00:00
|
|
|
|
|
|
|
if (aParent) {
|
|
|
|
parentnsWindow = static_cast<nsWindow*>(aParent);
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -3661,8 +3707,8 @@ nsWindow::Create(nsIWidget* aParent,
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
|
|
|
mShell = gtk_window_new(type);
|
|
|
|
|
|
|
|
- bool useAlphaVisual = (mWindowType == eWindowType_popup &&
|
|
|
|
- aInitData->mSupportTranslucency);
|
2018-11-21 18:35:56 +00:00
|
|
|
+ useAlphaVisual = (mWindowType == eWindowType_popup &&
|
|
|
|
+ aInitData->mSupportTranslucency);
|
2018-11-20 12:38:58 +00:00
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
// mozilla.widget.use-argb-visuals is a hidden pref defaulting to false
|
|
|
|
// to allow experimentation
|
|
|
|
@@ -3784,7 +3830,7 @@ nsWindow::Create(nsIWidget* aParent,
|
2018-11-20 12:38:58 +00:00
|
|
|
// it explicitly now.
|
|
|
|
gtk_widget_realize(mShell);
|
|
|
|
|
|
|
|
- /* There are two cases here:
|
|
|
|
+ /* There are several cases here:
|
|
|
|
*
|
|
|
|
* 1) We're running on Gtk+ without client side decorations.
|
|
|
|
* Content is rendered to mShell window and we listen
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -3859,17 +3905,7 @@ nsWindow::Create(nsIWidget* aParent,
|
2018-11-20 12:38:58 +00:00
|
|
|
// If the window were to get unredirected, there could be visible
|
|
|
|
// tearing because Gecko does not align its framebuffer updates with
|
|
|
|
// vblank.
|
|
|
|
- if (mIsX11Display) {
|
|
|
|
- gulong value = 2; // Opt out of unredirection
|
|
|
|
- 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);
|
|
|
|
- }
|
|
|
|
+ SetCompositorHint(GTK_WIDGET_COMPOSIDED_ENABLED);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
break;
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -3949,10 +3985,13 @@ nsWindow::Create(nsIWidget* aParent,
|
2018-11-20 12:38:58 +00:00
|
|
|
GtkSettings* default_settings = gtk_settings_get_default();
|
|
|
|
g_signal_connect_after(default_settings,
|
|
|
|
"notify::gtk-theme-name",
|
|
|
|
- G_CALLBACK(theme_changed_cb), this);
|
|
|
|
+ G_CALLBACK(settings_changed_cb), this);
|
|
|
|
g_signal_connect_after(default_settings,
|
|
|
|
"notify::gtk-font-name",
|
|
|
|
- G_CALLBACK(theme_changed_cb), this);
|
|
|
|
+ G_CALLBACK(settings_changed_cb), this);
|
|
|
|
+ g_signal_connect_after(default_settings,
|
|
|
|
+ "notify::gtk-enable-animations",
|
|
|
|
+ G_CALLBACK(settings_changed_cb), this);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mContainer) {
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -4083,60 +4122,70 @@ nsWindow::Create(nsIWidget* aParent,
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
-nsWindow::SetWindowClass(const nsAString &xulWinType)
|
|
|
|
+nsWindow::RefreshWindowClass(void)
|
|
|
|
{
|
|
|
|
- if (!mShell)
|
|
|
|
- return;
|
|
|
|
+ if (mGtkWindowTypeName.IsEmpty() || mGtkWindowRoleName.IsEmpty())
|
|
|
|
+ return;
|
|
|
|
|
|
|
|
- const char *res_class = gdk_get_program_class();
|
|
|
|
- if (!res_class)
|
|
|
|
- return;
|
|
|
|
+ GdkWindow* gdkWindow = gtk_widget_get_window(mShell);
|
|
|
|
+ gdk_window_set_role(gdkWindow, mGtkWindowRoleName.get());
|
|
|
|
|
|
|
|
- char *res_name = ToNewCString(xulWinType);
|
|
|
|
- if (!res_name)
|
|
|
|
- return;
|
|
|
|
+#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 */
|
|
|
|
+}
|
|
|
|
|
|
|
|
- const char *role = nullptr;
|
|
|
|
+void
|
|
|
|
+nsWindow::SetWindowClass(const nsAString &xulWinType)
|
|
|
|
+{
|
|
|
|
+ if (!mShell)
|
|
|
|
+ return;
|
|
|
|
|
|
|
|
- // Parse res_name into a name and role. Characters other than
|
|
|
|
- // [A-Za-z0-9_-] are converted to '_'. Anything after the first
|
|
|
|
- // colon is assigned to role; if there's no colon, assign the
|
|
|
|
- // whole thing to both role and res_name.
|
|
|
|
- for (char *c = res_name; *c; c++) {
|
|
|
|
- if (':' == *c) {
|
|
|
|
- *c = 0;
|
|
|
|
- role = c + 1;
|
|
|
|
- }
|
|
|
|
- else if (!isascii(*c) || (!isalnum(*c) && ('_' != *c) && ('-' != *c)))
|
|
|
|
- *c = '_';
|
|
|
|
- }
|
|
|
|
- res_name[0] = toupper(res_name[0]);
|
|
|
|
- if (!role) role = res_name;
|
|
|
|
+ char *res_name = ToNewCString(xulWinType);
|
|
|
|
+ if (!res_name)
|
|
|
|
+ return;
|
|
|
|
|
|
|
|
- GdkWindow* gdkWindow = gtk_widget_get_window(mShell);
|
|
|
|
- gdk_window_set_role(gdkWindow, role);
|
|
|
|
+ const char *role = nullptr;
|
|
|
|
|
|
|
|
-#ifdef MOZ_X11
|
|
|
|
- if (mIsX11Display) {
|
|
|
|
- XClassHint *class_hint = XAllocClassHint();
|
|
|
|
- if (!class_hint) {
|
|
|
|
- free(res_name);
|
|
|
|
- return;
|
|
|
|
+ // Parse res_name into a name and role. Characters other than
|
|
|
|
+ // [A-Za-z0-9_-] are converted to '_'. Anything after the first
|
|
|
|
+ // colon is assigned to role; if there's no colon, assign the
|
|
|
|
+ // whole thing to both role and res_name.
|
|
|
|
+ for (char *c = res_name; *c; c++) {
|
|
|
|
+ if (':' == *c) {
|
|
|
|
+ *c = 0;
|
|
|
|
+ role = c + 1;
|
|
|
|
}
|
|
|
|
- class_hint->res_name = res_name;
|
|
|
|
- class_hint->res_class = const_cast<char*>(res_class);
|
|
|
|
+ else if (!isascii(*c) || (!isalnum(*c) && ('_' != *c) && ('-' != *c)))
|
|
|
|
+ *c = '_';
|
|
|
|
+ }
|
|
|
|
+ res_name[0] = toupper(res_name[0]);
|
|
|
|
+ if (!role) role = res_name;
|
|
|
|
|
|
|
|
- // 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);
|
|
|
|
|
|
|
|
- free(res_name);
|
|
|
|
+ RefreshWindowClass();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -4162,6 +4211,8 @@ nsWindow::NativeResize()
|
2018-11-20 12:38:58 +00:00
|
|
|
size.width, size.height));
|
|
|
|
|
|
|
|
if (mIsTopLevel) {
|
|
|
|
+ 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) {
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -4207,6 +4258,8 @@ nsWindow::NativeMoveResize()
|
2018-11-20 12:38:58 +00:00
|
|
|
NativeShow(false);
|
|
|
|
}
|
|
|
|
NativeMove();
|
|
|
|
+
|
|
|
|
+ return;
|
|
|
|
}
|
|
|
|
|
|
|
|
GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mBounds.Size());
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -4219,6 +4272,8 @@ nsWindow::NativeMoveResize()
|
2018-11-20 12:38:58 +00:00
|
|
|
// 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) {
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -4271,6 +4326,16 @@ nsWindow::NativeShow(bool aAction)
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -4946,6 +5011,8 @@ FullscreenTransitionWindow::FullscreenTr
|
2018-11-20 12:38:58 +00:00
|
|
|
gdk_screen_get_monitor_geometry(screen, monitorNum, &monitorRect);
|
|
|
|
gtk_window_set_screen(gtkWin, screen);
|
|
|
|
gtk_window_move(gtkWin, monitorRect.x, monitorRect.y);
|
|
|
|
+ MOZ_ASSERT(monitorRect.width > 0 && monitorRect.height > 0,
|
|
|
|
+ "Can't resize window smaller than 1x1.");
|
|
|
|
gtk_window_resize(gtkWin, monitorRect.width, monitorRect.height);
|
|
|
|
|
|
|
|
GdkColor bgColor;
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -5951,7 +6018,7 @@ window_state_event_cb (GtkWidget *widget
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
-theme_changed_cb (GtkSettings *settings, GParamSpec *pspec, nsWindow *data)
|
|
|
|
+settings_changed_cb (GtkSettings *settings, GParamSpec *pspec, nsWindow *data)
|
|
|
|
{
|
|
|
|
RefPtr<nsWindow> window = data;
|
|
|
|
window->ThemeChanged();
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -6032,13 +6099,13 @@ nsWindow::InitDragEvent(WidgetDragEvent
|
2018-11-20 12:38:58 +00:00
|
|
|
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)
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -6063,15 +6130,24 @@ drag_motion_event_cb(GtkWidget *aWidget,
|
2018-11-20 12:38:58 +00:00
|
|
|
|
|
|
|
RefPtr<nsDragService> dragService = nsDragService::GetInstance();
|
|
|
|
return dragService->
|
|
|
|
- ScheduleMotionEvent(innerMostWindow, aDragContext,
|
|
|
|
+ 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)
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -6104,14 +6180,22 @@ drag_leave_event_cb(GtkWidget *aWidget,
|
2018-11-20 12:38:58 +00:00
|
|
|
dragService->ScheduleLeaveEvent();
|
|
|
|
}
|
|
|
|
|
|
|
|
+static void
|
|
|
|
+drag_leave_event_cb(GtkWidget *aWidget,
|
|
|
|
+ GdkDragContext *aDragContext,
|
|
|
|
+ guint aTime,
|
|
|
|
+ gpointer aData)
|
|
|
|
+{
|
|
|
|
+ WindowDragLeaveHandler(aWidget);
|
|
|
|
+}
|
|
|
|
|
|
|
|
-static gboolean
|
|
|
|
-drag_drop_event_cb(GtkWidget *aWidget,
|
|
|
|
- GdkDragContext *aDragContext,
|
|
|
|
- gint aX,
|
|
|
|
- gint aY,
|
|
|
|
- guint aTime,
|
|
|
|
- gpointer aData)
|
|
|
|
+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)
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -6136,10 +6220,21 @@ drag_drop_event_cb(GtkWidget *aWidget,
|
2018-11-20 12:38:58 +00:00
|
|
|
|
|
|
|
RefPtr<nsDragService> dragService = nsDragService::GetInstance();
|
|
|
|
return dragService->
|
|
|
|
- ScheduleDropEvent(innerMostWindow, aDragContext,
|
|
|
|
+ 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,
|
|
|
|
GdkDragContext *aDragContext,
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -6554,12 +6649,6 @@ nsWindow::GetLayerManager(PLayerTransact
|
2018-11-20 12:38:58 +00:00
|
|
|
return mLayerManager;
|
|
|
|
}
|
|
|
|
|
|
|
|
- if (!mLayerManager && !IsComposited() &&
|
|
|
|
- eTransparencyTransparent == GetTransparencyMode())
|
|
|
|
- {
|
|
|
|
- mLayerManager = CreateBasicLayerManager();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
return nsBaseWidget::GetLayerManager(aShadowManager, aBackendHint, aPersistence);
|
|
|
|
}
|
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -6601,6 +6690,13 @@ nsWindow::ClearCachedResources()
|
2018-11-20 12:38:58 +00:00
|
|
|
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.
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -6692,6 +6788,15 @@ nsWindow::SetDrawsInTitlebar(bool aState
|
2018-11-20 12:38:58 +00:00
|
|
|
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.
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -6998,6 +7103,8 @@ nsWindow::GetSystemCSDSupportLevel() {
|
2018-11-20 12:38:58 +00:00
|
|
|
// 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) {
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -7014,6 +7121,8 @@ nsWindow::GetSystemCSDSupportLevel() {
|
2018-11-20 12:38:58 +00:00
|
|
|
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.
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -7066,26 +7175,18 @@ nsWindow::RoundsWidgetCoordinatesTo()
|
2018-11-20 12:38:58 +00:00
|
|
|
|
|
|
|
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()
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -7110,3 +7211,85 @@ nsWindow::GetWaylandSurface()
|
2018-11-20 12:38:58 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
#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) {
|
|
|
|
+ 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.3.0/widget/gtk/nsWindow.h.wayland thunderbird-60.3.0/widget/gtk/nsWindow.h
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/nsWindow.h.wayland 2018-10-30 12:45:35.000000000 +0100
|
2018-11-21 18:35:56 +00:00
|
|
|
+++ thunderbird-60.3.0/widget/gtk/nsWindow.h 2018-11-21 13:42:00.762025644 +0100
|
2018-11-20 12:38:58 +00:00
|
|
|
@@ -66,6 +66,21 @@ 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 {
|
|
|
|
@@ -78,6 +93,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;
|
|
|
|
|
|
|
|
nsWindow();
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -115,8 +131,7 @@ public:
|
2018-11-20 12:38:58 +00:00
|
|
|
int32_t *aX,
|
|
|
|
int32_t *aY) override;
|
|
|
|
virtual void SetSizeConstraints(const SizeConstraints& aConstraints) override;
|
|
|
|
- virtual void Move(double aX,
|
|
|
|
- double aY) override;
|
|
|
|
+ virtual void Move(double aX, double aY) override;
|
|
|
|
virtual void Show (bool aState) override;
|
|
|
|
virtual void Resize (double aWidth,
|
|
|
|
double aHeight,
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -228,6 +243,8 @@ public:
|
2018-11-20 12:38:58 +00:00
|
|
|
virtual void EndRemoteDrawingInRegion(mozilla::gfx::DrawTarget* aDrawTarget,
|
|
|
|
LayoutDeviceIntRegion& aInvalidRegion) override;
|
|
|
|
|
|
|
|
+ void SetProgress(unsigned long progressPercent);
|
|
|
|
+
|
|
|
|
private:
|
|
|
|
void UpdateAlpha(mozilla::gfx::SourceSurface* aSourceSurface, nsIntRect aBoundsRect);
|
|
|
|
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -452,13 +469,24 @@ private:
|
2018-11-20 12:38:58 +00:00
|
|
|
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;
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -558,6 +586,9 @@ private:
|
2018-11-20 12:38:58 +00:00
|
|
|
// full translucency at this time; each pixel is either fully opaque
|
|
|
|
// or fully transparent.
|
|
|
|
gchar* mTransparencyBitmap;
|
|
|
|
+ // True when we're on compositing window manager and this
|
|
|
|
+ // window is using visual with alpha channel.
|
|
|
|
+ bool mHasAlphaVisual;
|
|
|
|
|
|
|
|
// all of our DND stuff
|
|
|
|
void InitDragEvent(mozilla::WidgetDragEvent& aEvent);
|
|
|
|
diff -up thunderbird-60.3.0/widget/gtk/WindowSurfaceProvider.h.wayland thunderbird-60.3.0/widget/gtk/WindowSurfaceProvider.h
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/WindowSurfaceProvider.h.wayland 2018-10-30 12:45:34.000000000 +0100
|
2018-11-21 18:35:56 +00:00
|
|
|
+++ thunderbird-60.3.0/widget/gtk/WindowSurfaceProvider.h 2018-11-21 13:42:00.762025644 +0100
|
2018-11-20 12:38:58 +00:00
|
|
|
@@ -17,6 +17,7 @@
|
|
|
|
#include <gdk/gdkwayland.h>
|
|
|
|
#endif
|
|
|
|
#include <X11/Xlib.h> // for Window, Display, Visual, etc.
|
|
|
|
+#include "X11UndefineNone.h"
|
|
|
|
|
|
|
|
class nsWindow;
|
|
|
|
|
|
|
|
diff -up thunderbird-60.3.0/widget/gtk/WindowSurfaceWayland.cpp.wayland thunderbird-60.3.0/widget/gtk/WindowSurfaceWayland.cpp
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/WindowSurfaceWayland.cpp.wayland 2018-10-30 12:45:35.000000000 +0100
|
2018-11-21 18:35:56 +00:00
|
|
|
+++ thunderbird-60.3.0/widget/gtk/WindowSurfaceWayland.cpp 2018-11-21 13:42:00.763025640 +0100
|
2018-11-20 12:38:58 +00:00
|
|
|
@@ -151,8 +151,9 @@ static nsWaylandDisplay* WaylandDisplayG
|
|
|
|
static void WaylandDisplayRelease(wl_display *aDisplay);
|
|
|
|
static void WaylandDisplayLoop(wl_display *aDisplay);
|
|
|
|
|
|
|
|
-// TODO: is the 60pfs loop correct?
|
|
|
|
-#define EVENT_LOOP_DELAY (1000/60)
|
|
|
|
+// TODO: Bug 1467125 - We need to integrate wl_display_dispatch_queue_pending() with
|
|
|
|
+// compositor event loop.
|
|
|
|
+#define EVENT_LOOP_DELAY (1000/240)
|
|
|
|
|
|
|
|
// Get WaylandDisplay for given wl_display and actual calling thread.
|
|
|
|
static nsWaylandDisplay*
|
|
|
|
@@ -304,6 +305,7 @@ nsWaylandDisplay::nsWaylandDisplay(wl_di
|
|
|
|
: mThreadId(PR_GetCurrentThread())
|
|
|
|
// gfx::SurfaceFormat::B8G8R8A8 is a basic Wayland format
|
|
|
|
// and is always present.
|
|
|
|
+ // TODO: Provide also format without alpha (Bug 1470126).
|
|
|
|
, mFormat(gfx::SurfaceFormat::B8G8R8A8)
|
|
|
|
, mShm(nullptr)
|
|
|
|
, mDisplay(aDisplay)
|
|
|
|
@@ -522,7 +524,7 @@ WindowBackBuffer::Detach()
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
-WindowBackBuffer::SetImageDataFromBackBuffer(
|
|
|
|
+WindowBackBuffer::SetImageDataFromBuffer(
|
|
|
|
class WindowBackBuffer* aSourceBuffer)
|
|
|
|
{
|
|
|
|
if (!IsMatchingSize(aSourceBuffer)) {
|
|
|
|
@@ -535,11 +537,9 @@ WindowBackBuffer::SetImageDataFromBackBu
|
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<gfx::DrawTarget>
|
|
|
|
-WindowBackBuffer::Lock(const LayoutDeviceIntRegion& aRegion)
|
|
|
|
+WindowBackBuffer::Lock()
|
|
|
|
{
|
|
|
|
- gfx::IntRect bounds = aRegion.GetBounds().ToUnknownRect();
|
|
|
|
- gfx::IntSize lockSize(bounds.XMost(), bounds.YMost());
|
|
|
|
-
|
|
|
|
+ gfx::IntSize lockSize(mWidth, mHeight);
|
|
|
|
return gfxPlatform::CreateDrawTargetForData(static_cast<unsigned char*>(mShmPool.GetImageData()),
|
|
|
|
lockSize,
|
|
|
|
BUFFER_BPP * mWidth,
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -560,26 +560,40 @@ static const struct wl_callback_listener
|
2018-11-20 12:38:58 +00:00
|
|
|
WindowSurfaceWayland::WindowSurfaceWayland(nsWindow *aWindow)
|
|
|
|
: mWindow(aWindow)
|
|
|
|
, mWaylandDisplay(WaylandDisplayGet(aWindow->GetWaylandDisplay()))
|
|
|
|
- , mFrontBuffer(nullptr)
|
|
|
|
- , mBackBuffer(nullptr)
|
|
|
|
+ , mWaylandBuffer(nullptr)
|
|
|
|
+ , mBackupBuffer(nullptr)
|
|
|
|
, mFrameCallback(nullptr)
|
|
|
|
- , mFrameCallbackSurface(nullptr)
|
|
|
|
+ , mLastCommittedSurface(nullptr)
|
|
|
|
, mDisplayThreadMessageLoop(MessageLoop::current())
|
|
|
|
- , mDelayedCommit(false)
|
|
|
|
- , mFullScreenDamage(false)
|
|
|
|
+ , mDelayedCommitHandle(nullptr)
|
|
|
|
+ , mDrawToWaylandBufferDirectly(true)
|
|
|
|
+ , mPendingCommit(false)
|
|
|
|
+ , mWaylandBufferFullScreenDamage(false)
|
|
|
|
, mIsMainThread(NS_IsMainThread())
|
|
|
|
+ , mNeedScaleFactorUpdate(true)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
+ delete mBackupBuffer;
|
|
|
|
+
|
|
|
|
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
|
2018-11-21 18:35:56 +00:00
|
|
|
@@ -593,162 +607,309 @@ WindowSurfaceWayland::~WindowSurfaceWayl
|
2018-11-20 12:38:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
-void
|
|
|
|
-WindowSurfaceWayland::UpdateScaleFactor()
|
|
|
|
-{
|
|
|
|
- wl_surface* waylandSurface = mWindow->GetWaylandSurface();
|
|
|
|
- if (waylandSurface) {
|
|
|
|
- wl_surface_set_buffer_scale(waylandSurface, mWindow->GdkScaleFactor());
|
|
|
|
- }
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
WindowBackBuffer*
|
|
|
|
-WindowSurfaceWayland::GetBufferToDraw(int aWidth, int aHeight)
|
|
|
|
+WindowSurfaceWayland::GetWaylandBufferToDraw(int aWidth, int aHeight)
|
|
|
|
{
|
|
|
|
- if (!mFrontBuffer) {
|
|
|
|
- mFrontBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
|
|
|
|
- mBackBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
|
|
|
|
- return mFrontBuffer;
|
|
|
|
+ if (!mWaylandBuffer) {
|
|
|
|
+ mWaylandBuffer = new WindowBackBuffer(mWaylandDisplay, aWidth, aHeight);
|
|
|
|
+ mBackupBuffer = 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 mFrontBuffer;
|
|
|
|
+ return mWaylandBuffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Front buffer is used by compositor, draw to back buffer
|
|
|
|
- if (mBackBuffer->IsAttached()) {
|
|
|
|
+ if (mBackupBuffer->IsAttached()) {
|
|
|
|
NS_WARNING("No drawing buffer available");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
- MOZ_ASSERT(!mDelayedCommit,
|
|
|
|
+ MOZ_ASSERT(!mPendingCommit,
|
|
|
|
"Uncommitted buffer switch, screen artifacts ahead.");
|
|
|
|
|
|
|
|
- WindowBackBuffer *tmp = mFrontBuffer;
|
|
|
|
- mFrontBuffer = mBackBuffer;
|
|
|
|
- mBackBuffer = tmp;
|
|
|
|
+ WindowBackBuffer *tmp = mWaylandBuffer;
|
|
|
|
+ mWaylandBuffer = mBackupBuffer;
|
|
|
|
+ mBackupBuffer = tmp;
|
|
|
|
|
|
|
|
- if (mBackBuffer->IsMatchingSize(aWidth, aHeight)) {
|
|
|
|
+ if (mBackupBuffer->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(mBackupBuffer);
|
|
|
|
// 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 mWaylandBuffer;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+already_AddRefed<gfx::DrawTarget>
|
|
|
|
+WindowSurfaceWayland::LockWaylandBuffer(int aWidth, int aHeight)
|
|
|
|
+{
|
|
|
|
+ WindowBackBuffer* buffer = GetWaylandBufferToDraw(aWidth, aHeight);
|
|
|
|
+ if (buffer) {
|
|
|
|
+ return buffer->Lock();
|
2018-11-21 18:35:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- return mFrontBuffer;
|
2018-11-20 12:38:58 +00:00
|
|
|
+ NS_WARNING("WindowSurfaceWayland::LockWaylandBuffer(): No buffer available");
|
|
|
|
+ return nullptr;
|
2018-11-21 18:35:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
already_AddRefed<gfx::DrawTarget>
|
2018-11-20 12:38:58 +00:00
|
|
|
+WindowSurfaceWayland::LockImageSurface(const gfx::IntSize& aLockSize)
|
|
|
|
+{
|
|
|
|
+ if (!mImageSurface || mImageSurface->CairoStatus() ||
|
|
|
|
+ !(aLockSize <= mImageSurface->GetSize())) {
|
|
|
|
+ mImageSurface = new gfxImageSurface(aLockSize,
|
|
|
|
+ SurfaceFormatToImageFormat(mWaylandDisplay->GetSurfaceFormat()));
|
|
|
|
+ if (mImageSurface->CairoStatus()) {
|
|
|
|
+ return nullptr;
|
|
|
|
+ }
|
2018-11-21 18:35:56 +00:00
|
|
|
+ }
|
|
|
|
+
|
2018-11-20 12:38:58 +00:00
|
|
|
+ return gfxPlatform::CreateDrawTargetForData(mImageSurface->Data(),
|
|
|
|
+ mImageSurface->GetSize(),
|
|
|
|
+ mImageSurface->Stride(),
|
|
|
|
+ mWaylandDisplay->GetSurfaceFormat());
|
2018-11-21 18:35:56 +00:00
|
|
|
+}
|
|
|
|
+
|
2018-11-20 12:38:58 +00:00
|
|
|
+/*
|
|
|
|
+ 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.
|
|
|
|
+ */
|
2018-11-21 18:35:56 +00:00
|
|
|
+already_AddRefed<gfx::DrawTarget>
|
2018-11-20 12:38:58 +00:00
|
|
|
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);
|
|
|
|
- if (!buffer) {
|
|
|
|
- NS_WARNING("No drawing buffer available");
|
|
|
|
- return nullptr;
|
|
|
|
+ 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);
|
|
|
|
+ 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;
|
2018-11-21 18:35:56 +00:00
|
|
|
+ }
|
|
|
|
+
|
2018-11-20 12:38:58 +00:00
|
|
|
+ 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);
|
|
|
|
+ RefPtr<gfx::SourceSurface> surf =
|
|
|
|
+ gfx::Factory::CreateSourceSurfaceForCairoSurface(mImageSurface->CairoSurface(),
|
|
|
|
+ mImageSurface->GetSize(),
|
|
|
|
+ mImageSurface->Format());
|
|
|
|
+ if (!dt || !surf) {
|
|
|
|
+ return false;
|
2018-11-21 18:35:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
- return buffer->Lock(aRegion);
|
2018-11-20 12:38:58 +00:00
|
|
|
+ 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::Commit(const LayoutDeviceIntRegion& aInvalidRegion)
|
|
|
|
+WindowSurfaceWayland::CommitWaylandBuffer()
|
|
|
|
{
|
|
|
|
- MOZ_ASSERT(mIsMainThread == NS_IsMainThread());
|
|
|
|
+ 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,
|
|
|
|
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()) {
|
|
|
|
+ gint scaleFactor = mWindow->GdkScaleFactor();
|
|
|
|
+ for (auto iter = mWaylandBufferDamage.RectIter(); !iter.Done(); iter.Next()) {
|
|
|
|
const mozilla::LayoutDeviceIntRect &r = iter.Get();
|
|
|
|
- wl_surface_damage(waylandSurface, r.x, r.y, r.width, r.height);
|
|
|
|
+ // 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.3.0/widget/gtk/WindowSurfaceWayland.h.wayland thunderbird-60.3.0/widget/gtk/WindowSurfaceWayland.h
|
|
|
|
--- thunderbird-60.3.0/widget/gtk/WindowSurfaceWayland.h.wayland 2018-10-30 12:45:35.000000000 +0100
|
2018-11-21 18:35:56 +00:00
|
|
|
+++ thunderbird-60.3.0/widget/gtk/WindowSurfaceWayland.h 2018-11-21 13:42:00.763025640 +0100
|
2018-11-20 12:38:58 +00:00
|
|
|
@@ -8,6 +8,7 @@
|
|
|
|
#define _MOZILLA_WIDGET_GTK_WINDOW_SURFACE_WAYLAND_H
|
|
|
|
|
|
|
|
#include <prthread.h>
|
|
|
|
+#include "mozilla/gfx/Types.h"
|
|
|
|
|
|
|
|
namespace mozilla {
|
|
|
|
namespace widget {
|
|
|
|
@@ -66,14 +67,14 @@ public:
|
|
|
|
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; }
|
|
|
|
|
|
|
|
bool Resize(int aWidth, int aHeight);
|
|
|
|
- bool SetImageDataFromBackBuffer(class WindowBackBuffer* aSourceBuffer);
|
|
|
|
+ bool SetImageDataFromBuffer(class WindowBackBuffer* aSourceBuffer);
|
|
|
|
|
|
|
|
bool IsMatchingSize(int aWidth, int aHeight)
|
|
|
|
{
|
|
|
|
@@ -110,22 +111,32 @@ public:
|
|
|
|
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);
|
|
|
|
+ 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;
|
|
|
|
+ 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
|