Bug Summary

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