Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp
Warning:line 2168, 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 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name nsWindow.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=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/widget/gtk -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/widget/gtk -resource-dir /usr/lib/llvm-19/lib/clang/19 -include /var/lib/jenkins/workspace/firefox-scan-build/config/gcc_hidden.h -include /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -I /var/lib/jenkins/workspace/firefox-scan-build/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 /var/lib/jenkins/workspace/firefox-scan-build/widget/gtk -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/widget/gtk -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /var/lib/jenkins/workspace/firefox-scan-build/ipc/chromium/src -I /var/lib/jenkins/workspace/firefox-scan-build/layout/base -I /var/lib/jenkins/workspace/firefox-scan-build/layout/forms -I /var/lib/jenkins/workspace/firefox-scan-build/layout/generic -I /var/lib/jenkins/workspace/firefox-scan-build/layout/xul -I /var/lib/jenkins/workspace/firefox-scan-build/other-licenses/atk-1.0 -I /var/lib/jenkins/workspace/firefox-scan-build/third_party/cups/include -I /var/lib/jenkins/workspace/firefox-scan-build/widget -I /var/lib/jenkins/workspace/firefox-scan-build/widget/headless -I /var/lib/jenkins/workspace/firefox-scan-build/widget/x11 -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -I /usr/include/atk-1.0 -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/gtk-3.0/unix-print -I /usr/include/gtk-3.0 -I /usr/include/pango-1.0 -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/cloudproviders -I /usr/include/atk-1.0 -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/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -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-deprecated-this-capture -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 -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 -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2024-09-22-115206-3586786-1 -x c++ /var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp
1/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2/* vim:expandtab:shiftwidth=2:tabstop=2:
3 */
4/* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8#include "nsWindow.h"
9
10#include <algorithm>
11#include <cstdint>
12#include <dlfcn.h>
13#include <gdk/gdkkeysyms.h>
14#include <wchar.h>
15
16#include "VsyncSource.h"
17#include "gfx2DGlue.h"
18#include "gfxContext.h"
19#include "gfxImageSurface.h"
20#include "gfxPlatformGtk.h"
21#include "gfxUtils.h"
22#include "GLContextProvider.h"
23#include "GLContext.h"
24#include "GtkCompositorWidget.h"
25#include "gtkdrawing.h"
26#include "imgIContainer.h"
27#include "InputData.h"
28#include "mozilla/ArrayUtils.h"
29#include "mozilla/Assertions.h"
30#include "mozilla/Components.h"
31#include "mozilla/GRefPtr.h"
32#include "mozilla/dom/Document.h"
33#include "mozilla/dom/WheelEventBinding.h"
34#include "mozilla/gfx/2D.h"
35#include "mozilla/gfx/gfxVars.h"
36#include "mozilla/gfx/GPUProcessManager.h"
37#include "mozilla/gfx/HelpersCairo.h"
38#include "mozilla/layers/APZThreadUtils.h"
39#include "mozilla/layers/LayersTypes.h"
40#include "mozilla/layers/CompositorBridgeChild.h"
41#include "mozilla/layers/CompositorBridgeParent.h"
42#include "mozilla/layers/CompositorThread.h"
43#include "mozilla/layers/KnowsCompositor.h"
44#include "mozilla/layers/WebRenderBridgeChild.h"
45#include "mozilla/layers/WebRenderLayerManager.h"
46#include "mozilla/layers/APZInputBridge.h"
47#include "mozilla/layers/IAPZCTreeManager.h"
48#include "mozilla/Likely.h"
49#include "mozilla/Maybe.h"
50#include "mozilla/MiscEvents.h"
51#include "mozilla/MouseEvents.h"
52#include "mozilla/NativeKeyBindingsType.h"
53#include "mozilla/Preferences.h"
54#include "mozilla/PresShell.h"
55#include "mozilla/ProfilerLabels.h"
56#include "mozilla/ScopeExit.h"
57#include "mozilla/StaticPrefs_apz.h"
58#include "mozilla/StaticPrefs_dom.h"
59#include "mozilla/StaticPrefs_layout.h"
60#include "mozilla/StaticPrefs_mozilla.h"
61#include "mozilla/StaticPrefs_ui.h"
62#include "mozilla/StaticPrefs_widget.h"
63#include "mozilla/SwipeTracker.h"
64#include "mozilla/TextEventDispatcher.h"
65#include "mozilla/TextEvents.h"
66#include "mozilla/TimeStamp.h"
67#include "mozilla/UniquePtrExtensions.h"
68#include "mozilla/WidgetUtils.h"
69#include "mozilla/WritingModes.h"
70#ifdef MOZ_X111
71# include "mozilla/X11Util.h"
72#endif
73#include "mozilla/XREAppData.h"
74#include "NativeKeyBindings.h"
75#include "nsAppDirectoryServiceDefs.h"
76#include "nsAppRunner.h"
77#include "nsDragService.h"
78#include "nsGTKToolkit.h"
79#include "nsGtkKeyUtils.h"
80#include "nsGtkCursors.h"
81#include "nsGfxCIID.h"
82#include "nsGtkUtils.h"
83#include "nsIFile.h"
84#include "nsIGSettingsService.h"
85#include "nsIInterfaceRequestorUtils.h"
86#include "nsImageToPixbuf.h"
87#include "nsINode.h"
88#include "nsIRollupListener.h"
89#include "nsIScreenManager.h"
90#include "nsIUserIdleServiceInternal.h"
91#include "nsIWidgetListener.h"
92#include "nsLayoutUtils.h"
93#include "nsMenuPopupFrame.h"
94#include "nsPresContext.h"
95#include "nsShmImage.h"
96#include "nsString.h"
97#include "nsWidgetsCID.h"
98#include "nsViewManager.h"
99#include "nsXPLookAndFeel.h"
100#include "prlink.h"
101#include "Screen.h"
102#include "ScreenHelperGTK.h"
103#include "SystemTimeConverter.h"
104#include "WidgetUtilsGtk.h"
105#include "NativeMenuGtk.h"
106
107#ifdef ACCESSIBILITY1
108# include "mozilla/a11y/LocalAccessible.h"
109# include "mozilla/a11y/Platform.h"
110# include "nsAccessibilityService.h"
111#endif
112
113#ifdef MOZ_X111
114# include <gdk/gdkkeysyms-compat.h>
115# include <X11/Xatom.h>
116# include <X11/extensions/XShm.h>
117# include <X11/extensions/shape.h>
118# include "gfxXlibSurface.h"
119# include "GLContextGLX.h" // for GLContextGLX::FindVisual()
120# include "GLContextEGL.h" // for GLContextEGL::FindVisual()
121# include "WindowSurfaceX11Image.h"
122# include "WindowSurfaceX11SHM.h"
123#endif
124#ifdef MOZ_WAYLAND1
125# include <gdk/gdkkeysyms-compat.h>
126# include "nsIClipboard.h"
127# include "nsView.h"
128#endif
129
130using namespace mozilla;
131using namespace mozilla::gfx;
132using namespace mozilla::layers;
133using namespace mozilla::widget;
134#ifdef MOZ_X111
135using mozilla::gl::GLContextEGL;
136using mozilla::gl::GLContextGLX;
137#endif
138
139// Don't put more than this many rects in the dirty region, just fluff
140// out to the bounding-box if there are more
141#define MAX_RECTS_IN_REGION100 100
142
143#if !GTK_CHECK_VERSION(3, 18, 0)((3) > (3) || ((3) == (3) && (24) > (18)) || ((
3) == (3) && (24) == (18) && (43) >= (0)))
144struct _GdkEventTouchpadPinch {
145 GdkEventType type;
146 GdkWindow* window;
147 gint8 send_event;
148 gint8 phase;
149 gint8 n_fingers;
150 guint32 time;
151 gdouble x;
152 gdouble y;
153 gdouble dx;
154 gdouble dy;
155 gdouble angle_delta;
156 gdouble scale;
157 gdouble x_root, y_root;
158 guint state;
159};
160
161gint GDK_TOUCHPAD_GESTURE_MASK = 1 << 24;
162GdkEventType GDK_TOUCHPAD_PINCH = static_cast<GdkEventType>(42);
163#endif
164
165const gint kEvents = GDK_TOUCHPAD_GESTURE_MASK | GDK_EXPOSURE_MASK |
166 GDK_STRUCTURE_MASK | GDK_VISIBILITY_NOTIFY_MASK |
167 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
168 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
169 GDK_SMOOTH_SCROLL_MASK | GDK_TOUCH_MASK | GDK_SCROLL_MASK |
170 GDK_POINTER_MOTION_MASK | GDK_PROPERTY_CHANGE_MASK;
171
172/* utility functions */
173static bool is_mouse_in_window(GdkWindow* aWindow, gdouble aMouseX,
174 gdouble aMouseY);
175static nsWindow* get_window_for_gtk_widget(GtkWidget* widget);
176static nsWindow* get_window_for_gdk_window(GdkWindow* window);
177static GtkWidget* get_gtk_widget_for_gdk_window(GdkWindow* window);
178static GdkCursor* get_gtk_cursor(nsCursor aCursor);
179
180/* callbacks from widgets */
181static gboolean expose_event_cb(GtkWidget* widget, cairo_t* cr);
182static gboolean configure_event_cb(GtkWidget* widget, GdkEventConfigure* event);
183static void size_allocate_cb(GtkWidget* widget, GtkAllocation* allocation);
184static void toplevel_window_size_allocate_cb(GtkWidget* widget,
185 GtkAllocation* allocation);
186static gboolean delete_event_cb(GtkWidget* widget, GdkEventAny* event);
187static gboolean enter_notify_event_cb(GtkWidget* widget,
188 GdkEventCrossing* event);
189static gboolean leave_notify_event_cb(GtkWidget* widget,
190 GdkEventCrossing* event);
191static gboolean motion_notify_event_cb(GtkWidget* widget,
192 GdkEventMotion* event);
193MOZ_CAN_RUN_SCRIPT static gboolean button_press_event_cb(GtkWidget* widget,
194 GdkEventButton* event);
195static gboolean button_release_event_cb(GtkWidget* widget,
196 GdkEventButton* event);
197static gboolean focus_in_event_cb(GtkWidget* widget, GdkEventFocus* event);
198static gboolean focus_out_event_cb(GtkWidget* widget, GdkEventFocus* event);
199static gboolean key_press_event_cb(GtkWidget* widget, GdkEventKey* event);
200static gboolean key_release_event_cb(GtkWidget* widget, GdkEventKey* event);
201static gboolean property_notify_event_cb(GtkWidget* widget,
202 GdkEventProperty* event);
203static gboolean scroll_event_cb(GtkWidget* widget, GdkEventScroll* event);
204static gboolean visibility_notify_event_cb(GtkWidget* widget,
205 GdkEventVisibility* event);
206static void hierarchy_changed_cb(GtkWidget* widget,
207 GtkWidget* previous_toplevel);
208static gboolean window_state_event_cb(GtkWidget* widget,
209 GdkEventWindowState* event);
210static void settings_xft_dpi_changed_cb(GtkSettings* settings,
211 GParamSpec* pspec, nsWindow* data);
212static void check_resize_cb(GtkContainer* container, gpointer user_data);
213static void screen_composited_changed_cb(GdkScreen* screen, gpointer user_data);
214static void widget_composited_changed_cb(GtkWidget* widget, gpointer user_data);
215
216static void scale_changed_cb(GtkWidget* widget, GParamSpec* aPSpec,
217 gpointer aPointer);
218static gboolean touch_event_cb(GtkWidget* aWidget, GdkEventTouch* aEvent);
219static gboolean generic_event_cb(GtkWidget* widget, GdkEvent* aEvent);
220
221#ifdef __cplusplus201703L
222extern "C" {
223#endif /* __cplusplus */
224#ifdef MOZ_X111
225static GdkFilterReturn popup_take_focus_filter(GdkXEvent* gdk_xevent,
226 GdkEvent* event, gpointer data);
227#endif /* MOZ_X11 */
228#ifdef __cplusplus201703L
229}
230#endif /* __cplusplus */
231
232static gboolean drag_motion_event_cb(GtkWidget* aWidget,
233 GdkDragContext* aDragContext, gint aX,
234 gint aY, guint aTime, gpointer aData);
235static void drag_leave_event_cb(GtkWidget* aWidget,
236 GdkDragContext* aDragContext, guint aTime,
237 gpointer aData);
238static gboolean drag_drop_event_cb(GtkWidget* aWidget,
239 GdkDragContext* aDragContext, gint aX,
240 gint aY, guint aTime, gpointer aData);
241static void drag_data_received_event_cb(GtkWidget* aWidget,
242 GdkDragContext* aDragContext, gint aX,
243 gint aY,
244 GtkSelectionData* aSelectionData,
245 guint aInfo, guint32 aTime,
246 gpointer aData);
247
248/* initialization static functions */
249static nsresult initialize_prefs(void);
250
251static guint32 sLastUserInputTime = GDK_CURRENT_TIME0L;
252
253static SystemTimeConverter<guint32>& TimeConverter() {
254 static SystemTimeConverter<guint32> sTimeConverterSingleton;
255 return sTimeConverterSingleton;
256}
257
258bool nsWindow::sTransparentMainWindow = false;
259
260// forward declare from mozgtk
261extern "C" MOZ_EXPORT__attribute__((visibility("default"))) void mozgtk_linker_holder();
262
263namespace mozilla {
264
265#ifdef MOZ_X111
266class CurrentX11TimeGetter {
267 public:
268 explicit CurrentX11TimeGetter(GdkWindow* aWindow) : mWindow(aWindow) {}
269
270 guint32 GetCurrentTime() const { return gdk_x11_get_server_time(mWindow); }
271
272 void GetTimeAsyncForPossibleBackwardsSkew(const TimeStamp& aNow) {
273 // Check for in-flight request
274 if (!mAsyncUpdateStart.IsNull()) {
275 return;
276 }
277 mAsyncUpdateStart = aNow;
278
279 Display* xDisplay = GDK_WINDOW_XDISPLAY(mWindow)((gdk_x11_display_get_xdisplay (gdk_window_get_display (mWindow
))))
;
280 Window xWindow = GDK_WINDOW_XID(mWindow)(gdk_x11_window_get_xid (mWindow));
281 unsigned char c = 'a';
282 Atom timeStampPropAtom = TimeStampPropAtom();
283 XChangeProperty(xDisplay, xWindow, timeStampPropAtom, timeStampPropAtom, 8,
284 PropModeReplace0, &c, 1);
285 XFlush(xDisplay);
286 }
287
288 gboolean PropertyNotifyHandler(GtkWidget* aWidget, GdkEventProperty* aEvent) {
289 if (aEvent->atom != gdk_x11_xatom_to_atom(TimeStampPropAtom())) {
290 return FALSE(0);
291 }
292
293 guint32 eventTime = aEvent->time;
294 TimeStamp lowerBound = mAsyncUpdateStart;
295
296 TimeConverter().CompensateForBackwardsSkew(eventTime, lowerBound);
297 mAsyncUpdateStart = TimeStamp();
298 return TRUE(!(0));
299 }
300
301 private:
302 static Atom TimeStampPropAtom() {
303 return gdk_x11_get_xatom_by_name_for_display(gdk_display_get_default(),
304 "GDK_TIMESTAMP_PROP");
305 }
306
307 // This is safe because this class is stored as a member of mWindow and
308 // won't outlive it.
309 GdkWindow* mWindow;
310 TimeStamp mAsyncUpdateStart;
311};
312#endif
313
314} // namespace mozilla
315
316// The window from which the focus manager asks us to dispatch key events.
317static nsWindow* gFocusWindow = nullptr;
318static bool gBlockActivateEvent = false;
319static bool gGlobalsInitialized = false;
320static bool gUseAspectRatio = true;
321static uint32_t gLastTouchID = 0;
322// See Bug 1777269 for details. We don't know if the suspected leave notify
323// event is a correct one when we get it.
324// Store it and issue it later from enter notify event if it's correct,
325// throw it away otherwise.
326static GUniquePtr<GdkEventCrossing> sStoredLeaveNotifyEvent;
327
328#define NS_WINDOW_TITLE_MAX_LENGTH4095 4095
329
330// cursor cache
331static GdkCursor* gCursorCache[eCursorCount];
332
333// Sometimes this actually also includes the state of the modifier keys, but
334// only the button state bits are used.
335static guint gButtonState;
336
337static inline bool TimestampIsNewerThan(guint32 a, guint32 b) {
338 // Timestamps are just the least significant bits of a monotonically
339 // increasing function, and so the use of unsigned overflow arithmetic.
340 return a - b <= G_MAXUINT32((guint32) 0xffffffff) / 2;
341}
342
343static void UpdateLastInputEventTime(void* aGdkEvent) {
344 nsCOMPtr<nsIUserIdleServiceInternal> idleService =
345 do_GetService("@mozilla.org/widget/useridleservice;1");
346 if (idleService) {
347 idleService->ResetIdleTimeOut(0);
348 }
349
350 guint timestamp = gdk_event_get_time(static_cast<GdkEvent*>(aGdkEvent));
351 if (timestamp == GDK_CURRENT_TIME0L) {
352 return;
353 }
354
355 sLastUserInputTime = timestamp;
356}
357
358// Don't set parent (transient for) if nothing changes.
359// gtk_window_set_transient_for() blows up wl_subsurfaces used by aWindow
360// even if aParent is the same.
361static void GtkWindowSetTransientFor(GtkWindow* aWindow, GtkWindow* aParent) {
362 GtkWindow* parent = gtk_window_get_transient_for(aWindow);
363 if (parent != aParent) {
364 gtk_window_set_transient_for(aWindow, aParent){ do { static_assert( mozilla::detail::AssertionConditionType
<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"gtk_window_set_transient_for() can't be used directly." ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 364); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "gtk_window_set_transient_for() can't be used directly."
")"); do { *((volatile int*)__null) = 364; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); }
;
365 }
366}
367
368#define gtk_window_set_transient_for(a, b){ do { static_assert( mozilla::detail::AssertionConditionType
<decltype(false)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"gtk_window_set_transient_for() can't be used directly." ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 368); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "gtk_window_set_transient_for() can't be used directly."
")"); do { *((volatile int*)__null) = 368; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); }
\
369 { \
370 MOZ_ASSERT_UNREACHABLE( \do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"gtk_window_set_transient_for() can't be used directly." ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 371); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "gtk_window_set_transient_for() can't be used directly."
")"); do { *((volatile int*)__null) = 371; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
371 "gtk_window_set_transient_for() can't be used directly.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"gtk_window_set_transient_for() can't be used directly." ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 371); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "gtk_window_set_transient_for() can't be used directly."
")"); do { *((volatile int*)__null) = 371; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
; \
372 }
373
374nsWindow::nsWindow()
375 : mWindowVisibilityMutex("nsWindow::mWindowVisibilityMutex"),
376 mIsMapped(false),
377 mIsDestroyed(false),
378 mIsShown(false),
379 mNeedsShow(false),
380 mEnabled(true),
381 mCreated(false),
382 mHandleTouchEvent(false),
383 mIsDragPopup(false),
384 mCompositedScreen(gdk_screen_is_composited(gdk_screen_get_default())),
385 mIsAccelerated(false),
386 mIsAlert(false),
387 mWindowShouldStartDragging(false),
388 mHasMappedToplevel(false),
389 mPanInProgress(false),
390 mTitlebarBackdropState(false),
391 mIsChildWindow(false),
392 mAlwaysOnTop(false),
393 mNoAutoHide(false),
394 mIsTransparent(false),
395 mHasReceivedSizeAllocate(false),
396 mWidgetCursorLocked(false),
397 mUndecorated(false),
398 mPopupTrackInHierarchy(false),
399 mPopupTrackInHierarchyConfigured(false),
400 mHiddenPopupPositioned(false),
401 mHasAlphaVisual(false),
402 mPopupAnchored(false),
403 mPopupContextMenu(false),
404 mPopupMatchesLayout(false),
405 mPopupChanged(false),
406 mPopupTemporaryHidden(false),
407 mPopupClosed(false),
408 mPopupUseMoveToRect(false),
409 mWaitingForMoveToRectCallback(false),
410 mMovedAfterMoveToRect(false),
411 mResizedAfterMoveToRect(false),
412 mConfiguredClearColor(false),
413 mGotNonBlankPaint(false),
414 mNeedsToRetryCapturingMouse(false) {
415 mWindowType = WindowType::Child;
416 mSizeConstraints.mMaxSize = GetSafeWindowSize(mSizeConstraints.mMaxSize);
417
418 if (!gGlobalsInitialized) {
419 gGlobalsInitialized = true;
420
421 // It's OK if either of these fail, but it may not be one day.
422 initialize_prefs();
423
424#ifdef MOZ_WAYLAND1
425 // Wayland provides clipboard data to application on focus-in event
426 // so we need to init our clipboard hooks before we create window
427 // and get focus.
428 if (GdkIsWaylandDisplay()) {
429 nsCOMPtr<nsIClipboard> clipboard =
430 do_GetService("@mozilla.org/widget/clipboard;1");
431 NS_ASSERTION(clipboard, "Failed to init clipboard!")do { if (!(clipboard)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Failed to init clipboard!"
, "clipboard", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 431); MOZ_PretendNoReturn(); } } while (0)
;
432 }
433#endif
434 }
435 // Dummy call to mozgtk to prevent the linker from removing
436 // the dependency with --as-needed.
437 // see toolkit/library/moz.build for details.
438 mozgtk_linker_holder();
439}
440
441nsWindow::~nsWindow() {
442 LOG("nsWindow::~nsWindow()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::~nsWindow()", GetDebugTag
().get()); } } while (0)
;
443 Destroy();
444}
445
446/* static */
447void nsWindow::ReleaseGlobals() {
448 for (auto& cursor : gCursorCache) {
449 if (cursor) {
450 g_object_unref(cursor);
451 cursor = nullptr;
452 }
453 }
454}
455
456void nsWindow::DispatchActivateEvent(void) {
457#ifdef ACCESSIBILITY1
458 DispatchActivateEventAccessible();
459#endif // ACCESSIBILITY
460
461 if (mWidgetListener) mWidgetListener->WindowActivated();
462}
463
464void nsWindow::DispatchDeactivateEvent() {
465 if (mWidgetListener) {
466 mWidgetListener->WindowDeactivated();
467 }
468
469#ifdef ACCESSIBILITY1
470 DispatchDeactivateEventAccessible();
471#endif // ACCESSIBILITY
472}
473
474void nsWindow::DispatchResized() {
475 LOG("nsWindow::DispatchResized() size [%d, %d]", (int)(mBounds.width),do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::DispatchResized() size [%d, %d]"
, GetDebugTag().get(), (int)(mBounds.width), (int)(mBounds.height
)); } } while (0)
476 (int)(mBounds.height))do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::DispatchResized() size [%d, %d]"
, GetDebugTag().get(), (int)(mBounds.width), (int)(mBounds.height
)); } } while (0)
;
477
478 mNeedsDispatchSize = LayoutDeviceIntSize(-1, -1);
479 if (mWidgetListener) {
480 mWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
481 }
482 if (mAttachedWidgetListener) {
483 mAttachedWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
484 }
485}
486
487void nsWindow::MaybeDispatchResized() {
488 if (mNeedsDispatchSize != LayoutDeviceIntSize(-1, -1) && !mIsDestroyed) {
489 mBounds.SizeTo(mNeedsDispatchSize);
490 // Check mBounds size
491 if (mCompositorSession &&
492 !wr::WindowSizeSanityCheck(mBounds.width, mBounds.height)) {
493 gfxCriticalNoteOncestatic mozilla::gfx::CriticalLog sOnceAtLine493 = mozilla::gfx
::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions(false
))
<< "Invalid mBounds in MaybeDispatchResized "
494 << mBounds << " size state " << mSizeMode;
495 }
496
497 // Notify the GtkCompositorWidget of a ClientSizeChange
498 if (mCompositorWidgetDelegate) {
499 mCompositorWidgetDelegate->NotifyClientSizeChanged(GetClientSize());
500 }
501
502 DispatchResized();
503 }
504}
505
506nsIWidgetListener* nsWindow::GetListener() {
507 return mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
508}
509
510nsresult nsWindow::DispatchEvent(WidgetGUIEvent* aEvent,
511 nsEventStatus& aStatus) {
512#ifdef DEBUG1
513 debug_DumpEvent(stdoutstdout, aEvent->mWidget, aEvent, "something", 0);
514#endif
515 aStatus = nsEventStatus_eIgnore;
516 nsIWidgetListener* listener = GetListener();
517 if (listener) {
518 aStatus = listener->HandleEvent(aEvent, mUseAttachedEvents);
519 }
520
521 return NS_OK;
522}
523
524void nsWindow::OnDestroy(void) {
525 if (mOnDestroyCalled) {
526 return;
527 }
528
529 mOnDestroyCalled = true;
530
531 // Prevent deletion.
532 nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
533
534 // release references to children, device context, toolkit + app shell
535 nsBaseWidget::OnDestroy();
536
537 // Remove association between this object and its parent and siblings.
538 nsBaseWidget::Destroy();
539 mParent = nullptr;
540
541 NotifyWindowDestroyed();
542}
543
544bool nsWindow::AreBoundsSane() {
545 // Check requested size, as mBounds might not have been updated.
546 return !mLastSizeRequest.IsEmpty();
547}
548
549void nsWindow::Destroy() {
550 MOZ_DIAGNOSTIC_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 550); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 550; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
551
552 if (mIsDestroyed || !mCreated) {
553 return;
554 }
555
556 LOG("nsWindow::Destroy\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::Destroy\n", GetDebugTag(
).get()); } } while (0)
;
557
558 mIsDestroyed = true;
559 mCreated = false;
560
561 MozClearHandleID(mCompositorPauseTimeoutID, g_source_remove);
562
563#ifdef MOZ_WAYLAND1
564 // Shut down our local vsync source
565 if (mWaylandVsyncSource) {
566 mWaylandVsyncSource->Shutdown();
567 mWaylandVsyncSource = nullptr;
568 }
569 mWaylandVsyncDispatcher = nullptr;
570 UnlockNativePointer();
571#endif
572
573 // Cancel (dragleave) the current drag session, if any.
574 RefPtr<nsDragService> dragService = nsDragService::GetInstance();
575 if (dragService) {
576 nsDragSession* dragSession =
577 static_cast<nsDragSession*>(dragService->GetCurrentSession(this));
578 if (dragSession && this == dragSession->GetMostRecentDestWindow()) {
579 dragSession->ScheduleLeaveEvent();
580 }
581 }
582
583 nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
584 if (rollupListener) {
585 nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
586 if (static_cast<nsIWidget*>(this) == rollupWidget) {
587 rollupListener->Rollup({});
588 }
589 }
590
591 NativeShow(false);
592
593 MOZ_ASSERT(!gtk_widget_get_mapped(mShell))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!gtk_widget_get_mapped(mShell))>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!gtk_widget_get_mapped(mShell
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!gtk_widget_get_mapped(mShell)", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 593); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gtk_widget_get_mapped(mShell)"
")"); do { *((volatile int*)__null) = 593; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
594 MOZ_ASSERT(!gtk_widget_get_mapped(GTK_WIDGET(mContainer)))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!gtk_widget_get_mapped(((((GtkWidget*) (void *) ((mContainer
)))))))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!gtk_widget_get_mapped(((((GtkWidget*) (void *) ((mContainer
))))))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!gtk_widget_get_mapped(((((GtkWidget*) (void *) ((mContainer))))))"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 594); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gtk_widget_get_mapped(((((GtkWidget*) (void *) ((mContainer))))))"
")"); do { *((volatile int*)__null) = 594; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
595
596 DestroyLayerManager();
597
598 // mSurfaceProvider holds reference to this nsWindow so we need to explicitly
599 // clear it here to avoid nsWindow leak.
600 mSurfaceProvider.CleanupResources();
601
602 g_signal_handlers_disconnect_by_data(gtk_settings_get_default(), this)g_signal_handlers_disconnect_matched ((gtk_settings_get_default
()), G_SIGNAL_MATCH_DATA, 0, 0, __null, __null, (this))
;
603
604 if (mIMContext) {
605 mIMContext->OnDestroyWindow(this);
606 }
607
608 // make sure that we remove ourself as the focus window
609 if (gFocusWindow == this) {
610 LOG("automatically losing focus...\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "automatically losing focus...\n", GetDebugTag
().get()); } } while (0)
;
611 gFocusWindow = nullptr;
612 }
613
614 if (sStoredLeaveNotifyEvent) {
615 nsWindow* window =
616 get_window_for_gdk_window(sStoredLeaveNotifyEvent->window);
617 if (window == this) {
618 sStoredLeaveNotifyEvent = nullptr;
619 }
620 }
621
622 // We need to detach accessible object here because mContainer is a custom
623 // widget and doesn't call gtk_widget_real_destroy() from destroy handler
624 // as regular widgets.
625 if (AtkObject* ac = gtk_widget_get_accessible(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))))) {
626 gtk_accessible_set_widget(GTK_ACCESSIBLE(ac)((((GtkAccessible*) (void *) ((ac))))), nullptr);
627 }
628
629 gtk_widget_destroy(mShell);
630 mShell = nullptr;
631 mContainer = nullptr;
632
633 MOZ_ASSERT(!mGdkWindow,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mGdkWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mGdkWindow))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mGdkWindow" " ("
"mGdkWindow should be NULL when mContainer is destroyed" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 634); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mGdkWindow"
") (" "mGdkWindow should be NULL when mContainer is destroyed"
")"); do { *((volatile int*)__null) = 634; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
634 "mGdkWindow should be NULL when mContainer is destroyed")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mGdkWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mGdkWindow))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mGdkWindow" " ("
"mGdkWindow should be NULL when mContainer is destroyed" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 634); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mGdkWindow"
") (" "mGdkWindow should be NULL when mContainer is destroyed"
")"); do { *((volatile int*)__null) = 634; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
635
636#ifdef ACCESSIBILITY1
637 if (mRootAccessible) {
638 mRootAccessible = nullptr;
639 }
640#endif
641
642 // Save until last because OnDestroy() may cause us to be deleted.
643 OnDestroy();
644}
645
646nsIWidget* nsWindow::GetParent() { return mParent; }
647
648float nsWindow::GetDPI() {
649 float dpi = 96.0f;
650 nsCOMPtr<nsIScreen> screen = GetWidgetScreen();
651 if (screen) {
652 screen->GetDpi(&dpi);
653 }
654 return dpi;
655}
656
657double nsWindow::GetDefaultScaleInternal() { return FractionalScaleFactor(); }
658
659DesktopToLayoutDeviceScale nsWindow::GetDesktopToDeviceScale() {
660#ifdef MOZ_WAYLAND1
661 if (GdkIsWaylandDisplay()) {
662 return DesktopToLayoutDeviceScale(FractionalScaleFactor());
663 }
664#endif
665
666 // In Gtk/X11, we manage windows using device pixels.
667 return DesktopToLayoutDeviceScale(1.0);
668}
669
670DesktopToLayoutDeviceScale nsWindow::GetDesktopToDeviceScaleByScreen() {
671#ifdef MOZ_WAYLAND1
672 // In Wayland there's no way to get absolute position of the window and use it
673 // to determine the screen factor of the monitor on which the window is
674 // placed. The window is notified of the current scale factor but not at this
675 // point, so the GdkScaleFactor can return wrong value which can lead to wrong
676 // popup placement. We need to use parent's window scale factor for the new
677 // one.
678 if (GdkIsWaylandDisplay()) {
679 nsView* view = nsView::GetViewFor(this);
680 if (view) {
681 nsView* parentView = view->GetParent();
682 if (parentView) {
683 nsIWidget* parentWidget = parentView->GetNearestWidget(nullptr);
684 if (parentWidget) {
685 return DesktopToLayoutDeviceScale(
686 parentWidget->RoundsWidgetCoordinatesTo());
687 }
688 NS_WARNING("Widget has no parent")NS_DebugBreak(NS_DEBUG_WARNING, "Widget has no parent", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 688)
;
689 }
690 } else {
691 NS_WARNING("Cannot find widget view")NS_DebugBreak(NS_DEBUG_WARNING, "Cannot find widget view", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 691)
;
692 }
693 }
694#endif
695 return nsBaseWidget::GetDesktopToDeviceScale();
696}
697
698// Reparent a child window to a new parent.
699void nsWindow::SetParent(nsIWidget* aNewParent) {
700 LOG("nsWindow::SetParent() new parent %p", aNewParent)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetParent() new parent %p"
, GetDebugTag().get(), aNewParent); } } while (0)
;
701 if (!mIsChildWindow) {
702 NS_WARNING("Used by child widgets only")NS_DebugBreak(NS_DEBUG_WARNING, "Used by child widgets only",
nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 702)
;
703 return;
704 }
705
706 nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
707 if (mParent) {
708 mParent->RemoveChild(this);
709 }
710 mParent = aNewParent;
711
712 // We're already deleted, quit.
713 if (!mGdkWindow || mIsDestroyed || !aNewParent) {
714 return;
715 }
716 aNewParent->AddChild(this);
717
718 auto* newParent = static_cast<nsWindow*>(aNewParent);
719
720 // New parent is deleted, quit.
721 if (newParent->mIsDestroyed) {
722 Destroy();
723 return;
724 }
725
726 GdkWindow* window = GetToplevelGdkWindow();
727 GdkWindow* parentWindow = newParent->GetToplevelGdkWindow();
728 LOG(" child GdkWindow %p set parent GdkWindow %p", window, parentWindow)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " child GdkWindow %p set parent GdkWindow %p"
, GetDebugTag().get(), window, parentWindow); } } while (0)
;
729 gdk_window_reparent(window, parentWindow, 0, 0);
730 SetHasMappedToplevel(newParent && newParent->mHasMappedToplevel);
731}
732
733bool nsWindow::WidgetTypeSupportsAcceleration() {
734 if (mWindowType == WindowType::Invisible) {
735 return false;
736 }
737
738 if (IsSmallPopup()) {
739 return false;
740 }
741 // Workaround for Bug 1479135
742 // We draw transparent popups on non-compositing screens by SW as we don't
743 // implement X shape masks in WebRender.
744 if (mWindowType == WindowType::Popup) {
745 return HasRemoteContent() && mCompositedScreen;
746 }
747
748 return true;
749}
750
751void nsWindow::ReparentNativeWidget(nsIWidget* aNewParent) {
752 MOZ_ASSERT(aNewParent, "null widget")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aNewParent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aNewParent))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aNewParent" " (" "null widget"
")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 752); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent" ") ("
"null widget" ")"); do { *((volatile int*)__null) = 752; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
753 MOZ_ASSERT(!mIsDestroyed, "")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mIsDestroyed)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mIsDestroyed))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!mIsDestroyed" " ("
"" ")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 753); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mIsDestroyed"
") (" "" ")"); do { *((volatile int*)__null) = 753; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
754 MOZ_ASSERT(!static_cast<nsWindow*>(aNewParent)->mIsDestroyed, "")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!static_cast<nsWindow*>(aNewParent)->mIsDestroyed
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(!static_cast<nsWindow*>(aNewParent)->mIsDestroyed
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!static_cast<nsWindow*>(aNewParent)->mIsDestroyed" " ("
"" ")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 754); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!static_cast<nsWindow*>(aNewParent)->mIsDestroyed"
") (" "" ")"); do { *((volatile int*)__null) = 754; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
755 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mParent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mParent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mParent" " (" "nsWindow::ReparentNativeWidget() works on toplevel windows only."
")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 757); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mParent" ") ("
"nsWindow::ReparentNativeWidget() works on toplevel windows only."
")"); do { *((volatile int*)__null) = 757; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
756 !mParent,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mParent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mParent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mParent" " (" "nsWindow::ReparentNativeWidget() works on toplevel windows only."
")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 757); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mParent" ") ("
"nsWindow::ReparentNativeWidget() works on toplevel windows only."
")"); do { *((volatile int*)__null) = 757; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
757 "nsWindow::ReparentNativeWidget() works on toplevel windows only.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mParent)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mParent))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("!mParent" " (" "nsWindow::ReparentNativeWidget() works on toplevel windows only."
")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 757); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mParent" ") ("
"nsWindow::ReparentNativeWidget() works on toplevel windows only."
")"); do { *((volatile int*)__null) = 757; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
758
759 auto* newParent = static_cast<nsWindow*>(aNewParent);
760 GtkWindow* newParentWidget = GTK_WINDOW(newParent->GetGtkWidget())((((GtkWindow*) (void *) ((newParent->GetGtkWidget())))));
761
762 LOG("nsWindow::ReparentNativeWidget new parent %p\n", newParent)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::ReparentNativeWidget new parent %p\n"
, GetDebugTag().get(), newParent); } } while (0)
;
763 GtkWindowSetTransientFor(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), newParentWidget);
764}
765
766static void InitPenEvent(WidgetMouseEvent& aGeckoEvent, GdkEvent* aEvent) {
767 // Find the source of the event
768 GdkDevice* device = gdk_event_get_source_device(aEvent);
769 GdkInputSource eSource = gdk_device_get_source(device);
770 gdouble value;
771
772 // We distinguish touch screens from pens using the event type
773 // Eraser corresponds to the pen with the "erase" button pressed
774 if (eSource != GDK_SOURCE_PEN && eSource != GDK_SOURCE_ERASER) {
775 bool XWaylandPen = false;
776#ifdef MOZ_X111
777 // Workaround : When using Xwayland, pens are reported as
778 // GDK_SOURCE_TOUCHSCREEN If eSource is GDK_SOURCE_TOUCHSCREEN and the
779 // GDK_AXIS_XTILT and GDK_AXIS_YTILT axes are reported then it's a pen and
780 // not a finger on a screen. Yes, that's a stupid heuristic but it works...
781 // Note, however, that the tilt values are not reliable
782 // Another approach could be use the device tool type, but that's only
783 // available in GTK > 3.22
784 XWaylandPen = (eSource == GDK_SOURCE_TOUCHSCREEN && GdkIsX11Display() &&
785 gdk_event_get_axis(aEvent, GDK_AXIS_XTILT, &value) &&
786 gdk_event_get_axis(aEvent, GDK_AXIS_YTILT, &value));
787#endif
788 if (!XWaylandPen) {
789 return;
790 }
791 LOGW("InitPenEvent(): Is XWayland pen")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, "InitPenEvent(): Is XWayland pen"
); } } while (0)
;
792 }
793
794 aGeckoEvent.mInputSource = dom::MouseEvent_Binding::MOZ_SOURCE_PEN;
795 aGeckoEvent.pointerId = 1;
796
797 // The range of xtilt and ytilt are -1 to 1. Normalize it to -90 to 90.
798 if (gdk_event_get_axis(aEvent, GDK_AXIS_XTILT, &value)) {
799 aGeckoEvent.tiltX = int32_t(NS_round(value * 90));
800 }
801 if (gdk_event_get_axis(aEvent, GDK_AXIS_YTILT, &value)) {
802 aGeckoEvent.tiltY = int32_t(NS_round(value * 90));
803 }
804 if (gdk_event_get_axis(aEvent, GDK_AXIS_PRESSURE, &value)) {
805 aGeckoEvent.mPressure = (float)value;
806 // Make sure the pression is acceptable
807 MOZ_ASSERT(aGeckoEvent.mPressure >= 0.0 && aGeckoEvent.mPressure <= 1.0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aGeckoEvent.mPressure >= 0.0 && aGeckoEvent
.mPressure <= 1.0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aGeckoEvent.mPressure >= 0.0
&& aGeckoEvent.mPressure <= 1.0))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aGeckoEvent.mPressure >= 0.0 && aGeckoEvent.mPressure <= 1.0"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 807); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGeckoEvent.mPressure >= 0.0 && aGeckoEvent.mPressure <= 1.0"
")"); do { *((volatile int*)__null) = 807; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
808 }
809
810 LOGW("InitPenEvent(): pressure %f\n", aGeckoEvent.mPressure)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, "InitPenEvent(): pressure %f\n"
, aGeckoEvent.mPressure); } } while (0)
;
811}
812
813void nsWindow::SetModal(bool aModal) {
814 LOG("nsWindow::SetModal %d\n", aModal)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetModal %d\n", GetDebugTag
().get(), aModal); } } while (0)
;
815 if (mIsDestroyed) {
816 return;
817 }
818
819 gtk_window_set_modal(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), aModal ? TRUE(!(0)) : FALSE(0));
820}
821
822// nsIWidget method, which means IsShown.
823bool nsWindow::IsVisible() const { return mIsShown; }
824
825bool nsWindow::IsMapped() const { return mIsMapped; }
826
827void nsWindow::RegisterTouchWindow() {
828 mHandleTouchEvent = true;
829 mTouches.Clear();
830}
831
832LayoutDeviceIntPoint nsWindow::GetScreenEdgeSlop() {
833 if (DrawsToCSDTitlebar()) {
834 return GetClientOffset();
835 }
836 return {};
837}
838
839void nsWindow::ConstrainPosition(DesktopIntPoint& aPoint) {
840 if (!mShell || GdkIsWaylandDisplay()) {
841 return;
842 }
843
844 double dpiScale = GetDefaultScale().scale;
845
846 // we need to use the window size in logical screen pixels
847 int32_t logWidth = std::max(NSToIntRound(mBounds.width / dpiScale), 1);
848 int32_t logHeight = std::max(NSToIntRound(mBounds.height / dpiScale), 1);
849
850 /* get our playing field. use the current screen, or failing that
851 for any reason, use device caps for the default screen. */
852 nsCOMPtr<nsIScreenManager> screenmgr =
853 do_GetService("@mozilla.org/gfx/screenmanager;1");
854 if (!screenmgr) {
855 return;
856 }
857 nsCOMPtr<nsIScreen> screen;
858 screenmgr->ScreenForRect(aPoint.x, aPoint.y, logWidth, logHeight,
859 getter_AddRefs(screen));
860 // We don't have any screen so leave the coordinates as is
861 if (!screen) {
862 return;
863 }
864
865 // For normalized windows, use the desktop work area.
866 // For full screen windows, use the desktop.
867 DesktopIntRect screenRect = mSizeMode == nsSizeMode_Fullscreen
868 ? screen->GetRectDisplayPix()
869 : screen->GetAvailRectDisplayPix();
870
871 // Expand for the decoration size if needed.
872 auto slop =
873 DesktopIntPoint::Round(GetScreenEdgeSlop() / GetDesktopToDeviceScale());
874 screenRect.Inflate(slop.x, slop.y);
875
876 if (aPoint.x < screenRect.x) {
877 aPoint.x = screenRect.x;
878 } else if (aPoint.x >= screenRect.XMost() - logWidth) {
879 aPoint.x = screenRect.XMost() - logWidth;
880 }
881
882 if (aPoint.y < screenRect.y) {
883 aPoint.y = screenRect.y;
884 } else if (aPoint.y >= screenRect.YMost() - logHeight) {
885 aPoint.y = screenRect.YMost() - logHeight;
886 }
887}
888
889void nsWindow::SetSizeConstraints(const SizeConstraints& aConstraints) {
890 mSizeConstraints.mMinSize = GetSafeWindowSize(aConstraints.mMinSize);
891 mSizeConstraints.mMaxSize = GetSafeWindowSize(aConstraints.mMaxSize);
892
893 ApplySizeConstraints();
894}
895
896bool nsWindow::DrawsToCSDTitlebar() const {
897 return mSizeMode == nsSizeMode_Normal &&
898 mGtkWindowDecoration == GTK_DECORATION_CLIENT && mDrawInTitlebar;
899}
900
901void nsWindow::AddCSDDecorationSize(int* aWidth, int* aHeight) {
902 if (mSizeMode != nsSizeMode_Normal || mUndecorated ||
903 mGtkWindowDecoration != GTK_DECORATION_CLIENT || !GdkIsWaylandDisplay() ||
904 !IsGnomeDesktopEnvironment()) {
905 return;
906 }
907
908 GtkBorder decorationSize = GetCSDDecorationSize(IsPopup());
909 *aWidth += decorationSize.left + decorationSize.right;
910 *aHeight += decorationSize.top + decorationSize.bottom;
911}
912
913#ifdef MOZ_WAYLAND1
914bool nsWindow::GetCSDDecorationOffset(int* aDx, int* aDy) {
915 if (!DrawsToCSDTitlebar()) {
916 return false;
917 }
918 GtkBorder decorationSize = GetCSDDecorationSize(IsPopup());
919 *aDx = decorationSize.left;
920 *aDy = decorationSize.top;
921 return true;
922}
923#endif
924
925void nsWindow::ApplySizeConstraints() {
926 if (mShell) {
927 GdkGeometry geometry;
928 geometry.min_width =
929 DevicePixelsToGdkCoordRoundUp(mSizeConstraints.mMinSize.width);
930 geometry.min_height =
931 DevicePixelsToGdkCoordRoundUp(mSizeConstraints.mMinSize.height);
932 geometry.max_width =
933 DevicePixelsToGdkCoordRoundDown(mSizeConstraints.mMaxSize.width);
934 geometry.max_height =
935 DevicePixelsToGdkCoordRoundDown(mSizeConstraints.mMaxSize.height);
936
937 uint32_t hints = 0;
938 if (mSizeConstraints.mMinSize != LayoutDeviceIntSize()) {
939 gtk_widget_set_size_request(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))), geometry.min_width,
940 geometry.min_height);
941 AddCSDDecorationSize(&geometry.min_width, &geometry.min_height);
942 hints |= GDK_HINT_MIN_SIZE;
943 }
944 if (mSizeConstraints.mMaxSize !=
945 LayoutDeviceIntSize(NS_MAXSIZE, NS_MAXSIZE)) {
946 AddCSDDecorationSize(&geometry.max_width, &geometry.max_height);
947 hints |= GDK_HINT_MAX_SIZE;
948 }
949
950 if (mAspectRatio != 0.0f && !mAspectResizer) {
951 geometry.min_aspect = mAspectRatio;
952 geometry.max_aspect = mAspectRatio;
953 hints |= GDK_HINT_ASPECT;
954 }
955
956 gtk_window_set_geometry_hints(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), nullptr, &geometry,
957 GdkWindowHints(hints));
958 }
959}
960
961void nsWindow::Show(bool aState) {
962 if (aState == mIsShown) {
963 return;
964 }
965
966 mIsShown = aState;
967
968#ifdef MOZ_LOGGING1
969 LOG("nsWindow::Show state %d frame %s\n", aState, GetFrameTag().get())do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::Show state %d frame %s\n"
, GetDebugTag().get(), aState, GetFrameTag().get()); } } while
(0)
;
970 if (!aState && mSourceDragContext && GdkIsWaylandDisplay()) {
971 LOG(" closing Drag&Drop source window, D&D will be canceled!")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " closing Drag&Drop source window, D&D will be canceled!"
, GetDebugTag().get()); } } while (0)
;
972 }
973#endif
974
975 // Ok, someone called show on a window that isn't sized to a sane
976 // value. Mark this window as needing to have Show() called on it
977 // and return.
978 if ((aState && !AreBoundsSane()) || !mCreated) {
979 LOG("\tbounds are insane or window hasn't been created yet\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "\tbounds are insane or window hasn't been created yet\n"
, GetDebugTag().get()); } } while (0)
;
980 mNeedsShow = true;
981 return;
982 }
983
984 // If someone is hiding this widget, clear any needing show flag.
985 if (!aState) mNeedsShow = false;
986
987#ifdef ACCESSIBILITY1
988 if (aState && a11y::ShouldA11yBeEnabled()) {
989 CreateRootAccessible();
990 }
991#endif
992
993 NativeShow(aState);
994 RefreshWindowClass();
995}
996
997void nsWindow::ResizeInt(const Maybe<LayoutDeviceIntPoint>& aMove,
998 LayoutDeviceIntSize aSize) {
999 LOG("nsWindow::ResizeInt w:%d h:%d\n", aSize.width, aSize.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::ResizeInt w:%d h:%d\n", GetDebugTag
().get(), aSize.width, aSize.height); } } while (0)
;
1000 const bool moved = aMove && *aMove != mBounds.TopLeft();
1001 if (moved) {
1002 mBounds.MoveTo(*aMove);
1003 LOG(" with move to left:%d top:%d", aMove->x.value, aMove->y.value)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " with move to left:%d top:%d", GetDebugTag
().get(), aMove->x.value, aMove->y.value); } } while (0
)
;
1004 }
1005
1006 ConstrainSize(&aSize.width, &aSize.height);
1007 LOG(" ConstrainSize: w:%d h;%d\n", aSize.width, aSize.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " ConstrainSize: w:%d h;%d\n", GetDebugTag
().get(), aSize.width, aSize.height); } } while (0)
;
1008
1009 const bool resized = aSize != mLastSizeRequest || mBounds.Size() != aSize;
1010#if MOZ_LOGGING1
1011 LOG(" resized %d aSize [%d, %d] mLastSizeRequest [%d, %d] mBounds [%d, %d]",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " resized %d aSize [%d, %d] mLastSizeRequest [%d, %d] mBounds [%d, %d]"
, GetDebugTag().get(), resized, aSize.width, aSize.height, mLastSizeRequest
.width, mLastSizeRequest.height, mBounds.width, mBounds.height
); } } while (0)
1012 resized, aSize.width, aSize.height, mLastSizeRequest.width,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " resized %d aSize [%d, %d] mLastSizeRequest [%d, %d] mBounds [%d, %d]"
, GetDebugTag().get(), resized, aSize.width, aSize.height, mLastSizeRequest
.width, mLastSizeRequest.height, mBounds.width, mBounds.height
); } } while (0)
1013 mLastSizeRequest.height, mBounds.width, mBounds.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " resized %d aSize [%d, %d] mLastSizeRequest [%d, %d] mBounds [%d, %d]"
, GetDebugTag().get(), resized, aSize.width, aSize.height, mLastSizeRequest
.width, mLastSizeRequest.height, mBounds.width, mBounds.height
); } } while (0)
;
1014#endif
1015
1016 // For top-level windows, aSize should possibly be
1017 // interpreted as frame bounds, but NativeMoveResize treats these as window
1018 // bounds (Bug 581866).
1019 mLastSizeRequest = aSize;
1020 // Check size
1021 if (mCompositorSession &&
1022 !wr::WindowSizeSanityCheck(aSize.width, aSize.height)) {
1023 gfxCriticalNoteOncestatic mozilla::gfx::CriticalLog sOnceAtLine1023 = mozilla::gfx
::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions(false
))
<< "Invalid aSize in ResizeInt " << aSize
1024 << " size state " << mSizeMode;
1025 }
1026
1027 // Recalculate aspect ratio when resized from DOM
1028 if (mAspectRatio != 0.0) {
1029 LockAspectRatio(true);
1030 }
1031
1032 if (!mCreated) {
1033 return;
1034 }
1035
1036 if (!moved && !resized) {
1037 LOG(" not moved or resized, quit")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 moved or resized, quit", GetDebugTag
().get()); } } while (0)
;
1038 return;
1039 }
1040
1041 NativeMoveResize(moved, resized);
1042
1043 // We optimistically assume size changes immediately in two cases:
1044 // 1. Override-redirect window: Size is controlled by only us.
1045 // 2. Managed window that has not not yet received a size-allocate event:
1046 // Resize() Callers expect initial sizes to be applied synchronously.
1047 // If the size request is not honored, then we'll correct in
1048 // OnSizeAllocate().
1049 //
1050 // When a managed window has already received a size-allocate, we cannot
1051 // assume we'll always get a notification if our request does not get
1052 // honored: "If the configure request has not changed, we don't ever resend
1053 // it, because it could mean fighting the user or window manager."
1054 // https://gitlab.gnome.org/GNOME/gtk/-/blob/3.24.31/gtk/gtkwindow.c#L9782
1055 // So we don't update mBounds until OnSizeAllocate() when we know the
1056 // request is granted.
1057 bool isOrWillBeVisible = mHasReceivedSizeAllocate || mNeedsShow || mIsShown;
1058 if (!isOrWillBeVisible ||
1059 gtk_window_get_window_type(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell)))))) == GTK_WINDOW_POPUP) {
1060 mBounds.SizeTo(aSize);
1061 if (mCompositorWidgetDelegate) {
1062 mCompositorWidgetDelegate->NotifyClientSizeChanged(aSize);
1063 }
1064 DispatchResized();
1065 }
1066}
1067
1068void nsWindow::Resize(double aWidth, double aHeight, bool aRepaint) {
1069 LOG("nsWindow::Resize %f %f\n", aWidth, aHeight)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::Resize %f %f\n", GetDebugTag
().get(), aWidth, aHeight); } } while (0)
;
1070
1071 double scale =
1072 BoundsUseDesktopPixels() ? GetDesktopToDeviceScale().scale : 1.0;
1073 auto size = LayoutDeviceIntSize::Round(scale * aWidth, scale * aHeight);
1074
1075 ResizeInt(Nothing(), size);
1076}
1077
1078void nsWindow::Resize(double aX, double aY, double aWidth, double aHeight,
1079 bool aRepaint) {
1080 LOG("nsWindow::Resize [%f,%f] -> [%f x %f] repaint %d\n", aX, aY, aWidth,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::Resize [%f,%f] -> [%f x %f] repaint %d\n"
, GetDebugTag().get(), aX, aY, aWidth, aHeight, aRepaint); } }
while (0)
1081 aHeight, aRepaint)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::Resize [%f,%f] -> [%f x %f] repaint %d\n"
, GetDebugTag().get(), aX, aY, aWidth, aHeight, aRepaint); } }
while (0)
;
1082
1083 double scale =
1084 BoundsUseDesktopPixels() ? GetDesktopToDeviceScale().scale : 1.0;
1085 auto size = LayoutDeviceIntSize::Round(scale * aWidth, scale * aHeight);
1086 auto topLeft = LayoutDeviceIntPoint::Round(scale * aX, scale * aY);
1087
1088 ResizeInt(Some(topLeft), size);
1089}
1090
1091void nsWindow::Enable(bool aState) { mEnabled = aState; }
1092
1093bool nsWindow::IsEnabled() const { return mEnabled; }
1094
1095void nsWindow::Move(double aX, double aY) {
1096 double scale =
1097 BoundsUseDesktopPixels() ? GetDesktopToDeviceScale().scale : 1.0;
1098 int32_t x = NSToIntRound(aX * scale);
1099 int32_t y = NSToIntRound(aY * scale);
1100
1101 LOG("nsWindow::Move to %d x %d\n", x, y)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::Move to %d x %d\n", GetDebugTag
().get(), x, y); } } while (0)
;
1102
1103 if (mSizeMode != nsSizeMode_Normal && IsTopLevelWindowType()) {
1104 LOG(" size state is not normal, bailing")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 state is not normal, bailing"
, GetDebugTag().get()); } } while (0)
;
1105 return;
1106 }
1107
1108 // Since a popup window's x/y coordinates are in relation to to
1109 // the parent, the parent might have moved so we always move a
1110 // popup window.
1111 LOG(" bounds %d x %d\n", mBounds.x, mBounds.y)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 %d x %d\n", GetDebugTag()
.get(), mBounds.x, mBounds.y); } } while (0)
;
1112 if (x == mBounds.x && y == mBounds.y && mWindowType != WindowType::Popup) {
1113 LOG(" position is the same, return\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " position is the same, return\n",
GetDebugTag().get()); } } while (0)
;
1114 return;
1115 }
1116
1117 // XXX Should we do some AreBoundsSane check here?
1118
1119 mBounds.x = x;
1120 mBounds.y = y;
1121
1122 if (!mCreated) {
1123 LOG(" is not created, return.\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 not created, return.\n", GetDebugTag
().get()); } } while (0)
;
1124 return;
1125 }
1126
1127 NativeMoveResize(/* move */ true, /* resize */ false);
1128}
1129
1130bool nsWindow::IsPopup() const { return mWindowType == WindowType::Popup; }
1131
1132bool nsWindow::IsWaylandPopup() const {
1133 return GdkIsWaylandDisplay() && IsPopup();
1134}
1135
1136static nsMenuPopupFrame* GetMenuPopupFrame(nsIFrame* aFrame) {
1137 return do_QueryFrame(aFrame);
1138}
1139
1140void nsWindow::AppendPopupToHierarchyList(nsWindow* aToplevelWindow) {
1141 mWaylandToplevel = aToplevelWindow;
1142
1143 nsWindow* popup = aToplevelWindow;
1144 while (popup && popup->mWaylandPopupNext) {
1145 popup = popup->mWaylandPopupNext;
1146 }
1147 popup->mWaylandPopupNext = this;
1148
1149 mWaylandPopupPrev = popup;
1150 mWaylandPopupNext = nullptr;
1151 mPopupChanged = true;
1152 mPopupClosed = false;
1153}
1154
1155void nsWindow::RemovePopupFromHierarchyList() {
1156 // We're already removed from the popup hierarchy
1157 if (!IsInPopupHierarchy()) {
1158 return;
1159 }
1160 mWaylandPopupPrev->mWaylandPopupNext = mWaylandPopupNext;
1161 if (mWaylandPopupNext) {
1162 mWaylandPopupNext->mWaylandPopupPrev = mWaylandPopupPrev;
1163 mWaylandPopupNext->mPopupChanged = true;
1164 }
1165 mWaylandPopupNext = mWaylandPopupPrev = nullptr;
1166}
1167
1168// Gtk refuses to map popup window with x < 0 && y < 0 relative coordinates
1169// see https://gitlab.gnome.org/GNOME/gtk/-/issues/4071
1170// as a workaround just fool around and place the popup temporary to 0,0.
1171bool nsWindow::WaylandPopupRemoveNegativePosition(int* aX, int* aY) {
1172 // https://gitlab.gnome.org/GNOME/gtk/-/issues/4071 applies to temporary
1173 // windows only
1174 GdkWindow* window = GetToplevelGdkWindow();
1175 if (!window || gdk_window_get_window_type(window) != GDK_WINDOW_TEMP) {
1176 return false;
1177 }
1178
1179 LOG("nsWindow::WaylandPopupRemoveNegativePosition()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupRemoveNegativePosition()"
, GetDebugTag().get()); } } while (0)
;
1180
1181 int x, y;
1182 gtk_window_get_position(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), &x, &y);
1183 bool moveBack = (x < 0 && y < 0);
1184 if (moveBack) {
1185 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), 0, 0);
1186 if (aX) {
1187 *aX = x;
1188 }
1189 if (aY) {
1190 *aY = y;
1191 }
1192 }
1193
1194 gdk_window_get_geometry(window, &x, &y, nullptr, nullptr);
1195 if (x < 0 && y < 0) {
1196 gdk_window_move(window, 0, 0);
1197 }
1198
1199 return moveBack;
1200}
1201
1202void nsWindow::ShowWaylandPopupWindow() {
1203 LOG("nsWindow::ShowWaylandPopupWindow. Expected to see visible.")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::ShowWaylandPopupWindow. Expected to see visible."
, GetDebugTag().get()); } } while (0)
;
1204 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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 1204); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsWaylandPopup()"
")"); do { *((volatile int*)__null) = 1204; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1205
1206 if (!mPopupTrackInHierarchy) {
1207 LOG(" popup is not tracked in popup hierarchy, show it now")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get()); } } while (0)
;
1208 gtk_widget_show(mShell);
1209 return;
1210 }
1211
1212 // Popup position was checked before gdk_window_move_to_rect() callback
1213 // so just show it.
1214 if (mPopupUseMoveToRect && mWaitingForMoveToRectCallback) {
1215 LOG(" active move-to-rect callback, show it as is")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get()); } } while (0)
;
1216 gtk_widget_show(mShell);
1217 return;
1218 }
1219
1220 if (gtk_widget_is_visible(mShell)) {
1221 LOG(" is already visible, quit")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get()); } } while (0)
;
1222 return;
1223 }
1224
1225 int x, y;
1226 bool moved = WaylandPopupRemoveNegativePosition(&x, &y);
1227 gtk_widget_show(mShell);
1228 if (moved) {
1229 LOG(" move back to (%d, %d) and show", x, y)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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",
GetDebugTag().get(), x, y); } } while (0)
;
1230 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), x, y);
1231 }
1232}
1233
1234void nsWindow::WaylandPopupMarkAsClosed() {
1235 LOG("nsWindow::WaylandPopupMarkAsClosed: [%p]\n", this)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupMarkAsClosed: [%p]\n"
, GetDebugTag().get(), this); } } while (0)
;
1236 mPopupClosed = true;
1237 // If we have any child popup window notify it about
1238 // parent switch.
1239 if (mWaylandPopupNext) {
1240 mWaylandPopupNext->mPopupChanged = true;
1241 }
1242}
1243
1244nsWindow* nsWindow::WaylandPopupFindLast(nsWindow* aPopup) {
1245 while (aPopup && aPopup->mWaylandPopupNext) {
1246 aPopup = aPopup->mWaylandPopupNext;
1247 }
1248 return aPopup;
1249}
1250
1251// Hide and potentially removes popup from popup hierarchy.
1252void nsWindow::HideWaylandPopupWindow(bool aTemporaryHide,
1253 bool aRemoveFromPopupList) {
1254 LOG("nsWindow::HideWaylandPopupWindow: remove from list %d\n",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::HideWaylandPopupWindow: remove from list %d\n"
, GetDebugTag().get(), aRemoveFromPopupList); } } while (0)
1255 aRemoveFromPopupList)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::HideWaylandPopupWindow: remove from list %d\n"
, GetDebugTag().get(), aRemoveFromPopupList); } } while (0)
;
1256 if (aRemoveFromPopupList) {
1257 RemovePopupFromHierarchyList();
1258 }
1259
1260 if (!mPopupClosed) {
1261 mPopupClosed = !aTemporaryHide;
1262 }
1263
1264 bool visible = gtk_widget_is_visible(mShell);
1265 LOG(" gtk_widget_is_visible() = %d\n", visible)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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",
GetDebugTag().get(), visible); } } while (0)
;
1266
1267 // Restore only popups which are really visible
1268 mPopupTemporaryHidden = aTemporaryHide && visible;
1269
1270 // Hide only visible popups or popups closed pernamently.
1271 if (visible) {
1272 gtk_widget_hide(mShell);
1273
1274 // If there's pending Move-To-Rect callback and we hide the popup
1275 // the callback won't be called any more.
1276 mWaitingForMoveToRectCallback = false;
1277 }
1278
1279 if (mPopupClosed) {
1280 LOG(" Clearing mMoveToRectPopupSize\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get()); } } while (0)
;
1281 mMoveToRectPopupSize = {};
1282#ifdef MOZ_WAYLAND1
1283 if (moz_container_wayland_is_waiting_to_show(mContainer)) {
1284 // We need to clear rendering queue, see Bug 1782948.
1285 LOG(" popup failed to show by Wayland compositor, clear rendering "do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 failed to show by Wayland compositor, clear rendering "
"queue.", GetDebugTag().get()); } } while (0)
1286 "queue.")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 failed to show by Wayland compositor, clear rendering "
"queue.", GetDebugTag().get()); } } while (0)
;
1287 moz_container_wayland_clear_waiting_to_show_flag(mContainer);
1288 ClearRenderingQueue();
1289 }
1290#endif
1291 }
1292}
1293
1294void nsWindow::HideWaylandToplevelWindow() {
1295 LOG("nsWindow::HideWaylandToplevelWindow: [%p]\n", this)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::HideWaylandToplevelWindow: [%p]\n"
, GetDebugTag().get(), this); } } while (0)
;
1296 if (mWaylandPopupNext) {
1297 nsWindow* popup = WaylandPopupFindLast(mWaylandPopupNext);
1298 while (popup->mWaylandToplevel != nullptr) {
1299 nsWindow* prev = popup->mWaylandPopupPrev;
1300 popup->HideWaylandPopupWindow(/* aTemporaryHide */ false,
1301 /* aRemoveFromPopupList */ true);
1302 popup = prev;
1303 }
1304 }
1305 WaylandStopVsync();
1306 gtk_widget_hide(mShell);
1307}
1308
1309void nsWindow::ShowWaylandToplevelWindow() {
1310 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()"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 1310); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsWaylandPopup()"
")"); do { *((volatile int*)__null) = 1310; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1311 LOG("nsWindow::ShowWaylandToplevelWindow")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::ShowWaylandToplevelWindow"
, GetDebugTag().get()); } } while (0)
;
1312 gtk_widget_show(mShell);
1313}
1314
1315void nsWindow::WaylandPopupRemoveClosedPopups() {
1316 LOG("nsWindow::WaylandPopupRemoveClosedPopups()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupRemoveClosedPopups()"
, GetDebugTag().get()); } } while (0)
;
1317 nsWindow* popup = this;
1318 while (popup) {
1319 nsWindow* next = popup->mWaylandPopupNext;
1320 if (popup->mPopupClosed) {
1321 popup->HideWaylandPopupWindow(/* aTemporaryHide */ false,
1322 /* aRemoveFromPopupList */ true);
1323 }
1324 popup = next;
1325 }
1326}
1327
1328// Hide all tooltips except the latest one.
1329void nsWindow::WaylandPopupHideTooltips() {
1330 LOG("nsWindow::WaylandPopupHideTooltips")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupHideTooltips"
, 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!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 1331); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWaylandToplevel == nullptr"
") (" "Should be called on toplevel only!" ")"); do { *((volatile
int*)__null) = 1331; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1332
1333 nsWindow* popup = mWaylandPopupNext;
1334 while (popup && popup->mWaylandPopupNext) {
1335 if (popup->mPopupType == PopupType::Tooltip) {
1336 LOG(" hidding tooltip [%p]", popup)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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]", GetDebugTag
().get(), popup); } } while (0)
;
1337 popup->WaylandPopupMarkAsClosed();
1338 }
1339 popup = popup->mWaylandPopupNext;
1340 }
1341}
1342
1343void nsWindow::WaylandPopupCloseOrphanedPopups() {
1344#ifdef MOZ_WAYLAND1
1345 LOG("nsWindow::WaylandPopupCloseOrphanedPopups")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupCloseOrphanedPopups"
, GetDebugTag().get()); } } while (0)
;
1346 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!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 1346); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWaylandToplevel == nullptr"
") (" "Should be called on toplevel only!" ")"); do { *((volatile
int*)__null) = 1346; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1347
1348 nsWindow* popup = mWaylandPopupNext;
1349 bool dangling = false;
1350 while (popup) {
1351 if (!dangling &&
1352 moz_container_wayland_is_waiting_to_show(popup->GetMozContainer())) {
1353 LOG(" popup [%p] is waiting to show, close all child popups", popup)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), popup); } } while (0)
;
1354 dangling = true;
1355 } else if (dangling) {
1356 popup->WaylandPopupMarkAsClosed();
1357 }
1358 popup = popup->mWaylandPopupNext;
1359 }
1360#endif
1361}
1362
1363// We can't show popups with remote content or overflow popups
1364// on top of regular ones.
1365// If there's any remote popup opened, close all parent popups of it.
1366void nsWindow::CloseAllPopupsBeforeRemotePopup() {
1367 LOG("nsWindow::CloseAllPopupsBeforeRemotePopup")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::CloseAllPopupsBeforeRemotePopup"
, GetDebugTag().get()); } } while (0)
;
1368 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!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 1368); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWaylandToplevel == nullptr"
") (" "Should be called on toplevel only!" ")"); do { *((volatile
int*)__null) = 1368; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1369
1370 // Don't waste time when there's only one popup opened.
1371 if (!mWaylandPopupNext || mWaylandPopupNext->mWaylandPopupNext == nullptr) {
1372 return;
1373 }
1374
1375 // Find the first opened remote content popup
1376 nsWindow* remotePopup = mWaylandPopupNext;
1377 while (remotePopup) {
1378 if (remotePopup->HasRemoteContent() ||
1379 remotePopup->IsWidgetOverflowWindow()) {
1380 LOG(" remote popup [%p]", remotePopup)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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]", GetDebugTag(
).get(), remotePopup); } } while (0)
;
1381 break;
1382 }
1383 remotePopup = remotePopup->mWaylandPopupNext;
1384 }
1385
1386 if (!remotePopup) {
1387 return;
1388 }
1389
1390 // ...hide opened popups before the remote one.
1391 nsWindow* popup = mWaylandPopupNext;
1392 while (popup && popup != remotePopup) {
1393 LOG(" hidding popup [%p]", popup)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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]", GetDebugTag
().get(), popup); } } while (0)
;
1394 popup->WaylandPopupMarkAsClosed();
1395 popup = popup->mWaylandPopupNext;
1396 }
1397}
1398
1399static void GetLayoutPopupWidgetChain(
1400 nsTArray<nsIWidget*>* aLayoutWidgetHierarchy) {
1401 nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
1402 pm->GetSubmenuWidgetChain(aLayoutWidgetHierarchy);
1403 aLayoutWidgetHierarchy->Reverse();
1404}
1405
1406// Compare 'this' popup position in Wayland widget hierarchy
1407// (mWaylandPopupPrev/mWaylandPopupNext) with
1408// 'this' popup position in layout hierarchy.
1409//
1410// When aMustMatchParent is true we also request
1411// 'this' parents match, i.e. 'this' has the same parent in
1412// both layout and widget hierarchy.
1413bool nsWindow::IsPopupInLayoutPopupChain(
1414 nsTArray<nsIWidget*>* aLayoutWidgetHierarchy, bool aMustMatchParent) {
1415 int len = (int)aLayoutWidgetHierarchy->Length();
1416 for (int i = 0; i < len; i++) {
1417 if (this == (*aLayoutWidgetHierarchy)[i]) {
1418 if (!aMustMatchParent) {
1419 return true;
1420 }
1421
1422 // Find correct parent popup for 'this' according to widget
1423 // hierarchy. That means we need to skip closed popups.
1424 nsWindow* parentPopup = nullptr;
1425 if (mWaylandPopupPrev != mWaylandToplevel) {
1426 parentPopup = mWaylandPopupPrev;
1427 while (parentPopup != mWaylandToplevel && parentPopup->mPopupClosed) {
1428 parentPopup = parentPopup->mWaylandPopupPrev;
1429 }
1430 }
1431
1432 if (i == 0) {
1433 // We found 'this' popups as a first popup in layout hierarchy.
1434 // It matches layout hierarchy if it's first widget also in
1435 // wayland widget hierarchy (i.e. parent is null).
1436 return parentPopup == nullptr;
1437 }
1438
1439 return parentPopup == (*aLayoutWidgetHierarchy)[i - 1];
1440 }
1441 }
1442 return false;
1443}
1444
1445// Hide popups which are not in popup chain.
1446void nsWindow::WaylandPopupHierarchyHideByLayout(
1447 nsTArray<nsIWidget*>* aLayoutWidgetHierarchy) {
1448 LOG("nsWindow::WaylandPopupHierarchyHideByLayout")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupHierarchyHideByLayout"
, GetDebugTag().get()); } } while (0)
;
1449 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!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 1449); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWaylandToplevel == nullptr"
") (" "Should be called on toplevel only!" ")"); do { *((volatile
int*)__null) = 1449; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1450
1451 // Hide all popups which are not in layout popup chain
1452 nsWindow* popup = mWaylandPopupNext;
1453 while (popup) {
1454 // Don't check closed popups and drag source popups and tooltips.
1455 if (!popup->mPopupClosed && popup->mPopupType != PopupType::Tooltip &&
1456 !popup->mSourceDragContext) {
1457 if (!popup->IsPopupInLayoutPopupChain(aLayoutWidgetHierarchy,
1458 /* aMustMatchParent */ false)) {
1459 LOG(" hidding popup [%p]", popup)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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]", GetDebugTag
().get(), popup); } } while (0)
;
1460 popup->WaylandPopupMarkAsClosed();
1461 }
1462 }
1463 popup = popup->mWaylandPopupNext;
1464 }
1465}
1466
1467// Mark popups outside of layout hierarchy
1468void nsWindow::WaylandPopupHierarchyValidateByLayout(
1469 nsTArray<nsIWidget*>* aLayoutWidgetHierarchy) {
1470 LOG("nsWindow::WaylandPopupHierarchyValidateByLayout")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupHierarchyValidateByLayout"
, GetDebugTag().get()); } } while (0)
;
1471 nsWindow* popup = mWaylandPopupNext;
1472 while (popup) {
1473 if (popup->mPopupType == PopupType::Tooltip) {
1474 popup->mPopupMatchesLayout = true;
1475 } else if (!popup->mPopupClosed) {
1476 popup->mPopupMatchesLayout = popup->IsPopupInLayoutPopupChain(
1477 aLayoutWidgetHierarchy, /* aMustMatchParent */ true);
1478 LOG(" popup [%p] parent window [%p] matches layout %d\n", (void*)popup,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), (void*)popup, (void*)popup->mWaylandPopupPrev
, popup->mPopupMatchesLayout); } } while (0)
1479 (void*)popup->mWaylandPopupPrev, popup->mPopupMatchesLayout)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), (void*)popup, (void*)popup->mWaylandPopupPrev
, popup->mPopupMatchesLayout); } } while (0)
;
1480 }
1481 popup = popup->mWaylandPopupNext;
1482 }
1483}
1484
1485void nsWindow::WaylandPopupHierarchyHideTemporary() {
1486 LOG("nsWindow::WaylandPopupHierarchyHideTemporary()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupHierarchyHideTemporary()"
, GetDebugTag().get()); } } while (0)
;
1487 nsWindow* popup = WaylandPopupFindLast(this);
1488 while (popup && popup != this) {
1489 LOG(" temporary hidding popup [%p]", popup)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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]", GetDebugTag
().get(), popup); } } while (0)
;
1490 nsWindow* prev = popup->mWaylandPopupPrev;
1491 popup->HideWaylandPopupWindow(/* aTemporaryHide */ true,
1492 /* aRemoveFromPopupList */ false);
1493 popup = prev;
1494 }
1495}
1496
1497void nsWindow::WaylandPopupHierarchyShowTemporaryHidden() {
1498 LOG("nsWindow::WaylandPopupHierarchyShowTemporaryHidden()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupHierarchyShowTemporaryHidden()"
, GetDebugTag().get()); } } while (0)
;
1499 nsWindow* popup = this;
1500 while (popup) {
1501 if (popup->mPopupTemporaryHidden) {
1502 popup->mPopupTemporaryHidden = false;
1503 LOG(" showing temporary hidden popup [%p]", popup)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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]"
, GetDebugTag().get(), popup); } } while (0)
;
1504 popup->ShowWaylandPopupWindow();
1505 }
1506 popup = popup->mWaylandPopupNext;
1507 }
1508}
1509
1510void nsWindow::WaylandPopupHierarchyCalculatePositions() {
1511 LOG("nsWindow::WaylandPopupHierarchyCalculatePositions()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupHierarchyCalculatePositions()"
, GetDebugTag().get()); } } while (0)
;
1512
1513 // Set widget hierarchy in Gtk
1514 nsWindow* popup = mWaylandToplevel->mWaylandPopupNext;
1515 while (popup) {
1516 LOG(" popup [%p] set parent window [%p]", (void*)popup,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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]"
, GetDebugTag().get(), (void*)popup, (void*)popup->mWaylandPopupPrev
); } } while (0)
1517 (void*)popup->mWaylandPopupPrev)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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]"
, GetDebugTag().get(), (void*)popup, (void*)popup->mWaylandPopupPrev
); } } while (0)
;
1518 GtkWindowSetTransientFor(GTK_WINDOW(popup->mShell)((((GtkWindow*) (void *) ((popup->mShell))))),
1519 GTK_WINDOW(popup->mWaylandPopupPrev->mShell)((((GtkWindow*) (void *) ((popup->mWaylandPopupPrev->mShell
)))))
);
1520 popup = popup->mWaylandPopupNext;
1521 }
1522
1523 popup = this;
1524 while (popup) {
1525 // Anchored window has mPopupPosition already calculated against
1526 // its parent, no need to recalculate.
1527 LOG(" popup [%p] bounds [%d, %d] -> [%d x %d]", popup,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] bounds [%d, %d] -> [%d x %d]"
, GetDebugTag().get(), popup, (int)(popup->mBounds.x / FractionalScaleFactor
()), (int)(popup->mBounds.y / FractionalScaleFactor()), (int
)(popup->mBounds.width / FractionalScaleFactor()), (int)(popup
->mBounds.height / FractionalScaleFactor())); } } while (0
)
1528 (int)(popup->mBounds.x / FractionalScaleFactor()),do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] bounds [%d, %d] -> [%d x %d]"
, GetDebugTag().get(), popup, (int)(popup->mBounds.x / FractionalScaleFactor
()), (int)(popup->mBounds.y / FractionalScaleFactor()), (int
)(popup->mBounds.width / FractionalScaleFactor()), (int)(popup
->mBounds.height / FractionalScaleFactor())); } } while (0
)
1529 (int)(popup->mBounds.y / FractionalScaleFactor()),do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] bounds [%d, %d] -> [%d x %d]"
, GetDebugTag().get(), popup, (int)(popup->mBounds.x / FractionalScaleFactor
()), (int)(popup->mBounds.y / FractionalScaleFactor()), (int
)(popup->mBounds.width / FractionalScaleFactor()), (int)(popup
->mBounds.height / FractionalScaleFactor())); } } while (0
)
1530 (int)(popup->mBounds.width / FractionalScaleFactor()),do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] bounds [%d, %d] -> [%d x %d]"
, GetDebugTag().get(), popup, (int)(popup->mBounds.x / FractionalScaleFactor
()), (int)(popup->mBounds.y / FractionalScaleFactor()), (int
)(popup->mBounds.width / FractionalScaleFactor()), (int)(popup
->mBounds.height / FractionalScaleFactor())); } } while (0
)
1531 (int)(popup->mBounds.height / FractionalScaleFactor()))do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] bounds [%d, %d] -> [%d x %d]"
, GetDebugTag().get(), popup, (int)(popup->mBounds.x / FractionalScaleFactor
()), (int)(popup->mBounds.y / FractionalScaleFactor()), (int
)(popup->mBounds.width / FractionalScaleFactor()), (int)(popup
->mBounds.height / FractionalScaleFactor())); } } while (0
)
;
1532#ifdef MOZ_LOGGING1
1533 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)
))
) {
1534 if (nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame())) {
1535 auto r = LayoutDeviceRect::FromAppUnitsRounded(
1536 popupFrame->GetRect(),
1537 popupFrame->PresContext()->AppUnitsPerDevPixel());
1538 LOG(" popup [%p] layout [%d, %d] -> [%d x %d]", popup, r.x, r.y,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] layout [%d, %d] -> [%d x %d]"
, GetDebugTag().get(), popup, r.x, r.y, r.width, r.height); }
} while (0)
1539 r.width, r.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] layout [%d, %d] -> [%d x %d]"
, GetDebugTag().get(), popup, r.x, r.y, r.width, r.height); }
} while (0)
;
1540 }
1541 }
1542#endif
1543 if (popup->WaylandPopupIsFirst()) {
1544 LOG(" popup [%p] has toplevel as parent", popup)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] has toplevel as parent"
, GetDebugTag().get(), popup); } } while (0)
;
1545 popup->mRelativePopupPosition = popup->mPopupPosition;
1546 } else {
1547 if (popup->mPopupAnchored) {
1548 LOG(" popup [%p] is anchored", popup)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 anchored", GetDebugTag
().get(), popup); } } while (0)
;
1549 if (!popup->mPopupMatchesLayout) {
1550 NS_WARNING("Anchored popup does not match layout!")NS_DebugBreak(NS_DEBUG_WARNING, "Anchored popup does not match layout!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 1550)
;
1551 }
1552 }
1553 GdkPoint parent = popup->WaylandGetParentPosition();
1554
1555 LOG(" popup [%p] uses transformed coordinates\n", popup)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] uses transformed coordinates\n"
, GetDebugTag().get(), popup); } } while (0)
;
1556 LOG(" parent position [%d, %d]\n", parent.x, parent.y)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 position [%d, %d]\n", GetDebugTag
().get(), parent.x, parent.y); } } while (0)
;
1557 LOG(" popup position [%d, %d]\n", popup->mPopupPosition.x,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 position [%d, %d]\n", GetDebugTag
().get(), popup->mPopupPosition.x, popup->mPopupPosition
.y); } } while (0)
1558 popup->mPopupPosition.y)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 position [%d, %d]\n", GetDebugTag
().get(), popup->mPopupPosition.x, popup->mPopupPosition
.y); } } while (0)
;
1559
1560 popup->mRelativePopupPosition.x = popup->mPopupPosition.x - parent.x;
1561 popup->mRelativePopupPosition.y = popup->mPopupPosition.y - parent.y;
1562 }
1563 LOG(" popup [%p] transformed popup coordinates from [%d, %d] to [%d, %d]",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] transformed popup coordinates from [%d, %d] to [%d, %d]"
, GetDebugTag().get(), popup, popup->mPopupPosition.x, popup
->mPopupPosition.y, popup->mRelativePopupPosition.x, popup
->mRelativePopupPosition.y); } } while (0)
1564 popup, popup->mPopupPosition.x, popup->mPopupPosition.y,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] transformed popup coordinates from [%d, %d] to [%d, %d]"
, GetDebugTag().get(), popup, popup->mPopupPosition.x, popup
->mPopupPosition.y, popup->mRelativePopupPosition.x, popup
->mRelativePopupPosition.y); } } while (0)
1565 popup->mRelativePopupPosition.x, popup->mRelativePopupPosition.y)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] transformed popup coordinates from [%d, %d] to [%d, %d]"
, GetDebugTag().get(), popup, popup->mPopupPosition.x, popup
->mPopupPosition.y, popup->mRelativePopupPosition.x, popup
->mRelativePopupPosition.y); } } while (0)
;
1566 popup = popup->mWaylandPopupNext;
1567 }
1568}
1569
1570// The MenuList popups are used as dropdown menus for example in WebRTC
1571// microphone/camera chooser or autocomplete widgets.
1572bool nsWindow::WaylandPopupIsMenu() {
1573 nsMenuPopupFrame* menuPopupFrame = GetMenuPopupFrame(GetFrame());
1574 if (menuPopupFrame) {
1575 return mPopupType == PopupType::Menu && !menuPopupFrame->IsMenuList();
1576 }
1577 return false;
1578}
1579
1580bool nsWindow::WaylandPopupIsContextMenu() {
1581 nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame());
1582 if (!popupFrame) {
1583 return false;
1584 }
1585 return popupFrame->IsContextMenu();
1586}
1587
1588bool nsWindow::WaylandPopupIsPermanent() {
1589 nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame());
1590 if (!popupFrame) {
1591 // We can always hide popups without frames.
1592 return false;
1593 }
1594 return popupFrame->IsNoAutoHide();
1595}
1596
1597bool nsWindow::WaylandPopupIsAnchored() {
1598 nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame());
1599 if (!popupFrame) {
1600 // We can always hide popups without frames.
1601 return false;
1602 }
1603 return !!popupFrame->GetAnchor();
1604}
1605
1606bool nsWindow::IsWidgetOverflowWindow() {
1607 if (this->GetFrame() && this->GetFrame()->GetContent()->GetID()) {
1608 nsCString nodeId;
1609 this->GetFrame()->GetContent()->GetID()->ToUTF8String(nodeId);
1610 return nodeId.Equals("widget-overflow");
1611 }
1612 return false;
1613}
1614
1615bool nsWindow::WaylandPopupIsFirst() {
1616 return !mWaylandPopupPrev || !mWaylandPopupPrev->mWaylandToplevel;
1617}
1618
1619nsWindow* nsWindow::GetEffectiveParent() {
1620 GtkWindow* parentGtkWindow = gtk_window_get_transient_for(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
1621 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; }))))
) {
1622 return nullptr;
1623 }
1624 return get_window_for_gtk_widget(GTK_WIDGET(parentGtkWindow)((((GtkWidget*) (void *) ((parentGtkWindow))))));
1625}
1626
1627GdkPoint nsWindow::WaylandGetParentPosition() {
1628 GdkPoint topLeft = {0, 0};
1629 nsWindow* window = GetEffectiveParent();
1630 if (window->IsPopup()) {
1631 topLeft = DevicePixelsToGdkPointRoundDown(window->mBounds.TopLeft());
1632 }
1633 LOG("nsWindow::WaylandGetParentPosition() [%d, %d]\n", topLeft.x, topLeft.y)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandGetParentPosition() [%d, %d]\n"
, GetDebugTag().get(), topLeft.x, topLeft.y); } } while (0)
;
1634 return topLeft;
1635}
1636
1637#ifdef MOZ_LOGGING1
1638void nsWindow::LogPopupHierarchy() {
1639 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)
))
) {
1640 return;
1641 }
1642
1643 LOG("Widget Popup Hierarchy:\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get()); } } while (0)
;
1644 if (!mWaylandToplevel->mWaylandPopupNext) {
1645 LOG(" Empty\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag().get())
; } } while (0)
;
1646 } else {
1647 int indent = 4;
1648 nsWindow* popup = mWaylandToplevel->mWaylandPopupNext;
1649 while (popup) {
1650 nsPrintfCString indentString("%*s", indent, " ");
1651 LOG("%s %s %s nsWindow [%p] Menu %d Permanent %d ContextMenu %d "do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] Menu %d Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", GetDebugTag().get
(), indentString.get(), popup->GetFrameTag().get(), popup->
GetPopupTypeName().get(), popup, popup->WaylandPopupIsMenu
(), popup->WaylandPopupIsPermanent(), popup->mPopupContextMenu
, popup->mPopupAnchored, gtk_widget_is_visible(popup->mShell
), popup->mPopupUseMoveToRect); } } while (0)
1652 "Anchored %d Visible %d MovedByRect %d\n",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] Menu %d Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", GetDebugTag().get
(), indentString.get(), popup->GetFrameTag().get(), popup->
GetPopupTypeName().get(), popup, popup->WaylandPopupIsMenu
(), popup->WaylandPopupIsPermanent(), popup->mPopupContextMenu
, popup->mPopupAnchored, gtk_widget_is_visible(popup->mShell
), popup->mPopupUseMoveToRect); } } while (0)
1653 indentString.get(), popup->GetFrameTag().get(),do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] Menu %d Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", GetDebugTag().get
(), indentString.get(), popup->GetFrameTag().get(), popup->
GetPopupTypeName().get(), popup, popup->WaylandPopupIsMenu
(), popup->WaylandPopupIsPermanent(), popup->mPopupContextMenu
, popup->mPopupAnchored, gtk_widget_is_visible(popup->mShell
), popup->mPopupUseMoveToRect); } } while (0)
1654 popup->GetPopupTypeName().get(), popup, popup->WaylandPopupIsMenu(),do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] Menu %d Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", GetDebugTag().get
(), indentString.get(), popup->GetFrameTag().get(), popup->
GetPopupTypeName().get(), popup, popup->WaylandPopupIsMenu
(), popup->WaylandPopupIsPermanent(), popup->mPopupContextMenu
, popup->mPopupAnchored, gtk_widget_is_visible(popup->mShell
), popup->mPopupUseMoveToRect); } } while (0)
1655 popup->WaylandPopupIsPermanent(), popup->mPopupContextMenu,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] Menu %d Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", GetDebugTag().get
(), indentString.get(), popup->GetFrameTag().get(), popup->
GetPopupTypeName().get(), popup, popup->WaylandPopupIsMenu
(), popup->WaylandPopupIsPermanent(), popup->mPopupContextMenu
, popup->mPopupAnchored, gtk_widget_is_visible(popup->mShell
), popup->mPopupUseMoveToRect); } } while (0)
1656 popup->mPopupAnchored, gtk_widget_is_visible(popup->mShell),do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] Menu %d Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", GetDebugTag().get
(), indentString.get(), popup->GetFrameTag().get(), popup->
GetPopupTypeName().get(), popup, popup->WaylandPopupIsMenu
(), popup->WaylandPopupIsPermanent(), popup->mPopupContextMenu
, popup->mPopupAnchored, gtk_widget_is_visible(popup->mShell
), popup->mPopupUseMoveToRect); } } while (0)
1657 popup->mPopupUseMoveToRect)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] Menu %d Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", GetDebugTag().get
(), indentString.get(), popup->GetFrameTag().get(), popup->
GetPopupTypeName().get(), popup, popup->WaylandPopupIsMenu
(), popup->WaylandPopupIsPermanent(), popup->mPopupContextMenu
, popup->mPopupAnchored, gtk_widget_is_visible(popup->mShell
), popup->mPopupUseMoveToRect); } } while (0)
;
1658 indent += 4;
1659 popup = popup->mWaylandPopupNext;
1660 }
1661 }
1662
1663 LOG("Layout Popup Hierarchy:\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get()); } } while (0)
;
1664 AutoTArray<nsIWidget*, 5> widgetChain;
1665 GetLayoutPopupWidgetChain(&widgetChain);
1666 if (widgetChain.Length() == 0) {
1667 LOG(" Empty\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag().get())
; } } while (0)
;
1668 } else {
1669 for (unsigned long i = 0; i < widgetChain.Length(); i++) {
1670 nsWindow* window = static_cast<nsWindow*>(widgetChain[i]);
1671 nsPrintfCString indentString("%*s", (int)(i + 1) * 4, " ");
1672 if (window) {
1673 LOG("%s %s %s nsWindow [%p] Menu %d Permanent %d ContextMenu %d "do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] Menu %d Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", GetDebugTag().get
(), indentString.get(), window->GetFrameTag().get(), window
->GetPopupTypeName().get(), window, window->WaylandPopupIsMenu
(), window->WaylandPopupIsPermanent(), window->mPopupContextMenu
, window->mPopupAnchored, gtk_widget_is_visible(window->
mShell), window->mPopupUseMoveToRect); } } while (0)
1674 "Anchored %d Visible %d MovedByRect %d\n",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] Menu %d Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", GetDebugTag().get
(), indentString.get(), window->GetFrameTag().get(), window
->GetPopupTypeName().get(), window, window->WaylandPopupIsMenu
(), window->WaylandPopupIsPermanent(), window->mPopupContextMenu
, window->mPopupAnchored, gtk_widget_is_visible(window->
mShell), window->mPopupUseMoveToRect); } } while (0)
1675 indentString.get(), window->GetFrameTag().get(),do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] Menu %d Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", GetDebugTag().get
(), indentString.get(), window->GetFrameTag().get(), window
->GetPopupTypeName().get(), window, window->WaylandPopupIsMenu
(), window->WaylandPopupIsPermanent(), window->mPopupContextMenu
, window->mPopupAnchored, gtk_widget_is_visible(window->
mShell), window->mPopupUseMoveToRect); } } while (0)
1676 window->GetPopupTypeName().get(), window,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] Menu %d Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", GetDebugTag().get
(), indentString.get(), window->GetFrameTag().get(), window
->GetPopupTypeName().get(), window, window->WaylandPopupIsMenu
(), window->WaylandPopupIsPermanent(), window->mPopupContextMenu
, window->mPopupAnchored, gtk_widget_is_visible(window->
mShell), window->mPopupUseMoveToRect); } } while (0)
1677 window->WaylandPopupIsMenu(), window->WaylandPopupIsPermanent(),do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] Menu %d Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", GetDebugTag().get
(), indentString.get(), window->GetFrameTag().get(), window
->GetPopupTypeName().get(), window, window->WaylandPopupIsMenu
(), window->WaylandPopupIsPermanent(), window->mPopupContextMenu
, window->mPopupAnchored, gtk_widget_is_visible(window->
mShell), window->mPopupUseMoveToRect); } } while (0)
1678 window->mPopupContextMenu, window->mPopupAnchored,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] Menu %d Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", GetDebugTag().get
(), indentString.get(), window->GetFrameTag().get(), window
->GetPopupTypeName().get(), window, window->WaylandPopupIsMenu
(), window->WaylandPopupIsPermanent(), window->mPopupContextMenu
, window->mPopupAnchored, gtk_widget_is_visible(window->
mShell), window->mPopupUseMoveToRect); } } while (0)
1679 gtk_widget_is_visible(window->mShell), window->mPopupUseMoveToRect)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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] Menu %d Permanent %d ContextMenu %d "
"Anchored %d Visible %d MovedByRect %d\n", GetDebugTag().get
(), indentString.get(), window->GetFrameTag().get(), window
->GetPopupTypeName().get(), window, window->WaylandPopupIsMenu
(), window->WaylandPopupIsPermanent(), window->mPopupContextMenu
, window->mPopupAnchored, gtk_widget_is_visible(window->
mShell), window->mPopupUseMoveToRect); } } while (0)
;
1680 } else {
1681 LOG("%s null window\n", indentString.get())do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag().get
(), indentString.get()); } } while (0)
;
1682 }
1683 }
1684 }
1685}
1686#endif
1687
1688nsWindow* nsWindow::GetTopmostWindow() {
1689 if (nsView* view = nsView::GetViewFor(this)) {
1690 if (nsView* parentView = view->GetParent()) {
1691 if (nsIWidget* parentWidget = parentView->GetNearestWidget(nullptr)) {
1692 return static_cast<nsWindow*>(parentWidget);
1693 }
1694 }
1695 }
1696 return nullptr;
1697}
1698
1699// Configure Wayland popup. If true is returned we need to track popup
1700// in popup hierarchy. Otherwise we just show it as is.
1701bool nsWindow::WaylandPopupConfigure() {
1702 if (mIsDragPopup) {
1703 return false;
1704 }
1705
1706 // Don't track popups without frame
1707 nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame());
1708 if (!popupFrame) {
1709 return false;
1710 }
1711
1712 // Popup state can be changed, see Bug 1728952.
1713 bool permanentStateMatches =
1714 mPopupTrackInHierarchy == !WaylandPopupIsPermanent();
1715
1716 // Popup permanent state (noautohide attribute) can change during popup life.
1717 if (mPopupTrackInHierarchyConfigured && permanentStateMatches) {
1718 return mPopupTrackInHierarchy;
1719 }
1720
1721 // Configure persistent popup params only once.
1722 // WaylandPopupIsAnchored() can give it wrong value after
1723 // nsMenuPopupFrame::MoveTo() call which we use in move-to-rect callback
1724 // to position popup after wayland position change.
1725 if (!mPopupTrackInHierarchyConfigured) {
1726 mPopupAnchored = WaylandPopupIsAnchored();
1727 mPopupContextMenu = WaylandPopupIsContextMenu();
1728 }
1729
1730 LOG("nsWindow::WaylandPopupConfigure tracked %d anchored %d hint %d\n",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupConfigure tracked %d anchored %d hint %d\n"
, GetDebugTag().get(), mPopupTrackInHierarchy, mPopupAnchored
, int(mPopupType)); } } while (0)
1731 mPopupTrackInHierarchy, mPopupAnchored, int(mPopupType))do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupConfigure tracked %d anchored %d hint %d\n"
, GetDebugTag().get(), mPopupTrackInHierarchy, mPopupAnchored
, int(mPopupType)); } } while (0)
;
1732
1733 // Permanent state changed and popup is mapped.
1734 // We need to switch popup type but that's done when popup is mapped
1735 // by Gtk so we need to unmap the popup here.
1736 // It will be mapped again by gtk_widget_show().
1737 if (!permanentStateMatches && mIsMapped) {
1738 LOG(" permanent state change from %d to %d, unmapping",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), mPopupTrackInHierarchy, !WaylandPopupIsPermanent
()); } } while (0)
1739 mPopupTrackInHierarchy, !WaylandPopupIsPermanent())do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), mPopupTrackInHierarchy, !WaylandPopupIsPermanent
()); } } while (0)
;
1740 gtk_widget_unmap(mShell);
1741 }
1742
1743 mPopupTrackInHierarchy = !WaylandPopupIsPermanent();
1744 LOG(" tracked in hierarchy %d\n", mPopupTrackInHierarchy)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get(), mPopupTrackInHierarchy); } } while (0)
;
1745
1746 // See gdkwindow-wayland.c and
1747 // should_map_as_popup()/should_map_as_subsurface()
1748 GdkWindowTypeHint gtkTypeHint;
1749 switch (mPopupType) {
1750 case PopupType::Menu:
1751 // GDK_WINDOW_TYPE_HINT_POPUP_MENU is mapped as xdg_popup by default.
1752 // We use this type for all menu popups.
1753 gtkTypeHint = GDK_WINDOW_TYPE_HINT_POPUP_MENU;
1754 LOG(" popup type Menu")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag().
get()); } } while (0)
;
1755 break;
1756 case PopupType::Tooltip:
1757 gtkTypeHint = GDK_WINDOW_TYPE_HINT_TOOLTIP;
1758 LOG(" popup type Tooltip")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get()); } } while (0)
;
1759 break;
1760 default:
1761 gtkTypeHint = GDK_WINDOW_TYPE_HINT_UTILITY;
1762 LOG(" popup type Utility")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get()); } } while (0)
;
1763 break;
1764 }
1765
1766 if (!mPopupTrackInHierarchy) {
1767 // GDK_WINDOW_TYPE_HINT_UTILITY is mapped as wl_subsurface
1768 // by default.
1769 LOG(" not tracked in popup hierarchy, switch to Utility")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get()); } } while (0)
;
1770 gtkTypeHint = GDK_WINDOW_TYPE_HINT_UTILITY;
1771 }
1772 gtk_window_set_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), gtkTypeHint);
1773
1774 mPopupTrackInHierarchyConfigured = true;
1775 return mPopupTrackInHierarchy;
1776}
1777
1778bool nsWindow::IsInPopupHierarchy() {
1779 return mPopupTrackInHierarchy && mWaylandToplevel && mWaylandPopupPrev;
1780}
1781
1782void nsWindow::AddWindowToPopupHierarchy() {
1783 LOG("nsWindow::AddWindowToPopupHierarchy\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::AddWindowToPopupHierarchy\n"
, GetDebugTag().get()); } } while (0)
;
1784 if (!GetFrame()) {
1785 LOG(" Window without frame cannot be added as popup!\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get()); } } while (0)
;
1786 return;
1787 }
1788
1789 // Check if we're already in the hierarchy
1790 if (!IsInPopupHierarchy()) {
1791 mWaylandToplevel = GetTopmostWindow();
1792 AppendPopupToHierarchyList(mWaylandToplevel);
1793 }
1794}
1795
1796// Wayland keeps strong popup window hierarchy. We need to track active
1797// (visible) popup windows and make sure we hide popup on the same level
1798// before we open another one on that level. It means that every open
1799// popup needs to have an unique parent.
1800void nsWindow::UpdateWaylandPopupHierarchy() {
1801 LOG("nsWindow::UpdateWaylandPopupHierarchy\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::UpdateWaylandPopupHierarchy\n"
, GetDebugTag().get()); } } while (0)
;
1802
1803 // This popup hasn't been added to popup hierarchy yet so no need to
1804 // do any configurations.
1805 if (!IsInPopupHierarchy()) {
1806 LOG(" popup isn't in hierarchy\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get()); } } while (0)
;
1807 return;
1808 }
1809
1810#ifdef MOZ_LOGGING1
1811 LogPopupHierarchy();
1812 auto printPopupHierarchy = MakeScopeExit([&] { LogPopupHierarchy(); });
1813#endif
1814
1815 // Hide all tooltips without the last one. Tooltip can't be popup parent.
1816 mWaylandToplevel->WaylandPopupHideTooltips();
1817
1818 // See Bug 1709254 / https://gitlab.gnome.org/GNOME/gtk/-/issues/5092
1819 // It's possible that Wayland compositor refuses to show
1820 // a popup although Gtk claims it's visible.
1821 // We don't know if the popup is shown or not.
1822 // To avoid application crash refuse to create any child of such invisible
1823 // popup and close any child of it now.
1824 mWaylandToplevel->WaylandPopupCloseOrphanedPopups();
1825
1826 // Check if we have any remote content / overflow window in hierarchy.
1827 // We can't attach such widget on top of other popup.
1828 mWaylandToplevel->CloseAllPopupsBeforeRemotePopup();
1829
1830 // Check if your popup hierarchy matches layout hierarchy.
1831 // For instance we should not connect hamburger menu on top
1832 // of context menu.
1833 // Close all popups from different layout chains if possible.
1834 AutoTArray<nsIWidget*, 5> layoutPopupWidgetChain;
1835 GetLayoutPopupWidgetChain(&layoutPopupWidgetChain);
1836
1837 mWaylandToplevel->WaylandPopupHierarchyHideByLayout(&layoutPopupWidgetChain);
1838 mWaylandToplevel->WaylandPopupHierarchyValidateByLayout(
1839 &layoutPopupWidgetChain);
1840
1841 // Now we have Popup hierarchy complete.
1842 // Find first unchanged (and still open) popup to start with hierarchy
1843 // changes.
1844 nsWindow* changedPopup = mWaylandToplevel->mWaylandPopupNext;
1845 while (changedPopup) {
1846 // Stop when parent of this popup was changed and we need to recalc
1847 // popup position.
1848 if (changedPopup->mPopupChanged) {
1849 break;
1850 }
1851 // Stop when this popup is closed.
1852 if (changedPopup->mPopupClosed) {
1853 break;
1854 }
1855 changedPopup = changedPopup->mWaylandPopupNext;
1856 }
1857
1858 // We don't need to recompute popup positions, quit now.
1859 if (!changedPopup) {
1860 LOG(" changed Popup is null, quit.\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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",
GetDebugTag().get()); } } while (0)
;
1861 return;
1862 }
1863
1864 LOG(" first changed popup [%p]\n", (void*)changedPopup)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get(), (void*)changedPopup); } } while (0)
;
1865
1866 // Hide parent popups if necessary (there are layout discontinuity)
1867 // reposition the popup and show them again.
1868 changedPopup->WaylandPopupHierarchyHideTemporary();
1869
1870 nsWindow* parentOfchangedPopup = nullptr;
1871 if (changedPopup->mPopupClosed) {
1872 parentOfchangedPopup = changedPopup->mWaylandPopupPrev;
1873 }
1874 changedPopup->WaylandPopupRemoveClosedPopups();
1875
1876 // It's possible that changedPopup was removed from widget hierarchy,
1877 // in such case use child popup of the removed one if there's any.
1878 if (!changedPopup->IsInPopupHierarchy()) {
1879 if (!parentOfchangedPopup || !parentOfchangedPopup->mWaylandPopupNext) {
1880 LOG(" last popup was removed, quit.\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get()); } } while (0)
;
1881 return;
1882 }
1883 changedPopup = parentOfchangedPopup->mWaylandPopupNext;
1884 }
1885
1886 GetLayoutPopupWidgetChain(&layoutPopupWidgetChain);
1887 mWaylandToplevel->WaylandPopupHierarchyValidateByLayout(
1888 &layoutPopupWidgetChain);
1889
1890 changedPopup->WaylandPopupHierarchyCalculatePositions();
1891
1892 nsWindow* popup = changedPopup;
1893 while (popup) {
1894 const bool useMoveToRect = [&] {
1895 if (!StaticPrefs::widget_wayland_use_move_to_rect_AtStartup()) {
1896 return false; // Not available.
1897 }
1898 if (!popup->mPopupMatchesLayout) {
1899 // We can use move_to_rect only when popups in popup hierarchy matches
1900 // layout hierarchy as move_to_rect request that parent/child
1901 // popups are adjacent.
1902 return false;
1903 }
1904 if (popup->mPopupType == PopupType::Panel &&
1905 popup->WaylandPopupIsFirst() &&
1906 popup->WaylandPopupFitsToplevelWindow(/* aMove */ true)) {
1907 // Workaround for https://gitlab.gnome.org/GNOME/gtk/-/issues/1986
1908 //
1909 // PopupType::Panel types are used for extension popups which may be
1910 // resized. If such popup uses move-to-rect, we need to hide it before
1911 // resize and show it again. That leads to massive flickering
1912 // so use plain move if possible to avoid it.
1913 //
1914 // Bug 1760276 - don't use move-to-rect when popup is inside main
1915 // Firefox window.
1916 //
1917 // Use it for first popups only due to another mutter bug
1918 // https://gitlab.gnome.org/GNOME/gtk/-/issues/5089
1919 // https://bugzilla.mozilla.org/show_bug.cgi?id=1784873
1920 return false;
1921 }
1922 if (!popup->WaylandPopupIsFirst() &&
1923 !popup->mWaylandPopupPrev->WaylandPopupIsFirst() &&
1924 !popup->mWaylandPopupPrev->mPopupUseMoveToRect) {
1925 // We can't use move-to-rect if there are more parents of
1926 // wl_subsurface popups types.
1927 //
1928 // It's because wl_subsurface is ignored by xgd_popup
1929 // (created by move-to-rect) so our popup scenario:
1930 //
1931 // toplevel -> xgd_popup(1) -> wl_subsurface(2) -> xgd_popup(3)
1932 //
1933 // looks for Wayland compositor as:
1934 //
1935 // toplevel -> xgd_popup(1) -> xgd_popup(3)
1936 //
1937 // If xgd_popup(1) and xgd_popup(3) are not connected
1938 // move-to-rect applied to xgd_popup(3) fails and we get missing popup.
1939 return false;
1940 }
1941 return true;
1942 }();
1943
1944 LOG(" popup [%p] matches layout [%d] anchored [%d] first popup [%d] use "do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag().get(), popup, popup->mPopupMatchesLayout
, popup->mPopupAnchored, popup->WaylandPopupIsFirst(), useMoveToRect
); } } while (0)
1945 "move-to-rect %d\n",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag().get(), popup, popup->mPopupMatchesLayout
, popup->mPopupAnchored, popup->WaylandPopupIsFirst(), useMoveToRect
); } } while (0)
1946 popup, popup->mPopupMatchesLayout, popup->mPopupAnchored,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag().get(), popup, popup->mPopupMatchesLayout
, popup->mPopupAnchored, popup->WaylandPopupIsFirst(), useMoveToRect
); } } while (0)
1947 popup->WaylandPopupIsFirst(), useMoveToRect)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag().get(), popup, popup->mPopupMatchesLayout
, popup->mPopupAnchored, popup->WaylandPopupIsFirst(), useMoveToRect
); } } while (0)
;
1948
1949 popup->mPopupUseMoveToRect = useMoveToRect;
1950 popup->WaylandPopupMoveImpl();
1951 popup->mPopupChanged = false;
1952 popup = popup->mWaylandPopupNext;
1953 }
1954
1955 changedPopup->WaylandPopupHierarchyShowTemporaryHidden();
1956}
1957
1958static void NativeMoveResizeCallback(GdkWindow* window,
1959 const GdkRectangle* flipped_rect,
1960 const GdkRectangle* final_rect,
1961 gboolean flipped_x, gboolean flipped_y,
1962 void* aWindow) {
1963 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)
1964 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)
;
1965 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)
1966 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)
1967 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)
;
1968 nsWindow* wnd = get_window_for_gdk_window(window);
1969
1970 wnd->NativeMoveResizeWaylandPopupCallback(final_rect, flipped_x, flipped_y);
1971}
1972
1973// When popup is repositioned by widget code, we need to notify
1974// layout about it. It's because we control popup placement
1975// on widget on Wayland so layout may have old popup size/coordinates.
1976void nsWindow::WaylandPopupPropagateChangesToLayout(bool aMove, bool aResize) {
1977 LOG("nsWindow::WaylandPopupPropagateChangesToLayout()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupPropagateChangesToLayout()"
, GetDebugTag().get()); } } while (0)
;
1978
1979 if (aResize) {
1980 LOG(" needSizeUpdate\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag()
.get()); } } while (0)
;
1981 if (nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame())) {
1982 RefPtr<PresShell> presShell = popupFrame->PresShell();
1983 presShell->FrameNeedsReflow(popupFrame, IntrinsicDirty::None,
1984 NS_FRAME_IS_DIRTY);
1985 }
1986 }
1987 if (aMove) {
1988 LOG(" needPositionUpdate, bounds [%d, %d]", mBounds.x, mBounds.y)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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]"
, GetDebugTag().get(), mBounds.x, mBounds.y); } } while (0)
;
1989 NotifyWindowMoved(mBounds.x, mBounds.y, ByMoveToRect::Yes);
1990 }
1991}
1992
1993void nsWindow::NativeMoveResizeWaylandPopupCallback(
1994 const GdkRectangle* aFinalSize, bool aFlippedX, bool aFlippedY) {
1995 // We're getting move-to-rect callback without move-to-rect call.
1996 // That indicates a compositor bug. It happens when a window is hidden and
1997 // shown again before move-to-rect callback is fired.
1998 // It may lead to incorrect popup placement as we may call
1999 // gtk_window_move() between hide & show.
2000 // See Bug 1777919, 1789581.
2001#if MOZ_LOGGING1
2002 if (!mWaitingForMoveToRectCallback) {
2003 LOG(" Bogus move-to-rect callback! Expect wrong popup coordinates.")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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."
, GetDebugTag().get()); } } while (0)
;
2004 }
2005#endif
2006
2007 mWaitingForMoveToRectCallback = false;
2008
2009 bool movedByLayout = mMovedAfterMoveToRect;
2010 bool resizedByLayout = mResizedAfterMoveToRect;
2011
2012 // Popup was moved between move-to-rect call and move-to-rect callback
2013 // and the coordinates from move-to-rect callback are outdated.
2014 if (movedByLayout || resizedByLayout) {
2015 LOG(" Another move/resize called during waiting for callback\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get()); } } while (0)
;
2016 mMovedAfterMoveToRect = false;
2017 mResizedAfterMoveToRect = false;
2018 // Fire another round of move/resize to reflect latest request
2019 // from layout.
2020 NativeMoveResize(movedByLayout, resizedByLayout);
2021 return;
2022 }
2023
2024 LOG(" orig mBounds [%d, %d] -> [%d x %d]\n", mBounds.x, mBounds.y,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 mBounds [%d, %d] -> [%d x %d]\n"
, GetDebugTag().get(), mBounds.x, mBounds.y, mBounds.width, mBounds
.height); } } while (0)
2025 mBounds.width, mBounds.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 mBounds [%d, %d] -> [%d x %d]\n"
, GetDebugTag().get(), mBounds.x, mBounds.y, mBounds.width, mBounds
.height); } } while (0)
;
2026
2027 LayoutDeviceIntRect newBounds = [&] {
2028 GdkRectangle finalRect = *aFinalSize;
2029 GdkPoint parent = WaylandGetParentPosition();
2030 finalRect.x += parent.x;
2031 finalRect.y += parent.y;
2032 return GdkRectToDevicePixels(finalRect);
2033 }();
2034
2035 LOG(" new mBounds [%d, %d] -> [%d x %d]", newBounds.x, newBounds.y,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 mBounds [%d, %d] -> [%d x %d]"
, GetDebugTag().get(), newBounds.x, newBounds.y, newBounds.width
, newBounds.height); } } while (0)
2036 newBounds.width, newBounds.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 mBounds [%d, %d] -> [%d x %d]"
, GetDebugTag().get(), newBounds.x, newBounds.y, newBounds.width
, newBounds.height); } } while (0)
;
2037
2038 bool needsPositionUpdate = newBounds.TopLeft() != mBounds.TopLeft();
2039 bool needsSizeUpdate = newBounds.Size() != mLastSizeRequest;
2040
2041 if (needsSizeUpdate) {
2042 // Wayland compositor changed popup size request from layout.
2043 // Set the constraints to use them in nsMenuPopupFrame::SetPopupPosition().
2044 // Beware that gtk_window_resize() requests sizes asynchronously and so
2045 // newBounds might not have the size from the most recent
2046 // gtk_window_resize().
2047 if (newBounds.width < mLastSizeRequest.width) {
2048 mMoveToRectPopupSize.width = newBounds.width;
2049 }
2050 if (newBounds.height < mLastSizeRequest.height) {
2051 mMoveToRectPopupSize.height = newBounds.height;
2052 }
2053 LOG(" mMoveToRectPopupSize set to [%d, %d]", mMoveToRectPopupSize.width,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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]"
, GetDebugTag().get(), mMoveToRectPopupSize.width, mMoveToRectPopupSize
.height); } } while (0)
2054 mMoveToRectPopupSize.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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]"
, GetDebugTag().get(), mMoveToRectPopupSize.width, mMoveToRectPopupSize
.height); } } while (0)
;
2055 }
2056 mBounds = newBounds;
2057 // Check mBounds size
2058 if (mCompositorSession &&
2059 !wr::WindowSizeSanityCheck(mBounds.width, mBounds.height)) {
2060 gfxCriticalNoteOncestatic mozilla::gfx::CriticalLog sOnceAtLine2060 = mozilla::gfx
::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions(false
))
<< "Invalid mBounds in PopupCallback " << mBounds
2061 << " size state " << mSizeMode;
2062 }
2063 WaylandPopupPropagateChangesToLayout(needsPositionUpdate, needsSizeUpdate);
2064}
2065
2066static GdkGravity PopupAlignmentToGdkGravity(int8_t aAlignment) {
2067 switch (aAlignment) {
2068 case POPUPALIGNMENT_NONE0:
2069 return GDK_GRAVITY_NORTH_WEST;
2070 case POPUPALIGNMENT_TOPLEFT1:
2071 return GDK_GRAVITY_NORTH_WEST;
2072 case POPUPALIGNMENT_TOPRIGHT-1:
2073 return GDK_GRAVITY_NORTH_EAST;
2074 case POPUPALIGNMENT_BOTTOMLEFT2:
2075 return GDK_GRAVITY_SOUTH_WEST;
2076 case POPUPALIGNMENT_BOTTOMRIGHT-2:
2077 return GDK_GRAVITY_SOUTH_EAST;
2078 case POPUPALIGNMENT_LEFTCENTER16:
2079 return GDK_GRAVITY_WEST;
2080 case POPUPALIGNMENT_RIGHTCENTER-16:
2081 return GDK_GRAVITY_EAST;
2082 case POPUPALIGNMENT_TOPCENTER17:
2083 return GDK_GRAVITY_NORTH;
2084 case POPUPALIGNMENT_BOTTOMCENTER18:
2085 return GDK_GRAVITY_SOUTH;
2086 }
2087 return GDK_GRAVITY_STATIC;
2088}
2089
2090bool nsWindow::IsPopupDirectionRTL() {
2091 nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame());
2092 return popupFrame && popupFrame->IsDirectionRTL();
2093}
2094
2095// Position the popup directly by gtk_window_move() and try to keep it
2096// on screen by just moving it in scope of it's parent window.
2097//
2098// It's used when we position noautihode popup and we don't use xdg_positioner.
2099// See Bug 1718867
2100void nsWindow::WaylandPopupSetDirectPosition() {
2101 GdkPoint topLeft = DevicePixelsToGdkPointRoundDown(mBounds.TopLeft());
2102 GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mLastSizeRequest);
2103
2104 LOG("nsWindow::WaylandPopupSetDirectPosition %d,%d -> %d x %d\n", topLeft.x,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupSetDirectPosition %d,%d -> %d x %d\n"
, GetDebugTag().get(), topLeft.x, topLeft.y, size.width, size
.height); } } while (0)
2105 topLeft.y, size.width, size.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupSetDirectPosition %d,%d -> %d x %d\n"
, GetDebugTag().get(), topLeft.x, topLeft.y, size.width, size
.height); } } while (0)
;
2106
2107 mPopupPosition = {topLeft.x, topLeft.y};
2108
2109 if (mIsDragPopup) {
2110 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), topLeft.x, topLeft.y);
2111 gtk_window_resize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), size.width, size.height);
2112 // DND window is placed inside container so we need to make hard size
2113 // request to ensure parent container is resized too.
2114 gtk_widget_set_size_request(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))), size.width, size.height);
2115 return;
2116 }
2117
2118 GtkWindow* parentGtkWindow = gtk_window_get_transient_for(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
2119 nsWindow* window = get_window_for_gtk_widget(GTK_WIDGET(parentGtkWindow)((((GtkWidget*) (void *) ((parentGtkWindow))))));
2120 if (!window) {
2121 return;
2122 }
2123 GdkWindow* gdkWindow = window->GetGdkWindow();
2124 if (!gdkWindow) {
2125 return;
2126 }
2127
2128 int parentWidth = gdk_window_get_width(gdkWindow);
2129 int popupWidth = size.width;
2130
2131 int x;
2132 gdk_window_get_position(gdkWindow, &x, nullptr);
2133
2134 // If popup is bigger than main window just center it.
2135 if (popupWidth > parentWidth) {
2136 mPopupPosition.x = -(parentWidth - popupWidth) / 2 + x;
2137 } else {
2138 if (IsPopupDirectionRTL()) {
2139 // Stick with right window edge
2140 if (mPopupPosition.x < x) {
2141 mPopupPosition.x = x;
2142 }
2143 } else {
2144 // Stick with left window edge
2145 if (mPopupPosition.x + popupWidth > parentWidth + x) {
2146 mPopupPosition.x = parentWidth + x - popupWidth;
2147 }
2148 }
2149 }
2150
2151 LOG(" set position [%d, %d]\n", mPopupPosition.x, mPopupPosition.y)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get(), mPopupPosition.x, mPopupPosition.y); } } while (0)
;
2152 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), mPopupPosition.x, mPopupPosition.y);
2153
2154 LOG(" set size [%d, %d]\n", size.width, size.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get(), size.width, size.height); } } while (0)
;
2155 gtk_window_resize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), size.width, size.height);
2156
2157 if (mPopupPosition.x != topLeft.x) {
2158 mBounds.MoveTo(GdkPointToDevicePixels(mPopupPosition));
2159 LOG(" setting new bounds [%d, %d]\n", mBounds.x, mBounds.y)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " setting new bounds [%d, %d]\n", GetDebugTag
().get(), mBounds.x, mBounds.y); } } while (0)
;
2160 WaylandPopupPropagateChangesToLayout(/* move */ true, /* resize */ false);
2161 }
2162}
2163
2164bool nsWindow::WaylandPopupFitsToplevelWindow(bool aMove) {
2165 LOG("nsWindow::WaylandPopupFitsToplevelWindow() move %d", aMove)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupFitsToplevelWindow() move %d"
, GetDebugTag().get(), aMove); } } while (0)
;
2166
2167 GtkWindow* parent = gtk_window_get_transient_for(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
2168 GtkWindow* tmp = parent;
Value stored to 'tmp' during its initialization is never read
2169 while ((tmp = gtk_window_get_transient_for(GTK_WINDOW(parent)((((GtkWindow*) (void *) ((parent)))))))) {
2170 parent = tmp;
2171 }
2172 GdkWindow* toplevelGdkWindow = gtk_widget_get_window(GTK_WIDGET(parent)((((GtkWidget*) (void *) ((parent))))));
2173 if (!toplevelGdkWindow) {
2174 NS_WARNING("Toplevel widget without GdkWindow?")NS_DebugBreak(NS_DEBUG_WARNING, "Toplevel widget without GdkWindow?"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 2174)
;
2175 return false;
2176 }
2177
2178 int parentWidth = gdk_window_get_width(toplevelGdkWindow);
2179 int parentHeight = gdk_window_get_height(toplevelGdkWindow);
2180 LOG(" parent size %d x %d", parentWidth, parentHeight)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get(), parentWidth, parentHeight); } } while (0)
;
2181
2182 GdkPoint topLeft = aMove ? mPopupPosition
2183 : DevicePixelsToGdkPointRoundDown(mBounds.TopLeft());
2184 GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mLastSizeRequest);
2185 LOG(" popup topleft %d, %d size %d x %d", topLeft.x, topLeft.y, size.width,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), topLeft.x, topLeft.y, size.width, size
.height); } } while (0)
2186 size.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), topLeft.x, topLeft.y, size.width, size
.height); } } while (0)
;
2187 int fits = topLeft.x >= 0 && topLeft.y >= 0 &&
2188 topLeft.x + size.width <= parentWidth &&
2189 topLeft.y + size.height <= parentHeight;
2190
2191 LOG(" fits %d", fits)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag().get(), fits
); } } while (0)
;
2192 return fits;
2193}
2194
2195void nsWindow::NativeMoveResizeWaylandPopup(bool aMove, bool aResize) {
2196 GdkPoint topLeft = DevicePixelsToGdkPointRoundDown(mBounds.TopLeft());
2197 GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mLastSizeRequest);
2198
2199 LOG("nsWindow::NativeMoveResizeWaylandPopup Bounds %d,%d -> %d x %d move %d "do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::NativeMoveResizeWaylandPopup Bounds %d,%d -> %d x %d move %d "
"resize %d\n", GetDebugTag().get(), topLeft.x, topLeft.y, size
.width, size.height, aMove, aResize); } } while (0)
2200 "resize %d\n",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::NativeMoveResizeWaylandPopup Bounds %d,%d -> %d x %d move %d "
"resize %d\n", GetDebugTag().get(), topLeft.x, topLeft.y, size
.width, size.height, aMove, aResize); } } while (0)
2201 topLeft.x, topLeft.y, size.width, size.height, aMove, aResize)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::NativeMoveResizeWaylandPopup Bounds %d,%d -> %d x %d move %d "
"resize %d\n", GetDebugTag().get(), topLeft.x, topLeft.y, size
.width, size.height, aMove, aResize); } } while (0)
;
2202
2203 // Compositor may be confused by windows with width/height = 0
2204 // and positioning such windows leads to Bug 1555866.
2205 if (!AreBoundsSane()) {
2206 LOG(" Bounds are not sane (width: %d height: %d)\n",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), mLastSizeRequest.width, mLastSizeRequest
.height); } } while (0)
2207 mLastSizeRequest.width, mLastSizeRequest.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), mLastSizeRequest.width, mLastSizeRequest
.height); } } while (0)
;
2208 return;
2209 }
2210
2211 if (mWaitingForMoveToRectCallback) {
2212 LOG(" waiting for move to rect, scheduling")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get()); } } while (0)
;
2213 // mBounds position must not be overwritten before it is applied.
2214 // OnConfigureEvent() will not set mBounds to an old position for
2215 // GTK_WINDOW_POPUP.
2216 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"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 2217); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gtk_window_get_window_type(((((GtkWindow*) (void *) ((mShell)))))) == GTK_WINDOW_POPUP"
")"); do { *((volatile int*)__null) = 2217; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2217 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"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 2217); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gtk_window_get_window_type(((((GtkWindow*) (void *) ((mShell)))))) == GTK_WINDOW_POPUP"
")"); do { *((volatile int*)__null) = 2217; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2218 mMovedAfterMoveToRect = aMove;
2219 mResizedAfterMoveToRect = aResize;
2220 return;
2221 }
2222
2223 mMovedAfterMoveToRect = false;
2224 mResizedAfterMoveToRect = false;
2225
2226 bool trackedInHierarchy = WaylandPopupConfigure();
2227
2228 // Read popup position from layout if it was moved or newly created.
2229 // This position is used by move-to-rect method as we need anchor and other
2230 // info to place popup correctly.
2231 // We need WaylandPopupConfigure() to be called before to have all needed
2232 // popup info in place (mainly the anchored flag).
2233 if (aMove) {
2234 mPopupMoveToRectParams = WaylandPopupGetPositionFromLayout();
2235 }
2236
2237 if (!trackedInHierarchy) {
2238 WaylandPopupSetDirectPosition();
2239 return;
2240 }
2241
2242 if (aResize) {
2243 LOG(" set size [%d, %d]\n", size.width, size.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get(), size.width, size.height); } } while (0)
;
2244 gtk_window_resize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), size.width, size.height);
2245 }
2246
2247 if (!aMove && WaylandPopupFitsToplevelWindow(aMove)) {
2248 // Popup position has not been changed and its position/size fits
2249 // parent window so no need to reposition the window.
2250 LOG(" fits parent window size, just resize\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get()); } } while (0)
;
2251 return;
2252 }
2253
2254 // Mark popup as changed as we're updating position/size.
2255 mPopupChanged = true;
2256
2257 // Save popup position for former re-calculations when popup hierarchy
2258 // is changed.
2259 LOG(" popup position changed from [%d, %d] to [%d, %d]\n", mPopupPosition.x,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 position changed from [%d, %d] to [%d, %d]\n"
, GetDebugTag().get(), mPopupPosition.x, mPopupPosition.y, topLeft
.x, topLeft.y); } } while (0)
2260 mPopupPosition.y, topLeft.x, topLeft.y)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 position changed from [%d, %d] to [%d, %d]\n"
, GetDebugTag().get(), mPopupPosition.x, mPopupPosition.y, topLeft
.x, topLeft.y); } } while (0)
;
2261 mPopupPosition = {topLeft.x, topLeft.y};
2262
2263 UpdateWaylandPopupHierarchy();
2264}
2265
2266struct PopupSides {
2267 Maybe<Side> mVertical;
2268 Maybe<Side> mHorizontal;
2269};
2270
2271static PopupSides SidesForPopupAlignment(int8_t aAlignment) {
2272 switch (aAlignment) {
2273 case POPUPALIGNMENT_NONE0:
2274 break;
2275 case POPUPALIGNMENT_TOPLEFT1:
2276 return {Some(eSideTop), Some(eSideLeft)};
2277 case POPUPALIGNMENT_TOPRIGHT-1:
2278 return {Some(eSideTop), Some(eSideRight)};
2279 case POPUPALIGNMENT_BOTTOMLEFT2:
2280 return {Some(eSideBottom), Some(eSideLeft)};
2281 case POPUPALIGNMENT_BOTTOMRIGHT-2:
2282 return {Some(eSideBottom), Some(eSideRight)};
2283 case POPUPALIGNMENT_LEFTCENTER16:
2284 return {Nothing(), Some(eSideLeft)};
2285 case POPUPALIGNMENT_RIGHTCENTER-16:
2286 return {Nothing(), Some(eSideRight)};
2287 case POPUPALIGNMENT_TOPCENTER17:
2288 return {Some(eSideTop), Nothing()};
2289 case POPUPALIGNMENT_BOTTOMCENTER18:
2290 return {Some(eSideBottom), Nothing()};
2291 }
2292 return {};
2293}
2294
2295// We want to apply margins based on popup alignment (which would generally be
2296// just an offset to apply to the popup). However, to deal with flipping
2297// correctly, we apply the margin to the anchor when possible.
2298struct ResolvedPopupMargin {
2299 // A margin to be applied to the anchor.
2300 nsMargin mAnchorMargin;
2301 // An offset in app units to be applied to the popup for when we need to tell
2302 // GTK to center inside the anchor precisely (so we can't really do better in
2303 // presence of flips).
2304 nsPoint mPopupOffset;
2305};
2306
2307static ResolvedPopupMargin ResolveMargin(nsMenuPopupFrame* aFrame,
2308 int8_t aPopupAlign,
2309 int8_t aAnchorAlign,
2310 bool aAnchoredToPoint,
2311 bool aIsContextMenu) {
2312 nsMargin margin = aFrame->GetMargin();
2313 nsPoint offset;
2314
2315 if (aAnchoredToPoint) {
2316 // Since GTK doesn't allow us to specify margins itself, when anchored to a
2317 // point we can just assume we'll be aligned correctly... This is kind of
2318 // annoying but alas.
2319 //
2320 // This calculation must match the relevant unanchored popup calculation in
2321 // nsMenuPopupFrame::SetPopupPosition(), which should itself be the inverse
2322 // inverse of nsMenuPopupFrame::MoveTo().
2323 if (aIsContextMenu && aFrame->IsDirectionRTL()) {
2324 offset.x = -margin.right;
2325 } else {
2326 offset.x = margin.left;
2327 }
2328 offset.y = margin.top;
2329 return {nsMargin(), offset};
2330 }
2331
2332 auto popupSides = SidesForPopupAlignment(aPopupAlign);
2333 auto anchorSides = SidesForPopupAlignment(aAnchorAlign);
2334 // Matched sides: Invert the margin, so that we pull in the right direction.
2335 // Popup not aligned to any anchor side: We give up and use the offset,
2336 // applying the margin from the popup side.
2337 // Mismatched sides: We swap the margins so that we pull in the right
2338 // direction, e.g. margin-left: -10px should shrink 10px the _right_ of the
2339 // box, not the left of the box.
2340 if (popupSides.mHorizontal == anchorSides.mHorizontal) {
2341 margin.left = -margin.left;
2342 margin.right = -margin.right;
2343 } else if (!anchorSides.mHorizontal) {
2344 auto popupSide = *popupSides.mHorizontal;
2345 offset.x += popupSide == eSideRight ? -margin.Side(popupSide)
2346 : margin.Side(popupSide);
2347 margin.left = margin.right = 0;
2348 } else {
2349 std::swap(margin.left, margin.right);
2350 }
2351
2352 // Same logic as above, but in the vertical direction.
2353 if (popupSides.mVertical == anchorSides.mVertical) {
2354 margin.top = -margin.top;
2355 margin.bottom = -margin.bottom;
2356 } else if (!anchorSides.mVertical) {
2357 auto popupSide = *popupSides.mVertical;
2358 offset.y += popupSide == eSideBottom ? -margin.Side(popupSide)
2359 : margin.Side(popupSide);
2360 margin.top = margin.bottom = 0;
2361 } else {
2362 std::swap(margin.top, margin.bottom);
2363 }
2364
2365 return {margin, offset};
2366}
2367
2368#ifdef MOZ_LOGGING1
2369void nsWindow::LogPopupAnchorHints(int aHints) {
2370 static struct hints_ {
2371 int hint;
2372 char name[100];
2373 } hints[] = {
2374 {GDK_ANCHOR_FLIP_X, "GDK_ANCHOR_FLIP_X"},
2375 {GDK_ANCHOR_FLIP_Y, "GDK_ANCHOR_FLIP_Y"},
2376 {GDK_ANCHOR_SLIDE_X, "GDK_ANCHOR_SLIDE_X"},
2377 {GDK_ANCHOR_SLIDE_Y, "GDK_ANCHOR_SLIDE_Y"},
2378 {GDK_ANCHOR_RESIZE_X, "GDK_ANCHOR_RESIZE_X"},
2379 {GDK_ANCHOR_RESIZE_Y, "GDK_ANCHOR_RESIZE_X"},
2380 };
2381
2382 LOG(" PopupAnchorHints")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag()
.get()); } } while (0)
;
2383 for (const auto& hint : hints) {
2384 if (hint.hint & aHints) {
2385 LOG(" %s", hint.name)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag().get(), hint
.name); } } while (0)
;
2386 }
2387 }
2388}
2389
2390void nsWindow::LogPopupGravity(GdkGravity aGravity) {
2391 static char gravity[][100]{"NONE",
2392 "GDK_GRAVITY_NORTH_WEST",
2393 "GDK_GRAVITY_NORTH",
2394 "GDK_GRAVITY_NORTH_EAST",
2395 "GDK_GRAVITY_WEST",
2396 "GDK_GRAVITY_CENTER",
2397 "GDK_GRAVITY_EAST",
2398 "GDK_GRAVITY_SOUTH_WEST",
2399 "GDK_GRAVITY_SOUTH",
2400 "GDK_GRAVITY_SOUTH_EAST",
2401 "GDK_GRAVITY_STATIC"};
2402 LOG(" %s", gravity[aGravity])do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag().get(), gravity
[aGravity]); } } while (0)
;
2403}
2404#endif
2405
2406const nsWindow::WaylandPopupMoveToRectParams
2407nsWindow::WaylandPopupGetPositionFromLayout() {
2408 LOG("nsWindow::WaylandPopupGetPositionFromLayout\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupGetPositionFromLayout\n"
, GetDebugTag().get()); } } while (0)
;
2409
2410 nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame());
2411
2412 const bool isTopContextMenu = mPopupContextMenu && !mPopupAnchored;
2413 const bool isRTL = popupFrame->IsDirectionRTL();
2414 const bool anchored = popupFrame->IsAnchored();
2415 int8_t popupAlign = POPUPALIGNMENT_TOPLEFT1;
2416 int8_t anchorAlign = POPUPALIGNMENT_BOTTOMRIGHT-2;
2417 if (anchored) {
2418 // See nsMenuPopupFrame::AdjustPositionForAnchorAlign.
2419 popupAlign = popupFrame->GetPopupAlignment();
2420 anchorAlign = popupFrame->GetPopupAnchor();
2421 }
2422 if (isRTL) {
2423 popupAlign = -popupAlign;
2424 anchorAlign = -anchorAlign;
2425 }
2426
2427 // Although we have mPopupPosition / mRelativePopupPosition here
2428 // we can't use it. move-to-rect needs anchor rectangle to position a popup
2429 // but we have only a point from Resize().
2430 //
2431 // So we need to extract popup position from nsMenuPopupFrame() and duplicate
2432 // the layout work here.
2433 LayoutDeviceIntRect anchorRect;
2434 ResolvedPopupMargin popupMargin;
2435 {
2436 nsRect anchorRectAppUnits = popupFrame->GetUntransformedAnchorRect();
2437 // This is a somewhat hacky way of applying the popup margin. We don't know
2438 // if GTK will end up flipping the popup, in which case the offset we
2439 // compute is just wrong / applied to the wrong side.
2440 //
2441 // Instead, we tell it to anchor us at a smaller or bigger rect depending on
2442 // the margin, which achieves the same result if the popup is positioned
2443 // correctly, but doesn't misposition the popup when flipped across the
2444 // anchor.
2445 popupMargin = ResolveMargin(popupFrame, popupAlign, anchorAlign,
2446 anchorRectAppUnits.IsEmpty(), isTopContextMenu);
2447 LOG(" layout popup CSS anchor (%d, %d) %s, margin %s offset %s\n",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), popupAlign, anchorAlign, ToString(anchorRectAppUnits
).c_str(), ToString(popupMargin.mAnchorMargin).c_str(), ToString
(popupMargin.mPopupOffset).c_str()); } } while (0)
2448 popupAlign, anchorAlign, ToString(anchorRectAppUnits).c_str(),do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), popupAlign, anchorAlign, ToString(anchorRectAppUnits
).c_str(), ToString(popupMargin.mAnchorMargin).c_str(), ToString
(popupMargin.mPopupOffset).c_str()); } } while (0)
2449 ToString(popupMargin.mAnchorMargin).c_str(),do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), popupAlign, anchorAlign, ToString(anchorRectAppUnits
).c_str(), ToString(popupMargin.mAnchorMargin).c_str(), ToString
(popupMargin.mPopupOffset).c_str()); } } while (0)
2450 ToString(popupMargin.mPopupOffset).c_str())do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), popupAlign, anchorAlign, ToString(anchorRectAppUnits
).c_str(), ToString(popupMargin.mAnchorMargin).c_str(), ToString
(popupMargin.mPopupOffset).c_str()); } } while (0)
;
2451 anchorRectAppUnits.Inflate(popupMargin.mAnchorMargin);
2452 LOG(" after margins %s\n", ToString(anchorRectAppUnits).c_str())do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get(), ToString(anchorRectAppUnits).c_str()); } } while (0
)
;
2453 nscoord auPerDev = popupFrame->PresContext()->AppUnitsPerDevPixel();
2454 anchorRect = LayoutDeviceIntRect::FromAppUnitsToNearest(anchorRectAppUnits,
2455 auPerDev);
2456 if (anchorRect.width < 0) {
2457 auto w = -anchorRect.width;
2458 anchorRect.width += w + 1;
2459 anchorRect.x += w;
2460 }
2461 LOG(" final %s\n", ToString(anchorRect).c_str())do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag().get
(), ToString(anchorRect).c_str()); } } while (0)
;
2462 }
2463
2464 LOG(" relative popup rect position [%d, %d] -> [%d x %d]\n", anchorRect.x,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), anchorRect.x, anchorRect.y, anchorRect
.width, anchorRect.height); } } while (0)
2465 anchorRect.y, anchorRect.width, anchorRect.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), anchorRect.x, anchorRect.y, anchorRect
.width, anchorRect.height); } } while (0)
;
2466
2467 // Get gravity and flip type
2468 GdkGravity rectAnchor = PopupAlignmentToGdkGravity(anchorAlign);
2469 GdkGravity menuAnchor = PopupAlignmentToGdkGravity(popupAlign);
2470
2471 LOG(" parentRect gravity: %d anchor gravity: %d\n", rectAnchor, menuAnchor)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), rectAnchor, menuAnchor); } } while (0)
;
2472
2473 // Gtk default is: GDK_ANCHOR_FLIP | GDK_ANCHOR_SLIDE | GDK_ANCHOR_RESIZE.
2474 // We want to SLIDE_X menu on the dual monitor setup rather than resize it
2475 // on the other monitor.
2476 GdkAnchorHints hints =
2477 GdkAnchorHints(GDK_ANCHOR_FLIP | GDK_ANCHOR_SLIDE_X | GDK_ANCHOR_RESIZE);
2478
2479 // slideHorizontal from nsMenuPopupFrame::SetPopupPosition
2480 int8_t position = popupFrame->GetAlignmentPosition();
2481 if (position >= POPUPPOSITION_BEFORESTART0 &&
2482 position <= POPUPPOSITION_AFTEREND3) {
2483 hints = GdkAnchorHints(hints | GDK_ANCHOR_SLIDE_X);
2484 }
2485 // slideVertical from nsMenuPopupFrame::SetPopupPosition
2486 if (position >= POPUPPOSITION_STARTBEFORE4 &&
2487 position <= POPUPPOSITION_ENDAFTER7) {
2488 hints = GdkAnchorHints(hints | GDK_ANCHOR_SLIDE_Y);
2489 }
2490
2491 FlipType flipType = popupFrame->GetFlipType();
2492 if (rectAnchor == GDK_GRAVITY_CENTER && menuAnchor == GDK_GRAVITY_CENTER) {
2493 // only slide
2494 hints = GdkAnchorHints(hints | GDK_ANCHOR_SLIDE);
2495 } else {
2496 switch (flipType) {
2497 case FlipType_Both:
2498 hints = GdkAnchorHints(hints | GDK_ANCHOR_FLIP);
2499 break;
2500 case FlipType_Slide:
2501 hints = GdkAnchorHints(hints | GDK_ANCHOR_SLIDE);
2502 break;
2503 case FlipType_Default:
2504 hints = GdkAnchorHints(hints | GDK_ANCHOR_FLIP);
2505 break;
2506 default:
2507 break;
2508 }
2509 }
2510 if (!WaylandPopupIsMenu()) {
2511 // we don't want to slide menus to fit the screen rather resize them
2512 hints = GdkAnchorHints(hints | GDK_ANCHOR_SLIDE);
2513 }
2514
2515 // We want tooltips to flip verticaly or slide only.
2516 // See nsMenuPopupFrame::SetPopupPosition().
2517 // https://searchfox.org/mozilla-central/rev/d0f5bc50aff3462c9d1546b88d60c5cb020eb15c/layout/xul/nsMenuPopupFrame.cpp#1603
2518 if (mPopupType == PopupType::Tooltip) {
2519 hints = GdkAnchorHints(GDK_ANCHOR_FLIP_Y | GDK_ANCHOR_SLIDE);
2520 }
2521
2522 return {
2523 anchorRect,
2524 rectAnchor,
2525 menuAnchor,
2526 hints,
2527 DevicePixelsToGdkPointRoundDown(LayoutDevicePoint::FromAppUnitsToNearest(
2528 popupMargin.mPopupOffset,
2529 popupFrame->PresContext()->AppUnitsPerDevPixel())),
2530 true};
2531}
2532
2533bool nsWindow::WaylandPopupAnchorAdjustForParentPopup(
2534 GdkRectangle* aPopupAnchor, GdkPoint* aOffset) {
2535 LOG("nsWindow::WaylandPopupAnchorAdjustForParentPopup")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupAnchorAdjustForParentPopup"
, GetDebugTag().get()); } } while (0)
;
2536
2537 GtkWindow* parentGtkWindow = gtk_window_get_transient_for(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
2538 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; }))))
) {
2539 NS_WARNING("Popup has no parent!")NS_DebugBreak(NS_DEBUG_WARNING, "Popup has no parent!", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 2539)
;
2540 return false;
2541 }
2542 GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(parentGtkWindow)((((GtkWidget*) (void *) ((parentGtkWindow))))));
2543 if (!window) {
2544 NS_WARNING("Popup parrent is not mapped!")NS_DebugBreak(NS_DEBUG_WARNING, "Popup parrent is not mapped!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 2544)
;
2545 return false;
2546 }
2547
2548 GdkRectangle parentWindowRect = {0, 0, gdk_window_get_width(window),
2549 gdk_window_get_height(window)};
2550 LOG(" parent window size %d x %d", parentWindowRect.width,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get(), parentWindowRect.width, parentWindowRect.height); }
} while (0)
2551 parentWindowRect.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get(), parentWindowRect.width, parentWindowRect.height); }
} while (0)
;
2552
2553 // We can't have rectangle anchor with zero width/height.
2554 if (!aPopupAnchor->width) {
2555 aPopupAnchor->width = 1;
2556 }
2557 if (!aPopupAnchor->height) {
2558 aPopupAnchor->height = 1;
2559 }
2560
2561 GdkRectangle finalRect;
2562 if (!gdk_rectangle_intersect(aPopupAnchor, &parentWindowRect, &finalRect)) {
2563 return false;
2564 }
2565 *aPopupAnchor = finalRect;
2566 LOG(" anchor is correct %d,%d -> %d x %d", finalRect.x, finalRect.y,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), finalRect.x, finalRect.y, finalRect.width
, finalRect.height); } } while (0)
2567 finalRect.width, finalRect.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), finalRect.x, finalRect.y, finalRect.width
, finalRect.height); } } while (0)
;
2568
2569 *aOffset = mPopupMoveToRectParams.mOffset;
2570 LOG(" anchor offset %d, %d", aOffset->x, aOffset->y)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get(), aOffset->x, aOffset->y); } } while (0)
;
2571 return true;
2572}
2573
2574bool nsWindow::WaylandPopupCheckAndGetAnchor(GdkRectangle* aPopupAnchor,
2575 GdkPoint* aOffset) {
2576 LOG("nsWindow::WaylandPopupCheckAndGetAnchor")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupCheckAndGetAnchor"
, GetDebugTag().get()); } } while (0)
;
2577
2578 GdkWindow* gdkWindow = GetToplevelGdkWindow();
2579 nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame());
2580 if (!gdkWindow || !popupFrame) {
2581 LOG(" can't use move-to-rect due missing gdkWindow or popupFrame")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get()); } } while (0)
;
2582 return false;
2583 }
2584
2585 if (popupFrame->IsConstrainedByLayout()) {
2586 LOG(" can't use move-to-rect, flipped / constrained by layout")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get()); } } while (0)
;
2587 return false;
2588 }
2589
2590 if (!mPopupMoveToRectParams.mAnchorSet) {
2591 LOG(" can't use move-to-rect due missing anchor")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 anchor"
, GetDebugTag().get()); } } while (0)
;
2592 return false;
2593 }
2594 // Update popup layout coordinates from layout by recent popup hierarchy
2595 // (calculate correct position according to parent window)
2596 // and convert to Gtk coordinates.
2597 LayoutDeviceIntRect anchorRect = mPopupMoveToRectParams.mAnchorRect;
2598 if (!WaylandPopupIsFirst()) {
2599 GdkPoint parent = WaylandGetParentPosition();
2600 LOG(" subtract parent position from anchor [%d, %d]\n", parent.x,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), parent.x, parent.y); } } while (0)
2601 parent.y)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), parent.x, parent.y); } } while (0)
;
2602 anchorRect.MoveBy(-GdkPointToDevicePixels(parent));
2603 }
2604
2605 *aPopupAnchor = DevicePixelsToGdkRectRoundOut(anchorRect);
2606 LOG(" anchored to rectangle [%d, %d] -> [%d x %d]", aPopupAnchor->x,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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]"
, GetDebugTag().get(), aPopupAnchor->x, aPopupAnchor->y
, aPopupAnchor->width, aPopupAnchor->height); } } while
(0)
2607 aPopupAnchor->y, aPopupAnchor->width, aPopupAnchor->height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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]"
, GetDebugTag().get(), aPopupAnchor->x, aPopupAnchor->y
, aPopupAnchor->width, aPopupAnchor->height); } } while
(0)
;
2608
2609 if (!WaylandPopupAnchorAdjustForParentPopup(aPopupAnchor, aOffset)) {
2610 LOG(" can't use move-to-rect, anchor is not placed inside of parent "do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag().get()); } } while (0)
2611 "window")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag().get()); } } while (0)
;
2612 return false;
2613 }
2614
2615 return true;
2616}
2617
2618void nsWindow::WaylandPopupPrepareForMove() {
2619 LOG("nsWindow::WaylandPopupPrepareForMove()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupPrepareForMove()"
, GetDebugTag().get()); } } while (0)
;
2620
2621 if (mPopupType == PopupType::Tooltip) {
2622 // Don't fiddle with tooltips type, just hide it before move-to-rect
2623 if (mPopupUseMoveToRect && gtk_widget_is_visible(mShell)) {
2624 HideWaylandPopupWindow(/* aTemporaryHide */ true,
2625 /* aRemoveFromPopupList */ false);
2626 }
2627 LOG(" it's tooltip, quit")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get()); } } while (0)
;
2628 return;
2629 }
2630
2631 // See https://bugzilla.mozilla.org/show_bug.cgi?id=1785185#c8
2632 // gtk_window_move() needs GDK_WINDOW_TYPE_HINT_UTILITY popup type.
2633 // move-to-rect requires GDK_WINDOW_TYPE_HINT_POPUP_MENU popups type.
2634 // We need to set it before map event when popup is hidden.
2635 const GdkWindowTypeHint currentType =
2636 gtk_window_get_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
2637 const GdkWindowTypeHint requiredType = mPopupUseMoveToRect
2638 ? GDK_WINDOW_TYPE_HINT_POPUP_MENU
2639 : GDK_WINDOW_TYPE_HINT_UTILITY;
2640
2641 if (!mPopupUseMoveToRect && currentType == requiredType) {
2642 LOG(" type matches and we're not forced to hide it, quit.")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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."
, GetDebugTag().get()); } } while (0)
;
2643 return;
2644 }
2645
2646 if (gtk_widget_is_visible(mShell)) {
2647 HideWaylandPopupWindow(/* aTemporaryHide */ true,
2648 /* aRemoveFromPopupList */ false);
2649 }
2650
2651 if (currentType != requiredType) {
2652 LOG(" set type %s",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag().get(
), requiredType == GDK_WINDOW_TYPE_HINT_POPUP_MENU ? "MENU" :
"UTILITY"); } } while (0)
2653 requiredType == GDK_WINDOW_TYPE_HINT_POPUP_MENU ? "MENU" : "UTILITY")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag().get(
), requiredType == GDK_WINDOW_TYPE_HINT_POPUP_MENU ? "MENU" :
"UTILITY"); } } while (0)
;
2654 gtk_window_set_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), requiredType);
2655 }
2656}
2657
2658// Plain popup move on Wayland - simply place popup on given location.
2659// We can't just call gtk_window_move() as it's not effective on visible
2660// popups.
2661void nsWindow::WaylandPopupMovePlain(int aX, int aY) {
2662 LOG("nsWindow::WaylandPopupMovePlain(%d, %d)", aX, aY)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupMovePlain(%d, %d)"
, GetDebugTag().get(), aX, aY); } } while (0)
;
2663
2664 // We can directly move only popups based on wl_subsurface type.
2665 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"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 2668); 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 { *((volatile int*)__null) = 2668; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2666 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"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 2668); 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 { *((volatile int*)__null) = 2668; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2667 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"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 2668); 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 { *((volatile int*)__null) = 2668; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2668 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"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 2668); 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 { *((volatile int*)__null) = 2668; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2669
2670 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), aX, aY);
2671
2672 // gtk_window_move() can trick us. When widget is hidden gtk_window_move()
2673 // does not move the widget but sets new widget coordinates when widget
2674 // is mapped again.
2675 //
2676 // If popup used move-to-rect before
2677 // (GdkWindow has POSITION_METHOD_MOVE_TO_RECT set), popup will use
2678 // move-to-rect again when it's mapped and we'll get bogus move-to-rect
2679 // callback.
2680 //
2681 // gdk_window_move() sets position_method to POSITION_METHOD_MOVE_RESIZE
2682 // so we'll use plain move when popup is shown.
2683 if (!gtk_widget_get_mapped(mShell)) {
2684 if (GdkWindow* window = GetToplevelGdkWindow()) {
2685 gdk_window_move(window, aX, aY);
2686 }
2687 }
2688}
2689
2690void nsWindow::WaylandPopupMoveImpl() {
2691 // Available as of GTK 3.24+
2692 static auto sGdkWindowMoveToRect = (void (*)(
2693 GdkWindow*, const GdkRectangle*, GdkGravity, GdkGravity, GdkAnchorHints,
2694 gint, gint))dlsym(RTLD_DEFAULT((void *) 0), "gdk_window_move_to_rect");
2695
2696 if (mPopupUseMoveToRect && !sGdkWindowMoveToRect) {
2697 LOG("can't use move-to-rect due missing gdk_window_move_to_rect()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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()"
, GetDebugTag().get()); } } while (0)
;
2698 mPopupUseMoveToRect = false;
2699 }
2700
2701 GdkRectangle gtkAnchorRect;
2702 GdkPoint offset;
2703 if (mPopupUseMoveToRect) {
2704 mPopupUseMoveToRect =
2705 WaylandPopupCheckAndGetAnchor(&gtkAnchorRect, &offset);
2706 }
2707
2708 LOG("nsWindow::WaylandPopupMove")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::WaylandPopupMove", GetDebugTag
().get()); } } while (0)
;
2709 LOG(" original widget popup position [%d, %d]\n", mPopupPosition.x,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " original widget popup position [%d, %d]\n"
, GetDebugTag().get(), mPopupPosition.x, mPopupPosition.y); }
} while (0)
2710 mPopupPosition.y)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " original widget popup position [%d, %d]\n"
, GetDebugTag().get(), mPopupPosition.x, mPopupPosition.y); }
} while (0)
;
2711 LOG(" relative widget popup position [%d, %d]\n", mRelativePopupPosition.x,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 widget popup position [%d, %d]\n"
, GetDebugTag().get(), mRelativePopupPosition.x, mRelativePopupPosition
.y); } } while (0)
2712 mRelativePopupPosition.y)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 widget popup position [%d, %d]\n"
, GetDebugTag().get(), mRelativePopupPosition.x, mRelativePopupPosition
.y); } } while (0)
;
2713 LOG(" popup use move to rect %d", mPopupUseMoveToRect)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get(), mPopupUseMoveToRect); } } while (0)
;
2714
2715 WaylandPopupPrepareForMove();
2716
2717 if (!mPopupUseMoveToRect) {
2718 WaylandPopupMovePlain(mRelativePopupPosition.x, mRelativePopupPosition.y);
2719 // Layout already should be aware of our bounds, since we didn't change it
2720 // from the widget side for flipping or so.
2721 return;
2722 }
2723
2724 // Correct popup position now. It will be updated by gdk_window_move_to_rect()
2725 // anyway but we need to set it now to avoid a race condition here.
2726 WaylandPopupRemoveNegativePosition();
2727
2728 GdkWindow* gdkWindow = GetToplevelGdkWindow();
2729 if (!g_signal_handler_find(gdkWindow, G_SIGNAL_MATCH_FUNC, 0, 0, nullptr,
2730 FuncToGpointer(NativeMoveResizeCallback), this)) {
2731 g_signal_connect(gdkWindow, "moved-to-rect",g_signal_connect_data ((gdkWindow), ("moved-to-rect"), (((GCallback
) (NativeMoveResizeCallback))), (this), __null, (GConnectFlags
) 0)
2732 G_CALLBACK(NativeMoveResizeCallback), this)g_signal_connect_data ((gdkWindow), ("moved-to-rect"), (((GCallback
) (NativeMoveResizeCallback))), (this), __null, (GConnectFlags
) 0)
;
2733 }
2734 mWaitingForMoveToRectCallback = true;
2735
2736#ifdef MOZ_LOGGING1
2737 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)
))
) {
2738 LOG(" Call move-to-rect")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag(
).get()); } } while (0)
;
2739 LOG(" Anchor rect [%d, %d] -> [%d x %d]", gtkAnchorRect.x, gtkAnchorRect.y,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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]"
, GetDebugTag().get(), gtkAnchorRect.x, gtkAnchorRect.y, gtkAnchorRect
.width, gtkAnchorRect.height); } } while (0)
2740 gtkAnchorRect.width, gtkAnchorRect.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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]"
, GetDebugTag().get(), gtkAnchorRect.x, gtkAnchorRect.y, gtkAnchorRect
.width, gtkAnchorRect.height); } } while (0)
;
2741 LOG(" Offset [%d, %d]", offset.x, offset.y)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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]", GetDebugTag().
get(), offset.x, offset.y); } } while (0)
;
2742 LOG(" AnchorType")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag().get()
); } } while (0)
;
2743 LogPopupGravity(mPopupMoveToRectParams.mAnchorRectType);
2744 LOG(" PopupAnchorType")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag().
get()); } } while (0)
;
2745 LogPopupGravity(mPopupMoveToRectParams.mPopupAnchorType);
2746 LogPopupAnchorHints(mPopupMoveToRectParams.mHints);
2747 }
2748#endif
2749
2750 sGdkWindowMoveToRect(gdkWindow, &gtkAnchorRect,
2751 mPopupMoveToRectParams.mAnchorRectType,
2752 mPopupMoveToRectParams.mPopupAnchorType,
2753 mPopupMoveToRectParams.mHints, offset.x, offset.y);
2754}
2755
2756void nsWindow::SetSizeMode(nsSizeMode aMode) {
2757 LOG("nsWindow::SetSizeMode %d\n", aMode)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetSizeMode %d\n", GetDebugTag
().get(), aMode); } } while (0)
;
2758
2759 // Return if there's no shell or our current state is the same as the mode we
2760 // were just set to.
2761 if (!mShell) {
2762 LOG(" no shell")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " no shell", GetDebugTag().get()
); } } while (0)
;
2763 return;
2764 }
2765
2766 if (mSizeMode == aMode && mLastSizeModeRequest == aMode) {
2767 LOG(" already set")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 set", GetDebugTag().get
()); } } while (0)
;
2768 return;
2769 }
2770
2771 // It is tempting to try to optimize calls below based only on current
2772 // mSizeMode, but that wouldn't work if there's a size-request in flight
2773 // (specially before show). See bug 1789823.
2774 const auto SizeModeMightBe = [&](nsSizeMode aModeToTest) {
2775 if (mSizeMode != mLastSizeModeRequest) {
2776 // Arbitrary size mode requests might be ongoing.
2777 return true;
2778 }
2779 return mSizeMode == aModeToTest;
2780 };
2781
2782 if (aMode != nsSizeMode_Fullscreen && aMode != nsSizeMode_Minimized) {
2783 // Fullscreen and minimized are compatible.
2784 if (SizeModeMightBe(nsSizeMode_Fullscreen)) {
2785 MakeFullScreen(false);
2786 }
2787 }
2788
2789 switch (aMode) {
2790 case nsSizeMode_Maximized:
2791 LOG(" set maximized")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 maximized", GetDebugTag().
get()); } } while (0)
;
2792 gtk_window_maximize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
2793 break;
2794 case nsSizeMode_Minimized:
2795 LOG(" set minimized")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 minimized", GetDebugTag().
get()); } } while (0)
;
2796 gtk_window_iconify(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
2797 break;
2798 case nsSizeMode_Fullscreen:
2799 LOG(" set fullscreen")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 fullscreen", GetDebugTag()
.get()); } } while (0)
;
2800 MakeFullScreen(true);
2801 break;
2802 default:
2803 MOZ_FALLTHROUGH_ASSERT("Unknown size mode")do { do { } while (false); MOZ_ReportCrash("" "MOZ_FALLTHROUGH_ASSERT: "
"Unknown size mode", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 2803); AnnotateMozCrashReason("MOZ_CRASH(" "MOZ_FALLTHROUGH_ASSERT: "
"Unknown size mode" ")"); do { *((volatile int*)__null) = 2803
; __attribute__((nomerge)) ::abort(); } while (false); } while
(false)
;
2804 case nsSizeMode_Normal:
2805 LOG(" set normal")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 normal", GetDebugTag().get
()); } } while (0)
;
2806 if (SizeModeMightBe(nsSizeMode_Maximized)) {
2807 gtk_window_unmaximize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
2808 }
2809 if (SizeModeMightBe(nsSizeMode_Minimized)) {
2810 gtk_window_deiconify(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
2811 // We need this for actual deiconification on mutter.
2812 gtk_window_present(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
2813 }
2814 break;
2815 }
2816 mLastSizeModeRequest = aMode;
2817}
2818
2819#define kDesktopMutterSchema"org.gnome.mutter"_ns "org.gnome.mutter"_ns
2820#define kDesktopDynamicWorkspacesKey"dynamic-workspaces"_ns "dynamic-workspaces"_ns
2821
2822static bool WorkspaceManagementDisabled(GdkScreen* screen) {
2823 if (Preferences::GetBool("widget.disable-workspace-management", false)) {
2824 return true;
2825 }
2826 if (Preferences::HasUserValue("widget.workspace-management")) {
2827 return Preferences::GetBool("widget.workspace-management");
2828 }
2829
2830 if (IsGnomeDesktopEnvironment()) {
2831 // Gnome uses dynamic workspaces by default so disable workspace management
2832 // in that case.
2833 bool usesDynamicWorkspaces = true;
2834 nsCOMPtr<nsIGSettingsService> gsettings =
2835 do_GetService(NS_GSETTINGSSERVICE_CONTRACTID"@mozilla.org/gsettings-service;1");
2836 if (gsettings) {
2837 nsCOMPtr<nsIGSettingsCollection> mutterSettings;
2838 gsettings->GetCollectionForSchema(kDesktopMutterSchema"org.gnome.mutter"_ns,
2839 getter_AddRefs(mutterSettings));
2840 if (mutterSettings) {
2841 mutterSettings->GetBoolean(kDesktopDynamicWorkspacesKey"dynamic-workspaces"_ns,
2842 &usesDynamicWorkspaces);
2843 }
2844 }
2845 return usesDynamicWorkspaces;
2846 }
2847
2848 const auto& desktop = GetDesktopEnvironmentIdentifier();
2849 return desktop.EqualsLiteral("bspwm") || desktop.EqualsLiteral("i3");
2850}
2851
2852void nsWindow::GetWorkspaceID(nsAString& workspaceID) {
2853 workspaceID.Truncate();
2854
2855 if (!GdkIsX11Display() || !mShell) {
2856 return;
2857 }
2858
2859#ifdef MOZ_X111
2860 LOG("nsWindow::GetWorkspaceID()\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::GetWorkspaceID()\n", GetDebugTag
().get()); } } while (0)
;
2861
2862 // Get the gdk window for this widget.
2863 GdkWindow* gdk_window = GetToplevelGdkWindow();
2864 if (!gdk_window) {
2865 LOG(" missing Gdk window, quit.")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " missing Gdk window, quit.", GetDebugTag
().get()); } } while (0)
;
2866 return;
2867 }
2868
2869 if (WorkspaceManagementDisabled(gdk_window_get_screen(gdk_window))) {
2870 LOG(" WorkspaceManagementDisabled, quit.")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " WorkspaceManagementDisabled, quit."
, GetDebugTag().get()); } } while (0)
;
2871 return;
2872 }
2873
2874 GdkAtom cardinal_atom = gdk_x11_xatom_to_atom(XA_CARDINAL((Atom) 6));
2875 GdkAtom type_returned;
2876 int format_returned;
2877 int length_returned;
2878 long* wm_desktop;
2879
2880 if (!gdk_property_get(gdk_window, gdk_atom_intern("_NET_WM_DESKTOP", FALSE(0)),
2881 cardinal_atom,
2882 0, // offset
2883 INT32_MAX(2147483647), // length
2884 FALSE(0), // delete
2885 &type_returned, &format_returned, &length_returned,
2886 (guchar**)&wm_desktop)) {
2887 LOG(" gdk_property_get() failed, quit.")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " gdk_property_get() failed, quit."
, GetDebugTag().get()); } } while (0)
;
2888 return;
2889 }
2890
2891 LOG(" got workspace ID %d", (int32_t)wm_desktop[0])do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " got workspace ID %d", GetDebugTag
().get(), (int32_t)wm_desktop[0]); } } while (0)
;
2892 workspaceID.AppendInt((int32_t)wm_desktop[0]);
2893 g_free(wm_desktop);
2894#endif
2895}
2896
2897void nsWindow::MoveToWorkspace(const nsAString& workspaceIDStr) {
2898 nsresult rv = NS_OK;
2899 int32_t workspaceID = workspaceIDStr.ToInteger(&rv);
2900
2901 LOG("nsWindow::MoveToWorkspace() ID %d", workspaceID)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::MoveToWorkspace() ID %d"
, GetDebugTag().get(), workspaceID); } } while (0)
;
2902 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !workspaceID || !GdkIsX11Display() || !mShell) {
2903 LOG(" MoveToWorkspace disabled, quit")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " MoveToWorkspace disabled, quit",
GetDebugTag().get()); } } while (0)
;
2904 return;
2905 }
2906
2907#ifdef MOZ_X111
2908 // Get the gdk window for this widget.
2909 GdkWindow* gdk_window = GetToplevelGdkWindow();
2910 if (!gdk_window) {
2911 LOG(" failed to get GdkWindow, quit.")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " failed to get GdkWindow, quit.",
GetDebugTag().get()); } } while (0)
;
2912 return;
2913 }
2914
2915 // This code is inspired by some found in the 'gxtuner' project.
2916 // https://github.com/brummer10/gxtuner/blob/792d453da0f3a599408008f0f1107823939d730d/deskpager.cpp#L50
2917 XEvent xevent;
2918 Display* xdisplay = gdk_x11_get_default_xdisplay();
2919 GdkScreen* screen = gdk_window_get_screen(gdk_window);
2920 Window root_win = GDK_WINDOW_XID(gdk_screen_get_root_window(screen))(gdk_x11_window_get_xid (gdk_screen_get_root_window(screen)));
2921 GdkDisplay* display = gdk_window_get_display(gdk_window);
2922 Atom type = gdk_x11_get_xatom_by_name_for_display(display, "_NET_WM_DESKTOP");
2923
2924 xevent.type = ClientMessage33;
2925 xevent.xclient.type = ClientMessage33;
2926 xevent.xclient.serial = 0;
2927 xevent.xclient.send_event = TRUE(!(0));
2928 xevent.xclient.display = xdisplay;
2929 xevent.xclient.window = GDK_WINDOW_XID(gdk_window)(gdk_x11_window_get_xid (gdk_window));
2930 xevent.xclient.message_type = type;
2931 xevent.xclient.format = 32;
2932 xevent.xclient.data.l[0] = workspaceID;
2933 xevent.xclient.data.l[1] = X11CurrentTime0L;
2934 xevent.xclient.data.l[2] = 0;
2935 xevent.xclient.data.l[3] = 0;
2936 xevent.xclient.data.l[4] = 0;
2937
2938 XSendEvent(xdisplay, root_win, FALSE(0),
2939 SubstructureNotifyMask(1L<<19) | SubstructureRedirectMask(1L<<20), &xevent);
2940
2941 XFlush(xdisplay);
2942 LOG(" moved to workspace")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " moved to workspace", GetDebugTag
().get()); } } while (0)
;
2943#endif
2944}
2945
2946void nsWindow::SetUserTimeAndStartupTokenForActivatedWindow() {
2947 nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit();
2948 if (!toolkit || MOZ_UNLIKELY(mWindowType == WindowType::Invisible)(__builtin_expect(!!(mWindowType == WindowType::Invisible), 0
))
) {
2949 return;
2950 }
2951
2952 mWindowActivationTokenFromEnv = toolkit->GetStartupToken();
2953 if (!mWindowActivationTokenFromEnv.IsEmpty()) {
2954 if (!GdkIsWaylandDisplay()) {
2955 gtk_window_set_startup_id(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))),
2956 mWindowActivationTokenFromEnv.get());
2957 // In the case of X11, the above call is all we need. For wayland we need
2958 // to keep the token around until we take it in
2959 // TransferFocusToWaylandWindow.
2960 mWindowActivationTokenFromEnv.Truncate();
2961 }
2962 } else if (uint32_t timestamp = toolkit->GetFocusTimestamp()) {
2963 // We don't have the data we need. Fall back to an
2964 // approximation ... using the timestamp of the remote command
2965 // being received as a guess for the timestamp of the user event
2966 // that triggered it.
2967 gdk_window_focus(GetToplevelGdkWindow(), timestamp);
2968 }
2969
2970 // If we used the startup ID, that already contains the focus timestamp;
2971 // we don't want to reuse the timestamp next time we raise the window
2972 toolkit->SetFocusTimestamp(0);
2973 toolkit->SetStartupToken(""_ns);
2974}
2975
2976/* static */
2977guint32 nsWindow::GetLastUserInputTime() {
2978 // gdk_x11_display_get_user_time/gtk_get_current_event_time tracks
2979 // button and key presses, DESKTOP_STARTUP_ID used to start the app,
2980 // drop events from external drags,
2981 // WM_DELETE_WINDOW delete events, but not usually mouse motion nor
2982 // button and key releases. Therefore use the most recent of
2983 // gdk_x11_display_get_user_time and the last time that we have seen.
2984#ifdef MOZ_X111
2985 GdkDisplay* gdkDisplay = gdk_display_get_default();
2986 guint32 timestamp = GdkIsX11Display(gdkDisplay)
2987 ? gdk_x11_display_get_user_time(gdkDisplay)
2988 : gtk_get_current_event_time();
2989#else
2990 guint32 timestamp = gtk_get_current_event_time();
2991#endif
2992
2993 if (sLastUserInputTime != GDK_CURRENT_TIME0L &&
2994 TimestampIsNewerThan(sLastUserInputTime, timestamp)) {
2995 return sLastUserInputTime;
2996 }
2997
2998 return timestamp;
2999}
3000
3001#ifdef MOZ_WAYLAND1
3002void nsWindow::FocusWaylandWindow(const char* aTokenID) {
3003 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", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 3003); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aTokenID"
")"); do { *((volatile int*)__null) = 3003; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3004
3005 LOG("nsWindow::FocusWaylandWindow(%s)", aTokenID)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::FocusWaylandWindow(%s)",
GetDebugTag().get(), aTokenID); } } while (0)
;
3006 if (IsDestroyed()) {
3007 LOG(" already destroyed, quit.")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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.", GetDebugTag
().get()); } } while (0)
;
3008 return;
3009 }
3010 wl_surface* surface =
3011 mGdkWindow ? gdk_wayland_window_get_wl_surface(mGdkWindow) : nullptr;
3012 if (!surface) {
3013 LOG(" mGdkWindow is not visible, quit.")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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."
, GetDebugTag().get()); } } while (0)
;
3014 return;
3015 }
3016
3017 LOG(" requesting xdg-activation, surface ID %d",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), wl_proxy_get_id((struct wl_proxy*)surface
)); } } while (0)
3018 wl_proxy_get_id((struct wl_proxy*)surface))do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get(), wl_proxy_get_id((struct wl_proxy*)surface
)); } } while (0)
;
3019 xdg_activation_v1* xdg_activation = WaylandDisplayGet()->GetXdgActivation();
3020 if (!xdg_activation) {
3021 return;
3022 }
3023 xdg_activation_v1_activate(xdg_activation, aTokenID, surface);
3024}
3025
3026// Transfer focus from gFocusWindow to aWindow and use xdg_activation
3027// protocol for it.
3028void nsWindow::TransferFocusToWaylandWindow(nsWindow* aWindow) {
3029 LOGW("nsWindow::TransferFocusToWaylandWindow(%p) gFocusWindow %p", aWindow,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, "nsWindow::TransferFocusToWaylandWindow(%p) gFocusWindow %p"
, aWindow, gFocusWindow); } } while (0)
3030 gFocusWindow)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, "nsWindow::TransferFocusToWaylandWindow(%p) gFocusWindow %p"
, aWindow, gFocusWindow); } } while (0)
;
3031 auto promise = mozilla::widget::RequestWaylandFocusPromise();
3032 if (NS_WARN_IF(!promise)NS_warn_if_impl(!promise, "!promise", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 3032)
) {
3033 LOGW(" quit, failed to create TransferFocusToWaylandWindow [%p]", aWindow)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, " quit, failed to create TransferFocusToWaylandWindow [%p]"
, aWindow); } } while (0)
;
3034 return;
3035 }
3036 promise->Then(
3037 GetMainThreadSerialEventTarget(), __func__,
3038 /* resolve */
3039 [window = RefPtr{aWindow}](nsCString token) {
3040 window->FocusWaylandWindow(token.get());
3041 },
3042 /* reject */
3043 [window = RefPtr{aWindow}](bool state) {
3044 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)
;
3045 });
3046}
3047#endif
3048
3049// Request activation of this window or give focus to this widget.
3050// aRaise means whether we should request activation of this widget's
3051// toplevel window.
3052//
3053// nsWindow::SetFocus(Raise::Yes) - Raise and give focus to toplevel window.
3054// nsWindow::SetFocus(Raise::No) - Give focus to this window.
3055void nsWindow::SetFocus(Raise aRaise, mozilla::dom::CallerType aCallerType) {
3056 LOG("nsWindow::SetFocus Raise %d\n", aRaise == Raise::Yes)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetFocus Raise %d\n", GetDebugTag
().get(), aRaise == Raise::Yes); } } while (0)
;
3057
3058 // Raise the window if someone passed in true and the prefs are
3059 // set properly.
3060 GtkWidget* toplevelWidget = gtk_widget_get_toplevel(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))));
3061
3062 LOG(" gFocusWindow [%p]\n", gFocusWindow)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " gFocusWindow [%p]\n", GetDebugTag
().get(), gFocusWindow); } } while (0)
;
3063 LOG(" mContainer [%p]\n", GTK_WIDGET(mContainer))do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " mContainer [%p]\n", GetDebugTag(
).get(), ((((GtkWidget*) (void *) ((mContainer)))))); } } while
(0)
;
3064 LOG(" Toplevel widget [%p]\n", toplevelWidget)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " Toplevel widget [%p]\n", GetDebugTag
().get(), toplevelWidget); } } while (0)
;
3065
3066 // Make sure that our owning widget has focus. If it doesn't try to
3067 // grab it. Note that we don't set our focus flag in this case.
3068 if (StaticPrefs::mozilla_widget_raise_on_setfocus_AtStartup() &&
3069 aRaise == Raise::Yes && toplevelWidget &&
3070 !gtk_widget_has_focus(toplevelWidget)) {
3071 if (gtk_widget_get_visible(mShell)) {
3072 LOG(" toplevel is not focused")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " toplevel is not focused", GetDebugTag
().get()); } } while (0)
;
3073 gdk_window_show_unraised(GetToplevelGdkWindow());
3074 // Unset the urgency hint if possible.
3075 SetUrgencyHint(mShell, false);
3076 }
3077 }
3078
3079 RefPtr<nsWindow> toplevelWindow = get_window_for_gtk_widget(toplevelWidget);
3080 if (!toplevelWindow) {
3081 LOG(" missing toplevel nsWindow, quit\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " missing toplevel nsWindow, quit\n"
, GetDebugTag().get()); } } while (0)
;
3082 return;
3083 }
3084
3085 if (aRaise == Raise::Yes) {
3086 // means request toplevel activation.
3087
3088 // This is asynchronous. If and when the window manager accepts the request,
3089 // then the focus widget will get a focus-in-event signal.
3090 if (StaticPrefs::mozilla_widget_raise_on_setfocus_AtStartup() &&
3091 toplevelWindow->mIsShown && toplevelWindow->mShell &&
3092 !gtk_window_is_active(GTK_WINDOW(toplevelWindow->mShell)((((GtkWindow*) (void *) ((toplevelWindow->mShell))))))) {
3093 LOG(" toplevel is visible but not active, requesting activation [%p]",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " toplevel is visible but not active, requesting activation [%p]"
, GetDebugTag().get(), toplevelWindow.get()); } } while (0)
3094 toplevelWindow.get())do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " toplevel is visible but not active, requesting activation [%p]"
, GetDebugTag().get(), toplevelWindow.get()); } } while (0)
;
3095
3096 // Take the time here explicitly for the call below.
3097 const uint32_t timestamp = [&] {
3098 if (nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit()) {
3099 if (uint32_t t = toolkit->GetFocusTimestamp()) {
3100 toolkit->SetFocusTimestamp(0);
3101 return t;
3102 }
3103 }
3104#if defined(MOZ_X111)
3105 // If it's X11 and there's a startup token, use GDK_CURRENT_TIME, so
3106 // gtk_window_present_with_time will pull the timestamp from the startup
3107 // token.
3108 if (GdkIsX11Display()) {
3109 nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit();
3110 const auto& startupToken = toolkit->GetStartupToken();
3111 if (!startupToken.IsEmpty()) {
3112 return static_cast<uint32_t>(GDK_CURRENT_TIME0L);
3113 }
3114 }
3115#endif
3116 return GetLastUserInputTime();
3117 }();
3118
3119 toplevelWindow->SetUserTimeAndStartupTokenForActivatedWindow();
3120 gtk_window_present_with_time(GTK_WINDOW(toplevelWindow->mShell)((((GtkWindow*) (void *) ((toplevelWindow->mShell))))),
3121 timestamp);
3122
3123#ifdef MOZ_WAYLAND1
3124 if (GdkIsWaylandDisplay()) {
3125 auto existingToken =
3126 std::move(toplevelWindow->mWindowActivationTokenFromEnv);
3127 if (!existingToken.IsEmpty()) {
3128 LOG(" has existing activation token.")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " has existing activation token.",
GetDebugTag().get()); } } while (0)
;
3129 toplevelWindow->FocusWaylandWindow(existingToken.get());
3130 } else {
3131 LOG(" missing activation token, try to transfer from focused "do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " missing activation token, try to transfer from focused "
"window", GetDebugTag().get()); } } while (0)
3132 "window")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " missing activation token, try to transfer from focused "
"window", GetDebugTag().get()); } } while (0)
;
3133 TransferFocusToWaylandWindow(toplevelWindow);
3134 }
3135 }
3136#endif
3137 }
3138 return;
3139 }
3140
3141 // aRaise == No means that keyboard events should be dispatched from this
3142 // widget.
3143
3144 // Ensure GTK_WIDGET(mContainer) is the focused GtkWidget within its toplevel
3145 // window.
3146 //
3147 // For WindowType::Popup, this GtkWidget may not actually be the one that
3148 // receives the key events as it may be the parent window that is active.
3149 if (!gtk_widget_is_focus(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))))) {
3150 // This is synchronous. It takes focus from a plugin or from a widget
3151 // in an embedder. The focus manager already knows that this window
3152 // is active so gBlockActivateEvent avoids another (unnecessary)
3153 // activate notification.
3154 gBlockActivateEvent = true;
3155 gtk_widget_grab_focus(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))));
3156 gBlockActivateEvent = false;
3157 }
3158
3159 // If this is the widget that already has focus, return.
3160 if (gFocusWindow == this) {
3161 LOG(" already have focus")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 have focus", GetDebugTag
().get()); } } while (0)
;
3162 return;
3163 }
3164
3165 // Set this window to be the focused child window
3166 gFocusWindow = this;
3167
3168 if (mIMContext) {
3169 mIMContext->OnFocusWindow(this);
3170 }
3171
3172 LOG(" widget now has focus in SetFocus()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 now has focus in SetFocus()"
, GetDebugTag().get()); } } while (0)
;
3173}
3174
3175void nsWindow::ResetScreenBounds() {
3176 mGdkWindowOrigin.reset();
3177 mGdkWindowRootOrigin.reset();
3178}
3179
3180LayoutDeviceIntRect nsWindow::GetScreenBounds() {
3181 if (!mGdkWindow) {
3182 return mBounds;
3183 }
3184
3185 const LayoutDeviceIntPoint origin = [&] {
3186 GdkPoint origin;
3187
3188 if (mGdkWindowRootOrigin.isSome()) {
3189 origin = mGdkWindowRootOrigin.value();
3190 } else {
3191 gdk_window_get_root_origin(mGdkWindow, &origin.x, &origin.y);
3192 mGdkWindowRootOrigin = Some(origin);
3193 }
3194
3195 // Workaround for https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/4820
3196 // Bug 1775017 Gtk < 3.24.35 returns scaled values for
3197 // override redirected window on X11.
3198 if (gtk_check_version(3, 24, 35) != nullptr && GdkIsX11Display() &&
3199 gdk_window_get_window_type(mGdkWindow) == GDK_WINDOW_TEMP) {
3200 return LayoutDeviceIntPoint(origin.x, origin.y);
3201 }
3202 return GdkPointToDevicePixels(origin);
3203 }();
3204
3205 // mBounds.Size() is the window bounds, not the window-manager frame
3206 // bounds (bug 581863). gdk_window_get_frame_extents would give the
3207 // frame bounds, but mBounds.Size() is returned here for consistency
3208 // with Resize.
3209 const LayoutDeviceIntRect rect(origin, mBounds.Size());
3210#if MOZ_LOGGING1
3211 if (MOZ_LOG_TEST(IsPopup() ? gWidgetPopupLog : gWidgetLog,(__builtin_expect(!!(mozilla::detail::log_test(IsPopup() ? gWidgetPopupLog
: gWidgetLog, LogLevel::Verbose)), 0))
3212 LogLevel::Verbose)(__builtin_expect(!!(mozilla::detail::log_test(IsPopup() ? gWidgetPopupLog
: gWidgetLog, LogLevel::Verbose)), 0))
) {
3213 gint scale = GdkCeiledScaleFactor();
3214 if (mLastLoggedScale != scale || !(mLastLoggedBoundSize == rect)) {
3215 mLastLoggedScale = scale;
3216 mLastLoggedBoundSize = rect;
3217 LOG("GetScreenBounds %d,%d -> %d x %d, unscaled %d,%d -> %d x %d\n",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "GetScreenBounds %d,%d -> %d x %d, unscaled %d,%d -> %d x %d\n"
, GetDebugTag().get(), rect.x, rect.y, rect.width, rect.height
, rect.x / scale, rect.y / scale, rect.width / scale, rect.height
/ scale); } } while (0)
3218 rect.x, rect.y, rect.width, rect.height, rect.x / scale,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "GetScreenBounds %d,%d -> %d x %d, unscaled %d,%d -> %d x %d\n"
, GetDebugTag().get(), rect.x, rect.y, rect.width, rect.height
, rect.x / scale, rect.y / scale, rect.width / scale, rect.height
/ scale); } } while (0)
3219 rect.y / scale, rect.width / scale, rect.height / scale)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "GetScreenBounds %d,%d -> %d x %d, unscaled %d,%d -> %d x %d\n"
, GetDebugTag().get(), rect.x, rect.y, rect.width, rect.height
, rect.x / scale, rect.y / scale, rect.width / scale, rect.height
/ scale); } } while (0)
;
3220 }
3221 }
3222#endif
3223 return rect;
3224}
3225
3226LayoutDeviceIntSize nsWindow::GetClientSize() { return mBounds.Size(); }
3227
3228LayoutDeviceIntRect nsWindow::GetClientBounds() {
3229 // GetBounds returns a rect whose top left represents the top left of the
3230 // outer bounds, but whose width/height represent the size of the inner
3231 // bounds (which is messed up).
3232 LayoutDeviceIntRect rect = GetBounds();
3233 rect.MoveBy(GetClientOffset());
3234 return rect;
3235}
3236
3237void nsWindow::RecomputeClientOffset(bool aNotify) {
3238 if (!IsTopLevelWindowType()) {
3239 return;
3240 }
3241
3242 auto oldOffset = mClientOffset;
3243
3244 mClientOffset = WidgetToScreenOffset() - mBounds.TopLeft();
3245
3246 if (aNotify && mClientOffset != oldOffset) {
3247 // Send a WindowMoved notification. This ensures that BrowserParent picks up
3248 // the new client offset and sends it to the child process if appropriate.
3249 NotifyWindowMoved(mBounds.x, mBounds.y);
3250 }
3251}
3252
3253gboolean nsWindow::OnPropertyNotifyEvent(GtkWidget* aWidget,
3254 GdkEventProperty* aEvent) {
3255 if (aEvent->atom == gdk_atom_intern("_NET_FRAME_EXTENTS", FALSE(0))) {
3256 ResetScreenBounds();
3257 RecomputeClientOffset(/* aNotify = */ true);
3258 return FALSE(0);
3259 }
3260 if (!mGdkWindow) {
3261 return FALSE(0);
3262 }
3263#ifdef MOZ_X111
3264 if (GetCurrentTimeGetter()->PropertyNotifyHandler(aWidget, aEvent)) {
3265 return TRUE(!(0));
3266 }
3267#endif
3268 return FALSE(0);
3269}
3270
3271static GdkCursor* GetCursorForImage(const nsIWidget::Cursor& aCursor,
3272 int32_t aWidgetScaleFactor) {
3273 if (!aCursor.IsCustom()) {
3274 return nullptr;
3275 }
3276 nsIntSize size = nsIWidget::CustomCursorSize(aCursor);
3277
3278 // NOTE: GTK only allows integer scale factors, so we ceil to the larger scale
3279 // factor and then tell gtk to scale it down. We ensure to scale at least to
3280 // the GDK scale factor, so that cursors aren't downsized in HiDPI on wayland,
3281 // see bug 1707533.
3282 int32_t gtkScale = std::max(
3283 aWidgetScaleFactor, int32_t(std::ceil(std::max(aCursor.mResolution.mX,
3284 aCursor.mResolution.mY))));
3285
3286 // Reject cursors greater than 128 pixels in some direction, to prevent
3287 // spoofing.
3288 // XXX ideally we should rescale. Also, we could modify the API to
3289 // allow trusted content to set larger cursors.
3290 //
3291 // TODO(emilio, bug 1445844): Unify the solution for this with other
3292 // platforms.
3293 if (size.width > 128 || size.height > 128) {
3294 return nullptr;
3295 }
3296
3297 nsIntSize rasterSize = size * gtkScale;
3298 RefPtr<GdkPixbuf> pixbuf =
3299 nsImageToPixbuf::ImageToPixbuf(aCursor.mContainer, Some(rasterSize));
3300 if (!pixbuf) {
3301 return nullptr;
3302 }
3303
3304 // Looks like all cursors need an alpha channel (tested on Gtk 2.4.4). This
3305 // is of course not documented anywhere...
3306 // So add one if there isn't one yet
3307 if (!gdk_pixbuf_get_has_alpha(pixbuf)) {
3308 RefPtr<GdkPixbuf> alphaBuf =
3309 dont_AddRef(gdk_pixbuf_add_alpha(pixbuf, FALSE(0), 0, 0, 0));
3310 pixbuf = std::move(alphaBuf);
3311 if (!pixbuf) {
3312 return nullptr;
3313 }
3314 }
3315
3316 cairo_surface_t* surface =
3317 gdk_cairo_surface_create_from_pixbuf(pixbuf, gtkScale, nullptr);
3318 if (!surface) {
3319 return nullptr;
3320 }
3321
3322 auto CleanupSurface =
3323 MakeScopeExit([&]() { cairo_surface_destroy(surface); });
3324
3325 return gdk_cursor_new_from_surface(gdk_display_get_default(), surface,
3326 aCursor.mHotspotX, aCursor.mHotspotY);
3327}
3328
3329void nsWindow::SetCursor(const Cursor& aCursor) {
3330 if (mWidgetCursorLocked || !mGdkWindow) {
3331 return;
3332 }
3333
3334 // Only change cursor if it's actually been changed
3335 if (!mUpdateCursor && mCursor == aCursor) {
3336 return;
3337 }
3338
3339 mUpdateCursor = false;
3340 mCursor = aCursor;
3341
3342 // Try to set the cursor image first, and fall back to the numeric cursor.
3343 GdkCursor* imageCursor = nullptr;
3344 if (mCustomCursorAllowed) {
3345 imageCursor = GetCursorForImage(aCursor, GdkCeiledScaleFactor());
3346 }
3347
3348 // When using a custom cursor, clear the cursor first using eCursor_none, in
3349 // order to work around https://gitlab.gnome.org/GNOME/gtk/-/issues/6242
3350 GdkCursor* nonImageCursor =
3351 get_gtk_cursor(imageCursor ? eCursor_none : aCursor.mDefaultCursor);
3352 auto CleanupCursor = mozilla::MakeScopeExit([&]() {
3353 // get_gtk_cursor returns a weak reference, which we shouldn't unref.
3354 if (imageCursor) {
3355 g_object_unref(imageCursor);
3356 }
3357 });
3358
3359 gdk_window_set_cursor(mGdkWindow, nonImageCursor);
3360 if (imageCursor) {
3361 gdk_window_set_cursor(mGdkWindow, imageCursor);
3362 }
3363}
3364
3365void nsWindow::Invalidate(const LayoutDeviceIntRect& aRect) {
3366 if (!mGdkWindow) {
3367 return;
3368 }
3369
3370 GdkRectangle rect = DevicePixelsToGdkRectRoundOut(aRect);
3371 gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE(0));
3372
3373 LOG("Invalidate (rect): %d %d %d %d\n", rect.x, rect.y, rect.width,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "Invalidate (rect): %d %d %d %d\n",
GetDebugTag().get(), rect.x, rect.y, rect.width, rect.height
); } } while (0)
3374 rect.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "Invalidate (rect): %d %d %d %d\n",
GetDebugTag().get(), rect.x, rect.y, rect.width, rect.height
); } } while (0)
;
3375}
3376
3377void* nsWindow::GetNativeData(uint32_t aDataType) {
3378 switch (aDataType) {
3379 case NS_NATIVE_WINDOW0:
3380 case NS_NATIVE_WIDGET3: {
3381 return mGdkWindow;
3382 }
3383
3384 case NS_NATIVE_SHELLWIDGET10:
3385 return GetToplevelWidget();
3386
3387 case NS_NATIVE_WINDOW_WEBRTC_DEVICE_ID15:
3388 if (!mGdkWindow) {
3389 return nullptr;
3390 }
3391#ifdef MOZ_X111
3392 if (GdkIsX11Display()) {
3393 return (void*)GDK_WINDOW_XID(gdk_window_get_toplevel(mGdkWindow))(gdk_x11_window_get_xid (gdk_window_get_toplevel(mGdkWindow))
)
;
3394 }
3395#endif
3396 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "nsWindow::GetNativeData(): NS_NATIVE_WINDOW_WEBRTC_DEVICE_ID is not "
"handled on Wayland!", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 3398)
3397 "nsWindow::GetNativeData(): NS_NATIVE_WINDOW_WEBRTC_DEVICE_ID is not "NS_DebugBreak(NS_DEBUG_WARNING, "nsWindow::GetNativeData(): NS_NATIVE_WINDOW_WEBRTC_DEVICE_ID is not "
"handled on Wayland!", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 3398)
3398 "handled on Wayland!")NS_DebugBreak(NS_DEBUG_WARNING, "nsWindow::GetNativeData(): NS_NATIVE_WINDOW_WEBRTC_DEVICE_ID is not "
"handled on Wayland!", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 3398)
;
3399 return nullptr;
3400 case NS_RAW_NATIVE_IME_CONTEXT14: {
3401 void* pseudoIMEContext = GetPseudoIMEContext();
3402 if (pseudoIMEContext) {
3403 return pseudoIMEContext;
3404 }
3405 // If IME context isn't available on this widget, we should set |this|
3406 // instead of nullptr.
3407 if (!mIMContext) {
3408 return this;
3409 }
3410 return mIMContext.get();
3411 }
3412 case NS_NATIVE_OPENGL_CONTEXT12:
3413 return nullptr;
3414 case NS_NATIVE_EGL_WINDOW106: {
3415 // On X11 we call it:
3416 // 1) If window is mapped on OnMap() by nsWindow::ResumeCompositorImpl(),
3417 // new EGLSurface/XWindow is created.
3418 // 2) If window is hidden on OnUnmap(), we replace EGLSurface/XWindow
3419 // by offline surface and release XWindow.
3420
3421 // On Wayland it:
3422 // 1) If window is mapped on OnMap(), we request frame callback
3423 // at MozContainer. If we get frame callback at MozContainer,
3424 // nsWindow::ResumeCompositorImpl() is called from it
3425 // and EGLSurface/wl_surface is created.
3426 // 2) If window is hidden on OnUnmap(), we replace EGLSurface/wl_surface
3427 // by offline surface and release XWindow.
3428
3429 // If nsWindow is already destroyed, don't try to get EGL window at all,
3430 // we're going to be deleted anyway.
3431 MutexAutoLock lock(mWindowVisibilityMutex);
3432 void* eglWindow = nullptr;
3433 if (mIsMapped && !mIsDestroyed) {
3434#ifdef MOZ_X111
3435 if (GdkIsX11Display()) {
3436 eglWindow = (void*)GDK_WINDOW_XID(mGdkWindow)(gdk_x11_window_get_xid (mGdkWindow));
3437 }
3438#endif
3439#ifdef MOZ_WAYLAND1
3440 if (GdkIsWaylandDisplay()) {
3441 eglWindow = moz_container_wayland_get_egl_window(
3442 mContainer, FractionalScaleFactor());
3443 }
3444#endif
3445 }
3446 LOG("Get NS_NATIVE_EGL_WINDOW mGdkWindow %p returned eglWindow %p",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "Get NS_NATIVE_EGL_WINDOW mGdkWindow %p returned eglWindow %p"
, GetDebugTag().get(), mGdkWindow, eglWindow); } } while (0)
3447 mGdkWindow, eglWindow)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "Get NS_NATIVE_EGL_WINDOW mGdkWindow %p returned eglWindow %p"
, GetDebugTag().get(), mGdkWindow, eglWindow); } } while (0)
;
3448 return eglWindow;
3449 }
3450 default:
3451 NS_WARNING("nsWindow::GetNativeData called with bad value")NS_DebugBreak(NS_DEBUG_WARNING, "nsWindow::GetNativeData called with bad value"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 3451)
;
3452 return nullptr;
3453 }
3454}
3455
3456nsresult nsWindow::SetTitle(const nsAString& aTitle) {
3457 if (!mShell) {
3458 return NS_OK;
3459 }
3460
3461 // convert the string into utf8 and set the title.
3462#define UTF8_FOLLOWBYTE(ch)(((ch) & 0xC0) == 0x80) (((ch) & 0xC0) == 0x80)
3463 NS_ConvertUTF16toUTF8 titleUTF8(aTitle);
3464 if (titleUTF8.Length() > NS_WINDOW_TITLE_MAX_LENGTH4095) {
3465 // Truncate overlong titles (bug 167315). Make sure we chop after a
3466 // complete sequence by making sure the next char isn't a follow-byte.
3467 uint32_t len = NS_WINDOW_TITLE_MAX_LENGTH4095;
3468 while (UTF8_FOLLOWBYTE(titleUTF8[len])(((titleUTF8[len]) & 0xC0) == 0x80)) --len;
3469 titleUTF8.Truncate(len);
3470 }
3471 gtk_window_set_title(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), (const char*)titleUTF8.get());
3472
3473 return NS_OK;
3474}
3475
3476void nsWindow::SetIcon(const nsAString& aIconSpec) {
3477 if (!mShell) {
3478 return;
3479 }
3480
3481 nsAutoCString iconName;
3482
3483 if (aIconSpec.EqualsLiteral("default")) {
3484 nsAutoString brandName;
3485 WidgetUtils::GetBrandShortName(brandName);
3486 if (brandName.IsEmpty()) {
3487 brandName.AssignLiteral(u"Mozilla");
3488 }
3489 AppendUTF16toUTF8(brandName, iconName);
3490 ToLowerCase(iconName);
3491 } else {
3492 AppendUTF16toUTF8(aIconSpec, iconName);
3493 }
3494
3495 nsCOMPtr<nsIFile> iconFile;
3496 nsAutoCString path;
3497
3498 gint* iconSizes = gtk_icon_theme_get_icon_sizes(gtk_icon_theme_get_default(),
3499 iconName.get());
3500 bool foundIcon = (iconSizes[0] != 0);
3501 g_free(iconSizes);
3502
3503 if (!foundIcon) {
3504 // Look for icons with the following suffixes appended to the base name
3505 // The last two entries (for the old XPM format) will be ignored unless
3506 // no icons are found using other suffixes. XPM icons are deprecated.
3507
3508 const char16_t extensions[9][8] = {u".png", u"16.png", u"32.png",
3509 u"48.png", u"64.png", u"128.png",
3510 u"256.png", u".xpm", u"16.xpm"};
3511
3512 for (uint32_t i = 0; i < ArrayLength(extensions); i++) {
3513 // Don't bother looking for XPM versions if we found a PNG.
3514 if (i == ArrayLength(extensions) - 2 && foundIcon) break;
3515
3516 ResolveIconName(aIconSpec, nsDependentString(extensions[i]),
3517 getter_AddRefs(iconFile));
3518 if (iconFile) {
3519 iconFile->GetNativePath(path);
3520 GdkPixbuf* icon = gdk_pixbuf_new_from_file(path.get(), nullptr);
3521 if (icon) {
3522 gtk_icon_theme_add_builtin_icon(iconName.get(),
3523 gdk_pixbuf_get_height(icon), icon);
3524 g_object_unref(icon);
3525 foundIcon = true;
3526 }
3527 }
3528 }
3529 }
3530
3531 // leave the default icon intact if no matching icons were found
3532 if (foundIcon) {
3533 gtk_window_set_icon_name(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), iconName.get());
3534 }
3535}
3536
3537/* TODO(bug 1655924): gdk_window_get_origin is can block waiting for the X
3538 server for a long time, we would like to use the implementation below
3539 instead. However, removing the synchronous x server queries causes a race
3540 condition to surface, causing issues such as bug 1652743 and bug 1653711.
3541
3542
3543 This code can be used instead of gdk_window_get_origin() but it cuases
3544 such issues:
3545
3546 *aX = 0;
3547 *aY = 0;
3548 if (!aWindow) {
3549 return;
3550 }
3551
3552 GdkWindow* current = aWindow;
3553 while (GdkWindow* parent = gdk_window_get_parent(current)) {
3554 if (parent == current) {
3555 break;
3556 }
3557
3558 int x = 0;
3559 int y = 0;
3560 gdk_window_get_position(current, &x, &y);
3561 *aX += x;
3562 *aY += y;
3563
3564 current = parent;
3565 }
3566*/
3567LayoutDeviceIntPoint nsWindow::WidgetToScreenOffset() {
3568 // Don't use gdk_window_get_origin() on wl_subsurface Wayland popups
3569 // https://gitlab.gnome.org/GNOME/gtk/-/issues/5287
3570 if (IsWaylandPopup() && !mPopupUseMoveToRect) {
3571 return mBounds.TopLeft();
3572 }
3573
3574 GdkPoint origin{};
3575 if (mGdkWindowOrigin.isSome()) {
3576 origin = mGdkWindowOrigin.value();
3577 } else if (mGdkWindow) {
3578 gdk_window_get_origin(mGdkWindow, &origin.x, &origin.y);
3579 mGdkWindowOrigin = Some(origin);
3580 }
3581
3582 return GdkPointToDevicePixels(origin);
3583}
3584
3585void nsWindow::CaptureRollupEvents(bool aDoCapture) {
3586 LOG("CaptureRollupEvents(%d)\n", aDoCapture)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "CaptureRollupEvents(%d)\n", GetDebugTag
().get(), aDoCapture); } } while (0)
;
3587 if (mIsDestroyed) {
3588 return;
3589 }
3590
3591 static constexpr auto kCaptureEventsMask =
3592 GdkEventMask(GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
3593 GDK_POINTER_MOTION_MASK | GDK_TOUCH_MASK);
3594
3595 static bool sSystemNeedsPointerGrab = [&] {
3596 if (GdkIsWaylandDisplay()) {
3597 return false;
3598 }
3599 // We only need to grab the pointer for X servers that move the focus with
3600 // the pointer (like twm, sawfish...). Since we roll up popups on focus out,
3601 // not grabbing the pointer triggers rollup when the mouse enters the popup
3602 // and leaves the main window, see bug 1807482.
3603 //
3604 // FVWM is also affected but less severely: the pointer can enter the
3605 // popup, but if it briefly moves out of the popup and over the main window
3606 // then we see a focus change and roll up the popup.
3607 //
3608 // We don't do it for most common desktops, if only because it causes X11
3609 // crashes like bug 1607713.
3610 const auto& desktop = GetDesktopEnvironmentIdentifier();
3611 return desktop.EqualsLiteral("twm") || desktop.EqualsLiteral("sawfish") ||
3612 StringBeginsWith(desktop, "fvwm"_ns);
3613 }();
3614
3615 const bool grabPointer = [] {
3616 switch (StaticPrefs::widget_gtk_grab_pointer()) {
3617 case 0:
3618 return false;
3619 case 1:
3620 return true;
3621 default:
3622 return sSystemNeedsPointerGrab;
3623 }
3624 }();
3625
3626 if (!grabPointer) {
3627 return;
3628 }
3629
3630 mNeedsToRetryCapturingMouse = false;
3631 if (aDoCapture) {
3632 if (mIsDragPopup || DragInProgress()) {
3633 // Don't add a grab if a drag is in progress, or if the widget is a drag
3634 // feedback popup. (panels with type="drag").
3635 return;
3636 }
3637
3638 if (!mHasMappedToplevel) {
3639 // On X, capturing an unmapped window is pointless (returns
3640 // GDK_GRAB_NOT_VIEWABLE). Avoid the X server round-trip and just retry
3641 // when we're mapped.
3642 mNeedsToRetryCapturingMouse = true;
3643 return;
3644 }
3645
3646 // gdk_pointer_grab is deprecated in favor of gdk_device_grab, but that
3647 // causes a strange bug on X11, most obviously with nested popup menus:
3648 // we somehow take the pointer position relative to the top left of the
3649 // outer menu and use it as if it were relative to the submenu. This
3650 // doesn't happen with gdk_pointer_grab even though the code is very
3651 // similar. See the video attached to bug 1750721 for a demonstration,
3652 // and see also bug 1820542 for when the same thing happened with
3653 // another attempt to use gdk_device_grab.
3654 //
3655 // (gdk_device_grab is deprecated in favor of gdk_seat_grab as of 3.20,
3656 // but at the time of this writing we still support older versions of
3657 // GTK 3.)
3658 GdkGrabStatus status =
3659 gdk_pointer_grab(GetToplevelGdkWindow(),
3660 /* owner_events = */ true, kCaptureEventsMask,
3661 /* confine_to = */ nullptr,
3662 /* cursor = */ nullptr, GetLastUserInputTime());
3663 Unused << NS_WARN_IF(status != GDK_GRAB_SUCCESS)NS_warn_if_impl(status != GDK_GRAB_SUCCESS, "status != GDK_GRAB_SUCCESS"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 3663)
;
3664 LOG(" > pointer grab with status %d", int(status))do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " > pointer grab with status %d"
, GetDebugTag().get(), int(status)); } } while (0)
;
3665 gtk_grab_add(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))));
3666 } else {
3667 // There may not have been a drag in process when aDoCapture was set,
3668 // so make sure to remove any added grab. This is a no-op if the grab
3669 // was not added to this widget.
3670 gtk_grab_remove(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))));
3671 gdk_pointer_ungrab(GetLastUserInputTime());
3672 }
3673}
3674
3675nsresult nsWindow::GetAttention(int32_t aCycleCount) {
3676 LOG("nsWindow::GetAttention")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::GetAttention", GetDebugTag
().get()); } } while (0)
;
3677
3678 GtkWidget* top_window = GetToplevelWidget();
3679 GtkWidget* top_focused_window =
3680 gFocusWindow ? gFocusWindow->GetToplevelWidget() : nullptr;
3681
3682 // Don't get attention if the window is focused anyway.
3683 if (top_window && (gtk_widget_get_visible(top_window)) &&
3684 top_window != top_focused_window) {
3685 SetUrgencyHint(top_window, true);
3686 }
3687
3688 return NS_OK;
3689}
3690
3691bool nsWindow::HasPendingInputEvent() {
3692 // This sucks, but gtk/gdk has no way to answer the question we want while
3693 // excluding paint events, and there's no X API that will let us peek
3694 // without blocking or removing. To prevent event reordering, peek
3695 // anything except expose events. Reordering expose and others should be
3696 // ok, hopefully.
3697 bool haveEvent = false;
3698#ifdef MOZ_X111
3699 XEvent ev;
3700 if (GdkIsX11Display()) {
3701 Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default())(gdk_x11_display_get_xdisplay (gdk_display_get_default()));
3702 haveEvent = XCheckMaskEvent(
3703 display,
3704 KeyPressMask(1L<<0) | KeyReleaseMask(1L<<1) | ButtonPressMask(1L<<2) | ButtonReleaseMask(1L<<3) |
3705 EnterWindowMask(1L<<4) | LeaveWindowMask(1L<<5) | PointerMotionMask(1L<<6) |
3706 PointerMotionHintMask(1L<<7) | Button1MotionMask(1L<<8) | Button2MotionMask(1L<<9) |
3707 Button3MotionMask(1L<<10) | Button4MotionMask(1L<<11) | Button5MotionMask(1L<<12) |
3708 ButtonMotionMask(1L<<13) | KeymapStateMask(1L<<14) | VisibilityChangeMask(1L<<16) |
3709 StructureNotifyMask(1L<<17) | ResizeRedirectMask(1L<<18) | SubstructureNotifyMask(1L<<19) |
3710 SubstructureRedirectMask(1L<<20) | FocusChangeMask(1L<<21) | PropertyChangeMask(1L<<22) |
3711 ColormapChangeMask(1L<<23) | OwnerGrabButtonMask(1L<<24),
3712 &ev);
3713 if (haveEvent) {
3714 XPutBackEvent(display, &ev);
3715 }
3716 }
3717#endif
3718 return haveEvent;
3719}
3720
3721#ifdef cairo_copy_clip_rectangle_list
3722# error "Looks like we're including Mozilla's cairo instead of system cairo"
3723#endif
3724static bool ExtractExposeRegion(LayoutDeviceIntRegion& aRegion, cairo_t* cr) {
3725 cairo_rectangle_list_t* rects = cairo_copy_clip_rectangle_list(cr);
3726 if (rects->status != CAIRO_STATUS_SUCCESS) {
3727 NS_WARNING("Failed to obtain cairo rectangle list.")NS_DebugBreak(NS_DEBUG_WARNING, "Failed to obtain cairo rectangle list."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 3727)
;
3728 return false;
3729 }
3730
3731 for (int i = 0; i < rects->num_rectangles; i++) {
3732 const cairo_rectangle_t& r = rects->rectangles[i];
3733 aRegion.Or(aRegion,
3734 LayoutDeviceIntRect::Truncate((float)r.x, (float)r.y,
3735 (float)r.width, (float)r.height));
3736 }
3737
3738 cairo_rectangle_list_destroy(rects);
3739 return true;
3740}
3741
3742#ifdef MOZ_WAYLAND1
3743void nsWindow::CreateCompositorVsyncDispatcher() {
3744 LOG_VSYNC("nsWindow::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, "nsWindow::CreateCompositorVsyncDispatcher()"
); } } while (0)
;
3745 if (!mWaylandVsyncSource) {
3746 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, " mWaylandVsyncSource is missing, create "
"nsBaseWidget::CompositorVsyncDispatcher()"); } } while (0)
3747 " 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, " mWaylandVsyncSource is missing, create "
"nsBaseWidget::CompositorVsyncDispatcher()"); } } while (0)
3748 "nsBaseWidget::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, " mWaylandVsyncSource is missing, create "
"nsBaseWidget::CompositorVsyncDispatcher()"); } } while (0)
;
3749 nsBaseWidget::CreateCompositorVsyncDispatcher();
3750 return;
3751 }
3752 if (!mCompositorVsyncDispatcherLock) {
3753 mCompositorVsyncDispatcherLock =
3754 MakeUnique<Mutex>("mCompositorVsyncDispatcherLock");
3755 }
3756 MutexAutoLock lock(*mCompositorVsyncDispatcherLock);
3757 if (!mCompositorVsyncDispatcher) {
3758 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, " create CompositorVsyncDispatcher()"
); } } while (0)
;
3759 mCompositorVsyncDispatcher =
3760 new CompositorVsyncDispatcher(mWaylandVsyncDispatcher);
3761 }
3762}
3763#endif
3764
3765void nsWindow::RequestRepaint(LayoutDeviceIntRegion& aRepaintRegion) {
3766 WindowRenderer* renderer = GetWindowRenderer();
3767 WebRenderLayerManager* layerManager = renderer->AsWebRender();
3768 KnowsCompositor* knowsCompositor = renderer->AsKnowsCompositor();
3769
3770 if (knowsCompositor && layerManager && mCompositorSession) {
3771 LOG("nsWindow::RequestRepaint()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::RequestRepaint()", GetDebugTag
().get()); } } while (0)
;
3772
3773 if (!mConfiguredClearColor && !IsPopup()) {
3774 layerManager->WrBridge()->SendSetDefaultClearColor(LookAndFeel::Color(
3775 LookAndFeel::ColorID::Window, PreferenceSheet::ColorSchemeForChrome(),
3776 LookAndFeel::UseStandins::No));
3777 mConfiguredClearColor = true;
3778 }
3779
3780 // We need to paint to the screen even if nothing changed, since if we
3781 // don't have a compositing window manager, our pixels could be stale.
3782 layerManager->SetNeedsComposite(true);
3783 layerManager->SendInvalidRegion(aRepaintRegion.ToUnknownRegion());
3784 }
3785}
3786
3787gboolean nsWindow::OnExposeEvent(cairo_t* cr) {
3788 LOG("nsWindow::OnExposeEvent GdkWindow [%p] XID [0x%lx]", mGdkWindow,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::OnExposeEvent GdkWindow [%p] XID [0x%lx]"
, GetDebugTag().get(), mGdkWindow, GetX11Window()); } } while
(0)
3789 GetX11Window())do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::OnExposeEvent GdkWindow [%p] XID [0x%lx]"
, GetDebugTag().get(), mGdkWindow, GetX11Window()); } } while
(0)
;
3790
3791 // This might destroy us.
3792 NotifyOcclusionState(OcclusionState::VISIBLE);
3793 if (mIsDestroyed) {
3794 LOG("destroyed after NotifyOcclusionState()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "destroyed after NotifyOcclusionState()"
, GetDebugTag().get()); } } while (0)
;
3795 return FALSE(0);
3796 }
3797
3798 // Send any pending resize events so that layout can update.
3799 // May run event loop and destroy us.
3800 MaybeDispatchResized();
3801 if (mIsDestroyed) {
3802 LOG("destroyed after MaybeDispatchResized()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "destroyed after MaybeDispatchResized()"
, GetDebugTag().get()); } } while (0)
;
3803 return FALSE(0);
3804 }
3805
3806 // Windows that are not visible will be painted after they become visible.
3807 if (!mGdkWindow || !mHasMappedToplevel) {
3808 LOG("quit, !mGdkWindow || !mHasMappedToplevel")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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, !mGdkWindow || !mHasMappedToplevel"
, GetDebugTag().get()); } } while (0)
;
3809 return FALSE(0);
3810 }
3811#ifdef MOZ_WAYLAND1
3812 if (GdkIsWaylandDisplay() && !moz_container_wayland_can_draw(mContainer)) {
3813 LOG("quit, !moz_container_wayland_can_draw()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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, !moz_container_wayland_can_draw()"
, GetDebugTag().get()); } } while (0)
;
3814 return FALSE(0);
3815 }
3816#endif
3817
3818 if (!GetListener()) {
3819 LOG("quit, !GetListener()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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, !GetListener()", GetDebugTag
().get()); } } while (0)
;
3820 return FALSE(0);
3821 }
3822
3823 LayoutDeviceIntRegion exposeRegion;
3824 if (!ExtractExposeRegion(exposeRegion, cr)) {
3825 LOG(" no rects, quit")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " no rects, quit", GetDebugTag().get
()); } } while (0)
;
3826 return FALSE(0);
3827 }
3828
3829 gint scale = GdkCeiledScaleFactor();
3830 LayoutDeviceIntRegion region = exposeRegion;
3831 region.ScaleRoundOut(scale, scale);
3832
3833 RequestRepaint(region);
3834
3835 RefPtr<nsWindow> strongThis(this);
3836
3837 // Dispatch WillPaintWindow notification to allow scripts etc. to run
3838 // before we paint. It also spins event loop which may show/hide the window
3839 // so we may have new renderer etc.
3840 GetListener()->WillPaintWindow(this);
3841
3842 // If the window has been destroyed during the will paint notification,
3843 // there is nothing left to do.
3844 if (!mGdkWindow || mIsDestroyed) {
3845 LOG("quit, !mGdkWindow || mIsDestroyed")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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, !mGdkWindow || mIsDestroyed"
, GetDebugTag().get()); } } while (0)
;
3846 return TRUE(!(0));
3847 }
3848
3849 // Re-get all rendering components since the will paint notification
3850 // might have killed it.
3851 nsIWidgetListener* listener = GetListener();
3852 if (!listener) {
3853 LOG("quit, !listener")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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, !listener", GetDebugTag().get
()); } } while (0)
;
3854 return FALSE(0);
3855 }
3856
3857 WindowRenderer* renderer = GetWindowRenderer();
3858 WebRenderLayerManager* layerManager = renderer->AsWebRender();
3859 KnowsCompositor* knowsCompositor = renderer->AsKnowsCompositor();
3860
3861 if (knowsCompositor && layerManager && layerManager->NeedsComposite()) {
3862 LOG("needs composite, ScheduleComposite() call")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "needs composite, ScheduleComposite() call"
, GetDebugTag().get()); } } while (0)
;
3863 layerManager->ScheduleComposite(wr::RenderReasons::WIDGET);
3864 layerManager->SetNeedsComposite(false);
3865 }
3866
3867 // Our bounds may have changed after calling WillPaintWindow. Clip
3868 // to the new bounds here. The region is relative to this
3869 // window.
3870 region.And(region, LayoutDeviceIntRect(0, 0, mBounds.width, mBounds.height));
3871 if (region.IsEmpty()) {
3872 LOG("quit, region.IsEmpty()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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, region.IsEmpty()", GetDebugTag
().get()); } } while (0)
;
3873 return TRUE(!(0));
3874 }
3875
3876 // If this widget uses OMTC...
3877 if (renderer->GetBackendType() == LayersBackend::LAYERS_WR) {
3878 LOG("redirect painting to OMTC rendering...")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "redirect painting to OMTC rendering..."
, GetDebugTag().get()); } } while (0)
;
3879 listener->PaintWindow(this, region);
3880
3881 // Re-get the listener since the will paint notification might have
3882 // killed it.
3883 listener = GetListener();
3884 if (!listener) {
3885 return TRUE(!(0));
3886 }
3887
3888 listener->DidPaintWindow();
3889 return TRUE(!(0));
3890 }
3891
3892 BufferMode layerBuffering = BufferMode::BUFFERED;
3893 RefPtr<DrawTarget> dt = StartRemoteDrawingInRegion(region, &layerBuffering);
3894 if (!dt || !dt->IsValid()) {
3895 return FALSE(0);
3896 }
3897 Maybe<gfxContext> ctx;
3898 IntRect boundsRect = region.GetBounds().ToUnknownRect();
3899 IntPoint offset(0, 0);
3900 if (dt->GetSize() == boundsRect.Size()) {
3901 offset = boundsRect.TopLeft();
3902 dt->SetTransform(Matrix::Translation(-offset));
3903 }
3904
3905#ifdef MOZ_X111
3906 gfxUtils::ClipToRegion(dt, region.ToUnknownRegion());
3907 ctx.emplace(dt, /* aPreserveTransform */ true);
3908
3909# if 0
3910 // NOTE: Paint flashing region would be wrong for cairo, since
3911 // cairo inflates the update region, etc. So don't paint flash
3912 // for cairo.
3913# ifdef DEBUG1
3914 // XXX aEvent->region may refer to a newly-invalid area. FIXME
3915 if (0 && WANT_PAINT_FLASHING && gtk_widget_get_window(aEvent))
3916 gdk_window_flash(mGdkWindow, 1, 100, aEvent->region);
3917# endif
3918# endif
3919
3920#endif // MOZ_X11
3921
3922 {
3923 if (renderer->GetBackendType() == LayersBackend::LAYERS_NONE) {
3924 if (GetTransparencyMode() == TransparencyMode::Transparent &&
3925 layerBuffering == BufferMode::BUFFER_NONE && mHasAlphaVisual) {
3926 // If our draw target is unbuffered and we use an alpha channel,
3927 // clear the image beforehand to ensure we don't get artifacts from a
3928 // reused SHM image. See bug 1258086.
3929 dt->ClearRect(Rect(boundsRect));
3930 }
3931 AutoLayerManagerSetup setupLayerManager(
3932 this, ctx.isNothing() ? nullptr : &ctx.ref(), layerBuffering);
3933 listener->PaintWindow(this, region);
3934
3935 // Re-get the listener since the will paint notification might have
3936 // killed it.
3937 listener = GetListener();
3938 if (!listener) {
3939 return TRUE(!(0));
3940 }
3941 }
3942 }
3943
3944#ifdef MOZ_X111
3945 ctx.reset();
3946 dt->PopClip();
3947#endif // MOZ_X11
3948
3949 EndRemoteDrawingInRegion(dt, region);
3950
3951 listener->DidPaintWindow();
3952
3953 // Synchronously flush any new dirty areas
3954 cairo_region_t* dirtyArea = gdk_window_get_update_area(mGdkWindow);
3955
3956 if (dirtyArea) {
3957 gdk_window_invalidate_region(mGdkWindow, dirtyArea, false);
3958 cairo_region_destroy(dirtyArea);
3959 gdk_window_process_updates(mGdkWindow, false);
3960 }
3961
3962 // check the return value!
3963 return TRUE(!(0));
3964}
3965
3966gboolean nsWindow::OnConfigureEvent(GtkWidget* aWidget,
3967 GdkEventConfigure* aEvent) {
3968 // These events are only received on toplevel windows.
3969 //
3970 // GDK ensures that the coordinates are the client window top-left wrt the
3971 // root window.
3972 //
3973 // GDK calculates the cordinates for real ConfigureNotify events on
3974 // managed windows (that would normally be relative to the parent
3975 // window).
3976 //
3977 // Synthetic ConfigureNotify events are from the window manager and
3978 // already relative to the root window. GDK creates all X windows with
3979 // border_width = 0, so synthetic events also indicate the top-left of
3980 // the client window.
3981 //
3982 // Override-redirect windows are children of the root window so parent
3983 // coordinates are root coordinates.
3984
3985#ifdef MOZ_LOGGING1
3986 int scale = mGdkWindow ? gdk_window_get_scale_factor(mGdkWindow) : -1;
3987 LOG("configure event %d,%d -> %d x %d direct mGdkWindow scale %d (scaled "do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "configure event %d,%d -> %d x %d direct mGdkWindow scale %d (scaled "
"size %d x %d)\n", GetDebugTag().get(), aEvent->x, aEvent
->y, aEvent->width, aEvent->height, scale, aEvent->
width * scale, aEvent->height * scale); } } while (0)
3988 "size %d x %d)\n",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "configure event %d,%d -> %d x %d direct mGdkWindow scale %d (scaled "
"size %d x %d)\n", GetDebugTag().get(), aEvent->x, aEvent
->y, aEvent->width, aEvent->height, scale, aEvent->
width * scale, aEvent->height * scale); } } while (0)
3989 aEvent->x, aEvent->y, aEvent->width, aEvent->height, scale,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "configure event %d,%d -> %d x %d direct mGdkWindow scale %d (scaled "
"size %d x %d)\n", GetDebugTag().get(), aEvent->x, aEvent
->y, aEvent->width, aEvent->height, scale, aEvent->
width * scale, aEvent->height * scale); } } while (0)
3990 aEvent->width * scale, aEvent->height * scale)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "configure event %d,%d -> %d x %d direct mGdkWindow scale %d (scaled "
"size %d x %d)\n", GetDebugTag().get(), aEvent->x, aEvent
->y, aEvent->width, aEvent->height, scale, aEvent->
width * scale, aEvent->height * scale); } } while (0)
;
3991#endif
3992
3993 if (mPendingConfigures > 0) {
3994 mPendingConfigures--;
3995 }
3996
3997 ResetScreenBounds();
3998
3999 // Don't fire configure event for scale changes, we handle that
4000 // OnScaleChanged event. Skip that for toplevel windows only.
4001 if (mGdkWindow && IsTopLevelWindowType()) {
4002 if (mCeiledScaleFactor != gdk_window_get_scale_factor(mGdkWindow)) {
4003 LOG(" scale factor changed to %d,return early",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " scale factor changed to %d,return early"
, GetDebugTag().get(), gdk_window_get_scale_factor(mGdkWindow
)); } } while (0)
4004 gdk_window_get_scale_factor(mGdkWindow))do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " scale factor changed to %d,return early"
, GetDebugTag().get(), gdk_window_get_scale_factor(mGdkWindow
)); } } while (0)
;
4005 return FALSE(0);
4006 }
4007 }
4008
4009 LayoutDeviceIntRect screenBounds = GetScreenBounds();
4010
4011 if (IsTopLevelWindowType()) {
4012 // This check avoids unwanted rollup on spurious configure events from
4013 // Cygwin/X (bug 672103).
4014 if (mBounds.x != screenBounds.x || mBounds.y != screenBounds.y) {
4015 RollupAllMenus();
4016 }
4017 }
4018
4019 NS_ASSERTION(GTK_IS_WINDOW(aWidget),do { if (!((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((aWidget)); GType __t = ((gtk_window_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; })))))) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Configure event on widget that is not a GtkWindow"
, "GTK_IS_WINDOW(aWidget)", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 4020); MOZ_PretendNoReturn(); } } while (0)
4020 "Configure event on widget that is not a GtkWindow")do { if (!((((__extension__ ({ GTypeInstance *__inst = (GTypeInstance
*) ((aWidget)); GType __t = ((gtk_window_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; })))))) { NS_DebugBreak
(NS_DEBUG_ASSERTION, "Configure event on widget that is not a GtkWindow"
, "GTK_IS_WINDOW(aWidget)", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 4020); MOZ_PretendNoReturn(); } } while (0)
;
4021 if (mGdkWindow &&
4022 gtk_window_get_window_type(GTK_WINDOW(aWidget)((((GtkWindow*) (void *) ((aWidget)))))) == GTK_WINDOW_POPUP) {
4023 // Override-redirect window
4024 //
4025 // These windows should not be moved by the window manager, and so any
4026 // change in position is a result of our direction. mBounds has
4027 // already been set in std::move() or Resize(), and that is more
4028 // up-to-date than the position in the ConfigureNotify event if the
4029 // event is from an earlier window move.
4030 //
4031 // Skipping the WindowMoved call saves context menus from an infinite
4032 // loop when nsXULPopupManager::PopupMoved moves the window to the new
4033 // position and nsMenuPopupFrame::SetPopupPosition adds
4034 // offsetForContextMenu on each iteration.
4035
4036 // Our back buffer might have been invalidated while we drew the last
4037 // frame, and its contents might be incorrect. See bug 1280653 comment 7
4038 // and comment 10. Specifically we must ensure we recomposite the frame
4039 // as soon as possible to avoid the corrupted frame being displayed.
4040 GetWindowRenderer()->FlushRendering(wr::RenderReasons::WIDGET);
4041 return FALSE(0);
4042 }
4043
4044 mBounds.MoveTo(screenBounds.TopLeft());
4045 RecomputeClientOffset(/* aNotify = */ false);
4046
4047 // XXX mozilla will invalidate the entire window after this move
4048 // complete. wtf?
4049 NotifyWindowMoved(mBounds.x, mBounds.y);
4050
4051 return FALSE(0);
4052}
4053
4054void nsWindow::OnSizeAllocate(GtkAllocation* aAllocation) {
4055 LOG("nsWindow::OnSizeAllocate %d,%d -> %d x %d\n", aAllocation->x,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::OnSizeAllocate %d,%d -> %d x %d\n"
, GetDebugTag().get(), aAllocation->x, aAllocation->y, aAllocation
->width, aAllocation->height); } } while (0)
4056 aAllocation->y, aAllocation->width, aAllocation->height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::OnSizeAllocate %d,%d -> %d x %d\n"
, GetDebugTag().get(), aAllocation->x, aAllocation->y, aAllocation
->width, aAllocation->height); } } while (0)
;
4057
4058 ResetScreenBounds();
4059
4060 // Client offset are updated by _NET_FRAME_EXTENTS on X11 when system titlebar
4061 // is enabled. In either cases (Wayland or system titlebar is off on X11)
4062 // we don't get _NET_FRAME_EXTENTS X11 property notification so we derive
4063 // it from mContainer position.
4064 RecomputeClientOffset(/* aNotify = */ true);
4065
4066 mHasReceivedSizeAllocate = true;
4067
4068 LayoutDeviceIntSize size = GdkRectToDevicePixels(*aAllocation).Size();
4069
4070 // Sometimes the window manager gives us garbage sizes (way past the maximum
4071 // texture size) causing crashes if we don't enforce size constraints again
4072 // here.
4073 ConstrainSize(&size.width, &size.height);
4074
4075 if (mBounds.Size() == size) {
4076 LOG(" Already the same size")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 the same size", GetDebugTag
().get()); } } while (0)
;
4077 // mBounds was set at Create() or Resize().
4078 if (mNeedsDispatchSize != LayoutDeviceIntSize(-1, -1)) {
4079 LOG(" No longer needs to dispatch %dx%d", mNeedsDispatchSize.width,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " No longer needs to dispatch %dx%d"
, GetDebugTag().get(), mNeedsDispatchSize.width, mNeedsDispatchSize
.height); } } while (0)
4080 mNeedsDispatchSize.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " No longer needs to dispatch %dx%d"
, GetDebugTag().get(), mNeedsDispatchSize.width, mNeedsDispatchSize
.height); } } while (0)
;
4081 mNeedsDispatchSize = LayoutDeviceIntSize(-1, -1);
4082 }
4083 return;
4084 }
4085
4086 // Invalidate the new part of the window now for the pending paint to
4087 // minimize background flashes (GDK does not do this for external resizes
4088 // of toplevels.)
4089 if (mGdkWindow) {
4090 if (mBounds.width < size.width) {
4091 GdkRectangle rect = DevicePixelsToGdkRectRoundOut(LayoutDeviceIntRect(
4092 mBounds.width, 0, size.width - mBounds.width, size.height));
4093 gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE(0));
4094 }
4095 if (mBounds.height < size.height) {
4096 GdkRectangle rect = DevicePixelsToGdkRectRoundOut(LayoutDeviceIntRect(
4097 0, mBounds.height, size.width, size.height - mBounds.height));
4098 gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE(0));
4099 }
4100 }
4101
4102 // If we update mBounds here, then inner/outerHeight are out of sync until
4103 // we call WindowResized.
4104 mNeedsDispatchSize = size;
4105
4106 // Gecko permits running nested event loops during processing of events,
4107 // GtkWindow callers of gtk_widget_size_allocate expect the signal
4108 // handlers to return sometime in the near future.
4109 NS_DispatchToCurrentThread(NewRunnableMethod(
4110 "nsWindow::MaybeDispatchResized", this, &nsWindow::MaybeDispatchResized));
4111}
4112
4113void nsWindow::OnDeleteEvent() {
4114 if (mWidgetListener) mWidgetListener->RequestWindowClose(this);
4115}
4116
4117void nsWindow::OnEnterNotifyEvent(GdkEventCrossing* aEvent) {
4118 LOG("enter notify (win=%p, sub=%p): %f, %f mode %d, detail %d\n",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "enter notify (win=%p, sub=%p): %f, %f mode %d, detail %d\n"
, GetDebugTag().get(), aEvent->window, aEvent->subwindow
, aEvent->x, aEvent->y, aEvent->mode, aEvent->detail
); } } while (0)
4119 aEvent->window, aEvent->subwindow, aEvent->x, aEvent->y, aEvent->mode,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "enter notify (win=%p, sub=%p): %f, %f mode %d, detail %d\n"
, GetDebugTag().get(), aEvent->window, aEvent->subwindow
, aEvent->x, aEvent->y, aEvent->mode, aEvent->detail
); } } while (0)
4120 aEvent->detail)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "enter notify (win=%p, sub=%p): %f, %f mode %d, detail %d\n"
, GetDebugTag().get(), aEvent->window, aEvent->subwindow
, aEvent->x, aEvent->y, aEvent->mode, aEvent->detail
); } } while (0)
;
4121 // This skips NotifyVirtual and NotifyNonlinearVirtual enter notify events
4122 // when the pointer enters a child window. If the destination window is a
4123 // Gecko window then we'll catch the corresponding event on that window,
4124 // but we won't notice when the pointer directly enters a foreign (plugin)
4125 // child window without passing over a visible portion of a Gecko window.
4126 if (aEvent->subwindow) {
4127 return;
4128 }
4129
4130 // Check before checking for ungrab as the button state may have
4131 // changed while a non-Gecko ancestor window had a pointer grab.
4132 DispatchMissedButtonReleases(aEvent);
4133
4134 WidgetMouseEvent event(true, eMouseEnterIntoWidget, this,
4135 WidgetMouseEvent::eReal);
4136
4137 event.mRefPoint = GdkEventCoordsToDevicePixels(aEvent->x, aEvent->y);
4138 event.AssignEventTime(GetWidgetEventTime(aEvent->time));
4139
4140 LOG("OnEnterNotify")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "OnEnterNotify", GetDebugTag().get(
)); } } while (0)
;
4141
4142 DispatchInputEvent(&event);
4143}
4144
4145// Some window managers send a bogus top-level leave-notify event on every
4146// click. That confuses our event handling code in ways that can break websites,
4147// see bug 1805939 for details.
4148//
4149// Make sure to only check this on bogus environments, since for environments
4150// with CSD, gdk_device_get_window_at_position could return the window even when
4151// the pointer is in the decoration area.
4152static bool IsBogusLeaveNotifyEvent(GdkWindow* aWindow,
4153 GdkEventCrossing* aEvent) {
4154 static bool sBogusWm = [] {
4155 if (GdkIsWaylandDisplay()) {
4156 return false;
4157 }
4158 const auto& desktopEnv = GetDesktopEnvironmentIdentifier();
4159 return desktopEnv.EqualsLiteral("fluxbox") || // Bug 1805939 comment 0.
4160 desktopEnv.EqualsLiteral("blackbox") || // Bug 1805939 comment 32.
4161 desktopEnv.EqualsLiteral("lg3d") || // Bug 1820405.
4162 desktopEnv.EqualsLiteral("pekwm") || // Bug 1822911.
4163 StringBeginsWith(desktopEnv, "fvwm"_ns);
4164 }();
4165
4166 const bool shouldCheck = [] {
4167 switch (StaticPrefs::widget_gtk_ignore_bogus_leave_notify()) {
4168 case 0:
4169 return false;
4170 case 1:
4171 return true;
4172 default:
4173 return sBogusWm;
4174 }
4175 }();
4176
4177 if (!shouldCheck || !aWindow) {
4178 return false;
4179 }
4180 GdkDevice* pointer = GdkGetPointer();
4181 GdkWindow* winAtPt =
4182 gdk_device_get_window_at_position(pointer, nullptr, nullptr);
4183 if (!winAtPt) {
4184 return false;
4185 }
4186 // We're still in the same top level window, ignore this leave notify event.
4187 GdkWindow* topLevelAtPt = gdk_window_get_toplevel(winAtPt);
4188 GdkWindow* topLevelWidget = gdk_window_get_toplevel(aWindow);
4189 return topLevelAtPt == topLevelWidget;
4190}
4191
4192void nsWindow::OnLeaveNotifyEvent(GdkEventCrossing* aEvent) {
4193 LOG("leave notify (win=%p, sub=%p): %f, %f mode %d, detail %d\n",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "leave notify (win=%p, sub=%p): %f, %f mode %d, detail %d\n"
, GetDebugTag().get(), aEvent->window, aEvent->subwindow
, aEvent->x, aEvent->y, aEvent->mode, aEvent->detail
); } } while (0)
4194 aEvent->window, aEvent->subwindow, aEvent->x, aEvent->y, aEvent->mode,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "leave notify (win=%p, sub=%p): %f, %f mode %d, detail %d\n"
, GetDebugTag().get(), aEvent->window, aEvent->subwindow
, aEvent->x, aEvent->y, aEvent->mode, aEvent->detail
); } } while (0)
4195 aEvent->detail)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "leave notify (win=%p, sub=%p): %f, %f mode %d, detail %d\n"
, GetDebugTag().get(), aEvent->window, aEvent->subwindow
, aEvent->x, aEvent->y, aEvent->mode, aEvent->detail
); } } while (0)
;
4196
4197 // This ignores NotifyVirtual and NotifyNonlinearVirtual leave notify
4198 // events when the pointer leaves a child window. If the destination
4199 // window is a Gecko window then we'll catch the corresponding event on
4200 // that window.
4201 //
4202 // XXXkt However, we will miss toplevel exits when the pointer directly
4203 // leaves a foreign (plugin) child window without passing over a visible
4204 // portion of a Gecko window.
4205 if (aEvent->subwindow) {
4206 return;
4207 }
4208
4209 // The filter out for subwindows should make sure that this is targeted to
4210 // this nsWindow.
4211 const bool leavingTopLevel = IsTopLevelWindowType();
4212 if (leavingTopLevel && IsBogusLeaveNotifyEvent(mGdkWindow, aEvent)) {
4213 return;
4214 }
4215
4216 WidgetMouseEvent event(true, eMouseExitFromWidget, this,
4217 WidgetMouseEvent::eReal);
4218
4219 event.mRefPoint = GdkEventCoordsToDevicePixels(aEvent->x, aEvent->y);
4220 event.AssignEventTime(GetWidgetEventTime(aEvent->time));
4221 event.mExitFrom = Some(leavingTopLevel ? WidgetMouseEvent::ePlatformTopLevel
4222 : WidgetMouseEvent::ePlatformChild);
4223
4224 LOG("OnLeaveNotify")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "OnLeaveNotify", GetDebugTag().get(
)); } } while (0)
;
4225
4226 DispatchInputEvent(&event);
4227}
4228
4229Maybe<GdkWindowEdge> nsWindow::CheckResizerEdge(
4230 const LayoutDeviceIntPoint& aPoint) {
4231 const bool canResize = [&] {
4232 // Don't allow resizing maximized/fullscreen windows.
4233 if (mSizeMode != nsSizeMode_Normal) {
4234 return false;
4235 }
4236 if (mIsPIPWindow) {
4237 // Note that since we do show resizers on left/right sides on PIP windows,
4238 // we still want the resizers there, even when tiled.
4239 return true;
4240 }
4241 if (!mDrawInTitlebar) {
4242 return false;
4243 }
4244 // On KDE, allow for 1 extra pixel at the top of regular windows when
4245 // drawing to the titlebar. This matches the native titlebar behavior on
4246 // that environment. See bug 1813554.
4247 //
4248 // Don't do that on GNOME (see bug 1822764). If we wanted to do this on
4249 // GNOME we'd need an extra check for mIsTiled, since the window is "stuck"
4250 // to the top and bottom.
4251 //
4252 // Other DEs are untested.
4253 return mDrawInTitlebar && IsKdeDesktopEnvironment();
4254 }();
4255
4256 if (!canResize) {
4257 return Nothing();
4258 }
4259
4260 // If we're not in a PiP window, allow 1px resizer edge from the top edge,
4261 // and nothing else.
4262 // This is to allow resizes of tiled windows on KDE, see bug 1813554.
4263 const int resizerHeight = (mIsPIPWindow ? 15 : 1) * GdkCeiledScaleFactor();
4264 const int resizerWidth = resizerHeight * 4;
4265
4266 const int topDist = aPoint.y;
4267 const int leftDist = aPoint.x;
4268 const int rightDist = mBounds.width - aPoint.x;
4269 const int bottomDist = mBounds.height - aPoint.y;
4270
4271 // We can't emulate resize of North/West edges on Wayland as we can't shift
4272 // toplevel window.
4273 bool waylandLimitedResize = mAspectRatio != 0.0f && GdkIsWaylandDisplay();
4274
4275 if (topDist <= resizerHeight) {
4276 if (rightDist <= resizerWidth) {
4277 return Some(GDK_WINDOW_EDGE_NORTH_EAST);
4278 }
4279 if (leftDist <= resizerWidth) {
4280 return Some(GDK_WINDOW_EDGE_NORTH_WEST);
4281 }
4282 return waylandLimitedResize ? Nothing() : Some(GDK_WINDOW_EDGE_NORTH);
4283 }
4284
4285 if (!mIsPIPWindow) {
4286 return Nothing();
4287 }
4288
4289 if (bottomDist <= resizerHeight) {
4290 if (leftDist <= resizerWidth) {
4291 return Some(GDK_WINDOW_EDGE_SOUTH_WEST);
4292 }
4293 if (rightDist <= resizerWidth) {
4294 return Some(GDK_WINDOW_EDGE_SOUTH_EAST);
4295 }
4296 return Some(GDK_WINDOW_EDGE_SOUTH);
4297 }
4298
4299 if (leftDist <= resizerHeight) {
4300 if (topDist <= resizerWidth) {
4301 return Some(GDK_WINDOW_EDGE_NORTH_WEST);
4302 }
4303 if (bottomDist <= resizerWidth) {
4304 return Some(GDK_WINDOW_EDGE_SOUTH_WEST);
4305 }
4306 return waylandLimitedResize ? Nothing() : Some(GDK_WINDOW_EDGE_WEST);
4307 }
4308
4309 if (rightDist <= resizerHeight) {
4310 if (topDist <= resizerWidth) {
4311 return Some(GDK_WINDOW_EDGE_NORTH_EAST);
4312 }
4313 if (bottomDist <= resizerWidth) {
4314 return Some(GDK_WINDOW_EDGE_SOUTH_EAST);
4315 }
4316 return Some(GDK_WINDOW_EDGE_EAST);
4317 }
4318 return Nothing();
4319}
4320
4321template <typename Event>
4322static LayoutDeviceIntPoint GetRefPoint(nsWindow* aWindow, Event* aEvent) {
4323 if (aEvent->window == aWindow->GetGdkWindow()) {
4324 // we are the window that the event happened on so no need for expensive
4325 // WidgetToScreenOffset
4326 return aWindow->GdkEventCoordsToDevicePixels(aEvent->x, aEvent->y);
4327 }
4328 // XXX we're never quite sure which GdkWindow the event came from due to our
4329 // custom bubbling in scroll_event_cb(), so use ScreenToWidget to translate
4330 // the screen root coordinates into coordinates relative to this widget.
4331 return aWindow->GdkEventCoordsToDevicePixels(aEvent->x_root, aEvent->y_root) -
4332 aWindow->WidgetToScreenOffset();
4333}
4334
4335void nsWindow::EmulateResizeDrag(GdkEventMotion* aEvent) {
4336 auto newPoint = LayoutDeviceIntPoint::Floor(aEvent->x, aEvent->y);
4337 LayoutDeviceIntPoint diff = newPoint - mLastResizePoint;
4338 mLastResizePoint = newPoint;
4339
4340 GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mBounds.Size());
4341 LayoutDeviceIntSize newSize(size.width + diff.x, size.height + diff.y);
4342
4343 if (mAspectResizer.value() == GTK_ORIENTATION_VERTICAL) {
4344 newSize.width = int(newSize.height * mAspectRatio);
4345 } else { // GTK_ORIENTATION_HORIZONTAL
4346 newSize.height = int(newSize.width / mAspectRatio);
4347 }
4348 LOG(" aspect ratio correction %d x %d aspect %f\n", newSize.width,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " aspect ratio correction %d x %d aspect %f\n"
, GetDebugTag().get(), newSize.width, newSize.height, mAspectRatio
); } } while (0)
4349 newSize.height, mAspectRatio)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " aspect ratio correction %d x %d aspect %f\n"
, GetDebugTag().get(), newSize.width, newSize.height, mAspectRatio
); } } while (0)
;
4350 gtk_window_resize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), newSize.width, newSize.height);
4351}
4352
4353void nsWindow::OnMotionNotifyEvent(GdkEventMotion* aEvent) {
4354 if (!mGdkWindow) {
4355 return;
4356 }
4357
4358 // Emulate gdk_window_begin_resize_drag() for windows
4359 // with fixed aspect ratio on Wayland.
4360 if (mAspectResizer && mAspectRatio != 0.0f) {
4361 EmulateResizeDrag(aEvent);
4362 return;
4363 }
4364
4365 if (mWindowShouldStartDragging) {
4366 mWindowShouldStartDragging = false;
4367 GdkWindow* dragWindow = nullptr;
4368
4369 // find the top-level window
4370 if (mGdkWindow) {
4371 dragWindow = gdk_window_get_toplevel(mGdkWindow);
4372 MOZ_ASSERT(dragWindow, "gdk_window_get_toplevel should not return null")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(dragWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(dragWindow))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("dragWindow" " (" "gdk_window_get_toplevel should not return null"
")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 4372); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragWindow"
") (" "gdk_window_get_toplevel should not return null" ")");
do { *((volatile int*)__null) = 4372; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4373 }
4374
4375#ifdef MOZ_X111
4376 if (dragWindow && GdkIsX11Display()) {
4377 // Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=789054
4378 // To avoid crashes disable double-click on WM without _NET_WM_MOVERESIZE.
4379 // See _should_perform_ewmh_drag() at gdkwindow-x11.c
4380 GdkScreen* screen = gdk_window_get_screen(dragWindow);
4381 GdkAtom atom = gdk_atom_intern("_NET_WM_MOVERESIZE", FALSE(0));
4382 if (!gdk_x11_screen_supports_net_wm_hint(screen, atom)) {
4383 dragWindow = nullptr;
4384 }
4385 }
4386#endif
4387
4388 if (dragWindow) {
4389 gdk_window_begin_move_drag(dragWindow, 1, aEvent->x_root, aEvent->y_root,
4390 aEvent->time);
4391 return;
4392 }
4393 }
4394
4395 mWidgetCursorLocked = false;
4396 const auto refPoint = GetRefPoint(this, aEvent);
4397 if (auto edge = CheckResizerEdge(refPoint)) {
4398 nsCursor cursor = eCursor_none;
4399 switch (*edge) {
4400 case GDK_WINDOW_EDGE_SOUTH:
4401 case GDK_WINDOW_EDGE_NORTH:
4402 cursor = eCursor_ns_resize;
4403 break;
4404 case GDK_WINDOW_EDGE_WEST:
4405 case GDK_WINDOW_EDGE_EAST:
4406 cursor = eCursor_ew_resize;
4407 break;
4408 case GDK_WINDOW_EDGE_NORTH_WEST:
4409 case GDK_WINDOW_EDGE_SOUTH_EAST:
4410 cursor = eCursor_nwse_resize;
4411 break;
4412 case GDK_WINDOW_EDGE_NORTH_EAST:
4413 case GDK_WINDOW_EDGE_SOUTH_WEST:
4414 cursor = eCursor_nesw_resize;
4415 break;
4416 }
4417 SetCursor(Cursor{cursor});
4418 // If we set resize cursor on widget level keep it locked and prevent layout
4419 // to switch it back to default (by synthetic mouse events for instance)
4420 // until resize is finished. This affects PIP windows only.
4421 if (mIsPIPWindow) {
4422 mWidgetCursorLocked = true;
4423 }
4424 return;
4425 }
4426
4427 WidgetMouseEvent event(true, eMouseMove, this, WidgetMouseEvent::eReal);
4428
4429 gdouble pressure = 0;
4430 gdk_event_get_axis((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
4431 // Sometime gdk generate 0 pressure value between normal values
4432 // We have to ignore that and use last valid value
4433 if (pressure) {
4434 mLastMotionPressure = pressure;
4435 }
4436 event.mPressure = mLastMotionPressure;
4437 event.mRefPoint = refPoint;
4438 event.AssignEventTime(GetWidgetEventTime(aEvent->time));
4439
4440 KeymapWrapper::InitInputEvent(event, aEvent->state);
4441 InitPenEvent(event, (GdkEvent*)aEvent);
4442
4443 DispatchInputEvent(&event);
4444}
4445
4446// If the automatic pointer grab on ButtonPress has deactivated before
4447// ButtonRelease, and the mouse button is released while the pointer is not
4448// over any a Gecko window, then the ButtonRelease event will not be received.
4449// (A similar situation exists when the pointer is grabbed with owner_events
4450// True as the ButtonRelease may be received on a foreign [plugin] window).
4451// Use this method to check for released buttons when the pointer returns to a
4452// Gecko window.
4453void nsWindow::DispatchMissedButtonReleases(GdkEventCrossing* aGdkEvent) {
4454 guint changed = aGdkEvent->state ^ gButtonState;
4455 // Only consider button releases.
4456 // (Ignore button presses that occurred outside Gecko.)
4457 guint released = changed & gButtonState;
4458 gButtonState = aGdkEvent->state;
4459
4460 // Loop over each button, excluding mouse wheel buttons 4 and 5 for which
4461 // GDK ignores releases.
4462 for (guint buttonMask = GDK_BUTTON1_MASK; buttonMask <= GDK_BUTTON3_MASK;
4463 buttonMask <<= 1) {
4464 if (released & buttonMask) {
4465 int16_t buttonType;
4466 switch (buttonMask) {
4467 case GDK_BUTTON1_MASK:
4468 buttonType = MouseButton::ePrimary;
4469 break;
4470 case GDK_BUTTON2_MASK:
4471 buttonType = MouseButton::eMiddle;
4472 break;
4473 default:
4474 NS_ASSERTION(buttonMask == GDK_BUTTON3_MASK,do { if (!(buttonMask == GDK_BUTTON3_MASK)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected button mask", "buttonMask == GDK_BUTTON3_MASK",
"/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 4475); MOZ_PretendNoReturn(); } } while (0)
4475 "Unexpected button mask")do { if (!(buttonMask == GDK_BUTTON3_MASK)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Unexpected button mask", "buttonMask == GDK_BUTTON3_MASK",
"/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 4475); MOZ_PretendNoReturn(); } } while (0)
;
4476 buttonType = MouseButton::eSecondary;
4477 }
4478
4479 LOG("Synthesized button %u release", guint(buttonType + 1))do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "Synthesized button %u release", GetDebugTag
().get(), guint(buttonType + 1)); } } while (0)
;
4480
4481 // Dispatch a synthesized button up event to tell Gecko about the
4482 // change in state. This event is marked as synthesized so that
4483 // it is not dispatched as a DOM event, because we don't know the
4484 // position, widget, modifiers, or time/order.
4485 WidgetMouseEvent synthEvent(true, eMouseUp, this,
4486 WidgetMouseEvent::eSynthesized);
4487 synthEvent.mButton = buttonType;
4488 DispatchInputEvent(&synthEvent);
4489 }
4490 }
4491}
4492
4493void nsWindow::InitButtonEvent(WidgetMouseEvent& aEvent,
4494 GdkEventButton* aGdkEvent,
4495 const LayoutDeviceIntPoint& aRefPoint) {
4496 aEvent.mRefPoint = aRefPoint;
4497
4498 guint modifierState = aGdkEvent->state;
4499 // aEvent's state includes the button state from immediately before this
4500 // event. If aEvent is a mousedown or mouseup event, we need to update
4501 // the button state.
4502 guint buttonMask = 0;
4503 switch (aGdkEvent->button) {
4504 case 1:
4505 buttonMask = GDK_BUTTON1_MASK;
4506 break;
4507 case 2:
4508 buttonMask = GDK_BUTTON2_MASK;
4509 break;
4510 case 3:
4511 buttonMask = GDK_BUTTON3_MASK;
4512 break;
4513 }
4514 if (aGdkEvent->type == GDK_BUTTON_RELEASE) {
4515 modifierState &= ~buttonMask;
4516 } else {
4517 modifierState |= buttonMask;
4518 }
4519
4520 KeymapWrapper::InitInputEvent(aEvent, modifierState);
4521
4522 aEvent.AssignEventTime(GetWidgetEventTime(aGdkEvent->time));
4523
4524 switch (aGdkEvent->type) {
4525 case GDK_2BUTTON_PRESS:
4526 aEvent.mClickCount = 2;
4527 break;
4528 case GDK_3BUTTON_PRESS:
4529 aEvent.mClickCount = 3;
4530 break;
4531 // default is one click
4532 default:
4533 aEvent.mClickCount = 1;
4534 }
4535}
4536
4537static guint ButtonMaskFromGDKButton(guint button) {
4538 return GDK_BUTTON1_MASK << (button - 1);
4539}
4540
4541void nsWindow::DispatchContextMenuEventFromMouseEvent(
4542 uint16_t domButton, GdkEventButton* aEvent,
4543 const LayoutDeviceIntPoint& aRefPoint) {
4544 if (domButton == MouseButton::eSecondary && MOZ_LIKELY(!mIsDestroyed)(__builtin_expect(!!(!mIsDestroyed), 1))) {
4545 WidgetPointerEvent contextMenuEvent(true, eContextMenu, this);
4546 InitButtonEvent(contextMenuEvent, aEvent, aRefPoint);
4547 contextMenuEvent.mPressure = mLastMotionPressure;
4548 DispatchInputEvent(&contextMenuEvent);
4549 }
4550}
4551
4552void nsWindow::TryToShowNativeWindowMenu(GdkEventButton* aEvent) {
4553 if (!gdk_window_show_window_menu(GetToplevelGdkWindow(), (GdkEvent*)aEvent)) {
4554 NS_WARNING("Native context menu wasn't shown")NS_DebugBreak(NS_DEBUG_WARNING, "Native context menu wasn't shown"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 4554)
;
4555 }
4556}
4557
4558bool nsWindow::DoTitlebarAction(LookAndFeel::TitlebarEvent aEvent,
4559 GdkEventButton* aButtonEvent) {
4560 LOG("DoTitlebarAction %s click",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "DoTitlebarAction %s click", GetDebugTag
().get(), aEvent == LookAndFeel::TitlebarEvent::Double_Click ?
"double" : "middle"); } } while (0)
4561 aEvent == LookAndFeel::TitlebarEvent::Double_Click ? "double" : "middle")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "DoTitlebarAction %s click", GetDebugTag
().get(), aEvent == LookAndFeel::TitlebarEvent::Double_Click ?
"double" : "middle"); } } while (0)
;
4562 switch (LookAndFeel::GetTitlebarAction(aEvent)) {
4563 case LookAndFeel::TitlebarAction::WindowMenu:
4564 // Titlebar app menu
4565 LOG(" action menu")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " action menu", GetDebugTag().get(
)); } } while (0)
;
4566 TryToShowNativeWindowMenu(aButtonEvent);
4567 break;
4568 case LookAndFeel::TitlebarAction::WindowLower:
4569 LOG(" action lower")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " action lower", GetDebugTag().get
()); } } while (0)
;
4570 // Lower is part of gtk_surface1 protocol which we can't support
4571 // as Gtk keeps it private. So emulate it by minimize.
4572 if (GdkIsWaylandDisplay()) {
4573 SetSizeMode(nsSizeMode_Minimized);
4574 } else {
4575 gdk_window_lower(GetToplevelGdkWindow());
4576 }
4577 break;
4578 case LookAndFeel::TitlebarAction::WindowMinimize:
4579 LOG(" action minimize")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " action minimize", GetDebugTag().
get()); } } while (0)
;
4580 SetSizeMode(nsSizeMode_Minimized);
4581 break;
4582 case LookAndFeel::TitlebarAction::WindowMaximize:
4583 LOG(" action maximize")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " action maximize", GetDebugTag().
get()); } } while (0)
;
4584 SetSizeMode(nsSizeMode_Maximized);
4585 break;
4586 case LookAndFeel::TitlebarAction::WindowMaximizeToggle:
4587 LOG(" action toggle maximize")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " action toggle maximize", GetDebugTag
().get()); } } while (0)
;
4588 if (mSizeMode == nsSizeMode_Maximized) {
4589 SetSizeMode(nsSizeMode_Normal);
4590 } else if (mSizeMode == nsSizeMode_Normal) {
4591 SetSizeMode(nsSizeMode_Maximized);
4592 }
4593 break;
4594 case LookAndFeel::TitlebarAction::None:
4595 default:
4596 LOG(" action none")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " action none", GetDebugTag().get(
)); } } while (0)
;
4597 return false;
4598 }
4599 return true;
4600}
4601
4602void nsWindow::OnButtonPressEvent(GdkEventButton* aEvent) {
4603 LOG("Button %u press\n", aEvent->button)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "Button %u press\n", GetDebugTag().
get(), aEvent->button); } } while (0)
;
4604
4605 SetLastMousePressEvent((GdkEvent*)aEvent);
4606
4607 // If you double click in GDK, it will actually generate a second
4608 // GDK_BUTTON_PRESS before sending the GDK_2BUTTON_PRESS, and this is
4609 // different than the DOM spec. GDK puts this in the queue
4610 // programatically, so it's safe to assume that if there's a
4611 // double click in the queue, it was generated so we can just drop
4612 // this click.
4613 GUniquePtr<GdkEvent> peekedEvent(gdk_event_peek());
4614 if (peekedEvent) {
4615 GdkEventType type = peekedEvent->any.type;
4616 if (type == GDK_2BUTTON_PRESS || type == GDK_3BUTTON_PRESS) {
4617 return;
4618 }
4619 }
4620
4621 nsWindow* containerWindow = GetContainerWindow();
4622 if (!gFocusWindow && containerWindow) {
4623 containerWindow->DispatchActivateEvent();
4624 }
4625
4626 const auto refPoint = GetRefPoint(this, aEvent);
4627
4628 // check to see if we should rollup
4629 if (CheckForRollup(aEvent->x_root, aEvent->y_root, false, false)) {
4630 if (aEvent->button == 3 && mDraggableRegion.Contains(refPoint)) {
4631 GUniquePtr<GdkEvent> eventCopy;
4632 if (aEvent->type != GDK_BUTTON_PRESS) {
4633 // If the user double-clicks too fast we'll get a 2BUTTON_PRESS event
4634 // instead, and that isn't handled by open_window_menu, so coerce it
4635 // into a regular press.
4636 eventCopy.reset(gdk_event_copy((GdkEvent*)aEvent));
4637 eventCopy->type = GDK_BUTTON_PRESS;
4638 }
4639 TryToShowNativeWindowMenu(eventCopy ? &eventCopy->button : aEvent);
4640 }
4641 return;
4642 }
4643
4644 // Check to see if the event is within our window's resize region
4645 if (auto edge = CheckResizerEdge(refPoint)) {
4646 // On Wayland Gtk fails to vertically/horizontally resize windows
4647 // with fixed aspect ratio. We need to emulate
4648 // gdk_window_begin_resize_drag() at OnMotionNotifyEvent().
4649 if (mAspectRatio != 0.0f && GdkIsWaylandDisplay()) {
4650 mLastResizePoint = LayoutDeviceIntPoint::Floor(aEvent->x, aEvent->y);
4651 switch (*edge) {
4652 case GDK_WINDOW_EDGE_SOUTH:
4653 mAspectResizer = Some(GTK_ORIENTATION_VERTICAL);
4654 break;
4655 case GDK_WINDOW_EDGE_EAST:
4656 mAspectResizer = Some(GTK_ORIENTATION_HORIZONTAL);
4657 break;
4658 default:
4659 mAspectResizer.reset();
4660 break;
4661 }
4662 ApplySizeConstraints();
4663 }
4664 if (!mAspectResizer) {
4665 gdk_window_begin_resize_drag(GetToplevelGdkWindow(), *edge,
4666 aEvent->button, aEvent->x_root,
4667 aEvent->y_root, aEvent->time);
4668 }
4669 return;
4670 }
4671
4672 gdouble pressure = 0;
4673 gdk_event_get_axis((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
4674 mLastMotionPressure = pressure;
4675
4676 uint16_t domButton;
4677 switch (aEvent->button) {
4678 case 1:
4679 domButton = MouseButton::ePrimary;
4680 break;
4681 case 2:
4682 domButton = MouseButton::eMiddle;
4683 break;
4684 case 3:
4685 domButton = MouseButton::eSecondary;
4686 break;
4687 // These are mapped to horizontal scroll
4688 case 6:
4689 case 7:
4690 NS_WARNING("We're not supporting legacy horizontal scroll event")NS_DebugBreak(NS_DEBUG_WARNING, "We're not supporting legacy horizontal scroll event"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 4690)
;
4691 return;
4692 // Map buttons 8-9(10) to back/forward
4693 case 8:
4694 if (!Preferences::GetBool("mousebutton.4th.enabled", true)) {
4695 return;
4696 }
4697 DispatchCommandEvent(nsGkAtoms::Back);
4698 return;
4699 case 9:
4700 case 10:
4701 if (!Preferences::GetBool("mousebutton.5th.enabled", true)) {
4702 return;
4703 }
4704 DispatchCommandEvent(nsGkAtoms::Forward);
4705 return;
4706 default:
4707 return;
4708 }
4709
4710 gButtonState |= ButtonMaskFromGDKButton(aEvent->button);
4711
4712 WidgetMouseEvent event(true, eMouseDown, this, WidgetMouseEvent::eReal);
4713 event.mButton = domButton;
4714 InitButtonEvent(event, aEvent, refPoint);
4715 event.mPressure = mLastMotionPressure;
4716
4717 InitPenEvent(event, (GdkEvent*)aEvent);
4718 nsIWidget::ContentAndAPZEventStatus eventStatus = DispatchInputEvent(&event);
4719
4720 const bool defaultPrevented =
4721 eventStatus.mContentStatus == nsEventStatus_eConsumeNoDefault;
4722
4723 if (!defaultPrevented && mDraggableRegion.Contains(refPoint)) {
4724 if (domButton == MouseButton::ePrimary) {
4725 mWindowShouldStartDragging = true;
4726 } else if (domButton == MouseButton::eMiddle &&
4727 StaticPrefs::widget_gtk_titlebar_action_middle_click_enabled()) {
4728 DoTitlebarAction(nsXPLookAndFeel::TitlebarEvent::Middle_Click, aEvent);
4729 }
4730 }
4731
4732 // right menu click on linux should also pop up a context menu
4733 if (!StaticPrefs::ui_context_menus_after_mouseup() &&
4734 eventStatus.mApzStatus != nsEventStatus_eConsumeNoDefault) {
4735 DispatchContextMenuEventFromMouseEvent(domButton, aEvent, refPoint);
4736 }
4737}
4738
4739void nsWindow::OnButtonReleaseEvent(GdkEventButton* aEvent) {
4740 LOG("Button %u release\n", aEvent->button)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "Button %u release\n", GetDebugTag(
).get(), aEvent->button); } } while (0)
;
4741
4742 SetLastMousePressEvent(nullptr);
4743
4744 if (!mGdkWindow) {
4745 return;
4746 }
4747
4748 if (mAspectResizer) {
4749 mAspectResizer = Nothing();
4750 return;
4751 }
4752
4753 if (mWindowShouldStartDragging) {
4754 mWindowShouldStartDragging = false;
4755 }
4756
4757 uint16_t domButton;
4758 switch (aEvent->button) {
4759 case 1:
4760 domButton = MouseButton::ePrimary;
4761 break;
4762 case 2:
4763 domButton = MouseButton::eMiddle;
4764 break;
4765 case 3:
4766 domButton = MouseButton::eSecondary;
4767 break;
4768 default:
4769 return;
4770 }
4771
4772 gButtonState &= ~ButtonMaskFromGDKButton(aEvent->button);
4773
4774 const auto refPoint = GetRefPoint(this, aEvent);
4775
4776 WidgetMouseEvent event(true, eMouseUp, this, WidgetMouseEvent::eReal);
4777 event.mButton = domButton;
4778 InitButtonEvent(event, aEvent, refPoint);
4779 gdouble pressure = 0;
4780 gdk_event_get_axis((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
4781 event.mPressure = pressure ? (float)pressure : (float)mLastMotionPressure;
4782
4783 // The mRefPoint is manipulated in DispatchInputEvent, we're saving it
4784 // to use it for the doubleclick position check.
4785 const LayoutDeviceIntPoint pos = event.mRefPoint;
4786
4787 InitPenEvent(event, (GdkEvent*)aEvent);
4788
4789 nsIWidget::ContentAndAPZEventStatus eventStatus = DispatchInputEvent(&event);
4790
4791 const bool defaultPrevented =
4792 eventStatus.mContentStatus == nsEventStatus_eConsumeNoDefault;
4793 // Check if mouse position in titlebar and doubleclick happened to
4794 // trigger defined action.
4795 if (!defaultPrevented && mDrawInTitlebar &&
4796 event.mButton == MouseButton::ePrimary && event.mClickCount == 2 &&
4797 mDraggableRegion.Contains(pos)) {
4798 DoTitlebarAction(nsXPLookAndFeel::TitlebarEvent::Double_Click, aEvent);
4799 }
4800 mLastMotionPressure = pressure;
4801
4802 // right menu click on linux should also pop up a context menu
4803 if (StaticPrefs::ui_context_menus_after_mouseup() &&
4804 eventStatus.mApzStatus != nsEventStatus_eConsumeNoDefault) {
4805 DispatchContextMenuEventFromMouseEvent(domButton, aEvent, refPoint);
4806 }
4807
4808 // Open window manager menu on PIP window to allow user
4809 // to place it on top / all workspaces.
4810 if (mAlwaysOnTop && aEvent->button == 3) {
4811 TryToShowNativeWindowMenu(aEvent);
4812 }
4813}
4814
4815void nsWindow::OnContainerFocusInEvent(GdkEventFocus* aEvent) {
4816 LOG("OnContainerFocusInEvent")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "OnContainerFocusInEvent", GetDebugTag
().get()); } } while (0)
;
4817
4818 // Unset the urgency hint, if possible
4819 GtkWidget* top_window = GetToplevelWidget();
4820 if (top_window && (gtk_widget_get_visible(top_window))) {
4821 SetUrgencyHint(top_window, false);
4822 }
4823
4824 // Return if being called within SetFocus because the focus manager
4825 // already knows that the window is active.
4826 if (gBlockActivateEvent) {
4827 LOG("activated notification is blocked")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "activated notification is blocked"
, GetDebugTag().get()); } } while (0)
;
4828 return;
4829 }
4830
4831 // If keyboard input will be accepted, the focus manager will call
4832 // SetFocus to set the correct window.
4833 gFocusWindow = nullptr;
4834
4835 DispatchActivateEvent();
4836
4837 if (!gFocusWindow) {
4838 // We don't really have a window for dispatching key events, but
4839 // setting a non-nullptr value here prevents OnButtonPressEvent() from
4840 // dispatching an activation notification if the widget is already
4841 // active.
4842 gFocusWindow = this;
4843 }
4844
4845 LOG("Events sent from focus in event")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "Events sent from focus in event", GetDebugTag
().get()); } } while (0)
;
4846}
4847
4848void nsWindow::OnContainerFocusOutEvent(GdkEventFocus* aEvent) {
4849 LOG("OnContainerFocusOutEvent")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "OnContainerFocusOutEvent", GetDebugTag
().get()); } } while (0)
;
4850
4851 if (IsTopLevelWindowType()) {
4852 // Rollup menus when a window is focused out unless a drag is occurring.
4853 // This check is because drags grab the keyboard and cause a focus out on
4854 // versions of GTK before 2.18.
4855 const bool shouldRollupMenus = [&] {
4856 nsCOMPtr<nsIDragService> dragService =
4857 do_GetService("@mozilla.org/widget/dragservice;1");
4858 nsCOMPtr<nsIDragSession> dragSession =
4859 dragService->GetCurrentSession(this);
4860 if (!dragSession) {
4861 return true;
4862 }
4863 // We also roll up when a drag is from a different application
4864 nsCOMPtr<nsINode> sourceNode;
4865 dragSession->GetSourceNode(getter_AddRefs(sourceNode));
4866 return !sourceNode;
4867 }();
4868
4869 if (shouldRollupMenus) {
4870 RollupAllMenus();
4871 }
4872
4873 if (RefPtr pm = nsXULPopupManager::GetInstance()) {
4874 pm->RollupTooltips();
4875 }
4876 }
4877
4878 if (gFocusWindow) {
4879 RefPtr<nsWindow> kungFuDeathGrip = gFocusWindow;
4880 if (gFocusWindow->mIMContext) {
4881 gFocusWindow->mIMContext->OnBlurWindow(gFocusWindow);
4882 }
4883 gFocusWindow = nullptr;
4884 }
4885
4886 DispatchDeactivateEvent();
4887
4888 if (IsChromeWindowTitlebar()) {
4889 // DispatchDeactivateEvent() ultimately results in a call to
4890 // BrowsingContext::SetIsActiveBrowserWindow(), which resets
4891 // the state. We call UpdateMozWindowActive() to keep it in
4892 // sync with GDK_WINDOW_STATE_FOCUSED.
4893 UpdateMozWindowActive();
4894 }
4895
4896 LOG("Done with container focus out")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "Done with container focus out", GetDebugTag
().get()); } } while (0)
;
4897}
4898
4899bool nsWindow::DispatchCommandEvent(nsAtom* aCommand) {
4900 nsEventStatus status;
4901 WidgetCommandEvent appCommandEvent(true, aCommand, this);
4902 DispatchEvent(&appCommandEvent, status);
4903 return TRUE(!(0));
4904}
4905
4906bool nsWindow::DispatchContentCommandEvent(EventMessage aMsg) {
4907 nsEventStatus status;
4908 WidgetContentCommandEvent event(true, aMsg, this);
4909 DispatchEvent(&event, status);
4910 return TRUE(!(0));
4911}
4912
4913WidgetEventTime nsWindow::GetWidgetEventTime(guint32 aEventTime) {
4914 return WidgetEventTime(GetEventTimeStamp(aEventTime));
4915}
4916
4917TimeStamp nsWindow::GetEventTimeStamp(guint32 aEventTime) {
4918 if (MOZ_UNLIKELY(!mGdkWindow)(__builtin_expect(!!(!mGdkWindow), 0))) {
4919 // nsWindow has been Destroy()ed.
4920 return TimeStamp::Now();
4921 }
4922 if (aEventTime == 0) {
4923 // Some X11 and GDK events may be received with a time of 0 to indicate
4924 // that they are synthetic events. Some input method editors do this.
4925 // In this case too, just return the current timestamp.
4926 return TimeStamp::Now();
4927 }
4928
4929 TimeStamp eventTimeStamp;
4930
4931 if (GdkIsWaylandDisplay()) {
4932 // Wayland compositors use monotonic time to set timestamps.
4933 int64_t timestampTime = g_get_monotonic_time() / 1000;
4934 guint32 refTimeTruncated = guint32(timestampTime);
4935
4936 timestampTime -= refTimeTruncated - aEventTime;
4937 int64_t tick =
4938 BaseTimeDurationPlatformUtils::TicksFromMilliseconds(timestampTime);
4939 eventTimeStamp = TimeStamp::FromSystemTime(tick);
4940 } else {
4941#ifdef MOZ_X111
4942 CurrentX11TimeGetter* getCurrentTime = GetCurrentTimeGetter();
4943 MOZ_ASSERT(getCurrentTime,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(getCurrentTime)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(getCurrentTime))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("getCurrentTime"
" (" "Null current time getter despite having a window" ")",
"/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 4944); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getCurrentTime"
") (" "Null current time getter despite having a window" ")"
); do { *((volatile int*)__null) = 4944; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
4944 "Null current time getter despite having a window")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(getCurrentTime)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(getCurrentTime))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("getCurrentTime"
" (" "Null current time getter despite having a window" ")",
"/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 4944); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getCurrentTime"
") (" "Null current time getter despite having a window" ")"
); do { *((volatile int*)__null) = 4944; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4945 eventTimeStamp =
4946 TimeConverter().GetTimeStampFromSystemTime(aEventTime, *getCurrentTime);
4947#endif
4948 }
4949 return eventTimeStamp;
4950}
4951
4952#ifdef MOZ_X111
4953mozilla::CurrentX11TimeGetter* nsWindow::GetCurrentTimeGetter() {
4954 MOZ_ASSERT(mGdkWindow, "Expected mGdkWindow to be set")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mGdkWindow)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mGdkWindow))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mGdkWindow" " (" "Expected mGdkWindow to be set"
")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 4954); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGdkWindow"
") (" "Expected mGdkWindow to be set" ")"); do { *((volatile
int*)__null) = 4954; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
4955 if (MOZ_UNLIKELY(!mCurrentTimeGetter)(__builtin_expect(!!(!mCurrentTimeGetter), 0))) {
4956 mCurrentTimeGetter = MakeUnique<CurrentX11TimeGetter>(mGdkWindow);
4957 }
4958 return mCurrentTimeGetter.get();
4959}
4960#endif
4961
4962gboolean nsWindow::OnKeyPressEvent(GdkEventKey* aEvent) {
4963 LOG("OnKeyPressEvent")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "OnKeyPressEvent", GetDebugTag().get
()); } } while (0)
;
4964
4965 KeymapWrapper::HandleKeyPressEvent(this, aEvent);
4966 return TRUE(!(0));
4967}
4968
4969gboolean nsWindow::OnKeyReleaseEvent(GdkEventKey* aEvent) {
4970 LOG("OnKeyReleaseEvent")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "OnKeyReleaseEvent", GetDebugTag().
get()); } } while (0)
;
4971 if (NS_WARN_IF(!KeymapWrapper::HandleKeyReleaseEvent(this, aEvent))NS_warn_if_impl(!KeymapWrapper::HandleKeyReleaseEvent(this, aEvent
), "!KeymapWrapper::HandleKeyReleaseEvent(this, aEvent)", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 4971)
) {
4972 return FALSE(0);
4973 }
4974 return TRUE(!(0));
4975}
4976
4977void nsWindow::OnScrollEvent(GdkEventScroll* aEvent) {
4978 LOG("OnScrollEvent")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "OnScrollEvent", GetDebugTag().get(
)); } } while (0)
;
4979
4980 // check to see if we should rollup
4981 if (CheckForRollup(aEvent->x_root, aEvent->y_root, true, false)) {
4982 return;
4983 }
4984
4985 // check for duplicate legacy scroll event, see GNOME bug 726878
4986 if (aEvent->direction != GDK_SCROLL_SMOOTH &&
4987 mLastScrollEventTime == aEvent->time) {
4988 LOG("[%d] duplicate legacy scroll event %d\n", aEvent->time,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "[%d] duplicate legacy scroll event %d\n"
, GetDebugTag().get(), aEvent->time, aEvent->direction)
; } } while (0)
4989 aEvent->direction)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "[%d] duplicate legacy scroll event %d\n"
, GetDebugTag().get(), aEvent->time, aEvent->direction)
; } } while (0)
;
4990 return;
4991 }
4992 WidgetWheelEvent wheelEvent(true, eWheel, this);
4993 wheelEvent.mDeltaMode = dom::WheelEvent_Binding::DOM_DELTA_LINE;
4994 switch (aEvent->direction) {
4995 case GDK_SCROLL_SMOOTH: {
4996 // As of GTK 3.4, all directional scroll events are provided by
4997 // the GDK_SCROLL_SMOOTH direction on XInput2 and Wayland devices.
4998 mLastScrollEventTime = aEvent->time;
4999
5000 // Special handling for touchpads to support flings
5001 // (also known as kinetic/inertial/momentum scrolling)
5002 GdkDevice* device = gdk_event_get_source_device((GdkEvent*)aEvent);
5003 GdkInputSource source = gdk_device_get_source(device);
5004 if (source == GDK_SOURCE_TOUCHSCREEN || source == GDK_SOURCE_TOUCHPAD ||
5005 mCurrentSynthesizedTouchpadPan.mTouchpadGesturePhase.isSome()) {
5006 if (StaticPrefs::apz_gtk_pangesture_enabled() &&
5007 gtk_check_version(3, 20, 0) == nullptr) {
5008 static auto sGdkEventIsScrollStopEvent =
5009 (gboolean(*)(const GdkEvent*))dlsym(
5010 RTLD_DEFAULT((void *) 0), "gdk_event_is_scroll_stop_event");
5011
5012 LOG("[%d] pan smooth event dx=%f dy=%f inprogress=%d\n", aEvent->time,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "[%d] pan smooth event dx=%f dy=%f inprogress=%d\n"
, GetDebugTag().get(), aEvent->time, aEvent->delta_x, aEvent
->delta_y, mPanInProgress); } } while (0)
5013 aEvent->delta_x, aEvent->delta_y, mPanInProgress)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "[%d] pan smooth event dx=%f dy=%f inprogress=%d\n"
, GetDebugTag().get(), aEvent->time, aEvent->delta_x, aEvent
->delta_y, mPanInProgress); } } while (0)
;
5014 auto eventType = PanGestureInput::PANGESTURE_PAN;
5015 if (sGdkEventIsScrollStopEvent((GdkEvent*)aEvent)) {
5016 eventType = PanGestureInput::PANGESTURE_END;
5017 mPanInProgress = false;
5018 } else if (!mPanInProgress) {
5019 eventType = PanGestureInput::PANGESTURE_START;
5020 mPanInProgress = true;
5021 } else if (mCurrentSynthesizedTouchpadPan.mTouchpadGesturePhase
5022 .isSome()) {
5023 switch (*mCurrentSynthesizedTouchpadPan.mTouchpadGesturePhase) {
5024 case PHASE_BEGIN:
5025 // we should never hit this because we'll hit the above case
5026 // before this.
5027 MOZ_ASSERT_UNREACHABLE()do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 5027); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " ")"); do { *((volatile int*)__null
) = 5027; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
5028 eventType = PanGestureInput::PANGESTURE_START;
5029 mPanInProgress = true;
5030 break;
5031 case PHASE_UPDATE:
5032 // nothing to do here, eventtype should already be set
5033 MOZ_ASSERT(mPanInProgress)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mPanInProgress)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mPanInProgress))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mPanInProgress"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 5033); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPanInProgress"
")"); do { *((volatile int*)__null) = 5033; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5034 MOZ_ASSERT(eventType == PanGestureInput::PANGESTURE_PAN)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(eventType == PanGestureInput::PANGESTURE_PAN)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(eventType == PanGestureInput::PANGESTURE_PAN))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("eventType == PanGestureInput::PANGESTURE_PAN"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 5034); AnnotateMozCrashReason("MOZ_ASSERT" "(" "eventType == PanGestureInput::PANGESTURE_PAN"
")"); do { *((volatile int*)__null) = 5034; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5035 eventType = PanGestureInput::PANGESTURE_PAN;
5036 break;
5037 case PHASE_END:
5038 MOZ_ASSERT(mPanInProgress)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mPanInProgress)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mPanInProgress))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mPanInProgress"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 5038); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPanInProgress"
")"); do { *((volatile int*)__null) = 5038; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5039 eventType = PanGestureInput::PANGESTURE_END;
5040 mPanInProgress = false;
5041 break;
5042 default:
5043 MOZ_ASSERT_UNREACHABLE()do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 5043); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " ")"); do { *((volatile int*)__null
) = 5043; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
5044 break;
5045 }
5046 }
5047
5048 mCurrentSynthesizedTouchpadPan.mTouchpadGesturePhase.reset();
5049
5050 const bool isPageMode =
5051#ifdef NIGHTLY_BUILD1
5052 StaticPrefs::apz_gtk_pangesture_delta_mode() == 1;
5053#else
5054 StaticPrefs::apz_gtk_pangesture_delta_mode() != 2;
5055#endif
5056 const double multiplier =
5057 isPageMode
5058 ? StaticPrefs::apz_gtk_pangesture_page_delta_mode_multiplier()
5059 : StaticPrefs::
5060 apz_gtk_pangesture_pixel_delta_mode_multiplier() *
5061 FractionalScaleFactor();
5062
5063 ScreenPoint deltas(float(aEvent->delta_x * multiplier),
5064 float(aEvent->delta_y * multiplier));
5065
5066 LayoutDeviceIntPoint touchPoint = GetRefPoint(this, aEvent);
5067 PanGestureInput panEvent(
5068 eventType, GetEventTimeStamp(aEvent->time),
5069 ScreenPoint(touchPoint.x, touchPoint.y), deltas,
5070 KeymapWrapper::ComputeKeyModifiers(aEvent->state));
5071 panEvent.mDeltaType = isPageMode ? PanGestureInput::PANDELTA_PAGE
5072 : PanGestureInput::PANDELTA_PIXEL;
5073 panEvent.mSimulateMomentum =
5074 StaticPrefs::apz_gtk_kinetic_scroll_enabled();
5075
5076 DispatchPanGesture(panEvent);
5077
5078 if (mCurrentSynthesizedTouchpadPan.mSavedObserver != 0) {
5079 mozilla::widget::AutoObserverNotifier::NotifySavedObserver(
5080 mCurrentSynthesizedTouchpadPan.mSavedObserver,
5081 "touchpadpanevent");
5082 mCurrentSynthesizedTouchpadPan.mSavedObserver = 0;
5083 }
5084
5085 return;
5086 }
5087
5088 // Older GTK doesn't support stop events, so we can't support fling
5089 wheelEvent.mScrollType = WidgetWheelEvent::SCROLL_ASYNCHRONOUSLY;
5090 }
5091
5092 // TODO - use a more appropriate scrolling unit than lines.
5093 // Multiply event deltas by 3 to emulate legacy behaviour.
5094 wheelEvent.mDeltaX = aEvent->delta_x * 3;
5095 wheelEvent.mDeltaY = aEvent->delta_y * 3;
5096 wheelEvent.mWheelTicksX = aEvent->delta_x;
5097 wheelEvent.mWheelTicksY = aEvent->delta_y;
5098 wheelEvent.mIsNoLineOrPageDelta = true;
5099
5100 break;
5101 }
5102 case GDK_SCROLL_UP:
5103 wheelEvent.mDeltaY = wheelEvent.mLineOrPageDeltaY = -3;
5104 wheelEvent.mWheelTicksY = -1;
5105 break;
5106 case GDK_SCROLL_DOWN:
5107 wheelEvent.mDeltaY = wheelEvent.mLineOrPageDeltaY = 3;
5108 wheelEvent.mWheelTicksY = 1;
5109 break;
5110 case GDK_SCROLL_LEFT:
5111 wheelEvent.mDeltaX = wheelEvent.mLineOrPageDeltaX = -1;
5112 wheelEvent.mWheelTicksX = -1;
5113 break;
5114 case GDK_SCROLL_RIGHT:
5115 wheelEvent.mDeltaX = wheelEvent.mLineOrPageDeltaX = 1;
5116 wheelEvent.mWheelTicksX = 1;
5117 break;
5118 }
5119
5120 wheelEvent.mRefPoint = GetRefPoint(this, aEvent);
5121
5122 KeymapWrapper::InitInputEvent(wheelEvent, aEvent->state);
5123
5124 wheelEvent.AssignEventTime(GetWidgetEventTime(aEvent->time));
5125
5126 DispatchInputEvent(&wheelEvent);
5127}
5128
5129void nsWindow::DispatchPanGesture(PanGestureInput& aPanInput) {
5130 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 5130); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 5130; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5131
5132 if (mSwipeTracker) {
5133 // Give the swipe tracker a first pass at the event. If a new pan gesture
5134 // has been started since the beginning of the swipe, the swipe tracker
5135 // will know to ignore the event.
5136 nsEventStatus status = mSwipeTracker->ProcessEvent(aPanInput);
5137 if (status == nsEventStatus_eConsumeNoDefault) {
5138 return;
5139 }
5140 }
5141
5142 APZEventResult result;
5143 if (mAPZC) {
5144 MOZ_ASSERT(APZThreadUtils::IsControllerThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(APZThreadUtils::IsControllerThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(APZThreadUtils::IsControllerThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("APZThreadUtils::IsControllerThread()", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 5144); AnnotateMozCrashReason("MOZ_ASSERT" "(" "APZThreadUtils::IsControllerThread()"
")"); do { *((volatile int*)__null) = 5144; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5145
5146 result = mAPZC->InputBridge()->ReceiveInputEvent(aPanInput);
5147 if (result.GetStatus() == nsEventStatus_eConsumeNoDefault) {
5148 return;
5149 }
5150 }
5151
5152 WidgetWheelEvent event = aPanInput.ToWidgetEvent(this);
5153 if (!mAPZC) {
5154 if (MayStartSwipeForNonAPZ(aPanInput)) {
5155 return;
5156 }
5157 } else {
5158 event = MayStartSwipeForAPZ(aPanInput, result);
5159 }
5160
5161 ProcessUntransformedAPZEvent(&event, result);
5162}
5163
5164void nsWindow::OnVisibilityNotifyEvent(GdkVisibilityState aState) {
5165 LOG("nsWindow::OnVisibilityNotifyEvent [%p] state 0x%x\n", this, aState)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::OnVisibilityNotifyEvent [%p] state 0x%x\n"
, GetDebugTag().get(), this, aState); } } while (0)
;
5166 auto state = aState == GDK_VISIBILITY_FULLY_OBSCURED
5167 ? OcclusionState::OCCLUDED
5168 : OcclusionState::UNKNOWN;
5169 NotifyOcclusionState(state);
5170}
5171
5172void nsWindow::OnWindowStateEvent(GtkWidget* aWidget,
5173 GdkEventWindowState* aEvent) {
5174 LOG("nsWindow::OnWindowStateEvent for %p changed 0x%x new_window_state "do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::OnWindowStateEvent for %p changed 0x%x new_window_state "
"0x%x\n", GetDebugTag().get(), aWidget, aEvent->changed_mask
, aEvent->new_window_state); } } while (0)
5175 "0x%x\n",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::OnWindowStateEvent for %p changed 0x%x new_window_state "
"0x%x\n", GetDebugTag().get(), aWidget, aEvent->changed_mask
, aEvent->new_window_state); } } while (0)
5176 aWidget, aEvent->changed_mask, aEvent->new_window_state)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::OnWindowStateEvent for %p changed 0x%x new_window_state "
"0x%x\n", GetDebugTag().get(), aWidget, aEvent->changed_mask
, aEvent->new_window_state); } } while (0)
;
5177
5178 if (IS_MOZ_CONTAINER(aWidget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(aWidget)); GType __t = ((moz_container_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; }))))
) {
5179 // This event is notifying the container widget of changes to the
5180 // toplevel window. Just detect changes affecting whether windows are
5181 // viewable.
5182 //
5183 // (A visibility notify event is sent to each window that becomes
5184 // viewable when the toplevel is mapped, but we can't rely on that for
5185 // setting mHasMappedToplevel because these toplevel window state
5186 // events are asynchronous. The windows in the hierarchy now may not
5187 // be the same windows as when the toplevel was mapped, so they may
5188 // not get VisibilityNotify events.)
5189 bool mapped = !(aEvent->new_window_state &
5190 (GDK_WINDOW_STATE_ICONIFIED | GDK_WINDOW_STATE_WITHDRAWN));
5191 SetHasMappedToplevel(mapped);
5192 LOG("\tquick return because IS_MOZ_CONTAINER(aWidget) is true\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "\tquick return because IS_MOZ_CONTAINER(aWidget) is true\n"
, GetDebugTag().get()); } } while (0)
;
5193 return;
5194 }
5195 // else the widget is a shell widget.
5196
5197 // The block below is a bit evil.
5198 //
5199 // When a window is resized before it is shown, gtk_window_resize() delays
5200 // resizes until the window is shown. If gtk_window_state_event() sees a
5201 // GDK_WINDOW_STATE_MAXIMIZED change [1] before the window is shown, then
5202 // gtk_window_compute_configure_request_size() ignores the values from the
5203 // resize [2]. See bug 1449166 for an example of how this could happen.
5204 //
5205 // [1] https://gitlab.gnome.org/GNOME/gtk/blob/3.22.30/gtk/gtkwindow.c#L7967
5206 // [2] https://gitlab.gnome.org/GNOME/gtk/blob/3.22.30/gtk/gtkwindow.c#L9377
5207 //
5208 // In order to provide a sensible size for the window when the user exits
5209 // maximized state, we hide the GDK_WINDOW_STATE_MAXIMIZED change from
5210 // gtk_window_state_event() so as to trick GTK into using the values from
5211 // gtk_window_resize() in its configure request.
5212 //
5213 // We instead notify gtk_window_state_event() of the maximized state change
5214 // once the window is shown.
5215 //
5216 // See https://gitlab.gnome.org/GNOME/gtk/issues/1044
5217 //
5218 // This may be fixed in Gtk 3.24+ but it's still live and kicking
5219 // (Bug 1791779).
5220 if (!mIsShown) {
5221 aEvent->changed_mask = static_cast<GdkWindowState>(
5222 aEvent->changed_mask & ~GDK_WINDOW_STATE_MAXIMIZED);
5223 } else if (aEvent->changed_mask & GDK_WINDOW_STATE_WITHDRAWN &&
5224 aEvent->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
5225 aEvent->changed_mask = static_cast<GdkWindowState>(
5226 aEvent->changed_mask | GDK_WINDOW_STATE_MAXIMIZED);
5227 }
5228
5229 // This is a workaround for https://gitlab.gnome.org/GNOME/gtk/issues/1395
5230 // Gtk+ controls window active appearance by window-state-event signal.
5231 if (IsChromeWindowTitlebar() &&
5232 (aEvent->changed_mask & GDK_WINDOW_STATE_FOCUSED)) {
5233 // Emulate what Gtk+ does at gtk_window_state_event().
5234 // We can't check GTK_STATE_FLAG_BACKDROP directly as it's set by Gtk+
5235 // *after* this window-state-event handler.
5236 mTitlebarBackdropState =
5237 !(aEvent->new_window_state & GDK_WINDOW_STATE_FOCUSED);
5238
5239 // keep IsActiveBrowserWindow in sync with GDK_WINDOW_STATE_FOCUSED
5240 UpdateMozWindowActive();
5241
5242 ForceTitlebarRedraw();
5243 }
5244
5245 // We don't care about anything but changes in the maximized/icon/fullscreen
5246 // states but we need a workaround for bug in Wayland:
5247 // https://gitlab.gnome.org/GNOME/gtk/issues/67
5248 // Under wayland the gtk_window_iconify implementation does NOT synthetize
5249 // window_state_event where the GDK_WINDOW_STATE_ICONIFIED is set.
5250 // During restore we won't get aEvent->changed_mask with
5251 // the GDK_WINDOW_STATE_ICONIFIED so to detect that change we use the stored
5252 // mSizeMode and obtaining a focus.
5253 bool waylandWasIconified =
5254 (GdkIsWaylandDisplay() &&
5255 aEvent->changed_mask & GDK_WINDOW_STATE_FOCUSED &&
5256 aEvent->new_window_state & GDK_WINDOW_STATE_FOCUSED &&
5257 mSizeMode == nsSizeMode_Minimized);
5258 if (!waylandWasIconified &&
5259 (aEvent->changed_mask &
5260 (GDK_WINDOW_STATE_ICONIFIED | GDK_WINDOW_STATE_MAXIMIZED |
5261 GDK_WINDOW_STATE_TILED | GDK_WINDOW_STATE_FULLSCREEN)) == 0) {
5262 LOG("\tearly return because no interesting bits changed\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "\tearly return because no interesting bits changed\n"
, GetDebugTag().get()); } } while (0)
;
5263 return;
5264 }
5265
5266 auto oldSizeMode = mSizeMode;
5267 if (aEvent->new_window_state & GDK_WINDOW_STATE_ICONIFIED) {
5268 LOG("\tIconified\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "\tIconified\n", GetDebugTag().get(
)); } } while (0)
;
5269 mSizeMode = nsSizeMode_Minimized;
5270#ifdef ACCESSIBILITY1
5271 DispatchMinimizeEventAccessible();
5272#endif // ACCESSIBILITY
5273 } else if (aEvent->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) {
5274 LOG("\tFullscreen\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "\tFullscreen\n", GetDebugTag().get
()); } } while (0)
;
5275 mSizeMode = nsSizeMode_Fullscreen;
5276 } else if (aEvent->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
5277 LOG("\tMaximized\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "\tMaximized\n", GetDebugTag().get(
)); } } while (0)
;
5278 mSizeMode = nsSizeMode_Maximized;
5279#ifdef ACCESSIBILITY1
5280 DispatchMaximizeEventAccessible();
5281#endif // ACCESSIBILITY
5282 } else {
5283 LOG("\tNormal\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "\tNormal\n", GetDebugTag().get());
} } while (0)
;
5284 mSizeMode = nsSizeMode_Normal;
5285#ifdef ACCESSIBILITY1
5286 DispatchRestoreEventAccessible();
5287#endif // ACCESSIBILITY
5288 }
5289
5290 mIsTiled = aEvent->new_window_state & GDK_WINDOW_STATE_TILED;
5291 LOG("\tTiled: %d\n", int(mIsTiled))do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "\tTiled: %d\n", GetDebugTag().get(
), int(mIsTiled)); } } while (0)
;
5292
5293 if (mWidgetListener && mSizeMode != oldSizeMode) {
5294 mWidgetListener->SizeModeChanged(mSizeMode);
5295 }
5296}
5297
5298void nsWindow::OnDPIChanged() {
5299 // Update menu's font size etc.
5300 // This affects style / layout because it affects system font sizes.
5301 if (mWidgetListener) {
5302 if (PresShell* presShell = mWidgetListener->GetPresShell()) {
5303 presShell->BackingScaleFactorChanged();
5304 }
5305 }
5306 NotifyAPZOfDPIChange();
5307}
5308
5309void nsWindow::OnCheckResize() { mPendingConfigures++; }
5310
5311void nsWindow::OnCompositedChanged() {
5312 // Update CSD after the change in alpha visibility. This only affects
5313 // system metrics, not other theme shenanigans.
5314 NotifyThemeChanged(ThemeChangeKind::MediaQueriesOnly);
5315 mCompositedScreen = gdk_screen_is_composited(gdk_screen_get_default());
5316}
5317
5318void nsWindow::OnScaleChanged(bool aNotify) {
5319 if (!IsTopLevelWindowType()) {
5320 return;
5321 }
5322 if (!mGdkWindow) {
5323 return; // We'll get there again when we configure the window.
5324 }
5325 gint newCeiled = gdk_window_get_scale_factor(mGdkWindow);
5326 double newFractional = [&] {
5327#ifdef MOZ_WAYLAND1
5328 if (GdkIsWaylandDisplay()) {
5329 return moz_container_wayland_get_fractional_scale(mContainer);
5330 }
5331#endif
5332 return 0.0;
5333 }();
5334
5335 if (mCeiledScaleFactor == newCeiled &&
5336 mFractionalScaleFactor == newFractional) {
5337 return;
5338 }
5339
5340 NotifyAPZOfDPIChange();
5341
5342 LOG("OnScaleChanged %d, %f -> %d, %f Notify %d\n", int(mCeiledScaleFactor),do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "OnScaleChanged %d, %f -> %d, %f Notify %d\n"
, GetDebugTag().get(), int(mCeiledScaleFactor), mFractionalScaleFactor
, newCeiled, newFractional, aNotify); } } while (0)
5343 mFractionalScaleFactor, newCeiled, newFractional, aNotify)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "OnScaleChanged %d, %f -> %d, %f Notify %d\n"
, GetDebugTag().get(), int(mCeiledScaleFactor), mFractionalScaleFactor
, newCeiled, newFractional, aNotify); } } while (0)
;
5344
5345 mCeiledScaleFactor = newCeiled;
5346 mFractionalScaleFactor = newFractional;
5347
5348 if (!aNotify) {
5349 return;
5350 }
5351
5352 // We pause compositor to avoid rendering of obsoleted remote content which
5353 // produces flickering.
5354 // Re-enable compositor again when remote content is updated or timeout
5355 // happens.
5356 PauseCompositorFlickering();
5357
5358 GtkAllocation allocation;
5359 gtk_widget_get_allocation(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))), &allocation);
5360 LayoutDeviceIntSize size = GdkRectToDevicePixels(allocation).Size();
5361 mBounds.SizeTo(size);
5362 // Check mBounds size
5363 if (mCompositorSession &&
5364 !wr::WindowSizeSanityCheck(mBounds.width, mBounds.height)) {
5365 gfxCriticalNoteOncestatic mozilla::gfx::CriticalLog sOnceAtLine5365 = mozilla::gfx
::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions(false
))
<< "Invalid mBounds in OnScaleChanged " << mBounds;
5366 }
5367
5368 if (mWidgetListener) {
5369 if (PresShell* presShell = mWidgetListener->GetPresShell()) {
5370 presShell->BackingScaleFactorChanged();
5371 }
5372 }
5373
5374 DispatchResized();
5375
5376 if (mCompositorWidgetDelegate) {
5377 mCompositorWidgetDelegate->NotifyClientSizeChanged(GetClientSize());
5378 }
5379
5380 if (mCursor.IsCustom()) {
5381 mUpdateCursor = true;
5382 SetCursor(Cursor{mCursor});
5383 }
5384}
5385
5386void nsWindow::DispatchDragEvent(EventMessage aMsg,
5387 const LayoutDeviceIntPoint& aRefPoint,
5388 guint aTime) {
5389 LOGDRAG("nsWindow::DispatchDragEvent")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, "nsWindow::DispatchDragEvent"
); } } while (0)
;
5390 WidgetDragEvent event(true, aMsg, this);
5391
5392 InitDragEvent(event);
5393
5394 event.mRefPoint = aRefPoint;
5395 event.AssignEventTime(GetWidgetEventTime(aTime));
5396
5397 DispatchInputEvent(&event);
5398}
5399
5400void nsWindow::OnDragDataReceivedEvent(GtkWidget* aWidget,
5401 GdkDragContext* aDragContext, gint aX,
5402 gint aY,
5403 GtkSelectionData* aSelectionData,
5404 guint aInfo, guint aTime,
5405 gpointer aData) {
5406 LOGDRAG("nsWindow::OnDragDataReceived")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, "nsWindow::OnDragDataReceived"
); } } while (0)
;
5407
5408 RefPtr<nsDragService> dragService = nsDragService::GetInstance();
5409 nsDragSession* dragSession =
5410 static_cast<nsDragSession*>(dragService->GetCurrentSession(this));
5411 if (dragSession) {
5412 nsDragSession::AutoEventLoop loop(dragSession);
5413 dragSession->TargetDataReceived(aWidget, aDragContext, aX, aY,
5414 aSelectionData, aInfo, aTime);
5415 }
5416}
5417
5418nsWindow* nsWindow::GetTransientForWindowIfPopup() {
5419 if (mWindowType != WindowType::Popup) {
5420 return nullptr;
5421 }
5422 GtkWindow* toplevel = gtk_window_get_transient_for(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
5423 if (toplevel) {
5424 return get_window_for_gtk_widget(GTK_WIDGET(toplevel)((((GtkWidget*) (void *) ((toplevel))))));
5425 }
5426 return nullptr;
5427}
5428
5429bool nsWindow::IsHandlingTouchSequence(GdkEventSequence* aSequence) {
5430 return mHandleTouchEvent && mTouches.Contains(aSequence);
5431}
5432
5433gboolean nsWindow::OnTouchpadPinchEvent(GdkEventTouchpadPinch* aEvent) {
5434 if (!StaticPrefs::apz_gtk_touchpad_pinch_enabled()) {
5435 return TRUE(!(0));
5436 }
5437 // Do not respond to pinch gestures involving more than two fingers
5438 // unless specifically preffed on. These are sometimes hooked up to other
5439 // actions at the desktop environment level and having the browser also
5440 // pinch can be undesirable.
5441 if (aEvent->n_fingers > 2 &&
5442 !StaticPrefs::apz_gtk_touchpad_pinch_three_fingers_enabled()) {
5443 return FALSE(0);
5444 }
5445 auto pinchGestureType = PinchGestureInput::PINCHGESTURE_SCALE;
5446 ScreenCoord currentSpan;
5447 ScreenCoord previousSpan;
5448
5449 switch (aEvent->phase) {
5450 case GDK_TOUCHPAD_GESTURE_PHASE_BEGIN:
5451 pinchGestureType = PinchGestureInput::PINCHGESTURE_START;
5452 currentSpan = aEvent->scale;
5453 mCurrentTouchpadFocus = ViewAs<ScreenPixel>(
5454 GetRefPoint(this, aEvent),
5455 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
5456
5457 // Assign PreviousSpan --> 0.999 to make mDeltaY field of the
5458 // WidgetWheelEvent that this PinchGestureInput event will be converted
5459 // to not equal Zero as our discussion because we observed that the
5460 // scale of the PHASE_BEGIN event is 1.
5461 previousSpan = 0.999;
5462 break;
5463
5464 case GDK_TOUCHPAD_GESTURE_PHASE_UPDATE:
5465 pinchGestureType = PinchGestureInput::PINCHGESTURE_SCALE;
5466 mCurrentTouchpadFocus += ScreenPoint(aEvent->dx, aEvent->dy);
5467 if (aEvent->scale == mLastPinchEventSpan) {
5468 return FALSE(0);
5469 }
5470 currentSpan = aEvent->scale;
5471 previousSpan = mLastPinchEventSpan;
5472 break;
5473
5474 case GDK_TOUCHPAD_GESTURE_PHASE_END:
5475 pinchGestureType = PinchGestureInput::PINCHGESTURE_END;
5476 currentSpan = aEvent->scale;
5477 previousSpan = mLastPinchEventSpan;
5478 break;
5479
5480 default:
5481 return FALSE(0);
5482 }
5483
5484 PinchGestureInput event(
5485 pinchGestureType, PinchGestureInput::TRACKPAD,
5486 GetEventTimeStamp(aEvent->time), ExternalPoint(0, 0),
5487 mCurrentTouchpadFocus,
5488 100.0 * ((aEvent->phase == GDK_TOUCHPAD_GESTURE_PHASE_END)
5489 ? ScreenCoord(1.f)
5490 : currentSpan),
5491 100.0 * ((aEvent->phase == GDK_TOUCHPAD_GESTURE_PHASE_END)
5492 ? ScreenCoord(1.f)
5493 : previousSpan),
5494 KeymapWrapper::ComputeKeyModifiers(aEvent->state));
5495
5496 if (!event.SetLineOrPageDeltaY(this)) {
5497 return FALSE(0);
5498 }
5499
5500 mLastPinchEventSpan = aEvent->scale;
5501 DispatchPinchGestureInput(event);
5502 return TRUE(!(0));
5503}
5504
5505void nsWindow::OnTouchpadHoldEvent(GdkTouchpadGesturePhase aPhase, guint aTime,
5506 uint32_t aFingers) {
5507 LOG("OnTouchpadHoldEvent: aPhase %d aFingers %d", aPhase, aFingers)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "OnTouchpadHoldEvent: aPhase %d aFingers %d"
, GetDebugTag().get(), aPhase, aFingers); } } while (0)
;
5508}
5509
5510gboolean nsWindow::OnTouchEvent(GdkEventTouch* aEvent) {
5511 LOG("OnTouchEvent: x=%f y=%f type=%d\n", aEvent->x, aEvent->y, aEvent->type)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "OnTouchEvent: x=%f y=%f type=%d\n"
, GetDebugTag().get(), aEvent->x, aEvent->y, aEvent->
type); } } while (0)
;
5512 if (!mHandleTouchEvent) {
5513 // If a popup window was spawned (e.g. as the result of a long-press)
5514 // and touch events got diverted to that window within a touch sequence,
5515 // ensure the touch event gets sent to the original window instead. We
5516 // keep the checks here very conservative so that we only redirect
5517 // events in this specific scenario.
5518 nsWindow* targetWindow = GetTransientForWindowIfPopup();
5519 if (targetWindow &&
5520 targetWindow->IsHandlingTouchSequence(aEvent->sequence)) {
5521 return targetWindow->OnTouchEvent(aEvent);
5522 }
5523
5524 return FALSE(0);
5525 }
5526
5527 EventMessage msg;
5528 switch (aEvent->type) {
5529 case GDK_TOUCH_BEGIN:
5530 // check to see if we should rollup
5531 if (CheckForRollup(aEvent->x_root, aEvent->y_root, false, false)) {
5532 return FALSE(0);
5533 }
5534 msg = eTouchStart;
5535 break;
5536 case GDK_TOUCH_UPDATE:
5537 msg = eTouchMove;
5538 // Start dragging when motion events happens in the dragging area
5539 if (mWindowShouldStartDragging) {
5540 mWindowShouldStartDragging = false;
5541 if (mGdkWindow) {
5542 GdkWindow* gdk_window = gdk_window_get_toplevel(mGdkWindow);
5543 MOZ_ASSERT(gdk_window,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gdk_window)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(gdk_window))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("gdk_window" " (" "gdk_window_get_toplevel should not return null"
")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 5544); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gdk_window"
") (" "gdk_window_get_toplevel should not return null" ")");
do { *((volatile int*)__null) = 5544; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5544 "gdk_window_get_toplevel should not return null")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gdk_window)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(gdk_window))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("gdk_window" " (" "gdk_window_get_toplevel should not return null"
")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 5544); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gdk_window"
") (" "gdk_window_get_toplevel should not return null" ")");
do { *((volatile int*)__null) = 5544; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5545
5546 LOG(" start window dragging window\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " start window dragging window\n",
GetDebugTag().get()); } } while (0)
;
5547 gdk_window_begin_move_drag(gdk_window, 1, aEvent->x_root,
5548 aEvent->y_root, aEvent->time);
5549
5550 // Cancel the event sequence. gdk will steal all subsequent events
5551 // (including TOUCH_END).
5552 msg = eTouchCancel;
5553 }
5554 }
5555 break;
5556 case GDK_TOUCH_END:
5557 msg = eTouchEnd;
5558 if (mWindowShouldStartDragging) {
5559 LOG(" end of window dragging window\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " end of window dragging window\n"
, GetDebugTag().get()); } } while (0)
;
5560 mWindowShouldStartDragging = false;
5561 }
5562 break;
5563 case GDK_TOUCH_CANCEL:
5564 msg = eTouchCancel;
5565 break;
5566 default:
5567 return FALSE(0);
5568 }
5569
5570 const LayoutDeviceIntPoint touchPoint = GetRefPoint(this, aEvent);
5571
5572 int32_t id;
5573 RefPtr<dom::Touch> touch;
5574 if (mTouches.Remove(aEvent->sequence, getter_AddRefs(touch))) {
5575 id = touch->mIdentifier;
5576 } else {
5577 id = ++gLastTouchID & 0x7FFFFFFF;
5578 }
5579
5580 touch =
5581 new dom::Touch(id, touchPoint, LayoutDeviceIntPoint(1, 1), 0.0f, 0.0f);
5582
5583 WidgetTouchEvent event(true, msg, this);
5584 KeymapWrapper::InitInputEvent(event, aEvent->state);
5585
5586 if (msg == eTouchStart || msg == eTouchMove) {
5587 mTouches.InsertOrUpdate(aEvent->sequence, std::move(touch));
5588 // add all touch points to event object
5589 for (const auto& data : mTouches.Values()) {
5590 event.mTouches.AppendElement(new dom::Touch(*data));
5591 }
5592 } else if (msg == eTouchEnd || msg == eTouchCancel) {
5593 *event.mTouches.AppendElement() = std::move(touch);
5594 }
5595
5596 nsIWidget::ContentAndAPZEventStatus eventStatus = DispatchInputEvent(&event);
5597
5598 // There's a chance that we are in drag area and the event is not consumed
5599 // by something on it.
5600 if (msg == eTouchStart && mDraggableRegion.Contains(touchPoint) &&
5601 eventStatus.mApzStatus != nsEventStatus_eConsumeNoDefault) {
5602 mWindowShouldStartDragging = true;
5603 }
5604 return TRUE(!(0));
5605}
5606
5607// Return true if toplevel window is transparent.
5608// It's transparent when we're running on composited screens
5609// and we can draw main window without system titlebar.
5610bool nsWindow::IsToplevelWindowTransparent() {
5611 static bool transparencyConfigured = false;
5612
5613 if (!transparencyConfigured) {
5614 if (gdk_screen_is_composited(gdk_screen_get_default())) {
5615 // Some Gtk+ themes use non-rectangular toplevel windows. To fully
5616 // support such themes we need to make toplevel window transparent
5617 // with ARGB visual.
5618 // It may cause performanance issue so make it configurable
5619 // and enable it by default for selected window managers.
5620 if (Preferences::HasUserValue("mozilla.widget.use-argb-visuals")) {
5621 // argb visual is explicitly required so use it
5622 sTransparentMainWindow =
5623 Preferences::GetBool("mozilla.widget.use-argb-visuals");
5624 } else {
5625 // Enable transparent toplevel window if we can draw main window
5626 // without system titlebar as Gtk+ themes use titlebar round corners.
5627 sTransparentMainWindow =
5628 GetSystemGtkWindowDecoration() != GTK_DECORATION_NONE;
5629 }
5630 }
5631 transparencyConfigured = true;
5632 }
5633
5634 return sTransparentMainWindow;
5635}
5636
5637#ifdef MOZ_X111
5638// Configure GL visual on X11.
5639bool nsWindow::ConfigureX11GLVisual() {
5640 auto* screen = gtk_widget_get_screen(mShell);
5641 int visualId = 0;
5642 bool haveVisual = false;
5643
5644 if (gfxVars::UseEGL()) {
5645 haveVisual = GLContextEGL::FindVisual(&visualId);
5646 }
5647
5648 // We are on GLX or use it as a fallback on Mesa, see
5649 // https://gitlab.freedesktop.org/mesa/mesa/-/issues/149
5650 if (!haveVisual) {
5651 auto* display = GDK_DISPLAY_XDISPLAY(gtk_widget_get_display(mShell))(gdk_x11_display_get_xdisplay (gtk_widget_get_display(mShell)
))
;
5652 int screenNumber = GDK_SCREEN_XNUMBER(screen)(gdk_x11_screen_get_screen_number (screen));
5653 haveVisual = GLContextGLX::FindVisual(display, screenNumber, &visualId);
5654 }
5655
5656 GdkVisual* gdkVisual = nullptr;
5657 if (haveVisual) {
5658 // If we're using CSD, rendering will go through mContainer, but
5659 // it will inherit this visual as it is a child of mShell.
5660 gdkVisual = gdk_x11_screen_lookup_visual(screen, visualId);
5661 }
5662 if (!gdkVisual) {
5663 NS_WARNING("We're missing X11 Visual!")NS_DebugBreak(NS_DEBUG_WARNING, "We're missing X11 Visual!", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 5663)
;
5664 // We try to use a fallback alpha visual
5665 GdkScreen* screen = gtk_widget_get_screen(mShell);
5666 gdkVisual = gdk_screen_get_rgba_visual(screen);
5667 }
5668 if (gdkVisual) {
5669 gtk_widget_set_visual(mShell, gdkVisual);
5670 mHasAlphaVisual = true;
5671 return true;
5672 }
5673
5674 return false;
5675}
5676#endif
5677
5678nsAutoCString nsWindow::GetFrameTag() const {
5679 if (nsIFrame* frame = GetFrame()) {
5680#ifdef DEBUG_FRAME_DUMP1
5681 return frame->ListTag();
5682#else
5683 nsAutoCString buf;
5684 buf.AppendPrintf("Frame(%p)", frame);
5685 if (nsIContent* content = frame->GetContent()) {
5686 buf.Append(' ');
5687 AppendUTF16toUTF8(content->NodeName(), buf);
5688 }
5689 return buf;
5690#endif
5691 }
5692 return nsAutoCString("(no frame)");
5693}
5694
5695nsCString nsWindow::GetPopupTypeName() {
5696 switch (mPopupType) {
5697 case PopupType::Menu:
5698 return nsCString("Menu");
5699 case PopupType::Tooltip:
5700 return nsCString("Tooltip");
5701 case PopupType::Panel:
5702 return nsCString("Panel/Utility");
5703 default:
5704 return nsCString("Unknown");
5705 }
5706}
5707
5708// Disables all rendering of GtkWidget from Gtk side.
5709// We do our best to persuade Gtk/Gdk to ignore all painting
5710// to the widget.
5711static void GtkWidgetDisableUpdates(GtkWidget* aWidget) {
5712 // Clear exposure mask - it disabled synthesized events.
5713 GdkWindow* window = gtk_widget_get_window(aWidget);
5714 if (!window) {
5715 return;
5716 }
5717 gdk_window_set_events(window, (GdkEventMask)(gdk_window_get_events(window) &
5718 (~GDK_EXPOSURE_MASK)));
5719
5720 // Remove before/after paint handles from frame clock.
5721 // It disables widget content updates.
5722 GdkFrameClock* frame_clock = gdk_window_get_frame_clock(window);
5723 g_signal_handlers_disconnect_by_data(frame_clock, window)g_signal_handlers_disconnect_matched ((frame_clock), G_SIGNAL_MATCH_DATA
, 0, 0, __null, __null, (window))
;
5724}
5725
5726Window nsWindow::GetX11Window() {
5727#ifdef MOZ_X111
5728 if (GdkIsX11Display()) {
5729 return mGdkWindow ? gdk_x11_window_get_xid(mGdkWindow) : X11None0L;
5730 }
5731#endif
5732 return (Window) nullptr;
5733}
5734
5735void nsWindow::EnsureGdkWindow() {
5736 MOZ_DIAGNOSTIC_ASSERT(mIsMapped)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIsMapped)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mIsMapped))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mIsMapped", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 5736); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mIsMapped"
")"); do { *((volatile int*)__null) = 5736; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5737 if (!mGdkWindow) {
5738 mGdkWindow = gtk_widget_get_window(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))));
5739 g_object_set_data(G_OBJECT(mGdkWindow)((((GObject*) (void *) ((mGdkWindow))))), "nsWindow", this);
5740 }
5741}
5742
5743void nsWindow::ConfigureCompositor() {
5744 MOZ_DIAGNOSTIC_ASSERT(mIsMapped)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIsMapped)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mIsMapped))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mIsMapped", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 5744); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mIsMapped"
")"); do { *((volatile int*)__null) = 5744; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5745 MOZ_DIAGNOSTIC_ASSERT(mCompositorState == COMPOSITOR_ENABLED)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCompositorState == COMPOSITOR_ENABLED)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mCompositorState == COMPOSITOR_ENABLED))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mCompositorState == COMPOSITOR_ENABLED"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 5745); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mCompositorState == COMPOSITOR_ENABLED"
")"); do { *((volatile int*)__null) = 5745; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5746
5747 LOG("nsWindow::ConfigureCompositor()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::ConfigureCompositor()", GetDebugTag
().get()); } } while (0)
;
5748 auto startCompositing = [self = RefPtr{this}, this]() -> void {
5749 LOG(" moz_container_wayland_add_or_fire_initial_draw_callback "do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " moz_container_wayland_add_or_fire_initial_draw_callback "
"ConfigureCompositor", GetDebugTag().get()); } } while (0)
5750 "ConfigureCompositor")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " moz_container_wayland_add_or_fire_initial_draw_callback "
"ConfigureCompositor", GetDebugTag().get()); } } while (0)
;
5751
5752 // too late
5753 if (mIsDestroyed || !mIsMapped) {
5754 LOG(" quit, mIsDestroyed = %d mIsMapped = %d", !!mIsDestroyed,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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, mIsDestroyed = %d mIsMapped = %d"
, GetDebugTag().get(), !!mIsDestroyed, !!mIsMapped); } } while
(0)
5755 !!mIsMapped)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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, mIsDestroyed = %d mIsMapped = %d"
, GetDebugTag().get(), !!mIsDestroyed, !!mIsMapped); } } while
(0)
;
5756 return;
5757 }
5758 // Compositor will be resumed later by ResumeCompositorFlickering().
5759 if (mCompositorState == COMPOSITOR_PAUSED_FLICKERING) {
5760 LOG(" quit, will be resumed by ResumeCompositorFlickering.")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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, will be resumed by ResumeCompositorFlickering."
, GetDebugTag().get()); } } while (0)
;
5761 return;
5762 }
5763 // Compositor will be resumed at nsWindow::SetCompositorWidgetDelegate().
5764 if (!mCompositorWidgetDelegate) {
5765 LOG(" quit, missing mCompositorWidgetDelegate")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 mCompositorWidgetDelegate"
, GetDebugTag().get()); } } while (0)
;
5766 return;
5767 }
5768
5769 ResumeCompositorImpl();
5770 };
5771
5772 if (GdkIsWaylandDisplay()) {
5773#ifdef MOZ_WAYLAND1
5774 moz_container_wayland_add_or_fire_initial_draw_callback(mContainer,
5775 startCompositing);
5776#endif
5777 } else {
5778 startCompositing();
5779 }
5780}
5781
5782nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
5783 const LayoutDeviceIntRect& aRect,
5784 widget::InitData* aInitData) {
5785 LOG("nsWindow::Create\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::Create\n", GetDebugTag()
.get()); } } while (0)
;
5786
5787 // only set the base parent if we're going to be a dialog or a
5788 // toplevel
5789 nsIWidget* baseParent =
5790 aInitData && (aInitData->mWindowType == WindowType::Dialog ||
5791 aInitData->mWindowType == WindowType::TopLevel ||
5792 aInitData->mWindowType == WindowType::Invisible)
5793 ? nullptr
5794 : aParent;
5795
5796#ifdef ACCESSIBILITY1
5797 // Send a DBus message to check whether a11y is enabled
5798 a11y::PreInit();
5799#endif
5800
5801#ifdef MOZ_WAYLAND1
5802 // Ensure that KeymapWrapper is created on Wayland as we need it for
5803 // keyboard focus tracking.
5804 if (GdkIsWaylandDisplay()) {
5805 KeymapWrapper::EnsureInstance();
5806 }
5807#endif
5808
5809 // Ensure that the toolkit is created.
5810 nsGTKToolkit::GetToolkit();
5811
5812 // initialize all the common bits of this class
5813 BaseCreate(baseParent, aInitData);
5814
5815 // and do our common creation
5816 mParent = aParent;
5817 // save our bounds
5818 mBounds = aRect;
5819 LOG(" mBounds: x:%d y:%d w:%d h:%d\n", mBounds.x, mBounds.y, mBounds.width,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " mBounds: x:%d y:%d w:%d h:%d\n",
GetDebugTag().get(), mBounds.x, mBounds.y, mBounds.width, mBounds
.height); } } while (0)
5820 mBounds.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " mBounds: x:%d y:%d w:%d h:%d\n",
GetDebugTag().get(), mBounds.x, mBounds.y, mBounds.width, mBounds
.height); } } while (0)
;
5821
5822 ConstrainSize(&mBounds.width, &mBounds.height);
5823 mLastSizeRequest = mBounds.Size();
5824
5825 bool popupNeedsAlphaVisual = mWindowType == WindowType::Popup &&
5826 (aInitData && aInitData->mTransparencyMode ==
5827 TransparencyMode::Transparent);
5828
5829 // Figure out our parent window - only used for WindowType::Child
5830 nsWindow* parentnsWindow = nullptr;
5831
5832 if (aParent) {
5833 parentnsWindow = static_cast<nsWindow*>(aParent);
5834 } else if (aNativeParent && GDK_IS_WINDOW(aNativeParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(aNativeParent)); GType __t = ((gdk_window_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; }))))
) {
5835 parentnsWindow = get_window_for_gdk_window(GDK_WINDOW(aNativeParent)((((GdkWindow*) (void *) ((aNativeParent))))));
5836 if (!parentnsWindow) {
5837 return NS_ERROR_FAILURE;
5838 }
5839 }
5840
5841 if (mWindowType == WindowType::Child) {
5842 // We don't support WindowType::Child directly but emulate it by popup
5843 // windows.
5844 mWindowType = WindowType::Popup;
5845 if (!parentnsWindow) {
5846 if (aNativeParent && GTK_IS_CONTAINER(aNativeParent)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(aNativeParent)); GType __t = ((gtk_container_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; }))))
) {
5847 parentnsWindow = get_window_for_gtk_widget(GTK_WIDGET(aNativeParent)((((GtkWidget*) (void *) ((aNativeParent))))));
5848 }
5849 }
5850 mIsChildWindow = true;
5851 LOG(" child widget, switch to popup. parent nsWindow %p", parentnsWindow)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " child widget, switch to popup. parent nsWindow %p"
, GetDebugTag().get(), parentnsWindow); } } while (0)
;
5852 }
5853
5854 MOZ_ASSERT_IF(mWindowType == WindowType::Popup, parentnsWindow)do { if (mWindowType == WindowType::Popup) { do { static_assert
( mozilla::detail::AssertionConditionType<decltype(parentnsWindow
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(parentnsWindow))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("parentnsWindow", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 5854); AnnotateMozCrashReason("MOZ_ASSERT" "(" "parentnsWindow"
")"); do { *((volatile int*)__null) = 5854; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
5855
5856 if (mWindowType != WindowType::Dialog && mWindowType != WindowType::Popup &&
5857 mWindowType != WindowType::TopLevel &&
5858 mWindowType != WindowType::Invisible) {
5859 MOZ_ASSERT_UNREACHABLE("Unexpected eWindowType")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Unexpected eWindowType" ")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 5859); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected eWindowType" ")"); do
{ *((volatile int*)__null) = 5859; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
5860 return NS_ERROR_FAILURE;
5861 }
5862
5863 mAlwaysOnTop = aInitData && aInitData->mAlwaysOnTop;
5864 // mNoAutoHide seems to be always false here.
5865 // The mNoAutoHide state is set later on nsMenuPopupFrame level
5866 // and can be changed so we use WaylandPopupIsPermanent() to get
5867 // recent popup config (Bug 1728952).
5868 mNoAutoHide = aInitData && aInitData->mNoAutoHide;
5869 mIsAlert = aInitData && aInitData->mIsAlert;
5870
5871 // Popups that are not noautohide are only temporary. The are used
5872 // for menus and the like and disappear when another window is used.
5873 // For most popups, use the standard GtkWindowType GTK_WINDOW_POPUP,
5874 // which will use a Window with the override-redirect attribute
5875 // (for temporary windows).
5876 // For long-lived windows, their stacking order is managed by the
5877 // window manager, as indicated by GTK_WINDOW_TOPLEVEL.
5878 // For Wayland we have to always use GTK_WINDOW_POPUP to control
5879 // popup window position.
5880 GtkWindowType type = GTK_WINDOW_TOPLEVEL;
5881 if (mWindowType == WindowType::Popup) {
5882 MOZ_ASSERT(aInitData)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aInitData)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aInitData))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aInitData", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 5882); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aInitData" ")"
); do { *((volatile int*)__null) = 5882; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5883 type = GTK_WINDOW_POPUP;
5884 if (GdkIsX11Display() && mNoAutoHide) {
5885 type = GTK_WINDOW_TOPLEVEL;
5886 }
5887 }
5888 mShell = gtk_window_new(type);
5889
5890 // It is important that this happens before the realize() call below, so that
5891 // we don't get bogus CSD margins on Wayland, see bug 1794577.
5892 mUndecorated = IsAlwaysUndecoratedWindow();
5893 if (mUndecorated) {
5894 LOG(" Is undecorated Window\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 undecorated Window\n", GetDebugTag
().get()); } } while (0)
;
5895 gtk_window_set_titlebar(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), gtk_fixed_new());
5896 gtk_window_set_decorated(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), false);
5897 }
5898
5899 // Ensure gfxPlatform is initialized, since that is what initializes
5900 // gfxVars, used below.
5901 Unused << gfxPlatform::GetPlatform();
5902
5903 if (IsTopLevelWindowType()) {
5904 mGtkWindowDecoration = GetSystemGtkWindowDecoration();
5905 // Inherit initial scale from our parent, or use the default monitor scale
5906 // otherwise.
5907 mCeiledScaleFactor = parentnsWindow
5908 ? int32_t(parentnsWindow->mCeiledScaleFactor)
5909 : ScreenHelperGTK::GetGTKMonitorScaleFactor();
5910 }
5911
5912 // Don't use transparency for PictureInPicture windows.
5913 bool toplevelNeedsAlphaVisual = false;
5914 if (mWindowType == WindowType::TopLevel && !mIsPIPWindow) {
5915 toplevelNeedsAlphaVisual = IsToplevelWindowTransparent();
5916 }
5917
5918 bool isGLVisualSet = false;
5919 mIsAccelerated = ComputeShouldAccelerate();
5920#ifdef MOZ_X111
5921 if (GdkIsX11Display() && mIsAccelerated) {
5922 isGLVisualSet = ConfigureX11GLVisual();
5923 }
5924#endif
5925 if (!isGLVisualSet && (popupNeedsAlphaVisual || toplevelNeedsAlphaVisual)) {
5926 // We're running on composited screen so we can use alpha visual
5927 // for both toplevel and popups.
5928 if (mCompositedScreen) {
5929 GdkVisual* visual =
5930 gdk_screen_get_rgba_visual(gtk_widget_get_screen(mShell));
5931 if (visual) {
5932 gtk_widget_set_visual(mShell, visual);
5933 mHasAlphaVisual = true;
5934 }
5935 }
5936 }
5937
5938 // We have a toplevel window with transparency.
5939 // Calls to UpdateTitlebarTransparencyBitmap() from OnExposeEvent()
5940 // occur before SetTransparencyMode() receives TransparencyMode::Transparent
5941 // from layout, so set mIsTransparent here.
5942 if (mWindowType == WindowType::TopLevel && mHasAlphaVisual) {
5943 mIsTransparent = true;
5944 }
5945
5946 // We only move a general managed toplevel window if someone has
5947 // actually placed the window somewhere. If no placement has taken
5948 // place, we just let the window manager Do The Right Thing.
5949 if (AreBoundsSane()) {
5950 GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mBounds.Size());
5951 LOG("nsWindow::Create() Initial resize to %d x %d\n", size.width,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::Create() Initial resize to %d x %d\n"
, GetDebugTag().get(), size.width, size.height); } } while (0
)
5952 size.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::Create() Initial resize to %d x %d\n"
, GetDebugTag().get(), size.width, size.height); } } while (0
)
;
5953 gtk_window_resize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), size.width, size.height);
5954 }
5955 if (mIsPIPWindow) {
5956 LOG(" Is PIP window\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 PIP window\n", GetDebugTag(
).get()); } } while (0)
;
5957 gtk_window_set_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), GDK_WINDOW_TYPE_HINT_UTILITY);
5958 } else if (mIsAlert) {
5959 LOG(" Is alert window\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 alert window\n", GetDebugTag
().get()); } } while (0)
;
5960 gtk_window_set_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))),
5961 GDK_WINDOW_TYPE_HINT_NOTIFICATION);
5962 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), TRUE(!(0)));
5963 } else if (mWindowType == WindowType::Dialog) {
5964 mGtkWindowRoleName = "Dialog";
5965
5966 SetDefaultIcon();
5967 gtk_window_set_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), GDK_WINDOW_TYPE_HINT_DIALOG);
5968 LOG("nsWindow::Create(): dialog")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::Create(): dialog", GetDebugTag
().get()); } } while (0)
;
5969 if (parentnsWindow) {
5970 GtkWindowSetTransientFor(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))),
5971 GTK_WINDOW(parentnsWindow->GetGtkWidget())((((GtkWindow*) (void *) ((parentnsWindow->GetGtkWidget())
))))
);
5972 LOG(" set parent window [%p]\n", parentnsWindow)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 parent window [%p]\n", GetDebugTag
().get(), parentnsWindow); } } while (0)
;
5973 }
5974 } else if (mWindowType == WindowType::Popup) {
5975 MOZ_ASSERT(aInitData)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aInitData)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aInitData))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aInitData", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 5975); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aInitData" ")"
); do { *((volatile int*)__null) = 5975; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5976 mGtkWindowRoleName = "Popup";
5977
5978 LOG("nsWindow::Create() Popup")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::Create() Popup", GetDebugTag
().get()); } } while (0)
;
5979
5980 if (mNoAutoHide) {
5981 // ... but the window manager does not decorate this window,
5982 // nor provide a separate taskbar icon.
5983 if (mBorderStyle == BorderStyle::Default) {
5984 gtk_window_set_decorated(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), FALSE(0));
5985 } else {
5986 bool decorate = bool(mBorderStyle & BorderStyle::Title);
5987 gtk_window_set_decorated(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), decorate);
5988 if (decorate) {
5989 gtk_window_set_deletable(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))),
5990 bool(mBorderStyle & BorderStyle::Close));
5991 }
5992 }
5993 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), TRUE(!(0)));
5994 // Element focus is managed by the parent window so the
5995 // WM_HINTS input field is set to False to tell the window
5996 // manager not to set input focus to this window ...
5997 gtk_window_set_accept_focus(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), FALSE(0));
5998#ifdef MOZ_X111
5999 // ... but when the window manager offers focus through
6000 // WM_TAKE_FOCUS, focus is requested on the parent window.
6001 if (GdkIsX11Display()) {
6002 gtk_widget_realize(mShell);
6003 gdk_window_add_filter(GetToplevelGdkWindow(), popup_take_focus_filter,
6004 nullptr);
6005 }
6006#endif
6007 }
6008
6009 if (aInitData->mIsDragPopup) {
6010 gtk_window_set_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), GDK_WINDOW_TYPE_HINT_DND);
6011 mIsDragPopup = true;
6012 LOG("nsWindow::Create() Drag popup\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::Create() Drag popup\n", GetDebugTag
().get()); } } while (0)
;
6013 } else if (GdkIsX11Display()) {
6014 // Set the window hints on X11 only. Wayland popups are configured
6015 // at WaylandPopupConfigure().
6016 GdkWindowTypeHint gtkTypeHint;
6017 switch (mPopupType) {
6018 case PopupType::Menu:
6019 gtkTypeHint = GDK_WINDOW_TYPE_HINT_POPUP_MENU;
6020 break;
6021 case PopupType::Tooltip:
6022 gtkTypeHint = GDK_WINDOW_TYPE_HINT_TOOLTIP;
6023 break;
6024 default:
6025 gtkTypeHint = GDK_WINDOW_TYPE_HINT_UTILITY;
6026 break;
6027 }
6028 gtk_window_set_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), gtkTypeHint);
6029 LOG("nsWindow::Create() popup type %s", GetPopupTypeName().get())do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::Create() popup type %s",
GetDebugTag().get(), GetPopupTypeName().get()); } } while (0
)
;
6030 }
6031 if (parentnsWindow) {
6032 LOG(" set parent window [%p] %s", parentnsWindow,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 parent window [%p] %s", GetDebugTag
().get(), parentnsWindow, parentnsWindow->mGtkWindowRoleName
.get()); } } while (0)
6033 parentnsWindow->mGtkWindowRoleName.get())do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 parent window [%p] %s", GetDebugTag
().get(), parentnsWindow, parentnsWindow->mGtkWindowRoleName
.get()); } } while (0)
;
6034 GtkWindow* parentWidget = GTK_WINDOW(parentnsWindow->GetGtkWidget())((((GtkWindow*) (void *) ((parentnsWindow->GetGtkWidget())
))))
;
6035 GtkWindowSetTransientFor(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), parentWidget);
6036
6037 // If popup parent is modal, we need to make popup modal too.
6038 if (mPopupType != PopupType::Tooltip &&
6039 gtk_window_get_modal(parentWidget)) {
6040 gtk_window_set_modal(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), true);
6041 }
6042 }
6043
6044 // We need realized mShell at NativeMoveResize().
6045 gtk_widget_realize(mShell);
6046
6047 // With popup windows, we want to set their position.
6048 // Place them immediately on X11 and save initial popup position
6049 // on Wayland as we place Wayland popup on show.
6050 if (GdkIsX11Display()) {
6051 NativeMoveResize(/* move */ true, /* resize */ false);
6052 } else if (AreBoundsSane()) {
6053 GdkRectangle rect = DevicePixelsToGdkRectRoundOut(mBounds);
6054 mPopupPosition = {rect.x, rect.y};
6055 }
6056 } else { // must be WindowType::TopLevel
6057 mGtkWindowRoleName = "Toplevel";
6058 SetDefaultIcon();
6059
6060 LOG("nsWindow::Create() Toplevel\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::Create() Toplevel\n", GetDebugTag
().get()); } } while (0)
;
6061
6062 // each toplevel window gets its own window group
6063 GtkWindowGroup* group = gtk_window_group_new();
6064 gtk_window_group_add_window(group, GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
6065 g_object_unref(group);
6066 }
6067
6068 if (mAlwaysOnTop) {
6069 gtk_window_set_keep_above(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), TRUE(!(0)));
6070 }
6071
6072 // Create a container to hold child windows and child GtkWidgets.
6073 GtkWidget* container = moz_container_new();
6074 mContainer = MOZ_CONTAINER(container)((((MozContainer*) (void *) ((container)))));
6075
6076 // Prevent GtkWindow from painting a background to avoid flickering.
6077 gtk_widget_set_app_paintable(
6078 GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))),
6079 StaticPrefs::widget_transparent_windows_AtStartup());
6080
6081 gtk_widget_add_events(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))), kEvents);
6082 gtk_widget_add_events(mShell, GDK_PROPERTY_CHANGE_MASK);
6083 gtk_widget_set_app_paintable(
6084 mShell, StaticPrefs::widget_transparent_windows_AtStartup());
6085
6086 // If we draw to mContainer window then configure it now because
6087 // gtk_container_add() realizes the child widget.
6088 gtk_widget_set_has_window(container, true);
6089 gtk_container_add(GTK_CONTAINER(mShell)((((GtkContainer*) (void *) ((mShell))))), container);
6090
6091 // alwaysontop windows are generally used for peripheral indicators,
6092 // so we don't focus them by default.
6093 if (mAlwaysOnTop) {
6094 gtk_window_set_focus_on_map(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), FALSE(0));
6095 }
6096
6097 gtk_widget_realize(container);
6098
6099 // make sure this is the focus widget in the container
6100 gtk_widget_show(container);
6101
6102 if (!mAlwaysOnTop) {
6103 gtk_widget_grab_focus(container);
6104 }
6105
6106#ifdef MOZ_WAYLAND1
6107 if (mIsDragPopup && GdkIsWaylandDisplay()) {
6108 LOG(" set commit to parent")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 commit to parent", GetDebugTag
().get()); } } while (0)
;
6109 moz_container_wayland_set_commit_to_parent(mContainer);
6110 }
6111#endif
6112
6113 if (mWindowType == WindowType::TopLevel && gKioskMode) {
6114 if (gKioskMonitor != -1) {
6115 mKioskMonitor = Some(gKioskMonitor);
6116 LOG(" set kiosk mode monitor %d", mKioskMonitor.value())do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 kiosk mode monitor %d", GetDebugTag
().get(), mKioskMonitor.value()); } } while (0)
;
6117 } else {
6118 LOG(" set kiosk mode")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 kiosk mode", GetDebugTag().get
()); } } while (0)
;
6119 }
6120 // Kiosk mode always use fullscreen.
6121 MakeFullScreen(/* aFullScreen */ true);
6122 }
6123
6124 if (mWindowType == WindowType::Popup) {
6125 MOZ_ASSERT(aInitData)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aInitData)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aInitData))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aInitData", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 6125); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aInitData" ")"
); do { *((volatile int*)__null) = 6125; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6126 // gdk does not automatically set the cursor for "temporary"
6127 // windows, which are what gtk uses for popups.
6128
6129 // force SetCursor to actually set the cursor, even though our internal
6130 // state indicates that we already have the standard cursor.
6131 mUpdateCursor = true;
6132 SetCursor(Cursor{eCursor_standard});
6133 }
6134
6135 if (mIsChildWindow && parentnsWindow) {
6136 GdkWindow* window = GetToplevelGdkWindow();
6137 GdkWindow* parentWindow = parentnsWindow->GetToplevelGdkWindow();
6138 LOG(" child GdkWindow %p set parent GdkWindow %p", window, parentWindow)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " child GdkWindow %p set parent GdkWindow %p"
, GetDebugTag().get(), window, parentWindow); } } while (0)
;
6139 gdk_window_reparent(window, parentWindow,
6140 DevicePixelsToGdkCoordRoundDown(mBounds.x),
6141 DevicePixelsToGdkCoordRoundDown(mBounds.y));
6142 }
6143
6144 // Also label mShell toplevel window,
6145 // property_notify_event_cb callback also needs to find its way home
6146 g_object_set_data(G_OBJECT(GetToplevelGdkWindow())((((GObject*) (void *) ((GetToplevelGdkWindow()))))), "nsWindow", this);
6147 g_object_set_data(G_OBJECT(mContainer)((((GObject*) (void *) ((mContainer))))), "nsWindow", this);
6148 g_object_set_data(G_OBJECT(mShell)((((GObject*) (void *) ((mShell))))), "nsWindow", this);
6149
6150 // attach listeners for events
6151 g_signal_connect(mShell, "configure_event", G_CALLBACK(configure_event_cb),g_signal_connect_data ((mShell), ("configure_event"), (((GCallback
) (configure_event_cb))), (nullptr), __null, (GConnectFlags) 0
)
6152 nullptr)g_signal_connect_data ((mShell), ("configure_event"), (((GCallback
) (configure_event_cb))), (nullptr), __null, (GConnectFlags) 0
)
;
6153 g_signal_connect(mShell, "delete_event", G_CALLBACK(delete_event_cb),g_signal_connect_data ((mShell), ("delete_event"), (((GCallback
) (delete_event_cb))), (nullptr), __null, (GConnectFlags) 0)
6154 nullptr)g_signal_connect_data ((mShell), ("delete_event"), (((GCallback
) (delete_event_cb))), (nullptr), __null, (GConnectFlags) 0)
;
6155 g_signal_connect(mShell, "window_state_event",g_signal_connect_data ((mShell), ("window_state_event"), (((GCallback
) (window_state_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
6156 G_CALLBACK(window_state_event_cb), nullptr)g_signal_connect_data ((mShell), ("window_state_event"), (((GCallback
) (window_state_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6157 g_signal_connect(mShell, "visibility-notify-event",g_signal_connect_data ((mShell), ("visibility-notify-event"),
(((GCallback) (visibility_notify_event_cb))), (nullptr), __null
, (GConnectFlags) 0)
6158 G_CALLBACK(visibility_notify_event_cb), nullptr)g_signal_connect_data ((mShell), ("visibility-notify-event"),
(((GCallback) (visibility_notify_event_cb))), (nullptr), __null
, (GConnectFlags) 0)
;
6159 g_signal_connect(mShell, "check-resize", G_CALLBACK(check_resize_cb),g_signal_connect_data ((mShell), ("check-resize"), (((GCallback
) (check_resize_cb))), (nullptr), __null, (GConnectFlags) 0)
6160 nullptr)g_signal_connect_data ((mShell), ("check-resize"), (((GCallback
) (check_resize_cb))), (nullptr), __null, (GConnectFlags) 0)
;
6161 g_signal_connect(mShell, "composited-changed",g_signal_connect_data ((mShell), ("composited-changed"), (((GCallback
) (widget_composited_changed_cb))), (nullptr), __null, (GConnectFlags
) 0)
6162 G_CALLBACK(widget_composited_changed_cb), nullptr)g_signal_connect_data ((mShell), ("composited-changed"), (((GCallback
) (widget_composited_changed_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6163 g_signal_connect(mShell, "property-notify-event",g_signal_connect_data ((mShell), ("property-notify-event"), (
((GCallback) (property_notify_event_cb))), (nullptr), __null,
(GConnectFlags) 0)
6164 G_CALLBACK(property_notify_event_cb), nullptr)g_signal_connect_data ((mShell), ("property-notify-event"), (
((GCallback) (property_notify_event_cb))), (nullptr), __null,
(GConnectFlags) 0)
;
6165
6166 if (mWindowType == WindowType::TopLevel) {
6167 g_signal_connect_after(mShell, "size_allocate",g_signal_connect_data ((mShell), ("size_allocate"), (((GCallback
) (toplevel_window_size_allocate_cb))), (nullptr), __null, G_CONNECT_AFTER
)
6168 G_CALLBACK(toplevel_window_size_allocate_cb),g_signal_connect_data ((mShell), ("size_allocate"), (((GCallback
) (toplevel_window_size_allocate_cb))), (nullptr), __null, G_CONNECT_AFTER
)
6169 nullptr)g_signal_connect_data ((mShell), ("size_allocate"), (((GCallback
) (toplevel_window_size_allocate_cb))), (nullptr), __null, G_CONNECT_AFTER
)
;
6170 }
6171
6172 GdkScreen* screen = gtk_widget_get_screen(mShell);
6173 if (!g_signal_handler_find(screen, G_SIGNAL_MATCH_FUNC, 0, 0, nullptr,
6174 FuncToGpointer(screen_composited_changed_cb),
6175 nullptr)) {
6176 g_signal_connect(screen, "composited-changed",g_signal_connect_data ((screen), ("composited-changed"), (((GCallback
) (screen_composited_changed_cb))), (nullptr), __null, (GConnectFlags
) 0)
6177 G_CALLBACK(screen_composited_changed_cb), nullptr)g_signal_connect_data ((screen), ("composited-changed"), (((GCallback
) (screen_composited_changed_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6178 }
6179
6180 gtk_drag_dest_set((GtkWidget*)mShell, (GtkDestDefaults)0, nullptr, 0,
6181 (GdkDragAction)0);
6182 g_signal_connect(mShell, "drag_motion", G_CALLBACK(drag_motion_event_cb),g_signal_connect_data ((mShell), ("drag_motion"), (((GCallback
) (drag_motion_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
6183 nullptr)g_signal_connect_data ((mShell), ("drag_motion"), (((GCallback
) (drag_motion_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6184 g_signal_connect(mShell, "drag_leave", G_CALLBACK(drag_leave_event_cb),g_signal_connect_data ((mShell), ("drag_leave"), (((GCallback
) (drag_leave_event_cb))), (nullptr), __null, (GConnectFlags)
0)
6185 nullptr)g_signal_connect_data ((mShell), ("drag_leave"), (((GCallback
) (drag_leave_event_cb))), (nullptr), __null, (GConnectFlags)
0)
;
6186 g_signal_connect(mShell, "drag_drop", G_CALLBACK(drag_drop_event_cb),g_signal_connect_data ((mShell), ("drag_drop"), (((GCallback)
(drag_drop_event_cb))), (nullptr), __null, (GConnectFlags) 0
)
6187 nullptr)g_signal_connect_data ((mShell), ("drag_drop"), (((GCallback)
(drag_drop_event_cb))), (nullptr), __null, (GConnectFlags) 0
)
;
6188 g_signal_connect(mShell, "drag_data_received",g_signal_connect_data ((mShell), ("drag_data_received"), (((GCallback
) (drag_data_received_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
6189 G_CALLBACK(drag_data_received_event_cb), nullptr)g_signal_connect_data ((mShell), ("drag_data_received"), (((GCallback
) (drag_data_received_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6190
6191 GtkSettings* default_settings = gtk_settings_get_default();
6192 g_signal_connect_after(default_settings, "notify::gtk-xft-dpi",g_signal_connect_data ((default_settings), ("notify::gtk-xft-dpi"
), (((GCallback) (settings_xft_dpi_changed_cb))), (this), __null
, G_CONNECT_AFTER)
6193 G_CALLBACK(settings_xft_dpi_changed_cb), this)g_signal_connect_data ((default_settings), ("notify::gtk-xft-dpi"
), (((GCallback) (settings_xft_dpi_changed_cb))), (this), __null
, G_CONNECT_AFTER)
;
6194
6195 // Widget signals
6196 g_signal_connect_after(mContainer, "size_allocate",g_signal_connect_data ((mContainer), ("size_allocate"), (((GCallback
) (size_allocate_cb))), (nullptr), __null, G_CONNECT_AFTER)
6197 G_CALLBACK(size_allocate_cb), nullptr)g_signal_connect_data ((mContainer), ("size_allocate"), (((GCallback
) (size_allocate_cb))), (nullptr), __null, G_CONNECT_AFTER)
;
6198 g_signal_connect(mContainer, "hierarchy-changed",g_signal_connect_data ((mContainer), ("hierarchy-changed"), (
((GCallback) (hierarchy_changed_cb))), (nullptr), __null, (GConnectFlags
) 0)
6199 G_CALLBACK(hierarchy_changed_cb), nullptr)g_signal_connect_data ((mContainer), ("hierarchy-changed"), (
((GCallback) (hierarchy_changed_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6200 g_signal_connect(mContainer, "notify::scale-factor",g_signal_connect_data ((mContainer), ("notify::scale-factor")
, (((GCallback) (scale_changed_cb))), (nullptr), __null, (GConnectFlags
) 0)
6201 G_CALLBACK(scale_changed_cb), nullptr)g_signal_connect_data ((mContainer), ("notify::scale-factor")
, (((GCallback) (scale_changed_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6202 // Initialize mHasMappedToplevel.
6203 hierarchy_changed_cb(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))), nullptr);
6204 // Expose, focus, key, and drag events are sent even to GTK_NO_WINDOW
6205 // widgets.
6206 g_signal_connect(G_OBJECT(mContainer), "draw", G_CALLBACK(expose_event_cb),g_signal_connect_data ((((((GObject*) (void *) ((mContainer))
)))), ("draw"), (((GCallback) (expose_event_cb))), (nullptr),
__null, (GConnectFlags) 0)
6207 nullptr)g_signal_connect_data ((((((GObject*) (void *) ((mContainer))
)))), ("draw"), (((GCallback) (expose_event_cb))), (nullptr),
__null, (GConnectFlags) 0)
;
6208 g_signal_connect(mContainer, "focus_in_event", G_CALLBACK(focus_in_event_cb),g_signal_connect_data ((mContainer), ("focus_in_event"), (((GCallback
) (focus_in_event_cb))), (nullptr), __null, (GConnectFlags) 0
)
6209 nullptr)g_signal_connect_data ((mContainer), ("focus_in_event"), (((GCallback
) (focus_in_event_cb))), (nullptr), __null, (GConnectFlags) 0
)
;
6210 g_signal_connect(mContainer, "focus_out_event",g_signal_connect_data ((mContainer), ("focus_out_event"), (((
GCallback) (focus_out_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
6211 G_CALLBACK(focus_out_event_cb), nullptr)g_signal_connect_data ((mContainer), ("focus_out_event"), (((
GCallback) (focus_out_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6212 g_signal_connect(mContainer, "key_press_event",g_signal_connect_data ((mContainer), ("key_press_event"), (((
GCallback) (key_press_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
6213 G_CALLBACK(key_press_event_cb), nullptr)g_signal_connect_data ((mContainer), ("key_press_event"), (((
GCallback) (key_press_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6214 g_signal_connect(mContainer, "key_release_event",g_signal_connect_data ((mContainer), ("key_release_event"), (
((GCallback) (key_release_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
6215 G_CALLBACK(key_release_event_cb), nullptr)g_signal_connect_data ((mContainer), ("key_release_event"), (
((GCallback) (key_release_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6216
6217#ifdef MOZ_X111
6218 if (GdkIsX11Display()) {
6219 gtk_widget_set_double_buffered(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))), FALSE(0));
6220 }
6221#endif
6222#ifdef MOZ_WAYLAND1
6223 // Initialize the window specific VsyncSource early in order to avoid races
6224 // with BrowserParent::UpdateVsyncParentVsyncDispatcher().
6225 // Only use for toplevel windows for now, see bug 1619246.
6226 if (GdkIsWaylandDisplay() &&
6227 StaticPrefs::widget_wayland_vsync_enabled_AtStartup() &&
6228 IsTopLevelWindowType()) {
6229 mWaylandVsyncSource = new WaylandVsyncSource(this);
6230 mWaylandVsyncDispatcher = new VsyncDispatcher(mWaylandVsyncSource);
6231 LOG_VSYNC(" created 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, " created WaylandVsyncSource"
); } } while (0)
;
6232 }
6233#endif
6234
6235 // We create input contexts for all containers, except for
6236 // toplevel popup windows
6237 if (mWindowType != WindowType::Popup) {
6238 mIMContext = new IMContextWrapper(this);
6239 }
6240
6241 // A popup attached to a modal parent window doesn't get mouse events
6242 // from Gtk as they'are directed to the modal parent. This is usually solved
6243 // by pointer grab which that doesn't work on Wayland in our current
6244 // setup as it performs show and grab in one step.
6245 //
6246 // We emulate it by setting popup as modal too but then patent
6247 // window doesn't get mouse events outside of popup (Bug 1899299).
6248 // we need to listen
6249 //
6250 // Surprisingly attaching events handler to mShell fixes it
6251 // and we're getting events from both parent and popup windows.
6252 GtkWidget* eventWidget = (mWindowType == WindowType::Popup &&
6253 gtk_window_get_modal(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell)))))))
6254 ? mShell
6255 : GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer)))));
6256 g_signal_connect(eventWidget, "enter-notify-event",g_signal_connect_data ((eventWidget), ("enter-notify-event"),
(((GCallback) (enter_notify_event_cb))), (nullptr), __null, (
GConnectFlags) 0)
6257 G_CALLBACK(enter_notify_event_cb), nullptr)g_signal_connect_data ((eventWidget), ("enter-notify-event"),
(((GCallback) (enter_notify_event_cb))), (nullptr), __null, (
GConnectFlags) 0)
;
6258 g_signal_connect(eventWidget, "leave-notify-event",g_signal_connect_data ((eventWidget), ("leave-notify-event"),
(((GCallback) (leave_notify_event_cb))), (nullptr), __null, (
GConnectFlags) 0)
6259 G_CALLBACK(leave_notify_event_cb), nullptr)g_signal_connect_data ((eventWidget), ("leave-notify-event"),
(((GCallback) (leave_notify_event_cb))), (nullptr), __null, (
GConnectFlags) 0)
;
6260 g_signal_connect(eventWidget, "motion-notify-event",g_signal_connect_data ((eventWidget), ("motion-notify-event")
, (((GCallback) (motion_notify_event_cb))), (nullptr), __null
, (GConnectFlags) 0)
6261 G_CALLBACK(motion_notify_event_cb), nullptr)g_signal_connect_data ((eventWidget), ("motion-notify-event")
, (((GCallback) (motion_notify_event_cb))), (nullptr), __null
, (GConnectFlags) 0)
;
6262 g_signal_connect(eventWidget, "button-press-event",g_signal_connect_data ((eventWidget), ("button-press-event"),
(((GCallback) (button_press_event_cb))), (nullptr), __null, (
GConnectFlags) 0)
6263 G_CALLBACK(button_press_event_cb), nullptr)g_signal_connect_data ((eventWidget), ("button-press-event"),
(((GCallback) (button_press_event_cb))), (nullptr), __null, (
GConnectFlags) 0)
;
6264 g_signal_connect(eventWidget, "button-release-event",g_signal_connect_data ((eventWidget), ("button-release-event"
), (((GCallback) (button_release_event_cb))), (nullptr), __null
, (GConnectFlags) 0)
6265 G_CALLBACK(button_release_event_cb), nullptr)g_signal_connect_data ((eventWidget), ("button-release-event"
), (((GCallback) (button_release_event_cb))), (nullptr), __null
, (GConnectFlags) 0)
;
6266 g_signal_connect(eventWidget, "scroll-event", G_CALLBACK(scroll_event_cb),g_signal_connect_data ((eventWidget), ("scroll-event"), (((GCallback
) (scroll_event_cb))), (nullptr), __null, (GConnectFlags) 0)
6267 nullptr)g_signal_connect_data ((eventWidget), ("scroll-event"), (((GCallback
) (scroll_event_cb))), (nullptr), __null, (GConnectFlags) 0)
;
6268 if (gtk_check_version(3, 18, 0) == nullptr) {
6269 g_signal_connect(eventWidget, "event", G_CALLBACK(generic_event_cb),g_signal_connect_data ((eventWidget), ("event"), (((GCallback
) (generic_event_cb))), (nullptr), __null, (GConnectFlags) 0)
6270 nullptr)g_signal_connect_data ((eventWidget), ("event"), (((GCallback
) (generic_event_cb))), (nullptr), __null, (GConnectFlags) 0)
;
6271 }
6272 g_signal_connect(eventWidget, "touch-event", G_CALLBACK(touch_event_cb),g_signal_connect_data ((eventWidget), ("touch-event"), (((GCallback
) (touch_event_cb))), (nullptr), __null, (GConnectFlags) 0)
6273 nullptr)g_signal_connect_data ((eventWidget), ("touch-event"), (((GCallback
) (touch_event_cb))), (nullptr), __null, (GConnectFlags) 0)
;
6274
6275 LOG(" nsWindow type %d %s\n", int(mWindowType),do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 type %d %s\n", GetDebugTag
().get(), int(mWindowType), mIsPIPWindow ? "PIP window" : "")
; } } while (0)
6276 mIsPIPWindow ? "PIP window" : "")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 type %d %s\n", GetDebugTag
().get(), int(mWindowType), mIsPIPWindow ? "PIP window" : "")
; } } while (0)
;
6277 LOG(" mShell %p (window %p) mContainer %p mGdkWindow %p XID 0x%lx\n", mShell,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " mShell %p (window %p) mContainer %p mGdkWindow %p XID 0x%lx\n"
, GetDebugTag().get(), mShell, GetToplevelGdkWindow(), mContainer
, mGdkWindow, GetX11Window()); } } while (0)
6278 GetToplevelGdkWindow(), mContainer, mGdkWindow, GetX11Window())do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " mShell %p (window %p) mContainer %p mGdkWindow %p XID 0x%lx\n"
, GetDebugTag().get(), mShell, GetToplevelGdkWindow(), mContainer
, mGdkWindow, GetX11Window()); } } while (0)
;
6279
6280 // Set default application name when it's empty.
6281 if (mGtkWindowAppName.IsEmpty()) {
6282 mGtkWindowAppName = gAppData->name;
6283 }
6284
6285 mCreated = true;
6286 return NS_OK;
6287}
6288
6289void nsWindow::RefreshWindowClass(void) {
6290 GdkWindow* gdkWindow = GetToplevelGdkWindow();
6291 if (!gdkWindow) {
6292 return;
6293 }
6294
6295 if (!mGtkWindowRoleName.IsEmpty()) {
6296 gdk_window_set_role(gdkWindow, mGtkWindowRoleName.get());
6297 }
6298
6299#ifdef MOZ_X111
6300 if (GdkIsX11Display()) {
6301 XClassHint* class_hint = XAllocClassHint();
6302 if (!class_hint) {
6303 return;
6304 }
6305
6306 const char* res_name =
6307 !mGtkWindowAppName.IsEmpty() ? mGtkWindowAppName.get() : gAppData->name;
6308
6309 const char* res_class = !mGtkWindowAppClass.IsEmpty()
6310 ? mGtkWindowAppClass.get()
6311 : gdk_get_program_class();
6312
6313 if (!res_name || !res_class) {
6314 XFree(class_hint);
6315 return;
6316 }
6317
6318 class_hint->res_name = const_cast<char*>(res_name);
6319 class_hint->res_class = const_cast<char*>(res_class);
6320
6321 // Can't use gtk_window_set_wmclass() for this; it prints
6322 // a warning & refuses to make the change.
6323 GdkDisplay* display = gdk_display_get_default();
6324 XSetClassHint(GDK_DISPLAY_XDISPLAY(display)(gdk_x11_display_get_xdisplay (display)),
6325 gdk_x11_window_get_xid(gdkWindow), class_hint);
6326 XFree(class_hint);
6327 }
6328#endif /* MOZ_X11 */
6329
6330#ifdef MOZ_WAYLAND1
6331 static auto sGdkWaylandWindowSetApplicationId =
6332 (void (*)(GdkWindow*, const char*))dlsym(
6333 RTLD_DEFAULT((void *) 0), "gdk_wayland_window_set_application_id");
6334
6335 if (GdkIsWaylandDisplay() && sGdkWaylandWindowSetApplicationId &&
6336 !mGtkWindowAppClass.IsEmpty()) {
6337 sGdkWaylandWindowSetApplicationId(gdkWindow, mGtkWindowAppClass.get());
6338 }
6339#endif /* MOZ_WAYLAND */
6340}
6341
6342void nsWindow::SetWindowClass(const nsAString& xulWinType,
6343 const nsAString& xulWinClass,
6344 const nsAString& xulWinName) {
6345 if (!mShell) {
6346 return;
6347 }
6348
6349 // If window type attribute is set, parse it into name and role
6350 if (!xulWinType.IsEmpty()) {
6351 char* res_name = ToNewCString(xulWinType, mozilla::fallible);
6352 const char* role = nullptr;
6353
6354 if (res_name) {
6355 // Parse res_name into a name and role. Characters other than
6356 // [A-Za-z0-9_-] are converted to '_'. Anything after the first
6357 // colon is assigned to role; if there's no colon, assign the
6358 // whole thing to both role and res_name.
6359 for (char* c = res_name; *c; c++) {
6360 if (':' == *c) {
6361 *c = 0;
6362 role = c + 1;
6363 } else if (!isascii(*c) ||
6364 (!isalnum(*c) && ('_' != *c) && ('-' != *c))) {
6365 *c = '_';
6366 }
6367 }
6368 res_name[0] = (char)toupper(res_name[0]);
6369 if (!role) role = res_name;
6370
6371 mGtkWindowAppName = res_name;
6372 mGtkWindowRoleName = role;
6373 free(res_name);
6374 }
6375 }
6376
6377 // If window class attribute is set, store it as app class
6378 // If this attribute is not set, reset app class to default
6379 if (!xulWinClass.IsEmpty()) {
6380 CopyUTF16toUTF8(xulWinClass, mGtkWindowAppClass);
6381 } else {
6382 mGtkWindowAppClass = nullptr;
6383 }
6384
6385 // If window class attribute is set, store it as app name
6386 // If both name and type are not set, reset app name to default
6387 if (!xulWinName.IsEmpty()) {
6388 CopyUTF16toUTF8(xulWinName, mGtkWindowAppName);
6389 } else if (xulWinType.IsEmpty()) {
6390 mGtkWindowAppClass = nullptr;
6391 }
6392
6393 RefreshWindowClass();
6394}
6395
6396nsAutoCString nsWindow::GetDebugTag() const {
6397 nsAutoCString tag;
6398 tag.AppendPrintf("[%p]", this);
6399 return tag;
6400}
6401
6402void nsWindow::NativeMoveResize(bool aMoved, bool aResized) {
6403 GdkPoint topLeft = [&] {
6404 auto target = mBounds.TopLeft();
6405 // gtk_window_move will undo the csd offset, but nothing else, so only add
6406 // the client offset if drawing to the csd titlebar.
6407 if (DrawsToCSDTitlebar()) {
6408 target += mClientOffset;
6409 }
6410 return DevicePixelsToGdkPointRoundDown(target);
6411 }();
6412 GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mLastSizeRequest);
6413
6414 LOG("nsWindow::NativeMoveResize move %d resize %d to %d,%d -> %d x %d\n",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::NativeMoveResize move %d resize %d to %d,%d -> %d x %d\n"
, GetDebugTag().get(), aMoved, aResized, topLeft.x, topLeft.y
, size.width, size.height); } } while (0)
6415 aMoved, aResized, topLeft.x, topLeft.y, size.width, size.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::NativeMoveResize move %d resize %d to %d,%d -> %d x %d\n"
, GetDebugTag().get(), aMoved, aResized, topLeft.x, topLeft.y
, size.width, size.height); } } while (0)
;
6416
6417 if (aMoved) {
6418 ResetScreenBounds();
6419 }
6420
6421 if (aResized && !AreBoundsSane()) {
6422 LOG(" bounds are insane, hidding the window")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 insane, hidding the window"
, GetDebugTag().get()); } } while (0)
;
6423 // We have been resized but to incorrect size.
6424 // If someone has set this so that the needs show flag is false
6425 // and it needs to be hidden, update the flag and hide the
6426 // window. This flag will be cleared the next time someone
6427 // hides the window or shows it. It also prevents us from
6428 // calling NativeShow(false) excessively on the window which
6429 // causes unneeded X traffic.
6430 if (!mNeedsShow && mIsShown) {
6431 mNeedsShow = true;
6432 NativeShow(false);
6433 }
6434 if (aMoved) {
6435 LOG(" moving to %d x %d", topLeft.x, topLeft.y)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " moving to %d x %d", GetDebugTag(
).get(), topLeft.x, topLeft.y); } } while (0)
;
6436 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), topLeft.x, topLeft.y);
6437 }
6438 return;
6439 }
6440
6441 // Set position to hidden window on X11 may fail, so save the position
6442 // and move it when it's shown.
6443 if (aMoved && GdkIsX11Display() && IsPopup() &&
6444 !gtk_widget_get_visible(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))))) {
6445 LOG(" store position of hidden popup window")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " store position of hidden popup window"
, GetDebugTag().get()); } } while (0)
;
6446 mHiddenPopupPositioned = true;
6447 mPopupPosition = {topLeft.x, topLeft.y};
6448 }
6449
6450 if (IsWaylandPopup()) {
6451 NativeMoveResizeWaylandPopup(aMoved, aResized);
6452 } else {
6453 // x and y give the position of the window manager frame top-left.
6454 if (aMoved) {
6455 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), topLeft.x, topLeft.y);
6456 }
6457 if (aResized) {
6458 gtk_window_resize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), size.width, size.height);
6459 if (mIsDragPopup) {
6460 // DND window is placed inside container so we need to make hard size
6461 // request to ensure parent container is resized too.
6462 gtk_widget_set_size_request(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))), size.width,
6463 size.height);
6464 }
6465 }
6466 }
6467
6468 if (aResized) {
6469 // Recompute the input region, in case the window grew or shrunk.
6470 SetInputRegion(mInputRegion);
6471 }
6472
6473 // Does it need to be shown because bounds were previously insane?
6474 if (mNeedsShow && mIsShown && aResized) {
6475 NativeShow(true);
6476 }
6477}
6478
6479// We pause compositor to avoid rendering of obsoleted remote content which
6480// produces flickering.
6481// Re-enable compositor again when remote content is updated or
6482// timeout happens.
6483
6484// Define maximal compositor pause when it's paused to avoid flickering,
6485// in milliseconds.
6486#define COMPOSITOR_PAUSE_TIMEOUT(1000) (1000)
6487
6488void nsWindow::PauseCompositorFlickering() {
6489 bool pauseCompositor = IsTopLevelWindowType() &&
6490 mCompositorState == COMPOSITOR_ENABLED &&
6491 mCompositorWidgetDelegate && !mIsDestroyed;
6492 if (!pauseCompositor) {
6493 return;
6494 }
6495
6496 LOG("nsWindow::PauseCompositorFlickering()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::PauseCompositorFlickering()"
, GetDebugTag().get()); } } while (0)
;
6497
6498 MozClearHandleID(mCompositorPauseTimeoutID, g_source_remove);
6499
6500 CompositorBridgeChild* remoteRenderer = GetRemoteRenderer();
6501 if (remoteRenderer) {
6502 mCompositorState = COMPOSITOR_PAUSED_FLICKERING;
6503 remoteRenderer->SendPause();
6504 mCompositorPauseTimeoutID = (int)g_timeout_add(
6505 COMPOSITOR_PAUSE_TIMEOUT(1000),
6506 [](void* data) -> gint {
6507 nsWindow* window = static_cast<nsWindow*>(data);
6508 if (!window->IsDestroyed()) {
6509 window->ResumeCompositorFlickering();
6510 }
6511 return true;
6512 },
6513 this);
6514 }
6515}
6516
6517bool nsWindow::IsWaitingForCompositorResume() {
6518 return mCompositorState == COMPOSITOR_PAUSED_FLICKERING;
6519}
6520
6521void nsWindow::ResumeCompositorFlickering() {
6522 MOZ_RELEASE_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 6522); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 6522; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6523
6524 LOG("nsWindow::ResumeCompositorFlickering()\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::ResumeCompositorFlickering()\n"
, GetDebugTag().get()); } } while (0)
;
6525
6526 if (mIsDestroyed || !IsWaitingForCompositorResume()) {
6527 LOG(" early quit\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " early quit\n", GetDebugTag().get
()); } } while (0)
;
6528 return;
6529 }
6530
6531 MozClearHandleID(mCompositorPauseTimeoutID, g_source_remove);
6532
6533 // mCompositorWidgetDelegate can be deleted during timeout.
6534 // In such case just flip compositor back to enabled and let
6535 // SetCompositorWidgetDelegate() or Map event resume it.
6536 if (!mCompositorWidgetDelegate) {
6537 mCompositorState = COMPOSITOR_ENABLED;
6538 return;
6539 }
6540
6541 ResumeCompositorImpl();
6542}
6543
6544void nsWindow::ResumeCompositorFromCompositorThread() {
6545 nsCOMPtr<nsIRunnable> event =
6546 NewRunnableMethod("nsWindow::ResumeCompositorFlickering", this,
6547 &nsWindow::ResumeCompositorFlickering);
6548 NS_DispatchToMainThread(event.forget());
6549}
6550
6551void nsWindow::ResumeCompositorImpl() {
6552 MOZ_RELEASE_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 6552); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 6552; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6553
6554 LOG("nsWindow::ResumeCompositorImpl()\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::ResumeCompositorImpl()\n"
, GetDebugTag().get()); } } while (0)
;
6555
6556 MOZ_DIAGNOSTIC_ASSERT(mCompositorWidgetDelegate)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCompositorWidgetDelegate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCompositorWidgetDelegate)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("mCompositorWidgetDelegate"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 6556); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mCompositorWidgetDelegate"
")"); do { *((volatile int*)__null) = 6556; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6557 mCompositorWidgetDelegate->SetRenderingSurface(GetX11Window());
6558
6559 // As WaylandStartVsync needs mCompositorWidgetDelegate this is the right
6560 // time to start it.
6561 WaylandStartVsync();
6562
6563 CompositorBridgeChild* remoteRenderer = GetRemoteRenderer();
6564 MOZ_RELEASE_ASSERT(remoteRenderer)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(remoteRenderer)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(remoteRenderer))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("remoteRenderer"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 6564); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "remoteRenderer"
")"); do { *((volatile int*)__null) = 6564; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6565 remoteRenderer->SendResume();
6566 remoteRenderer->SendForcePresent(wr::RenderReasons::WIDGET);
6567 mCompositorState = COMPOSITOR_ENABLED;
6568}
6569
6570void nsWindow::WaylandStartVsync() {
6571#ifdef MOZ_WAYLAND1
6572 if (!mWaylandVsyncSource) {
6573 return;
6574 }
6575
6576 LOG_VSYNC("nsWindow::WaylandStartVsync")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, "nsWindow::WaylandStartVsync"
); } } while (0)
;
6577
6578 MOZ_DIAGNOSTIC_ASSERT(mCompositorWidgetDelegate)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCompositorWidgetDelegate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCompositorWidgetDelegate)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("mCompositorWidgetDelegate"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 6578); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mCompositorWidgetDelegate"
")"); do { *((volatile int*)__null) = 6578; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6579 if (mCompositorWidgetDelegate->AsGtkCompositorWidget() &&
6580 mCompositorWidgetDelegate->AsGtkCompositorWidget()
6581 ->GetNativeLayerRoot()) {
6582 LOG_VSYNC(" use source NativeLayerRootWayland")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, " use source NativeLayerRootWayland"
); } } while (0)
;
6583 mWaylandVsyncSource->MaybeUpdateSource(
6584 mCompositorWidgetDelegate->AsGtkCompositorWidget()
6585 ->GetNativeLayerRoot()
6586 ->AsNativeLayerRootWayland());
6587 } else {
6588 LOG_VSYNC(" use source mContainer")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, " use source mContainer"
); } } while (0)
;
6589 mWaylandVsyncSource->MaybeUpdateSource(mContainer);
6590 }
6591
6592 mWaylandVsyncSource->EnableMonitor();
6593#endif
6594}
6595
6596void nsWindow::WaylandStopVsync() {
6597#ifdef MOZ_WAYLAND1
6598 if (!mWaylandVsyncSource) {
6599 return;
6600 }
6601
6602 LOG_VSYNC("nsWindow::WaylandStopVsync")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, "nsWindow::WaylandStopVsync"
); } } while (0)
;
6603
6604 // The widget is going to be hidden, so clear the surface of our
6605 // vsync source.
6606 mWaylandVsyncSource->DisableMonitor();
6607 mWaylandVsyncSource->MaybeUpdateSource(nullptr);
6608#endif
6609}
6610
6611void nsWindow::NativeShow(bool aAction) {
6612 if (aAction) {
6613 // unset our flag now that our window has been shown
6614 mNeedsShow = true;
6615 auto removeShow = MakeScopeExit([&] { mNeedsShow = false; });
6616
6617 LOG("nsWindow::NativeShow show\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 show\n", GetDebugTag
().get()); } } while (0)
;
6618
6619 if (IsWaylandPopup()) {
6620 mPopupClosed = false;
6621 if (WaylandPopupConfigure()) {
6622 AddWindowToPopupHierarchy();
6623 UpdateWaylandPopupHierarchy();
6624 if (mPopupClosed) {
6625 return;
6626 }
6627 }
6628 }
6629 // Set up usertime/startupID metadata for the created window.
6630 // On X11 we use gtk_window_set_startup_id() so we need to call it
6631 // before show.
6632 if (GdkIsX11Display()) {
6633 SetUserTimeAndStartupTokenForActivatedWindow();
6634 }
6635 if (GdkIsWaylandDisplay()) {
6636 if (IsWaylandPopup()) {
6637 ShowWaylandPopupWindow();
6638 } else {
6639 ShowWaylandToplevelWindow();
6640 }
6641 } else {
6642 LOG(" calling gtk_widget_show(mShell)\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " calling gtk_widget_show(mShell)\n"
, GetDebugTag().get()); } } while (0)
;
6643 gtk_widget_show(mShell);
6644 }
6645 if (GdkIsWaylandDisplay()) {
6646 SetUserTimeAndStartupTokenForActivatedWindow();
6647#ifdef MOZ_WAYLAND1
6648 auto token = std::move(mWindowActivationTokenFromEnv);
6649 if (!token.IsEmpty()) {
6650 FocusWaylandWindow(token.get());
6651 }
6652#endif
6653 }
6654 if (mHiddenPopupPositioned && IsPopup()) {
6655 LOG(" re-position hidden popup window")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " re-position hidden popup window"
, GetDebugTag().get()); } } while (0)
;
6656 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), mPopupPosition.x, mPopupPosition.y);
6657 mHiddenPopupPositioned = false;
6658 }
6659 } else {
6660 LOG("nsWindow::NativeShow hide\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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", GetDebugTag
().get()); } } while (0)
;
6661 if (GdkIsWaylandDisplay()) {
6662 if (IsWaylandPopup()) {
6663 // We can't close tracked popups directly as they may have visible
6664 // child popups. Just mark is as closed and let
6665 // UpdateWaylandPopupHierarchy() do the job.
6666 if (IsInPopupHierarchy()) {
6667 WaylandPopupMarkAsClosed();
6668 UpdateWaylandPopupHierarchy();
6669 } else {
6670 // Close untracked popups directly.
6671 HideWaylandPopupWindow(/* aTemporaryHide */ false,
6672 /* aRemoveFromPopupList */ true);
6673 }
6674 } else {
6675 HideWaylandToplevelWindow();
6676 }
6677 } else {
6678 // Workaround window freezes on GTK versions before 3.21.2 by
6679 // ensuring that configure events get dispatched to windows before
6680 // they are unmapped. See bug 1225044.
6681 if (gtk_check_version(3, 21, 2) != nullptr && mPendingConfigures > 0) {
6682 GtkAllocation allocation;
6683 gtk_widget_get_allocation(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))), &allocation);
6684
6685 GdkEventConfigure event;
6686 PodZero(&event);
6687 event.type = GDK_CONFIGURE;
6688 event.window = mGdkWindow;
6689 event.send_event = TRUE(!(0));
6690 event.x = allocation.x;
6691 event.y = allocation.y;
6692 event.width = allocation.width;
6693 event.height = allocation.height;
6694
6695 auto* shellClass = GTK_WIDGET_GET_CLASS(mShell)((((GtkWidgetClass*) (((GTypeInstance*) ((mShell)))->g_class
))))
;
6696 for (unsigned int i = 0; i < mPendingConfigures; i++) {
6697 Unused << shellClass->configure_event(mShell, &event);
6698 }
6699 mPendingConfigures = 0;
6700 }
6701 gtk_widget_hide(mShell);
6702 }
6703 }
6704}
6705
6706void nsWindow::SetHasMappedToplevel(bool aState) {
6707 LOG("nsWindow::SetHasMappedToplevel(%d)", aState)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetHasMappedToplevel(%d)"
, GetDebugTag().get(), aState); } } while (0)
;
6708 if (aState == mHasMappedToplevel) {
6709 return;
6710 }
6711 // Even when aState == mHasMappedToplevel (as when this method is called
6712 // from Show()), child windows need to have their state checked, so don't
6713 // return early.
6714 mHasMappedToplevel = aState;
6715 if (aState && mNeedsToRetryCapturingMouse) {
6716 CaptureRollupEvents(true);
6717 MOZ_ASSERT(!mNeedsToRetryCapturingMouse)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mNeedsToRetryCapturingMouse)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mNeedsToRetryCapturingMouse
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"!mNeedsToRetryCapturingMouse", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 6717); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mNeedsToRetryCapturingMouse"
")"); do { *((volatile int*)__null) = 6717; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6718 }
6719}
6720
6721LayoutDeviceIntSize nsWindow::GetSafeWindowSize(LayoutDeviceIntSize aSize) {
6722 // The X protocol uses CARD32 for window sizes, but the server (1.11.3)
6723 // reads it as CARD16. Sizes of pixmaps, used for drawing, are (unsigned)
6724 // CARD16 in the protocol, but the server's ProcCreatePixmap returns
6725 // BadAlloc if dimensions cannot be represented by signed shorts.
6726 // Because we are creating Cairo surfaces to represent window buffers,
6727 // we also must ensure that the window can fit in a Cairo surface.
6728 LayoutDeviceIntSize result = aSize;
6729 int32_t maxSize = 32767;
6730 if (mWindowRenderer && mWindowRenderer->AsKnowsCompositor()) {
6731 maxSize = std::min(
6732 maxSize, mWindowRenderer->AsKnowsCompositor()->GetMaxTextureSize());
6733 }
6734 if (result.width > maxSize) {
6735 result.width = maxSize;
6736 }
6737 if (result.height > maxSize) {
6738 result.height = maxSize;
6739 }
6740 return result;
6741}
6742
6743void nsWindow::SetTransparencyMode(TransparencyMode aMode) {
6744 const bool isTransparent = aMode == TransparencyMode::Transparent;
6745
6746 if (mIsTransparent == isTransparent) {
6747 return;
6748 }
6749
6750 if (mWindowType != WindowType::Popup) {
6751 // https://bugzilla.mozilla.org/show_bug.cgi?id=1344839 reported
6752 // problems cleaning the layer manager for toplevel windows.
6753 // Ignore the request so as to workaround that.
6754 // mIsTransparent is set in Create() if transparency may be required.
6755 if (isTransparent) {
6756 NS_WARNING("Transparent mode not supported on non-popup windows.")NS_DebugBreak(NS_DEBUG_WARNING, "Transparent mode not supported on non-popup windows."
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 6756)
;
6757 }
6758 return;
6759 }
6760
6761 mIsTransparent = isTransparent;
6762
6763 if (!mHasAlphaVisual) {
6764 // The choice of layer manager depends on
6765 // GtkCompositorWidgetInitData::Shaped(), which will need to change, so
6766 // clean out the old layer manager.
6767 DestroyLayerManager();
6768 }
6769}
6770
6771TransparencyMode nsWindow::GetTransparencyMode() {
6772 return mIsTransparent ? TransparencyMode::Transparent
6773 : TransparencyMode::Opaque;
6774}
6775
6776gint nsWindow::GetInputRegionMarginInGdkCoords() {
6777 return DevicePixelsToGdkCoordRoundDown(mInputRegion.mMargin);
6778}
6779
6780void nsWindow::SetInputRegion(const InputRegion& aInputRegion) {
6781 mInputRegion = aInputRegion;
6782
6783 GdkWindow* window = GetToplevelGdkWindow();
6784 if (!window) {
6785 return;
6786 }
6787
6788 LOG("nsWindow::SetInputRegion(%d, %d)", aInputRegion.mFullyTransparent,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetInputRegion(%d, %d)",
GetDebugTag().get(), aInputRegion.mFullyTransparent, int(aInputRegion
.mMargin)); } } while (0)
6789 int(aInputRegion.mMargin))do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetInputRegion(%d, %d)",
GetDebugTag().get(), aInputRegion.mFullyTransparent, int(aInputRegion
.mMargin)); } } while (0)
;
6790
6791 cairo_rectangle_int_t rect = {0, 0, 0, 0};
6792 cairo_region_t* region = nullptr;
6793 auto releaseRegion = MakeScopeExit([&] {
6794 if (region) {
6795 cairo_region_destroy(region);
6796 }
6797 });
6798
6799 if (aInputRegion.mFullyTransparent) {
6800 region = cairo_region_create_rectangle(&rect);
6801 } else if (aInputRegion.mMargin != 0) {
6802 LayoutDeviceIntRect inputRegion(LayoutDeviceIntPoint(), mLastSizeRequest);
6803 inputRegion.Deflate(aInputRegion.mMargin);
6804 GdkRectangle gdkRect = DevicePixelsToGdkRectRoundOut(inputRegion);
6805 rect = {gdkRect.x, gdkRect.y, gdkRect.width, gdkRect.height};
6806 region = cairo_region_create_rectangle(&rect);
6807 }
6808
6809 gdk_window_input_shape_combine_region(window, region, 0, 0);
6810
6811 // On Wayland gdk_window_input_shape_combine_region() call is cached and
6812 // applied to underlying wl_surface when GdkWindow is repainted.
6813 // Force repaint of GdkWindow to apply the change immediately.
6814 if (GdkIsWaylandDisplay()) {
6815 gdk_window_invalidate_rect(window, nullptr, false);
6816 }
6817}
6818
6819// For setting the draggable titlebar region from CSS
6820// with -moz-window-dragging: drag.
6821void nsWindow::UpdateWindowDraggingRegion(
6822 const LayoutDeviceIntRegion& aRegion) {
6823 if (mDraggableRegion != aRegion) {
6824 mDraggableRegion = aRegion;
6825 }
6826}
6827
6828#ifdef MOZ_ENABLE_DBUS1
6829void nsWindow::SetDBusMenuBar(
6830 RefPtr<mozilla::widget::DBusMenuBar> aDbusMenuBar) {
6831 mDBusMenuBar = std::move(aDbusMenuBar);
6832}
6833#endif
6834
6835LayoutDeviceIntCoord nsWindow::GetTitlebarRadius() {
6836 MOZ_RELEASE_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 6836); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 6836; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6837 int32_t cssCoord = LookAndFeel::GetInt(LookAndFeel::IntID::TitlebarRadius);
6838 return GdkCoordToDevicePixels(cssCoord);
6839}
6840
6841LayoutDeviceIntRegion nsWindow::GetOpaqueRegion() const {
6842 AutoReadLock r(mOpaqueRegionLock);
6843 return mOpaqueRegion;
6844}
6845
6846// See subtract_corners_from_region() at gtk/gtkwindow.c
6847// We need to subtract corners from toplevel window opaque region
6848// to draw transparent corners of default Gtk titlebar.
6849// Both implementations (cairo_region_t and wl_region) needs to be synced.
6850static void SubtractTitlebarCorners(LayoutDeviceIntRegion& aRegion,
6851 const LayoutDeviceIntRect& aRect,
6852 LayoutDeviceIntCoord aRadius) {
6853 if (!aRadius) {
6854 return;
6855 }
6856 const LayoutDeviceIntSize size(aRadius, aRadius);
6857 aRegion.SubOut(LayoutDeviceIntRect(aRect.TopLeft(), size));
6858 aRegion.SubOut(LayoutDeviceIntRect(
6859 aRect.TopRight() - LayoutDeviceIntPoint(aRadius, 0), size));
6860 aRegion.SubOut(LayoutDeviceIntRect(
6861 aRect.BottomLeft() - LayoutDeviceIntPoint(0, aRadius), size));
6862 aRegion.SubOut(LayoutDeviceIntRect(
6863 aRect.BottomRight() - LayoutDeviceIntPoint(aRadius, aRadius), size));
6864}
6865
6866void nsWindow::UpdateOpaqueRegion(const LayoutDeviceIntRegion& aRegion) {
6867 LayoutDeviceIntRegion region = aRegion;
6868 SubtractTitlebarCorners(region, LayoutDeviceIntRect({}, mBounds.Size()),
6869 GetTitlebarRadius());
6870 {
6871 AutoReadLock r(mOpaqueRegionLock);
6872 if (mOpaqueRegion == region) {
6873 return;
6874 }
6875 }
6876 {
6877 AutoWriteLock w(mOpaqueRegionLock);
6878 mOpaqueRegion = region;
6879 }
6880 UpdateOpaqueRegionInternal();
6881}
6882
6883void nsWindow::UpdateOpaqueRegionInternal() {
6884 if (!mCompositedScreen) {
6885 return;
6886 }
6887
6888 if (!IsTopLevelWindowType()) {
6889 // We need to clear target buffer alpha values of popup windows as
6890 // SW-WR paints with alpha blending (see Bug 1674473).
6891 return;
6892 }
6893
6894 GdkWindow* window = GetToplevelGdkWindow();
6895 if (!window) {
6896 return;
6897 }
6898 MOZ_ASSERT(gdk_window_get_window_type(window) == GDK_WINDOW_TOPLEVEL)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gdk_window_get_window_type(window) == GDK_WINDOW_TOPLEVEL
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(gdk_window_get_window_type(window) == GDK_WINDOW_TOPLEVEL
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"gdk_window_get_window_type(window) == GDK_WINDOW_TOPLEVEL", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 6898); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gdk_window_get_window_type(window) == GDK_WINDOW_TOPLEVEL"
")"); do { *((volatile int*)__null) = 6898; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6899
6900 {
6901 AutoReadLock lock(mOpaqueRegionLock);
6902 cairo_region_t* region = nullptr;
6903 if (!mOpaqueRegion.IsEmpty()) {
6904 // NOTE(emilio): The opaque region is relative to our mContainer /
6905 // mGdkWindow / inner window, but we're setting it on the top level
6906 // GdkWindow / mShell.
6907 //
6908 // So we need to offset the rects by the position of mGdkWindow, in order
6909 // for them to be in the right coordinate system.
6910 GdkPoint offset{0, 0};
6911 gdk_window_get_position(mGdkWindow, &offset.x, &offset.y);
6912
6913 region = cairo_region_create();
6914
6915 for (auto iter = mOpaqueRegion.RectIter(); !iter.Done(); iter.Next()) {
6916 auto gdkRect = DevicePixelsToGdkRectRoundIn(iter.Get());
6917 cairo_rectangle_int_t rect = {gdkRect.x + offset.x,
6918 gdkRect.y + offset.y, gdkRect.width,
6919 gdkRect.height};
6920 cairo_region_union_rectangle(region, &rect);
6921 }
6922 }
6923 gdk_window_set_opaque_region(window, region);
6924 if (region) {
6925 cairo_region_destroy(region);
6926 }
6927 }
6928
6929#ifdef MOZ_WAYLAND1
6930 if (GdkIsWaylandDisplay()) {
6931 moz_container_wayland_update_opaque_region(mContainer);
6932 }
6933#endif
6934}
6935
6936bool nsWindow::IsChromeWindowTitlebar() {
6937 return mDrawInTitlebar && !mIsPIPWindow &&
6938 mWindowType == WindowType::TopLevel;
6939}
6940
6941bool nsWindow::DoDrawTilebarCorners() {
6942 return IsChromeWindowTitlebar() && mSizeMode == nsSizeMode_Normal &&
6943 !mIsTiled;
6944}
6945
6946GtkWidget* nsWindow::GetToplevelWidget() const { return mShell; }
6947
6948GdkWindow* nsWindow::GetToplevelGdkWindow() const {
6949 return gtk_widget_get_window(mShell);
6950}
6951
6952nsWindow* nsWindow::GetContainerWindow() const {
6953 GtkWidget* owningWidget = GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer)))));
6954 if (!owningWidget) {
6955 return nullptr;
6956 }
6957
6958 nsWindow* window = get_window_for_gtk_widget(owningWidget);
6959 NS_ASSERTION(window, "No nsWindow for container widget")do { if (!(window)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "No nsWindow for container widget"
, "window", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 6959); MOZ_PretendNoReturn(); } } while (0)
;
6960 return window;
6961}
6962
6963void nsWindow::SetUrgencyHint(GtkWidget* top_window, bool state) {
6964 LOG(" nsWindow::SetUrgencyHint widget %p\n", top_window)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetUrgencyHint widget %p\n"
, GetDebugTag().get(), top_window); } } while (0)
;
6965 if (!top_window) {
6966 return;
6967 }
6968 GdkWindow* window = gtk_widget_get_window(top_window);
6969 if (!window) {
6970 return;
6971 }
6972 // TODO: Use xdg-activation on Wayland?
6973 gdk_window_set_urgency_hint(window, state);
6974}
6975
6976void nsWindow::SetDefaultIcon(void) { SetIcon(u"default"_ns); }
6977
6978gint nsWindow::ConvertBorderStyles(BorderStyle aStyle) {
6979 gint w = 0;
6980
6981 if (aStyle == BorderStyle::Default) {
6982 return -1;
6983 }
6984
6985 // note that we don't handle BorderStyle::Close yet
6986 if (aStyle & BorderStyle::All) w |= GDK_DECOR_ALL;
6987 if (aStyle & BorderStyle::Border) w |= GDK_DECOR_BORDER;
6988 if (aStyle & BorderStyle::ResizeH) w |= GDK_DECOR_RESIZEH;
6989 if (aStyle & BorderStyle::Title) w |= GDK_DECOR_TITLE;
6990 if (aStyle & BorderStyle::Menu) w |= GDK_DECOR_MENU;
6991 if (aStyle & BorderStyle::Minimize) w |= GDK_DECOR_MINIMIZE;
6992 if (aStyle & BorderStyle::Maximize) w |= GDK_DECOR_MAXIMIZE;
6993
6994 return w;
6995}
6996
6997class FullscreenTransitionWindow final : public nsISupports {
6998 public:
6999 NS_DECL_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::false_type;
protected: nsAutoRefCnt mRefCnt; nsAutoOwningThread _mOwningThread
; public:
7000
7001 explicit FullscreenTransitionWindow(GtkWidget* aWidget);
7002
7003 GtkWidget* mWindow;
7004
7005 private:
7006 ~FullscreenTransitionWindow();
7007};
7008
7009NS_IMPL_ISUPPORTS0(FullscreenTransitionWindow)MozExternalRefCountType FullscreenTransitionWindow::AddRef(void
) { static_assert(!std::is_destructible_v<FullscreenTransitionWindow
>, "Reference-counted class " "FullscreenTransitionWindow"
" should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7009); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
7009; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("FullscreenTransitionWindow" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("FullscreenTransitionWindow" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"FullscreenTransitionWindow\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7009); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"FullscreenTransitionWindow\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 7009; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("FullscreenTransitionWindow" " not thread-safe"
); nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"FullscreenTransitionWindow"), (uint32_t)(sizeof(*this))); return
count; } MozExternalRefCountType FullscreenTransitionWindow::
Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7009); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 7009
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("FullscreenTransitionWindow" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("FullscreenTransitionWindow" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"FullscreenTransitionWindow\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7009); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"FullscreenTransitionWindow\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 7009; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("FullscreenTransitionWindow" " not thread-safe"
); const char* const nametmp = "FullscreenTransitionWindow"; nsrefcnt
count = --mRefCnt; NS_LogRelease((this), (count), (nametmp))
; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return
count; } nsresult FullscreenTransitionWindow::QueryInterface
(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7009); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<FullscreenTransitionWindow, nsISupports>
, int32_t( reinterpret_cast<char*>(static_cast<nsISupports
*>((FullscreenTransitionWindow*)0x1000)) - reinterpret_cast
<char*>((FullscreenTransitionWindow*)0x1000))}, { nullptr
, 0 } } ; static_assert((sizeof(table) / sizeof(table[0])) >
1, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast
<void*>(this), aIID, aInstancePtr, table); return rv; }
7010
7011FullscreenTransitionWindow::FullscreenTransitionWindow(GtkWidget* aWidget) {
7012 mWindow = gtk_window_new(GTK_WINDOW_POPUP);
7013 GtkWindow* gtkWin = GTK_WINDOW(mWindow)((((GtkWindow*) (void *) ((mWindow)))));
7014
7015 gtk_window_set_type_hint(gtkWin, GDK_WINDOW_TYPE_HINT_SPLASHSCREEN);
7016 GtkWindowSetTransientFor(gtkWin, GTK_WINDOW(aWidget)((((GtkWindow*) (void *) ((aWidget))))));
7017 gtk_window_set_decorated(gtkWin, false);
7018
7019 GdkWindow* gdkWin = gtk_widget_get_window(aWidget);
7020 GdkScreen* screen = gtk_widget_get_screen(aWidget);
7021 gint monitorNum = gdk_screen_get_monitor_at_window(screen, gdkWin);
7022 GdkRectangle monitorRect;
7023 gdk_screen_get_monitor_geometry(screen, monitorNum, &monitorRect);
7024 gtk_window_set_screen(gtkWin, screen);
7025 gtk_window_move(gtkWin, monitorRect.x, monitorRect.y);
7026 MOZ_ASSERT(monitorRect.width > 0 && monitorRect.height > 0,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(monitorRect.width > 0 && monitorRect.height
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(monitorRect.width > 0 && monitorRect.height
> 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("monitorRect.width > 0 && monitorRect.height > 0"
" (" "Can't resize window smaller than 1x1." ")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7027); AnnotateMozCrashReason("MOZ_ASSERT" "(" "monitorRect.width > 0 && monitorRect.height > 0"
") (" "Can't resize window smaller than 1x1." ")"); do { *((
volatile int*)__null) = 7027; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
7027 "Can't resize window smaller than 1x1.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(monitorRect.width > 0 && monitorRect.height
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(monitorRect.width > 0 && monitorRect.height
> 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("monitorRect.width > 0 && monitorRect.height > 0"
" (" "Can't resize window smaller than 1x1." ")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7027); AnnotateMozCrashReason("MOZ_ASSERT" "(" "monitorRect.width > 0 && monitorRect.height > 0"
") (" "Can't resize window smaller than 1x1." ")"); do { *((
volatile int*)__null) = 7027; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
7028 gtk_window_resize(gtkWin, monitorRect.width, monitorRect.height);
7029
7030 GdkRGBA bgColor;
7031 bgColor.red = bgColor.green = bgColor.blue = 0.0;
7032 bgColor.alpha = 1.0;
7033 gtk_widget_override_background_color(mWindow, GTK_STATE_FLAG_NORMAL,
7034 &bgColor);
7035
7036 gtk_widget_set_opacity(mWindow, 0.0);
7037 gtk_widget_show(mWindow);
7038}
7039
7040FullscreenTransitionWindow::~FullscreenTransitionWindow() {
7041 gtk_widget_destroy(mWindow);
7042}
7043
7044class FullscreenTransitionData {
7045 public:
7046 FullscreenTransitionData(nsIWidget::FullscreenTransitionStage aStage,
7047 uint16_t aDuration, nsIRunnable* aCallback,
7048 FullscreenTransitionWindow* aWindow)
7049 : mStage(aStage),
7050 mStartTime(TimeStamp::Now()),
7051 mDuration(TimeDuration::FromMilliseconds(aDuration)),
7052 mCallback(aCallback),
7053 mWindow(aWindow) {}
7054
7055 static const guint sInterval = 1000 / 30; // 30fps
7056 static gboolean TimeoutCallback(gpointer aData);
7057
7058 private:
7059 nsIWidget::FullscreenTransitionStage mStage;
7060 TimeStamp mStartTime;
7061 TimeDuration mDuration;
7062 nsCOMPtr<nsIRunnable> mCallback;
7063 RefPtr<FullscreenTransitionWindow> mWindow;
7064};
7065
7066/* static */
7067gboolean FullscreenTransitionData::TimeoutCallback(gpointer aData) {
7068 bool finishing = false;
7069 auto* data = static_cast<FullscreenTransitionData*>(aData);
7070 gdouble opacity = (TimeStamp::Now() - data->mStartTime) / data->mDuration;
7071 if (opacity >= 1.0) {
7072 opacity = 1.0;
7073 finishing = true;
7074 }
7075 if (data->mStage == nsIWidget::eAfterFullscreenToggle) {
7076 opacity = 1.0 - opacity;
7077 }
7078 gtk_widget_set_opacity(data->mWindow->mWindow, opacity);
7079
7080 if (!finishing) {
7081 return TRUE(!(0));
7082 }
7083 NS_DispatchToMainThread(data->mCallback.forget());
7084 delete data;
7085 return FALSE(0);
7086}
7087
7088/* virtual */
7089bool nsWindow::PrepareForFullscreenTransition(nsISupports** aData) {
7090 if (!mCompositedScreen) {
7091 return false;
7092 }
7093 *aData = do_AddRef(new FullscreenTransitionWindow(mShell)).take();
7094 return true;
7095}
7096
7097/* virtual */
7098void nsWindow::PerformFullscreenTransition(FullscreenTransitionStage aStage,
7099 uint16_t aDuration,
7100 nsISupports* aData,
7101 nsIRunnable* aCallback) {
7102 auto* data = static_cast<FullscreenTransitionWindow*>(aData);
7103 // This will be released at the end of the last timeout callback for it.
7104 auto* transitionData =
7105 new FullscreenTransitionData(aStage, aDuration, aCallback, data);
7106 g_timeout_add_full(G_PRIORITY_HIGH-100, FullscreenTransitionData::sInterval,
7107 FullscreenTransitionData::TimeoutCallback, transitionData,
7108 nullptr);
7109}
7110
7111already_AddRefed<widget::Screen> nsWindow::GetWidgetScreen() {
7112 // Wayland can read screen directly
7113 if (GdkIsWaylandDisplay()) {
7114 if (RefPtr<Screen> screen = ScreenHelperGTK::GetScreenForWindow(this)) {
7115 return screen.forget();
7116 }
7117 }
7118
7119 // GetScreenBounds() is slow for the GTK port so we override and use
7120 // mBounds directly.
7121 ScreenManager& screenManager = ScreenManager::GetSingleton();
7122 LayoutDeviceIntRect bounds = mBounds;
7123 DesktopIntRect deskBounds = RoundedToInt(bounds / GetDesktopToDeviceScale());
7124 return screenManager.ScreenForRect(deskBounds);
7125}
7126
7127RefPtr<VsyncDispatcher> nsWindow::GetVsyncDispatcher() {
7128#ifdef MOZ_WAYLAND1
7129 if (mWaylandVsyncDispatcher) {
7130 return mWaylandVsyncDispatcher;
7131 }
7132#endif
7133 return nullptr;
7134}
7135
7136bool nsWindow::SynchronouslyRepaintOnResize() {
7137 if (GdkIsWaylandDisplay()) {
7138 // See Bug 1734368
7139 // Don't request synchronous repaint on HW accelerated backend - mesa can be
7140 // deadlocked when it's missing back buffer and main event loop is blocked.
7141 return false;
7142 }
7143
7144 // default is synced repaint.
7145 return true;
7146}
7147
7148void nsWindow::KioskLockOnMonitor() {
7149 // Available as of GTK 3.18+
7150 static auto sGdkWindowFullscreenOnMonitor =
7151 (void (*)(GdkWindow* window, gint monitor))dlsym(
7152 RTLD_DEFAULT((void *) 0), "gdk_window_fullscreen_on_monitor");
7153
7154 if (!sGdkWindowFullscreenOnMonitor) {
7155 return;
7156 }
7157
7158 int monitor = mKioskMonitor.value();
7159 if (monitor < 0 || monitor >= ScreenHelperGTK::GetMonitorCount()) {
7160 LOG("nsWindow::KioskLockOnMonitor() wrong monitor number! (%d)\n", monitor)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::KioskLockOnMonitor() wrong monitor number! (%d)\n"
, GetDebugTag().get(), monitor); } } while (0)
;
7161 return;
7162 }
7163
7164 LOG("nsWindow::KioskLockOnMonitor() locked on %d\n", monitor)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::KioskLockOnMonitor() locked on %d\n"
, GetDebugTag().get(), monitor); } } while (0)
;
7165 sGdkWindowFullscreenOnMonitor(GetToplevelGdkWindow(), monitor);
7166}
7167
7168static bool IsFullscreenSupported(GtkWidget* aShell) {
7169#ifdef MOZ_X111
7170 GdkScreen* screen = gtk_widget_get_screen(aShell);
7171 GdkAtom atom = gdk_atom_intern("_NET_WM_STATE_FULLSCREEN", FALSE(0));
7172 return gdk_x11_screen_supports_net_wm_hint(screen, atom);
7173#else
7174 return true;
7175#endif
7176}
7177
7178nsresult nsWindow::MakeFullScreen(bool aFullScreen) {
7179 LOG("nsWindow::MakeFullScreen aFullScreen %d\n", aFullScreen)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::MakeFullScreen aFullScreen %d\n"
, GetDebugTag().get(), aFullScreen); } } while (0)
;
7180
7181 if (GdkIsX11Display() && !IsFullscreenSupported(mShell)) {
7182 return NS_ERROR_NOT_AVAILABLE;
7183 }
7184
7185 if (aFullScreen) {
7186 if (mSizeMode != nsSizeMode_Fullscreen &&
7187 mSizeMode != nsSizeMode_Minimized) {
7188 mLastSizeModeBeforeFullscreen = mSizeMode;
7189 }
7190 if (mIsPIPWindow) {
7191 gtk_window_set_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), GDK_WINDOW_TYPE_HINT_NORMAL);
7192 if (gUseAspectRatio) {
7193 mAspectRatioSaved = mAspectRatio;
7194 mAspectRatio = 0.0f;
7195 ApplySizeConstraints();
7196 }
7197 }
7198
7199 if (mKioskMonitor.isSome()) {
7200 KioskLockOnMonitor();
7201 } else {
7202 gtk_window_fullscreen(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
7203 }
7204 } else {
7205 // Kiosk mode always use fullscreen mode.
7206 if (gKioskMode) {
7207 return NS_ERROR_NOT_AVAILABLE;
7208 }
7209
7210 gtk_window_unfullscreen(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
7211
7212 if (mIsPIPWindow && gUseAspectRatio) {
7213 mAspectRatio = mAspectRatioSaved;
7214 // ApplySizeConstraints();
7215 }
7216 }
7217
7218 MOZ_ASSERT(mLastSizeModeBeforeFullscreen != nsSizeMode_Fullscreen)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mLastSizeModeBeforeFullscreen != nsSizeMode_Fullscreen
)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mLastSizeModeBeforeFullscreen != nsSizeMode_Fullscreen
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mLastSizeModeBeforeFullscreen != nsSizeMode_Fullscreen", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7218); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mLastSizeModeBeforeFullscreen != nsSizeMode_Fullscreen"
")"); do { *((volatile int*)__null) = 7218; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7219 return NS_OK;
7220}
7221
7222void nsWindow::SetWindowDecoration(BorderStyle aStyle) {
7223 LOG("nsWindow::SetWindowDecoration() Border style %x\n", int(aStyle))do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetWindowDecoration() Border style %x\n"
, GetDebugTag().get(), int(aStyle)); } } while (0)
;
7224
7225 // We can't use mGdkWindow directly here as it can be
7226 // derived from mContainer which is not a top-level GdkWindow.
7227 GdkWindow* window = GetToplevelGdkWindow();
7228
7229 // Sawfish, metacity, and presumably other window managers get
7230 // confused if we change the window decorations while the window
7231 // is visible.
7232 bool wasVisible = false;
7233 if (gdk_window_is_visible(window)) {
7234 gdk_window_hide(window);
7235 wasVisible = true;
7236 }
7237
7238 gint wmd = ConvertBorderStyles(aStyle);
7239 if (wmd != -1) gdk_window_set_decorations(window, (GdkWMDecoration)wmd);
7240
7241 if (wasVisible) gdk_window_show(window);
7242
7243 // For some window managers, adding or removing window decorations
7244 // requires unmapping and remapping our toplevel window. Go ahead
7245 // and flush the queue here so that we don't end up with a BadWindow
7246 // error later when this happens (when the persistence timer fires
7247 // and GetWindowPos is called)
7248#ifdef MOZ_X111
7249 if (GdkIsX11Display()) {
7250 XSync(GDK_DISPLAY_XDISPLAY(gdk_display_get_default())(gdk_x11_display_get_xdisplay (gdk_display_get_default())), X11False0);
7251 } else
7252#endif /* MOZ_X11 */
7253 {
7254 gdk_flush();
7255 }
7256}
7257
7258void nsWindow::HideWindowChrome(bool aShouldHide) {
7259 SetWindowDecoration(aShouldHide ? BorderStyle::None : mBorderStyle);
7260}
7261
7262bool nsWindow::CheckForRollup(gdouble aMouseX, gdouble aMouseY, bool aIsWheel,
7263 bool aAlwaysRollup) {
7264 LOG("nsWindow::CheckForRollup() aAlwaysRollup %d", aAlwaysRollup)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::CheckForRollup() aAlwaysRollup %d"
, GetDebugTag().get(), aAlwaysRollup); } } while (0)
;
7265 nsIRollupListener* rollupListener = GetActiveRollupListener();
7266 nsCOMPtr<nsIWidget> rollupWidget;
7267 if (rollupListener) {
7268 rollupWidget = rollupListener->GetRollupWidget();
7269 }
7270 if (!rollupWidget) {
7271 return false;
7272 }
7273
7274 auto* rollupWindow =
7275 (GdkWindow*)rollupWidget->GetNativeData(NS_NATIVE_WINDOW0);
7276 if (!aAlwaysRollup && is_mouse_in_window(rollupWindow, aMouseX, aMouseY)) {
7277 return false;
7278 }
7279 bool retVal = false;
7280 if (aIsWheel) {
7281 retVal = rollupListener->ShouldConsumeOnMouseWheelEvent();
7282 if (!rollupListener->ShouldRollupOnMouseWheelEvent()) {
7283 return retVal;
7284 }
7285 }
7286 LayoutDeviceIntPoint point;
7287 nsIRollupListener::RollupOptions options{0,
7288 nsIRollupListener::FlushViews::Yes};
7289 // if we're dealing with menus, we probably have submenus and
7290 // we don't want to rollup if the click is in a parent menu of
7291 // the current submenu
7292 if (!aAlwaysRollup) {
7293 AutoTArray<nsIWidget*, 5> widgetChain;
7294 uint32_t sameTypeCount =
7295 rollupListener->GetSubmenuWidgetChain(&widgetChain);
7296 for (unsigned long i = 0; i < widgetChain.Length(); ++i) {
7297 nsIWidget* widget = widgetChain[i];
7298 auto* currWindow = (GdkWindow*)widget->GetNativeData(NS_NATIVE_WINDOW0);
7299 if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) {
7300 // Don't roll up if the mouse event occurred within a menu of the same
7301 // type.
7302 // If the mouse event occurred in a menu higher than that, roll up, but
7303 // pass the number of popups to Rollup so that only those of the same
7304 // type close up.
7305 if (i < sameTypeCount) {
7306 return retVal;
7307 }
7308 options.mCount = sameTypeCount;
7309 break;
7310 }
7311 } // foreach parent menu widget
7312 if (!aIsWheel) {
7313 point = GdkEventCoordsToDevicePixels(aMouseX, aMouseY);
7314 options.mPoint = &point;
7315 }
7316 }
7317
7318 if (mSizeMode == nsSizeMode_Minimized) {
7319 // When we try to rollup in a minimized window, transitionend events for
7320 // panels might not fire and thus we might not hide the popup after all,
7321 // see bug 1810797.
7322 options.mAllowAnimations = nsIRollupListener::AllowAnimations::No;
7323 }
7324
7325 if (rollupListener->Rollup(options)) {
7326 retVal = true;
7327 }
7328 return retVal;
7329}
7330
7331bool nsWindow::DragInProgress() {
7332 nsCOMPtr<nsIDragService> dragService =
7333 do_GetService("@mozilla.org/widget/dragservice;1");
7334 if (!dragService) {
7335 return false;
7336 }
7337
7338 nsCOMPtr<nsIDragSession> currentDragSession =
7339 dragService->GetCurrentSession(this);
7340 return !!currentDragSession;
7341}
7342
7343// This is an ugly workaround for
7344// https://bugzilla.mozilla.org/show_bug.cgi?id=1622107
7345// We try to detect when Wayland compositor / gtk fails to deliver
7346// info about finished D&D operations and cancel it on our own.
7347MOZ_CAN_RUN_SCRIPT static void WaylandDragWorkaround(nsWindow* aWindow,
7348 GdkEventButton* aEvent) {
7349 static int buttonPressCountWithDrag = 0;
7350
7351 // We track only left button state as Firefox performs D&D on left
7352 // button only.
7353 if (aEvent->button != 1 || aEvent->type != GDK_BUTTON_PRESS) {
7354 return;
7355 }
7356
7357 nsCOMPtr<nsIDragService> dragService =
7358 do_GetService("@mozilla.org/widget/dragservice;1");
7359 if (!dragService) {
7360 return;
7361 }
7362 nsCOMPtr<nsIDragSession> currentDragSession =
7363 dragService->GetCurrentSession(aWindow);
7364
7365 if (!currentDragSession) {
7366 buttonPressCountWithDrag = 0;
7367 return;
7368 }
7369
7370 buttonPressCountWithDrag++;
7371 if (buttonPressCountWithDrag > 1) {
7372 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "Quit unfinished Wayland Drag and Drop operation. Buggy Wayland "
"compositor?", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7374)
7373 "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, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7374)
7374 "compositor?")NS_DebugBreak(NS_DEBUG_WARNING, "Quit unfinished Wayland Drag and Drop operation. Buggy Wayland "
"compositor?", nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7374)
;
7375 buttonPressCountWithDrag = 0;
7376 currentDragSession->EndDragSession(false, 0);
7377 }
7378}
7379
7380static nsWindow* get_window_for_gtk_widget(GtkWidget* widget) {
7381 gpointer user_data = g_object_get_data(G_OBJECT(widget)((((GObject*) (void *) ((widget))))), "nsWindow");
7382 return static_cast<nsWindow*>(user_data);
7383}
7384
7385static nsWindow* get_window_for_gdk_window(GdkWindow* window) {
7386 gpointer user_data = g_object_get_data(G_OBJECT(window)((((GObject*) (void *) ((window))))), "nsWindow");
7387 return static_cast<nsWindow*>(user_data);
7388}
7389
7390static bool is_mouse_in_window(GdkWindow* aWindow, gdouble aMouseX,
7391 gdouble aMouseY) {
7392 GdkWindow* window = aWindow;
7393 if (!window) {
7394 return false;
7395 }
7396
7397 gint x = 0;
7398 gint y = 0;
7399
7400 {
7401 gint offsetX = 0;
7402 gint offsetY = 0;
7403
7404 while (window) {
7405 gint tmpX = 0;
7406 gint tmpY = 0;
7407
7408 gdk_window_get_position(window, &tmpX, &tmpY);
7409 GtkWidget* widget = get_gtk_widget_for_gdk_window(window);
7410
7411 // if this is a window, compute x and y given its origin and our
7412 // offset
7413 if (GTK_IS_WINDOW(widget)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(widget)); GType __t = ((gtk_window_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; }))))
) {
7414 x = tmpX + offsetX;
7415 y = tmpY + offsetY;
7416 break;
7417 }
7418
7419 offsetX += tmpX;
7420 offsetY += tmpY;
7421 window = gdk_window_get_parent(window);
7422 }
7423 }
7424
7425 gint margin = 0;
7426 if (nsWindow* w = get_window_for_gdk_window(aWindow)) {
7427 margin = w->GetInputRegionMarginInGdkCoords();
7428 }
7429
7430 x += margin;
7431 y += margin;
7432
7433 gint w = gdk_window_get_width(aWindow) - margin;
7434 gint h = gdk_window_get_height(aWindow) - margin;
7435
7436 return aMouseX > x && aMouseX < x + w && aMouseY > y && aMouseY < y + h;
7437}
7438
7439static GtkWidget* get_gtk_widget_for_gdk_window(GdkWindow* window) {
7440 gpointer user_data = nullptr;
7441 gdk_window_get_user_data(window, &user_data);
7442
7443 return GTK_WIDGET(user_data)((((GtkWidget*) (void *) ((user_data)))));
7444}
7445
7446static GdkCursor* get_gtk_cursor_from_type(uint8_t aCursorType) {
7447 GdkDisplay* defaultDisplay = gdk_display_get_default();
7448 GdkCursor* gdkcursor = nullptr;
7449
7450 // GtkCursors are defined at nsGtkCursors.h
7451 if (aCursorType > MOZ_CURSOR_NONE) {
7452 return nullptr;
7453 }
7454
7455 // If by now we don't have a xcursor, this means we have to make a custom
7456 // one. First, we try creating a named cursor based on the hash of our
7457 // custom bitmap, as libXcursor has some magic to convert bitmapped cursors
7458 // to themed cursors
7459 if (GtkCursors[aCursorType].hash) {
7460 gdkcursor =
7461 gdk_cursor_new_from_name(defaultDisplay, GtkCursors[aCursorType].hash);
7462 if (gdkcursor) {
7463 return gdkcursor;
7464 }
7465 }
7466
7467 LOGW("get_gtk_cursor_from_type(): Failed to get cursor type %d, try bitmap",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, "get_gtk_cursor_from_type(): Failed to get cursor type %d, try bitmap"
, aCursorType); } } while (0)
7468 aCursorType)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, "get_gtk_cursor_from_type(): Failed to get cursor type %d, try bitmap"
, aCursorType); } } while (0)
;
7469
7470 // If we still don't have a xcursor, we now really create a bitmap cursor
7471 GdkPixbuf* cursor_pixbuf =
7472 gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE(!(0)), 8, 32, 32);
7473 if (!cursor_pixbuf) {
7474 return nullptr;
7475 }
7476
7477 guchar* data = gdk_pixbuf_get_pixels(cursor_pixbuf);
7478
7479 // Read data from GtkCursors and compose RGBA surface from 1bit bitmap and
7480 // mask GtkCursors bits and mask are 32x32 monochrome bitmaps (1 bit for
7481 // each pixel) so it's 128 byte array (4 bytes for are one bitmap row and
7482 // there are 32 rows here).
7483 const unsigned char* bits = GtkCursors[aCursorType].bits;
7484 const unsigned char* mask_bits = GtkCursors[aCursorType].mask_bits;
7485
7486 for (int i = 0; i < 128; i++) {
7487 char bit = (char)*bits++;
7488 char mask = (char)*mask_bits++;
7489 for (int j = 0; j < 8; j++) {
7490 unsigned char pix = ~(((bit >> j) & 0x01) * 0xff);
7491 *data++ = pix;
7492 *data++ = pix;
7493 *data++ = pix;
7494 *data++ = (((mask >> j) & 0x01) * 0xff);
7495 }
7496 }
7497
7498 gdkcursor = gdk_cursor_new_from_pixbuf(
7499 gdk_display_get_default(), cursor_pixbuf, GtkCursors[aCursorType].hot_x,
7500 GtkCursors[aCursorType].hot_y);
7501
7502 g_object_unref(cursor_pixbuf);
7503 return gdkcursor;
7504}
7505
7506static GdkCursor* get_gtk_cursor_legacy(nsCursor aCursor) {
7507 GdkCursor* gdkcursor = nullptr;
7508 Maybe<uint8_t> fallbackType;
7509
7510 GdkDisplay* defaultDisplay = gdk_display_get_default();
7511
7512 // The strategy here is to use standard GDK cursors, and, if not available,
7513 // load by standard name with gdk_cursor_new_from_name.
7514 // Spec is here: http://www.freedesktop.org/wiki/Specifications/cursor-spec/
7515 switch (aCursor) {
7516 case eCursor_standard:
7517 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_LEFT_PTR);
7518 break;
7519 case eCursor_wait:
7520 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_WATCH);
7521 break;
7522 case eCursor_select:
7523 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_XTERM);
7524 break;
7525 case eCursor_hyperlink:
7526 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_HAND2);
7527 break;
7528 case eCursor_n_resize:
7529 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_TOP_SIDE);
7530 break;
7531 case eCursor_s_resize:
7532 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_BOTTOM_SIDE);
7533 break;
7534 case eCursor_w_resize:
7535 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_LEFT_SIDE);
7536 break;
7537 case eCursor_e_resize:
7538 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_RIGHT_SIDE);
7539 break;
7540 case eCursor_nw_resize:
7541 gdkcursor =
7542 gdk_cursor_new_for_display(defaultDisplay, GDK_TOP_LEFT_CORNER);
7543 break;
7544 case eCursor_se_resize:
7545 gdkcursor =
7546 gdk_cursor_new_for_display(defaultDisplay, GDK_BOTTOM_RIGHT_CORNER);
7547 break;
7548 case eCursor_ne_resize:
7549 gdkcursor =
7550 gdk_cursor_new_for_display(defaultDisplay, GDK_TOP_RIGHT_CORNER);
7551 break;
7552 case eCursor_sw_resize:
7553 gdkcursor =
7554 gdk_cursor_new_for_display(defaultDisplay, GDK_BOTTOM_LEFT_CORNER);
7555 break;
7556 case eCursor_crosshair:
7557 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_CROSSHAIR);
7558 break;
7559 case eCursor_move:
7560 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_FLEUR);
7561 break;
7562 case eCursor_help:
7563 gdkcursor =
7564 gdk_cursor_new_for_display(defaultDisplay, GDK_QUESTION_ARROW);
7565 break;
7566 case eCursor_copy: // CSS3
7567 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "copy");
7568 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_COPY);
7569 break;
7570 case eCursor_alias:
7571 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "alias");
7572 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ALIAS);
7573 break;
7574 case eCursor_context_menu:
7575 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "context-menu");
7576 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_CONTEXT_MENU);
7577 break;
7578 case eCursor_cell:
7579 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_PLUS);
7580 break;
7581 // Those two aren’t standardized. Trying both KDE’s and GNOME’s names
7582 case eCursor_grab:
7583 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "openhand");
7584 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_HAND_GRAB);
7585 break;
7586 case eCursor_grabbing:
7587 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "closedhand");
7588 if (!gdkcursor) {
7589 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "grabbing");
7590 }
7591 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_HAND_GRABBING);
7592 break;
7593 case eCursor_spinning:
7594 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "progress");
7595 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_SPINNING);
7596 break;
7597 case eCursor_zoom_in:
7598 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "zoom-in");
7599 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ZOOM_IN);
7600 break;
7601 case eCursor_zoom_out:
7602 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "zoom-out");
7603 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ZOOM_OUT);
7604 break;
7605 case eCursor_not_allowed:
7606 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "not-allowed");
7607 if (!gdkcursor) { // nonstandard, yet common
7608 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "crossed_circle");
7609 }
7610 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NOT_ALLOWED);
7611 break;
7612 case eCursor_no_drop:
7613 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "no-drop");
7614 if (!gdkcursor) { // this nonstandard sequence makes it work on KDE and
7615 // GNOME
7616 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "forbidden");
7617 }
7618 if (!gdkcursor) {
7619 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "circle");
7620 }
7621 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NOT_ALLOWED);
7622 break;
7623 case eCursor_vertical_text:
7624 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "vertical-text");
7625 if (!gdkcursor) {
7626 fallbackType.emplace(MOZ_CURSOR_VERTICAL_TEXT);
7627 }
7628 break;
7629 case eCursor_all_scroll:
7630 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "all-scroll");
7631 break;
7632 case eCursor_nesw_resize:
7633 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "size_bdiag");
7634 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NESW_RESIZE);
7635 break;
7636 case eCursor_nwse_resize:
7637 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "size_fdiag");
7638 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NWSE_RESIZE);
7639 break;
7640 case eCursor_ns_resize:
7641 gdkcursor =
7642 gdk_cursor_new_for_display(defaultDisplay, GDK_SB_V_DOUBLE_ARROW);
7643 break;
7644 case eCursor_ew_resize:
7645 gdkcursor =
7646 gdk_cursor_new_for_display(defaultDisplay, GDK_SB_H_DOUBLE_ARROW);
7647 break;
7648 // Here, two better fitting cursors exist in some cursor themes. Try those
7649 // first
7650 case eCursor_row_resize:
7651 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "split_v");
7652 if (!gdkcursor) {
7653 gdkcursor =
7654 gdk_cursor_new_for_display(defaultDisplay, GDK_SB_V_DOUBLE_ARROW);
7655 }
7656 break;
7657 case eCursor_col_resize:
7658 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "split_h");
7659 if (!gdkcursor) {
7660 gdkcursor =
7661 gdk_cursor_new_for_display(defaultDisplay, GDK_SB_H_DOUBLE_ARROW);
7662 }
7663 break;
7664 case eCursor_none:
7665 fallbackType.emplace(MOZ_CURSOR_NONE);
7666 break;
7667 default:
7668 NS_ASSERTION(aCursor, "Invalid cursor type")do { if (!(aCursor)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Invalid cursor type"
, "aCursor", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7668); MOZ_PretendNoReturn(); } } while (0)
;
7669 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_LEFT_PTR);
7670 break;
7671 }
7672
7673 if (!gdkcursor && fallbackType.isSome()) {
7674 LOGW("get_gtk_cursor_legacy(): Failed to get cursor %d, try fallback",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, "get_gtk_cursor_legacy(): Failed to get cursor %d, try fallback"
, aCursor); } } while (0)
7675 aCursor)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, "get_gtk_cursor_legacy(): Failed to get cursor %d, try fallback"
, aCursor); } } while (0)
;
7676 gdkcursor = get_gtk_cursor_from_type(*fallbackType);
7677 }
7678
7679 return gdkcursor;
7680}
7681
7682static GdkCursor* get_gtk_cursor_from_name(nsCursor aCursor) {
7683 GdkCursor* gdkcursor = nullptr;
7684 Maybe<uint8_t> fallbackType;
7685
7686 GdkDisplay* defaultDisplay = gdk_display_get_default();
7687
7688 switch (aCursor) {
7689 case eCursor_standard:
7690 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "default");
7691 break;
7692 case eCursor_wait:
7693 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "wait");
7694 break;
7695 case eCursor_select:
7696 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "text");
7697 break;
7698 case eCursor_hyperlink:
7699 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "pointer");
7700 break;
7701 case eCursor_n_resize:
7702 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "n-resize");
7703 break;
7704 case eCursor_s_resize:
7705 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "s-resize");
7706 break;
7707 case eCursor_w_resize:
7708 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "w-resize");
7709 break;
7710 case eCursor_e_resize:
7711 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "e-resize");
7712 break;
7713 case eCursor_nw_resize:
7714 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "nw-resize");
7715 break;
7716 case eCursor_se_resize:
7717 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "se-resize");
7718 break;
7719 case eCursor_ne_resize:
7720 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "ne-resize");
7721 break;
7722 case eCursor_sw_resize:
7723 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "sw-resize");
7724 break;
7725 case eCursor_crosshair:
7726 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "crosshair");
7727 break;
7728 case eCursor_move:
7729 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "move");
7730 break;
7731 case eCursor_help:
7732 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "help");
7733 break;
7734 case eCursor_copy:
7735 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "copy");
7736 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_COPY);
7737 break;
7738 case eCursor_alias:
7739 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "alias");
7740 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ALIAS);
7741 break;
7742 case eCursor_context_menu:
7743 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "context-menu");
7744 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_CONTEXT_MENU);
7745 break;
7746 case eCursor_cell:
7747 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "cell");
7748 break;
7749 case eCursor_grab:
7750 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "grab");
7751 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_HAND_GRAB);
7752 break;
7753 case eCursor_grabbing:
7754 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "grabbing");
7755 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_HAND_GRABBING);
7756 break;
7757 case eCursor_spinning:
7758 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "progress");
7759 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_SPINNING);
7760 break;
7761 case eCursor_zoom_in:
7762 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "zoom-in");
7763 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ZOOM_IN);
7764 break;
7765 case eCursor_zoom_out:
7766 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "zoom-out");
7767 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ZOOM_OUT);
7768 break;
7769 case eCursor_not_allowed:
7770 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "not-allowed");
7771 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NOT_ALLOWED);
7772 break;
7773 case eCursor_no_drop:
7774 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "no-drop");
7775 if (!gdkcursor) { // this nonstandard sequence makes it work on KDE and
7776 // GNOME
7777 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "forbidden");
7778 }
7779 if (!gdkcursor) {
7780 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "circle");
7781 }
7782 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NOT_ALLOWED);
7783 break;
7784 case eCursor_vertical_text:
7785 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "vertical-text");
7786 if (!gdkcursor) {
7787 fallbackType.emplace(MOZ_CURSOR_VERTICAL_TEXT);
7788 }
7789 break;
7790 case eCursor_all_scroll:
7791 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "all-scroll");
7792 break;
7793 case eCursor_nesw_resize:
7794 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "nesw-resize");
7795 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NESW_RESIZE);
7796 break;
7797 case eCursor_nwse_resize:
7798 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "nwse-resize");
7799 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NWSE_RESIZE);
7800 break;
7801 case eCursor_ns_resize:
7802 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "ns-resize");
7803 break;
7804 case eCursor_ew_resize:
7805 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "ew-resize");
7806 break;
7807 case eCursor_row_resize:
7808 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "row-resize");
7809 break;
7810 case eCursor_col_resize:
7811 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "col-resize");
7812 break;
7813 case eCursor_none:
7814 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "none");
7815 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NONE);
7816 break;
7817 default:
7818 NS_ASSERTION(aCursor, "Invalid cursor type")do { if (!(aCursor)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "Invalid cursor type"
, "aCursor", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7818); MOZ_PretendNoReturn(); } } while (0)
;
7819 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "default");
7820 break;
7821 }
7822
7823 if (!gdkcursor && fallbackType.isSome()) {
7824 LOGW("get_gtk_cursor_from_name(): Failed to get cursor %d, try fallback",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, "get_gtk_cursor_from_name(): Failed to get cursor %d, try fallback"
, aCursor); } } while (0)
7825 aCursor)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, "get_gtk_cursor_from_name(): Failed to get cursor %d, try fallback"
, aCursor); } } while (0)
;
7826 gdkcursor = get_gtk_cursor_from_type(*fallbackType);
7827 }
7828
7829 return gdkcursor;
7830}
7831
7832static GdkCursor* get_gtk_cursor(nsCursor aCursor) {
7833 GdkCursor* gdkcursor = nullptr;
7834
7835 if ((gdkcursor = gCursorCache[aCursor])) {
7836 return gdkcursor;
7837 }
7838
7839 gdkcursor = StaticPrefs::widget_gtk_legacy_cursors_enabled()
7840 ? get_gtk_cursor_legacy(aCursor)
7841 : get_gtk_cursor_from_name(aCursor);
7842
7843 gCursorCache[aCursor] = gdkcursor;
7844
7845 return gdkcursor;
7846}
7847
7848// gtk callbacks
7849
7850void draw_window_of_widget(GtkWidget* widget, GdkWindow* aWindow, cairo_t* cr) {
7851 if (gtk_cairo_should_draw_window(cr, aWindow)) {
7852 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
7853 if (!window) {
7854 NS_WARNING("Cannot get nsWindow from GtkWidget")NS_DebugBreak(NS_DEBUG_WARNING, "Cannot get nsWindow from GtkWidget"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7854)
;
7855 } else {
7856 cairo_save(cr);
7857 gtk_cairo_transform_to_window(cr, widget, aWindow);
7858 // TODO - window->OnExposeEvent() can destroy this or other windows,
7859 // do we need to handle it somehow?
7860 window->OnExposeEvent(cr);
7861 cairo_restore(cr);
7862 }
7863 }
7864}
7865
7866/* static */
7867gboolean expose_event_cb(GtkWidget* widget, cairo_t* cr) {
7868 draw_window_of_widget(widget, gtk_widget_get_window(widget), cr);
7869
7870 // A strong reference is already held during "draw" signal emission,
7871 // but GTK+ 3.4 wants the object to live a little longer than that
7872 // (bug 1225970).
7873 g_object_ref(widget);
7874 g_idle_add(
7875 [](gpointer data) -> gboolean {
7876 g_object_unref(data);
7877 return G_SOURCE_REMOVE(0);
7878 },
7879 widget);
7880
7881 return FALSE(0);
7882}
7883
7884static gboolean configure_event_cb(GtkWidget* widget,
7885 GdkEventConfigure* event) {
7886 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
7887 if (!window) {
7888 return FALSE(0);
7889 }
7890
7891 return window->OnConfigureEvent(widget, event);
7892}
7893
7894static void size_allocate_cb(GtkWidget* widget, GtkAllocation* allocation) {
7895 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
7896 if (!window) {
7897 return;
7898 }
7899
7900 window->OnSizeAllocate(allocation);
7901}
7902
7903static void toplevel_window_size_allocate_cb(GtkWidget* widget,
7904 GtkAllocation* allocation) {
7905 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
7906 if (!window) {
7907 return;
7908 }
7909
7910 // NOTE(emilio): We need to do this here to override GTK's own opaque region
7911 // setting (which would clobber ours).
7912 window->UpdateOpaqueRegionInternal();
7913}
7914
7915static gboolean delete_event_cb(GtkWidget* widget, GdkEventAny* event) {
7916 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
7917 if (!window) {
7918 return FALSE(0);
7919 }
7920
7921 window->OnDeleteEvent();
7922
7923 return TRUE(!(0));
7924}
7925
7926static gboolean enter_notify_event_cb(GtkWidget* widget,
7927 GdkEventCrossing* event) {
7928 RefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
7929 if (!window) {
7930 return TRUE(!(0));
7931 }
7932
7933 // We have stored leave notify - check if it's the correct one and
7934 // fire it before enter notify in such case.
7935 if (sStoredLeaveNotifyEvent) {
7936 auto clearNofityEvent =
7937 MakeScopeExit([&] { sStoredLeaveNotifyEvent = nullptr; });
7938 if (event->x_root == sStoredLeaveNotifyEvent->x_root &&
7939 event->y_root == sStoredLeaveNotifyEvent->y_root &&
7940 window->ApplyEnterLeaveMutterWorkaround()) {
7941 // Enter/Leave notify events has the same coordinates
7942 // and uses know buggy window config.
7943 // Consider it as a bogus one.
7944 return TRUE(!(0));
7945 }
7946 RefPtr<nsWindow> leftWindow =
7947 get_window_for_gdk_window(sStoredLeaveNotifyEvent->window);
7948 if (leftWindow) {
7949 leftWindow->OnLeaveNotifyEvent(sStoredLeaveNotifyEvent.get());
7950 }
7951 }
7952
7953 window->OnEnterNotifyEvent(event);
7954 return TRUE(!(0));
7955}
7956
7957static gboolean leave_notify_event_cb(GtkWidget* widget,
7958 GdkEventCrossing* event) {
7959 RefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
7960 if (!window) {
7961 return TRUE(!(0));
7962 }
7963
7964 if (window->ApplyEnterLeaveMutterWorkaround()) {
7965 // The leave event is potentially wrong, don't fire it now but store
7966 // it for further check at enter_notify_event_cb().
7967 sStoredLeaveNotifyEvent.reset(reinterpret_cast<GdkEventCrossing*>(
7968 gdk_event_copy(reinterpret_cast<GdkEvent*>(event))));
7969 } else {
7970 sStoredLeaveNotifyEvent = nullptr;
7971 window->OnLeaveNotifyEvent(event);
7972 }
7973
7974 return TRUE(!(0));
7975}
7976
7977static gboolean motion_notify_event_cb(GtkWidget* widget,
7978 GdkEventMotion* event) {
7979 UpdateLastInputEventTime(event);
7980
7981 RefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
7982 if (!window) {
7983 return FALSE(0);
7984 }
7985
7986 window->OnMotionNotifyEvent(event);
7987
7988 return TRUE(!(0));
7989}
7990
7991static gboolean button_press_event_cb(GtkWidget* widget,
7992 GdkEventButton* event) {
7993 UpdateLastInputEventTime(event);
7994
7995 if (event->button == 2 && !StaticPrefs::widget_gtk_middle_click_enabled()) {
7996 return FALSE(0);
7997 }
7998
7999 RefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
8000 if (!window) {
8001 return FALSE(0);
8002 }
8003
8004 window->OnButtonPressEvent(event);
8005
8006 if (GdkIsWaylandDisplay()) {
8007 WaylandDragWorkaround(window, event);
8008 }
8009
8010 return TRUE(!(0));
8011}
8012
8013static gboolean button_release_event_cb(GtkWidget* widget,
8014 GdkEventButton* event) {
8015 UpdateLastInputEventTime(event);
8016
8017 if (event->button == 2 && !StaticPrefs::widget_gtk_middle_click_enabled()) {
8018 return FALSE(0);
8019 }
8020
8021 RefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
8022 if (!window) {
8023 return FALSE(0);
8024 }
8025
8026 window->OnButtonReleaseEvent(event);
8027
8028 return TRUE(!(0));
8029}
8030
8031static gboolean focus_in_event_cb(GtkWidget* widget, GdkEventFocus* event) {
8032 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
8033 if (!window) {
8034 return FALSE(0);
8035 }
8036
8037 window->OnContainerFocusInEvent(event);
8038
8039 return FALSE(0);
8040}
8041
8042static gboolean focus_out_event_cb(GtkWidget* widget, GdkEventFocus* event) {
8043 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
8044 if (!window) {
8045 return FALSE(0);
8046 }
8047
8048 window->OnContainerFocusOutEvent(event);
8049
8050 return FALSE(0);
8051}
8052
8053#ifdef MOZ_X111
8054// For long-lived popup windows that don't really take focus themselves but
8055// may have elements that accept keyboard input when the parent window is
8056// active, focus is handled specially. These windows include noautohide
8057// panels. (This special handling is not necessary for temporary popups where
8058// the keyboard is grabbed.)
8059//
8060// Mousing over or clicking on these windows should not cause them to steal
8061// focus from their parent windows, so, the input field of WM_HINTS is set to
8062// False to request that the window manager not set the input focus to this
8063// window. http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.7
8064//
8065// However, these windows can still receive WM_TAKE_FOCUS messages from the
8066// window manager, so they can still detect when the user has indicated that
8067// they wish to direct keyboard input at these windows. When the window
8068// manager offers focus to these windows (after a mouse over or click, for
8069// example), a request to make the parent window active is issued. When the
8070// parent window becomes active, keyboard events will be received.
8071
8072static GdkFilterReturn popup_take_focus_filter(GdkXEvent* gdk_xevent,
8073 GdkEvent* event, gpointer data) {
8074 auto* xevent = static_cast<XEvent*>(gdk_xevent);
8075 if (xevent->type != ClientMessage33) {
8076 return GDK_FILTER_CONTINUE;
8077 }
8078
8079 XClientMessageEvent& xclient = xevent->xclient;
8080 if (xclient.message_type != gdk_x11_get_xatom_by_name("WM_PROTOCOLS")) {
8081 return GDK_FILTER_CONTINUE;
8082 }
8083
8084 Atom atom = xclient.data.l[0];
8085 if (atom != gdk_x11_get_xatom_by_name("WM_TAKE_FOCUS")) {
8086 return GDK_FILTER_CONTINUE;
8087 }
8088
8089 guint32 timestamp = xclient.data.l[1];
8090
8091 GtkWidget* widget = get_gtk_widget_for_gdk_window(event->any.window);
8092 if (!widget) {
8093 return GDK_FILTER_CONTINUE;
8094 }
8095
8096 GtkWindow* parent = gtk_window_get_transient_for(GTK_WINDOW(widget)((((GtkWindow*) (void *) ((widget))))));
8097 if (!parent) {
8098 return GDK_FILTER_CONTINUE;
8099 }
8100
8101 if (gtk_window_is_active(parent)) {
8102 return GDK_FILTER_REMOVE; // leave input focus on the parent
8103 }
8104
8105 GdkWindow* parent_window = gtk_widget_get_window(GTK_WIDGET(parent)((((GtkWidget*) (void *) ((parent))))));
8106 if (!parent_window) {
8107 return GDK_FILTER_CONTINUE;
8108 }
8109
8110 // In case the parent has not been deiconified.
8111 gdk_window_show_unraised(parent_window);
8112
8113 // Request focus on the parent window.
8114 // Use gdk_window_focus rather than gtk_window_present to avoid
8115 // raising the parent window.
8116 gdk_window_focus(parent_window, timestamp);
8117 return GDK_FILTER_REMOVE;
8118}
8119#endif /* MOZ_X11 */
8120
8121static gboolean key_press_event_cb(GtkWidget* widget, GdkEventKey* event) {
8122 LOGW("key_press_event_cb\n")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, "key_press_event_cb\n"
); } } while (0)
;
8123
8124 UpdateLastInputEventTime(event);
8125
8126 // find the window with focus and dispatch this event to that widget
8127 nsWindow* window = get_window_for_gtk_widget(widget);
8128 if (!window) {
8129 return FALSE(0);
8130 }
8131
8132 RefPtr<nsWindow> focusWindow = gFocusWindow ? gFocusWindow : window;
8133
8134#ifdef MOZ_X111
8135 // Keyboard repeat can cause key press events to queue up when there are
8136 // slow event handlers (bug 301029). Throttle these events by removing
8137 // consecutive pending duplicate KeyPress events to the same window.
8138 // We use the event time of the last one.
8139 // Note: GDK calls XkbSetDetectableAutorepeat so that KeyRelease events
8140 // are generated only when the key is physically released.
8141# define NS_GDKEVENT_MATCH_MASK0x1FFF 0x1FFF // GDK_SHIFT_MASK .. GDK_BUTTON5_MASK
8142 // Our headers undefine X11 KeyPress - let's redefine it here.
8143# ifndef KeyPress2
8144# define KeyPress2 2
8145# endif
8146 GdkDisplay* gdkDisplay = gtk_widget_get_display(widget);
8147 if (GdkIsX11Display(gdkDisplay)) {
8148 Display* dpy = GDK_DISPLAY_XDISPLAY(gdkDisplay)(gdk_x11_display_get_xdisplay (gdkDisplay));
8149 while (XPending(dpy)) {
8150 XEvent next_event;
8151 XPeekEvent(dpy, &next_event);
8152 GdkWindow* nextGdkWindow =
8153 gdk_x11_window_lookup_for_display(gdkDisplay, next_event.xany.window);
8154 if (nextGdkWindow != event->window || next_event.type != KeyPress2 ||
8155 next_event.xkey.keycode != event->hardware_keycode ||
8156 next_event.xkey.state != (event->state & NS_GDKEVENT_MATCH_MASK0x1FFF)) {
8157 break;
8158 }
8159 XNextEvent(dpy, &next_event);
8160 event->time = next_event.xkey.time;
8161 }
8162 }
8163#endif
8164
8165 return focusWindow->OnKeyPressEvent(event);
8166}
8167
8168static gboolean key_release_event_cb(GtkWidget* widget, GdkEventKey* event) {
8169 LOGW("key_release_event_cb\n")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, "key_release_event_cb\n"
); } } while (0)
;
8170
8171 UpdateLastInputEventTime(event);
8172
8173 // find the window with focus and dispatch this event to that widget
8174 nsWindow* window = get_window_for_gtk_widget(widget);
8175 if (!window) {
8176 return FALSE(0);
8177 }
8178
8179 RefPtr<nsWindow> focusWindow = gFocusWindow ? gFocusWindow : window;
8180 return focusWindow->OnKeyReleaseEvent(event);
8181}
8182
8183static gboolean property_notify_event_cb(GtkWidget* aWidget,
8184 GdkEventProperty* aEvent) {
8185 RefPtr<nsWindow> window = get_window_for_gdk_window(aEvent->window);
8186 if (!window) {
8187 return FALSE(0);
8188 }
8189
8190 return window->OnPropertyNotifyEvent(aWidget, aEvent);
8191}
8192
8193static gboolean scroll_event_cb(GtkWidget* widget, GdkEventScroll* event) {
8194 RefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
8195 if (NS_WARN_IF(!window)NS_warn_if_impl(!window, "!window", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 8195)
) {
8196 return FALSE(0);
8197 }
8198
8199 window->OnScrollEvent(event);
8200
8201 return TRUE(!(0));
8202}
8203
8204static gboolean visibility_notify_event_cb(GtkWidget* widget,
8205 GdkEventVisibility* event) {
8206 RefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
8207 if (!window) {
8208 return FALSE(0);
8209 }
8210 window->OnVisibilityNotifyEvent(event->state);
8211 return TRUE(!(0));
8212}
8213
8214static void hierarchy_changed_cb(GtkWidget* widget,
8215 GtkWidget* previous_toplevel) {
8216 GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
8217 GdkWindowState old_window_state = GDK_WINDOW_STATE_WITHDRAWN;
8218 GdkEventWindowState event;
8219
8220 event.new_window_state = GDK_WINDOW_STATE_WITHDRAWN;
8221
8222 if (GTK_IS_WINDOW(previous_toplevel)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(previous_toplevel)); GType __t = ((gtk_window_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; }
))))
) {
8223 g_signal_handlers_disconnect_by_func(g_signal_handlers_disconnect_matched ((previous_toplevel), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, __null, (
FuncToGpointer(window_state_event_cb)), (widget))
8224 previous_toplevel, FuncToGpointer(window_state_event_cb), widget)g_signal_handlers_disconnect_matched ((previous_toplevel), (GSignalMatchType
) (G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA), 0, 0, __null, (
FuncToGpointer(window_state_event_cb)), (widget))
;
8225 GdkWindow* win = gtk_widget_get_window(previous_toplevel);
8226 if (win) {
8227 old_window_state = gdk_window_get_state(win);
8228 }
8229 }
8230
8231 if (GTK_IS_WINDOW(toplevel)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(toplevel)); GType __t = ((gtk_window_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; }))))
) {
8232 g_signal_connect_swapped(toplevel, "window-state-event",g_signal_connect_data ((toplevel), ("window-state-event"), ((
(GCallback) (window_state_event_cb))), (widget), __null, G_CONNECT_SWAPPED
)
8233 G_CALLBACK(window_state_event_cb), widget)g_signal_connect_data ((toplevel), ("window-state-event"), ((
(GCallback) (window_state_event_cb))), (widget), __null, G_CONNECT_SWAPPED
)
;
8234 GdkWindow* win = gtk_widget_get_window(toplevel);
8235 if (win) {
8236 event.new_window_state = gdk_window_get_state(win);
8237 }
8238 }
8239
8240 event.changed_mask =
8241 static_cast<GdkWindowState>(old_window_state ^ event.new_window_state);
8242
8243 if (event.changed_mask) {
8244 event.type = GDK_WINDOW_STATE;
8245 event.window = nullptr;
8246 event.send_event = TRUE(!(0));
8247 window_state_event_cb(widget, &event);
8248 }
8249}
8250
8251static gboolean window_state_event_cb(GtkWidget* widget,
8252 GdkEventWindowState* event) {
8253 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
8254 if (!window) {
8255 return FALSE(0);
8256 }
8257
8258 window->OnWindowStateEvent(widget, event);
8259
8260 return FALSE(0);
8261}
8262
8263static void settings_xft_dpi_changed_cb(GtkSettings* gtk_settings,
8264 GParamSpec* pspec, nsWindow* data) {
8265 RefPtr<nsWindow> window = data;
8266 window->OnDPIChanged();
8267 // Even though the window size in screen pixels has not changed,
8268 // nsViewManager stores the dimensions in app units.
8269 // DispatchResized() updates those.
8270 window->DispatchResized();
8271}
8272
8273static void check_resize_cb(GtkContainer* container, gpointer user_data) {
8274 RefPtr<nsWindow> window = get_window_for_gtk_widget(GTK_WIDGET(container)((((GtkWidget*) (void *) ((container))))));
8275 if (!window) {
8276 return;
8277 }
8278 window->OnCheckResize();
8279}
8280
8281static void screen_composited_changed_cb(GdkScreen* screen,
8282 gpointer user_data) {
8283 // This callback can run before gfxPlatform::Init() in rare
8284 // cases involving the profile manager. When this happens,
8285 // we have no reason to reset any compositors as graphics
8286 // hasn't been initialized yet.
8287 if (GPUProcessManager::Get()) {
8288 GPUProcessManager::Get()->ResetCompositors();
8289 }
8290}
8291
8292static void widget_composited_changed_cb(GtkWidget* widget,
8293 gpointer user_data) {
8294 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
8295 if (!window) {
8296 return;
8297 }
8298 window->OnCompositedChanged();
8299}
8300
8301static void scale_changed_cb(GtkWidget* widget, GParamSpec* aPSpec,
8302 gpointer aPointer) {
8303 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
8304 if (!window) {
8305 return;
8306 }
8307
8308 window->OnScaleChanged(/* aNotify = */ true);
8309}
8310
8311static gboolean touch_event_cb(GtkWidget* aWidget, GdkEventTouch* aEvent) {
8312 UpdateLastInputEventTime(aEvent);
8313
8314 RefPtr<nsWindow> window = get_window_for_gdk_window(aEvent->window);
8315 if (!window) {
8316 return FALSE(0);
8317 }
8318
8319 return window->OnTouchEvent(aEvent);
8320}
8321
8322// This function called generic because there is no signal specific to touchpad
8323// pinch events.
8324static gboolean generic_event_cb(GtkWidget* widget, GdkEvent* aEvent) {
8325 if (aEvent->type != GDK_TOUCHPAD_PINCH) {
8326 return FALSE(0);
8327 }
8328 // Using reinterpret_cast because the touchpad_pinch field of GdkEvent is not
8329 // available in GTK+ versions lower than v3.18
8330 GdkEventTouchpadPinch* event =
8331 reinterpret_cast<GdkEventTouchpadPinch*>(aEvent);
8332
8333 RefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
8334
8335 if (!window) {
8336 return FALSE(0);
8337 }
8338 return window->OnTouchpadPinchEvent(event);
8339}
8340
8341//////////////////////////////////////////////////////////////////////
8342// These are all of our drag and drop operations
8343
8344void nsWindow::InitDragEvent(WidgetDragEvent& aEvent) {
8345 // set the keyboard modifiers
8346 guint modifierState = KeymapWrapper::GetCurrentModifierState();
8347 KeymapWrapper::InitInputEvent(aEvent, modifierState);
8348}
8349
8350static LayoutDeviceIntPoint GetWindowDropPosition(nsWindow* aWindow, int aX,
8351 int aY) {
8352 // Workaround for Bug 1710344
8353 // Caused by Gtk issue https://gitlab.gnome.org/GNOME/gtk/-/issues/4437
8354 if (aWindow->IsWaylandPopup()) {
8355 int tx = 0, ty = 0;
8356 gdk_window_get_position(aWindow->GetToplevelGdkWindow(), &tx, &ty);
8357 aX += tx;
8358 aY += ty;
8359 }
8360 LOGDRAG("WindowDropPosition [%d, %d]", aX, aY)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, "WindowDropPosition [%d, %d]"
, aX, aY); } } while (0)
;
8361 return aWindow->GdkPointToDevicePixels({aX, aY});
8362}
8363
8364gboolean WindowDragMotionHandler(GtkWidget* aWidget,
8365 GdkDragContext* aDragContext, gint aX, gint aY,
8366 guint aTime) {
8367 RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
8368 if (!window || !window->GetGdkWindow()) {
8369 return FALSE(0);
8370 }
8371
8372 // We're getting aX,aY in mShell coordinates space.
8373 // mContainer is shifted by CSD decorations so translate the coords
8374 // to mContainer space where our content lives.
8375 if (aWidget == window->GetGtkWidget()) {
8376 int x, y;
8377 gdk_window_get_geometry(window->GetGdkWindow(), &x, &y, nullptr, nullptr);
8378 aX -= x;
8379 aY -= y;
8380 }
8381
8382 LOGDRAG("WindowDragMotionHandler target nsWindow [%p]", window.get())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, "WindowDragMotionHandler target nsWindow [%p]"
, window.get()); } } while (0)
;
8383
8384 RefPtr<nsDragService> dragService = nsDragService::GetInstance();
8385 NS_ENSURE_TRUE(dragService, FALSE)do { if ((__builtin_expect(!!(!(dragService)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "dragService" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 8385); return (0); } } while (false)
;
8386 nsDragSession* dragSession =
8387 static_cast<nsDragSession*>(dragService->GetCurrentSession(window));
8388 if (!dragSession) {
8389 // This may be the start of an external drag session.
8390 nsIWidget* widget = window;
8391 dragSession =
8392 static_cast<nsDragSession*>(dragService->StartDragSession(widget));
8393 }
8394 NS_ENSURE_TRUE(dragSession, FALSE)do { if ((__builtin_expect(!!(!(dragSession)), 0))) { NS_DebugBreak
(NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "dragSession" ") failed"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 8394); return (0); } } while (false)
;
8395
8396 nsDragSession::AutoEventLoop loop(dragSession);
8397 if (!dragSession->ScheduleMotionEvent(
8398 window, aDragContext, GetWindowDropPosition(window, aX, aY), aTime)) {
8399 return FALSE(0);
8400 }
8401 return TRUE(!(0));
8402}
8403
8404static gboolean drag_motion_event_cb(GtkWidget* aWidget,
8405 GdkDragContext* aDragContext, gint aX,
8406 gint aY, guint aTime, gpointer aData) {
8407 return WindowDragMotionHandler(aWidget, aDragContext, aX, aY, aTime);
8408}
8409
8410void WindowDragLeaveHandler(GtkWidget* aWidget) {
8411 LOGDRAG("WindowDragLeaveHandler()\n")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, "WindowDragLeaveHandler()\n"
); } } while (0)
;
8412
8413 RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
8414 if (!window) {
8415 LOGDRAG(" Failed - can't find nsWindow!\n")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, " Failed - can't find nsWindow!\n"
); } } while (0)
;
8416 return;
8417 }
8418
8419 RefPtr<nsDragService> dragService = nsDragService::GetInstance();
8420 nsIWidget* widget = window;
8421 nsDragSession* dragSession =
8422 static_cast<nsDragSession*>(dragService->GetCurrentSession(widget));
8423 if (!dragSession) {
8424 LOGDRAG(" Received dragleave after drag had ended.\n")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, " Received dragleave after drag had ended.\n"
); } } while (0)
;
8425 return;
8426 }
8427
8428 nsDragSession::AutoEventLoop loop(dragSession);
8429
8430 nsWindow* mostRecentDragWindow = dragSession->GetMostRecentDestWindow();
8431 if (!mostRecentDragWindow) {
8432 // This can happen when the target will not accept a drop. A GTK drag
8433 // source sends the leave message to the destination before the
8434 // drag-failed signal on the source widget, but the leave message goes
8435 // via the X server, and so doesn't get processed at least until the
8436 // event loop runs again.
8437 LOGDRAG(" Failed - GetMostRecentDestWindow()!\n")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, " Failed - GetMostRecentDestWindow()!\n"
); } } while (0)
;
8438 return;
8439 }
8440
8441 if (aWidget != window->GetGtkWidget()) {
8442 // When the drag moves between widgets, GTK can send leave signal for
8443 // the old widget after the motion or drop signal for the new widget.
8444 // We'll send the leave event when the motion or drop event is run.
8445 LOGDRAG(" Failed - GtkWidget mismatch!\n")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, " Failed - GtkWidget mismatch!\n"
); } } while (0)
;
8446 return;
8447 }
8448
8449 LOGDRAG("WindowDragLeaveHandler nsWindow %p\n", (void*)mostRecentDragWindow)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, "WindowDragLeaveHandler nsWindow %p\n"
, (void*)mostRecentDragWindow); } } while (0)
;
8450 dragSession->ScheduleLeaveEvent();
8451}
8452
8453static void drag_leave_event_cb(GtkWidget* aWidget,
8454 GdkDragContext* aDragContext, guint aTime,
8455 gpointer aData) {
8456 WindowDragLeaveHandler(aWidget);
8457}
8458
8459gboolean WindowDragDropHandler(GtkWidget* aWidget, GdkDragContext* aDragContext,
8460 gint aX, gint aY, guint aTime) {
8461 RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
8462 if (!window || !window->GetGdkWindow()) {
8463 return FALSE(0);
8464 }
8465
8466 // We're getting aX,aY in mShell coordinates space.
8467 // mContainer is shifted by CSD decorations so translate the coords
8468 // to mContainer space where our content lives.
8469 if (aWidget == window->GetGtkWidget()) {
8470 int x, y;
8471 gdk_window_get_geometry(window->GetGdkWindow(), &x, &y, nullptr, nullptr);
8472 aX -= x;
8473 aY -= y;
8474 }
8475
8476 LOGDRAG("WindowDragDropHandler nsWindow [%p]", window.get())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, "WindowDragDropHandler nsWindow [%p]"
, window.get()); } } while (0)
;
8477 RefPtr<nsDragService> dragService = nsDragService::GetInstance();
8478 nsDragSession* dragSession =
8479 static_cast<nsDragSession*>(dragService->GetCurrentSession(window));
8480 if (!dragSession) {
8481 LOGDRAG(" Received dragdrop after drag end.\n")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, " Received dragdrop after drag end.\n"
); } } while (0)
;
8482 return FALSE(0);
8483 }
8484 nsDragSession::AutoEventLoop loop(dragSession);
8485 return dragSession->ScheduleDropEvent(
8486 window, aDragContext, GetWindowDropPosition(window, aX, aY), aTime);
8487}
8488
8489static gboolean drag_drop_event_cb(GtkWidget* aWidget,
8490 GdkDragContext* aDragContext, gint aX,
8491 gint aY, guint aTime, gpointer aData) {
8492 return WindowDragDropHandler(aWidget, aDragContext, aX, aY, aTime);
8493}
8494
8495static void drag_data_received_event_cb(GtkWidget* aWidget,
8496 GdkDragContext* aDragContext, gint aX,
8497 gint aY,
8498 GtkSelectionData* aSelectionData,
8499 guint aInfo, guint aTime,
8500 gpointer aData) {
8501 RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
8502 if (!window) {
8503 return;
8504 }
8505
8506 window->OnDragDataReceivedEvent(aWidget, aDragContext, aX, aY, aSelectionData,
8507 aInfo, aTime, aData);
8508}
8509
8510static nsresult initialize_prefs(void) {
8511 if (Preferences::HasUserValue("widget.use-aspect-ratio")) {
8512 gUseAspectRatio = Preferences::GetBool("widget.use-aspect-ratio", true);
8513 } else {
8514 gUseAspectRatio = IsGnomeDesktopEnvironment() || IsKdeDesktopEnvironment();
8515 }
8516 return NS_OK;
8517}
8518
8519#ifdef ACCESSIBILITY1
8520void nsWindow::CreateRootAccessible() {
8521 if (!mRootAccessible) {
8522 LOG("nsWindow:: Create Toplevel Accessibility\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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:: Create Toplevel Accessibility\n"
, GetDebugTag().get()); } } while (0)
;
8523 mRootAccessible = GetRootAccessible();
8524 }
8525}
8526
8527void nsWindow::DispatchEventToRootAccessible(uint32_t aEventType) {
8528 if (!a11y::ShouldA11yBeEnabled()) {
8529 return;
8530 }
8531
8532 nsAccessibilityService* accService = GetOrCreateAccService();
8533 if (!accService) {
8534 return;
8535 }
8536
8537 // Get the root document accessible and fire event to it.
8538 CreateRootAccessible();
8539 if (mRootAccessible) {
8540 accService->FireAccessibleEvent(aEventType, mRootAccessible);
8541 }
8542}
8543
8544void nsWindow::DispatchActivateEventAccessible(void) {
8545 DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_ACTIVATE);
8546}
8547
8548void nsWindow::DispatchDeactivateEventAccessible(void) {
8549 DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_DEACTIVATE);
8550}
8551
8552void nsWindow::DispatchMaximizeEventAccessible(void) {
8553 DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_MAXIMIZE);
8554}
8555
8556void nsWindow::DispatchMinimizeEventAccessible(void) {
8557 DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_MINIMIZE);
8558}
8559
8560void nsWindow::DispatchRestoreEventAccessible(void) {
8561 DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_RESTORE);
8562}
8563
8564#endif /* #ifdef ACCESSIBILITY */
8565
8566void nsWindow::SetInputContext(const InputContext& aContext,
8567 const InputContextAction& aAction) {
8568 if (!mIMContext) {
8569 return;
8570 }
8571 mIMContext->SetInputContext(this, &aContext, &aAction);
8572}
8573
8574InputContext nsWindow::GetInputContext() {
8575 InputContext context;
8576 if (!mIMContext) {
8577 context.mIMEState.mEnabled = IMEEnabled::Disabled;
8578 context.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
8579 } else {
8580 context = mIMContext->GetInputContext();
8581 }
8582 return context;
8583}
8584
8585TextEventDispatcherListener* nsWindow::GetNativeTextEventDispatcherListener() {
8586 if (NS_WARN_IF(!mIMContext)NS_warn_if_impl(!mIMContext, "!mIMContext", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 8586)
) {
8587 return nullptr;
8588 }
8589 return mIMContext;
8590}
8591
8592bool nsWindow::GetEditCommands(NativeKeyBindingsType aType,
8593 const WidgetKeyboardEvent& aEvent,
8594 nsTArray<CommandInt>& aCommands) {
8595 // Validate the arguments.
8596 if (NS_WARN_IF(!nsIWidget::GetEditCommands(aType, aEvent, aCommands))NS_warn_if_impl(!nsIWidget::GetEditCommands(aType, aEvent, aCommands
), "!nsIWidget::GetEditCommands(aType, aEvent, aCommands)", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 8596)
) {
8597 return false;
8598 }
8599
8600 Maybe<WritingMode> writingMode;
8601 if (aEvent.NeedsToRemapNavigationKey()) {
8602 if (RefPtr<TextEventDispatcher> dispatcher = GetTextEventDispatcher()) {
8603 writingMode = dispatcher->MaybeQueryWritingModeAtSelection();
8604 }
8605 }
8606
8607 NativeKeyBindings* keyBindings = NativeKeyBindings::GetInstance(aType);
8608 keyBindings->GetEditCommands(aEvent, writingMode, aCommands);
8609 return true;
8610}
8611
8612already_AddRefed<DrawTarget> nsWindow::StartRemoteDrawingInRegion(
8613 const LayoutDeviceIntRegion& aInvalidRegion, BufferMode* aBufferMode) {
8614 return mSurfaceProvider.StartRemoteDrawingInRegion(aInvalidRegion,
8615 aBufferMode);
8616}
8617
8618void nsWindow::EndRemoteDrawingInRegion(
8619 DrawTarget* aDrawTarget, const LayoutDeviceIntRegion& aInvalidRegion) {
8620 mSurfaceProvider.EndRemoteDrawingInRegion(aDrawTarget, aInvalidRegion);
8621}
8622
8623bool nsWindow::GetDragInfo(WidgetMouseEvent* aMouseEvent, GdkWindow** aWindow,
8624 gint* aButton, gint* aRootX, gint* aRootY) {
8625 if (aMouseEvent->mButton != MouseButton::ePrimary) {
8626 // we can only begin a move drag with the left mouse button
8627 return false;
8628 }
8629 *aButton = 1;
8630
8631 // get the gdk window for this widget
8632 GdkWindow* gdk_window = mGdkWindow;
8633 if (!gdk_window) {
8634 return false;
8635 }
8636#ifdef DEBUG1
8637 // GDK_IS_WINDOW(...) expands to a statement-expression, and
8638 // statement-expressions are not allowed in template-argument lists. So we
8639 // have to make the MOZ_ASSERT condition indirect.
8640 if (!GDK_IS_WINDOW(gdk_window)(((__extension__ ({ GTypeInstance *__inst = (GTypeInstance*) (
(gdk_window)); GType __t = ((gdk_window_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; }))))
) {
8641 MOZ_ASSERT(false, "must really be window")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "must really be window"
")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 8641); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"must really be window" ")"); do { *((volatile int*)__null) =
8641; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
8642 }
8643#endif
8644
8645 // find the top-level window
8646 gdk_window = gdk_window_get_toplevel(gdk_window);
8647 MOZ_ASSERT(gdk_window, "gdk_window_get_toplevel should not return null")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(gdk_window)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(gdk_window))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("gdk_window" " (" "gdk_window_get_toplevel should not return null"
")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 8647); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gdk_window"
") (" "gdk_window_get_toplevel should not return null" ")");
do { *((volatile int*)__null) = 8647; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8648 *aWindow = gdk_window;
8649
8650 if (!aMouseEvent->mWidget) {
8651 return false;
8652 }
8653
8654#ifdef MOZ_X111
8655 if (GdkIsX11Display()) {
8656 // Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=789054
8657 // To avoid crashes disable double-click on WM without _NET_WM_MOVERESIZE.
8658 // See _should_perform_ewmh_drag() at gdkwindow-x11.c
8659 // XXXsmaug remove this old hack. gtk should be fixed now.
8660 GdkScreen* screen = gdk_window_get_screen(gdk_window);
8661 GdkAtom atom = gdk_atom_intern("_NET_WM_MOVERESIZE", FALSE(0));
8662 if (!gdk_x11_screen_supports_net_wm_hint(screen, atom)) {
8663 static TimeStamp lastTimeStamp;
8664 if (lastTimeStamp != aMouseEvent->mTimeStamp) {
8665 lastTimeStamp = aMouseEvent->mTimeStamp;
8666 } else {
8667 return false;
8668 }
8669 }
8670 }
8671#endif
8672
8673 // FIXME: It would be nice to have the widget position at the time
8674 // of the event, but it's relatively unlikely that the widget has
8675 // moved since the mousedown. (On the other hand, it's quite likely
8676 // that the mouse has moved, which is why we use the mouse position
8677 // from the event.)
8678 LayoutDeviceIntPoint offset = aMouseEvent->mWidget->WidgetToScreenOffset();
8679 *aRootX = aMouseEvent->mRefPoint.x + offset.x;
8680 *aRootY = aMouseEvent->mRefPoint.y + offset.y;
8681
8682 return true;
8683}
8684
8685nsIWidget::WindowRenderer* nsWindow::GetWindowRenderer() {
8686 if (mIsDestroyed) {
8687 // Prevent external code from triggering the re-creation of the
8688 // LayerManager/Compositor during shutdown. Just return what we currently
8689 // have, which is most likely null.
8690 return mWindowRenderer;
8691 }
8692
8693 return nsBaseWidget::GetWindowRenderer();
8694}
8695
8696void nsWindow::DidGetNonBlankPaint() {
8697 if (mGotNonBlankPaint) {
8698 return;
8699 }
8700 mGotNonBlankPaint = true;
8701 if (!mConfiguredClearColor) {
8702 // Nothing to do, we hadn't overridden the clear color.
8703 mConfiguredClearColor = true;
8704 return;
8705 }
8706 // Reset the clear color set in the expose event to transparent.
8707 GetWindowRenderer()->AsWebRender()->WrBridge()->SendSetDefaultClearColor(
8708 NS_TRANSPARENT);
8709}
8710
8711/* nsWindow::SetCompositorWidgetDelegate() sets remote GtkCompositorWidget
8712 * to render into with compositor.
8713 *
8714 * SetCompositorWidgetDelegate(delegate) is called from
8715 * nsBaseWidget::CreateCompositor(), i.e. nsWindow::GetWindowRenderer().
8716 *
8717 * SetCompositorWidgetDelegate(null) is called from
8718 * nsBaseWidget::DestroyCompositor().
8719 */
8720void nsWindow::SetCompositorWidgetDelegate(CompositorWidgetDelegate* delegate) {
8721 LOG("nsWindow::SetCompositorWidgetDelegate %p mIsMapped %d "do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetCompositorWidgetDelegate %p mIsMapped %d "
"mCompositorWidgetDelegate %p\n", GetDebugTag().get(), delegate
, !!mIsMapped, mCompositorWidgetDelegate); } } while (0)
8722 "mCompositorWidgetDelegate %p\n",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetCompositorWidgetDelegate %p mIsMapped %d "
"mCompositorWidgetDelegate %p\n", GetDebugTag().get(), delegate
, !!mIsMapped, mCompositorWidgetDelegate); } } while (0)
8723 delegate, !!mIsMapped, mCompositorWidgetDelegate)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetCompositorWidgetDelegate %p mIsMapped %d "
"mCompositorWidgetDelegate %p\n", GetDebugTag().get(), delegate
, !!mIsMapped, mCompositorWidgetDelegate); } } while (0)
;
8724
8725 MOZ_RELEASE_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 8725); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 8725; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8726 if (delegate) {
8727 mCompositorWidgetDelegate = delegate->AsPlatformSpecificDelegate();
8728 MOZ_ASSERT(mCompositorWidgetDelegate,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCompositorWidgetDelegate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCompositorWidgetDelegate)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("mCompositorWidgetDelegate"
" (" "nsWindow::SetCompositorWidgetDelegate called with a " "non-PlatformCompositorWidgetDelegate"
")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 8730); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCompositorWidgetDelegate"
") (" "nsWindow::SetCompositorWidgetDelegate called with a "
"non-PlatformCompositorWidgetDelegate" ")"); do { *((volatile
int*)__null) = 8730; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
8729 "nsWindow::SetCompositorWidgetDelegate called with a "do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCompositorWidgetDelegate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCompositorWidgetDelegate)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("mCompositorWidgetDelegate"
" (" "nsWindow::SetCompositorWidgetDelegate called with a " "non-PlatformCompositorWidgetDelegate"
")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 8730); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCompositorWidgetDelegate"
") (" "nsWindow::SetCompositorWidgetDelegate called with a "
"non-PlatformCompositorWidgetDelegate" ")"); do { *((volatile
int*)__null) = 8730; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
8730 "non-PlatformCompositorWidgetDelegate")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCompositorWidgetDelegate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCompositorWidgetDelegate)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("mCompositorWidgetDelegate"
" (" "nsWindow::SetCompositorWidgetDelegate called with a " "non-PlatformCompositorWidgetDelegate"
")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 8730); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCompositorWidgetDelegate"
") (" "nsWindow::SetCompositorWidgetDelegate called with a "
"non-PlatformCompositorWidgetDelegate" ")"); do { *((volatile
int*)__null) = 8730; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
8731 if (mIsMapped) {
8732 ConfigureCompositor();
8733 }
8734 } else {
8735 mCompositorWidgetDelegate = nullptr;
8736 }
8737}
8738
8739nsresult nsWindow::SetNonClientMargins(const LayoutDeviceIntMargin& aMargins) {
8740 SetDrawsInTitlebar(aMargins.top == 0);
8741 return NS_OK;
8742}
8743
8744bool nsWindow::IsAlwaysUndecoratedWindow() const {
8745 if (mIsPIPWindow || gKioskMode) {
8746 return true;
8747 }
8748 if (mWindowType == WindowType::Dialog &&
8749 mBorderStyle != BorderStyle::Default &&
8750 mBorderStyle != BorderStyle::All &&
8751 !(mBorderStyle & BorderStyle::Title) &&
8752 !(mBorderStyle & BorderStyle::ResizeH)) {
8753 return true;
8754 }
8755 return false;
8756}
8757
8758void nsWindow::SetDrawsInTitlebar(bool aState) {
8759 LOG("nsWindow::SetDrawsInTitlebar() State %d mGtkWindowDecoration %d\n",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetDrawsInTitlebar() State %d mGtkWindowDecoration %d\n"
, GetDebugTag().get(), aState, (int)mGtkWindowDecoration); } }
while (0)
8760 aState, (int)mGtkWindowDecoration)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetDrawsInTitlebar() State %d mGtkWindowDecoration %d\n"
, GetDebugTag().get(), aState, (int)mGtkWindowDecoration); } }
while (0)
;
8761
8762 if (mGtkWindowDecoration == GTK_DECORATION_NONE ||
8763 aState == mDrawInTitlebar) {
8764 LOG(" already set, quit")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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 set, quit", GetDebugTag(
).get()); } } while (0)
;
8765 return;
8766 }
8767
8768 if (mUndecorated) {
8769 MOZ_ASSERT(aState, "Unexpected decoration request")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aState)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(aState))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aState" " (" "Unexpected decoration request"
")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 8769); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aState" ") ("
"Unexpected decoration request" ")"); do { *((volatile int*)
__null) = 8769; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
8770 MOZ_ASSERT(!gtk_window_get_decorated(GTK_WINDOW(mShell)))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!gtk_window_get_decorated(((((GtkWindow*) (void *) (
(mShell)))))))>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(!gtk_window_get_decorated(((((GtkWindow
*) (void *) ((mShell))))))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("!gtk_window_get_decorated(((((GtkWindow*) (void *) ((mShell))))))"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 8770); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gtk_window_get_decorated(((((GtkWindow*) (void *) ((mShell))))))"
")"); do { *((volatile int*)__null) = 8770; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
8771 return;
8772 }
8773
8774 mDrawInTitlebar = aState;
8775
8776 if (mGtkWindowDecoration == GTK_DECORATION_SYSTEM) {
8777 SetWindowDecoration(aState ? BorderStyle::Border : mBorderStyle);
8778 } else if (mGtkWindowDecoration == GTK_DECORATION_CLIENT) {
8779 LOG(" Using CSD mode\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " Using CSD mode\n", GetDebugTag
().get()); } } while (0)
;
8780
8781 if (!gtk_widget_get_realized(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))))) {
8782 LOG(" Using CSD mode fast path\n")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " Using CSD mode fast path\n", GetDebugTag
().get()); } } while (0)
;
8783 gtk_window_set_titlebar(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))),
8784 aState ? gtk_fixed_new() : nullptr);
8785 return;
8786 }
8787
8788 /* Window manager does not support GDK_DECOR_BORDER,
8789 * emulate it by CSD.
8790 *
8791 * gtk_window_set_titlebar() works on unrealized widgets only,
8792 * we need to handle mShell carefully here.
8793 * When CSD is enabled mGdkWindow is owned by mContainer which is good
8794 * as we can't delete our mGdkWindow. To make mShell unrealized while
8795 * mContainer is preserved we temporary reparent mContainer to an
8796 * invisible GtkWindow.
8797 */
8798 bool visible = !mNeedsShow && mIsShown;
8799 if (visible) {
8800 NativeShow(false);
8801 }
8802
8803 // Using GTK_WINDOW_POPUP rather than
8804 // GTK_WINDOW_TOPLEVEL in the hope that POPUP results in less
8805 // initialization and window manager interaction.
8806 GtkWidget* tmpWindow = gtk_window_new(GTK_WINDOW_POPUP);
8807 gtk_widget_realize(tmpWindow);
8808
8809 gtk_widget_reparent(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))), tmpWindow);
8810 gtk_widget_unrealize(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))));
8811
8812 // Add a hidden titlebar widget to trigger CSD, but disable the default
8813 // titlebar. GtkFixed is a somewhat random choice for a simple unused
8814 // widget. gtk_window_set_titlebar() takes ownership of the titlebar
8815 // widget.
8816 gtk_window_set_titlebar(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))),
8817 aState ? gtk_fixed_new() : nullptr);
8818
8819 /* A workaround for https://bugzilla.gnome.org/show_bug.cgi?id=791081
8820 * gtk_widget_realize() throws:
8821 * "In pixman_region32_init_rect: Invalid rectangle passed"
8822 * when mShell has default 1x1 size.
8823 */
8824 GtkAllocation allocation = {0, 0, 0, 0};
8825 gtk_widget_get_preferred_width(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))), nullptr,
8826 &allocation.width);
8827 gtk_widget_get_preferred_height(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))), nullptr,
8828 &allocation.height);
8829 gtk_widget_size_allocate(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))), &allocation);
8830
8831 gtk_widget_realize(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))));
8832 gtk_widget_reparent(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))), GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))));
8833
8834 // Label mShell toplevel window so property_notify_event_cb callback
8835 // can find its way home.
8836 g_object_set_data(G_OBJECT(GetToplevelGdkWindow())((((GObject*) (void *) ((GetToplevelGdkWindow()))))), "nsWindow", this);
8837
8838 if (AreBoundsSane()) {
8839 GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mBounds.Size());
8840 LOG(" resize to %d x %d\n", size.width, size.height)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " resize to %d x %d\n", GetDebugTag
().get(), size.width, size.height); } } while (0)
;
8841 gtk_window_resize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), size.width, size.height);
8842 }
8843
8844 if (visible) {
8845 mNeedsShow = true;
8846 NativeShow(true);
8847 }
8848
8849 gtk_widget_destroy(tmpWindow);
8850 }
8851
8852 // Recompute the input region (which should generally be null, but this is
8853 // enough to work around bug 1844497, which is probably a gtk bug).
8854 SetInputRegion(mInputRegion);
8855}
8856
8857GtkWindow* nsWindow::GetCurrentTopmostWindow() const {
8858 GtkWindow* parentWindow = GTK_WINDOW(GetGtkWidget())((((GtkWindow*) (void *) ((GetGtkWidget())))));
8859 GtkWindow* topmostParentWindow = nullptr;
8860 while (parentWindow) {
8861 topmostParentWindow = parentWindow;
8862 parentWindow = gtk_window_get_transient_for(parentWindow);
8863 }
8864 return topmostParentWindow;
8865}
8866
8867gint nsWindow::GdkCeiledScaleFactor() {
8868 if (IsTopLevelWindowType()) {
8869 return mCeiledScaleFactor;
8870 }
8871 if (nsWindow* topmost = GetTopmostWindow()) {
8872 return topmost->mCeiledScaleFactor;
8873 }
8874 return ScreenHelperGTK::GetGTKMonitorScaleFactor();
8875}
8876
8877double nsWindow::FractionalScaleFactor() {
8878#ifdef MOZ_WAYLAND1
8879 double fractional_scale = [&] {
8880 if (IsTopLevelWindowType()) {
8881 return mFractionalScaleFactor;
8882 }
8883 if (nsWindow* topmost = GetTopmostWindow()) {
8884 return topmost->mFractionalScaleFactor;
8885 }
8886 return 0.0;
8887 }();
8888 if (fractional_scale != 0.0) {
8889 return fractional_scale;
8890 }
8891#endif
8892 return GdkCeiledScaleFactor();
8893}
8894
8895gint nsWindow::DevicePixelsToGdkCoordRoundUp(int aPixels) {
8896 double scale = FractionalScaleFactor();
8897 return ceil(aPixels / scale);
8898}
8899
8900gint nsWindow::DevicePixelsToGdkCoordRoundDown(int aPixels) {
8901 double scale = FractionalScaleFactor();
8902 return floor(aPixels / scale);
8903}
8904
8905GdkPoint nsWindow::DevicePixelsToGdkPointRoundDown(
8906 const LayoutDeviceIntPoint& aPoint) {
8907 double scale = FractionalScaleFactor();
8908 return {int(aPoint.x / scale), int(aPoint.y / scale)};
8909}
8910
8911GdkRectangle nsWindow::DevicePixelsToGdkRectRoundOut(
8912 const LayoutDeviceIntRect& aRect) {
8913 double scale = FractionalScaleFactor();
8914 int x = floor(aRect.x / scale);
8915 int y = floor(aRect.y / scale);
8916 int right = ceil((aRect.x + aRect.width) / scale);
8917 int bottom = ceil((aRect.y + aRect.height) / scale);
8918 return {x, y, right - x, bottom - y};
8919}
8920
8921GdkRectangle nsWindow::DevicePixelsToGdkRectRoundIn(
8922 const LayoutDeviceIntRect& aRect) {
8923 double scale = FractionalScaleFactor();
8924 int x = ceil(aRect.x / scale);
8925 int y = ceil(aRect.y / scale);
8926 int right = floor((aRect.x + aRect.width) / scale);
8927 int bottom = floor((aRect.y + aRect.height) / scale);
8928 return {x, y, std::max(right - x, 0), std::max(bottom - y, 0)};
8929}
8930
8931GdkRectangle nsWindow::DevicePixelsToGdkSizeRoundUp(
8932 const LayoutDeviceIntSize& aSize) {
8933 double scale = FractionalScaleFactor();
8934 gint width = ceil(aSize.width / scale);
8935 gint height = ceil(aSize.height / scale);
8936 return {0, 0, width, height};
8937}
8938
8939int nsWindow::GdkCoordToDevicePixels(gint aCoord) {
8940 return (int)(aCoord * FractionalScaleFactor());
8941}
8942
8943LayoutDeviceIntPoint nsWindow::GdkEventCoordsToDevicePixels(gdouble aX,
8944 gdouble aY) {
8945 double scale = FractionalScaleFactor();
8946 return LayoutDeviceIntPoint::Floor((float)(aX * scale), (float)(aY * scale));
8947}
8948
8949LayoutDeviceIntPoint nsWindow::GdkPointToDevicePixels(const GdkPoint& aPoint) {
8950 double scale = FractionalScaleFactor();
8951 return LayoutDeviceIntPoint::Floor((float)(aPoint.x * scale),
8952 (float)(aPoint.y * scale));
8953}
8954
8955LayoutDeviceIntRect nsWindow::GdkRectToDevicePixels(const GdkRectangle& aRect) {
8956 double scale = FractionalScaleFactor();
8957 return LayoutDeviceIntRect::RoundIn(
8958 (float)(aRect.x * scale), (float)(aRect.y * scale),
8959 (float)(aRect.width * scale), (float)(aRect.height * scale));
8960}
8961
8962nsresult nsWindow::SynthesizeNativeMouseEvent(
8963 LayoutDeviceIntPoint aPoint, NativeMouseMessage aNativeMessage,
8964 MouseButton aButton, nsIWidget::Modifiers aModifierFlags,
8965 nsIObserver* aObserver) {
8966 LOG("SynthesizeNativeMouseEvent(%d, %d, %d, %d, %d)", aPoint.x.value,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "SynthesizeNativeMouseEvent(%d, %d, %d, %d, %d)"
, GetDebugTag().get(), aPoint.x.value, aPoint.y.value, int(aNativeMessage
), int(aButton), int(aModifierFlags)); } } while (0)
8967 aPoint.y.value, int(aNativeMessage), int(aButton), int(aModifierFlags))do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " "SynthesizeNativeMouseEvent(%d, %d, %d, %d, %d)"
, GetDebugTag().get(), aPoint.x.value, aPoint.y.value, int(aNativeMessage
), int(aButton), int(aModifierFlags)); } } while (0)
;
8968
8969 AutoObserverNotifier notifier(aObserver, "mouseevent");
8970
8971 if (!mGdkWindow) {
8972 return NS_OK;
8973 }
8974
8975 // When a button-press/release event is requested, create it here and put it
8976 // in the event queue. This will not emit a motion event - this needs to be
8977 // done explicitly *before* requesting a button-press/release. You will also
8978 // need to wait for the motion event to be dispatched before requesting a
8979 // button-press/release event to maintain the desired event order.
8980 switch (aNativeMessage) {
8981 case NativeMouseMessage::ButtonDown:
8982 case NativeMouseMessage::ButtonUp: {
8983 GdkEvent event;
8984 memset(&event, 0, sizeof(GdkEvent));
8985 event.type = aNativeMessage == NativeMouseMessage::ButtonDown
8986 ? GDK_BUTTON_PRESS
8987 : GDK_BUTTON_RELEASE;
8988 switch (aButton) {
8989 case MouseButton::ePrimary:
8990 case MouseButton::eMiddle:
8991 case MouseButton::eSecondary:
8992 case MouseButton::eX1:
8993 case MouseButton::eX2:
8994 event.button.button = aButton + 1;
8995 break;
8996 default:
8997 return NS_ERROR_INVALID_ARG;
8998 }
8999 event.button.state =
9000 KeymapWrapper::ConvertWidgetModifierToGdkState(aModifierFlags);
9001 event.button.window = mGdkWindow;
9002 event.button.time = GDK_CURRENT_TIME0L;
9003
9004 // Get device for event source
9005 event.button.device = GdkGetPointer();
9006
9007 event.button.x_root = DevicePixelsToGdkCoordRoundDown(aPoint.x);
9008 event.button.y_root = DevicePixelsToGdkCoordRoundDown(aPoint.y);
9009
9010 LayoutDeviceIntPoint pointInWindow = aPoint - WidgetToScreenOffset();
9011 event.button.x = DevicePixelsToGdkCoordRoundDown(pointInWindow.x);
9012 event.button.y = DevicePixelsToGdkCoordRoundDown(pointInWindow.y);
9013
9014 gdk_event_put(&event);
9015 return NS_OK;
9016 }
9017 case NativeMouseMessage::Move: {
9018 // We don't support specific events other than button-press/release. In
9019 // all other cases we'll synthesize a motion event that will be emitted by
9020 // gdk_display_warp_pointer().
9021 // XXX How to activate native modifier for the other events?
9022#ifdef MOZ_WAYLAND1
9023 // Impossible to warp the pointer on Wayland.
9024 // For pointer lock, pointer-constraints and relative-pointer are used.
9025 if (GdkIsWaylandDisplay()) {
9026 return NS_OK;
9027 }
9028#endif
9029 GdkScreen* screen = gdk_window_get_screen(mGdkWindow);
9030 GdkPoint point = DevicePixelsToGdkPointRoundDown(aPoint);
9031 gdk_device_warp(GdkGetPointer(), screen, point.x, point.y);
9032 return NS_OK;
9033 }
9034 case NativeMouseMessage::EnterWindow:
9035 case NativeMouseMessage::LeaveWindow:
9036 MOZ_ASSERT_UNREACHABLE("Non supported mouse event on Linux")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"Non supported mouse event on Linux" ")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 9036); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Non supported mouse event on Linux"
")"); do { *((volatile int*)__null) = 9036; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9037 return NS_ERROR_INVALID_ARG;
9038 }
9039 return NS_ERROR_UNEXPECTED;
9040}
9041
9042void nsWindow::CreateAndPutGdkScrollEvent(mozilla::LayoutDeviceIntPoint aPoint,
9043 double aDeltaX, double aDeltaY) {
9044 GdkEvent event;
9045 memset(&event, 0, sizeof(GdkEvent));
9046 event.type = GDK_SCROLL;
9047 event.scroll.window = mGdkWindow;
9048 event.scroll.time = GDK_CURRENT_TIME0L;
9049 // Get device for event source
9050 GdkDisplay* display = gdk_window_get_display(mGdkWindow);
9051 GdkDeviceManager* device_manager = gdk_display_get_device_manager(display);
9052 // See note in nsWindow::SynthesizeNativeTouchpadPan about the device we use
9053 // here.
9054 event.scroll.device = gdk_device_manager_get_client_pointer(device_manager);
9055 event.scroll.x_root = DevicePixelsToGdkCoordRoundDown(aPoint.x);
9056 event.scroll.y_root = DevicePixelsToGdkCoordRoundDown(aPoint.y);
9057
9058 LayoutDeviceIntPoint pointInWindow = aPoint - WidgetToScreenOffset();
9059 event.scroll.x = DevicePixelsToGdkCoordRoundDown(pointInWindow.x);
9060 event.scroll.y = DevicePixelsToGdkCoordRoundDown(pointInWindow.y);
9061
9062 // The delta values are backwards on Linux compared to Windows and Cocoa,
9063 // hence the negation.
9064 event.scroll.direction = GDK_SCROLL_SMOOTH;
9065 event.scroll.delta_x = -aDeltaX;
9066 event.scroll.delta_y = -aDeltaY;
9067
9068 gdk_event_put(&event);
9069}
9070
9071nsresult nsWindow::SynthesizeNativeMouseScrollEvent(
9072 mozilla::LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage,
9073 double aDeltaX, double aDeltaY, double aDeltaZ, uint32_t aModifierFlags,
9074 uint32_t aAdditionalFlags, nsIObserver* aObserver) {
9075 AutoObserverNotifier notifier(aObserver, "mousescrollevent");
9076
9077 if (!mGdkWindow) {
9078 return NS_OK;
9079 }
9080
9081 CreateAndPutGdkScrollEvent(aPoint, aDeltaX, aDeltaY);
9082
9083 return NS_OK;
9084}
9085
9086nsresult nsWindow::SynthesizeNativeTouchPoint(uint32_t aPointerId,
9087 TouchPointerState aPointerState,
9088 LayoutDeviceIntPoint aPoint,
9089 double aPointerPressure,
9090 uint32_t aPointerOrientation,
9091 nsIObserver* aObserver) {
9092 AutoObserverNotifier notifier(aObserver, "touchpoint");
9093
9094 if (!mGdkWindow) {
9095 return NS_OK;
9096 }
9097
9098 GdkEvent event;
9099 memset(&event, 0, sizeof(GdkEvent));
9100
9101 static std::map<uint32_t, GdkEventSequence*> sKnownPointers;
9102
9103 auto result = sKnownPointers.find(aPointerId);
9104 switch (aPointerState) {
9105 case TOUCH_CONTACT:
9106 if (result == sKnownPointers.end()) {
9107 // GdkEventSequence isn't a thing we can instantiate, and never gets
9108 // dereferenced in the gtk code. It's an opaque pointer, the only
9109 // requirement is that it be distinct from other instances of
9110 // GdkEventSequence*.
9111 event.touch.sequence = (GdkEventSequence*)((uintptr_t)aPointerId);
9112 sKnownPointers[aPointerId] = event.touch.sequence;
9113 event.type = GDK_TOUCH_BEGIN;
9114 } else {
9115 event.touch.sequence = result->second;
9116 event.type = GDK_TOUCH_UPDATE;
9117 }
9118 break;
9119 case TOUCH_REMOVE:
9120 event.type = GDK_TOUCH_END;
9121 if (result == sKnownPointers.end()) {
9122 NS_WARNING("Tried to synthesize touch-end for unknown pointer!")NS_DebugBreak(NS_DEBUG_WARNING, "Tried to synthesize touch-end for unknown pointer!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 9122)
;
9123 return NS_ERROR_UNEXPECTED;
9124 }
9125 event.touch.sequence = result->second;
9126 sKnownPointers.erase(result);
9127 break;
9128 case TOUCH_CANCEL:
9129 event.type = GDK_TOUCH_CANCEL;
9130 if (result == sKnownPointers.end()) {
9131 NS_WARNING("Tried to synthesize touch-cancel for unknown pointer!")NS_DebugBreak(NS_DEBUG_WARNING, "Tried to synthesize touch-cancel for unknown pointer!"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 9131)
;
9132 return NS_ERROR_UNEXPECTED;
9133 }
9134 event.touch.sequence = result->second;
9135 sKnownPointers.erase(result);
9136 break;
9137 case TOUCH_HOVER:
9138 default:
9139 return NS_ERROR_NOT_IMPLEMENTED;
9140 }
9141
9142 event.touch.window = mGdkWindow;
9143 event.touch.time = GDK_CURRENT_TIME0L;
9144
9145 GdkDisplay* display = gdk_window_get_display(mGdkWindow);
9146 GdkDeviceManager* device_manager = gdk_display_get_device_manager(display);
9147 event.touch.device = gdk_device_manager_get_client_pointer(device_manager);
9148
9149 event.touch.x_root = DevicePixelsToGdkCoordRoundDown(aPoint.x);
9150 event.touch.y_root = DevicePixelsToGdkCoordRoundDown(aPoint.y);
9151
9152 LayoutDeviceIntPoint pointInWindow = aPoint - WidgetToScreenOffset();
9153 event.touch.x = DevicePixelsToGdkCoordRoundDown(pointInWindow.x);
9154 event.touch.y = DevicePixelsToGdkCoordRoundDown(pointInWindow.y);
9155
9156 gdk_event_put(&event);
9157
9158 return NS_OK;
9159}
9160
9161nsresult nsWindow::SynthesizeNativeTouchPadPinch(
9162 TouchpadGesturePhase aEventPhase, float aScale, LayoutDeviceIntPoint aPoint,
9163 int32_t aModifierFlags) {
9164 if (!mGdkWindow) {
9165 return NS_OK;
9166 }
9167 GdkEvent event;
9168 memset(&event, 0, sizeof(GdkEvent));
9169
9170 GdkEventTouchpadPinch* touchpad_event =
9171 reinterpret_cast<GdkEventTouchpadPinch*>(&event);
9172 touchpad_event->type = GDK_TOUCHPAD_PINCH;
9173
9174 const ScreenIntPoint widgetToScreenOffset = ViewAs<ScreenPixel>(
9175 WidgetToScreenOffset(),
9176 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
9177
9178 ScreenPoint pointInWindow =
9179 ViewAs<ScreenPixel>(
9180 aPoint,
9181 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent) -
9182 widgetToScreenOffset;
9183
9184 gdouble dx = 0, dy = 0;
9185
9186 switch (aEventPhase) {
9187 case PHASE_BEGIN:
9188 touchpad_event->phase = GDK_TOUCHPAD_GESTURE_PHASE_BEGIN;
9189 mCurrentSynthesizedTouchpadPinch = {pointInWindow, pointInWindow};
9190 break;
9191 case PHASE_UPDATE:
9192 dx = pointInWindow.x - mCurrentSynthesizedTouchpadPinch.mCurrentFocus.x;
9193 dy = pointInWindow.y - mCurrentSynthesizedTouchpadPinch.mCurrentFocus.y;
9194 mCurrentSynthesizedTouchpadPinch.mCurrentFocus = pointInWindow;
9195 touchpad_event->phase = GDK_TOUCHPAD_GESTURE_PHASE_UPDATE;
9196 break;
9197 case PHASE_END:
9198 touchpad_event->phase = GDK_TOUCHPAD_GESTURE_PHASE_END;
9199 break;
9200
9201 default:
9202 return NS_ERROR_NOT_IMPLEMENTED;
9203 }
9204
9205 touchpad_event->window = mGdkWindow;
9206 // We only set the fields of GdkEventTouchpadPinch which are
9207 // actually used in OnTouchpadPinchEvent().
9208 // GdkEventTouchpadPinch has additional fields.
9209 // If OnTouchpadPinchEvent() is changed to use other fields, this function
9210 // will need to change to set them as well.
9211 touchpad_event->time = GDK_CURRENT_TIME0L;
9212 touchpad_event->scale = aScale;
9213 touchpad_event->x_root = DevicePixelsToGdkCoordRoundDown(
9214 mCurrentSynthesizedTouchpadPinch.mBeginFocus.x +
9215 ScreenCoord(widgetToScreenOffset.x));
9216 touchpad_event->y_root = DevicePixelsToGdkCoordRoundDown(
9217 mCurrentSynthesizedTouchpadPinch.mBeginFocus.y +
9218 ScreenCoord(widgetToScreenOffset.y));
9219
9220 touchpad_event->x = DevicePixelsToGdkCoordRoundDown(
9221 mCurrentSynthesizedTouchpadPinch.mBeginFocus.x);
9222 touchpad_event->y = DevicePixelsToGdkCoordRoundDown(
9223 mCurrentSynthesizedTouchpadPinch.mBeginFocus.y);
9224
9225 touchpad_event->dx = dx;
9226 touchpad_event->dy = dy;
9227
9228 touchpad_event->state = aModifierFlags;
9229
9230 gdk_event_put(&event);
9231
9232 return NS_OK;
9233}
9234
9235nsresult nsWindow::SynthesizeNativeTouchpadPan(TouchpadGesturePhase aEventPhase,
9236 LayoutDeviceIntPoint aPoint,
9237 double aDeltaX, double aDeltaY,
9238 int32_t aModifierFlags,
9239 nsIObserver* aObserver) {
9240 AutoObserverNotifier notifier(aObserver, "touchpadpanevent");
9241
9242 if (!mGdkWindow) {
9243 return NS_OK;
9244 }
9245
9246 // This should/could maybe send GdkEventTouchpadSwipe events, however we don't
9247 // currently consume those (either real user input or testing events). So we
9248 // send gdk scroll events to be more like what we do for real user input. If
9249 // we start consuming GdkEventTouchpadSwipe and get those hooked up to swipe
9250 // to nav, then maybe we should test those too.
9251
9252 mCurrentSynthesizedTouchpadPan.mTouchpadGesturePhase = Some(aEventPhase);
9253 MOZ_ASSERT(mCurrentSynthesizedTouchpadPan.mSavedObserver == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCurrentSynthesizedTouchpadPan.mSavedObserver == 0)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mCurrentSynthesizedTouchpadPan.mSavedObserver == 0))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mCurrentSynthesizedTouchpadPan.mSavedObserver == 0"
, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 9253); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCurrentSynthesizedTouchpadPan.mSavedObserver == 0"
")"); do { *((volatile int*)__null) = 9253; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9254 mCurrentSynthesizedTouchpadPan.mSavedObserver = notifier.SaveObserver();
9255
9256 // Note that CreateAndPutGdkScrollEvent sets the device source for the created
9257 // event as the "client pointer" (a kind of default device) which will
9258 // probably be of type mouse. We would ideally want to set the device of the
9259 // created event to be a touchpad, but the system might not have a touchpad.
9260 // To get around this we use
9261 // mCurrentSynthesizedTouchpadPan.mTouchpadGesturePhase being something to
9262 // indicate that we should treat the source of the event as touchpad in
9263 // OnScrollEvent.
9264 CreateAndPutGdkScrollEvent(aPoint, aDeltaX, aDeltaY);
9265
9266 return NS_OK;
9267}
9268
9269nsWindow::GtkWindowDecoration nsWindow::GetSystemGtkWindowDecoration() {
9270 static GtkWindowDecoration sGtkWindowDecoration = [] {
9271 // Allow MOZ_GTK_TITLEBAR_DECORATION to override our heuristics
9272 if (const char* decorationOverride =
9273 getenv("MOZ_GTK_TITLEBAR_DECORATION")) {
9274 if (strcmp(decorationOverride, "none") == 0) {
9275 return GTK_DECORATION_NONE;
9276 }
9277 if (strcmp(decorationOverride, "client") == 0) {
9278 return GTK_DECORATION_CLIENT;
9279 }
9280 if (strcmp(decorationOverride, "system") == 0) {
9281 return GTK_DECORATION_SYSTEM;
9282 }
9283 }
9284
9285 // nsWindow::GetSystemGtkWindowDecoration can be called from various
9286 // threads so we can't use gfxPlatformGtk here.
9287 if (GdkIsWaylandDisplay()) {
9288 return GTK_DECORATION_CLIENT;
9289 }
9290
9291 // GTK_CSD forces CSD mode - use also CSD because window manager
9292 // decorations does not work with CSD.
9293 // We check GTK_CSD as well as gtk_window_should_use_csd() does.
9294 if (const char* csdOverride = getenv("GTK_CSD")) {
9295 return *csdOverride == '0' ? GTK_DECORATION_NONE : GTK_DECORATION_CLIENT;
9296 }
9297
9298 // TODO: Consider switching this to GetDesktopEnvironmentIdentifier().
9299 const char* currentDesktop = getenv("XDG_CURRENT_DESKTOP");
9300 if (!currentDesktop) {
9301 return GTK_DECORATION_NONE;
9302 }
9303 if (strstr(currentDesktop, "i3")) {
9304 return GTK_DECORATION_NONE;
9305 }
9306
9307 // Tested desktops: pop:GNOME, KDE, Enlightenment, LXDE, openbox, MATE,
9308 // X-Cinnamon, Pantheon, Deepin, GNOME, LXQt, Unity.
9309 return GTK_DECORATION_CLIENT;
9310 }();
9311 return sGtkWindowDecoration;
9312}
9313
9314int32_t nsWindow::RoundsWidgetCoordinatesTo() { return GdkCeiledScaleFactor(); }
9315
9316void nsWindow::GetCompositorWidgetInitData(
9317 mozilla::widget::CompositorWidgetInitData* aInitData) {
9318 nsCString displayName;
9319
9320 LOG("nsWindow::GetCompositorWidgetInitData")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::GetCompositorWidgetInitData"
, GetDebugTag().get()); } } while (0)
;
9321
9322 Window window = GetX11Window();
9323#ifdef MOZ_X111
9324 // We're bit hackish here. Old GLX backend needs XWindow when GLContext
9325 // is created so get XWindow now before map signal.
9326 // We may see crashes/errors when nsWindow is unmapped (XWindow is
9327 // invalidated) but we can't do anything about it.
9328 if (!window && !gfxVars::UseEGL()) {
9329 window =
9330 gdk_x11_window_get_xid(gtk_widget_get_window(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer)))))));
9331 }
9332#endif
9333 *aInitData = mozilla::widget::GtkCompositorWidgetInitData(
9334 window, displayName, GdkIsX11Display(), GetClientSize());
9335
9336#ifdef MOZ_X111
9337 if (GdkIsX11Display()) {
9338 // Make sure the window XID is propagated to X server, we can fail otherwise
9339 // in GPU process (Bug 1401634).
9340 Display* display = DefaultXDisplay();
9341 XFlush(display);
9342 displayName = nsCString(XDisplayString(display));
9343 }
9344#endif
9345}
9346
9347#ifdef MOZ_X111
9348/* XApp progress support currently works by setting a property
9349 * on a window with this Atom name. A supporting window manager
9350 * will notice this and pass it along to whatever handling has
9351 * been implemented on that end (e.g. passing it on to a taskbar
9352 * widget.) There is no issue if WM support is lacking, this is
9353 * simply ignored in that case.
9354 *
9355 * See https://github.com/linuxmint/xapps/blob/master/libxapp/xapp-gtk-window.c
9356 * for further details.
9357 */
9358
9359# define PROGRESS_HINT"_NET_WM_XAPP_PROGRESS" "_NET_WM_XAPP_PROGRESS"
9360
9361static void set_window_hint_cardinal(Window xid, const gchar* atom_name,
9362 gulong cardinal) {
9363 GdkDisplay* display;
9364
9365 display = gdk_display_get_default();
9366
9367 if (cardinal > 0) {
9368 XChangeProperty(GDK_DISPLAY_XDISPLAY(display)(gdk_x11_display_get_xdisplay (display)), xid,
9369 gdk_x11_get_xatom_by_name_for_display(display, atom_name),
9370 XA_CARDINAL((Atom) 6), 32, PropModeReplace0, (guchar*)&cardinal, 1);
9371 } else {
9372 XDeleteProperty(GDK_DISPLAY_XDISPLAY(display)(gdk_x11_display_get_xdisplay (display)), xid,
9373 gdk_x11_get_xatom_by_name_for_display(display, atom_name));
9374 }
9375}
9376#endif // MOZ_X11
9377
9378void nsWindow::SetProgress(unsigned long progressPercent) {
9379#ifdef MOZ_X111
9380
9381 if (!GdkIsX11Display()) {
9382 return;
9383 }
9384
9385 if (!mShell) {
9386 return;
9387 }
9388
9389 progressPercent = MIN(progressPercent, 100)(((progressPercent) < (100)) ? (progressPercent) : (100));
9390
9391 set_window_hint_cardinal(GDK_WINDOW_XID(GetToplevelGdkWindow())(gdk_x11_window_get_xid (GetToplevelGdkWindow())),
9392 PROGRESS_HINT"_NET_WM_XAPP_PROGRESS", progressPercent);
9393#endif // MOZ_X11
9394}
9395
9396#ifdef MOZ_X111
9397void nsWindow::SetCompositorHint(WindowComposeRequest aState) {
9398 if (!GdkIsX11Display()) {
9399 return;
9400 }
9401
9402 gulong value = aState;
9403 GdkAtom cardinal_atom = gdk_x11_xatom_to_atom(XA_CARDINAL((Atom) 6));
9404 gdk_property_change(GetToplevelGdkWindow(),
9405 gdk_atom_intern("_NET_WM_BYPASS_COMPOSITOR", FALSE(0)),
9406 cardinal_atom,
9407 32, // format
9408 GDK_PROP_MODE_REPLACE, (guchar*)&value, 1);
9409}
9410#endif
9411
9412nsresult nsWindow::SetSystemFont(const nsCString& aFontName) {
9413 GtkSettings* settings = gtk_settings_get_default();
9414 g_object_set(settings, "gtk-font-name", aFontName.get(), nullptr);
9415 return NS_OK;
9416}
9417
9418nsresult nsWindow::GetSystemFont(nsCString& aFontName) {
9419 GtkSettings* settings = gtk_settings_get_default();
9420 gchar* fontName = nullptr;
9421 g_object_get(settings, "gtk-font-name", &fontName, nullptr);
9422 if (fontName) {
9423 aFontName.Assign(fontName);
9424 g_free(fontName);
9425 }
9426 return NS_OK;
9427}
9428
9429already_AddRefed<nsIWidget> nsIWidget::CreateTopLevelWindow() {
9430 nsCOMPtr<nsIWidget> window = new nsWindow();
9431 return window.forget();
9432}
9433
9434already_AddRefed<nsIWidget> nsIWidget::CreateChildWindow() {
9435 nsCOMPtr<nsIWidget> window = new nsWindow();
9436 return window.forget();
9437}
9438
9439#ifdef MOZ_WAYLAND1
9440static void relative_pointer_handle_relative_motion(
9441 void* data, struct zwp_relative_pointer_v1* pointer, uint32_t time_hi,
9442 uint32_t time_lo, wl_fixed_t dx_w, wl_fixed_t dy_w, wl_fixed_t dx_unaccel_w,
9443 wl_fixed_t dy_unaccel_w) {
9444 RefPtr<nsWindow> window(reinterpret_cast<nsWindow*>(data));
9445
9446 WidgetMouseEvent event(true, eMouseMove, window, WidgetMouseEvent::eReal);
9447
9448 double scale = window->FractionalScaleFactor();
9449 event.mRefPoint = window->GetNativePointerLockCenter();
9450 event.mRefPoint.x += int(wl_fixed_to_double(dx_w) * scale);
9451 event.mRefPoint.y += int(wl_fixed_to_double(dy_w) * scale);
9452
9453 event.AssignEventTime(window->GetWidgetEventTime(time_lo));
9454 window->DispatchInputEvent(&event);
9455}
9456
9457static const struct zwp_relative_pointer_v1_listener relative_pointer_listener =
9458 {
9459 relative_pointer_handle_relative_motion,
9460};
9461
9462void nsWindow::SetNativePointerLockCenter(
9463 const LayoutDeviceIntPoint& aLockCenter) {
9464 mNativePointerLockCenter = aLockCenter;
9465}
9466
9467void nsWindow::LockNativePointer() {
9468 if (!GdkIsWaylandDisplay()) {
9469 return;
9470 }
9471
9472 auto* waylandDisplay = WaylandDisplayGet();
9473
9474 auto* pointerConstraints = waylandDisplay->GetPointerConstraints();
9475 if (!pointerConstraints) {
9476 return;
9477 }
9478
9479 auto* relativePointerMgr = waylandDisplay->GetRelativePointerManager();
9480 if (!relativePointerMgr) {
9481 return;
9482 }
9483
9484 GdkDisplay* display = gdk_display_get_default();
9485
9486 GdkDeviceManager* manager = gdk_display_get_device_manager(display);
9487 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", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 9487); AnnotateMozCrashReason("MOZ_ASSERT" "(" "manager" ")"
); do { *((volatile int*)__null) = 9487; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9488
9489 GdkDevice* device = gdk_device_manager_get_client_pointer(manager);
9490 if (!device) {
9491 NS_WARNING("Could not find Wayland pointer to lock")NS_DebugBreak(NS_DEBUG_WARNING, "Could not find Wayland pointer to lock"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 9491)
;
9492 return;
9493 }
9494 wl_pointer* pointer = gdk_wayland_device_get_wl_pointer(device);
9495 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", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 9495); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pointer" ")"
); do { *((volatile int*)__null) = 9495; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9496
9497 wl_surface* surface =
9498 gdk_wayland_window_get_wl_surface(GetToplevelGdkWindow());
9499 if (!surface) {
9500 /* Can be null when the window is hidden.
9501 * Though it's unlikely that a lock request comes in that case, be
9502 * defensive. */
9503 return;
9504 }
9505
9506 UnlockNativePointer();
9507
9508 mLockedPointer = zwp_pointer_constraints_v1_lock_pointer(
9509 pointerConstraints, surface, pointer, nullptr,
9510 ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
9511 if (!mLockedPointer) {
9512 NS_WARNING("Could not lock Wayland pointer")NS_DebugBreak(NS_DEBUG_WARNING, "Could not lock Wayland pointer"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 9512)
;
9513 return;
9514 }
9515
9516 mRelativePointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
9517 relativePointerMgr, pointer);
9518 if (!mRelativePointer) {
9519 NS_WARNING("Could not create relative Wayland pointer")NS_DebugBreak(NS_DEBUG_WARNING, "Could not create relative Wayland pointer"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 9519)
;
9520 zwp_locked_pointer_v1_destroy(mLockedPointer);
9521 mLockedPointer = nullptr;
9522 return;
9523 }
9524
9525 zwp_relative_pointer_v1_add_listener(mRelativePointer,
9526 &relative_pointer_listener, this);
9527}
9528
9529void nsWindow::UnlockNativePointer() {
9530 if (mRelativePointer) {
9531 zwp_relative_pointer_v1_destroy(mRelativePointer);
9532 mRelativePointer = nullptr;
9533 }
9534 if (mLockedPointer) {
9535 zwp_locked_pointer_v1_destroy(mLockedPointer);
9536 mLockedPointer = nullptr;
9537 }
9538}
9539#endif
9540
9541static nsIFrame* FindTitlebarFrame(nsIFrame* aFrame) {
9542 for (nsIFrame* childFrame : aFrame->PrincipalChildList()) {
9543 StyleAppearance appearance =
9544 childFrame->StyleDisplay()->EffectiveAppearance();
9545 if (appearance == StyleAppearance::MozWindowTitlebar ||
9546 appearance == StyleAppearance::MozWindowTitlebarMaximized) {
9547 return childFrame;
9548 }
9549
9550 if (nsIFrame* foundFrame = FindTitlebarFrame(childFrame)) {
9551 return foundFrame;
9552 }
9553 }
9554 return nullptr;
9555}
9556
9557nsIFrame* nsWindow::GetFrame() const {
9558 nsView* view = nsView::GetViewFor(this);
9559 if (!view) {
9560 return nullptr;
9561 }
9562 return view->GetFrame();
9563}
9564
9565void nsWindow::UpdateMozWindowActive() {
9566 // Update activation state for the :-moz-window-inactive pseudoclass.
9567 // Normally, this follows focus; we override it here to follow
9568 // GDK_WINDOW_STATE_FOCUSED.
9569 if (mozilla::dom::Document* document = GetDocument()) {
9570 if (nsPIDOMWindowOuter* window = document->GetWindow()) {
9571 if (RefPtr<mozilla::dom::BrowsingContext> bc =
9572 window->GetBrowsingContext()) {
9573 bc->SetIsActiveBrowserWindow(!mTitlebarBackdropState);
9574 }
9575 }
9576 }
9577}
9578
9579void nsWindow::ForceTitlebarRedraw() {
9580 MOZ_ASSERT(mDrawInTitlebar, "We should not redraw invisible titlebar.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDrawInTitlebar)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDrawInTitlebar))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mDrawInTitlebar"
" (" "We should not redraw invisible titlebar." ")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 9580); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDrawInTitlebar"
") (" "We should not redraw invisible titlebar." ")"); do { *
((volatile int*)__null) = 9580; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
9581
9582 if (!mWidgetListener || !mWidgetListener->GetPresShell()) {
9583 return;
9584 }
9585
9586 nsIFrame* frame = GetFrame();
9587 if (!frame) {
9588 return;
9589 }
9590
9591 frame = FindTitlebarFrame(frame);
9592 if (frame) {
9593 nsIContent* content = frame->GetContent();
9594 if (content) {
9595 nsLayoutUtils::PostRestyleEvent(content->AsElement(), RestyleHint{0},
9596 nsChangeHint_RepaintFrame);
9597 }
9598 }
9599}
9600
9601void nsWindow::LockAspectRatio(bool aShouldLock) {
9602 if (!gUseAspectRatio) {
9603 return;
9604 }
9605
9606 if (aShouldLock) {
9607 int decWidth = 0, decHeight = 0;
9608 AddCSDDecorationSize(&decWidth, &decHeight);
9609
9610 float width =
9611 DevicePixelsToGdkCoordRoundDown(mLastSizeRequest.width) + decWidth;
9612 float height =
9613 DevicePixelsToGdkCoordRoundDown(mLastSizeRequest.height) + decHeight;
9614
9615 mAspectRatio = width / height;
9616 LOG("nsWindow::LockAspectRatio() width %f height %f aspect %f", width,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::LockAspectRatio() width %f height %f aspect %f"
, GetDebugTag().get(), width, height, mAspectRatio); } } while
(0)
9617 height, mAspectRatio)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::LockAspectRatio() width %f height %f aspect %f"
, GetDebugTag().get(), width, height, mAspectRatio); } } while
(0)
;
9618 } else {
9619 mAspectRatio = 0.0;
9620 LOG("nsWindow::LockAspectRatio() removed aspect ratio")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::LockAspectRatio() removed aspect ratio"
, GetDebugTag().get()); } } while (0)
;
9621 }
9622
9623 ApplySizeConstraints();
9624}
9625
9626nsWindow* nsWindow::GetFocusedWindow() { return gFocusWindow; }
9627
9628#ifdef MOZ_WAYLAND1
9629bool nsWindow::SetEGLNativeWindowSize(
9630 const LayoutDeviceIntSize& aEGLWindowSize) {
9631 if (!GdkIsWaylandDisplay() || !mIsMapped) {
9632 return true;
9633 }
9634
9635 if (mCompositorState == COMPOSITOR_PAUSED_FLICKERING) {
9636 LOG("nsWindow::SetEGLNativeWindowSize() return, "do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetEGLNativeWindowSize() return, "
"COMPOSITOR_PAUSED_FLICKERING is set", GetDebugTag().get());
} } while (0)
9637 "COMPOSITOR_PAUSED_FLICKERING is set")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetEGLNativeWindowSize() return, "
"COMPOSITOR_PAUSED_FLICKERING is set", GetDebugTag().get());
} } while (0)
;
9638 return false;
9639 }
9640
9641 gint scale = GdkCeiledScaleFactor();
9642# ifdef MOZ_LOGGING1
9643 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)
))
) {
9644 static uintptr_t lastSizeLog = 0;
9645 uintptr_t sizeLog =
9646 uintptr_t(this) + aEGLWindowSize.width + aEGLWindowSize.height + scale +
9647 aEGLWindowSize.width / scale + aEGLWindowSize.height / scale;
9648 if (lastSizeLog != sizeLog) {
9649 lastSizeLog = sizeLog;
9650 LOG("nsWindow::SetEGLNativeWindowSize() %d x %d scale %d (unscaled "do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetEGLNativeWindowSize() %d x %d scale %d (unscaled "
"%d x %d)", GetDebugTag().get(), aEGLWindowSize.width, aEGLWindowSize
.height, scale, aEGLWindowSize.width / scale, aEGLWindowSize.
height / scale); } } while (0)
9651 "%d x %d)",do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetEGLNativeWindowSize() %d x %d scale %d (unscaled "
"%d x %d)", GetDebugTag().get(), aEGLWindowSize.width, aEGLWindowSize
.height, scale, aEGLWindowSize.width / scale, aEGLWindowSize.
height / scale); } } while (0)
9652 aEGLWindowSize.width, aEGLWindowSize.height, scale,do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetEGLNativeWindowSize() %d x %d scale %d (unscaled "
"%d x %d)", GetDebugTag().get(), aEGLWindowSize.width, aEGLWindowSize
.height, scale, aEGLWindowSize.width / scale, aEGLWindowSize.
height / scale); } } while (0)
9653 aEGLWindowSize.width / scale, aEGLWindowSize.height / scale)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::SetEGLNativeWindowSize() %d x %d scale %d (unscaled "
"%d x %d)", GetDebugTag().get(), aEGLWindowSize.width, aEGLWindowSize
.height, scale, aEGLWindowSize.width / scale, aEGLWindowSize.
height / scale); } } while (0)
;
9654 }
9655 }
9656# endif
9657 return moz_container_wayland_egl_window_set_size(
9658 mContainer, aEGLWindowSize.ToUnknownSize(), scale);
9659}
9660#endif
9661
9662nsWindow* nsWindow::GetWindow(GdkWindow* window) {
9663 return get_window_for_gdk_window(window);
9664}
9665
9666void nsWindow::ClearRenderingQueue() {
9667 LOG("nsWindow::ClearRenderingQueue()")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::ClearRenderingQueue()", GetDebugTag
().get()); } } while (0)
;
9668
9669 if (mWidgetListener) {
9670 mWidgetListener->RequestWindowClose(this);
9671 }
9672 DestroyLayerManager();
9673}
9674
9675// nsWindow::OnMap() / nsWindow::OnUnmap() is called from map/unmap mContainer
9676// handlers directly as we paint to mContainer.
9677void nsWindow::OnMap() {
9678 LOG("nsWindow::OnMap")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::OnMap", GetDebugTag().get
()); } } while (0)
;
9679
9680 {
9681 MutexAutoLock lock(mWindowVisibilityMutex);
9682 mIsMapped = true;
9683
9684 EnsureGdkWindow();
9685 OnScaleChanged(/* aNotify = */ false);
9686
9687 if (mIsAlert) {
9688 gdk_window_set_override_redirect(GetToplevelGdkWindow(), TRUE(!(0)));
9689 }
9690
9691#ifdef MOZ_X111
9692 if (GdkIsX11Display()) {
9693 mSurfaceProvider.Initialize(GetX11Window());
9694
9695 // Set window manager hint to keep fullscreen windows composited.
9696 //
9697 // If the window were to get unredirected, there could be visible
9698 // tearing because Gecko does not align its framebuffer updates with
9699 // vblank.
9700 SetCompositorHint(GTK_WIDGET_COMPOSITED_ENABLED);
9701 }
9702#endif
9703#ifdef MOZ_WAYLAND1
9704 if (GdkIsWaylandDisplay()) {
9705 mSurfaceProvider.Initialize(this);
9706 }
9707#endif
9708 }
9709
9710 if (mIsDragPopup) {
9711 if (GdkIsWaylandDisplay()) {
9712 // Disable painting to the widget on Wayland as we paint directly to the
9713 // widget. Wayland compositors does not paint wl_subsurface
9714 // of D&D widget.
9715 if (GtkWidget* parent = gtk_widget_get_parent(mShell)) {
9716 GtkWidgetDisableUpdates(parent);
9717 }
9718 GtkWidgetDisableUpdates(mShell);
9719 GtkWidgetDisableUpdates(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))));
9720 } else {
9721 // Disable rendering of parent container on X11 to avoid flickering.
9722 if (GtkWidget* parent = gtk_widget_get_parent(mShell)) {
9723 gtk_widget_set_opacity(parent, 0.0);
9724 }
9725 }
9726 }
9727
9728 if (mWindowType == WindowType::Popup) {
9729 if (mNoAutoHide) {
9730 gint wmd = ConvertBorderStyles(mBorderStyle);
9731 if (wmd != -1) {
9732 gdk_window_set_decorations(mGdkWindow, (GdkWMDecoration)wmd);
9733 }
9734 }
9735 // If the popup ignores mouse events, set an empty input shape.
9736 SetInputRegion(mInputRegion);
9737 }
9738
9739 RefreshWindowClass();
9740
9741 // We're not mapped yet but we have already created compositor.
9742 if (mCompositorWidgetDelegate) {
9743 ConfigureCompositor();
9744 }
9745
9746 LOG(" finished, new GdkWindow %p XID 0x%lx\n", mGdkWindow, GetX11Window())do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__builtin_expect(!!(mozilla
::detail::log_test(moz_real_module, mozilla::LogLevel::Debug)
), 0))) { mozilla::detail::log_print(moz_real_module, mozilla
::LogLevel::Debug, "%s: " " finished, new GdkWindow %p XID 0x%lx\n"
, GetDebugTag().get(), mGdkWindow, GetX11Window()); } } while
(0)
;
9747}
9748
9749void nsWindow::OnUnmap() {
9750 LOG("nsWindow::OnUnmap")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::OnUnmap", GetDebugTag().
get()); } } while (0)
;
9751
9752 {
9753 MutexAutoLock lock(mWindowVisibilityMutex);
9754 mIsMapped = false;
9755
9756 if (mSourceDragContext) {
9757 static auto sGtkDragCancel =
9758 (void (*)(GdkDragContext*))dlsym(RTLD_DEFAULT((void *) 0), "gtk_drag_cancel");
9759 if (sGtkDragCancel) {
9760 sGtkDragCancel(mSourceDragContext);
9761 mSourceDragContext = nullptr;
9762 }
9763 }
9764
9765 if (mGdkWindow) {
9766 g_object_set_data(G_OBJECT(mGdkWindow)((((GObject*) (void *) ((mGdkWindow))))), "nsWindow", nullptr);
9767 mGdkWindow = nullptr;
9768 }
9769
9770 // Clear resources (mainly XWindow) stored at GtkCompositorWidget.
9771 // It makes sure we don't paint to it when nsWindow becomes hiden/deleted
9772 // and XWindow is released.
9773 if (mCompositorWidgetDelegate) {
9774 mCompositorWidgetDelegate->CleanupResources();
9775 }
9776
9777 // Clear nsWindow resources used for old (in-thread) rendering.
9778 mSurfaceProvider.CleanupResources();
9779 }
9780
9781 // Until Bug 1654938 is fixed we delete layer manager for hidden popups,
9782 // otherwise it can easily hold 1GB+ memory for long time.
9783 if (mWindowType == WindowType::Popup) {
9784 DestroyLayerManager();
9785 } else {
9786 // Widget is backed by OpenGL EGLSurface created over wl_surface/XWindow.
9787 //
9788 // RenderCompositorEGL::Resume() deletes recent EGLSurface,
9789 // calls nsWindow::GetNativeData(NS_NATIVE_EGL_WINDOW) from compositor
9790 // thread to get new native rendering surface.
9791 //
9792 // For hidden/unmapped windows we return nullptr NS_NATIVE_EGL_WINDOW at
9793 // nsWindow::GetNativeData() so RenderCompositorEGL::Resume() creates
9794 // offscreen fallback EGLSurface to avoid compositor pause.
9795 //
9796 // We don't want to pause compositor as it may lead to whole
9797 // browser freeze (Bug 1777664).
9798 //
9799 // If RenderCompositorSWGL compositor is used (SW fallback)
9800 // RenderCompositorSWGL::Resume() only requests full render for next paint
9801 // as wl_surface/XWindow is managed by WindowSurfaceProvider owned
9802 // directly by GtkCompositorWidget and that's covered by
9803 // mCompositorWidgetDelegate->CleanupResources() call above.
9804 if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) {
9805 remoteRenderer->SendResume();
9806 }
9807 }
9808}
9809
9810// Apply workaround for Mutter compositor bug (mzbz#1777269).
9811//
9812// When we open a popup window (tooltip for instance) attached to
9813// GDK_WINDOW_TYPE_HINT_UTILITY parent popup, Mutter compositor sends bogus
9814// leave/enter events to the GDK_WINDOW_TYPE_HINT_UTILITY popup.
9815// That leads to immediate tooltip close. As a workaround ignore these
9816// bogus events.
9817//
9818// We need to check two affected window types:
9819//
9820// - toplevel window with at least two child popups where the first one is
9821// GDK_WINDOW_TYPE_HINT_UTILITY.
9822// - GDK_WINDOW_TYPE_HINT_UTILITY popup with a child popup
9823//
9824// We need to mask two bogus leave/enter sequences:
9825// 1) Leave (popup) -> Enter (toplevel)
9826// 2) Leave (toplevel) -> Enter (popup)
9827//
9828// TODO: persistent (non-tracked) popups with tooltip/child popups?
9829//
9830bool nsWindow::ApplyEnterLeaveMutterWorkaround() {
9831 // Leave (toplevel) case
9832 if (mWindowType == WindowType::TopLevel && mWaylandPopupNext &&
9833 mWaylandPopupNext->mWaylandPopupNext &&
9834 gtk_window_get_type_hint(GTK_WINDOW(mWaylandPopupNext->GetGtkWidget())((((GtkWindow*) (void *) ((mWaylandPopupNext->GetGtkWidget
())))))
) ==
9835 GDK_WINDOW_TYPE_HINT_UTILITY) {
9836 LOG("nsWindow::ApplyEnterLeaveMutterWorkaround(): leave toplevel")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get()); } } while (0)
;
9837 return true;
9838 }
9839 // Leave (popup) case
9840 if (IsWaylandPopup() && mWaylandPopupNext &&
9841 gtk_window_get_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell)))))) ==
9842 GDK_WINDOW_TYPE_HINT_UTILITY) {
9843 LOG("nsWindow::ApplyEnterLeaveMutterWorkaround(): leave popup")do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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"
, GetDebugTag().get()); } } while (0)
;
9844 return true;
9845 }
9846 return false;
9847}
9848
9849void nsWindow::NotifyOcclusionState(OcclusionState aState) {
9850 if (!IsTopLevelWindowType()) {
9851 return;
9852 }
9853
9854 bool isFullyOccluded = aState == OcclusionState::OCCLUDED;
9855 if (mIsFullyOccluded == isFullyOccluded) {
9856 return;
9857 }
9858 mIsFullyOccluded = isFullyOccluded;
9859
9860 LOG("nsWindow::NotifyOcclusionState() mIsFullyOccluded %d", mIsFullyOccluded)do { const ::mozilla::LogModule* moz_real_module = IsPopup() ?
gWidgetPopupLog : gWidgetLog; if ((__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::NotifyOcclusionState() mIsFullyOccluded %d"
, GetDebugTag().get(), mIsFullyOccluded); } } while (0)
;
9861 if (mWidgetListener) {
9862 mWidgetListener->OcclusionStateChanged(mIsFullyOccluded);
9863 }
9864}
9865
9866void nsWindow::SetDragSource(GdkDragContext* aSourceDragContext) {
9867 mSourceDragContext = aSourceDragContext;
9868 if (IsPopup() &&
9869 (widget::GdkIsWaylandDisplay() || widget::IsXWaylandProtocol())) {
9870 if (auto* menuPopupFrame = GetMenuPopupFrame(GetFrame())) {
9871 menuPopupFrame->SetIsDragSource(!!aSourceDragContext);
9872 }
9873 }
9874}
9875
9876UniquePtr<MozContainerSurfaceLock> nsWindow::LockSurface() {
9877 if (mIsDestroyed) {
9878 return nullptr;
9879 }
9880 LOG_WAYLAND("nsWindow::LockSurface()")do { const ::mozilla::LogModule* moz_real_module = gWidgetWaylandLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "nsWindow::LockSurface()"
); } } while (0)
;
9881 return MakeUnique<MozContainerSurfaceLock>(mContainer);
9882}