Bug Summary

File:root/firefox-clang/widget/gtk/nsWindowWayland.cpp
Warning:line 1892, column 14
Value stored to 'tmp' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name nsWindowWayland.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/widget/gtk -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/widget/gtk -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D CAIRO_GFX -D MOZ_APP_NAME="firefox" -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/widget/gtk -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/widget/gtk -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/toolkit/components/telemetry -I /root/firefox-clang/xpcom/base -I /root/firefox-clang/layout/base -I /root/firefox-clang/layout/forms -I /root/firefox-clang/layout/generic -I /root/firefox-clang/layout/xul -I /root/firefox-clang/other-licenses/atk-1.0 -I /root/firefox-clang/third_party/cups/include -I /root/firefox-clang/widget -I /root/firefox-clang/widget/headless -I /root/firefox-clang/widget/x11 -I /root/firefox-clang/third_party/gbm/gbm -I /root/firefox-clang/third_party/drm/drm -I /root/firefox-clang/third_party/drm/drm/include -I /root/firefox-clang/third_party/drm/drm/include/libdrm -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -I /usr/include/gtk-3.0/unix-print -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cloudproviders -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/fribidi -I /usr/include/harfbuzz -I /usr/include/atk-1.0 -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/glycin-2 -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/gio-unix-2.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/cloudproviders -I /usr/include/cairo -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/glycin-2 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/atk-1.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/fribidi -I /usr/include/pixman-1 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/gio-unix-2.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/sysprof-6 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ /root/firefox-clang/widget/gtk/nsWindowWayland.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include "nsWindowWayland.h"
6
7#include <dlfcn.h>
8
9#include "WaylandVsyncSource.h"
10#include "WidgetUtilsGtk.h"
11#include "mozilla/PresShell.h"
12#include "mozilla/StaticPrefs_widget.h"
13#include "mozilla/VsyncDispatcher.h"
14#include "mozilla/gfx/Logging.h"
15#include "mozilla/webrender/WebRenderTypes.h"
16#include "nsAppShell.h"
17#include "nsDragService.h"
18#include "nsDragSessionSource.h"
19#include "nsGtkKeyUtils.h"
20#include "nsGtkUtils.h"
21#include "nsIAppWindow.h"
22#include "nsIClipboard.h"
23#include "nsIDocShell.h"
24#include "nsISessionStoreFunctions.h"
25#include "nsIUUIDGenerator.h"
26#include "nsMenuPopupFrame.h"
27#include "nsPIDOMWindow.h"
28#include "nsWaylandDisplay.h"
29#include "nsWindow.h"
30
31using namespace mozilla;
32using namespace mozilla::gfx;
33using namespace mozilla::layers;
34using namespace mozilla::widget;
35
36/*
37 Window restore session uses GetWorkspaceID()/MoveToWorkspace() differently
38 on Wayland.
39
40 MoveToWorkspace() is normally called when a window is visible/rendered and
41 widget code moves the window to a particular workspace. That approach doesn't
42 work on Wayland where an application can't position itself.
43
44 On Wayland we need to place the window before it's shown, so we use this
45 path instead:
46
47 1) In ConfigureToplevelWindowNative() we register an "xdg-toplevel-realized"
48 GTK signal handler to get notified when the xdg_toplevel window is created.
49 2) Block NativeShow() while mWaitingToSessionRestore is set. We can't show
50 the toplevel window until we have a window restore ID provided by a
51 MoveToWorkspace() call.
52 3) In MoveToWorkspace(), save the session ID and show the window. That fires
53 the "xdg-toplevel-realized" signal which gives us the xdg_toplevel and we
54 restore window state according to the session ID.
55
56 Likewise we use GetWorkspaceID() to create/save the xdg_toplevel session
57 for later restore.
58*/
59
60bool GenerateWorkspaceID(nsAString& aName) {
61 nsresult rv;
62 nsCOMPtr<nsIUUIDGenerator> uuidGenerator =
63 do_GetService("@mozilla.org/uuid-generator;1", &rv);
64 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 64)
) {
65 return false;
66 }
67
68 nsID id;
69 rv = uuidGenerator->GenerateUUIDInPlace(&id);
70 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 70)
) {
71 return false;
72 }
73
74 char chars[NSID_LENGTH39];
75 id.ToProvidedString(chars);
76
77 // NSID_LENGTH counts the null terminator.
78 aName.AssignASCII(chars, NSID_LENGTH39 - 1);
79 return true;
80}
81
82static struct xdg_toplevel* GetXdgToplevelFromGdkWindow(GdkWindow* aWindow) {
83 static auto sGdkWaylandWindowGetXdgToplevel =
84 (struct xdg_toplevel * (*)(GdkWindow*))
85 dlsym(RTLD_DEFAULT((void *) 0), "gdk_wayland_window_get_xdg_toplevel");
86 if (!sGdkWaylandWindowGetXdgToplevel) {
87 return nullptr;
88 }
89 return sGdkWaylandWindowGetXdgToplevel(aWindow);
90}
91
92// aRestoreWindow = true means we're loading mSessionRestoreToken
93// from already saved toplevel window state.
94// aRestoreWindow = false means we're creating a new restore session.
95bool nsWindowWayland::CreateRestoreSession(bool aRestoreWindow) {
96 MOZ_DIAGNOSTIC_ASSERT(!mSessionRestoreToken)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mSessionRestoreToken)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mSessionRestoreToken))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("!mSessionRestoreToken"
, "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp", 96); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "!mSessionRestoreToken" ")"); do
{ MOZ_CrashSequence(__null, 96); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
97 GdkWindow* window = GetToplevelGdkWindow();
98 if (!window) {
99 LOG("nsWindowWayland::CreateRestoreSession(): failed to get GdkWindow, "do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::CreateRestoreSession(): failed to get GdkWindow, "
"quit.", this->GetDebugTag().get()); } } while (0)
100 "quit.")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::CreateRestoreSession(): failed to get GdkWindow, "
"quit.", this->GetDebugTag().get()); } } while (0)
;
101 return false;
102 }
103 struct xdg_toplevel* toplevel = GetXdgToplevelFromGdkWindow(window);
104 if (!toplevel) {
105 LOG("nsWindowWayland::CreateRestoreSession(): failed to get xdg-toplevel, "do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::CreateRestoreSession(): failed to get xdg-toplevel, "
"quit.", this->GetDebugTag().get()); } } while (0)
106 "quit.")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::CreateRestoreSession(): failed to get xdg-toplevel, "
"quit.", this->GetDebugTag().get()); } } while (0)
;
107 return false;
108 }
109 auto* session = WaylandDisplayGet()->GetSession();
110 if (!session) {
111 LOG("nsWindowWayland::CreateRestoreSession(): failed to get restore "do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::CreateRestoreSession(): failed to get restore "
"session, quit.", this->GetDebugTag().get()); } } while (
0)
112 "session, quit.")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::CreateRestoreSession(): failed to get restore "
"session, quit.", this->GetDebugTag().get()); } } while (
0)
;
113 return false;
114 }
115
116 NS_ConvertUTF16toUTF8 id(mSessionID);
117 if (aRestoreWindow) {
118 mSessionRestoreToken =
119 xdg_session_v1_restore_toplevel(session, toplevel, id.get());
120 } else {
121 mSessionRestoreToken =
122 xdg_session_v1_add_toplevel(session, toplevel, id.get());
123 }
124
125 LOG("nsWindowWayland::CreateRestoreSession() ID %s restore %d token %p",do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::CreateRestoreSession() ID %s restore %d token %p"
, this->GetDebugTag().get(), id.get(), aRestoreWindow, mSessionRestoreToken
); } } while (0)
126 id.get(), aRestoreWindow, mSessionRestoreToken)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::CreateRestoreSession() ID %s restore %d token %p"
, this->GetDebugTag().get(), id.get(), aRestoreWindow, mSessionRestoreToken
); } } while (0)
;
127 return !!mSessionRestoreToken;
128}
129
130void nsWindowWayland::GetWorkspaceID(nsAString& workspaceID) {
131 if (mSessionID.IsEmpty() && !GenerateWorkspaceID(mSessionID)) {
132 return;
133 }
134 workspaceID.Assign(mSessionID);
135
136 LOG("nsWindowWayland::GetWorkspaceID() ID %s token %p",do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::GetWorkspaceID() ID %s token %p"
, this->GetDebugTag().get(), NS_ConvertUTF16toUTF8(mSessionID
).get(), mSessionRestoreToken); } } while (0)
137 NS_ConvertUTF16toUTF8(mSessionID).get(), mSessionRestoreToken)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::GetWorkspaceID() ID %s token %p"
, this->GetDebugTag().get(), NS_ConvertUTF16toUTF8(mSessionID
).get(), mSessionRestoreToken); } } while (0)
;
138
139 if (mSessionRestoreToken) {
140 return;
141 }
142
143 CreateRestoreSession(/* aRestoreWindow */ false);
144}
145
146#ifdef MOZ_LOGGING1
147static void SessionRestoredHandler(void* aData,
148 xdg_toplevel_session_v1* aToplevelSession) {
149 LOGW("nsWindowWayland restored [%p]", aData)do { const ::mozilla::LogModule* moz_real_module = gWidgetLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "nsWindowWayland restored [%p]"
, aData); } } while (0)
;
150}
151
152static const xdg_toplevel_session_v1_listener sSessionListener = {
153 SessionRestoredHandler,
154};
155#endif
156
157void nsWindowWayland::RestoreXdgToplevel() {
158 LOG("nsWindowWayland::RestoreXdgToplevel() ID %s GdkWindow [%p]",do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::RestoreXdgToplevel() ID %s GdkWindow [%p]"
, this->GetDebugTag().get(), NS_ConvertUTF16toUTF8(mSessionID
).get(), GetToplevelGdkWindow()); } } while (0)
159 NS_ConvertUTF16toUTF8(mSessionID).get(), GetToplevelGdkWindow())do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::RestoreXdgToplevel() ID %s GdkWindow [%p]"
, this->GetDebugTag().get(), NS_ConvertUTF16toUTF8(mSessionID
).get(), GetToplevelGdkWindow()); } } while (0)
;
160 if (CreateRestoreSession(/* aRestoreWindow */ true)) {
161#ifdef MOZ_LOGGING1
162 if (LOG_ENABLED()((__builtin_expect(!!(mozilla::detail::log_test(gWidgetPopupLog
, mozilla::LogLevel::Debug)), 0)) || (__builtin_expect(!!(mozilla
::detail::log_test(gWidgetLog, mozilla::LogLevel::Debug)), 0)
))
) {
163 xdg_toplevel_session_v1_add_listener(mSessionRestoreToken,
164 &sSessionListener, this);
165 }
166#endif
167 }
168}
169
170void nsWindowWayland::MoveToWorkspace(const nsAString& workspaceIDStr) {
171 mSessionID.Assign(workspaceIDStr);
172 LOG("nsWindowWayland::MoveToWorkspace() session ID %s "do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::MoveToWorkspace() session ID %s "
"mWaitingToSessionRestore %d mNeedsShow %d", this->GetDebugTag
().get(), NS_ConvertUTF16toUTF8(mSessionID).get(), mWaitingToSessionRestore
, mNeedsShow); } } while (0)
173 "mWaitingToSessionRestore %d mNeedsShow %d",do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::MoveToWorkspace() session ID %s "
"mWaitingToSessionRestore %d mNeedsShow %d", this->GetDebugTag
().get(), NS_ConvertUTF16toUTF8(mSessionID).get(), mWaitingToSessionRestore
, mNeedsShow); } } while (0)
174 NS_ConvertUTF16toUTF8(mSessionID).get(), mWaitingToSessionRestore,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::MoveToWorkspace() session ID %s "
"mWaitingToSessionRestore %d mNeedsShow %d", this->GetDebugTag
().get(), NS_ConvertUTF16toUTF8(mSessionID).get(), mWaitingToSessionRestore
, mNeedsShow); } } while (0)
175 mNeedsShow)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::MoveToWorkspace() session ID %s "
"mWaitingToSessionRestore %d mNeedsShow %d", this->GetDebugTag
().get(), NS_ConvertUTF16toUTF8(mSessionID).get(), mWaitingToSessionRestore
, mNeedsShow); } } while (0)
;
176 if (!mWaitingToSessionRestore) {
177 return;
178 }
179 mWaitingToSessionRestore = false;
180 if (mNeedsShow) {
181 NativeShow(/* show */ true);
182 }
183}
184
185// This is an ugly workaround for
186// https://bugzilla.mozilla.org/show_bug.cgi?id=1622107
187// We try to detect when Wayland compositor / gtk fails to deliver
188// info about finished D&D operations and cancel it on our own.
189//
190// The sequence is:
191// 1) D&D is started on both Wayland & Firefox side
192// 2) D&D is finished on Wayland side, Wayland doesn't deliver drag finish to
193// Firefox, Firefox D&D is still active.
194// 4) Firefox UI is blocked by the D&D from 1)
195// 5) We use mouse button to get mouse clicks and cancel the Firefox D&D
196// session.
197//
198void nsWindowWayland::WaylandDragWorkaround(GdkEventButton* aEvent) {
199 // We track only left button state as Firefox performs D&D on left
200 // button only.
201 if (aEvent->button != 1 || aEvent->type != GDK_BUTTON_RELEASE) {
202 return;
203 }
204
205 nsCOMPtr<nsIDragService> dragService =
206 do_GetService("@mozilla.org/widget/dragservice;1");
207 if (!dragService) {
208 return;
209 }
210 nsCOMPtr<nsIDragSession> currentDragSession =
211 dragService->GetCurrentSession(this);
212 if (!currentDragSession ||
213 static_cast<nsDragSessionSource*>(currentDragSession.get())->IsActive()) {
214 return;
215 }
216
217 LOGDRAG("WaylandDragWorkaround applied, quit D&D session")do { const ::mozilla::LogModule* moz_real_module = gWidgetDragLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WaylandDragWorkaround applied, quit D&D session"
); } } while (0)
;
218 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "Quit unfinished Wayland Drag and Drop operation. Buggy Wayland "
"compositor?", nullptr, "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 220)
219 "Quit unfinished Wayland Drag and Drop operation. Buggy Wayland "NS_DebugBreak(NS_DEBUG_WARNING, "Quit unfinished Wayland Drag and Drop operation. Buggy Wayland "
"compositor?", nullptr, "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 220)
220 "compositor?")NS_DebugBreak(NS_DEBUG_WARNING, "Quit unfinished Wayland Drag and Drop operation. Buggy Wayland "
"compositor?", nullptr, "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 220)
;
221 currentDragSession->EndDragSession(true, 0);
222}
223
224nsWindowWayland::nsWindowWayland()
225 : mPopupTrackInHierarchy(false),
226 mPopupTrackInHierarchyConfigured(false),
227 mWaylandApplyPopupPositionBeforeShow(true),
228 mPopupAnchored(false),
229 mPopupContextMenu(false),
230 mPopupMatchesLayout(false),
231 mPopupChanged(false),
232 mPopupClosed(false),
233 mPopupUseMoveToRect(false),
234 mWaitingForMoveToRectCallback(false),
235 mMovedAfterMoveToRect(false),
236 mResizedAfterMoveToRect(false) {}
237
238void nsWindowWayland::FocusWaylandWindow(const char* aTokenID) {
239 MOZ_DIAGNOSTIC_ASSERT(aTokenID)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aTokenID)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aTokenID))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aTokenID", "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 239); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aTokenID"
")"); do { MOZ_CrashSequence(__null, 239); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
240
241 LOG("nsWindowWayland::FocusWaylandWindow(%s)", aTokenID)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::FocusWaylandWindow(%s)"
, this->GetDebugTag().get(), aTokenID); } } while (0)
;
242 if (IsDestroyed()) {
243 LOG(" already destroyed, quit.")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " already destroyed, quit.", this->
GetDebugTag().get()); } } while (0)
;
244 return;
245 }
246 wl_surface* surface =
247 mGdkWindow ? gdk_wayland_window_get_wl_surface(mGdkWindow) : nullptr;
248 if (!surface) {
249 LOG(" mGdkWindow is not visible, quit.")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " mGdkWindow is not visible, quit."
, this->GetDebugTag().get()); } } while (0)
;
250 return;
251 }
252
253 LOG(" requesting xdg-activation, surface ID %d",do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " requesting xdg-activation, surface ID %d"
, this->GetDebugTag().get(), wl_proxy_get_id((struct wl_proxy
*)surface)); } } while (0)
254 wl_proxy_get_id((struct wl_proxy*)surface))do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " requesting xdg-activation, surface ID %d"
, this->GetDebugTag().get(), wl_proxy_get_id((struct wl_proxy
*)surface)); } } while (0)
;
255 xdg_activation_v1* xdg_activation = WaylandDisplayGet()->GetXdgActivation();
256 if (!xdg_activation) {
257 return;
258 }
259 xdg_activation_v1_activate(xdg_activation, aTokenID, surface);
260}
261
262// Transfer focus from gFocusWindow to aWindow and use xdg_activation
263// protocol for it.
264void nsWindowWayland::TransferFocusTo() {
265 LOG("nsWindowWayland::TransferFocusTo() gFocusWindow %p", GetFocusedWindow())do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::TransferFocusTo() gFocusWindow %p"
, this->GetDebugTag().get(), GetFocusedWindow()); } } while
(0)
;
266 auto promise = mozilla::widget::RequestWaylandFocusPromise();
267 if (NS_WARN_IF(!promise)NS_warn_if_impl(!promise, "!promise", "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 267)
) {
268 LOG(" quit, failed to create focus promise")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " quit, failed to create focus promise"
, this->GetDebugTag().get()); } } while (0)
;
269 return;
270 }
271 promise->Then(
272 GetMainThreadSerialEventTarget(), __func__,
273 /* resolve */
274 [window = RefPtr{this}](nsCString token) {
275 window->FocusWaylandWindow(token.get());
276 },
277 /* reject */
278 [window = RefPtr{this}](bool state) {
279 LOGW("TransferFocusToWaylandWindow [%p] failed", window.get())do { const ::mozilla::LogModule* moz_real_module = gWidgetLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "TransferFocusToWaylandWindow [%p] failed"
, window.get()); } } while (0)
;
280 });
281}
282
283void nsWindowWayland::CreateCompositorVsyncDispatcher() {
284 LOG_VSYNC("nsWindowWayland::CreateCompositorVsyncDispatcher()")do { const ::mozilla::LogModule* moz_real_module = gWidgetVsync
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "%s: " "nsWindowWayland::CreateCompositorVsyncDispatcher()"
, GetDebugTag().get()); } } while (0)
;
285 if (!mWaylandVsyncSource) {
286 LOG_VSYNC(do { const ::mozilla::LogModule* moz_real_module = gWidgetVsync
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "%s: " " mWaylandVsyncSource is missing, create "
"nsIWidget::CompositorVsyncDispatcher()", GetDebugTag().get(
)); } } while (0)
287 " mWaylandVsyncSource is missing, create "do { const ::mozilla::LogModule* moz_real_module = gWidgetVsync
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "%s: " " mWaylandVsyncSource is missing, create "
"nsIWidget::CompositorVsyncDispatcher()", GetDebugTag().get(
)); } } while (0)
288 "nsIWidget::CompositorVsyncDispatcher()")do { const ::mozilla::LogModule* moz_real_module = gWidgetVsync
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "%s: " " mWaylandVsyncSource is missing, create "
"nsIWidget::CompositorVsyncDispatcher()", GetDebugTag().get(
)); } } while (0)
;
289 nsIWidget::CreateCompositorVsyncDispatcher();
290 return;
291 }
292 if (!mCompositorVsyncDispatcherLock) {
293 mCompositorVsyncDispatcherLock =
294 MakeUnique<Mutex>("mCompositorVsyncDispatcherLock");
295 }
296 MutexAutoLock lock(*mCompositorVsyncDispatcherLock);
297 if (!mCompositorVsyncDispatcher) {
298 LOG_VSYNC(" create CompositorVsyncDispatcher()")do { const ::mozilla::LogModule* moz_real_module = gWidgetVsync
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "%s: " " create CompositorVsyncDispatcher()"
, GetDebugTag().get()); } } while (0)
;
299 mCompositorVsyncDispatcher =
300 new CompositorVsyncDispatcher(mWaylandVsyncDispatcher);
301 }
302}
303
304RefPtr<VsyncDispatcher> nsWindowWayland::GetVsyncDispatcher() {
305 return mWaylandVsyncDispatcher;
306}
307
308void nsWindowWayland::EnableVSyncSource() {
309 if (mWaylandVsyncSource) {
310 mWaylandVsyncSource->EnableVSyncSource();
311 }
312}
313
314void nsWindowWayland::DisableVSyncSource() {
315 if (mWaylandVsyncSource) {
316 mWaylandVsyncSource->DisableVSyncSource();
317 }
318}
319
320nsresult nsWindowWayland::SynthesizeNativeMouseMove(
321 LayoutDeviceIntPoint aPoint, nsISynthesizedEventCallback* aCallback) {
322 if (IsNativePointerLocked()) {
323 AutoSynthesizedEventCallbackNotifier notifier(aCallback);
324 mNativeLockedPoint = aPoint - WidgetToScreenOffset();
325
326 WidgetMouseEvent event(true, eMouseMove, this, WidgetMouseEvent::eReal);
327 event.mRefPoint = mNativeLockedPoint;
328 event.AssignEventTime(GetWidgetEventTime(0));
329 event.mMovement = Some(LayoutDeviceIntPoint(0, 0));
330 DispatchInputEvent(&event);
331
332 return NS_OK;
333 }
334
335 return nsWindow::SynthesizeNativeMouseMove(aPoint, aCallback);
336}
337
338static void relative_pointer_handle_relative_motion(
339 void* data, struct zwp_relative_pointer_v1* pointer, uint32_t time_hi,
340 uint32_t time_lo, wl_fixed_t dx_w, wl_fixed_t dy_w, wl_fixed_t dx_unaccel_w,
341 wl_fixed_t dy_unaccel_w) {
342 RefPtr<nsWindowWayland> window(reinterpret_cast<nsWindowWayland*>(data));
343 double scale = window->FractionalScaleFactor();
344 LOGW(do { const ::mozilla::LogModule* moz_real_module = gWidgetLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "[%p] relative_pointer_handle_relative_motion center dx = %f, "
"dy = %f scale %f", data, wl_fixed_to_double(dx_w), wl_fixed_to_double
(dy_w), scale); } } while (0)
345 "[%p] relative_pointer_handle_relative_motion center dx = %f, "do { const ::mozilla::LogModule* moz_real_module = gWidgetLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "[%p] relative_pointer_handle_relative_motion center dx = %f, "
"dy = %f scale %f", data, wl_fixed_to_double(dx_w), wl_fixed_to_double
(dy_w), scale); } } while (0)
346 "dy = %f scale %f",do { const ::mozilla::LogModule* moz_real_module = gWidgetLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "[%p] relative_pointer_handle_relative_motion center dx = %f, "
"dy = %f scale %f", data, wl_fixed_to_double(dx_w), wl_fixed_to_double
(dy_w), scale); } } while (0)
347 data, wl_fixed_to_double(dx_w), wl_fixed_to_double(dy_w), scale)do { const ::mozilla::LogModule* moz_real_module = gWidgetLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "[%p] relative_pointer_handle_relative_motion center dx = %f, "
"dy = %f scale %f", data, wl_fixed_to_double(dx_w), wl_fixed_to_double
(dy_w), scale); } } while (0)
;
348
349 int32_t movementX = int32_t(wl_fixed_to_double(dx_w) * scale);
350 int32_t movementY = int32_t(wl_fixed_to_double(dy_w) * scale);
351 if (movementX == 0 && movementY == 0) {
352 // Ignore event with zero movement.
353 return;
354 }
355
356 WidgetMouseEvent event(true, eMouseMove, window, WidgetMouseEvent::eReal);
357 event.mRefPoint = window->GetNativeLockedPoint();
358 event.AssignEventTime(window->GetWidgetEventTime(time_lo));
359 event.mMovement = Some(LayoutDeviceIntPoint(movementX, movementY));
360 window->DispatchInputEvent(&event);
361}
362
363static const struct zwp_relative_pointer_v1_listener relative_pointer_listener =
364 {
365 relative_pointer_handle_relative_motion,
366};
367
368void nsWindowWayland::LockNativePointer(
369 NativePointerLockMode aNativePointerLockMode) {
370 if (!GdkIsWaylandDisplay()) {
371 return;
372 }
373
374 auto* waylandDisplay = WaylandDisplayGet();
375
376 auto* pointerConstraints = waylandDisplay->GetPointerConstraints();
377 if (!pointerConstraints) {
378 return;
379 }
380
381 auto* relativePointerMgr = waylandDisplay->GetRelativePointerManager();
382 if (!relativePointerMgr) {
383 LOG("nsWindowWayland::LockNativePointer() - quit, missing pointer "do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::LockNativePointer() - quit, missing pointer "
"manager.", this->GetDebugTag().get()); } } while (0)
384 "manager.")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::LockNativePointer() - quit, missing pointer "
"manager.", this->GetDebugTag().get()); } } while (0)
;
385 return;
386 }
387
388 GdkDisplay* display = gdk_display_get_default();
389
390 GdkDeviceManager* manager = gdk_display_get_device_manager(display);
391 MOZ_ASSERT(manager)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(manager)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(manager))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("manager", "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 391); AnnotateMozCrashReason("MOZ_ASSERT" "(" "manager" ")"
); do { MOZ_CrashSequence(__null, 391); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
392
393 GdkDevice* device = gdk_device_manager_get_client_pointer(manager);
394 if (!device) {
395 LOG("nsWindowWayland::LockNativePointer() - quit, could not find Wayland "do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::LockNativePointer() - quit, could not find Wayland "
"pointer " "to lock.", this->GetDebugTag().get()); } } while
(0)
396 "pointer "do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::LockNativePointer() - quit, could not find Wayland "
"pointer " "to lock.", this->GetDebugTag().get()); } } while
(0)
397 "to lock.")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::LockNativePointer() - quit, could not find Wayland "
"pointer " "to lock.", this->GetDebugTag().get()); } } while
(0)
;
398 return;
399 }
400 wl_pointer* pointer = gdk_wayland_device_get_wl_pointer(device);
401 MOZ_ASSERT(pointer)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(pointer)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(pointer))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("pointer", "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 401); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pointer" ")"
); do { MOZ_CrashSequence(__null, 401); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
402
403 wl_surface* surface =
404 gdk_wayland_window_get_wl_surface(GetToplevelGdkWindow());
405 if (!surface) {
406 LOG("nsWindowWayland::LockNativePointer() - quit, toplevel surface is "do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::LockNativePointer() - quit, toplevel surface is "
"hidden.", this->GetDebugTag().get()); } } while (0)
407 "hidden.")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::LockNativePointer() - quit, toplevel surface is "
"hidden.", this->GetDebugTag().get()); } } while (0)
;
408 /* Can be null when the window is hidden.
409 * Though it's unlikely that a lock request comes in that case, be
410 * defensive. */
411 return;
412 }
413
414 UnlockNativePointer();
415
416 LOG("nsWindowWayland::LockNativePointer()")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::LockNativePointer()"
, this->GetDebugTag().get()); } } while (0)
;
417
418 mLockedPointer = zwp_pointer_constraints_v1_lock_pointer(
419 pointerConstraints, surface, pointer, nullptr,
420 ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
421 if (!mLockedPointer) {
422 LOG(" can't lock Wayland pointer")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " can't lock Wayland pointer", this
->GetDebugTag().get()); } } while (0)
;
423 return;
424 }
425
426 mRelativePointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
427 relativePointerMgr, pointer);
428 if (!mRelativePointer) {
429 LOG(" can't create relative Wayland pointer")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " can't create relative Wayland pointer"
, this->GetDebugTag().get()); } } while (0)
;
430 zwp_locked_pointer_v1_destroy(mLockedPointer);
431 mLockedPointer = nullptr;
432 return;
433 }
434
435 zwp_relative_pointer_v1_add_listener(mRelativePointer,
436 &relative_pointer_listener, this);
437}
438
439void nsWindowWayland::UnlockNativePointer() {
440 mNativeLockedPoint = LayoutDeviceIntPoint(0, 0);
441 if (mRelativePointer) {
442 zwp_relative_pointer_v1_destroy(mRelativePointer);
443 mRelativePointer = nullptr;
444 }
445 if (mLockedPointer) {
446 zwp_locked_pointer_v1_destroy(mLockedPointer);
447 mLockedPointer = nullptr;
448 }
449}
450
451LayoutDeviceIntSize nsWindowWayland::GetMoveToRectPopupSize() {
452 return ToLayoutDevicePixels(mMoveToRectPopupSize);
453}
454
455nsWindow* nsWindowWayland::GetEffectiveParent() const {
456 GtkWindow* parentGtkWindow = gtk_window_get_transient_for(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
457 if (!parentGtkWindow || !GTK_IS_WIDGET(parentGtkWindow)(((__extension__ ({ GTypeInstance *_inst = (GTypeInstance*) (
(parentGtkWindow)); GType _t = ((gtk_widget_get_type ())); gboolean
_r; if (!_inst) _r = (0); else if (_inst->g_class &&
_inst->g_class->g_type == _t) _r = (!(0)); else _r = g_type_check_instance_is_a
(_inst, _t); _r; }))))
) {
458 return nullptr;
459 }
460 return nsWindow::FromGtkWidget(GTK_WIDGET(parentGtkWindow)((((GtkWidget*) (void *) ((parentGtkWindow))))));
461}
462
463static GdkGravity PopupAlignmentToGdkGravity(int8_t aAlignment) {
464 switch (aAlignment) {
465 case POPUPALIGNMENT_NONE0:
466 return GDK_GRAVITY_NORTH_WEST;
467 case POPUPALIGNMENT_TOPLEFT1:
468 return GDK_GRAVITY_NORTH_WEST;
469 case POPUPALIGNMENT_TOPRIGHT-1:
470 return GDK_GRAVITY_NORTH_EAST;
471 case POPUPALIGNMENT_BOTTOMLEFT2:
472 return GDK_GRAVITY_SOUTH_WEST;
473 case POPUPALIGNMENT_BOTTOMRIGHT-2:
474 return GDK_GRAVITY_SOUTH_EAST;
475 case POPUPALIGNMENT_LEFTCENTER16:
476 return GDK_GRAVITY_WEST;
477 case POPUPALIGNMENT_RIGHTCENTER-16:
478 return GDK_GRAVITY_EAST;
479 case POPUPALIGNMENT_TOPCENTER17:
480 return GDK_GRAVITY_NORTH;
481 case POPUPALIGNMENT_BOTTOMCENTER18:
482 return GDK_GRAVITY_SOUTH;
483 }
484 return GDK_GRAVITY_STATIC;
485}
486
487bool nsWindowWayland::IsPopupDirectionRTL() {
488 nsMenuPopupFrame* popupFrame = GetPopupFrame();
489 return popupFrame && popupFrame->IsDirectionRTL();
490}
491
492struct PopupSides {
493 Maybe<Side> mVertical;
494 Maybe<Side> mHorizontal;
495};
496
497static PopupSides SidesForPopupAlignment(int8_t aAlignment) {
498 switch (aAlignment) {
499 case POPUPALIGNMENT_NONE0:
500 break;
501 case POPUPALIGNMENT_TOPLEFT1:
502 return {Some(eSideTop), Some(eSideLeft)};
503 case POPUPALIGNMENT_TOPRIGHT-1:
504 return {Some(eSideTop), Some(eSideRight)};
505 case POPUPALIGNMENT_BOTTOMLEFT2:
506 return {Some(eSideBottom), Some(eSideLeft)};
507 case POPUPALIGNMENT_BOTTOMRIGHT-2:
508 return {Some(eSideBottom), Some(eSideRight)};
509 case POPUPALIGNMENT_LEFTCENTER16:
510 return {Nothing(), Some(eSideLeft)};
511 case POPUPALIGNMENT_RIGHTCENTER-16:
512 return {Nothing(), Some(eSideRight)};
513 case POPUPALIGNMENT_TOPCENTER17:
514 return {Some(eSideTop), Nothing()};
515 case POPUPALIGNMENT_BOTTOMCENTER18:
516 return {Some(eSideBottom), Nothing()};
517 }
518 return {};
519}
520
521// We want to apply margins based on popup alignment (which would generally be
522// just an offset to apply to the popup). However, to deal with flipping
523// correctly, we apply the margin to the anchor when possible.
524struct ResolvedPopupMargin {
525 // A margin to be applied to the anchor.
526 nsMargin mAnchorMargin;
527 // An offset in app units to be applied to the popup for when we need to tell
528 // GTK to center inside the anchor precisely (so we can't really do better in
529 // presence of flips).
530 nsPoint mPopupOffset;
531};
532
533static ResolvedPopupMargin ResolveMargin(nsMenuPopupFrame* aFrame,
534 int8_t aPopupAlign,
535 int8_t aAnchorAlign,
536 bool aAnchoredToPoint,
537 bool aIsContextMenu) {
538 nsMargin margin = aFrame->GetMargin();
539 nsPoint offset;
540
541 if (aAnchoredToPoint) {
542 // Since GTK doesn't allow us to specify margins itself, when anchored to a
543 // point we can just assume we'll be aligned correctly... This is kind of
544 // annoying but alas.
545 //
546 // This calculation must match the relevant unanchored popup calculation in
547 // nsMenuPopupFrame::SetPopupPosition(), which should itself be the inverse
548 // inverse of nsMenuPopupFrame::MoveTo().
549 if (aIsContextMenu && aFrame->IsDirectionRTL()) {
550 offset.x = -margin.right;
551 } else {
552 offset.x = margin.left;
553 }
554 offset.y = margin.top;
555 return {nsMargin(), offset};
556 }
557
558 auto popupSides = SidesForPopupAlignment(aPopupAlign);
559 auto anchorSides = SidesForPopupAlignment(aAnchorAlign);
560 // Matched sides: Invert the margin, so that we pull in the right direction.
561 // Popup not aligned to any anchor side: We give up and use the offset,
562 // applying the margin from the popup side.
563 // Mismatched sides: We swap the margins so that we pull in the right
564 // direction, e.g. margin-left: -10px should shrink 10px the _right_ of the
565 // box, not the left of the box.
566 if (popupSides.mHorizontal == anchorSides.mHorizontal) {
567 margin.left = -margin.left;
568 margin.right = -margin.right;
569 } else if (!anchorSides.mHorizontal) {
570 auto popupSide = *popupSides.mHorizontal;
571 offset.x += popupSide == eSideRight ? -margin.Side(popupSide)
572 : margin.Side(popupSide);
573 margin.left = margin.right = 0;
574 } else {
575 std::swap(margin.left, margin.right);
576 }
577
578 // Same logic as above, but in the vertical direction.
579 if (popupSides.mVertical == anchorSides.mVertical) {
580 margin.top = -margin.top;
581 margin.bottom = -margin.bottom;
582 } else if (!anchorSides.mVertical) {
583 auto popupSide = *popupSides.mVertical;
584 offset.y += popupSide == eSideBottom ? -margin.Side(popupSide)
585 : margin.Side(popupSide);
586 margin.top = margin.bottom = 0;
587 } else {
588 std::swap(margin.top, margin.bottom);
589 }
590
591 return {margin, offset};
592}
593
594#ifdef MOZ_LOGGING1
595void nsWindowWayland::LogPopupAnchorHints(int aHints) {
596 static struct hints_ {
597 int hint;
598 char name[100];
599 } hints[] = {
600 {GDK_ANCHOR_FLIP_X, "GDK_ANCHOR_FLIP_X"},
601 {GDK_ANCHOR_FLIP_Y, "GDK_ANCHOR_FLIP_Y"},
602 {GDK_ANCHOR_SLIDE_X, "GDK_ANCHOR_SLIDE_X"},
603 {GDK_ANCHOR_SLIDE_Y, "GDK_ANCHOR_SLIDE_Y"},
604 {GDK_ANCHOR_RESIZE_X, "GDK_ANCHOR_RESIZE_X"},
605 {GDK_ANCHOR_RESIZE_Y, "GDK_ANCHOR_RESIZE_X"},
606 };
607
608 LOG(" PopupAnchorHints")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " PopupAnchorHints", this->GetDebugTag
().get()); } } while (0)
;
609 for (const auto& hint : hints) {
610 if (hint.hint & aHints) {
611 LOG(" %s", hint.name)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " %s", this->GetDebugTag().get
(), hint.name); } } while (0)
;
612 }
613 }
614}
615
616void nsWindowWayland::LogPopupGravity(GdkGravity aGravity) {
617 static char gravity[][100]{"NONE",
618 "GDK_GRAVITY_NORTH_WEST",
619 "GDK_GRAVITY_NORTH",
620 "GDK_GRAVITY_NORTH_EAST",
621 "GDK_GRAVITY_WEST",
622 "GDK_GRAVITY_CENTER",
623 "GDK_GRAVITY_EAST",
624 "GDK_GRAVITY_SOUTH_WEST",
625 "GDK_GRAVITY_SOUTH",
626 "GDK_GRAVITY_SOUTH_EAST",
627 "GDK_GRAVITY_STATIC"};
628 LOG(" %s", gravity[aGravity])do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " %s", this->GetDebugTag().get
(), gravity[aGravity]); } } while (0)
;
629}
630#endif
631
632const nsWindowWayland::WaylandPopupMoveToRectParams
633nsWindowWayland::WaylandPopupGetPositionFromLayout() {
634 LOG("nsWindowWayland::WaylandPopupGetPositionFromLayout\n")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupGetPositionFromLayout\n"
, this->GetDebugTag().get()); } } while (0)
;
635
636 nsMenuPopupFrame* popupFrame = GetPopupFrame();
637 if (!popupFrame) {
638 return {};
639 }
640
641 const bool isTopContextMenu = mPopupContextMenu && !mPopupAnchored;
642 const bool isRTL = popupFrame->IsDirectionRTL();
643 const bool anchored = popupFrame->IsAnchored();
644 int8_t popupAlign = POPUPALIGNMENT_TOPLEFT1;
645 int8_t anchorAlign = POPUPALIGNMENT_BOTTOMRIGHT-2;
646 if (anchored) {
647 // See nsMenuPopupFrame::AdjustPositionForAnchorAlign.
648 popupAlign = popupFrame->GetUntransformedPopupAlignment();
649 anchorAlign = popupFrame->GetUntransformedPopupAnchor();
650 }
651 if (isRTL) {
652 popupAlign = -popupAlign;
653 anchorAlign = -anchorAlign;
654 }
655
656 // So we need to extract popup position from nsMenuPopupFrame() and duplicate
657 // the layout work here.
658 LayoutDeviceIntRect anchorRect;
659 ResolvedPopupMargin popupMargin;
660 {
661 nsRect anchorRectAppUnits = popupFrame->GetUntransformedAnchorRect();
662 // This is a somewhat hacky way of applying the popup margin. We don't know
663 // if GTK will end up flipping the popup, in which case the offset we
664 // compute is just wrong / applied to the wrong side.
665 //
666 // Instead, we tell it to anchor us at a smaller or bigger rect depending on
667 // the margin, which achieves the same result if the popup is positioned
668 // correctly, but doesn't misposition the popup when flipped across the
669 // anchor.
670 popupMargin = ResolveMargin(popupFrame, popupAlign, anchorAlign,
671 anchorRectAppUnits.IsEmpty(), isTopContextMenu);
672 LOG(" layout popup CSS anchor (%d, %d) %s, margin %s offset %s\n",do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " layout popup CSS anchor (%d, %d) %s, margin %s offset %s\n"
, this->GetDebugTag().get(), popupAlign, anchorAlign, ToString
(anchorRectAppUnits).c_str(), ToString(popupMargin.mAnchorMargin
).c_str(), ToString(popupMargin.mPopupOffset).c_str()); } } while
(0)
673 popupAlign, anchorAlign, ToString(anchorRectAppUnits).c_str(),do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " layout popup CSS anchor (%d, %d) %s, margin %s offset %s\n"
, this->GetDebugTag().get(), popupAlign, anchorAlign, ToString
(anchorRectAppUnits).c_str(), ToString(popupMargin.mAnchorMargin
).c_str(), ToString(popupMargin.mPopupOffset).c_str()); } } while
(0)
674 ToString(popupMargin.mAnchorMargin).c_str(),do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " layout popup CSS anchor (%d, %d) %s, margin %s offset %s\n"
, this->GetDebugTag().get(), popupAlign, anchorAlign, ToString
(anchorRectAppUnits).c_str(), ToString(popupMargin.mAnchorMargin
).c_str(), ToString(popupMargin.mPopupOffset).c_str()); } } while
(0)
675 ToString(popupMargin.mPopupOffset).c_str())do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " layout popup CSS anchor (%d, %d) %s, margin %s offset %s\n"
, this->GetDebugTag().get(), popupAlign, anchorAlign, ToString
(anchorRectAppUnits).c_str(), ToString(popupMargin.mAnchorMargin
).c_str(), ToString(popupMargin.mPopupOffset).c_str()); } } while
(0)
;
676 anchorRectAppUnits.Inflate(popupMargin.mAnchorMargin);
677 LOG(" after margins %s\n", ToString(anchorRectAppUnits).c_str())do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " after margins %s\n", this->
GetDebugTag().get(), ToString(anchorRectAppUnits).c_str()); }
} while (0)
;
678 nscoord auPerDev = popupFrame->PresContext()->AppUnitsPerDevPixel();
679 anchorRect = LayoutDeviceIntRect::FromAppUnitsToNearest(anchorRectAppUnits,
680 auPerDev);
681 if (anchorRect.width < 0) {
682 auto w = -anchorRect.width;
683 anchorRect.width += w + 1;
684 anchorRect.x += w;
685 }
686 LOG(" final %s\n", ToString(anchorRect).c_str())do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " final %s\n", this->GetDebugTag
().get(), ToString(anchorRect).c_str()); } } while (0)
;
687 }
688
689 LOG(" relative popup rect position [%d, %d] -> [%d x %d]\n", anchorRect.x,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " relative popup rect position [%d, %d] -> [%d x %d]\n"
, this->GetDebugTag().get(), anchorRect.x, anchorRect.y, anchorRect
.width, anchorRect.height); } } while (0)
690 anchorRect.y, anchorRect.width, anchorRect.height)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " relative popup rect position [%d, %d] -> [%d x %d]\n"
, this->GetDebugTag().get(), anchorRect.x, anchorRect.y, anchorRect
.width, anchorRect.height); } } while (0)
;
691
692 // Get gravity and flip type
693 GdkGravity rectAnchor = PopupAlignmentToGdkGravity(anchorAlign);
694 GdkGravity menuAnchor = PopupAlignmentToGdkGravity(popupAlign);
695
696 LOG(" parentRect gravity: %d anchor gravity: %d\n", rectAnchor, menuAnchor)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " parentRect gravity: %d anchor gravity: %d\n"
, this->GetDebugTag().get(), rectAnchor, menuAnchor); } } while
(0)
;
697
698 // slideHorizontal from nsMenuPopupFrame::SetPopupPosition
699 const int8_t position = popupFrame->GetAlignmentPosition();
700 // Gtk default is: GDK_ANCHOR_FLIP | GDK_ANCHOR_SLIDE | GDK_ANCHOR_RESIZE.
701 const auto hints = GdkAnchorHints([&] {
702 // We want tooltips to flip vertically or slide only.
703 // See nsMenuPopupFrame::SetPopupPosition().
704 // https://searchfox.org/mozilla-central/rev/d0f5bc50aff3462c9d1546b88d60c5cb020eb15c/layout/xul/nsMenuPopupFrame.cpp#1603
705 if (mPopupType == PopupType::Tooltip) {
706 return GDK_ANCHOR_FLIP_Y | GDK_ANCHOR_SLIDE;
707 }
708 // We want to SLIDE_X menu on dual monitor setup rather than resize it
709 // on the other monitor, so we always allow sliding horizontally.
710 // slideVertical position check comes from the same variable in
711 // nsMenuPopupFrame::SetPopupPosition.
712 //
713 // NOTE(emilio): It feels odd to not honor Gecko's FlipType more, but
714 // historically we've done that... Maybe reconsider? But note that
715 // flipping is tried before sliding, so it seems not too bad?
716 const bool slideVertical =
717 (position >= POPUPPOSITION_STARTBEFORE4 &&
718 position <= POPUPPOSITION_ENDAFTER7) ||
719 !anchored || popupFrame->GetFlipType() == FlipType::Slide ||
720 (rectAnchor == GDK_GRAVITY_CENTER && menuAnchor == GDK_GRAVITY_CENTER);
721 return GDK_ANCHOR_FLIP | GDK_ANCHOR_SLIDE_X |
722 (slideVertical ? GDK_ANCHOR_SLIDE_Y : 0) | GDK_ANCHOR_RESIZE;
723 }());
724
725 return {
726 anchorRect,
727 rectAnchor,
728 menuAnchor,
729 hints,
730 DevicePixelsToGdkPointRoundDown(LayoutDevicePoint::FromAppUnitsToNearest(
731 popupMargin.mPopupOffset,
732 popupFrame->PresContext()->AppUnitsPerDevPixel())),
733 true};
734}
735
736bool nsWindowWayland::WaylandPopupAnchorAdjustForParentPopup(
737 GdkRectangle* aPopupAnchor, GdkPoint* aOffset) {
738 LOG("nsWindowWayland::WaylandPopupAnchorAdjustForParentPopup")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupAnchorAdjustForParentPopup"
, this->GetDebugTag().get()); } } while (0)
;
739
740 GtkWindow* parentGtkWindow = gtk_window_get_transient_for(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
741 if (!parentGtkWindow || !GTK_IS_WIDGET(parentGtkWindow)(((__extension__ ({ GTypeInstance *_inst = (GTypeInstance*) (
(parentGtkWindow)); GType _t = ((gtk_widget_get_type ())); gboolean
_r; if (!_inst) _r = (0); else if (_inst->g_class &&
_inst->g_class->g_type == _t) _r = (!(0)); else _r = g_type_check_instance_is_a
(_inst, _t); _r; }))))
) {
742 NS_WARNING("Popup has no parent!")NS_DebugBreak(NS_DEBUG_WARNING, "Popup has no parent!", nullptr
, "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp", 742)
;
743 return false;
744 }
745 GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(parentGtkWindow)((((GtkWidget*) (void *) ((parentGtkWindow))))));
746 if (!window) {
747 NS_WARNING("Popup parrent is not mapped!")NS_DebugBreak(NS_DEBUG_WARNING, "Popup parrent is not mapped!"
, nullptr, "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 747)
;
748 return false;
749 }
750
751 GdkRectangle parentWindowRect = {0, 0, gdk_window_get_width(window),
752 gdk_window_get_height(window)};
753 LOG(" parent window size %d x %d", parentWindowRect.width,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " parent window size %d x %d", this
->GetDebugTag().get(), parentWindowRect.width, parentWindowRect
.height); } } while (0)
754 parentWindowRect.height)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " parent window size %d x %d", this
->GetDebugTag().get(), parentWindowRect.width, parentWindowRect
.height); } } while (0)
;
755
756 // We can't have rectangle anchor with zero width/height.
757 if (!aPopupAnchor->width) {
758 aPopupAnchor->width = 1;
759 }
760 if (!aPopupAnchor->height) {
761 aPopupAnchor->height = 1;
762 }
763
764 GdkRectangle finalRect;
765 if (!gdk_rectangle_intersect(aPopupAnchor, &parentWindowRect, &finalRect)) {
766 return false;
767 }
768 *aPopupAnchor = finalRect;
769 LOG(" anchor is correct %d,%d -> %d x %d", finalRect.x, finalRect.y,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " anchor is correct %d,%d -> %d x %d"
, this->GetDebugTag().get(), finalRect.x, finalRect.y, finalRect
.width, finalRect.height); } } while (0)
770 finalRect.width, finalRect.height)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " anchor is correct %d,%d -> %d x %d"
, this->GetDebugTag().get(), finalRect.x, finalRect.y, finalRect
.width, finalRect.height); } } while (0)
;
771
772 *aOffset = mPopupMoveToRectParams.mOffset;
773 LOG(" anchor offset %d, %d", aOffset->x, aOffset->y)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " anchor offset %d, %d", this->
GetDebugTag().get(), aOffset->x, aOffset->y); } } while
(0)
;
774 return true;
775}
776
777bool nsWindowWayland::WaylandPopupCheckAndGetAnchor(GdkRectangle* aPopupAnchor,
778 GdkPoint* aOffset) {
779 LOG("nsWindowWayland::WaylandPopupCheckAndGetAnchor")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupCheckAndGetAnchor"
, this->GetDebugTag().get()); } } while (0)
;
780
781 GdkWindow* gdkWindow = GetToplevelGdkWindow();
782 nsMenuPopupFrame* popupFrame = GetPopupFrame();
783 if (!gdkWindow || !popupFrame) {
784 LOG(" can't use move-to-rect due missing gdkWindow or popupFrame")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " can't use move-to-rect due missing gdkWindow or popupFrame"
, this->GetDebugTag().get()); } } while (0)
;
785 return false;
786 }
787
788 if (popupFrame->IsConstrainedByLayout()) {
789 LOG(" can't use move-to-rect, flipped / constrained by layout")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " can't use move-to-rect, flipped / constrained by layout"
, this->GetDebugTag().get()); } } while (0)
;
790 return false;
791 }
792
793 if (!mPopupMoveToRectParams.mAnchorSet) {
794 mPopupMoveToRectParams = WaylandPopupGetPositionFromLayout();
795 }
796
797 // Update popup layout coordinates from layout by recent popup hierarchy
798 // (calculate correct position according to parent window)
799 // and convert to Gtk coordinates.
800 DesktopIntRect anchorRect =
801 ToDesktopPixels(mPopupMoveToRectParams.mAnchorRect);
802 if (!WaylandPopupIsFirst()) {
803 DesktopIntPoint parent = WaylandGetParentPosition();
804 LOG(" subtract parent position from anchor [%d, %d]\n", parent.x.value,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " subtract parent position from anchor [%d, %d]\n"
, this->GetDebugTag().get(), parent.x.value, parent.y.value
); } } while (0)
805 parent.y.value)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " subtract parent position from anchor [%d, %d]\n"
, this->GetDebugTag().get(), parent.x.value, parent.y.value
); } } while (0)
;
806 anchorRect.MoveBy(-parent);
807 }
808
809 *aPopupAnchor = GdkRectangle{anchorRect.x, anchorRect.y, anchorRect.width,
810 anchorRect.height};
811 LOG(" anchored to rectangle [%d, %d] -> [%d x %d]", aPopupAnchor->x,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " anchored to rectangle [%d, %d] -> [%d x %d]"
, this->GetDebugTag().get(), aPopupAnchor->x, aPopupAnchor
->y, aPopupAnchor->width, aPopupAnchor->height); } }
while (0)
812 aPopupAnchor->y, aPopupAnchor->width, aPopupAnchor->height)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " anchored to rectangle [%d, %d] -> [%d x %d]"
, this->GetDebugTag().get(), aPopupAnchor->x, aPopupAnchor
->y, aPopupAnchor->width, aPopupAnchor->height); } }
while (0)
;
813
814 if (!WaylandPopupAnchorAdjustForParentPopup(aPopupAnchor, aOffset)) {
815 LOG(" can't use move-to-rect, anchor is not placed inside of parent "do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " can't use move-to-rect, anchor is not placed inside of parent "
"window", this->GetDebugTag().get()); } } while (0)
816 "window")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " can't use move-to-rect, anchor is not placed inside of parent "
"window", this->GetDebugTag().get()); } } while (0)
;
817 return false;
818 }
819
820 return true;
821}
822
823void nsWindowWayland::WaylandPopupPrepareForMove() {
824 LOG("nsWindowWayland::WaylandPopupPrepareForMove()")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupPrepareForMove()"
, this->GetDebugTag().get()); } } while (0)
;
825
826 if (mPopupType == PopupType::Tooltip) {
827 // Don't fiddle with tooltips type, just hide it before move-to-rect
828 if (mPopupUseMoveToRect && gtk_widget_is_visible(mShell)) {
829 HideWaylandPopupWindow(/* aTemporaryHide */ true,
830 /* aRemoveFromPopupList */ false);
831 }
832 LOG(" it's tooltip, quit")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " it's tooltip, quit", this->GetDebugTag
().get()); } } while (0)
;
833 return;
834 }
835
836 // See https://bugzilla.mozilla.org/show_bug.cgi?id=1785185#c8
837 // gtk_window_move() needs GDK_WINDOW_TYPE_HINT_UTILITY popup type.
838 // move-to-rect requires GDK_WINDOW_TYPE_HINT_POPUP_MENU popups type.
839 // We need to set it before map event when popup is hidden.
840 const GdkWindowTypeHint currentType =
841 gtk_window_get_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
842 const GdkWindowTypeHint requiredType = mPopupUseMoveToRect
843 ? GDK_WINDOW_TYPE_HINT_POPUP_MENU
844 : GDK_WINDOW_TYPE_HINT_UTILITY;
845
846 if (!mPopupUseMoveToRect && currentType == requiredType) {
847 LOG(" type matches and we're not forced to hide it, quit.")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " type matches and we're not forced to hide it, quit."
, this->GetDebugTag().get()); } } while (0)
;
848 return;
849 }
850
851 if (gtk_widget_is_visible(mShell)) {
852 HideWaylandPopupWindow(/* aTemporaryHide */ true,
853 /* aRemoveFromPopupList */ false);
854 }
855
856 if (currentType != requiredType) {
857 LOG(" set type %s",do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " set type %s", this->GetDebugTag
().get(), requiredType == GDK_WINDOW_TYPE_HINT_POPUP_MENU ? "MENU"
: "UTILITY"); } } while (0)
858 requiredType == GDK_WINDOW_TYPE_HINT_POPUP_MENU ? "MENU" : "UTILITY")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " set type %s", this->GetDebugTag
().get(), requiredType == GDK_WINDOW_TYPE_HINT_POPUP_MENU ? "MENU"
: "UTILITY"); } } while (0)
;
859 gtk_window_set_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), requiredType);
860 }
861}
862
863// Plain popup move on Wayland - simply place popup on given location.
864// We can't just call gtk_window_move() as it's not effective on visible
865// popups.
866void nsWindowWayland::WaylandPopupMovePlain(int aX, int aY) {
867 LOG("nsWindowWayland::WaylandPopupMovePlain(%d, %d)", aX, aY)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupMovePlain(%d, %d)"
, this->GetDebugTag().get(), aX, aY); } } while (0)
;
868
869 // We can directly move only popups based on wl_subsurface type.
870 MOZ_DIAGNOSTIC_ASSERT(gtk_window_get_type_hint(GTK_WINDOW(mShell)) ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gtk_window_get_type_hint(((((GtkWindow*) (void *) ((
mShell)))))) == GDK_WINDOW_TYPE_HINT_UTILITY || gtk_window_get_type_hint
(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_TOOLTIP
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(gtk_window_get_type_hint(((((GtkWindow*) (void *) ((
mShell)))))) == GDK_WINDOW_TYPE_HINT_UTILITY || gtk_window_get_type_hint
(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_TOOLTIP
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"gtk_window_get_type_hint(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_UTILITY || gtk_window_get_type_hint(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_TOOLTIP"
, "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp", 873);
AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gtk_window_get_type_hint(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_UTILITY || gtk_window_get_type_hint(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_TOOLTIP"
")"); do { MOZ_CrashSequence(__null, 873); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
871 GDK_WINDOW_TYPE_HINT_UTILITY ||do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gtk_window_get_type_hint(((((GtkWindow*) (void *) ((
mShell)))))) == GDK_WINDOW_TYPE_HINT_UTILITY || gtk_window_get_type_hint
(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_TOOLTIP
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(gtk_window_get_type_hint(((((GtkWindow*) (void *) ((
mShell)))))) == GDK_WINDOW_TYPE_HINT_UTILITY || gtk_window_get_type_hint
(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_TOOLTIP
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"gtk_window_get_type_hint(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_UTILITY || gtk_window_get_type_hint(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_TOOLTIP"
, "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp", 873);
AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gtk_window_get_type_hint(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_UTILITY || gtk_window_get_type_hint(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_TOOLTIP"
")"); do { MOZ_CrashSequence(__null, 873); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
872 gtk_window_get_type_hint(GTK_WINDOW(mShell)) ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gtk_window_get_type_hint(((((GtkWindow*) (void *) ((
mShell)))))) == GDK_WINDOW_TYPE_HINT_UTILITY || gtk_window_get_type_hint
(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_TOOLTIP
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(gtk_window_get_type_hint(((((GtkWindow*) (void *) ((
mShell)))))) == GDK_WINDOW_TYPE_HINT_UTILITY || gtk_window_get_type_hint
(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_TOOLTIP
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"gtk_window_get_type_hint(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_UTILITY || gtk_window_get_type_hint(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_TOOLTIP"
, "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp", 873);
AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gtk_window_get_type_hint(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_UTILITY || gtk_window_get_type_hint(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_TOOLTIP"
")"); do { MOZ_CrashSequence(__null, 873); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
873 GDK_WINDOW_TYPE_HINT_TOOLTIP)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gtk_window_get_type_hint(((((GtkWindow*) (void *) ((
mShell)))))) == GDK_WINDOW_TYPE_HINT_UTILITY || gtk_window_get_type_hint
(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_TOOLTIP
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(gtk_window_get_type_hint(((((GtkWindow*) (void *) ((
mShell)))))) == GDK_WINDOW_TYPE_HINT_UTILITY || gtk_window_get_type_hint
(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_TOOLTIP
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"gtk_window_get_type_hint(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_UTILITY || gtk_window_get_type_hint(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_TOOLTIP"
, "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp", 873);
AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "gtk_window_get_type_hint(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_UTILITY || gtk_window_get_type_hint(((((GtkWindow*) (void *) ((mShell)))))) == GDK_WINDOW_TYPE_HINT_TOOLTIP"
")"); do { MOZ_CrashSequence(__null, 873); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
874
875 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), aX, aY);
876
877 // gtk_window_move() can trick us. When widget is hidden gtk_window_move()
878 // does not move the widget but sets new widget coordinates when widget
879 // is mapped again.
880 //
881 // If popup used move-to-rect before
882 // (GdkWindow has POSITION_METHOD_MOVE_TO_RECT set), popup will use
883 // move-to-rect again when it's mapped and we'll get bogus move-to-rect
884 // callback.
885 //
886 // gdk_window_move() sets position_method to POSITION_METHOD_MOVE_RESIZE
887 // so we'll use plain move when popup is shown.
888 if (!gtk_widget_get_mapped(mShell)) {
889 if (GdkWindow* window = GetToplevelGdkWindow()) {
890 gdk_window_move(window, aX, aY);
891 }
892 }
893}
894
895static void NativeMoveResizeCallback(GdkWindow* window,
896 const GdkRectangle* flipped_rect,
897 const GdkRectangle* final_rect,
898 gboolean flipped_x, gboolean flipped_y,
899 void* aWindow) {
900 LOG_POPUP("[%p] NativeMoveResizeCallback flipped_x %d flipped_y %d\n",do { const ::mozilla::LogModule* moz_real_module = gWidgetPopupLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "[%p] NativeMoveResizeCallback flipped_x %d flipped_y %d\n"
, aWindow, flipped_x, flipped_y); } } while (0)
901 aWindow, flipped_x, flipped_y)do { const ::mozilla::LogModule* moz_real_module = gWidgetPopupLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "[%p] NativeMoveResizeCallback flipped_x %d flipped_y %d\n"
, aWindow, flipped_x, flipped_y); } } while (0)
;
902 LOG_POPUP("[%p] new position [%d, %d] -> [%d x %d]", aWindow,do { const ::mozilla::LogModule* moz_real_module = gWidgetPopupLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "[%p] new position [%d, %d] -> [%d x %d]"
, aWindow, final_rect->x, final_rect->y, final_rect->
width, final_rect->height); } } while (0)
903 final_rect->x, final_rect->y, final_rect->width,do { const ::mozilla::LogModule* moz_real_module = gWidgetPopupLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "[%p] new position [%d, %d] -> [%d x %d]"
, aWindow, final_rect->x, final_rect->y, final_rect->
width, final_rect->height); } } while (0)
904 final_rect->height)do { const ::mozilla::LogModule* moz_real_module = gWidgetPopupLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "[%p] new position [%d, %d] -> [%d x %d]"
, aWindow, final_rect->x, final_rect->y, final_rect->
width, final_rect->height); } } while (0)
;
905 MOZ_DIAGNOSTIC_ASSERT(nsWindow::FromGdkWindow(window), "Missing nsWindow!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(nsWindow::FromGdkWindow(window))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(nsWindow::FromGdkWindow(window
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("nsWindow::FromGdkWindow(window)" " (" "Missing nsWindow!" ")"
, "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp", 905);
AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "nsWindow::FromGdkWindow(window)"
") (" "Missing nsWindow!" ")"); do { MOZ_CrashSequence(__null
, 905); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
906 nsWindow::FromGdkWindow(window)
907 ->AsWayland()
908 ->NativeMoveResizeWaylandPopupCallback(final_rect, flipped_x, flipped_y);
909}
910
911void nsWindowWayland::WaylandPopupMoveImpl() {
912 // Available as of GTK 3.24+
913 static auto sGdkWindowMoveToRect = (void (*)(
914 GdkWindow*, const GdkRectangle*, GdkGravity, GdkGravity, GdkAnchorHints,
915 gint, gint))dlsym(RTLD_DEFAULT((void *) 0), "gdk_window_move_to_rect");
916
917 if (mPopupUseMoveToRect && !sGdkWindowMoveToRect) {
918 LOG("can't use move-to-rect due missing gdk_window_move_to_rect()")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "can't use move-to-rect due missing gdk_window_move_to_rect()"
, this->GetDebugTag().get()); } } while (0)
;
919 mPopupUseMoveToRect = false;
920 }
921
922 GdkRectangle gtkAnchorRect;
923 GdkPoint offset;
924 if (mPopupUseMoveToRect) {
925 mPopupUseMoveToRect =
926 WaylandPopupCheckAndGetAnchor(&gtkAnchorRect, &offset);
927 }
928
929 LOG("nsWindowWayland::WaylandPopupMove")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupMove"
, this->GetDebugTag().get()); } } while (0)
;
930 LOG(" popup use move to rect %d", mPopupUseMoveToRect)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " popup use move to rect %d", this
->GetDebugTag().get(), mPopupUseMoveToRect); } } while (0)
;
931
932 WaylandPopupPrepareForMove();
933
934 if (!mPopupUseMoveToRect) {
935 auto pos = mLastMoveRequest - WaylandGetParentPosition();
936 WaylandPopupMovePlain(pos.x, pos.y);
937 // Layout already should be aware of our bounds, since we didn't change it
938 // from the widget side for flipping or so.
939 return;
940 }
941
942 // Correct popup position now. It will be updated by gdk_window_move_to_rect()
943 // anyway but we need to set it now to avoid a race condition here.
944 WaylandPopupRemoveNegativePosition();
945
946 GdkWindow* gdkWindow = GetToplevelGdkWindow();
947 if (!g_signal_handler_find(gdkWindow, G_SIGNAL_MATCH_FUNC, 0, 0, nullptr,
948 FuncToGpointer(NativeMoveResizeCallback), this)) {
949 g_signal_connect(gdkWindow, "moved-to-rect",g_signal_connect_data ((gdkWindow), ("moved-to-rect"), (((GCallback
) (NativeMoveResizeCallback))), (this), __null, (GConnectFlags
) 0)
950 G_CALLBACK(NativeMoveResizeCallback), this)g_signal_connect_data ((gdkWindow), ("moved-to-rect"), (((GCallback
) (NativeMoveResizeCallback))), (this), __null, (GConnectFlags
) 0)
;
951 }
952 mWaitingForMoveToRectCallback = true;
953
954#ifdef MOZ_LOGGING1
955 if (LOG_ENABLED()((__builtin_expect(!!(mozilla::detail::log_test(gWidgetPopupLog
, mozilla::LogLevel::Debug)), 0)) || (__builtin_expect(!!(mozilla
::detail::log_test(gWidgetLog, mozilla::LogLevel::Debug)), 0)
))
) {
956 LOG(" Call move-to-rect")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " Call move-to-rect", this->GetDebugTag
().get()); } } while (0)
;
957 LOG(" Anchor rect [%d, %d] -> [%d x %d]", gtkAnchorRect.x, gtkAnchorRect.y,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " Anchor rect [%d, %d] -> [%d x %d]"
, this->GetDebugTag().get(), gtkAnchorRect.x, gtkAnchorRect
.y, gtkAnchorRect.width, gtkAnchorRect.height); } } while (0)
958 gtkAnchorRect.width, gtkAnchorRect.height)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " Anchor rect [%d, %d] -> [%d x %d]"
, this->GetDebugTag().get(), gtkAnchorRect.x, gtkAnchorRect
.y, gtkAnchorRect.width, gtkAnchorRect.height); } } while (0)
;
959 LOG(" Offset [%d, %d]", offset.x, offset.y)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " Offset [%d, %d]", this->GetDebugTag
().get(), offset.x, offset.y); } } while (0)
;
960 LOG(" AnchorType")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " AnchorType", this->GetDebugTag
().get()); } } while (0)
;
961 LogPopupGravity(mPopupMoveToRectParams.mAnchorRectType);
962 LOG(" PopupAnchorType")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " PopupAnchorType", this->GetDebugTag
().get()); } } while (0)
;
963 LogPopupGravity(mPopupMoveToRectParams.mPopupAnchorType);
964 LogPopupAnchorHints(mPopupMoveToRectParams.mHints);
965 }
966#endif
967
968 sGdkWindowMoveToRect(gdkWindow, &gtkAnchorRect,
969 mPopupMoveToRectParams.mAnchorRectType,
970 mPopupMoveToRectParams.mPopupAnchorType,
971 mPopupMoveToRectParams.mHints, offset.x, offset.y);
972}
973
974static void GetLayoutPopupWidgetChain(
975 nsTArray<nsIWidget*>* aLayoutWidgetHierarchy) {
976 nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
977 pm->GetSubmenuWidgetChain(aLayoutWidgetHierarchy);
978 aLayoutWidgetHierarchy->Reverse();
979}
980
981// Wayland keeps strong popup window hierarchy. We need to track active
982// (visible) popup windows and make sure we hide popup on the same level
983// before we open another one on that level. It means that every open
984// popup needs to have an unique parent.
985void nsWindowWayland::UpdateWaylandPopupHierarchy() {
986 LOG("nsWindowWayland::UpdateWaylandPopupHierarchy\n")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::UpdateWaylandPopupHierarchy\n"
, this->GetDebugTag().get()); } } while (0)
;
987
988 // This popup hasn't been added to popup hierarchy yet so no need to
989 // do any configurations.
990 if (!IsInPopupHierarchy()) {
991 LOG(" popup isn't in hierarchy\n")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " popup isn't in hierarchy\n", this
->GetDebugTag().get()); } } while (0)
;
992 return;
993 }
994
995#ifdef MOZ_LOGGING1
996 LogPopupHierarchy();
997 auto printPopupHierarchy = MakeScopeExit([&] { LogPopupHierarchy(); });
998#endif
999
1000 // Hide all tooltips without the last one. Tooltip can't be popup parent.
1001 mWaylandToplevel->WaylandPopupHideTooltips();
1002
1003 // See Bug 1709254 / https://gitlab.gnome.org/GNOME/gtk/-/issues/5092
1004 // It's possible that Wayland compositor refuses to show
1005 // a popup although Gtk claims it's visible.
1006 // We don't know if the popup is shown or not.
1007 // To avoid application crash refuse to create any child of such invisible
1008 // popup and close any child of it now.
1009 mWaylandToplevel->WaylandPopupCloseOrphanedPopups();
1010
1011 // Check if we have any remote content / overflow window in hierarchy.
1012 // We can't attach such widget on top of other popup.
1013 mWaylandToplevel->CloseAllPopupsBeforeRemotePopup();
1014
1015 // Check if your popup hierarchy matches layout hierarchy.
1016 // For instance we should not connect hamburger menu on top
1017 // of context menu.
1018 // Close all popups from different layout chains if possible.
1019 AutoTArray<nsIWidget*, 5> layoutPopupWidgetChain;
1020 GetLayoutPopupWidgetChain(&layoutPopupWidgetChain);
1021
1022 mWaylandToplevel->WaylandPopupHierarchyHideByLayout(&layoutPopupWidgetChain);
1023 mWaylandToplevel->WaylandPopupHierarchyValidateByLayout(
1024 &layoutPopupWidgetChain);
1025
1026 // Now we have Popup hierarchy complete.
1027 // Find first unchanged (and still open) popup to start with hierarchy
1028 // changes.
1029 nsWindowWayland* changedPopup = mWaylandToplevel->mWaylandPopupNext;
1030 while (changedPopup) {
1031 // Stop when parent of this popup was changed and we need to recalc
1032 // popup position.
1033 if (changedPopup->mPopupChanged) {
1034 break;
1035 }
1036 // Stop when this popup is closed.
1037 if (changedPopup->mPopupClosed) {
1038 break;
1039 }
1040 changedPopup = changedPopup->mWaylandPopupNext;
1041 }
1042
1043 // We don't need to recompute popup positions, quit now.
1044 if (!changedPopup) {
1045 LOG(" changed Popup is null, quit.\n")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " changed Popup is null, quit.\n",
this->GetDebugTag().get()); } } while (0)
;
1046 return;
1047 }
1048
1049 LOG(" first changed popup [%p]\n", (void*)changedPopup)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " first changed popup [%p]\n", this
->GetDebugTag().get(), (void*)changedPopup); } } while (0)
;
1050
1051 // Hide parent popups if necessary (there are layout discontinuity)
1052 // reposition the popup and show them again.
1053 changedPopup->WaylandPopupHierarchyHideTemporary();
1054
1055 nsWindowWayland* parentOfchangedPopup = nullptr;
1056 if (changedPopup->mPopupClosed) {
1057 parentOfchangedPopup = changedPopup->mWaylandPopupPrev;
1058 }
1059 changedPopup->WaylandPopupRemoveClosedPopups();
1060
1061 // It's possible that changedPopup was removed from widget hierarchy,
1062 // in such case use child popup of the removed one if there's any.
1063 if (!changedPopup->IsInPopupHierarchy()) {
1064 if (!parentOfchangedPopup || !parentOfchangedPopup->mWaylandPopupNext) {
1065 LOG(" last popup was removed, quit.\n")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " last popup was removed, quit.\n"
, this->GetDebugTag().get()); } } while (0)
;
1066 return;
1067 }
1068 changedPopup = parentOfchangedPopup->mWaylandPopupNext;
1069 }
1070
1071 GetLayoutPopupWidgetChain(&layoutPopupWidgetChain);
1072 mWaylandToplevel->WaylandPopupHierarchyValidateByLayout(
1073 &layoutPopupWidgetChain);
1074
1075 changedPopup->WaylandPopupHierarchyCalculatePositions();
1076
1077 nsWindowWayland* popup = changedPopup;
1078 while (popup) {
1079 const bool useMoveToRect = [&] {
1080 if (!StaticPrefs::widget_wayland_use_move_to_rect_AtStartup()) {
1081 return false; // Not available.
1082 }
1083 if (!popup->mPopupMatchesLayout) {
1084 // We can use move_to_rect only when popups in popup hierarchy matches
1085 // layout hierarchy as move_to_rect request that parent/child
1086 // popups are adjacent.
1087 return false;
1088 }
1089 if (!popup->WaylandPopupIsFirst() &&
1090 !popup->mWaylandPopupPrev->WaylandPopupIsFirst() &&
1091 !popup->mWaylandPopupPrev->mPopupUseMoveToRect) {
1092 // We can't use move-to-rect if there are more parents of
1093 // wl_subsurface popups types.
1094 //
1095 // It's because wl_subsurface is ignored by xdg_popup
1096 // (created by move-to-rect) so our popup scenario:
1097 //
1098 // toplevel -> xdg_popup(1) -> wl_subsurface(2) -> xdg_popup(3)
1099 //
1100 // looks for Wayland compositor as:
1101 //
1102 // toplevel -> xdg_popup(1) -> xdg_popup(3)
1103 //
1104 // If xdg_popup(1) and xdg_popup(3) are not connected
1105 // move-to-rect applied to xdg_popup(3) fails and we get missing popup.
1106 return false;
1107 }
1108 return true;
1109 }();
1110
1111 popup->mPopupUseMoveToRect = useMoveToRect;
1112
1113 LOG(" popup [%p] matches layout [%d] anchored [%d] first popup [%d] use "do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " popup [%p] matches layout [%d] anchored [%d] first popup [%d] use "
"move-to-rect %d\n", this->GetDebugTag().get(), popup, popup
->mPopupMatchesLayout, popup->mPopupAnchored, popup->
WaylandPopupIsFirst(), popup->mPopupUseMoveToRect); } } while
(0)
1114 "move-to-rect %d\n",do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " popup [%p] matches layout [%d] anchored [%d] first popup [%d] use "
"move-to-rect %d\n", this->GetDebugTag().get(), popup, popup
->mPopupMatchesLayout, popup->mPopupAnchored, popup->
WaylandPopupIsFirst(), popup->mPopupUseMoveToRect); } } while
(0)
1115 popup, popup->mPopupMatchesLayout, popup->mPopupAnchored,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " popup [%p] matches layout [%d] anchored [%d] first popup [%d] use "
"move-to-rect %d\n", this->GetDebugTag().get(), popup, popup
->mPopupMatchesLayout, popup->mPopupAnchored, popup->
WaylandPopupIsFirst(), popup->mPopupUseMoveToRect); } } while
(0)
1116 popup->WaylandPopupIsFirst(), popup->mPopupUseMoveToRect)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " popup [%p] matches layout [%d] anchored [%d] first popup [%d] use "
"move-to-rect %d\n", this->GetDebugTag().get(), popup, popup
->mPopupMatchesLayout, popup->mPopupAnchored, popup->
WaylandPopupIsFirst(), popup->mPopupUseMoveToRect); } } while
(0)
;
1117
1118 if (popup->mPopupUseMoveToRect && !popup->mPopupMatchesLayout) {
1119 gfxCriticalNotemozilla::gfx::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions
(false))
<< "Wayland: Positioned popup with missing anchor!";
1120 }
1121
1122 popup->WaylandPopupMoveImpl();
1123 popup->mPopupChanged = false;
1124 popup = popup->mWaylandPopupNext;
1125 }
1126
1127 changedPopup->WaylandPopupHierarchyShowTemporaryHidden();
1128}
1129
1130void nsWindowWayland::AppendPopupToHierarchyList(
1131 nsWindowWayland* aToplevelWindow) {
1132 mWaylandToplevel = aToplevelWindow;
1133
1134 auto* popup = aToplevelWindow;
1135 while (popup && popup->mWaylandPopupNext) {
1136 popup = popup->mWaylandPopupNext;
1137 }
1138 popup->mWaylandPopupNext = this;
1139
1140 mWaylandPopupPrev = popup;
1141 mWaylandPopupNext = nullptr;
1142 mPopupChanged = true;
1143 mPopupClosed = false;
1144}
1145
1146void nsWindowWayland::RemovePopupFromHierarchyList() {
1147 // We're already removed from the popup hierarchy
1148 if (!IsInPopupHierarchy()) {
1149 return;
1150 }
1151 mWaylandPopupPrev->mWaylandPopupNext = mWaylandPopupNext;
1152 if (mWaylandPopupNext) {
1153 mWaylandPopupNext->mWaylandPopupPrev = mWaylandPopupPrev;
1154 mWaylandPopupNext->mPopupChanged = true;
1155 }
1156 mWaylandPopupNext = mWaylandPopupPrev = nullptr;
1157}
1158
1159// Gtk refuses to map popup window with x < 0 && y < 0 relative coordinates
1160// see https://gitlab.gnome.org/GNOME/gtk/-/issues/4071
1161// as a workaround just fool around and place the popup temporary to 0,0.
1162bool nsWindowWayland::WaylandPopupRemoveNegativePosition(int* aX, int* aY) {
1163 // https://gitlab.gnome.org/GNOME/gtk/-/issues/4071 applies to temporary
1164 // windows only
1165 GdkWindow* window = GetToplevelGdkWindow();
1166 if (!window || gdk_window_get_window_type(window) != GDK_WINDOW_TEMP) {
1167 return false;
1168 }
1169
1170 LOG("nsWindowWayland::WaylandPopupRemoveNegativePosition()")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupRemoveNegativePosition()"
, this->GetDebugTag().get()); } } while (0)
;
1171
1172 int x, y;
1173 gtk_window_get_position(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), &x, &y);
1174 bool moveBack = (x < 0 && y < 0);
1175 if (moveBack) {
1176 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), 0, 0);
1177 if (aX) {
1178 *aX = x;
1179 }
1180 if (aY) {
1181 *aY = y;
1182 }
1183 }
1184
1185 gdk_window_get_geometry(window, &x, &y, nullptr, nullptr);
1186 if (x < 0 && y < 0) {
1187 gdk_window_move(window, 0, 0);
1188 }
1189
1190 return moveBack;
1191}
1192
1193void nsWindowWayland::ShowWaylandPopupWindow() {
1194 LOG("nsWindowWayland::ShowWaylandPopupWindow. Expected to see visible.")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::ShowWaylandPopupWindow. Expected to see visible."
, this->GetDebugTag().get()); } } while (0)
;
1195 MOZ_ASSERT(IsWaylandPopup())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsWaylandPopup())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsWaylandPopup()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("IsWaylandPopup()"
, "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp", 1195)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsWaylandPopup()" ")"
); do { MOZ_CrashSequence(__null, 1195); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1196
1197 if (!mPopupTrackInHierarchy) {
1198 LOG(" popup is not tracked in popup hierarchy, show it now")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " popup is not tracked in popup hierarchy, show it now"
, this->GetDebugTag().get()); } } while (0)
;
1199 gtk_widget_show(mShell);
1200 return;
1201 }
1202
1203 // Popup position was checked before gdk_window_move_to_rect() callback
1204 // so just show it.
1205 if (mPopupUseMoveToRect && mWaitingForMoveToRectCallback) {
1206 LOG(" active move-to-rect callback, show it as is")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " active move-to-rect callback, show it as is"
, this->GetDebugTag().get()); } } while (0)
;
1207 gtk_widget_show(mShell);
1208 return;
1209 }
1210
1211 if (gtk_widget_is_visible(mShell)) {
1212 LOG(" is already visible, quit")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " is already visible, quit", this->
GetDebugTag().get()); } } while (0)
;
1213 return;
1214 }
1215
1216 int x, y;
1217 bool moved = WaylandPopupRemoveNegativePosition(&x, &y);
1218 gtk_widget_show(mShell);
1219 if (moved) {
1220 LOG(" move back to (%d, %d) and show", x, y)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " move back to (%d, %d) and show",
this->GetDebugTag().get(), x, y); } } while (0)
;
1221 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), x, y);
1222 }
1223}
1224
1225void nsWindowWayland::WaylandPopupMarkAsClosed() {
1226 LOG("nsWindowWayland::WaylandPopupMarkAsClosed: [%p]\n", this)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupMarkAsClosed: [%p]\n"
, this->GetDebugTag().get(), this); } } while (0)
;
1227 mPopupClosed = true;
1228 // If we have any child popup window notify it about
1229 // parent switch.
1230 if (mWaylandPopupNext) {
1231 mWaylandPopupNext->mPopupChanged = true;
1232 }
1233}
1234
1235nsWindowWayland* nsWindowWayland::WaylandPopupFindLast(
1236 nsWindowWayland* aPopup) {
1237 while (aPopup && aPopup->mWaylandPopupNext) {
1238 aPopup = aPopup->mWaylandPopupNext;
1239 }
1240 return aPopup;
1241}
1242
1243// Hide and potentially removes popup from popup hierarchy.
1244void nsWindowWayland::HideWaylandPopupWindow(bool aTemporaryHide,
1245 bool aRemoveFromPopupList) {
1246 LOG("nsWindowWayland::HideWaylandPopupWindow: remove from list %d\n",do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::HideWaylandPopupWindow: remove from list %d\n"
, this->GetDebugTag().get(), aRemoveFromPopupList); } } while
(0)
1247 aRemoveFromPopupList)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::HideWaylandPopupWindow: remove from list %d\n"
, this->GetDebugTag().get(), aRemoveFromPopupList); } } while
(0)
;
1248 if (aRemoveFromPopupList) {
1249 RemovePopupFromHierarchyList();
1250 }
1251
1252 if (!mPopupClosed) {
1253 mPopupClosed = !aTemporaryHide;
1254 }
1255
1256 bool visible = gtk_widget_is_visible(mShell);
1257 LOG(" gtk_widget_is_visible() = %d\n", visible)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " gtk_widget_is_visible() = %d\n",
this->GetDebugTag().get(), visible); } } while (0)
;
1258
1259 // Restore only popups which are really visible
1260 mPopupTemporaryHidden = aTemporaryHide && visible;
1261
1262 // Hide only visible popups or popups closed pernamently.
1263 if (visible) {
1264 gtk_widget_hide(mShell);
1265
1266 // If there's pending Move-To-Rect callback and we hide the popup
1267 // the callback won't be called any more.
1268 mWaitingForMoveToRectCallback = false;
1269 }
1270
1271 if (mPopupClosed) {
1272 LOG(" Clearing mMoveToRectPopupSize\n")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " Clearing mMoveToRectPopupSize\n"
, this->GetDebugTag().get()); } } while (0)
;
1273 mMoveToRectPopupSize = {};
1274 }
1275}
1276
1277void nsWindowWayland::HideWaylandToplevelWindow() {
1278 LOG("nsWindowWayland::HideWaylandToplevelWindow: [%p]\n", this)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::HideWaylandToplevelWindow: [%p]\n"
, this->GetDebugTag().get(), this); } } while (0)
;
1279 if (mWaylandPopupNext) {
1280 auto* popup = WaylandPopupFindLast(mWaylandPopupNext);
1281 while (popup->mWaylandToplevel != nullptr) {
1282 nsWindowWayland* prev = popup->mWaylandPopupPrev;
1283 popup->HideWaylandPopupWindow(/* aTemporaryHide */ false,
1284 /* aRemoveFromPopupList */ true);
1285 popup = prev;
1286 }
1287 }
1288 gtk_widget_hide(mShell);
1289}
1290
1291void nsWindowWayland::ShowWaylandToplevelWindow() {
1292 MOZ_ASSERT(!IsWaylandPopup())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!IsWaylandPopup())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!IsWaylandPopup()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!IsWaylandPopup()"
, "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp", 1292)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsWaylandPopup()"
")"); do { MOZ_CrashSequence(__null, 1292); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1293 LOG("nsWindowWayland::ShowWaylandToplevelWindow")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::ShowWaylandToplevelWindow"
, this->GetDebugTag().get()); } } while (0)
;
1294 gtk_widget_show(mShell);
1295}
1296
1297void nsWindowWayland::WaylandPopupRemoveClosedPopups() {
1298 LOG("nsWindowWayland::WaylandPopupRemoveClosedPopups()")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupRemoveClosedPopups()"
, this->GetDebugTag().get()); } } while (0)
;
1299 auto* popup = this;
1300 while (popup) {
1301 nsWindowWayland* next = popup->mWaylandPopupNext;
1302 if (popup->mPopupClosed) {
1303 popup->HideWaylandPopupWindow(/* aTemporaryHide */ false,
1304 /* aRemoveFromPopupList */ true);
1305 }
1306 popup = next;
1307 }
1308}
1309
1310// Hide all tooltips except the latest one.
1311void nsWindowWayland::WaylandPopupHideTooltips() {
1312 LOG("nsWindowWayland::WaylandPopupHideTooltips")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupHideTooltips"
, this->GetDebugTag().get()); } } while (0)
;
1313 MOZ_ASSERT(mWaylandToplevel == nullptr, "Should be called on toplevel only!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mWaylandToplevel == nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mWaylandToplevel == nullptr)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mWaylandToplevel == nullptr"
" (" "Should be called on toplevel only!" ")", "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 1313); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWaylandToplevel == nullptr"
") (" "Should be called on toplevel only!" ")"); do { MOZ_CrashSequence
(__null, 1313); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1314
1315 nsWindowWayland* popup = mWaylandPopupNext;
1316 while (popup && popup->mWaylandPopupNext) {
1317 if (popup->mPopupType == PopupType::Tooltip) {
1318 LOG(" hidding tooltip [%p]", popup)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " hidding tooltip [%p]", this->
GetDebugTag().get(), popup); } } while (0)
;
1319 popup->WaylandPopupMarkAsClosed();
1320 }
1321 popup = popup->mWaylandPopupNext;
1322 }
1323}
1324
1325void nsWindowWayland::WaylandPopupCloseOrphanedPopups() {
1326 LOG("nsWindowWayland::WaylandPopupCloseOrphanedPopups")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupCloseOrphanedPopups"
, this->GetDebugTag().get()); } } while (0)
;
1327 MOZ_ASSERT(mWaylandToplevel == nullptr, "Should be called on toplevel only!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mWaylandToplevel == nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mWaylandToplevel == nullptr)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mWaylandToplevel == nullptr"
" (" "Should be called on toplevel only!" ")", "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 1327); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWaylandToplevel == nullptr"
") (" "Should be called on toplevel only!" ")"); do { MOZ_CrashSequence
(__null, 1327); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1328
1329 nsWindowWayland* popup = mWaylandPopupNext;
1330 bool dangling = false;
1331 while (popup) {
1332 if (!dangling && !MOZ_WL_SURFACE(popup->GetMozContainer())(((((MozContainer*) (void *) ((popup->GetMozContainer())))
))->wl->mSurface)
->IsVisible()) {
1333 LOG(" popup [%p] is waiting to show, close all child popups", popup)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " popup [%p] is waiting to show, close all child popups"
, this->GetDebugTag().get(), popup); } } while (0)
;
1334 dangling = true;
1335 } else if (dangling) {
1336 LOG(" popup [%p] is dangling, hide it", popup)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " popup [%p] is dangling, hide it"
, this->GetDebugTag().get(), popup); } } while (0)
;
1337 popup->WaylandPopupMarkAsClosed();
1338 }
1339 popup = popup->mWaylandPopupNext;
1340 }
1341}
1342
1343// We can't show popups with remote content or overflow popups
1344// on top of regular ones.
1345// If there's any remote popup opened, close all parent popups of it.
1346void nsWindowWayland::CloseAllPopupsBeforeRemotePopup() {
1347 LOG("nsWindowWayland::CloseAllPopupsBeforeRemotePopup")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::CloseAllPopupsBeforeRemotePopup"
, this->GetDebugTag().get()); } } while (0)
;
1348 MOZ_ASSERT(mWaylandToplevel == nullptr, "Should be called on toplevel only!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mWaylandToplevel == nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mWaylandToplevel == nullptr)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mWaylandToplevel == nullptr"
" (" "Should be called on toplevel only!" ")", "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 1348); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWaylandToplevel == nullptr"
") (" "Should be called on toplevel only!" ")"); do { MOZ_CrashSequence
(__null, 1348); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1349
1350 // Don't waste time when there's only one popup opened.
1351 if (!mWaylandPopupNext || mWaylandPopupNext->mWaylandPopupNext == nullptr) {
1352 return;
1353 }
1354
1355 // Find the first opened remote content popup
1356 nsWindowWayland* remotePopup = mWaylandPopupNext;
1357 while (remotePopup) {
1358 if (remotePopup->HasRemoteContent() ||
1359 remotePopup->IsWidgetOverflowWindow()) {
1360 LOG(" remote popup [%p]", remotePopup)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " remote popup [%p]", this->GetDebugTag
().get(), remotePopup); } } while (0)
;
1361 break;
1362 }
1363 remotePopup = remotePopup->mWaylandPopupNext;
1364 }
1365
1366 if (!remotePopup) {
1367 return;
1368 }
1369
1370 // ...hide opened popups before the remote one.
1371 nsWindowWayland* popup = mWaylandPopupNext;
1372 while (popup && popup != remotePopup) {
1373 LOG(" hidding popup [%p]", popup)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " hidding popup [%p]", this->GetDebugTag
().get(), popup); } } while (0)
;
1374 popup->WaylandPopupMarkAsClosed();
1375 popup = popup->mWaylandPopupNext;
1376 }
1377}
1378
1379// Compare 'this' popup position in Wayland widget hierarchy
1380// (mWaylandPopupPrev/mWaylandPopupNext) with
1381// 'this' popup position in layout hierarchy.
1382//
1383// When aMustMatchParent is true we also request
1384// 'this' parents match, i.e. 'this' has the same parent in
1385// both layout and widget hierarchy.
1386bool nsWindowWayland::IsPopupInLayoutPopupChain(
1387 nsTArray<nsIWidget*>* aLayoutWidgetHierarchy, bool aMustMatchParent) {
1388 int len = (int)aLayoutWidgetHierarchy->Length();
1389 for (int i = 0; i < len; i++) {
1390 if (this == (*aLayoutWidgetHierarchy)[i]) {
1391 if (!aMustMatchParent) {
1392 return true;
1393 }
1394
1395 // Find correct parent popup for 'this' according to widget
1396 // hierarchy. That means we need to skip closed popups.
1397 nsWindowWayland* parentPopup = nullptr;
1398 if (mWaylandPopupPrev != mWaylandToplevel) {
1399 parentPopup = mWaylandPopupPrev;
1400 while (parentPopup != mWaylandToplevel && parentPopup->mPopupClosed) {
1401 parentPopup = parentPopup->mWaylandPopupPrev;
1402 }
1403 }
1404
1405 if (i == 0) {
1406 // We found 'this' popups as a first popup in layout hierarchy.
1407 // It matches layout hierarchy if it's first widget also in
1408 // wayland widget hierarchy (i.e. parent is null).
1409 return parentPopup == nullptr;
1410 }
1411
1412 return parentPopup == (*aLayoutWidgetHierarchy)[i - 1];
1413 }
1414 }
1415 return false;
1416}
1417
1418// Configure Wayland popup. If true is returned we need to track popup
1419// in popup hierarchy. Otherwise we just show it as is.
1420bool nsWindowWayland::WaylandPopupConfigure() {
1421 if (mIsDragPopup) {
1422 return false;
1423 }
1424
1425 // Don't track popups without frame
1426 nsMenuPopupFrame* popupFrame = GetPopupFrame();
1427 if (!popupFrame) {
1428 return false;
1429 }
1430
1431 // Popup state can be changed, see Bug 1728952.
1432 bool permanentStateMatches =
1433 mPopupTrackInHierarchy == !WaylandPopupIsPermanent();
1434
1435 // Popup permanent state (noautohide attribute) can change during popup life.
1436 if (mPopupTrackInHierarchyConfigured && permanentStateMatches) {
1437 return mPopupTrackInHierarchy;
1438 }
1439
1440 // Configure persistent popup params only once.
1441 // WaylandPopupIsAnchored() can give it wrong value after
1442 // nsMenuPopupFrame::MoveTo() call which we use in move-to-rect callback
1443 // to position popup after wayland position change.
1444 if (!mPopupTrackInHierarchyConfigured) {
1445 mPopupAnchored = WaylandPopupIsAnchored();
1446 mPopupContextMenu = WaylandPopupIsContextMenu();
1447 }
1448
1449 LOG("nsWindowWayland::WaylandPopupConfigure tracked %d anchored %d hint %d "do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupConfigure tracked %d anchored %d hint %d "
"permanent %d\n", this->GetDebugTag().get(), mPopupTrackInHierarchy
, mPopupAnchored, int(mPopupType), WaylandPopupIsPermanent())
; } } while (0)
1450 "permanent %d\n",do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupConfigure tracked %d anchored %d hint %d "
"permanent %d\n", this->GetDebugTag().get(), mPopupTrackInHierarchy
, mPopupAnchored, int(mPopupType), WaylandPopupIsPermanent())
; } } while (0)
1451 mPopupTrackInHierarchy, mPopupAnchored, int(mPopupType),do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupConfigure tracked %d anchored %d hint %d "
"permanent %d\n", this->GetDebugTag().get(), mPopupTrackInHierarchy
, mPopupAnchored, int(mPopupType), WaylandPopupIsPermanent())
; } } while (0)
1452 WaylandPopupIsPermanent())do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupConfigure tracked %d anchored %d hint %d "
"permanent %d\n", this->GetDebugTag().get(), mPopupTrackInHierarchy
, mPopupAnchored, int(mPopupType), WaylandPopupIsPermanent())
; } } while (0)
;
1453
1454 // Permanent state changed and popup is mapped.
1455 // We need to switch popup type but that's done when popup is mapped
1456 // by Gtk so we need to unmap the popup here.
1457 // It will be mapped again by gtk_widget_show().
1458 if (!permanentStateMatches && mIsMapped) {
1459 LOG(" permanent state change from %d to %d, unmapping",do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " permanent state change from %d to %d, unmapping"
, this->GetDebugTag().get(), mPopupTrackInHierarchy, !WaylandPopupIsPermanent
()); } } while (0)
1460 mPopupTrackInHierarchy, !WaylandPopupIsPermanent())do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " permanent state change from %d to %d, unmapping"
, this->GetDebugTag().get(), mPopupTrackInHierarchy, !WaylandPopupIsPermanent
()); } } while (0)
;
1461 gtk_widget_unmap(mShell);
1462 }
1463
1464 mPopupTrackInHierarchy = !WaylandPopupIsPermanent();
1465 LOG(" tracked in hierarchy %d\n", mPopupTrackInHierarchy)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " tracked in hierarchy %d\n", this
->GetDebugTag().get(), mPopupTrackInHierarchy); } } while (
0)
;
1466
1467 // See gdkwindow-wayland.c and
1468 // should_map_as_popup()/should_map_as_subsurface()
1469 GdkWindowTypeHint gtkTypeHint;
1470 switch (mPopupType) {
1471 case PopupType::Menu:
1472 // GDK_WINDOW_TYPE_HINT_POPUP_MENU is mapped as xdg_popup by default.
1473 // We use this type for all menu popups.
1474 gtkTypeHint = GDK_WINDOW_TYPE_HINT_POPUP_MENU;
1475 LOG(" popup type Menu")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " popup type Menu", this->GetDebugTag
().get()); } } while (0)
;
1476 break;
1477 case PopupType::Tooltip:
1478 gtkTypeHint = GDK_WINDOW_TYPE_HINT_TOOLTIP;
1479 LOG(" popup type Tooltip")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " popup type Tooltip", this->GetDebugTag
().get()); } } while (0)
;
1480 break;
1481 default:
1482 gtkTypeHint = GDK_WINDOW_TYPE_HINT_UTILITY;
1483 LOG(" popup type Utility")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " popup type Utility", this->GetDebugTag
().get()); } } while (0)
;
1484 break;
1485 }
1486
1487 if (!mPopupTrackInHierarchy) {
1488 // GDK_WINDOW_TYPE_HINT_UTILITY is mapped as wl_subsurface
1489 // by default.
1490 LOG(" not tracked in popup hierarchy, switch to Utility")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " not tracked in popup hierarchy, switch to Utility"
, this->GetDebugTag().get()); } } while (0)
;
1491 gtkTypeHint = GDK_WINDOW_TYPE_HINT_UTILITY;
1492 }
1493 gtk_window_set_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), gtkTypeHint);
1494
1495 mPopupTrackInHierarchyConfigured = true;
1496 return mPopupTrackInHierarchy;
1497}
1498
1499bool nsWindowWayland::IsInPopupHierarchy() {
1500 return mPopupTrackInHierarchy && mWaylandToplevel && mWaylandPopupPrev;
1501}
1502
1503void nsWindowWayland::AddWindowToPopupHierarchy() {
1504 LOG("nsWindowWayland::AddWindowToPopupHierarchy\n")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::AddWindowToPopupHierarchy\n"
, this->GetDebugTag().get()); } } while (0)
;
1505 if (!GetPopupFrame()) {
1506 LOG(" Window without frame cannot be added as popup!\n")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " Window without frame cannot be added as popup!\n"
, this->GetDebugTag().get()); } } while (0)
;
1507 return;
1508 }
1509
1510 // Check if we're already in the hierarchy
1511 if (!IsInPopupHierarchy()) {
1512 mWaylandToplevel =
1513 nsWindowWayland::FromWidget(GetTopLevelWidget())->AsWayland();
1514 if (mWaylandToplevel) {
1515 AppendPopupToHierarchyList(mWaylandToplevel);
1516 }
1517 }
1518}
1519
1520// Hide popups which are not in popup chain.
1521void nsWindowWayland::WaylandPopupHierarchyHideByLayout(
1522 nsTArray<nsIWidget*>* aLayoutWidgetHierarchy) {
1523 LOG("nsWindowWayland::WaylandPopupHierarchyHideByLayout")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupHierarchyHideByLayout"
, this->GetDebugTag().get()); } } while (0)
;
1524 MOZ_ASSERT(mWaylandToplevel == nullptr, "Should be called on toplevel only!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mWaylandToplevel == nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mWaylandToplevel == nullptr)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mWaylandToplevel == nullptr"
" (" "Should be called on toplevel only!" ")", "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 1524); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWaylandToplevel == nullptr"
") (" "Should be called on toplevel only!" ")"); do { MOZ_CrashSequence
(__null, 1524); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1525
1526 // Hide all popups which are not in layout popup chain
1527 nsWindowWayland* popup = mWaylandPopupNext;
1528 while (popup) {
1529 // Don't check closed popups and drag source popups and tooltips.
1530 if (!popup->mPopupClosed && popup->mPopupType != PopupType::Tooltip &&
1531 !popup->mSourceDragContext) {
1532 if (!popup->IsPopupInLayoutPopupChain(aLayoutWidgetHierarchy,
1533 /* aMustMatchParent */ false)) {
1534 LOG(" hidding popup [%p]", popup)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " hidding popup [%p]", this->GetDebugTag
().get(), popup); } } while (0)
;
1535 popup->WaylandPopupMarkAsClosed();
1536 }
1537 }
1538 popup = popup->mWaylandPopupNext;
1539 }
1540}
1541
1542// Mark popups outside of layout hierarchy
1543void nsWindowWayland::WaylandPopupHierarchyValidateByLayout(
1544 nsTArray<nsIWidget*>* aLayoutWidgetHierarchy) {
1545 LOG("nsWindowWayland::WaylandPopupHierarchyValidateByLayout")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupHierarchyValidateByLayout"
, this->GetDebugTag().get()); } } while (0)
;
1546 nsWindowWayland* popup = mWaylandPopupNext;
1547 while (popup) {
1548 if (popup->mPopupType == PopupType::Tooltip) {
1549 popup->mPopupMatchesLayout = true;
1550 } else if (!popup->mPopupClosed) {
1551 popup->mPopupMatchesLayout = popup->IsPopupInLayoutPopupChain(
1552 aLayoutWidgetHierarchy, /* aMustMatchParent */ true);
1553 LOG(" popup [%p] parent window [%p] matches layout %d\n", (void*)popup,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " popup [%p] parent window [%p] matches layout %d\n"
, this->GetDebugTag().get(), (void*)popup, (void*)popup->
mWaylandPopupPrev, popup->mPopupMatchesLayout); } } while (
0)
1554 (void*)popup->mWaylandPopupPrev, popup->mPopupMatchesLayout)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " popup [%p] parent window [%p] matches layout %d\n"
, this->GetDebugTag().get(), (void*)popup, (void*)popup->
mWaylandPopupPrev, popup->mPopupMatchesLayout); } } while (
0)
;
1555 }
1556 popup = popup->mWaylandPopupNext;
1557 }
1558}
1559
1560void nsWindowWayland::WaylandPopupHierarchyHideTemporary() {
1561 LOG("nsWindowWayland::WaylandPopupHierarchyHideTemporary()")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupHierarchyHideTemporary()"
, this->GetDebugTag().get()); } } while (0)
;
1562 nsWindowWayland* popup = WaylandPopupFindLast(this);
1563 while (popup && popup != this) {
1564 LOG(" temporary hidding popup [%p]", popup)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " temporary hidding popup [%p]", this
->GetDebugTag().get(), popup); } } while (0)
;
1565 nsWindowWayland* prev = popup->mWaylandPopupPrev;
1566 popup->HideWaylandPopupWindow(/* aTemporaryHide */ true,
1567 /* aRemoveFromPopupList */ false);
1568 popup = prev;
1569 }
1570}
1571
1572void nsWindowWayland::WaylandPopupHierarchyShowTemporaryHidden() {
1573 LOG("nsWindowWayland::WaylandPopupHierarchyShowTemporaryHidden()")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupHierarchyShowTemporaryHidden()"
, this->GetDebugTag().get()); } } while (0)
;
1574 nsWindowWayland* popup = this;
1575 while (popup) {
1576 if (popup->mPopupTemporaryHidden) {
1577 popup->mPopupTemporaryHidden = false;
1578 LOG(" showing temporary hidden popup [%p]", popup)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " showing temporary hidden popup [%p]"
, this->GetDebugTag().get(), popup); } } while (0)
;
1579 popup->ShowWaylandPopupWindow();
1580 }
1581 popup = popup->mWaylandPopupNext;
1582 }
1583}
1584
1585void nsWindowWayland::WaylandPopupHierarchyCalculatePositions() {
1586 LOG("nsWindowWayland::WaylandPopupHierarchyCalculatePositions()")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupHierarchyCalculatePositions()"
, this->GetDebugTag().get()); } } while (0)
;
1587
1588 // Set widget hierarchy in Gtk
1589 nsWindowWayland* popup = mWaylandToplevel->mWaylandPopupNext;
1590 while (popup) {
1591 LOG(" popup [%p] set parent window [%p]", (void*)popup,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " popup [%p] set parent window [%p]"
, this->GetDebugTag().get(), (void*)popup, (void*)popup->
mWaylandPopupPrev); } } while (0)
1592 (void*)popup->mWaylandPopupPrev)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " popup [%p] set parent window [%p]"
, this->GetDebugTag().get(), (void*)popup, (void*)popup->
mWaylandPopupPrev); } } while (0)
;
1593 GtkWindowSetTransientFor(GTK_WINDOW(popup->mShell)((((GtkWindow*) (void *) ((popup->mShell))))),
1594 GTK_WINDOW(popup->mWaylandPopupPrev->mShell)((((GtkWindow*) (void *) ((popup->mWaylandPopupPrev->mShell
)))))
);
1595 popup = popup->mWaylandPopupNext;
1596 }
1597}
1598
1599bool nsWindowWayland::WaylandPopupIsContextMenu() {
1600 nsMenuPopupFrame* popupFrame = GetPopupFrame();
1601 if (!popupFrame) {
1602 return false;
1603 }
1604 return popupFrame->IsContextMenu();
1605}
1606
1607bool nsWindowWayland::WaylandPopupIsPermanent() {
1608 nsMenuPopupFrame* popupFrame = GetPopupFrame();
1609 if (!popupFrame) {
1610 // We can always hide popups without frames.
1611 return false;
1612 }
1613 return popupFrame->IsNoAutoHide();
1614}
1615
1616bool nsWindowWayland::WaylandPopupIsAnchored() {
1617 nsMenuPopupFrame* popupFrame = GetPopupFrame();
1618 if (!popupFrame) {
1619 // We can always hide popups without frames.
1620 return false;
1621 }
1622 return !!popupFrame->GetAnchor();
1623}
1624
1625bool nsWindowWayland::IsWidgetOverflowWindow() {
1626 if (auto* frame = GetPopupFrame()) {
1627 if (nsAtom* id = frame->GetContent()->GetID()) {
1628 return id->Equals(u"widget-overflow"_ns);
1629 }
1630 }
1631 return false;
1632}
1633
1634bool nsWindowWayland::WaylandPopupIsFirst() {
1635 return !mWaylandPopupPrev || !mWaylandPopupPrev->mWaylandToplevel;
1636}
1637
1638DesktopIntPoint nsWindowWayland::WaylandGetParentPosition() const {
1639 MOZ_ASSERT(IsPopup())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsPopup())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsPopup()))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("IsPopup()", "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 1639); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsPopup()" ")"
); do { MOZ_CrashSequence(__null, 1639); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1640 auto* window = GetEffectiveParent();
1641 if (NS_WARN_IF(!window)NS_warn_if_impl(!window, "!window", "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 1641)
|| !window->IsPopup()) {
1642 return {0, 0};
1643 }
1644 // If our parent is a popup, offset to our toplevel bounds (note that in
1645 // Wayland there's no global coordinate space, so our "screen" offset is
1646 // really relative to the origin of our toplevel).
1647 DesktopIntPoint offset = window->WidgetToScreenOffsetUnscaled();
1648 LOG("nsWindowWayland::WaylandGetParentPosition() [%d, %d]\n", offset.x.value,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandGetParentPosition() [%d, %d]\n"
, this->GetDebugTag().get(), offset.x.value, offset.y.value
); } } while (0)
1649 offset.y.value)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandGetParentPosition() [%d, %d]\n"
, this->GetDebugTag().get(), offset.x.value, offset.y.value
); } } while (0)
;
1650 return offset;
1651}
1652
1653#ifdef MOZ_LOGGING1
1654void nsWindowWayland::LogPopupHierarchy() {
1655 if (!LOG_ENABLED()((__builtin_expect(!!(mozilla::detail::log_test(gWidgetPopupLog
, mozilla::LogLevel::Debug)), 0)) || (__builtin_expect(!!(mozilla
::detail::log_test(gWidgetLog, mozilla::LogLevel::Debug)), 0)
))
) {
1656 return;
1657 }
1658
1659 LOG("Widget Popup Hierarchy:\n")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "Widget Popup Hierarchy:\n", this->
GetDebugTag().get()); } } while (0)
;
1660 if (!mWaylandToplevel->mWaylandPopupNext) {
1661 LOG(" Empty\n")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " Empty\n", this->GetDebugTag
().get()); } } while (0)
;
1662 } else {
1663 int indent = 4;
1664 nsWindowWayland* popup = mWaylandToplevel->mWaylandPopupNext;
1665 while (popup) {
1666 nsPrintfCString indentString("%*s", indent, " ");
1667 LOG("%s %s %s nsWindow [%p] Permanent %d ContextMenu %d "do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "%s %s %s nsWindow [%p] Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", this->GetDebugTag
().get(), indentString.get(), popup->GetFrameTag().get(), popup
->GetPopupTypeName().get(), popup, popup->WaylandPopupIsPermanent
(), popup->mPopupContextMenu, popup->mPopupAnchored, gtk_widget_is_visible
(popup->mShell), popup->mPopupUseMoveToRect); } } while
(0)
1668 "Anchored %d Visible %d MovedByRect %d\n",do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "%s %s %s nsWindow [%p] Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", this->GetDebugTag
().get(), indentString.get(), popup->GetFrameTag().get(), popup
->GetPopupTypeName().get(), popup, popup->WaylandPopupIsPermanent
(), popup->mPopupContextMenu, popup->mPopupAnchored, gtk_widget_is_visible
(popup->mShell), popup->mPopupUseMoveToRect); } } while
(0)
1669 indentString.get(), popup->GetFrameTag().get(),do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "%s %s %s nsWindow [%p] Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", this->GetDebugTag
().get(), indentString.get(), popup->GetFrameTag().get(), popup
->GetPopupTypeName().get(), popup, popup->WaylandPopupIsPermanent
(), popup->mPopupContextMenu, popup->mPopupAnchored, gtk_widget_is_visible
(popup->mShell), popup->mPopupUseMoveToRect); } } while
(0)
1670 popup->GetPopupTypeName().get(), popup,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "%s %s %s nsWindow [%p] Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", this->GetDebugTag
().get(), indentString.get(), popup->GetFrameTag().get(), popup
->GetPopupTypeName().get(), popup, popup->WaylandPopupIsPermanent
(), popup->mPopupContextMenu, popup->mPopupAnchored, gtk_widget_is_visible
(popup->mShell), popup->mPopupUseMoveToRect); } } while
(0)
1671 popup->WaylandPopupIsPermanent(), popup->mPopupContextMenu,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "%s %s %s nsWindow [%p] Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", this->GetDebugTag
().get(), indentString.get(), popup->GetFrameTag().get(), popup
->GetPopupTypeName().get(), popup, popup->WaylandPopupIsPermanent
(), popup->mPopupContextMenu, popup->mPopupAnchored, gtk_widget_is_visible
(popup->mShell), popup->mPopupUseMoveToRect); } } while
(0)
1672 popup->mPopupAnchored, gtk_widget_is_visible(popup->mShell),do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "%s %s %s nsWindow [%p] Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", this->GetDebugTag
().get(), indentString.get(), popup->GetFrameTag().get(), popup
->GetPopupTypeName().get(), popup, popup->WaylandPopupIsPermanent
(), popup->mPopupContextMenu, popup->mPopupAnchored, gtk_widget_is_visible
(popup->mShell), popup->mPopupUseMoveToRect); } } while
(0)
1673 popup->mPopupUseMoveToRect)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "%s %s %s nsWindow [%p] Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", this->GetDebugTag
().get(), indentString.get(), popup->GetFrameTag().get(), popup
->GetPopupTypeName().get(), popup, popup->WaylandPopupIsPermanent
(), popup->mPopupContextMenu, popup->mPopupAnchored, gtk_widget_is_visible
(popup->mShell), popup->mPopupUseMoveToRect); } } while
(0)
;
1674 indent += 4;
1675 popup = popup->mWaylandPopupNext;
1676 }
1677 }
1678
1679 LOG("Layout Popup Hierarchy:\n")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "Layout Popup Hierarchy:\n", this->
GetDebugTag().get()); } } while (0)
;
1680 AutoTArray<nsIWidget*, 5> widgetChain;
1681 GetLayoutPopupWidgetChain(&widgetChain);
1682 if (widgetChain.Length() == 0) {
1683 LOG(" Empty\n")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " Empty\n", this->GetDebugTag
().get()); } } while (0)
;
1684 } else {
1685 for (unsigned long i = 0; i < widgetChain.Length(); i++) {
1686 nsWindowWayland* window = static_cast<nsWindowWayland*>(widgetChain[i]);
1687 nsPrintfCString indentString("%*s", (int)(i + 1) * 4, " ");
1688 if (window) {
1689 LOG("%s %s %s nsWindow [%p] Permanent %d ContextMenu %d "do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "%s %s %s nsWindow [%p] Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", this->GetDebugTag
().get(), indentString.get(), window->GetFrameTag().get(),
window->GetPopupTypeName().get(), window, window->WaylandPopupIsPermanent
(), window->mPopupContextMenu, window->mPopupAnchored, gtk_widget_is_visible
(window->mShell), window->mPopupUseMoveToRect); } } while
(0)
1690 "Anchored %d Visible %d MovedByRect %d\n",do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "%s %s %s nsWindow [%p] Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", this->GetDebugTag
().get(), indentString.get(), window->GetFrameTag().get(),
window->GetPopupTypeName().get(), window, window->WaylandPopupIsPermanent
(), window->mPopupContextMenu, window->mPopupAnchored, gtk_widget_is_visible
(window->mShell), window->mPopupUseMoveToRect); } } while
(0)
1691 indentString.get(), window->GetFrameTag().get(),do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "%s %s %s nsWindow [%p] Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", this->GetDebugTag
().get(), indentString.get(), window->GetFrameTag().get(),
window->GetPopupTypeName().get(), window, window->WaylandPopupIsPermanent
(), window->mPopupContextMenu, window->mPopupAnchored, gtk_widget_is_visible
(window->mShell), window->mPopupUseMoveToRect); } } while
(0)
1692 window->GetPopupTypeName().get(), window,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "%s %s %s nsWindow [%p] Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", this->GetDebugTag
().get(), indentString.get(), window->GetFrameTag().get(),
window->GetPopupTypeName().get(), window, window->WaylandPopupIsPermanent
(), window->mPopupContextMenu, window->mPopupAnchored, gtk_widget_is_visible
(window->mShell), window->mPopupUseMoveToRect); } } while
(0)
1693 window->WaylandPopupIsPermanent(), window->mPopupContextMenu,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "%s %s %s nsWindow [%p] Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", this->GetDebugTag
().get(), indentString.get(), window->GetFrameTag().get(),
window->GetPopupTypeName().get(), window, window->WaylandPopupIsPermanent
(), window->mPopupContextMenu, window->mPopupAnchored, gtk_widget_is_visible
(window->mShell), window->mPopupUseMoveToRect); } } while
(0)
1694 window->mPopupAnchored, gtk_widget_is_visible(window->mShell),do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "%s %s %s nsWindow [%p] Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", this->GetDebugTag
().get(), indentString.get(), window->GetFrameTag().get(),
window->GetPopupTypeName().get(), window, window->WaylandPopupIsPermanent
(), window->mPopupContextMenu, window->mPopupAnchored, gtk_widget_is_visible
(window->mShell), window->mPopupUseMoveToRect); } } while
(0)
1695 window->mPopupUseMoveToRect)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "%s %s %s nsWindow [%p] Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", this->GetDebugTag
().get(), indentString.get(), window->GetFrameTag().get(),
window->GetPopupTypeName().get(), window, window->WaylandPopupIsPermanent
(), window->mPopupContextMenu, window->mPopupAnchored, gtk_widget_is_visible
(window->mShell), window->mPopupUseMoveToRect); } } while
(0)
;
1696 } else {
1697 LOG("%s null window\n", indentString.get())do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "%s null window\n", this->GetDebugTag
().get(), indentString.get()); } } while (0)
;
1698 }
1699 }
1700 }
1701}
1702#endif
1703
1704// When popup is repositioned by widget code, we need to notify
1705// layout about it. It's because we control popup placement
1706// on widget on Wayland so layout may have old popup size/coordinates.
1707void nsWindowWayland::WaylandPopupPropagateChangesToLayout(bool aMove,
1708 bool aResize) {
1709 LOG("nsWindowWayland::WaylandPopupPropagateChangesToLayout()")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupPropagateChangesToLayout()"
, this->GetDebugTag().get()); } } while (0)
;
1710
1711 if (aResize) {
1712 LOG(" needSizeUpdate\n")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " needSizeUpdate\n", this->GetDebugTag
().get()); } } while (0)
;
1713 if (nsMenuPopupFrame* popupFrame = GetPopupFrame()) {
1714 RefPtr<PresShell> presShell = popupFrame->PresShell();
1715 presShell->FrameNeedsReflow(popupFrame, IntrinsicDirty::None,
1716 NS_FRAME_IS_DIRTY);
1717 }
1718 }
1719 if (aMove) {
1720 LOG(" needPositionUpdate, bounds [%d, %d]", mClientArea.x, mClientArea.y)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " needPositionUpdate, bounds [%d, %d]"
, this->GetDebugTag().get(), mClientArea.x, mClientArea.y)
; } } while (0)
;
1721 NotifyWindowMoved(mClientArea.TopLeft(), ByMoveToRect::Yes);
1722 }
1723}
1724
1725void nsWindowWayland::NativeMoveResizeWaylandPopupCallback(
1726 const GdkRectangle* aFinalSize, bool aFlippedX, bool aFlippedY) {
1727 // We're getting move-to-rect callback without move-to-rect call.
1728 // That indicates a compositor bug. It happens when a window is hidden and
1729 // shown again before move-to-rect callback is fired.
1730 // It may lead to incorrect popup placement as we may call
1731 // gtk_window_move() between hide & show.
1732 // See Bug 1777919, 1789581.
1733#if MOZ_LOGGING1
1734 if (!mWaitingForMoveToRectCallback) {
1735 LOG(" Bogus move-to-rect callback! Expect wrong popup coordinates.")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " Bogus move-to-rect callback! Expect wrong popup coordinates."
, this->GetDebugTag().get()); } } while (0)
;
1736 }
1737#endif
1738
1739 mWaitingForMoveToRectCallback = false;
1740
1741 bool movedByLayout = mMovedAfterMoveToRect;
1742 bool resizedByLayout = mResizedAfterMoveToRect;
1743
1744 // Popup was moved between move-to-rect call and move-to-rect callback
1745 // and the coordinates from move-to-rect callback are outdated.
1746 if (movedByLayout || resizedByLayout) {
1747 LOG(" Another move/resize called during waiting for callback\n")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " Another move/resize called during waiting for callback\n"
, this->GetDebugTag().get()); } } while (0)
;
1748 mMovedAfterMoveToRect = false;
1749 mResizedAfterMoveToRect = false;
1750 // Fire another round of move/resize to reflect latest request from layout.
1751 NativeMoveResize(movedByLayout, resizedByLayout);
1752 return;
1753 }
1754
1755 const GdkRectangle finalGdkRect = [&] {
1756 GdkRectangle finalRect = *aFinalSize;
1757 DesktopIntPoint parent = WaylandGetParentPosition();
1758 finalRect.x += parent.x;
1759 finalRect.y += parent.y;
1760 return finalRect;
1761 }();
1762
1763 // With fractional scaling, our devPx->Gdk->devPx conversion might not
1764 // perfectly round-trip. Compare gdk rects to check whether size or positions
1765 // have changed from what we'd request otherwise, in order to avoid
1766 // flickering.
1767 const auto currentRect = mClientArea;
1768 auto scale = GdkCeiledScaleFactor();
1769 auto IsSubstantiallyDifferent = [=](gint a, gint b) {
1770 return std::abs(a - b) > scale;
1771 };
1772
1773 const bool needsPositionUpdate =
1774 IsSubstantiallyDifferent(finalGdkRect.x, currentRect.x) ||
1775 IsSubstantiallyDifferent(finalGdkRect.y, currentRect.y);
1776 const bool needsSizeUpdate =
1777 IsSubstantiallyDifferent(finalGdkRect.width, currentRect.width) ||
1778 IsSubstantiallyDifferent(finalGdkRect.height, currentRect.height);
1779 const DesktopIntRect newClientArea = DesktopIntRect(
1780 finalGdkRect.x, finalGdkRect.y, finalGdkRect.width, finalGdkRect.height);
1781
1782 LOG(" orig gdk [%d, %d] -> [%d x %d]", currentRect.x, currentRect.y,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " orig gdk [%d, %d] -> [%d x %d]"
, this->GetDebugTag().get(), currentRect.x, currentRect.y,
currentRect.width, currentRect.height); } } while (0)
1783 currentRect.width, currentRect.height)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " orig gdk [%d, %d] -> [%d x %d]"
, this->GetDebugTag().get(), currentRect.x, currentRect.y,
currentRect.width, currentRect.height); } } while (0)
;
1784 LOG(" new gdk [%d, %d] -> [%d x %d]\n", finalGdkRect.x, finalGdkRect.y,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " new gdk [%d, %d] -> [%d x %d]\n"
, this->GetDebugTag().get(), finalGdkRect.x, finalGdkRect.
y, finalGdkRect.width, finalGdkRect.height); } } while (0)
1785 finalGdkRect.width, finalGdkRect.height)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " new gdk [%d, %d] -> [%d x %d]\n"
, this->GetDebugTag().get(), finalGdkRect.x, finalGdkRect.
y, finalGdkRect.width, finalGdkRect.height); } } while (0)
;
1786 LOG(" new mClientArea [%d, %d] -> [%d x %d]", newClientArea.x,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " new mClientArea [%d, %d] -> [%d x %d]"
, this->GetDebugTag().get(), newClientArea.x, newClientArea
.y, newClientArea.width, newClientArea.height); } } while (0)
1787 newClientArea.y, newClientArea.width, newClientArea.height)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " new mClientArea [%d, %d] -> [%d x %d]"
, this->GetDebugTag().get(), newClientArea.x, newClientArea
.y, newClientArea.width, newClientArea.height); } } while (0)
;
1788
1789 if (!needsSizeUpdate && !needsPositionUpdate) {
1790 LOG(" Size/position is the same, quit.")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " Size/position is the same, quit."
, this->GetDebugTag().get()); } } while (0)
;
1791 return;
1792 }
1793 if (needsSizeUpdate) {
1794 // Wayland compositor changed popup size request from layout.
1795 // Set the constraints to use them in nsMenuPopupFrame::SetPopupPosition().
1796 // Beware that gtk_window_resize() requests sizes asynchronously and so
1797 // newClientArea might not have the size from the most recent
1798 // gtk_window_resize().
1799 if (newClientArea.width < mLastSizeRequest.width) {
1800 mMoveToRectPopupSize.width = newClientArea.width;
1801 }
1802 if (newClientArea.height < mLastSizeRequest.height) {
1803 mMoveToRectPopupSize.height = newClientArea.height;
1804 }
1805 LOG(" mMoveToRectPopupSize set to [%d, %d]", mMoveToRectPopupSize.width,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " mMoveToRectPopupSize set to [%d, %d]"
, this->GetDebugTag().get(), mMoveToRectPopupSize.width, mMoveToRectPopupSize
.height); } } while (0)
1806 mMoveToRectPopupSize.height)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " mMoveToRectPopupSize set to [%d, %d]"
, this->GetDebugTag().get(), mMoveToRectPopupSize.width, mMoveToRectPopupSize
.height); } } while (0)
;
1807 }
1808
1809 mClientArea = newClientArea;
1810 mLastSizeRequest = newClientArea.Size();
1811 mLastMoveRequest = newClientArea.TopLeft();
1812
1813 // Check mClientArea size
1814 auto scaledSize = ToLayoutDevicePixels(mClientArea);
1815 if (mCompositorSession &&
1816 !wr::WindowSizeSanityCheck(scaledSize.width, scaledSize.height)) {
1817 gfxCriticalNoteOncestatic mozilla::gfx::CriticalLog sOnceAtLine1817 = mozilla::gfx
::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions(false
))
<< "Invalid mClientArea in PopupCallback " << scaledSize
1818 << " size state " << mSizeMode;
1819 }
1820 WaylandPopupPropagateChangesToLayout(needsPositionUpdate, needsSizeUpdate);
1821}
1822
1823// Position the popup directly by gtk_window_move() and try to keep it
1824// on screen by just moving it in scope of it's parent window.
1825//
1826// It's used when we position noautihode popup and we don't use xdg_positioner.
1827// See Bug 1718867
1828void nsWindowWayland::WaylandPopupSetDirectPosition() {
1829 const DesktopIntRect newRect(mLastMoveRequest, mLastSizeRequest);
1830
1831 LOG("nsWindowWayland::WaylandPopupSetDirectPosition %s",do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupSetDirectPosition %s"
, this->GetDebugTag().get(), ToString(newRect).c_str()); }
} while (0)
1832 ToString(newRect).c_str())do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupSetDirectPosition %s"
, this->GetDebugTag().get(), ToString(newRect).c_str()); }
} while (0)
;
1833
1834 mClientArea = newRect;
1835
1836 if (mIsDragPopup) {
1837 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), newRect.x, newRect.y);
1838 gtk_window_resize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), newRect.width, newRect.height);
1839 // DND window is placed inside container so we need to make hard size
1840 // request to ensure parent container is resized too.
1841 gtk_widget_set_size_request(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))), newRect.width,
1842 newRect.height);
1843 return;
1844 }
1845
1846 GtkWindow* parentGtkWindow = gtk_window_get_transient_for(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
1847 auto* window = nsWindow::FromGtkWidget(GTK_WIDGET(parentGtkWindow)((((GtkWidget*) (void *) ((parentGtkWindow))))));
1848 if (!window) {
1849 return;
1850 }
1851 GdkWindow* gdkWindow = window->GetGdkWindow();
1852 if (!gdkWindow) {
1853 return;
1854 }
1855
1856 int parentWidth = gdk_window_get_width(gdkWindow);
1857 int popupWidth = newRect.width;
1858
1859 int x;
1860 gdk_window_get_position(gdkWindow, &x, nullptr);
1861
1862 auto pos = newRect.TopLeft();
1863 // If popup is bigger than main window just center it.
1864 if (popupWidth > parentWidth) {
1865 pos.x = -(parentWidth - popupWidth) / 2 + x;
1866 } else {
1867 if (pos.x < x) {
1868 // Stick with left window edge if it's placed too left
1869 pos.x = x;
1870 } else if (pos.x + popupWidth > parentWidth + x) {
1871 // Stick with right window edge otherwise
1872 pos.x = parentWidth + x - popupWidth;
1873 }
1874 }
1875
1876 LOG(" set position [%d, %d]\n", pos.x.value, pos.y.value)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " set position [%d, %d]\n", this->
GetDebugTag().get(), pos.x.value, pos.y.value); } } while (0)
;
1877 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), pos.x, pos.y);
1878
1879 LOG(" set size [%d, %d]\n", newRect.width, newRect.height)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " set size [%d, %d]\n", this->GetDebugTag
().get(), newRect.width, newRect.height); } } while (0)
;
1880 gtk_window_resize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), newRect.width, newRect.height);
1881
1882 if (pos.x != newRect.x) {
1883 mClientArea.MoveTo(pos);
1884 WaylandPopupPropagateChangesToLayout(/* move */ true, /* resize */ false);
1885 }
1886}
1887
1888bool nsWindowWayland::WaylandPopupFitsToplevelWindow() {
1889 LOG("nsWindowWayland::WaylandPopupFitsToplevelWindow()")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::WaylandPopupFitsToplevelWindow()"
, this->GetDebugTag().get()); } } while (0)
;
1890
1891 GtkWindow* parent = gtk_window_get_transient_for(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
1892 GtkWindow* tmp = parent;
Value stored to 'tmp' during its initialization is never read
1893 while ((tmp = gtk_window_get_transient_for(GTK_WINDOW(parent)((((GtkWindow*) (void *) ((parent)))))))) {
1894 parent = tmp;
1895 }
1896 GdkWindow* toplevelGdkWindow = gtk_widget_get_window(GTK_WIDGET(parent)((((GtkWidget*) (void *) ((parent))))));
1897 if (NS_WARN_IF(!toplevelGdkWindow)NS_warn_if_impl(!toplevelGdkWindow, "!toplevelGdkWindow", "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 1897)
) {
1898 return false;
1899 }
1900
1901 int parentWidth = gdk_window_get_width(toplevelGdkWindow);
1902 int parentHeight = gdk_window_get_height(toplevelGdkWindow);
1903 DesktopIntRect parentWidgetRect(0, 0, parentWidth, parentHeight);
1904
1905 nsWindowWayland* parentWindow = nullptr;
1906 if (auto* window = nsWindow::FromGtkWidget(GTK_WIDGET(parent)((((GtkWidget*) (void *) ((parent))))))) {
1907 parentWindow = window->AsWayland();
1908 }
1909 if (!parentWindow) {
1910 return false;
1911 }
1912
1913 LOG(" parent size %d x %d", parentWindow->mClientArea.width,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " parent size %d x %d", this->GetDebugTag
().get(), parentWindow->mClientArea.width, parentWindow->
mClientArea.height); } } while (0)
1914 parentWindow->mClientArea.height)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " parent size %d x %d", this->GetDebugTag
().get(), parentWindow->mClientArea.width, parentWindow->
mClientArea.height); } } while (0)
;
1915
1916 DesktopIntRect popupRect(mLastMoveRequest, mLastSizeRequest);
1917 LOG(" popup topleft %d, %d size %d x %d", popupRect.x, popupRect.y,do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " popup topleft %d, %d size %d x %d"
, this->GetDebugTag().get(), popupRect.x, popupRect.y, popupRect
.width, popupRect.height); } } while (0)
1918 popupRect.width, popupRect.height)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " popup topleft %d, %d size %d x %d"
, this->GetDebugTag().get(), popupRect.x, popupRect.y, popupRect
.width, popupRect.height); } } while (0)
;
1919
1920 bool fits = parentWindow->mClientArea.Contains(popupRect);
1921 LOG(" fits %d", fits)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " fits %d", this->GetDebugTag()
.get(), fits); } } while (0)
;
1922 return fits;
1923}
1924
1925void nsWindowWayland::NativeMoveResizeWaylandPopup(bool aMove, bool aResize) {
1926 GdkRectangle rect{mLastMoveRequest.x, mLastMoveRequest.y,
1927 mLastSizeRequest.width, mLastSizeRequest.height};
1928
1929 LOG("nsWindowWayland::NativeMoveResizeWaylandPopup [%d,%d] -> [%d x %d] move "do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::NativeMoveResizeWaylandPopup [%d,%d] -> [%d x %d] move "
"%d " "resize %d\n", this->GetDebugTag().get(), rect.x, rect
.y, rect.width, rect.height, aMove, aResize); } } while (0)
1930 "%d "do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::NativeMoveResizeWaylandPopup [%d,%d] -> [%d x %d] move "
"%d " "resize %d\n", this->GetDebugTag().get(), rect.x, rect
.y, rect.width, rect.height, aMove, aResize); } } while (0)
1931 "resize %d\n",do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::NativeMoveResizeWaylandPopup [%d,%d] -> [%d x %d] move "
"%d " "resize %d\n", this->GetDebugTag().get(), rect.x, rect
.y, rect.width, rect.height, aMove, aResize); } } while (0)
1932 rect.x, rect.y, rect.width, rect.height, aMove, aResize)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::NativeMoveResizeWaylandPopup [%d,%d] -> [%d x %d] move "
"%d " "resize %d\n", this->GetDebugTag().get(), rect.x, rect
.y, rect.width, rect.height, aMove, aResize); } } while (0)
;
1933
1934 // Compositor may be confused by windows with width/height = 0
1935 // and positioning such windows leads to Bug 1555866.
1936 if (!AreBoundsSane()) {
1937 LOG(" Bounds are not sane (width: %d height: %d)\n",do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " Bounds are not sane (width: %d height: %d)\n"
, this->GetDebugTag().get(), mLastSizeRequest.width, mLastSizeRequest
.height); } } while (0)
1938 mLastSizeRequest.width, mLastSizeRequest.height)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " Bounds are not sane (width: %d height: %d)\n"
, this->GetDebugTag().get(), mLastSizeRequest.width, mLastSizeRequest
.height); } } while (0)
;
1939 return;
1940 }
1941
1942 // It's safe to expect the popup position is handled onwards.
1943 if (aMove) {
1944 mWaylandApplyPopupPositionBeforeShow = false;
1945 }
1946
1947 MOZ_ASSERT(mClientMargin.IsAllZero())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mClientMargin.IsAllZero())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mClientMargin.IsAllZero())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("mClientMargin.IsAllZero()"
, "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp", 1947)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClientMargin.IsAllZero()"
")"); do { MOZ_CrashSequence(__null, 1947); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1948
1949 if (mWaitingForMoveToRectCallback) {
1950 LOG(" waiting for move to rect, scheduling")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " waiting for move to rect, scheduling"
, this->GetDebugTag().get()); } } while (0)
;
1951 // mClientArea position must not be overwritten before it is applied.
1952 // OnShellConfigureEvent() will not set mClientArea to an old position for
1953 // GTK_WINDOW_POPUP.
1954 MOZ_ASSERT(gtk_window_get_window_type(GTK_WINDOW(mShell)) ==do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gtk_window_get_window_type(((((GtkWindow*) (void *) (
(mShell)))))) == GTK_WINDOW_POPUP)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(gtk_window_get_window_type((
(((GtkWindow*) (void *) ((mShell)))))) == GTK_WINDOW_POPUP)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("gtk_window_get_window_type(((((GtkWindow*) (void *) ((mShell)))))) == GTK_WINDOW_POPUP"
, "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp", 1955)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "gtk_window_get_window_type(((((GtkWindow*) (void *) ((mShell)))))) == GTK_WINDOW_POPUP"
")"); do { MOZ_CrashSequence(__null, 1955); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1955 GTK_WINDOW_POPUP)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gtk_window_get_window_type(((((GtkWindow*) (void *) (
(mShell)))))) == GTK_WINDOW_POPUP)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(gtk_window_get_window_type((
(((GtkWindow*) (void *) ((mShell)))))) == GTK_WINDOW_POPUP)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("gtk_window_get_window_type(((((GtkWindow*) (void *) ((mShell)))))) == GTK_WINDOW_POPUP"
, "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp", 1955)
; AnnotateMozCrashReason("MOZ_ASSERT" "(" "gtk_window_get_window_type(((((GtkWindow*) (void *) ((mShell)))))) == GTK_WINDOW_POPUP"
")"); do { MOZ_CrashSequence(__null, 1955); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1956 mMovedAfterMoveToRect = aMove;
1957 mResizedAfterMoveToRect = aResize;
1958 return;
1959 }
1960
1961 mMovedAfterMoveToRect = false;
1962 mResizedAfterMoveToRect = false;
1963
1964 bool trackedInHierarchy = WaylandPopupConfigure();
1965 // Read popup position from layout if it was moved.
1966 // This position is used by move-to-rect method as we need anchor and other
1967 // info to place popup correctly.
1968 // We need WaylandPopupConfigure() to be called before to have all needed
1969 // popup info in place (mainly the anchored flag).
1970 if (aMove) {
1971 mPopupMoveToRectParams = WaylandPopupGetPositionFromLayout();
1972 }
1973 if (!trackedInHierarchy) {
1974 WaylandPopupSetDirectPosition();
1975 return;
1976 }
1977
1978 if (aResize) {
1979 LOG(" set size [%d, %d]\n", rect.width, rect.height)do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " set size [%d, %d]\n", this->GetDebugTag
().get(), rect.width, rect.height); } } while (0)
;
1980 gtk_window_resize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), rect.width, rect.height);
1981 }
1982
1983 if (!aMove && WaylandPopupFitsToplevelWindow()) {
1984 // Popup position has not been changed and its position/size fits
1985 // parent window so no need to reposition the window.
1986 LOG(" fits parent window size, just resize\n")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " fits parent window size, just resize\n"
, this->GetDebugTag().get()); } } while (0)
;
1987 return;
1988 }
1989
1990 // Mark popup as changed as we're updating position/size.
1991 mPopupChanged = true;
1992
1993 mClientArea = DesktopIntRect(mLastMoveRequest, mLastSizeRequest);
1994
1995 UpdateWaylandPopupHierarchy();
1996}
1997
1998bool nsWindowWayland::WaylandPipEnabled() const {
1999 return mPiPType == PiPType::MediaPiP &&
2000 StaticPrefs::widget_wayland_experimental_pip_enabled_AtStartup() &&
2001 GdkIsWaylandDisplay() && WaylandDisplayGet()->GetPipShell();
2002}
2003
2004void nsWindowWayland::MaybeCreatePipResources() {
2005 LOG("MaybeCreatePipResources()")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "MaybeCreatePipResources()", this->
GetDebugTag().get()); } } while (0)
;
2006 if (!WaylandPipEnabled()) {
2007 return;
2008 }
2009
2010 static xx_pip_v1_listener pip_listener = {
2011 .closed =
2012 [](void* data, xx_pip_v1*) {
2013 LOGW("xx_pip_v1_listener::closed()")do { const ::mozilla::LogModule* moz_real_module = gWidgetLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "xx_pip_v1_listener::closed()"
); } } while (0)
;
2014 RefPtr self = static_cast<nsWindowWayland*>(data);
2015 gtk_window_close(GTK_WINDOW(self->mShell)((((GtkWindow*) (void *) ((self->mShell))))));
2016 },
2017 .configure_bounds =
2018 [](void* data, xx_pip_v1*, int32_t w, int32_t h) {
2019 LOGW("xx_pip_v1_listener::configure_bounds(%d, %d)", w, h)do { const ::mozilla::LogModule* moz_real_module = gWidgetLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "xx_pip_v1_listener::configure_bounds(%d, %d)"
, w, h); } } while (0)
;
2020 },
2021 .configure_size =
2022 [](void* data, xx_pip_v1*, int32_t w, int32_t h) {
2023 LOGW("xx_pip_v1_listener::configure_size(%d, %d)", w, h)do { const ::mozilla::LogModule* moz_real_module = gWidgetLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "xx_pip_v1_listener::configure_size(%d, %d)"
, w, h); } } while (0)
;
2024 auto* self = static_cast<nsWindowWayland*>(data);
2025 if (w == 0 && h == 0) {
2026 gtk_window_get_size(GTK_WINDOW(self->mShell)((((GtkWindow*) (void *) ((self->mShell))))), &w, &h);
2027 }
2028 self->mPipResources.mConfigureSize = {w, h};
2029 },
2030 };
2031
2032 static xdg_surface_listener surface_listener = {
2033 .configure =
2034 [](void* data, struct xdg_surface* surface, uint32_t serial) {
2035 LOGW("xdg_surface_listener::configure(%u)", serial)do { const ::mozilla::LogModule* moz_real_module = gWidgetLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "xdg_surface_listener::configure(%u)"
, serial); } } while (0)
;
2036 RefPtr self = static_cast<nsWindowWayland*>(data);
2037 xdg_surface_ack_configure(surface, serial);
2038 auto size = self->mPipResources.mConfigureSize;
2039 gtk_window_resize(GTK_WINDOW(self->mShell)((((GtkWindow*) (void *) ((self->mShell))))), size.width,
2040 size.height);
2041 },
2042 };
2043
2044 auto* surf = gdk_wayland_window_get_wl_surface(GetToplevelGdkWindow());
2045 MOZ_DIAGNOSTIC_ASSERT(surf, "Should have a wayland surface by now")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(surf)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(surf))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("surf" " (" "Should have a wayland surface by now"
")", "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp", 2045
); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "surf" ") ("
"Should have a wayland surface by now" ")"); do { MOZ_CrashSequence
(__null, 2045); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2046 mPipResources.mXdgSurface =
2047 xdg_wm_base_get_xdg_surface(WaylandDisplayGet()->GetXdgWm(), surf);
2048 xdg_surface_add_listener(mPipResources.mXdgSurface, &surface_listener, this);
2049 mPipResources.mPipSurface = xx_pip_shell_v1_get_pip(
2050 WaylandDisplayGet()->GetPipShell(), mPipResources.mXdgSurface);
2051 xx_pip_v1_add_listener(mPipResources.mPipSurface, &pip_listener, this);
2052 xx_pip_v1_set_app_id(mPipResources.mPipSurface, "org.mozilla." MOZ_APP_NAME"firefox");
2053 wl_surface_commit(surf);
2054}
2055
2056void nsWindowWayland::ClearPipResources() {
2057 MozClearPointer(mPipResources.mPipSurface, xx_pip_v1_destroy);
2058 MozClearPointer(mPipResources.mXdgSurface, xdg_surface_destroy);
2059}
2060
2061bool nsWindowWayland::PIPMove() {
2062 if (!mPipResources.mPipSurface) {
2063 return false;
2064 }
2065 xx_pip_v1_move(mPipResources.mPipSurface,
2066 gdk_wayland_device_get_wl_seat(GdkGetPointer()),
2067 nsWaylandDisplay::GetLastEventSerial());
2068 return true;
2069}
2070
2071bool nsWindowWayland::PIPResize(GdkWindowEdge aEdge) {
2072 if (!mPipResources.mPipSurface) {
2073 return false;
2074 }
2075 auto pipEdges = [&] {
2076 switch (aEdge) {
2077 case GDK_WINDOW_EDGE_NORTH:
2078 return XX_PIP_V1_RESIZE_EDGE_TOP;
2079 case GDK_WINDOW_EDGE_NORTH_WEST:
2080 return XX_PIP_V1_RESIZE_EDGE_TOP_LEFT;
2081 case GDK_WINDOW_EDGE_NORTH_EAST:
2082 return XX_PIP_V1_RESIZE_EDGE_TOP_RIGHT;
2083 case GDK_WINDOW_EDGE_SOUTH:
2084 return XX_PIP_V1_RESIZE_EDGE_BOTTOM;
2085 case GDK_WINDOW_EDGE_SOUTH_WEST:
2086 return XX_PIP_V1_RESIZE_EDGE_BOTTOM_LEFT;
2087 case GDK_WINDOW_EDGE_SOUTH_EAST:
2088 return XX_PIP_V1_RESIZE_EDGE_BOTTOM_RIGHT;
2089 case GDK_WINDOW_EDGE_WEST:
2090 return XX_PIP_V1_RESIZE_EDGE_LEFT;
2091 case GDK_WINDOW_EDGE_EAST:
2092 return XX_PIP_V1_RESIZE_EDGE_RIGHT;
2093 }
2094 return XX_PIP_V1_RESIZE_EDGE_TOP_LEFT;
2095 }();
2096 xx_pip_v1_resize(mPipResources.mPipSurface,
2097 gdk_wayland_device_get_wl_seat(GdkGetPointer()),
2098 nsWaylandDisplay::GetLastEventSerial(), pipEdges);
2099 return true;
2100}
2101
2102void nsWindowWayland::CreateNative() {
2103 LOG("nsWindowWayland::CreateNative()")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::CreateNative()", this
->GetDebugTag().get()); } } while (0)
;
2104
2105 // Ensure that KeymapWrapper is created on Wayland as we need it for
2106 // keyboard focus tracking.
2107 KeymapWrapper::EnsureInstance();
2108
2109 mSurfaceProvider.Initialize(this);
2110
2111 // Initialize the window specific VsyncSource early in order to avoid races
2112 // with BrowserParent::UpdateVsyncParentVsyncDispatcher().
2113 // Only use for toplevel windows for now, see bug 1619246.
2114
2115 if (StaticPrefs::widget_wayland_vsync_enabled_AtStartup() &&
2116 IsTopLevelWidget()) {
2117 LOG_VSYNC(" create WaylandVsyncSource")do { const ::mozilla::LogModule* moz_real_module = gWidgetVsync
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "%s: " " create WaylandVsyncSource"
, GetDebugTag().get()); } } while (0)
;
2118 mWaylandVsyncSource = new WaylandVsyncSource(this);
2119 mWaylandVsyncSource->Init();
2120 mWaylandVsyncDispatcher = new VsyncDispatcher(mWaylandVsyncSource);
2121 mWaylandVsyncSource->EnableVSyncSource();
2122 }
2123
2124 if (WaylandPipEnabled()) {
2125 // This avoids GTK from managing our top level surface role.
2126 // We'll handle it manually in OnMap().
2127 gdk_wayland_window_set_use_custom_surface(GetToplevelGdkWindow());
2128 }
2129
2130 mWaitingToSessionRestore =
2131 IsTopLevelWidget() &&
2132 nsAppShell::UpdateAndGetSessionState() == eSessionRestoring;
2133
2134 LOGVERBOSE(" mWaitingToSessionRestore %d", mWaitingToSessionRestore)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Verbose
)), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Verbose, "%s: " " mWaitingToSessionRestore %d", GetDebugTag
().get(), mWaitingToSessionRestore); } } while (0)
;
2135}
2136
2137void nsWindowWayland::ConfigureToplevelWindowNative() {
2138 LOG("nsWindowWayland::ConfigureToplevelWindow() register callback for "do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::ConfigureToplevelWindow() register callback for "
"toplevel GdkWindow [%p]", this->GetDebugTag().get(), GetToplevelGdkWindow
()); } } while (0)
2139 "toplevel GdkWindow [%p]",do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::ConfigureToplevelWindow() register callback for "
"toplevel GdkWindow [%p]", this->GetDebugTag().get(), GetToplevelGdkWindow
()); } } while (0)
2140 GetToplevelGdkWindow())do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::ConfigureToplevelWindow() register callback for "
"toplevel GdkWindow [%p]", this->GetDebugTag().get(), GetToplevelGdkWindow
()); } } while (0)
;
2141 if (!mWaitingToSessionRestore) {
2142 return;
2143 }
2144 auto* window = GetToplevelGdkWindow();
2145 if (!window) {
2146 LOG(" quit, missing toplevel GdkWindow!")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " quit, missing toplevel GdkWindow!"
, this->GetDebugTag().get()); } } while (0)
;
2147 return;
2148 }
2149 MOZ_ASSERT(g_signal_lookup("xdg-toplevel-realized", G_OBJECT_TYPE(window)),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(g_signal_lookup("xdg-toplevel-realized", (((((GTypeClass
*) (((GTypeInstance*) (window))->g_class))->g_type)))))
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(g_signal_lookup("xdg-toplevel-realized", (((((GTypeClass
*) (((GTypeInstance*) (window))->g_class))->g_type)))))
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("g_signal_lookup(\"xdg-toplevel-realized\", (((((GTypeClass*) (((GTypeInstance*) (window))->g_class))->g_type))))"
" (" "Session restore support shouldbe disabled!" ")", "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 2150); AnnotateMozCrashReason("MOZ_ASSERT" "(" "g_signal_lookup(\"xdg-toplevel-realized\", (((((GTypeClass*) (((GTypeInstance*) (window))->g_class))->g_type))))"
") (" "Session restore support shouldbe disabled!" ")"); do {
MOZ_CrashSequence(__null, 2150); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
2150 "Session restore support shouldbe disabled!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(g_signal_lookup("xdg-toplevel-realized", (((((GTypeClass
*) (((GTypeInstance*) (window))->g_class))->g_type)))))
>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(g_signal_lookup("xdg-toplevel-realized", (((((GTypeClass
*) (((GTypeInstance*) (window))->g_class))->g_type)))))
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("g_signal_lookup(\"xdg-toplevel-realized\", (((((GTypeClass*) (((GTypeInstance*) (window))->g_class))->g_type))))"
" (" "Session restore support shouldbe disabled!" ")", "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 2150); AnnotateMozCrashReason("MOZ_ASSERT" "(" "g_signal_lookup(\"xdg-toplevel-realized\", (((((GTypeClass*) (((GTypeInstance*) (window))->g_class))->g_type))))"
") (" "Session restore support shouldbe disabled!" ")"); do {
MOZ_CrashSequence(__null, 2150); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
2151 if (g_signal_handler_is_connected(window, mXdgToplevelRealizedID)) {
2152 return;
2153 }
2154 mXdgToplevelRealizedID = g_signal_connect(g_signal_connect_data ((window), ("xdg-toplevel-realized"), (
((GCallback) (+[](GtkWidget* widget) -> gboolean { do { const
::mozilla::LogModule* moz_real_module = gWidgetLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, mozilla::LogLevel
::Debug)), 0))) { mozilla::detail::log_print(moz_real_module,
mozilla::LogLevel::Debug, "nsWindowWayland::ConfigureToplevelWindow() callback"
); } } while (0); RefPtr<nsWindowWayland> window = static_cast
<nsWindowWayland*>(nsWindow::FromGtkWidget(widget)); if
(!window) { return (0); } g_signal_handler_disconnect(window
->GetToplevelGdkWindow(), window->mXdgToplevelRealizedID
); window->mXdgToplevelRealizedID = 0; window->RestoreXdgToplevel
(); return (0); }))), (nullptr), __null, (GConnectFlags) 0)
2155 window, "xdg-toplevel-realized",g_signal_connect_data ((window), ("xdg-toplevel-realized"), (
((GCallback) (+[](GtkWidget* widget) -> gboolean { do { const
::mozilla::LogModule* moz_real_module = gWidgetLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, mozilla::LogLevel
::Debug)), 0))) { mozilla::detail::log_print(moz_real_module,
mozilla::LogLevel::Debug, "nsWindowWayland::ConfigureToplevelWindow() callback"
); } } while (0); RefPtr<nsWindowWayland> window = static_cast
<nsWindowWayland*>(nsWindow::FromGtkWidget(widget)); if
(!window) { return (0); } g_signal_handler_disconnect(window
->GetToplevelGdkWindow(), window->mXdgToplevelRealizedID
); window->mXdgToplevelRealizedID = 0; window->RestoreXdgToplevel
(); return (0); }))), (nullptr), __null, (GConnectFlags) 0)
2156 G_CALLBACK(+[](GtkWidget* widget) -> gboolean {g_signal_connect_data ((window), ("xdg-toplevel-realized"), (
((GCallback) (+[](GtkWidget* widget) -> gboolean { do { const
::mozilla::LogModule* moz_real_module = gWidgetLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, mozilla::LogLevel
::Debug)), 0))) { mozilla::detail::log_print(moz_real_module,
mozilla::LogLevel::Debug, "nsWindowWayland::ConfigureToplevelWindow() callback"
); } } while (0); RefPtr<nsWindowWayland> window = static_cast
<nsWindowWayland*>(nsWindow::FromGtkWidget(widget)); if
(!window) { return (0); } g_signal_handler_disconnect(window
->GetToplevelGdkWindow(), window->mXdgToplevelRealizedID
); window->mXdgToplevelRealizedID = 0; window->RestoreXdgToplevel
(); return (0); }))), (nullptr), __null, (GConnectFlags) 0)
2157 LOGW("nsWindowWayland::ConfigureToplevelWindow() callback");g_signal_connect_data ((window), ("xdg-toplevel-realized"), (
((GCallback) (+[](GtkWidget* widget) -> gboolean { do { const
::mozilla::LogModule* moz_real_module = gWidgetLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, mozilla::LogLevel
::Debug)), 0))) { mozilla::detail::log_print(moz_real_module,
mozilla::LogLevel::Debug, "nsWindowWayland::ConfigureToplevelWindow() callback"
); } } while (0); RefPtr<nsWindowWayland> window = static_cast
<nsWindowWayland*>(nsWindow::FromGtkWidget(widget)); if
(!window) { return (0); } g_signal_handler_disconnect(window
->GetToplevelGdkWindow(), window->mXdgToplevelRealizedID
); window->mXdgToplevelRealizedID = 0; window->RestoreXdgToplevel
(); return (0); }))), (nullptr), __null, (GConnectFlags) 0)
2158 RefPtr<nsWindowWayland> window =g_signal_connect_data ((window), ("xdg-toplevel-realized"), (
((GCallback) (+[](GtkWidget* widget) -> gboolean { do { const
::mozilla::LogModule* moz_real_module = gWidgetLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, mozilla::LogLevel
::Debug)), 0))) { mozilla::detail::log_print(moz_real_module,
mozilla::LogLevel::Debug, "nsWindowWayland::ConfigureToplevelWindow() callback"
); } } while (0); RefPtr<nsWindowWayland> window = static_cast
<nsWindowWayland*>(nsWindow::FromGtkWidget(widget)); if
(!window) { return (0); } g_signal_handler_disconnect(window
->GetToplevelGdkWindow(), window->mXdgToplevelRealizedID
); window->mXdgToplevelRealizedID = 0; window->RestoreXdgToplevel
(); return (0); }))), (nullptr), __null, (GConnectFlags) 0)
2159 static_cast<nsWindowWayland*>(nsWindow::FromGtkWidget(widget));g_signal_connect_data ((window), ("xdg-toplevel-realized"), (
((GCallback) (+[](GtkWidget* widget) -> gboolean { do { const
::mozilla::LogModule* moz_real_module = gWidgetLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, mozilla::LogLevel
::Debug)), 0))) { mozilla::detail::log_print(moz_real_module,
mozilla::LogLevel::Debug, "nsWindowWayland::ConfigureToplevelWindow() callback"
); } } while (0); RefPtr<nsWindowWayland> window = static_cast
<nsWindowWayland*>(nsWindow::FromGtkWidget(widget)); if
(!window) { return (0); } g_signal_handler_disconnect(window
->GetToplevelGdkWindow(), window->mXdgToplevelRealizedID
); window->mXdgToplevelRealizedID = 0; window->RestoreXdgToplevel
(); return (0); }))), (nullptr), __null, (GConnectFlags) 0)
2160 if (!window) {g_signal_connect_data ((window), ("xdg-toplevel-realized"), (
((GCallback) (+[](GtkWidget* widget) -> gboolean { do { const
::mozilla::LogModule* moz_real_module = gWidgetLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, mozilla::LogLevel
::Debug)), 0))) { mozilla::detail::log_print(moz_real_module,
mozilla::LogLevel::Debug, "nsWindowWayland::ConfigureToplevelWindow() callback"
); } } while (0); RefPtr<nsWindowWayland> window = static_cast
<nsWindowWayland*>(nsWindow::FromGtkWidget(widget)); if
(!window) { return (0); } g_signal_handler_disconnect(window
->GetToplevelGdkWindow(), window->mXdgToplevelRealizedID
); window->mXdgToplevelRealizedID = 0; window->RestoreXdgToplevel
(); return (0); }))), (nullptr), __null, (GConnectFlags) 0)
2161 return FALSE;g_signal_connect_data ((window), ("xdg-toplevel-realized"), (
((GCallback) (+[](GtkWidget* widget) -> gboolean { do { const
::mozilla::LogModule* moz_real_module = gWidgetLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, mozilla::LogLevel
::Debug)), 0))) { mozilla::detail::log_print(moz_real_module,
mozilla::LogLevel::Debug, "nsWindowWayland::ConfigureToplevelWindow() callback"
); } } while (0); RefPtr<nsWindowWayland> window = static_cast
<nsWindowWayland*>(nsWindow::FromGtkWidget(widget)); if
(!window) { return (0); } g_signal_handler_disconnect(window
->GetToplevelGdkWindow(), window->mXdgToplevelRealizedID
); window->mXdgToplevelRealizedID = 0; window->RestoreXdgToplevel
(); return (0); }))), (nullptr), __null, (GConnectFlags) 0)
2162 }g_signal_connect_data ((window), ("xdg-toplevel-realized"), (
((GCallback) (+[](GtkWidget* widget) -> gboolean { do { const
::mozilla::LogModule* moz_real_module = gWidgetLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, mozilla::LogLevel
::Debug)), 0))) { mozilla::detail::log_print(moz_real_module,
mozilla::LogLevel::Debug, "nsWindowWayland::ConfigureToplevelWindow() callback"
); } } while (0); RefPtr<nsWindowWayland> window = static_cast
<nsWindowWayland*>(nsWindow::FromGtkWidget(widget)); if
(!window) { return (0); } g_signal_handler_disconnect(window
->GetToplevelGdkWindow(), window->mXdgToplevelRealizedID
); window->mXdgToplevelRealizedID = 0; window->RestoreXdgToplevel
(); return (0); }))), (nullptr), __null, (GConnectFlags) 0)
2163
2164 g_signal_handler_disconnect(window->GetToplevelGdkWindow(),g_signal_connect_data ((window), ("xdg-toplevel-realized"), (
((GCallback) (+[](GtkWidget* widget) -> gboolean { do { const
::mozilla::LogModule* moz_real_module = gWidgetLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, mozilla::LogLevel
::Debug)), 0))) { mozilla::detail::log_print(moz_real_module,
mozilla::LogLevel::Debug, "nsWindowWayland::ConfigureToplevelWindow() callback"
); } } while (0); RefPtr<nsWindowWayland> window = static_cast
<nsWindowWayland*>(nsWindow::FromGtkWidget(widget)); if
(!window) { return (0); } g_signal_handler_disconnect(window
->GetToplevelGdkWindow(), window->mXdgToplevelRealizedID
); window->mXdgToplevelRealizedID = 0; window->RestoreXdgToplevel
(); return (0); }))), (nullptr), __null, (GConnectFlags) 0)
2165 window->mXdgToplevelRealizedID);g_signal_connect_data ((window), ("xdg-toplevel-realized"), (
((GCallback) (+[](GtkWidget* widget) -> gboolean { do { const
::mozilla::LogModule* moz_real_module = gWidgetLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, mozilla::LogLevel
::Debug)), 0))) { mozilla::detail::log_print(moz_real_module,
mozilla::LogLevel::Debug, "nsWindowWayland::ConfigureToplevelWindow() callback"
); } } while (0); RefPtr<nsWindowWayland> window = static_cast
<nsWindowWayland*>(nsWindow::FromGtkWidget(widget)); if
(!window) { return (0); } g_signal_handler_disconnect(window
->GetToplevelGdkWindow(), window->mXdgToplevelRealizedID
); window->mXdgToplevelRealizedID = 0; window->RestoreXdgToplevel
(); return (0); }))), (nullptr), __null, (GConnectFlags) 0)
2166 window->mXdgToplevelRealizedID = 0;g_signal_connect_data ((window), ("xdg-toplevel-realized"), (
((GCallback) (+[](GtkWidget* widget) -> gboolean { do { const
::mozilla::LogModule* moz_real_module = gWidgetLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, mozilla::LogLevel
::Debug)), 0))) { mozilla::detail::log_print(moz_real_module,
mozilla::LogLevel::Debug, "nsWindowWayland::ConfigureToplevelWindow() callback"
); } } while (0); RefPtr<nsWindowWayland> window = static_cast
<nsWindowWayland*>(nsWindow::FromGtkWidget(widget)); if
(!window) { return (0); } g_signal_handler_disconnect(window
->GetToplevelGdkWindow(), window->mXdgToplevelRealizedID
); window->mXdgToplevelRealizedID = 0; window->RestoreXdgToplevel
(); return (0); }))), (nullptr), __null, (GConnectFlags) 0)
2167
2168 window->RestoreXdgToplevel();g_signal_connect_data ((window), ("xdg-toplevel-realized"), (
((GCallback) (+[](GtkWidget* widget) -> gboolean { do { const
::mozilla::LogModule* moz_real_module = gWidgetLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, mozilla::LogLevel
::Debug)), 0))) { mozilla::detail::log_print(moz_real_module,
mozilla::LogLevel::Debug, "nsWindowWayland::ConfigureToplevelWindow() callback"
); } } while (0); RefPtr<nsWindowWayland> window = static_cast
<nsWindowWayland*>(nsWindow::FromGtkWidget(widget)); if
(!window) { return (0); } g_signal_handler_disconnect(window
->GetToplevelGdkWindow(), window->mXdgToplevelRealizedID
); window->mXdgToplevelRealizedID = 0; window->RestoreXdgToplevel
(); return (0); }))), (nullptr), __null, (GConnectFlags) 0)
2169 return FALSE;g_signal_connect_data ((window), ("xdg-toplevel-realized"), (
((GCallback) (+[](GtkWidget* widget) -> gboolean { do { const
::mozilla::LogModule* moz_real_module = gWidgetLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, mozilla::LogLevel
::Debug)), 0))) { mozilla::detail::log_print(moz_real_module,
mozilla::LogLevel::Debug, "nsWindowWayland::ConfigureToplevelWindow() callback"
); } } while (0); RefPtr<nsWindowWayland> window = static_cast
<nsWindowWayland*>(nsWindow::FromGtkWidget(widget)); if
(!window) { return (0); } g_signal_handler_disconnect(window
->GetToplevelGdkWindow(), window->mXdgToplevelRealizedID
); window->mXdgToplevelRealizedID = 0; window->RestoreXdgToplevel
(); return (0); }))), (nullptr), __null, (GConnectFlags) 0)
2170 }),g_signal_connect_data ((window), ("xdg-toplevel-realized"), (
((GCallback) (+[](GtkWidget* widget) -> gboolean { do { const
::mozilla::LogModule* moz_real_module = gWidgetLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, mozilla::LogLevel
::Debug)), 0))) { mozilla::detail::log_print(moz_real_module,
mozilla::LogLevel::Debug, "nsWindowWayland::ConfigureToplevelWindow() callback"
); } } while (0); RefPtr<nsWindowWayland> window = static_cast
<nsWindowWayland*>(nsWindow::FromGtkWidget(widget)); if
(!window) { return (0); } g_signal_handler_disconnect(window
->GetToplevelGdkWindow(), window->mXdgToplevelRealizedID
); window->mXdgToplevelRealizedID = 0; window->RestoreXdgToplevel
(); return (0); }))), (nullptr), __null, (GConnectFlags) 0)
2171 nullptr)g_signal_connect_data ((window), ("xdg-toplevel-realized"), (
((GCallback) (+[](GtkWidget* widget) -> gboolean { do { const
::mozilla::LogModule* moz_real_module = gWidgetLog; if ((__builtin_expect
(!!(mozilla::detail::log_test(moz_real_module, mozilla::LogLevel
::Debug)), 0))) { mozilla::detail::log_print(moz_real_module,
mozilla::LogLevel::Debug, "nsWindowWayland::ConfigureToplevelWindow() callback"
); } } while (0); RefPtr<nsWindowWayland> window = static_cast
<nsWindowWayland*>(nsWindow::FromGtkWidget(widget)); if
(!window) { return (0); } g_signal_handler_disconnect(window
->GetToplevelGdkWindow(), window->mXdgToplevelRealizedID
); window->mXdgToplevelRealizedID = 0; window->RestoreXdgToplevel
(); return (0); }))), (nullptr), __null, (GConnectFlags) 0)
;
2172}
2173
2174void nsWindowWayland::DestroyNative() {
2175 LOG("nsWindowWayland::DestroyNative()")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::DestroyNative()",
this->GetDebugTag().get()); } } while (0)
;
2176 if (mXdgToplevelRealizedID) {
2177 g_signal_handler_disconnect(GetToplevelGdkWindow(), mXdgToplevelRealizedID);
2178 mXdgToplevelRealizedID = 0;
2179 }
2180 MozClearPointer(mSessionRestoreToken, xdg_toplevel_session_v1_destroy);
2181 ClearPipResources();
2182
2183 // Shut down our local vsync source
2184 // Also drops reference to nsWindow::mSurface.
2185 if (mWaylandVsyncSource) {
2186 mWaylandVsyncSource->Shutdown();
2187 mWaylandVsyncSource = nullptr;
2188 }
2189 mWaylandVsyncDispatcher = nullptr;
2190 UnlockNativePointer();
2191}
2192
2193void nsWindowWayland::NativeShow(bool aAction) {
2194 if (aAction) {
2195 // unset our flag now that our window has been shown
2196 mNeedsShow = true;
2197
2198 if (mWaitingToSessionRestore) {
2199 LOG("nsWindowWayland::NativeShow() waiting to session restore, quit.")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::NativeShow() waiting to session restore, quit."
, this->GetDebugTag().get()); } } while (0)
;
2200 if (nsAppShell::UpdateAndGetSessionState() == eSessionRestoring) {
2201 return;
2202 }
2203 mWaitingToSessionRestore = false;
2204 NS_WARNING("Wayland session restore failed!")NS_DebugBreak(NS_DEBUG_WARNING, "Wayland session restore failed!"
, nullptr, "/root/firefox-clang/widget/gtk/nsWindowWayland.cpp"
, 2204)
;
2205 }
2206
2207 auto removeShow = MakeScopeExit([&] { mNeedsShow = false; });
2208
2209 LOG("nsWindowWayland::NativeShow show\n")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindowWayland::NativeShow show\n"
, this->GetDebugTag().get()); } } while (0)
;
2210
2211 if (IsWaylandPopup()) {
2212 mPopupClosed = false;
2213 const bool trackedInHierarchy = WaylandPopupConfigure();
2214 if (trackedInHierarchy) {
2215 AddWindowToPopupHierarchy();
2216 }
2217 if (mWaylandApplyPopupPositionBeforeShow) {
2218 // NOTE(emilio): This will end up calling UpdateWaylandPopupHierarchy if
2219 // needed.
2220 NativeMoveResize(/* move */ true, /* resize */ false);
2221 } else if (trackedInHierarchy) {
2222 UpdateWaylandPopupHierarchy();
2223 }
2224 if (mPopupClosed) {
2225 return;
2226 }
2227 ShowWaylandPopupWindow();
2228 } else {
2229 ShowWaylandToplevelWindow();
2230 }
2231
2232 SetUserTimeAndStartupTokenForActivatedWindow();
2233
2234 auto token = std::move(mWindowActivationTokenFromEnv);
2235 if (!token.IsEmpty()) {
2236 FocusWaylandWindow(token.get());
2237 } else if (!IsPopup()) {
2238 TransferFocusTo();
2239 }
2240 } else {
2241 LOG("nsWindow::NativeShow hide\n")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindow::NativeShow hide\n", this
->GetDebugTag().get()); } } while (0)
;
2242 if (IsWaylandPopup()) {
2243 // We can't close tracked popups directly as they may have visible
2244 // child popups. Just mark is as closed and let
2245 // UpdateWaylandPopupHierarchy() do the job.
2246 if (IsInPopupHierarchy()) {
2247 WaylandPopupMarkAsClosed();
2248 UpdateWaylandPopupHierarchy();
2249 } else {
2250 // Close untracked popups directly.
2251 HideWaylandPopupWindow(/* aTemporaryHide */ false,
2252 /* aRemoveFromPopupList */ true);
2253 }
2254 } else {
2255 HideWaylandToplevelWindow();
2256 }
2257 }
2258}
2259
2260// Apply workaround for Mutter compositor bug (mzbz#1777269).
2261//
2262// When we open a popup window (tooltip for instance) attached to
2263// GDK_WINDOW_TYPE_HINT_UTILITY parent popup, Mutter compositor sends bogus
2264// leave/enter events to the GDK_WINDOW_TYPE_HINT_UTILITY popup.
2265// That leads to immediate tooltip close. As a workaround ignore these
2266// bogus events.
2267//
2268// We need to check two affected window types:
2269//
2270// - toplevel window with at least two child popups where the first one is
2271// GDK_WINDOW_TYPE_HINT_UTILITY.
2272// - GDK_WINDOW_TYPE_HINT_UTILITY popup with a child popup
2273//
2274// We need to mask two bogus leave/enter sequences:
2275// 1) Leave (popup) -> Enter (toplevel)
2276// 2) Leave (toplevel) -> Enter (popup)
2277//
2278// TODO: persistent (non-tracked) popups with tooltip/child popups?
2279//
2280bool nsWindowWayland::ApplyEnterLeaveMutterWorkaround() {
2281 // Leave (toplevel) case
2282 if (mWindowType == WindowType::TopLevel && mWaylandPopupNext &&
2283 mWaylandPopupNext->mWaylandPopupNext &&
2284 gtk_window_get_type_hint(GTK_WINDOW(mWaylandPopupNext->GetGtkWidget())((((GtkWindow*) (void *) ((mWaylandPopupNext->GetGtkWidget
())))))
) ==
2285 GDK_WINDOW_TYPE_HINT_UTILITY) {
2286 LOG("nsWindow::ApplyEnterLeaveMutterWorkaround(): leave toplevel")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindow::ApplyEnterLeaveMutterWorkaround(): leave toplevel"
, this->GetDebugTag().get()); } } while (0)
;
2287 return true;
2288 }
2289 // Leave (popup) case
2290 if (IsWaylandPopup() && mWaylandPopupNext &&
2291 gtk_window_get_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell)))))) ==
2292 GDK_WINDOW_TYPE_HINT_UTILITY) {
2293 LOG("nsWindow::ApplyEnterLeaveMutterWorkaround(): leave popup")do { const ::mozilla::LogModule* moz_real_module = this->IsPopup
() ? gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "nsWindow::ApplyEnterLeaveMutterWorkaround(): leave popup"
, this->GetDebugTag().get()); } } while (0)
;
2294 return true;
2295 }
2296 return false;
2297}
2298
2299void nsWindowWayland::OnMapNative() { MaybeCreatePipResources(); }