summaryrefslogtreecommitdiffstats
path: root/widget/gtk/nsWindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'widget/gtk/nsWindow.cpp')
-rw-r--r--widget/gtk/nsWindow.cpp528
1 files changed, 366 insertions, 162 deletions
diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp
index 8185c7bda9..e84044990c 100644
--- a/widget/gtk/nsWindow.cpp
+++ b/widget/gtk/nsWindow.cpp
@@ -100,6 +100,7 @@
#include "ScreenHelperGTK.h"
#include "SystemTimeConverter.h"
#include "WidgetUtilsGtk.h"
+#include "NativeMenuGtk.h"
#ifdef ACCESSIBILITY
# include "mozilla/a11y/LocalAccessible.h"
@@ -182,8 +183,6 @@ static nsWindow* get_window_for_gtk_widget(GtkWidget* widget);
static nsWindow* get_window_for_gdk_window(GdkWindow* window);
static GtkWidget* get_gtk_widget_for_gdk_window(GdkWindow* window);
static GdkCursor* get_gtk_cursor(nsCursor aCursor);
-static GdkWindow* get_inner_gdk_window(GdkWindow* aWindow, gint x, gint y,
- gint* retx, gint* rety);
/* callbacks from widgets */
static gboolean expose_event_cb(GtkWidget* widget, cairo_t* cr);
@@ -404,6 +403,7 @@ nsWindow::nsWindow()
mIsDragPopup(false),
mCompositedScreen(gdk_screen_is_composited(gdk_screen_get_default())),
mIsAccelerated(false),
+ mIsAlert(false),
mWindowShouldStartDragging(false),
mHasMappedToplevel(false),
mRetryPointerGrab(false),
@@ -572,21 +572,6 @@ bool nsWindow::AreBoundsSane() {
return !mLastSizeRequest.IsEmpty();
}
-// Walk the list of child windows and call destroy on them.
-void nsWindow::DestroyChildWindows() {
- LOG("nsWindow::DestroyChildWindows()");
- if (!mGdkWindow) {
- return;
- }
- while (GList* children = gdk_window_peek_children(mGdkWindow)) {
- GdkWindow* child = GDK_WINDOW(children->data);
- nsWindow* kid = get_window_for_gdk_window(child);
- if (kid) {
- kid->Destroy();
- }
- }
-}
-
void nsWindow::Destroy() {
MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread());
@@ -4141,6 +4126,16 @@ void nsWindow::OnUnmap() {
mSourceDragContext = nullptr;
}
}
+
+ // We don't have valid XWindow any more,
+ // so clear stored ones at GtkCompositorWidget() for OMTC rendering
+ // and mSurfaceProvider for legacy rendering.
+ if (GdkIsX11Display()) {
+ mSurfaceProvider.CleanupResources();
+ if (mCompositorWidgetDelegate) {
+ mCompositorWidgetDelegate->DisableRendering();
+ }
+ }
}
void nsWindow::OnSizeAllocate(GtkAllocation* aAllocation) {
@@ -5394,6 +5389,7 @@ void nsWindow::OnDPIChanged() {
}
mWidgetListener->UIResolutionChanged();
}
+ NotifyAPZOfDPIChange();
}
void nsWindow::OnCheckResize() { mPendingConfigures++; }
@@ -5427,6 +5423,8 @@ void nsWindow::OnScaleChanged(bool aNotify) {
return;
}
+ NotifyAPZOfDPIChange();
+
LOG("OnScaleChanged %d, %f -> %d, %f\n", int(mCeiledScaleFactor),
mFractionalScaleFactor, newCeiled, newFractional);
@@ -5816,9 +5814,6 @@ void nsWindow::EnsureGdkWindow() {
if (!mGdkWindow) {
mGdkWindow = gtk_widget_get_window(GTK_WIDGET(mContainer));
g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", this);
- if (mIMContext) {
- mIMContext->SetGdkWindow(mGdkWindow);
- }
}
}
@@ -5871,13 +5866,13 @@ void nsWindow::ConfigureGdkWindow() {
EnsureGdkWindow();
OnScaleChanged(/* aNotify = */ false);
+ if (mIsAlert) {
+ gdk_window_set_override_redirect(mGdkWindow, TRUE);
+ }
+
#ifdef MOZ_X11
if (GdkIsX11Display()) {
- GdkVisual* gdkVisual = gdk_window_get_visual(mGdkWindow);
- Visual* visual = gdk_x11_visual_get_xvisual(gdkVisual);
- int depth = gdk_visual_get_depth(gdkVisual);
- mSurfaceProvider.Initialize(GetX11Window(), visual, depth,
- GetShapedState());
+ mSurfaceProvider.Initialize(GetX11Window(), GetShapedState());
// Set window manager hint to keep fullscreen windows composited.
//
@@ -6019,6 +6014,7 @@ nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
// and can be changed so we use WaylandPopupIsPermanent() to get
// recent popup config (Bug 1728952).
mNoAutoHide = aInitData && aInitData->mNoAutoHide;
+ mIsAlert = aInitData && aInitData->mIsAlert;
// Popups that are not noautohide are only temporary. The are used
// for menus and the like and disappear when another window is used.
@@ -6108,10 +6104,11 @@ nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
if (mIsPIPWindow) {
LOG(" Is PIP window\n");
gtk_window_set_type_hint(GTK_WINDOW(mShell), GDK_WINDOW_TYPE_HINT_UTILITY);
- } else if (aInitData && aInitData->mIsAlert) {
+ } else if (mIsAlert) {
LOG(" Is alert window\n");
gtk_window_set_type_hint(GTK_WINDOW(mShell),
GDK_WINDOW_TYPE_HINT_NOTIFICATION);
+ gtk_window_set_skip_taskbar_hint(GTK_WINDOW(mShell), TRUE);
} else if (mWindowType == WindowType::Dialog) {
mGtkWindowRoleName = "Dialog";
@@ -6706,10 +6703,6 @@ void nsWindow::ResumeCompositorImpl() {
LOG("nsWindow::ResumeCompositorImpl()\n");
MOZ_DIAGNOSTIC_ASSERT(mCompositorWidgetDelegate);
-
- // DisableRendering() clears stored X11Window so we're sure EnableRendering()
- // really updates it.
- mCompositorWidgetDelegate->DisableRendering();
mCompositorWidgetDelegate->EnableRendering(GetX11Window(), GetShapedState());
// As WaylandStartVsync needs mCompositorWidgetDelegate this is the right
@@ -6988,6 +6981,13 @@ void nsWindow::UpdateWindowDraggingRegion(
}
}
+#ifdef MOZ_ENABLE_DBUS
+void nsWindow::SetDBusMenuBar(
+ RefPtr<mozilla::widget::DBusMenuBar> aDbusMenuBar) {
+ mDBusMenuBar = std::move(aDbusMenuBar);
+}
+#endif
+
LayoutDeviceIntCoord nsWindow::GetTitlebarRadius() {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
int32_t cssCoord = LookAndFeel::GetInt(LookAndFeel::IntID::TitlebarRadius);
@@ -7839,14 +7839,246 @@ static GtkWidget* get_gtk_widget_for_gdk_window(GdkWindow* window) {
return GTK_WIDGET(user_data);
}
-static GdkCursor* get_gtk_cursor(nsCursor aCursor) {
+static GdkCursor* get_gtk_cursor_from_type(uint8_t aCursorType) {
+ GdkDisplay* defaultDisplay = gdk_display_get_default();
GdkCursor* gdkcursor = nullptr;
- uint8_t newType = 0xff;
- if ((gdkcursor = gCursorCache[aCursor])) {
- return gdkcursor;
+ // GtkCursors are defined at nsGtkCursors.h
+ if (aCursorType > MOZ_CURSOR_NONE) {
+ return nullptr;
}
+ // If by now we don't have a xcursor, this means we have to make a custom
+ // one. First, we try creating a named cursor based on the hash of our
+ // custom bitmap, as libXcursor has some magic to convert bitmapped cursors
+ // to themed cursors
+ if (GtkCursors[aCursorType].hash) {
+ gdkcursor =
+ gdk_cursor_new_from_name(defaultDisplay, GtkCursors[aCursorType].hash);
+ if (gdkcursor) {
+ return gdkcursor;
+ }
+ }
+
+ LOGW("get_gtk_cursor_from_type(): Failed to get cursor type %d, try bitmap",
+ aCursorType);
+
+ // If we still don't have a xcursor, we now really create a bitmap cursor
+ GdkPixbuf* cursor_pixbuf =
+ gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 32, 32);
+ if (!cursor_pixbuf) {
+ return nullptr;
+ }
+
+ guchar* data = gdk_pixbuf_get_pixels(cursor_pixbuf);
+
+ // Read data from GtkCursors and compose RGBA surface from 1bit bitmap and
+ // mask GtkCursors bits and mask are 32x32 monochrome bitmaps (1 bit for
+ // each pixel) so it's 128 byte array (4 bytes for are one bitmap row and
+ // there are 32 rows here).
+ const unsigned char* bits = GtkCursors[aCursorType].bits;
+ const unsigned char* mask_bits = GtkCursors[aCursorType].mask_bits;
+
+ for (int i = 0; i < 128; i++) {
+ char bit = (char)*bits++;
+ char mask = (char)*mask_bits++;
+ for (int j = 0; j < 8; j++) {
+ unsigned char pix = ~(((bit >> j) & 0x01) * 0xff);
+ *data++ = pix;
+ *data++ = pix;
+ *data++ = pix;
+ *data++ = (((mask >> j) & 0x01) * 0xff);
+ }
+ }
+
+ gdkcursor = gdk_cursor_new_from_pixbuf(
+ gdk_display_get_default(), cursor_pixbuf, GtkCursors[aCursorType].hot_x,
+ GtkCursors[aCursorType].hot_y);
+
+ g_object_unref(cursor_pixbuf);
+ return gdkcursor;
+}
+
+static GdkCursor* get_gtk_cursor_legacy(nsCursor aCursor) {
+ GdkCursor* gdkcursor = nullptr;
+ Maybe<uint8_t> fallbackType;
+
+ GdkDisplay* defaultDisplay = gdk_display_get_default();
+
+ // The strategy here is to use standard GDK cursors, and, if not available,
+ // load by standard name with gdk_cursor_new_from_name.
+ // Spec is here: http://www.freedesktop.org/wiki/Specifications/cursor-spec/
+ switch (aCursor) {
+ case eCursor_standard:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_LEFT_PTR);
+ break;
+ case eCursor_wait:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_WATCH);
+ break;
+ case eCursor_select:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_XTERM);
+ break;
+ case eCursor_hyperlink:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_HAND2);
+ break;
+ case eCursor_n_resize:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_TOP_SIDE);
+ break;
+ case eCursor_s_resize:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_BOTTOM_SIDE);
+ break;
+ case eCursor_w_resize:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_LEFT_SIDE);
+ break;
+ case eCursor_e_resize:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_RIGHT_SIDE);
+ break;
+ case eCursor_nw_resize:
+ gdkcursor =
+ gdk_cursor_new_for_display(defaultDisplay, GDK_TOP_LEFT_CORNER);
+ break;
+ case eCursor_se_resize:
+ gdkcursor =
+ gdk_cursor_new_for_display(defaultDisplay, GDK_BOTTOM_RIGHT_CORNER);
+ break;
+ case eCursor_ne_resize:
+ gdkcursor =
+ gdk_cursor_new_for_display(defaultDisplay, GDK_TOP_RIGHT_CORNER);
+ break;
+ case eCursor_sw_resize:
+ gdkcursor =
+ gdk_cursor_new_for_display(defaultDisplay, GDK_BOTTOM_LEFT_CORNER);
+ break;
+ case eCursor_crosshair:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_CROSSHAIR);
+ break;
+ case eCursor_move:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_FLEUR);
+ break;
+ case eCursor_help:
+ gdkcursor =
+ gdk_cursor_new_for_display(defaultDisplay, GDK_QUESTION_ARROW);
+ break;
+ case eCursor_copy: // CSS3
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "copy");
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_COPY);
+ break;
+ case eCursor_alias:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "alias");
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ALIAS);
+ break;
+ case eCursor_context_menu:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "context-menu");
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_CONTEXT_MENU);
+ break;
+ case eCursor_cell:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_PLUS);
+ break;
+ // Those two aren’t standardized. Trying both KDE’s and GNOME’s names
+ case eCursor_grab:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "openhand");
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_HAND_GRAB);
+ break;
+ case eCursor_grabbing:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "closedhand");
+ if (!gdkcursor) {
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "grabbing");
+ }
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_HAND_GRABBING);
+ break;
+ case eCursor_spinning:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "progress");
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_SPINNING);
+ break;
+ case eCursor_zoom_in:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "zoom-in");
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ZOOM_IN);
+ break;
+ case eCursor_zoom_out:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "zoom-out");
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ZOOM_OUT);
+ break;
+ case eCursor_not_allowed:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "not-allowed");
+ if (!gdkcursor) { // nonstandard, yet common
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "crossed_circle");
+ }
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NOT_ALLOWED);
+ break;
+ case eCursor_no_drop:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "no-drop");
+ if (!gdkcursor) { // this nonstandard sequence makes it work on KDE and
+ // GNOME
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "forbidden");
+ }
+ if (!gdkcursor) {
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "circle");
+ }
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NOT_ALLOWED);
+ break;
+ case eCursor_vertical_text:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "vertical-text");
+ if (!gdkcursor) {
+ fallbackType.emplace(MOZ_CURSOR_VERTICAL_TEXT);
+ }
+ break;
+ case eCursor_all_scroll:
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_FLEUR);
+ break;
+ case eCursor_nesw_resize:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "size_bdiag");
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NESW_RESIZE);
+ break;
+ case eCursor_nwse_resize:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "size_fdiag");
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NWSE_RESIZE);
+ break;
+ case eCursor_ns_resize:
+ gdkcursor =
+ gdk_cursor_new_for_display(defaultDisplay, GDK_SB_V_DOUBLE_ARROW);
+ break;
+ case eCursor_ew_resize:
+ gdkcursor =
+ gdk_cursor_new_for_display(defaultDisplay, GDK_SB_H_DOUBLE_ARROW);
+ break;
+ // Here, two better fitting cursors exist in some cursor themes. Try those
+ // first
+ case eCursor_row_resize:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "split_v");
+ if (!gdkcursor) {
+ gdkcursor =
+ gdk_cursor_new_for_display(defaultDisplay, GDK_SB_V_DOUBLE_ARROW);
+ }
+ break;
+ case eCursor_col_resize:
+ gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "split_h");
+ if (!gdkcursor) {
+ gdkcursor =
+ gdk_cursor_new_for_display(defaultDisplay, GDK_SB_H_DOUBLE_ARROW);
+ }
+ break;
+ case eCursor_none:
+ fallbackType.emplace(MOZ_CURSOR_NONE);
+ break;
+ default:
+ NS_ASSERTION(aCursor, "Invalid cursor type");
+ gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_LEFT_PTR);
+ break;
+ }
+
+ if (!gdkcursor && fallbackType.isSome()) {
+ LOGW("get_gtk_cursor_legacy(): Failed to get cursor %d, try fallback",
+ aCursor);
+ gdkcursor = get_gtk_cursor_from_type(*fallbackType);
+ }
+
+ return gdkcursor;
+}
+
+static GdkCursor* get_gtk_cursor_from_name(nsCursor aCursor) {
+ GdkCursor* gdkcursor = nullptr;
+ Maybe<uint8_t> fallbackType;
+
GdkDisplay* defaultDisplay = gdk_display_get_default();
switch (aCursor) {
@@ -7897,42 +8129,42 @@ static GdkCursor* get_gtk_cursor(nsCursor aCursor) {
break;
case eCursor_copy:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "copy");
- if (!gdkcursor) newType = MOZ_CURSOR_COPY;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_COPY);
break;
case eCursor_alias:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "alias");
- if (!gdkcursor) newType = MOZ_CURSOR_ALIAS;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ALIAS);
break;
case eCursor_context_menu:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "context-menu");
- if (!gdkcursor) newType = MOZ_CURSOR_CONTEXT_MENU;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_CONTEXT_MENU);
break;
case eCursor_cell:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "cell");
break;
case eCursor_grab:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "grab");
- if (!gdkcursor) newType = MOZ_CURSOR_HAND_GRAB;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_HAND_GRAB);
break;
case eCursor_grabbing:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "grabbing");
- if (!gdkcursor) newType = MOZ_CURSOR_HAND_GRABBING;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_HAND_GRABBING);
break;
case eCursor_spinning:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "progress");
- if (!gdkcursor) newType = MOZ_CURSOR_SPINNING;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_SPINNING);
break;
case eCursor_zoom_in:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "zoom-in");
- if (!gdkcursor) newType = MOZ_CURSOR_ZOOM_IN;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ZOOM_IN);
break;
case eCursor_zoom_out:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "zoom-out");
- if (!gdkcursor) newType = MOZ_CURSOR_ZOOM_OUT;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ZOOM_OUT);
break;
case eCursor_not_allowed:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "not-allowed");
- if (!gdkcursor) newType = MOZ_CURSOR_NOT_ALLOWED;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NOT_ALLOWED);
break;
case eCursor_no_drop:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "no-drop");
@@ -7943,12 +8175,12 @@ static GdkCursor* get_gtk_cursor(nsCursor aCursor) {
if (!gdkcursor) {
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "circle");
}
- if (!gdkcursor) newType = MOZ_CURSOR_NOT_ALLOWED;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NOT_ALLOWED);
break;
case eCursor_vertical_text:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "vertical-text");
if (!gdkcursor) {
- newType = MOZ_CURSOR_VERTICAL_TEXT;
+ fallbackType.emplace(MOZ_CURSOR_VERTICAL_TEXT);
}
break;
case eCursor_all_scroll:
@@ -7956,11 +8188,11 @@ static GdkCursor* get_gtk_cursor(nsCursor aCursor) {
break;
case eCursor_nesw_resize:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "nesw-resize");
- if (!gdkcursor) newType = MOZ_CURSOR_NESW_RESIZE;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NESW_RESIZE);
break;
case eCursor_nwse_resize:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "nwse-resize");
- if (!gdkcursor) newType = MOZ_CURSOR_NWSE_RESIZE;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NWSE_RESIZE);
break;
case eCursor_ns_resize:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "ns-resize");
@@ -7976,7 +8208,7 @@ static GdkCursor* get_gtk_cursor(nsCursor aCursor) {
break;
case eCursor_none:
gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "none");
- if (!gdkcursor) newType = MOZ_CURSOR_NONE;
+ if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NONE);
break;
default:
NS_ASSERTION(aCursor, "Invalid cursor type");
@@ -7984,51 +8216,26 @@ static GdkCursor* get_gtk_cursor(nsCursor aCursor) {
break;
}
- // If by now we don't have a xcursor, this means we have to make a custom
- // one. First, we try creating a named cursor based on the hash of our
- // custom bitmap, as libXcursor has some magic to convert bitmapped cursors
- // to themed cursors
- if (newType != 0xFF && GtkCursors[newType].hash) {
- gdkcursor =
- gdk_cursor_new_from_name(defaultDisplay, GtkCursors[newType].hash);
+ if (!gdkcursor && fallbackType.isSome()) {
+ LOGW("get_gtk_cursor_from_name(): Failed to get cursor %d, try fallback",
+ aCursor);
+ gdkcursor = get_gtk_cursor_from_type(*fallbackType);
}
- // If we still don't have a xcursor, we now really create a bitmap cursor
- if (newType != 0xff && !gdkcursor) {
- GdkPixbuf* cursor_pixbuf =
- gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 32, 32);
- if (!cursor_pixbuf) {
- return nullptr;
- }
-
- guchar* data = gdk_pixbuf_get_pixels(cursor_pixbuf);
-
- // Read data from GtkCursors and compose RGBA surface from 1bit bitmap and
- // mask GtkCursors bits and mask are 32x32 monochrome bitmaps (1 bit for
- // each pixel) so it's 128 byte array (4 bytes for are one bitmap row and
- // there are 32 rows here).
- const unsigned char* bits = GtkCursors[newType].bits;
- const unsigned char* mask_bits = GtkCursors[newType].mask_bits;
-
- for (int i = 0; i < 128; i++) {
- char bit = (char)*bits++;
- char mask = (char)*mask_bits++;
- for (int j = 0; j < 8; j++) {
- unsigned char pix = ~(((bit >> j) & 0x01) * 0xff);
- *data++ = pix;
- *data++ = pix;
- *data++ = pix;
- *data++ = (((mask >> j) & 0x01) * 0xff);
- }
- }
+ return gdkcursor;
+}
- gdkcursor = gdk_cursor_new_from_pixbuf(
- gdk_display_get_default(), cursor_pixbuf, GtkCursors[newType].hot_x,
- GtkCursors[newType].hot_y);
+static GdkCursor* get_gtk_cursor(nsCursor aCursor) {
+ GdkCursor* gdkcursor = nullptr;
- g_object_unref(cursor_pixbuf);
+ if ((gdkcursor = gCursorCache[aCursor])) {
+ return gdkcursor;
}
+ gdkcursor = StaticPrefs::widget_gtk_legacy_cursors_enabled()
+ ? get_gtk_cursor_legacy(aCursor)
+ : get_gtk_cursor_from_name(aCursor);
+
gCursorCache[aCursor] = gdkcursor;
return gdkcursor;
@@ -8214,6 +8421,10 @@ static gboolean button_press_event_cb(GtkWidget* widget,
GdkEventButton* event) {
UpdateLastInputEventTime(event);
+ if (event->button == 2 && !StaticPrefs::widget_gtk_middle_click_enabled()) {
+ return FALSE;
+ }
+
RefPtr<nsWindow> window = GetFirstNSWindowForGDKWindow(event->window);
if (!window) {
return FALSE;
@@ -8232,6 +8443,10 @@ static gboolean button_release_event_cb(GtkWidget* widget,
GdkEventButton* event) {
UpdateLastInputEventTime(event);
+ if (event->button == 2 && !StaticPrefs::widget_gtk_middle_click_enabled()) {
+ return FALSE;
+ }
+
RefPtr<nsWindow> window = GetFirstNSWindowForGDKWindow(event->window);
if (!window) {
return FALSE;
@@ -8579,28 +8794,26 @@ gboolean WindowDragMotionHandler(GtkWidget* aWidget,
GdkDragContext* aDragContext, gint aX, gint aY,
guint aTime) {
RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
- if (!window) {
+ if (!window || !window->GetGdkWindow()) {
return FALSE;
}
- // figure out which internal widget this drag motion actually happened on
- nscoord retx = 0;
- nscoord rety = 0;
-
- GdkWindow* innerWindow = get_inner_gdk_window(gtk_widget_get_window(aWidget),
- aX, aY, &retx, &rety);
- RefPtr<nsWindow> innerMostWindow = get_window_for_gdk_window(innerWindow);
- if (!innerMostWindow) {
- innerMostWindow = window;
+ // We're getting aX,aY in mShell coordinates space.
+ // mContainer is shifted by CSD decorations so translate the coords
+ // to mContainer space where our content lives.
+ if (aWidget == window->GetGtkWidget()) {
+ int x, y;
+ gdk_window_get_geometry(window->GetGdkWindow(), &x, &y, nullptr, nullptr);
+ aX -= x;
+ aY -= y;
}
- LOGDRAG("WindowDragMotionHandler target nsWindow [%p]",
- innerMostWindow.get());
+
+ LOGDRAG("WindowDragMotionHandler target nsWindow [%p]", window.get());
RefPtr<nsDragService> dragService = nsDragService::GetInstance();
nsDragService::AutoEventLoop loop(dragService);
if (!dragService->ScheduleMotionEvent(
- innerMostWindow, aDragContext,
- GetWindowDropPosition(innerMostWindow, retx, rety), aTime)) {
+ window, aDragContext, GetWindowDropPosition(window, aX, aY), aTime)) {
return FALSE;
}
return TRUE;
@@ -8656,28 +8869,25 @@ static void drag_leave_event_cb(GtkWidget* aWidget,
gboolean WindowDragDropHandler(GtkWidget* aWidget, GdkDragContext* aDragContext,
gint aX, gint aY, guint aTime) {
RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
- if (!window) {
+ if (!window || !window->GetGdkWindow()) {
return FALSE;
}
- // figure out which internal widget this drag motion actually happened on
- nscoord retx = 0;
- nscoord rety = 0;
-
- GdkWindow* innerWindow = get_inner_gdk_window(gtk_widget_get_window(aWidget),
- aX, aY, &retx, &rety);
- RefPtr<nsWindow> innerMostWindow = get_window_for_gdk_window(innerWindow);
-
- if (!innerMostWindow) {
- innerMostWindow = window;
+ // We're getting aX,aY in mShell coordinates space.
+ // mContainer is shifted by CSD decorations so translate the coords
+ // to mContainer space where our content lives.
+ if (aWidget == window->GetGtkWidget()) {
+ int x, y;
+ gdk_window_get_geometry(window->GetGdkWindow(), &x, &y, nullptr, nullptr);
+ aX -= x;
+ aY -= y;
}
- LOGDRAG("WindowDragDropHandler nsWindow [%p]", innerMostWindow.get());
+ LOGDRAG("WindowDragDropHandler nsWindow [%p]", window.get());
RefPtr<nsDragService> dragService = nsDragService::GetInstance();
nsDragService::AutoEventLoop loop(dragService);
return dragService->ScheduleDropEvent(
- innerMostWindow, aDragContext,
- GetWindowDropPosition(innerMostWindow, retx, rety), aTime);
+ window, aDragContext, GetWindowDropPosition(window, aX, aY), aTime);
}
static gboolean drag_drop_event_cb(GtkWidget* aWidget,
@@ -8710,27 +8920,6 @@ static nsresult initialize_prefs(void) {
return NS_OK;
}
-// TODO: Can we simplify it for mShell/mContainer only scenario?
-static GdkWindow* get_inner_gdk_window(GdkWindow* aWindow, gint x, gint y,
- gint* retx, gint* rety) {
- gint cx, cy, cw, ch;
- GList* children = gdk_window_peek_children(aWindow);
- for (GList* child = g_list_last(children); child;
- child = g_list_previous(child)) {
- auto* childWindow = (GdkWindow*)child->data;
- if (get_window_for_gdk_window(childWindow)) {
- gdk_window_get_geometry(childWindow, &cx, &cy, &cw, &ch);
- if ((cx < x) && (x < (cx + cw)) && (cy < y) && (y < (cy + ch)) &&
- gdk_window_is_visible(childWindow)) {
- return get_inner_gdk_window(childWindow, x - cx, y - cy, retx, rety);
- }
- }
- }
- *retx = x;
- *rety = y;
- return aWindow;
-}
-
#ifdef ACCESSIBILITY
void nsWindow::CreateRootAccessible() {
if (!mRootAccessible) {
@@ -9548,8 +9737,19 @@ void nsWindow::GetCompositorWidgetInitData(
LOG("nsWindow::GetCompositorWidgetInitData");
+ Window window = GetX11Window();
+#ifdef MOZ_X11
+ // We're bit hackish here. Old GLX backend needs XWindow when GLContext
+ // is created so get XWindow now before map signal.
+ // We may see crashes/errors when nsWindow is unmapped (XWindow is
+ // invalidated) but we can't do anything about it.
+ if (!window && !gfxVars::UseEGL()) {
+ window =
+ gdk_x11_window_get_xid(gtk_widget_get_window(GTK_WIDGET(mContainer)));
+ }
+#endif
*aInitData = mozilla::widget::GtkCompositorWidgetInitData(
- GetX11Window(), displayName, GetShapedState(), GdkIsX11Display(),
+ window, displayName, GetShapedState(), GdkIsX11Display(),
GetClientSize());
#ifdef MOZ_X11
@@ -9927,38 +10127,42 @@ void nsWindow::DisableRendering() {
LOG("nsWindow::DisableRendering()");
if (mGdkWindow) {
- if (mIMContext) {
- mIMContext->SetGdkWindow(nullptr);
- }
g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", nullptr);
mGdkWindow = nullptr;
}
+ // Until Bug 1654938 is fixed we delete layer manager for hidden popups,
+ // otherwise it can easily hold 1GB+ memory for long time.
+ if (mWindowType == WindowType::Popup) {
+ DestroyLayerManager();
+ mSurfaceProvider.CleanupResources();
+ } else {
#ifdef MOZ_WAYLAND
- // Widget is backed by OpenGL EGLSurface created over wl_surface
- // owned by mContainer.
- // RenderCompositorEGL::Resume() deletes recent EGLSurface based on
- // wl_surface owned by mContainer and creates a new fallback EGLSurface.
- // Then we can delete wl_surface in moz_container_wayland_unmap().
- // We don't want to pause compositor as it may lead to whole
- // browser freeze (Bug 1777664).
- ///
- // We don't need to do such operation for SW backend as
- // WindowSurfaceWaylandMB::Commit() gets wl_surface from
- // MozContainer every commit.
- if (moz_container_wayland_has_egl_window(mContainer) &&
- mCompositorWidgetDelegate) {
- if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) {
- // Call DisableRendering() to make GtkCompositorWidget hidden.
- // Then SendResume() will create fallback EGLSurface, see
- // GLContextEGL::CreateEGLSurfaceForCompositorWidget().
- mCompositorWidgetDelegate->DisableRendering();
- remoteRenderer->SendResume();
- mCompositorWidgetDelegate->EnableRendering(GetX11Window(),
- GetShapedState());
+ // Widget is backed by OpenGL EGLSurface created over wl_surface
+ // owned by mContainer.
+ // RenderCompositorEGL::Resume() deletes recent EGLSurface based on
+ // wl_surface owned by mContainer and creates a new fallback EGLSurface.
+ // Then we can delete wl_surface in moz_container_wayland_unmap().
+ // We don't want to pause compositor as it may lead to whole
+ // browser freeze (Bug 1777664).
+ ///
+ // We don't need to do such operation for SW backend as
+ // WindowSurfaceWaylandMB::Commit() gets wl_surface from
+ // MozContainer every commit.
+ if (moz_container_wayland_has_egl_window(mContainer) &&
+ mCompositorWidgetDelegate) {
+ if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) {
+ // Call DisableRendering() to make GtkCompositorWidget hidden.
+ // Then SendResume() will create fallback EGLSurface, see
+ // GLContextEGL::CreateEGLSurfaceForCompositorWidget().
+ mCompositorWidgetDelegate->DisableRendering();
+ remoteRenderer->SendResume();
+ mCompositorWidgetDelegate->EnableRendering(GetX11Window(),
+ GetShapedState());
+ }
}
- }
#endif
+ }
}
// Apply workaround for Mutter compositor bug (mzbz#1777269).