diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:14:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:14:29 +0000 |
commit | fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8 (patch) | |
tree | 4c1ccaf5486d4f2009f9a338a98a83e886e29c97 /widget/gtk/nsWindow.cpp | |
parent | Releasing progress-linux version 124.0.1-1~progress7.99u1. (diff) | |
download | firefox-fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8.tar.xz firefox-fbaf0bb26397aa498eb9156f06d5a6fe34dd7dd8.zip |
Merging upstream version 125.0.1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'widget/gtk/nsWindow.cpp')
-rw-r--r-- | widget/gtk/nsWindow.cpp | 528 |
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). |