Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp
Warning:line 2189, 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-18/lib/clang/18 -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-18/lib/clang/18/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 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -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-07-21-021012-413605-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)))
144
145struct _GdkEventTouchpadPinch {
146 GdkEventType type;
147 GdkWindow* window;
148 gint8 send_event;
149 gint8 phase;
150 gint8 n_fingers;
151 guint32 time;
152 gdouble x;
153 gdouble y;
154 gdouble dx;
155 gdouble dy;
156 gdouble angle_delta;
157 gdouble scale;
158 gdouble x_root, y_root;
159 guint state;
160};
161
162typedef enum {
163 GDK_TOUCHPAD_GESTURE_PHASE_BEGIN,
164 GDK_TOUCHPAD_GESTURE_PHASE_UPDATE,
165 GDK_TOUCHPAD_GESTURE_PHASE_END,
166 GDK_TOUCHPAD_GESTURE_PHASE_CANCEL
167} GdkTouchpadGesturePhase;
168
169gint GDK_TOUCHPAD_GESTURE_MASK = 1 << 24;
170GdkEventType GDK_TOUCHPAD_PINCH = static_cast<GdkEventType>(42);
171
172#endif
173
174const gint kEvents = GDK_TOUCHPAD_GESTURE_MASK | GDK_EXPOSURE_MASK |
175 GDK_STRUCTURE_MASK | GDK_VISIBILITY_NOTIFY_MASK |
176 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
177 GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
178 GDK_SMOOTH_SCROLL_MASK | GDK_TOUCH_MASK | GDK_SCROLL_MASK |
179 GDK_POINTER_MOTION_MASK | GDK_PROPERTY_CHANGE_MASK;
180
181/* utility functions */
182static bool is_mouse_in_window(GdkWindow* aWindow, gdouble aMouseX,
183 gdouble aMouseY);
184static nsWindow* get_window_for_gtk_widget(GtkWidget* widget);
185static nsWindow* get_window_for_gdk_window(GdkWindow* window);
186static GtkWidget* get_gtk_widget_for_gdk_window(GdkWindow* window);
187static GdkCursor* get_gtk_cursor(nsCursor aCursor);
188
189/* callbacks from widgets */
190static gboolean expose_event_cb(GtkWidget* widget, cairo_t* cr);
191static gboolean configure_event_cb(GtkWidget* widget, GdkEventConfigure* event);
192static void size_allocate_cb(GtkWidget* widget, GtkAllocation* allocation);
193static void toplevel_window_size_allocate_cb(GtkWidget* widget,
194 GtkAllocation* allocation);
195static gboolean delete_event_cb(GtkWidget* widget, GdkEventAny* event);
196static gboolean enter_notify_event_cb(GtkWidget* widget,
197 GdkEventCrossing* event);
198static gboolean leave_notify_event_cb(GtkWidget* widget,
199 GdkEventCrossing* event);
200static gboolean motion_notify_event_cb(GtkWidget* widget,
201 GdkEventMotion* event);
202MOZ_CAN_RUN_SCRIPT static gboolean button_press_event_cb(GtkWidget* widget,
203 GdkEventButton* event);
204static gboolean button_release_event_cb(GtkWidget* widget,
205 GdkEventButton* event);
206static gboolean focus_in_event_cb(GtkWidget* widget, GdkEventFocus* event);
207static gboolean focus_out_event_cb(GtkWidget* widget, GdkEventFocus* event);
208static gboolean key_press_event_cb(GtkWidget* widget, GdkEventKey* event);
209static gboolean key_release_event_cb(GtkWidget* widget, GdkEventKey* event);
210static gboolean property_notify_event_cb(GtkWidget* widget,
211 GdkEventProperty* event);
212static gboolean scroll_event_cb(GtkWidget* widget, GdkEventScroll* event);
213static gboolean visibility_notify_event_cb(GtkWidget* widget,
214 GdkEventVisibility* event);
215static void hierarchy_changed_cb(GtkWidget* widget,
216 GtkWidget* previous_toplevel);
217static gboolean window_state_event_cb(GtkWidget* widget,
218 GdkEventWindowState* event);
219static void settings_xft_dpi_changed_cb(GtkSettings* settings,
220 GParamSpec* pspec, nsWindow* data);
221static void check_resize_cb(GtkContainer* container, gpointer user_data);
222static void screen_composited_changed_cb(GdkScreen* screen, gpointer user_data);
223static void widget_composited_changed_cb(GtkWidget* widget, gpointer user_data);
224
225static void scale_changed_cb(GtkWidget* widget, GParamSpec* aPSpec,
226 gpointer aPointer);
227static gboolean touch_event_cb(GtkWidget* aWidget, GdkEventTouch* aEvent);
228static gboolean generic_event_cb(GtkWidget* widget, GdkEvent* aEvent);
229
230static nsWindow* GetFirstNSWindowForGDKWindow(GdkWindow* aGdkWindow);
231
232#ifdef __cplusplus201703L
233extern "C" {
234#endif /* __cplusplus */
235#ifdef MOZ_X111
236static GdkFilterReturn popup_take_focus_filter(GdkXEvent* gdk_xevent,
237 GdkEvent* event, gpointer data);
238#endif /* MOZ_X11 */
239#ifdef __cplusplus201703L
240}
241#endif /* __cplusplus */
242
243static gboolean drag_motion_event_cb(GtkWidget* aWidget,
244 GdkDragContext* aDragContext, gint aX,
245 gint aY, guint aTime, gpointer aData);
246static void drag_leave_event_cb(GtkWidget* aWidget,
247 GdkDragContext* aDragContext, guint aTime,
248 gpointer aData);
249static gboolean drag_drop_event_cb(GtkWidget* aWidget,
250 GdkDragContext* aDragContext, gint aX,
251 gint aY, guint aTime, gpointer aData);
252static void drag_data_received_event_cb(GtkWidget* aWidget,
253 GdkDragContext* aDragContext, gint aX,
254 gint aY,
255 GtkSelectionData* aSelectionData,
256 guint aInfo, guint32 aTime,
257 gpointer aData);
258
259/* initialization static functions */
260static nsresult initialize_prefs(void);
261
262static guint32 sLastUserInputTime = GDK_CURRENT_TIME0L;
263
264static SystemTimeConverter<guint32>& TimeConverter() {
265 static SystemTimeConverter<guint32> sTimeConverterSingleton;
266 return sTimeConverterSingleton;
267}
268
269bool nsWindow::sTransparentMainWindow = false;
270
271// forward declare from mozgtk
272extern "C" MOZ_EXPORT__attribute__((visibility("default"))) void mozgtk_linker_holder();
273
274namespace mozilla {
275
276#ifdef MOZ_X111
277class CurrentX11TimeGetter {
278 public:
279 explicit CurrentX11TimeGetter(GdkWindow* aWindow) : mWindow(aWindow) {}
280
281 guint32 GetCurrentTime() const { return gdk_x11_get_server_time(mWindow); }
282
283 void GetTimeAsyncForPossibleBackwardsSkew(const TimeStamp& aNow) {
284 // Check for in-flight request
285 if (!mAsyncUpdateStart.IsNull()) {
286 return;
287 }
288 mAsyncUpdateStart = aNow;
289
290 Display* xDisplay = GDK_WINDOW_XDISPLAY(mWindow)((gdk_x11_display_get_xdisplay (gdk_window_get_display (mWindow
))))
;
291 Window xWindow = GDK_WINDOW_XID(mWindow)(gdk_x11_window_get_xid (mWindow));
292 unsigned char c = 'a';
293 Atom timeStampPropAtom = TimeStampPropAtom();
294 XChangeProperty(xDisplay, xWindow, timeStampPropAtom, timeStampPropAtom, 8,
295 PropModeReplace0, &c, 1);
296 XFlush(xDisplay);
297 }
298
299 gboolean PropertyNotifyHandler(GtkWidget* aWidget, GdkEventProperty* aEvent) {
300 if (aEvent->atom != gdk_x11_xatom_to_atom(TimeStampPropAtom())) {
301 return FALSE(0);
302 }
303
304 guint32 eventTime = aEvent->time;
305 TimeStamp lowerBound = mAsyncUpdateStart;
306
307 TimeConverter().CompensateForBackwardsSkew(eventTime, lowerBound);
308 mAsyncUpdateStart = TimeStamp();
309 return TRUE(!(0));
310 }
311
312 private:
313 static Atom TimeStampPropAtom() {
314 return gdk_x11_get_xatom_by_name_for_display(gdk_display_get_default(),
315 "GDK_TIMESTAMP_PROP");
316 }
317
318 // This is safe because this class is stored as a member of mWindow and
319 // won't outlive it.
320 GdkWindow* mWindow;
321 TimeStamp mAsyncUpdateStart;
322};
323#endif
324
325} // namespace mozilla
326
327// The window from which the focus manager asks us to dispatch key events.
328static nsWindow* gFocusWindow = nullptr;
329static bool gBlockActivateEvent = false;
330static bool gGlobalsInitialized = false;
331static bool gUseAspectRatio = true;
332static uint32_t gLastTouchID = 0;
333// See Bug 1777269 for details. We don't know if the suspected leave notify
334// event is a correct one when we get it.
335// Store it and issue it later from enter notify event if it's correct,
336// throw it away otherwise.
337static GUniquePtr<GdkEventCrossing> sStoredLeaveNotifyEvent;
338
339#define NS_WINDOW_TITLE_MAX_LENGTH4095 4095
340
341// cursor cache
342static GdkCursor* gCursorCache[eCursorCount];
343
344// Sometimes this actually also includes the state of the modifier keys, but
345// only the button state bits are used.
346static guint gButtonState;
347
348static inline int32_t GetBitmapStride(int32_t width) {
349#if defined(MOZ_X111)
350 return (width + 7) / 8;
351#else
352 return cairo_format_stride_for_width(CAIRO_FORMAT_A1, width);
353#endif
354}
355
356static inline bool TimestampIsNewerThan(guint32 a, guint32 b) {
357 // Timestamps are just the least significant bits of a monotonically
358 // increasing function, and so the use of unsigned overflow arithmetic.
359 return a - b <= G_MAXUINT32((guint32) 0xffffffff) / 2;
360}
361
362static void UpdateLastInputEventTime(void* aGdkEvent) {
363 nsCOMPtr<nsIUserIdleServiceInternal> idleService =
364 do_GetService("@mozilla.org/widget/useridleservice;1");
365 if (idleService) {
366 idleService->ResetIdleTimeOut(0);
367 }
368
369 guint timestamp = gdk_event_get_time(static_cast<GdkEvent*>(aGdkEvent));
370 if (timestamp == GDK_CURRENT_TIME0L) {
371 return;
372 }
373
374 sLastUserInputTime = timestamp;
375}
376
377// Don't set parent (transient for) if nothing changes.
378// gtk_window_set_transient_for() blows up wl_subsurfaces used by aWindow
379// even if aParent is the same.
380static void GtkWindowSetTransientFor(GtkWindow* aWindow, GtkWindow* aParent) {
381 GtkWindow* parent = gtk_window_get_transient_for(aWindow);
382 if (parent != aParent) {
383 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"
, 383); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "gtk_window_set_transient_for() can't be used directly."
")"); do { *((volatile int*)__null) = 383; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); }
;
384 }
385}
386
387#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"
, 387); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "gtk_window_set_transient_for() can't be used directly."
")"); do { *((volatile int*)__null) = 387; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); }
\
388 { \
389 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"
, 390); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "gtk_window_set_transient_for() can't be used directly."
")"); do { *((volatile int*)__null) = 390; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
390 "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"
, 390); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "gtk_window_set_transient_for() can't be used directly."
")"); do { *((volatile int*)__null) = 390; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
; \
391 }
392
393nsWindow::nsWindow()
394 : mWindowVisibilityMutex("nsWindow::mWindowVisibilityMutex"),
395 mIsMapped(false),
396 mIsDestroyed(false),
397 mIsShown(false),
398 mNeedsShow(false),
399 mEnabled(true),
400 mCreated(false),
401 mHandleTouchEvent(false),
402 mIsDragPopup(false),
403 mCompositedScreen(gdk_screen_is_composited(gdk_screen_get_default())),
404 mIsAccelerated(false),
405 mIsAlert(false),
406 mWindowShouldStartDragging(false),
407 mHasMappedToplevel(false),
408 mRetryPointerGrab(false),
409 mPanInProgress(false),
410 mTitlebarBackdropState(false),
411 mIsChildWindow(false),
412 mAlwaysOnTop(false),
413 mNoAutoHide(false),
414 mIsTransparent(false),
415 mHasReceivedSizeAllocate(false),
416 mWidgetCursorLocked(false),
417 mUndecorated(false),
418 mPopupTrackInHierarchy(false),
419 mPopupTrackInHierarchyConfigured(false),
420 mHiddenPopupPositioned(false),
421 mTransparencyBitmapForTitlebar(false),
422 mHasAlphaVisual(false),
423 mPopupAnchored(false),
424 mPopupContextMenu(false),
425 mPopupMatchesLayout(false),
426 mPopupChanged(false),
427 mPopupTemporaryHidden(false),
428 mPopupClosed(false),
429 mPopupUseMoveToRect(false),
430 mWaitingForMoveToRectCallback(false),
431 mMovedAfterMoveToRect(false),
432 mResizedAfterMoveToRect(false),
433 mConfiguredClearColor(false),
434 mGotNonBlankPaint(false),
435 mNeedsToRetryCapturingMouse(false) {
436 mWindowType = WindowType::Child;
437 mSizeConstraints.mMaxSize = GetSafeWindowSize(mSizeConstraints.mMaxSize);
438
439 if (!gGlobalsInitialized) {
440 gGlobalsInitialized = true;
441
442 // It's OK if either of these fail, but it may not be one day.
443 initialize_prefs();
444
445#ifdef MOZ_WAYLAND1
446 // Wayland provides clipboard data to application on focus-in event
447 // so we need to init our clipboard hooks before we create window
448 // and get focus.
449 if (GdkIsWaylandDisplay()) {
450 nsCOMPtr<nsIClipboard> clipboard =
451 do_GetService("@mozilla.org/widget/clipboard;1");
452 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"
, 452); MOZ_PretendNoReturn(); } } while (0)
;
453 }
454#endif
455 }
456 // Dummy call to mozgtk to prevent the linker from removing
457 // the dependency with --as-needed.
458 // see toolkit/library/moz.build for details.
459 mozgtk_linker_holder();
460}
461
462nsWindow::~nsWindow() {
463 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)
;
464 Destroy();
465}
466
467/* static */
468void nsWindow::ReleaseGlobals() {
469 for (auto& cursor : gCursorCache) {
470 if (cursor) {
471 g_object_unref(cursor);
472 cursor = nullptr;
473 }
474 }
475}
476
477void nsWindow::DispatchActivateEvent(void) {
478#ifdef ACCESSIBILITY1
479 DispatchActivateEventAccessible();
480#endif // ACCESSIBILITY
481
482 if (mWidgetListener) mWidgetListener->WindowActivated();
483}
484
485void nsWindow::DispatchDeactivateEvent() {
486 if (mWidgetListener) {
487 mWidgetListener->WindowDeactivated();
488 }
489
490#ifdef ACCESSIBILITY1
491 DispatchDeactivateEventAccessible();
492#endif // ACCESSIBILITY
493}
494
495void nsWindow::DispatchResized() {
496 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)
497 (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)
;
498
499 mNeedsDispatchSize = LayoutDeviceIntSize(-1, -1);
500 if (mWidgetListener) {
501 mWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
502 }
503 if (mAttachedWidgetListener) {
504 mAttachedWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
505 }
506}
507
508void nsWindow::MaybeDispatchResized() {
509 if (mNeedsDispatchSize != LayoutDeviceIntSize(-1, -1) && !mIsDestroyed) {
510 mBounds.SizeTo(mNeedsDispatchSize);
511 // Check mBounds size
512 if (mCompositorSession &&
513 !wr::WindowSizeSanityCheck(mBounds.width, mBounds.height)) {
514 gfxCriticalNoteOncestatic mozilla::gfx::CriticalLog sOnceAtLine514 = mozilla::gfx
::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions(false
))
<< "Invalid mBounds in MaybeDispatchResized "
515 << mBounds << " size state " << mSizeMode;
516 }
517
518 // Notify the GtkCompositorWidget of a ClientSizeChange
519 if (mCompositorWidgetDelegate) {
520 mCompositorWidgetDelegate->NotifyClientSizeChanged(GetClientSize());
521 }
522
523 DispatchResized();
524 }
525}
526
527nsIWidgetListener* nsWindow::GetListener() {
528 return mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
529}
530
531nsresult nsWindow::DispatchEvent(WidgetGUIEvent* aEvent,
532 nsEventStatus& aStatus) {
533#ifdef DEBUG1
534 debug_DumpEvent(stdoutstdout, aEvent->mWidget, aEvent, "something", 0);
535#endif
536 aStatus = nsEventStatus_eIgnore;
537 nsIWidgetListener* listener = GetListener();
538 if (listener) {
539 aStatus = listener->HandleEvent(aEvent, mUseAttachedEvents);
540 }
541
542 return NS_OK;
543}
544
545void nsWindow::OnDestroy(void) {
546 if (mOnDestroyCalled) {
547 return;
548 }
549
550 mOnDestroyCalled = true;
551
552 // Prevent deletion.
553 nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
554
555 // release references to children, device context, toolkit + app shell
556 nsBaseWidget::OnDestroy();
557
558 // Remove association between this object and its parent and siblings.
559 nsBaseWidget::Destroy();
560 mParent = nullptr;
561
562 NotifyWindowDestroyed();
563}
564
565bool nsWindow::AreBoundsSane() {
566 // Check requested size, as mBounds might not have been updated.
567 return !mLastSizeRequest.IsEmpty();
568}
569
570void nsWindow::Destroy() {
571 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"
, 571); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 571; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
572
573 if (mIsDestroyed || !mCreated) {
574 return;
575 }
576
577 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)
;
578
579 mIsDestroyed = true;
580 mCreated = false;
581
582 MozClearHandleID(mCompositorPauseTimeoutID, g_source_remove);
583
584#ifdef MOZ_WAYLAND1
585 // Shut down our local vsync source
586 if (mWaylandVsyncSource) {
587 mWaylandVsyncSource->Shutdown();
588 mWaylandVsyncSource = nullptr;
589 }
590 mWaylandVsyncDispatcher = nullptr;
591 UnlockNativePointer();
592#endif
593
594 // Cancel (dragleave) the current drag session, if any.
595 RefPtr<nsDragService> dragService = nsDragService::GetInstance();
596 if (dragService) {
597 nsDragSession* dragSession =
598 static_cast<nsDragSession*>(dragService->GetCurrentSession(this));
599 if (dragSession && this == dragSession->GetMostRecentDestWindow()) {
600 dragSession->ScheduleLeaveEvent();
601 }
602 }
603
604 nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
605 if (rollupListener) {
606 nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
607 if (static_cast<nsIWidget*>(this) == rollupWidget) {
608 rollupListener->Rollup({});
609 }
610 }
611
612 NativeShow(false);
613
614 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"
, 614); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gtk_widget_get_mapped(mShell)"
")"); do { *((volatile int*)__null) = 614; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
615 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"
, 615); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gtk_widget_get_mapped(((((GtkWidget*) (void *) ((mContainer))))))"
")"); do { *((volatile int*)__null) = 615; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
616
617 ClearTransparencyBitmap();
618
619 DestroyLayerManager();
620
621 // mSurfaceProvider holds reference to this nsWindow so we need to explicitly
622 // clear it here to avoid nsWindow leak.
623 mSurfaceProvider.CleanupResources();
624
625 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))
;
626
627 if (mIMContext) {
628 mIMContext->OnDestroyWindow(this);
629 }
630
631 // make sure that we remove ourself as the focus window
632 if (gFocusWindow == this) {
633 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)
;
634 gFocusWindow = nullptr;
635 }
636
637 if (sStoredLeaveNotifyEvent) {
638 nsWindow* window =
639 get_window_for_gdk_window(sStoredLeaveNotifyEvent->window);
640 if (window == this) {
641 sStoredLeaveNotifyEvent = nullptr;
642 }
643 }
644
645 // We need to detach accessible object here because mContainer is a custom
646 // widget and doesn't call gtk_widget_real_destroy() from destroy handler
647 // as regular widgets.
648 if (AtkObject* ac = gtk_widget_get_accessible(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))))) {
649 gtk_accessible_set_widget(GTK_ACCESSIBLE(ac)((((GtkAccessible*) (void *) ((ac))))), nullptr);
650 }
651
652 gtk_widget_destroy(mShell);
653 mShell = nullptr;
654 mContainer = nullptr;
655
656 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"
, 657); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mGdkWindow"
") (" "mGdkWindow should be NULL when mContainer is destroyed"
")"); do { *((volatile int*)__null) = 657; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
657 "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"
, 657); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mGdkWindow"
") (" "mGdkWindow should be NULL when mContainer is destroyed"
")"); do { *((volatile int*)__null) = 657; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
658
659#ifdef ACCESSIBILITY1
660 if (mRootAccessible) {
661 mRootAccessible = nullptr;
662 }
663#endif
664
665 // Save until last because OnDestroy() may cause us to be deleted.
666 OnDestroy();
667}
668
669nsIWidget* nsWindow::GetParent() { return mParent; }
670
671float nsWindow::GetDPI() {
672 float dpi = 96.0f;
673 nsCOMPtr<nsIScreen> screen = GetWidgetScreen();
674 if (screen) {
675 screen->GetDpi(&dpi);
676 }
677 return dpi;
678}
679
680double nsWindow::GetDefaultScaleInternal() { return FractionalScaleFactor(); }
681
682DesktopToLayoutDeviceScale nsWindow::GetDesktopToDeviceScale() {
683#ifdef MOZ_WAYLAND1
684 if (GdkIsWaylandDisplay()) {
685 return DesktopToLayoutDeviceScale(FractionalScaleFactor());
686 }
687#endif
688
689 // In Gtk/X11, we manage windows using device pixels.
690 return DesktopToLayoutDeviceScale(1.0);
691}
692
693DesktopToLayoutDeviceScale nsWindow::GetDesktopToDeviceScaleByScreen() {
694#ifdef MOZ_WAYLAND1
695 // In Wayland there's no way to get absolute position of the window and use it
696 // to determine the screen factor of the monitor on which the window is
697 // placed. The window is notified of the current scale factor but not at this
698 // point, so the GdkScaleFactor can return wrong value which can lead to wrong
699 // popup placement. We need to use parent's window scale factor for the new
700 // one.
701 if (GdkIsWaylandDisplay()) {
702 nsView* view = nsView::GetViewFor(this);
703 if (view) {
704 nsView* parentView = view->GetParent();
705 if (parentView) {
706 nsIWidget* parentWidget = parentView->GetNearestWidget(nullptr);
707 if (parentWidget) {
708 return DesktopToLayoutDeviceScale(
709 parentWidget->RoundsWidgetCoordinatesTo());
710 }
711 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"
, 711)
;
712 }
713 } else {
714 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"
, 714)
;
715 }
716 }
717#endif
718 return nsBaseWidget::GetDesktopToDeviceScale();
719}
720
721// Reparent a child window to a new parent.
722void nsWindow::SetParent(nsIWidget* aNewParent) {
723 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)
;
724 if (!mIsChildWindow) {
725 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"
, 725)
;
726 return;
727 }
728
729 nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
730 if (mParent) {
731 mParent->RemoveChild(this);
732 }
733 mParent = aNewParent;
734
735 // We're already deleted, quit.
736 if (!mGdkWindow || mIsDestroyed || !aNewParent) {
737 return;
738 }
739 aNewParent->AddChild(this);
740
741 auto* newParent = static_cast<nsWindow*>(aNewParent);
742
743 // New parent is deleted, quit.
744 if (newParent->mIsDestroyed) {
745 Destroy();
746 return;
747 }
748
749 GdkWindow* window = GetToplevelGdkWindow();
750 GdkWindow* parentWindow = newParent->GetToplevelGdkWindow();
751 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)
;
752 gdk_window_reparent(window, parentWindow, 0, 0);
753 SetHasMappedToplevel(newParent && newParent->mHasMappedToplevel);
754}
755
756bool nsWindow::WidgetTypeSupportsAcceleration() {
757 if (mWindowType == WindowType::Invisible) {
758 return false;
759 }
760
761 if (IsSmallPopup()) {
762 return false;
763 }
764 // Workaround for Bug 1479135
765 // We draw transparent popups on non-compositing screens by SW as we don't
766 // implement X shape masks in WebRender.
767 if (mWindowType == WindowType::Popup) {
768 return HasRemoteContent() && mCompositedScreen;
769 }
770
771 return true;
772}
773
774void nsWindow::ReparentNativeWidget(nsIWidget* aNewParent) {
775 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"
, 775); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aNewParent" ") ("
"null widget" ")"); do { *((volatile int*)__null) = 775; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
776 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"
, 776); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mIsDestroyed"
") (" "" ")"); do { *((volatile int*)__null) = 776; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
777 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"
, 777); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!static_cast<nsWindow*>(aNewParent)->mIsDestroyed"
") (" "" ")"); do { *((volatile int*)__null) = 777; __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
;
778 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"
, 780); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mParent" ") ("
"nsWindow::ReparentNativeWidget() works on toplevel windows only."
")"); do { *((volatile int*)__null) = 780; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
779 !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"
, 780); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mParent" ") ("
"nsWindow::ReparentNativeWidget() works on toplevel windows only."
")"); do { *((volatile int*)__null) = 780; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
780 "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"
, 780); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mParent" ") ("
"nsWindow::ReparentNativeWidget() works on toplevel windows only."
")"); do { *((volatile int*)__null) = 780; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
781
782 auto* newParent = static_cast<nsWindow*>(aNewParent);
783 GtkWindow* newParentWidget = GTK_WINDOW(newParent->GetGtkWidget())((((GtkWindow*) (void *) ((newParent->GetGtkWidget())))));
784
785 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)
;
786 GtkWindowSetTransientFor(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), newParentWidget);
787}
788
789static void InitPenEvent(WidgetMouseEvent& aGeckoEvent, GdkEvent* aEvent) {
790 // Find the source of the event
791 GdkDevice* device = gdk_event_get_source_device(aEvent);
792 GdkInputSource eSource = gdk_device_get_source(device);
793 gdouble value;
794
795 // We distinguish touch screens from pens using the event type
796 // Eraser corresponds to the pen with the "erase" button pressed
797 if (eSource != GDK_SOURCE_PEN && eSource != GDK_SOURCE_ERASER) {
798 bool XWaylandPen = false;
799#ifdef MOZ_X111
800 // Workaround : When using Xwayland, pens are reported as
801 // GDK_SOURCE_TOUCHSCREEN If eSource is GDK_SOURCE_TOUCHSCREEN and the
802 // GDK_AXIS_XTILT and GDK_AXIS_YTILT axes are reported then it's a pen and
803 // not a finger on a screen. Yes, that's a stupid heuristic but it works...
804 // Note, however, that the tilt values are not reliable
805 // Another approach could be use the device tool type, but that's only
806 // available in GTK > 3.22
807 XWaylandPen = (eSource == GDK_SOURCE_TOUCHSCREEN && GdkIsX11Display() &&
808 gdk_event_get_axis(aEvent, GDK_AXIS_XTILT, &value) &&
809 gdk_event_get_axis(aEvent, GDK_AXIS_YTILT, &value));
810#endif
811 if (!XWaylandPen) {
812 return;
813 }
814 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)
;
815 }
816
817 aGeckoEvent.mInputSource = dom::MouseEvent_Binding::MOZ_SOURCE_PEN;
818 aGeckoEvent.pointerId = 1;
819
820 // The range of xtilt and ytilt are -1 to 1. Normalize it to -90 to 90.
821 if (gdk_event_get_axis(aEvent, GDK_AXIS_XTILT, &value)) {
822 aGeckoEvent.tiltX = int32_t(NS_round(value * 90));
823 }
824 if (gdk_event_get_axis(aEvent, GDK_AXIS_YTILT, &value)) {
825 aGeckoEvent.tiltY = int32_t(NS_round(value * 90));
826 }
827 if (gdk_event_get_axis(aEvent, GDK_AXIS_PRESSURE, &value)) {
828 aGeckoEvent.mPressure = (float)value;
829 // Make sure the pression is acceptable
830 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"
, 830); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aGeckoEvent.mPressure >= 0.0 && aGeckoEvent.mPressure <= 1.0"
")"); do { *((volatile int*)__null) = 830; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
831 }
832
833 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)
;
834}
835
836void nsWindow::SetModal(bool aModal) {
837 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)
;
838 if (mIsDestroyed) {
839 return;
840 }
841
842 gtk_window_set_modal(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), aModal ? TRUE(!(0)) : FALSE(0));
843}
844
845// nsIWidget method, which means IsShown.
846bool nsWindow::IsVisible() const { return mIsShown; }
847
848bool nsWindow::IsMapped() const { return mIsMapped; }
849
850void nsWindow::RegisterTouchWindow() {
851 mHandleTouchEvent = true;
852 mTouches.Clear();
853}
854
855LayoutDeviceIntPoint nsWindow::GetScreenEdgeSlop() {
856 if (DrawsToCSDTitlebar()) {
857 return GetClientOffset();
858 }
859 return {};
860}
861
862void nsWindow::ConstrainPosition(DesktopIntPoint& aPoint) {
863 if (!mShell || GdkIsWaylandDisplay()) {
864 return;
865 }
866
867 double dpiScale = GetDefaultScale().scale;
868
869 // we need to use the window size in logical screen pixels
870 int32_t logWidth = std::max(NSToIntRound(mBounds.width / dpiScale), 1);
871 int32_t logHeight = std::max(NSToIntRound(mBounds.height / dpiScale), 1);
872
873 /* get our playing field. use the current screen, or failing that
874 for any reason, use device caps for the default screen. */
875 nsCOMPtr<nsIScreenManager> screenmgr =
876 do_GetService("@mozilla.org/gfx/screenmanager;1");
877 if (!screenmgr) {
878 return;
879 }
880 nsCOMPtr<nsIScreen> screen;
881 screenmgr->ScreenForRect(aPoint.x, aPoint.y, logWidth, logHeight,
882 getter_AddRefs(screen));
883 // We don't have any screen so leave the coordinates as is
884 if (!screen) {
885 return;
886 }
887
888 // For normalized windows, use the desktop work area.
889 // For full screen windows, use the desktop.
890 DesktopIntRect screenRect = mSizeMode == nsSizeMode_Fullscreen
891 ? screen->GetRectDisplayPix()
892 : screen->GetAvailRectDisplayPix();
893
894 // Expand for the decoration size if needed.
895 auto slop =
896 DesktopIntPoint::Round(GetScreenEdgeSlop() / GetDesktopToDeviceScale());
897 screenRect.Inflate(slop.x, slop.y);
898
899 if (aPoint.x < screenRect.x) {
900 aPoint.x = screenRect.x;
901 } else if (aPoint.x >= screenRect.XMost() - logWidth) {
902 aPoint.x = screenRect.XMost() - logWidth;
903 }
904
905 if (aPoint.y < screenRect.y) {
906 aPoint.y = screenRect.y;
907 } else if (aPoint.y >= screenRect.YMost() - logHeight) {
908 aPoint.y = screenRect.YMost() - logHeight;
909 }
910}
911
912void nsWindow::SetSizeConstraints(const SizeConstraints& aConstraints) {
913 mSizeConstraints.mMinSize = GetSafeWindowSize(aConstraints.mMinSize);
914 mSizeConstraints.mMaxSize = GetSafeWindowSize(aConstraints.mMaxSize);
915
916 ApplySizeConstraints();
917}
918
919bool nsWindow::DrawsToCSDTitlebar() const {
920 return mSizeMode == nsSizeMode_Normal &&
921 mGtkWindowDecoration == GTK_DECORATION_CLIENT && mDrawInTitlebar;
922}
923
924void nsWindow::AddCSDDecorationSize(int* aWidth, int* aHeight) {
925 if (mSizeMode != nsSizeMode_Normal || mUndecorated ||
926 mGtkWindowDecoration != GTK_DECORATION_CLIENT || !GdkIsWaylandDisplay() ||
927 !IsGnomeDesktopEnvironment()) {
928 return;
929 }
930
931 GtkBorder decorationSize = GetCSDDecorationSize(IsPopup());
932 *aWidth += decorationSize.left + decorationSize.right;
933 *aHeight += decorationSize.top + decorationSize.bottom;
934}
935
936#ifdef MOZ_WAYLAND1
937bool nsWindow::GetCSDDecorationOffset(int* aDx, int* aDy) {
938 if (!DrawsToCSDTitlebar()) {
939 return false;
940 }
941 GtkBorder decorationSize = GetCSDDecorationSize(IsPopup());
942 *aDx = decorationSize.left;
943 *aDy = decorationSize.top;
944 return true;
945}
946#endif
947
948void nsWindow::ApplySizeConstraints() {
949 if (mShell) {
950 GdkGeometry geometry;
951 geometry.min_width =
952 DevicePixelsToGdkCoordRoundUp(mSizeConstraints.mMinSize.width);
953 geometry.min_height =
954 DevicePixelsToGdkCoordRoundUp(mSizeConstraints.mMinSize.height);
955 geometry.max_width =
956 DevicePixelsToGdkCoordRoundDown(mSizeConstraints.mMaxSize.width);
957 geometry.max_height =
958 DevicePixelsToGdkCoordRoundDown(mSizeConstraints.mMaxSize.height);
959
960 uint32_t hints = 0;
961 if (mSizeConstraints.mMinSize != LayoutDeviceIntSize()) {
962 gtk_widget_set_size_request(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))), geometry.min_width,
963 geometry.min_height);
964 AddCSDDecorationSize(&geometry.min_width, &geometry.min_height);
965 hints |= GDK_HINT_MIN_SIZE;
966 }
967 if (mSizeConstraints.mMaxSize !=
968 LayoutDeviceIntSize(NS_MAXSIZE, NS_MAXSIZE)) {
969 AddCSDDecorationSize(&geometry.max_width, &geometry.max_height);
970 hints |= GDK_HINT_MAX_SIZE;
971 }
972
973 if (mAspectRatio != 0.0f && !mAspectResizer) {
974 geometry.min_aspect = mAspectRatio;
975 geometry.max_aspect = mAspectRatio;
976 hints |= GDK_HINT_ASPECT;
977 }
978
979 gtk_window_set_geometry_hints(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), nullptr, &geometry,
980 GdkWindowHints(hints));
981 }
982}
983
984void nsWindow::Show(bool aState) {
985 if (aState == mIsShown) {
986 return;
987 }
988
989 mIsShown = aState;
990
991#ifdef MOZ_LOGGING1
992 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)
;
993 if (!aState && mSourceDragContext && GdkIsWaylandDisplay()) {
994 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)
;
995 }
996#endif
997
998 // Ok, someone called show on a window that isn't sized to a sane
999 // value. Mark this window as needing to have Show() called on it
1000 // and return.
1001 if ((aState && !AreBoundsSane()) || !mCreated) {
1002 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)
;
1003 mNeedsShow = true;
1004 return;
1005 }
1006
1007 // If someone is hiding this widget, clear any needing show flag.
1008 if (!aState) mNeedsShow = false;
1009
1010#ifdef ACCESSIBILITY1
1011 if (aState && a11y::ShouldA11yBeEnabled()) CreateRootAccessible();
1012#endif
1013
1014 NativeShow(aState);
1015 RefreshWindowClass();
1016}
1017
1018void nsWindow::ResizeInt(const Maybe<LayoutDeviceIntPoint>& aMove,
1019 LayoutDeviceIntSize aSize) {
1020 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)
;
1021 const bool moved = aMove && *aMove != mBounds.TopLeft();
1022 if (moved) {
1023 mBounds.MoveTo(*aMove);
1024 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
)
;
1025 }
1026
1027 ConstrainSize(&aSize.width, &aSize.height);
1028 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)
;
1029
1030 const bool resized = aSize != mLastSizeRequest || mBounds.Size() != aSize;
1031#if MOZ_LOGGING1
1032 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)
1033 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)
1034 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)
;
1035#endif
1036
1037 // For top-level windows, aSize should possibly be
1038 // interpreted as frame bounds, but NativeMoveResize treats these as window
1039 // bounds (Bug 581866).
1040 mLastSizeRequest = aSize;
1041 // Check size
1042 if (mCompositorSession &&
1043 !wr::WindowSizeSanityCheck(aSize.width, aSize.height)) {
1044 gfxCriticalNoteOncestatic mozilla::gfx::CriticalLog sOnceAtLine1044 = mozilla::gfx
::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions(false
))
<< "Invalid aSize in ResizeInt " << aSize
1045 << " size state " << mSizeMode;
1046 }
1047
1048 // Recalculate aspect ratio when resized from DOM
1049 if (mAspectRatio != 0.0) {
1050 LockAspectRatio(true);
1051 }
1052
1053 if (!mCreated) {
1054 return;
1055 }
1056
1057 if (!moved && !resized) {
1058 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)
;
1059 return;
1060 }
1061
1062 NativeMoveResize(moved, resized);
1063
1064 // We optimistically assume size changes immediately in two cases:
1065 // 1. Override-redirect window: Size is controlled by only us.
1066 // 2. Managed window that has not not yet received a size-allocate event:
1067 // Resize() Callers expect initial sizes to be applied synchronously.
1068 // If the size request is not honored, then we'll correct in
1069 // OnSizeAllocate().
1070 //
1071 // When a managed window has already received a size-allocate, we cannot
1072 // assume we'll always get a notification if our request does not get
1073 // honored: "If the configure request has not changed, we don't ever resend
1074 // it, because it could mean fighting the user or window manager."
1075 // https://gitlab.gnome.org/GNOME/gtk/-/blob/3.24.31/gtk/gtkwindow.c#L9782
1076 // So we don't update mBounds until OnSizeAllocate() when we know the
1077 // request is granted.
1078 bool isOrWillBeVisible = mHasReceivedSizeAllocate || mNeedsShow || mIsShown;
1079 if (!isOrWillBeVisible ||
1080 gtk_window_get_window_type(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell)))))) == GTK_WINDOW_POPUP) {
1081 mBounds.SizeTo(aSize);
1082 if (mCompositorWidgetDelegate) {
1083 mCompositorWidgetDelegate->NotifyClientSizeChanged(aSize);
1084 }
1085 DispatchResized();
1086 }
1087}
1088
1089void nsWindow::Resize(double aWidth, double aHeight, bool aRepaint) {
1090 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)
;
1091
1092 double scale =
1093 BoundsUseDesktopPixels() ? GetDesktopToDeviceScale().scale : 1.0;
1094 auto size = LayoutDeviceIntSize::Round(scale * aWidth, scale * aHeight);
1095
1096 ResizeInt(Nothing(), size);
1097}
1098
1099void nsWindow::Resize(double aX, double aY, double aWidth, double aHeight,
1100 bool aRepaint) {
1101 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)
1102 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)
;
1103
1104 double scale =
1105 BoundsUseDesktopPixels() ? GetDesktopToDeviceScale().scale : 1.0;
1106 auto size = LayoutDeviceIntSize::Round(scale * aWidth, scale * aHeight);
1107 auto topLeft = LayoutDeviceIntPoint::Round(scale * aX, scale * aY);
1108
1109 ResizeInt(Some(topLeft), size);
1110}
1111
1112void nsWindow::Enable(bool aState) { mEnabled = aState; }
1113
1114bool nsWindow::IsEnabled() const { return mEnabled; }
1115
1116void nsWindow::Move(double aX, double aY) {
1117 double scale =
1118 BoundsUseDesktopPixels() ? GetDesktopToDeviceScale().scale : 1.0;
1119 int32_t x = NSToIntRound(aX * scale);
1120 int32_t y = NSToIntRound(aY * scale);
1121
1122 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)
;
1123
1124 if (mSizeMode != nsSizeMode_Normal && IsTopLevelWindowType()) {
1125 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)
;
1126 return;
1127 }
1128
1129 // Since a popup window's x/y coordinates are in relation to to
1130 // the parent, the parent might have moved so we always move a
1131 // popup window.
1132 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)
;
1133 if (x == mBounds.x && y == mBounds.y && mWindowType != WindowType::Popup) {
1134 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)
;
1135 return;
1136 }
1137
1138 // XXX Should we do some AreBoundsSane check here?
1139
1140 mBounds.x = x;
1141 mBounds.y = y;
1142
1143 if (!mCreated) {
1144 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)
;
1145 return;
1146 }
1147
1148 NativeMoveResize(/* move */ true, /* resize */ false);
1149}
1150
1151bool nsWindow::IsPopup() const { return mWindowType == WindowType::Popup; }
1152
1153bool nsWindow::IsWaylandPopup() const {
1154 return GdkIsWaylandDisplay() && IsPopup();
1155}
1156
1157static nsMenuPopupFrame* GetMenuPopupFrame(nsIFrame* aFrame) {
1158 return do_QueryFrame(aFrame);
1159}
1160
1161void nsWindow::AppendPopupToHierarchyList(nsWindow* aToplevelWindow) {
1162 mWaylandToplevel = aToplevelWindow;
1163
1164 nsWindow* popup = aToplevelWindow;
1165 while (popup && popup->mWaylandPopupNext) {
1166 popup = popup->mWaylandPopupNext;
1167 }
1168 popup->mWaylandPopupNext = this;
1169
1170 mWaylandPopupPrev = popup;
1171 mWaylandPopupNext = nullptr;
1172 mPopupChanged = true;
1173 mPopupClosed = false;
1174}
1175
1176void nsWindow::RemovePopupFromHierarchyList() {
1177 // We're already removed from the popup hierarchy
1178 if (!IsInPopupHierarchy()) {
1179 return;
1180 }
1181 mWaylandPopupPrev->mWaylandPopupNext = mWaylandPopupNext;
1182 if (mWaylandPopupNext) {
1183 mWaylandPopupNext->mWaylandPopupPrev = mWaylandPopupPrev;
1184 mWaylandPopupNext->mPopupChanged = true;
1185 }
1186 mWaylandPopupNext = mWaylandPopupPrev = nullptr;
1187}
1188
1189// Gtk refuses to map popup window with x < 0 && y < 0 relative coordinates
1190// see https://gitlab.gnome.org/GNOME/gtk/-/issues/4071
1191// as a workaround just fool around and place the popup temporary to 0,0.
1192bool nsWindow::WaylandPopupRemoveNegativePosition(int* aX, int* aY) {
1193 // https://gitlab.gnome.org/GNOME/gtk/-/issues/4071 applies to temporary
1194 // windows only
1195 GdkWindow* window = GetToplevelGdkWindow();
1196 if (!window || gdk_window_get_window_type(window) != GDK_WINDOW_TEMP) {
1197 return false;
1198 }
1199
1200 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)
;
1201
1202 int x, y;
1203 gtk_window_get_position(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), &x, &y);
1204 bool moveBack = (x < 0 && y < 0);
1205 if (moveBack) {
1206 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), 0, 0);
1207 if (aX) {
1208 *aX = x;
1209 }
1210 if (aY) {
1211 *aY = y;
1212 }
1213 }
1214
1215 gdk_window_get_geometry(window, &x, &y, nullptr, nullptr);
1216 if (x < 0 && y < 0) {
1217 gdk_window_move(window, 0, 0);
1218 }
1219
1220 return moveBack;
1221}
1222
1223void nsWindow::ShowWaylandPopupWindow() {
1224 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)
;
1225 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"
, 1225); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsWaylandPopup()"
")"); do { *((volatile int*)__null) = 1225; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1226
1227 if (!mPopupTrackInHierarchy) {
1228 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)
;
1229 gtk_widget_show(mShell);
1230 return;
1231 }
1232
1233 // Popup position was checked before gdk_window_move_to_rect() callback
1234 // so just show it.
1235 if (mPopupUseMoveToRect && mWaitingForMoveToRectCallback) {
1236 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)
;
1237 gtk_widget_show(mShell);
1238 return;
1239 }
1240
1241 if (gtk_widget_is_visible(mShell)) {
1242 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)
;
1243 return;
1244 }
1245
1246 int x, y;
1247 bool moved = WaylandPopupRemoveNegativePosition(&x, &y);
1248 gtk_widget_show(mShell);
1249 if (moved) {
1250 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)
;
1251 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), x, y);
1252 }
1253}
1254
1255void nsWindow::WaylandPopupMarkAsClosed() {
1256 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)
;
1257 mPopupClosed = true;
1258 // If we have any child popup window notify it about
1259 // parent switch.
1260 if (mWaylandPopupNext) {
1261 mWaylandPopupNext->mPopupChanged = true;
1262 }
1263}
1264
1265nsWindow* nsWindow::WaylandPopupFindLast(nsWindow* aPopup) {
1266 while (aPopup && aPopup->mWaylandPopupNext) {
1267 aPopup = aPopup->mWaylandPopupNext;
1268 }
1269 return aPopup;
1270}
1271
1272// Hide and potentially removes popup from popup hierarchy.
1273void nsWindow::HideWaylandPopupWindow(bool aTemporaryHide,
1274 bool aRemoveFromPopupList) {
1275 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)
1276 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)
;
1277 if (aRemoveFromPopupList) {
1278 RemovePopupFromHierarchyList();
1279 }
1280
1281 if (!mPopupClosed) {
1282 mPopupClosed = !aTemporaryHide;
1283 }
1284
1285 bool visible = gtk_widget_is_visible(mShell);
1286 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)
;
1287
1288 // Restore only popups which are really visible
1289 mPopupTemporaryHidden = aTemporaryHide && visible;
1290
1291 // Hide only visible popups or popups closed pernamently.
1292 if (visible) {
1293 gtk_widget_hide(mShell);
1294
1295 // If there's pending Move-To-Rect callback and we hide the popup
1296 // the callback won't be called any more.
1297 mWaitingForMoveToRectCallback = false;
1298 }
1299
1300 if (mPopupClosed) {
1301 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)
;
1302 mMoveToRectPopupSize = {};
1303#ifdef MOZ_WAYLAND1
1304 if (moz_container_wayland_is_waiting_to_show(mContainer)) {
1305 // We need to clear rendering queue, see Bug 1782948.
1306 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)
1307 "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)
;
1308 moz_container_wayland_clear_waiting_to_show_flag(mContainer);
1309 ClearRenderingQueue();
1310 }
1311#endif
1312 }
1313}
1314
1315void nsWindow::HideWaylandToplevelWindow() {
1316 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)
;
1317 if (mWaylandPopupNext) {
1318 nsWindow* popup = WaylandPopupFindLast(mWaylandPopupNext);
1319 while (popup->mWaylandToplevel != nullptr) {
1320 nsWindow* prev = popup->mWaylandPopupPrev;
1321 popup->HideWaylandPopupWindow(/* aTemporaryHide */ false,
1322 /* aRemoveFromPopupList */ true);
1323 popup = prev;
1324 }
1325 }
1326 WaylandStopVsync();
1327 gtk_widget_hide(mShell);
1328}
1329
1330void nsWindow::ShowWaylandToplevelWindow() {
1331 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"
, 1331); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!IsWaylandPopup()"
")"); do { *((volatile int*)__null) = 1331; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1332 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)
;
1333 gtk_widget_show(mShell);
1334}
1335
1336void nsWindow::WaylandPopupRemoveClosedPopups() {
1337 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)
;
1338 nsWindow* popup = this;
1339 while (popup) {
1340 nsWindow* next = popup->mWaylandPopupNext;
1341 if (popup->mPopupClosed) {
1342 popup->HideWaylandPopupWindow(/* aTemporaryHide */ false,
1343 /* aRemoveFromPopupList */ true);
1344 }
1345 popup = next;
1346 }
1347}
1348
1349// Hide all tooltips except the latest one.
1350void nsWindow::WaylandPopupHideTooltips() {
1351 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)
;
1352 MOZ_ASSERT(mWaylandToplevel == nullptr, "Should be called on toplevel only!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mWaylandToplevel == nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mWaylandToplevel == nullptr)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mWaylandToplevel == nullptr"
" (" "Should be called on toplevel only!" ")", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 1352); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWaylandToplevel == nullptr"
") (" "Should be called on toplevel only!" ")"); do { *((volatile
int*)__null) = 1352; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1353
1354 nsWindow* popup = mWaylandPopupNext;
1355 while (popup && popup->mWaylandPopupNext) {
1356 if (popup->mPopupType == PopupType::Tooltip) {
1357 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)
;
1358 popup->WaylandPopupMarkAsClosed();
1359 }
1360 popup = popup->mWaylandPopupNext;
1361 }
1362}
1363
1364void nsWindow::WaylandPopupCloseOrphanedPopups() {
1365#ifdef MOZ_WAYLAND1
1366 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)
;
1367 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"
, 1367); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWaylandToplevel == nullptr"
") (" "Should be called on toplevel only!" ")"); do { *((volatile
int*)__null) = 1367; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1368
1369 nsWindow* popup = mWaylandPopupNext;
1370 bool dangling = false;
1371 while (popup) {
1372 if (!dangling &&
1373 moz_container_wayland_is_waiting_to_show(popup->GetMozContainer())) {
1374 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)
;
1375 dangling = true;
1376 } else if (dangling) {
1377 popup->WaylandPopupMarkAsClosed();
1378 }
1379 popup = popup->mWaylandPopupNext;
1380 }
1381#endif
1382}
1383
1384// We can't show popups with remote content or overflow popups
1385// on top of regular ones.
1386// If there's any remote popup opened, close all parent popups of it.
1387void nsWindow::CloseAllPopupsBeforeRemotePopup() {
1388 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)
;
1389 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"
, 1389); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWaylandToplevel == nullptr"
") (" "Should be called on toplevel only!" ")"); do { *((volatile
int*)__null) = 1389; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1390
1391 // Don't waste time when there's only one popup opened.
1392 if (!mWaylandPopupNext || mWaylandPopupNext->mWaylandPopupNext == nullptr) {
1393 return;
1394 }
1395
1396 // Find the first opened remote content popup
1397 nsWindow* remotePopup = mWaylandPopupNext;
1398 while (remotePopup) {
1399 if (remotePopup->HasRemoteContent() ||
1400 remotePopup->IsWidgetOverflowWindow()) {
1401 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)
;
1402 break;
1403 }
1404 remotePopup = remotePopup->mWaylandPopupNext;
1405 }
1406
1407 if (!remotePopup) {
1408 return;
1409 }
1410
1411 // ...hide opened popups before the remote one.
1412 nsWindow* popup = mWaylandPopupNext;
1413 while (popup && popup != remotePopup) {
1414 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)
;
1415 popup->WaylandPopupMarkAsClosed();
1416 popup = popup->mWaylandPopupNext;
1417 }
1418}
1419
1420static void GetLayoutPopupWidgetChain(
1421 nsTArray<nsIWidget*>* aLayoutWidgetHierarchy) {
1422 nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
1423 pm->GetSubmenuWidgetChain(aLayoutWidgetHierarchy);
1424 aLayoutWidgetHierarchy->Reverse();
1425}
1426
1427// Compare 'this' popup position in Wayland widget hierarchy
1428// (mWaylandPopupPrev/mWaylandPopupNext) with
1429// 'this' popup position in layout hierarchy.
1430//
1431// When aMustMatchParent is true we also request
1432// 'this' parents match, i.e. 'this' has the same parent in
1433// both layout and widget hierarchy.
1434bool nsWindow::IsPopupInLayoutPopupChain(
1435 nsTArray<nsIWidget*>* aLayoutWidgetHierarchy, bool aMustMatchParent) {
1436 int len = (int)aLayoutWidgetHierarchy->Length();
1437 for (int i = 0; i < len; i++) {
1438 if (this == (*aLayoutWidgetHierarchy)[i]) {
1439 if (!aMustMatchParent) {
1440 return true;
1441 }
1442
1443 // Find correct parent popup for 'this' according to widget
1444 // hierarchy. That means we need to skip closed popups.
1445 nsWindow* parentPopup = nullptr;
1446 if (mWaylandPopupPrev != mWaylandToplevel) {
1447 parentPopup = mWaylandPopupPrev;
1448 while (parentPopup != mWaylandToplevel && parentPopup->mPopupClosed) {
1449 parentPopup = parentPopup->mWaylandPopupPrev;
1450 }
1451 }
1452
1453 if (i == 0) {
1454 // We found 'this' popups as a first popup in layout hierarchy.
1455 // It matches layout hierarchy if it's first widget also in
1456 // wayland widget hierarchy (i.e. parent is null).
1457 return parentPopup == nullptr;
1458 }
1459
1460 return parentPopup == (*aLayoutWidgetHierarchy)[i - 1];
1461 }
1462 }
1463 return false;
1464}
1465
1466// Hide popups which are not in popup chain.
1467void nsWindow::WaylandPopupHierarchyHideByLayout(
1468 nsTArray<nsIWidget*>* aLayoutWidgetHierarchy) {
1469 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)
;
1470 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"
, 1470); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mWaylandToplevel == nullptr"
") (" "Should be called on toplevel only!" ")"); do { *((volatile
int*)__null) = 1470; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
1471
1472 // Hide all popups which are not in layout popup chain
1473 nsWindow* popup = mWaylandPopupNext;
1474 while (popup) {
1475 // Don't check closed popups and drag source popups and tooltips.
1476 if (!popup->mPopupClosed && popup->mPopupType != PopupType::Tooltip &&
1477 !popup->mSourceDragContext) {
1478 if (!popup->IsPopupInLayoutPopupChain(aLayoutWidgetHierarchy,
1479 /* aMustMatchParent */ false)) {
1480 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)
;
1481 popup->WaylandPopupMarkAsClosed();
1482 }
1483 }
1484 popup = popup->mWaylandPopupNext;
1485 }
1486}
1487
1488// Mark popups outside of layout hierarchy
1489void nsWindow::WaylandPopupHierarchyValidateByLayout(
1490 nsTArray<nsIWidget*>* aLayoutWidgetHierarchy) {
1491 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)
;
1492 nsWindow* popup = mWaylandPopupNext;
1493 while (popup) {
1494 if (popup->mPopupType == PopupType::Tooltip) {
1495 popup->mPopupMatchesLayout = true;
1496 } else if (!popup->mPopupClosed) {
1497 popup->mPopupMatchesLayout = popup->IsPopupInLayoutPopupChain(
1498 aLayoutWidgetHierarchy, /* aMustMatchParent */ true);
1499 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)
1500 (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)
;
1501 }
1502 popup = popup->mWaylandPopupNext;
1503 }
1504}
1505
1506void nsWindow::WaylandPopupHierarchyHideTemporary() {
1507 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)
;
1508 nsWindow* popup = WaylandPopupFindLast(this);
1509 while (popup && popup != this) {
1510 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)
;
1511 nsWindow* prev = popup->mWaylandPopupPrev;
1512 popup->HideWaylandPopupWindow(/* aTemporaryHide */ true,
1513 /* aRemoveFromPopupList */ false);
1514 popup = prev;
1515 }
1516}
1517
1518void nsWindow::WaylandPopupHierarchyShowTemporaryHidden() {
1519 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)
;
1520 nsWindow* popup = this;
1521 while (popup) {
1522 if (popup->mPopupTemporaryHidden) {
1523 popup->mPopupTemporaryHidden = false;
1524 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)
;
1525 popup->ShowWaylandPopupWindow();
1526 }
1527 popup = popup->mWaylandPopupNext;
1528 }
1529}
1530
1531void nsWindow::WaylandPopupHierarchyCalculatePositions() {
1532 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)
;
1533
1534 // Set widget hierarchy in Gtk
1535 nsWindow* popup = mWaylandToplevel->mWaylandPopupNext;
1536 while (popup) {
1537 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)
1538 (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)
;
1539 GtkWindowSetTransientFor(GTK_WINDOW(popup->mShell)((((GtkWindow*) (void *) ((popup->mShell))))),
1540 GTK_WINDOW(popup->mWaylandPopupPrev->mShell)((((GtkWindow*) (void *) ((popup->mWaylandPopupPrev->mShell
)))))
);
1541 popup = popup->mWaylandPopupNext;
1542 }
1543
1544 popup = this;
1545 while (popup) {
1546 // Anchored window has mPopupPosition already calculated against
1547 // its parent, no need to recalculate.
1548 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
)
1549 (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
)
1550 (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
)
1551 (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
)
1552 (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
)
;
1553#ifdef MOZ_LOGGING1
1554 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)
))
) {
1555 if (nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame())) {
1556 auto r = LayoutDeviceRect::FromAppUnitsRounded(
1557 popupFrame->GetRect(),
1558 popupFrame->PresContext()->AppUnitsPerDevPixel());
1559 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)
1560 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)
;
1561 }
1562 }
1563#endif
1564 if (popup->WaylandPopupIsFirst()) {
1565 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)
;
1566 popup->mRelativePopupPosition = popup->mPopupPosition;
1567 } else {
1568 if (popup->mPopupAnchored) {
1569 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)
;
1570 if (!popup->mPopupMatchesLayout) {
1571 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"
, 1571)
;
1572 }
1573 }
1574 GdkPoint parent = popup->WaylandGetParentPosition();
1575
1576 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)
;
1577 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)
;
1578 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)
1579 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)
;
1580
1581 popup->mRelativePopupPosition.x = popup->mPopupPosition.x - parent.x;
1582 popup->mRelativePopupPosition.y = popup->mPopupPosition.y - parent.y;
1583 }
1584 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)
1585 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)
1586 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)
;
1587 popup = popup->mWaylandPopupNext;
1588 }
1589}
1590
1591// The MenuList popups are used as dropdown menus for example in WebRTC
1592// microphone/camera chooser or autocomplete widgets.
1593bool nsWindow::WaylandPopupIsMenu() {
1594 nsMenuPopupFrame* menuPopupFrame = GetMenuPopupFrame(GetFrame());
1595 if (menuPopupFrame) {
1596 return mPopupType == PopupType::Menu && !menuPopupFrame->IsMenuList();
1597 }
1598 return false;
1599}
1600
1601bool nsWindow::WaylandPopupIsContextMenu() {
1602 nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame());
1603 if (!popupFrame) {
1604 return false;
1605 }
1606 return popupFrame->IsContextMenu();
1607}
1608
1609bool nsWindow::WaylandPopupIsPermanent() {
1610 nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame());
1611 if (!popupFrame) {
1612 // We can always hide popups without frames.
1613 return false;
1614 }
1615 return popupFrame->IsNoAutoHide();
1616}
1617
1618bool nsWindow::WaylandPopupIsAnchored() {
1619 nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame());
1620 if (!popupFrame) {
1621 // We can always hide popups without frames.
1622 return false;
1623 }
1624 return !!popupFrame->GetAnchor();
1625}
1626
1627bool nsWindow::IsWidgetOverflowWindow() {
1628 if (this->GetFrame() && this->GetFrame()->GetContent()->GetID()) {
1629 nsCString nodeId;
1630 this->GetFrame()->GetContent()->GetID()->ToUTF8String(nodeId);
1631 return nodeId.Equals("widget-overflow");
1632 }
1633 return false;
1634}
1635
1636bool nsWindow::WaylandPopupIsFirst() {
1637 return !mWaylandPopupPrev || !mWaylandPopupPrev->mWaylandToplevel;
1638}
1639
1640nsWindow* nsWindow::GetEffectiveParent() {
1641 GtkWindow* parentGtkWindow = gtk_window_get_transient_for(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
1642 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; }))))
) {
1643 return nullptr;
1644 }
1645 return get_window_for_gtk_widget(GTK_WIDGET(parentGtkWindow)((((GtkWidget*) (void *) ((parentGtkWindow))))));
1646}
1647
1648GdkPoint nsWindow::WaylandGetParentPosition() {
1649 GdkPoint topLeft = {0, 0};
1650 nsWindow* window = GetEffectiveParent();
1651 if (window->IsPopup()) {
1652 topLeft = DevicePixelsToGdkPointRoundDown(window->mBounds.TopLeft());
1653 }
1654 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)
;
1655 return topLeft;
1656}
1657
1658#ifdef MOZ_LOGGING1
1659void nsWindow::LogPopupHierarchy() {
1660 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)
))
) {
1661 return;
1662 }
1663
1664 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)
;
1665 if (!mWaylandToplevel->mWaylandPopupNext) {
1666 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)
;
1667 } else {
1668 int indent = 4;
1669 nsWindow* popup = mWaylandToplevel->mWaylandPopupNext;
1670 while (popup) {
1671 nsPrintfCString indentString("%*s", indent, " ");
1672 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)
1673 "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)
1674 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)
1675 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)
1676 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)
1677 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)
1678 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)
;
1679 indent += 4;
1680 popup = popup->mWaylandPopupNext;
1681 }
1682 }
1683
1684 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)
;
1685 AutoTArray<nsIWidget*, 5> widgetChain;
1686 GetLayoutPopupWidgetChain(&widgetChain);
1687 if (widgetChain.Length() == 0) {
1688 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)
;
1689 } else {
1690 for (unsigned long i = 0; i < widgetChain.Length(); i++) {
1691 nsWindow* window = static_cast<nsWindow*>(widgetChain[i]);
1692 nsPrintfCString indentString("%*s", (int)(i + 1) * 4, " ");
1693 if (window) {
1694 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)
1695 "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)
1696 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)
1697 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)
1698 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)
1699 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)
1700 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)
;
1701 } else {
1702 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)
;
1703 }
1704 }
1705 }
1706}
1707#endif
1708
1709nsWindow* nsWindow::GetTopmostWindow() {
1710 if (nsView* view = nsView::GetViewFor(this)) {
1711 if (nsView* parentView = view->GetParent()) {
1712 if (nsIWidget* parentWidget = parentView->GetNearestWidget(nullptr)) {
1713 return static_cast<nsWindow*>(parentWidget);
1714 }
1715 }
1716 }
1717 return nullptr;
1718}
1719
1720// Configure Wayland popup. If true is returned we need to track popup
1721// in popup hierarchy. Otherwise we just show it as is.
1722bool nsWindow::WaylandPopupConfigure() {
1723 if (mIsDragPopup) {
1724 return false;
1725 }
1726
1727 // Don't track popups without frame
1728 nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame());
1729 if (!popupFrame) {
1730 return false;
1731 }
1732
1733 // Popup state can be changed, see Bug 1728952.
1734 bool permanentStateMatches =
1735 mPopupTrackInHierarchy == !WaylandPopupIsPermanent();
1736
1737 // Popup permanent state (noautohide attribute) can change during popup life.
1738 if (mPopupTrackInHierarchyConfigured && permanentStateMatches) {
1739 return mPopupTrackInHierarchy;
1740 }
1741
1742 // Configure persistent popup params only once.
1743 // WaylandPopupIsAnchored() can give it wrong value after
1744 // nsMenuPopupFrame::MoveTo() call which we use in move-to-rect callback
1745 // to position popup after wayland position change.
1746 if (!mPopupTrackInHierarchyConfigured) {
1747 mPopupAnchored = WaylandPopupIsAnchored();
1748 mPopupContextMenu = WaylandPopupIsContextMenu();
1749 }
1750
1751 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)
1752 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)
;
1753
1754 // Permanent state changed and popup is mapped.
1755 // We need to switch popup type but that's done when popup is mapped
1756 // by Gtk so we need to unmap the popup here.
1757 // It will be mapped again by gtk_widget_show().
1758 if (!permanentStateMatches && mIsMapped) {
1759 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)
1760 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)
;
1761 gtk_widget_unmap(mShell);
1762 }
1763
1764 mPopupTrackInHierarchy = !WaylandPopupIsPermanent();
1765 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)
;
1766
1767 // See gdkwindow-wayland.c and
1768 // should_map_as_popup()/should_map_as_subsurface()
1769 GdkWindowTypeHint gtkTypeHint;
1770 switch (mPopupType) {
1771 case PopupType::Menu:
1772 // GDK_WINDOW_TYPE_HINT_POPUP_MENU is mapped as xdg_popup by default.
1773 // We use this type for all menu popups.
1774 gtkTypeHint = GDK_WINDOW_TYPE_HINT_POPUP_MENU;
1775 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)
;
1776 break;
1777 case PopupType::Tooltip:
1778 gtkTypeHint = GDK_WINDOW_TYPE_HINT_TOOLTIP;
1779 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)
;
1780 break;
1781 default:
1782 gtkTypeHint = GDK_WINDOW_TYPE_HINT_UTILITY;
1783 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)
;
1784 break;
1785 }
1786
1787 if (!mPopupTrackInHierarchy) {
1788 // GDK_WINDOW_TYPE_HINT_UTILITY is mapped as wl_subsurface
1789 // by default.
1790 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)
;
1791 gtkTypeHint = GDK_WINDOW_TYPE_HINT_UTILITY;
1792 }
1793 gtk_window_set_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), gtkTypeHint);
1794
1795 mPopupTrackInHierarchyConfigured = true;
1796 return mPopupTrackInHierarchy;
1797}
1798
1799bool nsWindow::IsInPopupHierarchy() {
1800 return mPopupTrackInHierarchy && mWaylandToplevel && mWaylandPopupPrev;
1801}
1802
1803void nsWindow::AddWindowToPopupHierarchy() {
1804 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)
;
1805 if (!GetFrame()) {
1806 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)
;
1807 return;
1808 }
1809
1810 // Check if we're already in the hierarchy
1811 if (!IsInPopupHierarchy()) {
1812 mWaylandToplevel = GetTopmostWindow();
1813 AppendPopupToHierarchyList(mWaylandToplevel);
1814 }
1815}
1816
1817// Wayland keeps strong popup window hierarchy. We need to track active
1818// (visible) popup windows and make sure we hide popup on the same level
1819// before we open another one on that level. It means that every open
1820// popup needs to have an unique parent.
1821void nsWindow::UpdateWaylandPopupHierarchy() {
1822 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)
;
1823
1824 // This popup hasn't been added to popup hierarchy yet so no need to
1825 // do any configurations.
1826 if (!IsInPopupHierarchy()) {
1827 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)
;
1828 return;
1829 }
1830
1831#ifdef MOZ_LOGGING1
1832 LogPopupHierarchy();
1833 auto printPopupHierarchy = MakeScopeExit([&] { LogPopupHierarchy(); });
1834#endif
1835
1836 // Hide all tooltips without the last one. Tooltip can't be popup parent.
1837 mWaylandToplevel->WaylandPopupHideTooltips();
1838
1839 // See Bug 1709254 / https://gitlab.gnome.org/GNOME/gtk/-/issues/5092
1840 // It's possible that Wayland compositor refuses to show
1841 // a popup although Gtk claims it's visible.
1842 // We don't know if the popup is shown or not.
1843 // To avoid application crash refuse to create any child of such invisible
1844 // popup and close any child of it now.
1845 mWaylandToplevel->WaylandPopupCloseOrphanedPopups();
1846
1847 // Check if we have any remote content / overflow window in hierarchy.
1848 // We can't attach such widget on top of other popup.
1849 mWaylandToplevel->CloseAllPopupsBeforeRemotePopup();
1850
1851 // Check if your popup hierarchy matches layout hierarchy.
1852 // For instance we should not connect hamburger menu on top
1853 // of context menu.
1854 // Close all popups from different layout chains if possible.
1855 AutoTArray<nsIWidget*, 5> layoutPopupWidgetChain;
1856 GetLayoutPopupWidgetChain(&layoutPopupWidgetChain);
1857
1858 mWaylandToplevel->WaylandPopupHierarchyHideByLayout(&layoutPopupWidgetChain);
1859 mWaylandToplevel->WaylandPopupHierarchyValidateByLayout(
1860 &layoutPopupWidgetChain);
1861
1862 // Now we have Popup hierarchy complete.
1863 // Find first unchanged (and still open) popup to start with hierarchy
1864 // changes.
1865 nsWindow* changedPopup = mWaylandToplevel->mWaylandPopupNext;
1866 while (changedPopup) {
1867 // Stop when parent of this popup was changed and we need to recalc
1868 // popup position.
1869 if (changedPopup->mPopupChanged) {
1870 break;
1871 }
1872 // Stop when this popup is closed.
1873 if (changedPopup->mPopupClosed) {
1874 break;
1875 }
1876 changedPopup = changedPopup->mWaylandPopupNext;
1877 }
1878
1879 // We don't need to recompute popup positions, quit now.
1880 if (!changedPopup) {
1881 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)
;
1882 return;
1883 }
1884
1885 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)
;
1886
1887 // Hide parent popups if necessary (there are layout discontinuity)
1888 // reposition the popup and show them again.
1889 changedPopup->WaylandPopupHierarchyHideTemporary();
1890
1891 nsWindow* parentOfchangedPopup = nullptr;
1892 if (changedPopup->mPopupClosed) {
1893 parentOfchangedPopup = changedPopup->mWaylandPopupPrev;
1894 }
1895 changedPopup->WaylandPopupRemoveClosedPopups();
1896
1897 // It's possible that changedPopup was removed from widget hierarchy,
1898 // in such case use child popup of the removed one if there's any.
1899 if (!changedPopup->IsInPopupHierarchy()) {
1900 if (!parentOfchangedPopup || !parentOfchangedPopup->mWaylandPopupNext) {
1901 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)
;
1902 return;
1903 }
1904 changedPopup = parentOfchangedPopup->mWaylandPopupNext;
1905 }
1906
1907 GetLayoutPopupWidgetChain(&layoutPopupWidgetChain);
1908 mWaylandToplevel->WaylandPopupHierarchyValidateByLayout(
1909 &layoutPopupWidgetChain);
1910
1911 changedPopup->WaylandPopupHierarchyCalculatePositions();
1912
1913 nsWindow* popup = changedPopup;
1914 while (popup) {
1915 const bool useMoveToRect = [&] {
1916 if (!StaticPrefs::widget_wayland_use_move_to_rect_AtStartup()) {
1917 return false; // Not available.
1918 }
1919 if (!popup->mPopupMatchesLayout) {
1920 // We can use move_to_rect only when popups in popup hierarchy matches
1921 // layout hierarchy as move_to_rect request that parent/child
1922 // popups are adjacent.
1923 return false;
1924 }
1925 if (popup->mPopupType == PopupType::Panel &&
1926 popup->WaylandPopupIsFirst() &&
1927 popup->WaylandPopupFitsToplevelWindow(/* aMove */ true)) {
1928 // Workaround for https://gitlab.gnome.org/GNOME/gtk/-/issues/1986
1929 //
1930 // PopupType::Panel types are used for extension popups which may be
1931 // resized. If such popup uses move-to-rect, we need to hide it before
1932 // resize and show it again. That leads to massive flickering
1933 // so use plain move if possible to avoid it.
1934 //
1935 // Bug 1760276 - don't use move-to-rect when popup is inside main
1936 // Firefox window.
1937 //
1938 // Use it for first popups only due to another mutter bug
1939 // https://gitlab.gnome.org/GNOME/gtk/-/issues/5089
1940 // https://bugzilla.mozilla.org/show_bug.cgi?id=1784873
1941 return false;
1942 }
1943 if (!popup->WaylandPopupIsFirst() &&
1944 !popup->mWaylandPopupPrev->WaylandPopupIsFirst() &&
1945 !popup->mWaylandPopupPrev->mPopupUseMoveToRect) {
1946 // We can't use move-to-rect if there are more parents of
1947 // wl_subsurface popups types.
1948 //
1949 // It's because wl_subsurface is ignored by xgd_popup
1950 // (created by move-to-rect) so our popup scenario:
1951 //
1952 // toplevel -> xgd_popup(1) -> wl_subsurface(2) -> xgd_popup(3)
1953 //
1954 // looks for Wayland compositor as:
1955 //
1956 // toplevel -> xgd_popup(1) -> xgd_popup(3)
1957 //
1958 // If xgd_popup(1) and xgd_popup(3) are not connected
1959 // move-to-rect applied to xgd_popup(3) fails and we get missing popup.
1960 return false;
1961 }
1962 return true;
1963 }();
1964
1965 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)
1966 "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)
1967 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)
1968 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)
;
1969
1970 popup->mPopupUseMoveToRect = useMoveToRect;
1971 popup->WaylandPopupMoveImpl();
1972 popup->mPopupChanged = false;
1973 popup = popup->mWaylandPopupNext;
1974 }
1975
1976 changedPopup->WaylandPopupHierarchyShowTemporaryHidden();
1977}
1978
1979static void NativeMoveResizeCallback(GdkWindow* window,
1980 const GdkRectangle* flipped_rect,
1981 const GdkRectangle* final_rect,
1982 gboolean flipped_x, gboolean flipped_y,
1983 void* aWindow) {
1984 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)
1985 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)
;
1986 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)
1987 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)
1988 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)
;
1989 nsWindow* wnd = get_window_for_gdk_window(window);
1990
1991 wnd->NativeMoveResizeWaylandPopupCallback(final_rect, flipped_x, flipped_y);
1992}
1993
1994// When popup is repositioned by widget code, we need to notify
1995// layout about it. It's because we control popup placement
1996// on widget on Wayland so layout may have old popup size/coordinates.
1997void nsWindow::WaylandPopupPropagateChangesToLayout(bool aMove, bool aResize) {
1998 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)
;
1999
2000 if (aResize) {
2001 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)
;
2002 if (nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame())) {
2003 RefPtr<PresShell> presShell = popupFrame->PresShell();
2004 presShell->FrameNeedsReflow(popupFrame, IntrinsicDirty::None,
2005 NS_FRAME_IS_DIRTY);
2006 }
2007 }
2008 if (aMove) {
2009 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)
;
2010 NotifyWindowMoved(mBounds.x, mBounds.y, ByMoveToRect::Yes);
2011 }
2012}
2013
2014void nsWindow::NativeMoveResizeWaylandPopupCallback(
2015 const GdkRectangle* aFinalSize, bool aFlippedX, bool aFlippedY) {
2016 // We're getting move-to-rect callback without move-to-rect call.
2017 // That indicates a compositor bug. It happens when a window is hidden and
2018 // shown again before move-to-rect callback is fired.
2019 // It may lead to incorrect popup placement as we may call
2020 // gtk_window_move() between hide & show.
2021 // See Bug 1777919, 1789581.
2022#if MOZ_LOGGING1
2023 if (!mWaitingForMoveToRectCallback) {
2024 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)
;
2025 }
2026#endif
2027
2028 mWaitingForMoveToRectCallback = false;
2029
2030 bool movedByLayout = mMovedAfterMoveToRect;
2031 bool resizedByLayout = mResizedAfterMoveToRect;
2032
2033 // Popup was moved between move-to-rect call and move-to-rect callback
2034 // and the coordinates from move-to-rect callback are outdated.
2035 if (movedByLayout || resizedByLayout) {
2036 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)
;
2037 mMovedAfterMoveToRect = false;
2038 mResizedAfterMoveToRect = false;
2039 // Fire another round of move/resize to reflect latest request
2040 // from layout.
2041 NativeMoveResize(movedByLayout, resizedByLayout);
2042 return;
2043 }
2044
2045 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)
2046 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)
;
2047
2048 LayoutDeviceIntRect newBounds = [&] {
2049 GdkRectangle finalRect = *aFinalSize;
2050 GdkPoint parent = WaylandGetParentPosition();
2051 finalRect.x += parent.x;
2052 finalRect.y += parent.y;
2053 return GdkRectToDevicePixels(finalRect);
2054 }();
2055
2056 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)
2057 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)
;
2058
2059 bool needsPositionUpdate = newBounds.TopLeft() != mBounds.TopLeft();
2060 bool needsSizeUpdate = newBounds.Size() != mLastSizeRequest;
2061
2062 if (needsSizeUpdate) {
2063 // Wayland compositor changed popup size request from layout.
2064 // Set the constraints to use them in nsMenuPopupFrame::SetPopupPosition().
2065 // Beware that gtk_window_resize() requests sizes asynchronously and so
2066 // newBounds might not have the size from the most recent
2067 // gtk_window_resize().
2068 if (newBounds.width < mLastSizeRequest.width) {
2069 mMoveToRectPopupSize.width = newBounds.width;
2070 }
2071 if (newBounds.height < mLastSizeRequest.height) {
2072 mMoveToRectPopupSize.height = newBounds.height;
2073 }
2074 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)
2075 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)
;
2076 }
2077 mBounds = newBounds;
2078 // Check mBounds size
2079 if (mCompositorSession &&
2080 !wr::WindowSizeSanityCheck(mBounds.width, mBounds.height)) {
2081 gfxCriticalNoteOncestatic mozilla::gfx::CriticalLog sOnceAtLine2081 = mozilla::gfx
::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions(false
))
<< "Invalid mBounds in PopupCallback " << mBounds
2082 << " size state " << mSizeMode;
2083 }
2084 WaylandPopupPropagateChangesToLayout(needsPositionUpdate, needsSizeUpdate);
2085}
2086
2087static GdkGravity PopupAlignmentToGdkGravity(int8_t aAlignment) {
2088 switch (aAlignment) {
2089 case POPUPALIGNMENT_NONE0:
2090 return GDK_GRAVITY_NORTH_WEST;
2091 case POPUPALIGNMENT_TOPLEFT1:
2092 return GDK_GRAVITY_NORTH_WEST;
2093 case POPUPALIGNMENT_TOPRIGHT-1:
2094 return GDK_GRAVITY_NORTH_EAST;
2095 case POPUPALIGNMENT_BOTTOMLEFT2:
2096 return GDK_GRAVITY_SOUTH_WEST;
2097 case POPUPALIGNMENT_BOTTOMRIGHT-2:
2098 return GDK_GRAVITY_SOUTH_EAST;
2099 case POPUPALIGNMENT_LEFTCENTER16:
2100 return GDK_GRAVITY_WEST;
2101 case POPUPALIGNMENT_RIGHTCENTER-16:
2102 return GDK_GRAVITY_EAST;
2103 case POPUPALIGNMENT_TOPCENTER17:
2104 return GDK_GRAVITY_NORTH;
2105 case POPUPALIGNMENT_BOTTOMCENTER18:
2106 return GDK_GRAVITY_SOUTH;
2107 }
2108 return GDK_GRAVITY_STATIC;
2109}
2110
2111bool nsWindow::IsPopupDirectionRTL() {
2112 nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame());
2113 return popupFrame && popupFrame->IsDirectionRTL();
2114}
2115
2116// Position the popup directly by gtk_window_move() and try to keep it
2117// on screen by just moving it in scope of it's parent window.
2118//
2119// It's used when we position noautihode popup and we don't use xdg_positioner.
2120// See Bug 1718867
2121void nsWindow::WaylandPopupSetDirectPosition() {
2122 GdkPoint topLeft = DevicePixelsToGdkPointRoundDown(mBounds.TopLeft());
2123 GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mLastSizeRequest);
2124
2125 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)
2126 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)
;
2127
2128 mPopupPosition = {topLeft.x, topLeft.y};
2129
2130 if (mIsDragPopup) {
2131 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), topLeft.x, topLeft.y);
2132 gtk_window_resize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), size.width, size.height);
2133 // DND window is placed inside container so we need to make hard size
2134 // request to ensure parent container is resized too.
2135 gtk_widget_set_size_request(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))), size.width, size.height);
2136 return;
2137 }
2138
2139 GtkWindow* parentGtkWindow = gtk_window_get_transient_for(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
2140 nsWindow* window = get_window_for_gtk_widget(GTK_WIDGET(parentGtkWindow)((((GtkWidget*) (void *) ((parentGtkWindow))))));
2141 if (!window) {
2142 return;
2143 }
2144 GdkWindow* gdkWindow = window->GetGdkWindow();
2145 if (!gdkWindow) {
2146 return;
2147 }
2148
2149 int parentWidth = gdk_window_get_width(gdkWindow);
2150 int popupWidth = size.width;
2151
2152 int x;
2153 gdk_window_get_position(gdkWindow, &x, nullptr);
2154
2155 // If popup is bigger than main window just center it.
2156 if (popupWidth > parentWidth) {
2157 mPopupPosition.x = -(parentWidth - popupWidth) / 2 + x;
2158 } else {
2159 if (IsPopupDirectionRTL()) {
2160 // Stick with right window edge
2161 if (mPopupPosition.x < x) {
2162 mPopupPosition.x = x;
2163 }
2164 } else {
2165 // Stick with left window edge
2166 if (mPopupPosition.x + popupWidth > parentWidth + x) {
2167 mPopupPosition.x = parentWidth + x - popupWidth;
2168 }
2169 }
2170 }
2171
2172 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)
;
2173 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), mPopupPosition.x, mPopupPosition.y);
2174
2175 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)
;
2176 gtk_window_resize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), size.width, size.height);
2177
2178 if (mPopupPosition.x != topLeft.x) {
2179 mBounds.MoveTo(GdkPointToDevicePixels(mPopupPosition));
2180 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)
;
2181 WaylandPopupPropagateChangesToLayout(/* move */ true, /* resize */ false);
2182 }
2183}
2184
2185bool nsWindow::WaylandPopupFitsToplevelWindow(bool aMove) {
2186 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)
;
2187
2188 GtkWindow* parent = gtk_window_get_transient_for(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
2189 GtkWindow* tmp = parent;
Value stored to 'tmp' during its initialization is never read
2190 while ((tmp = gtk_window_get_transient_for(GTK_WINDOW(parent)((((GtkWindow*) (void *) ((parent)))))))) {
2191 parent = tmp;
2192 }
2193 GdkWindow* toplevelGdkWindow = gtk_widget_get_window(GTK_WIDGET(parent)((((GtkWidget*) (void *) ((parent))))));
2194 if (!toplevelGdkWindow) {
2195 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"
, 2195)
;
2196 return false;
2197 }
2198
2199 int parentWidth = gdk_window_get_width(toplevelGdkWindow);
2200 int parentHeight = gdk_window_get_height(toplevelGdkWindow);
2201 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)
;
2202
2203 GdkPoint topLeft = aMove ? mPopupPosition
2204 : DevicePixelsToGdkPointRoundDown(mBounds.TopLeft());
2205 GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mLastSizeRequest);
2206 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)
2207 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)
;
2208 int fits = topLeft.x >= 0 && topLeft.y >= 0 &&
2209 topLeft.x + size.width <= parentWidth &&
2210 topLeft.y + size.height <= parentHeight;
2211
2212 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)
;
2213 return fits;
2214}
2215
2216void nsWindow::NativeMoveResizeWaylandPopup(bool aMove, bool aResize) {
2217 GdkPoint topLeft = DevicePixelsToGdkPointRoundDown(mBounds.TopLeft());
2218 GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mLastSizeRequest);
2219
2220 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)
2221 "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)
2222 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)
;
2223
2224 // Compositor may be confused by windows with width/height = 0
2225 // and positioning such windows leads to Bug 1555866.
2226 if (!AreBoundsSane()) {
2227 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)
2228 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)
;
2229 return;
2230 }
2231
2232 if (mWaitingForMoveToRectCallback) {
2233 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)
;
2234 // mBounds position must not be overwritten before it is applied.
2235 // OnConfigureEvent() will not set mBounds to an old position for
2236 // GTK_WINDOW_POPUP.
2237 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"
, 2238); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gtk_window_get_window_type(((((GtkWindow*) (void *) ((mShell)))))) == GTK_WINDOW_POPUP"
")"); do { *((volatile int*)__null) = 2238; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2238 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"
, 2238); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gtk_window_get_window_type(((((GtkWindow*) (void *) ((mShell)))))) == GTK_WINDOW_POPUP"
")"); do { *((volatile int*)__null) = 2238; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2239 mMovedAfterMoveToRect = aMove;
2240 mResizedAfterMoveToRect = aResize;
2241 return;
2242 }
2243
2244 mMovedAfterMoveToRect = false;
2245 mResizedAfterMoveToRect = false;
2246
2247 bool trackedInHierarchy = WaylandPopupConfigure();
2248
2249 // Read popup position from layout if it was moved or newly created.
2250 // This position is used by move-to-rect method as we need anchor and other
2251 // info to place popup correctly.
2252 // We need WaylandPopupConfigure() to be called before to have all needed
2253 // popup info in place (mainly the anchored flag).
2254 if (aMove) {
2255 mPopupMoveToRectParams = WaylandPopupGetPositionFromLayout();
2256 }
2257
2258 if (!trackedInHierarchy) {
2259 WaylandPopupSetDirectPosition();
2260 return;
2261 }
2262
2263 if (aResize) {
2264 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)
;
2265 gtk_window_resize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), size.width, size.height);
2266 }
2267
2268 if (!aMove && WaylandPopupFitsToplevelWindow(aMove)) {
2269 // Popup position has not been changed and its position/size fits
2270 // parent window so no need to reposition the window.
2271 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)
;
2272 return;
2273 }
2274
2275 // Mark popup as changed as we're updating position/size.
2276 mPopupChanged = true;
2277
2278 // Save popup position for former re-calculations when popup hierarchy
2279 // is changed.
2280 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)
2281 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)
;
2282 mPopupPosition = {topLeft.x, topLeft.y};
2283
2284 UpdateWaylandPopupHierarchy();
2285}
2286
2287struct PopupSides {
2288 Maybe<Side> mVertical;
2289 Maybe<Side> mHorizontal;
2290};
2291
2292static PopupSides SidesForPopupAlignment(int8_t aAlignment) {
2293 switch (aAlignment) {
2294 case POPUPALIGNMENT_NONE0:
2295 break;
2296 case POPUPALIGNMENT_TOPLEFT1:
2297 return {Some(eSideTop), Some(eSideLeft)};
2298 case POPUPALIGNMENT_TOPRIGHT-1:
2299 return {Some(eSideTop), Some(eSideRight)};
2300 case POPUPALIGNMENT_BOTTOMLEFT2:
2301 return {Some(eSideBottom), Some(eSideLeft)};
2302 case POPUPALIGNMENT_BOTTOMRIGHT-2:
2303 return {Some(eSideBottom), Some(eSideRight)};
2304 case POPUPALIGNMENT_LEFTCENTER16:
2305 return {Nothing(), Some(eSideLeft)};
2306 case POPUPALIGNMENT_RIGHTCENTER-16:
2307 return {Nothing(), Some(eSideRight)};
2308 case POPUPALIGNMENT_TOPCENTER17:
2309 return {Some(eSideTop), Nothing()};
2310 case POPUPALIGNMENT_BOTTOMCENTER18:
2311 return {Some(eSideBottom), Nothing()};
2312 }
2313 return {};
2314}
2315
2316// We want to apply margins based on popup alignment (which would generally be
2317// just an offset to apply to the popup). However, to deal with flipping
2318// correctly, we apply the margin to the anchor when possible.
2319struct ResolvedPopupMargin {
2320 // A margin to be applied to the anchor.
2321 nsMargin mAnchorMargin;
2322 // An offset in app units to be applied to the popup for when we need to tell
2323 // GTK to center inside the anchor precisely (so we can't really do better in
2324 // presence of flips).
2325 nsPoint mPopupOffset;
2326};
2327
2328static ResolvedPopupMargin ResolveMargin(nsMenuPopupFrame* aFrame,
2329 int8_t aPopupAlign,
2330 int8_t aAnchorAlign,
2331 bool aAnchoredToPoint,
2332 bool aIsContextMenu) {
2333 nsMargin margin = aFrame->GetMargin();
2334 nsPoint offset;
2335
2336 if (aAnchoredToPoint) {
2337 // Since GTK doesn't allow us to specify margins itself, when anchored to a
2338 // point we can just assume we'll be aligned correctly... This is kind of
2339 // annoying but alas.
2340 //
2341 // This calculation must match the relevant unanchored popup calculation in
2342 // nsMenuPopupFrame::SetPopupPosition(), which should itself be the inverse
2343 // inverse of nsMenuPopupFrame::MoveTo().
2344 if (aIsContextMenu && aFrame->IsDirectionRTL()) {
2345 offset.x = -margin.right;
2346 } else {
2347 offset.x = margin.left;
2348 }
2349 offset.y = margin.top;
2350 return {nsMargin(), offset};
2351 }
2352
2353 auto popupSides = SidesForPopupAlignment(aPopupAlign);
2354 auto anchorSides = SidesForPopupAlignment(aAnchorAlign);
2355 // Matched sides: Invert the margin, so that we pull in the right direction.
2356 // Popup not aligned to any anchor side: We give up and use the offset,
2357 // applying the margin from the popup side.
2358 // Mismatched sides: We swap the margins so that we pull in the right
2359 // direction, e.g. margin-left: -10px should shrink 10px the _right_ of the
2360 // box, not the left of the box.
2361 if (popupSides.mHorizontal == anchorSides.mHorizontal) {
2362 margin.left = -margin.left;
2363 margin.right = -margin.right;
2364 } else if (!anchorSides.mHorizontal) {
2365 auto popupSide = *popupSides.mHorizontal;
2366 offset.x += popupSide == eSideRight ? -margin.Side(popupSide)
2367 : margin.Side(popupSide);
2368 margin.left = margin.right = 0;
2369 } else {
2370 std::swap(margin.left, margin.right);
2371 }
2372
2373 // Same logic as above, but in the vertical direction.
2374 if (popupSides.mVertical == anchorSides.mVertical) {
2375 margin.top = -margin.top;
2376 margin.bottom = -margin.bottom;
2377 } else if (!anchorSides.mVertical) {
2378 auto popupSide = *popupSides.mVertical;
2379 offset.y += popupSide == eSideBottom ? -margin.Side(popupSide)
2380 : margin.Side(popupSide);
2381 margin.top = margin.bottom = 0;
2382 } else {
2383 std::swap(margin.top, margin.bottom);
2384 }
2385
2386 return {margin, offset};
2387}
2388
2389#ifdef MOZ_LOGGING1
2390void nsWindow::LogPopupAnchorHints(int aHints) {
2391 static struct hints_ {
2392 int hint;
2393 char name[100];
2394 } hints[] = {
2395 {GDK_ANCHOR_FLIP_X, "GDK_ANCHOR_FLIP_X"},
2396 {GDK_ANCHOR_FLIP_Y, "GDK_ANCHOR_FLIP_Y"},
2397 {GDK_ANCHOR_SLIDE_X, "GDK_ANCHOR_SLIDE_X"},
2398 {GDK_ANCHOR_SLIDE_Y, "GDK_ANCHOR_SLIDE_Y"},
2399 {GDK_ANCHOR_RESIZE_X, "GDK_ANCHOR_RESIZE_X"},
2400 {GDK_ANCHOR_RESIZE_Y, "GDK_ANCHOR_RESIZE_X"},
2401 };
2402
2403 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)
;
2404 for (const auto& hint : hints) {
2405 if (hint.hint & aHints) {
2406 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)
;
2407 }
2408 }
2409}
2410
2411void nsWindow::LogPopupGravity(GdkGravity aGravity) {
2412 static char gravity[][100]{"NONE",
2413 "GDK_GRAVITY_NORTH_WEST",
2414 "GDK_GRAVITY_NORTH",
2415 "GDK_GRAVITY_NORTH_EAST",
2416 "GDK_GRAVITY_WEST",
2417 "GDK_GRAVITY_CENTER",
2418 "GDK_GRAVITY_EAST",
2419 "GDK_GRAVITY_SOUTH_WEST",
2420 "GDK_GRAVITY_SOUTH",
2421 "GDK_GRAVITY_SOUTH_EAST",
2422 "GDK_GRAVITY_STATIC"};
2423 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)
;
2424}
2425#endif
2426
2427const nsWindow::WaylandPopupMoveToRectParams
2428nsWindow::WaylandPopupGetPositionFromLayout() {
2429 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)
;
2430
2431 nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame());
2432
2433 const bool isTopContextMenu = mPopupContextMenu && !mPopupAnchored;
2434 const bool isRTL = popupFrame->IsDirectionRTL();
2435 const bool anchored = popupFrame->IsAnchored();
2436 int8_t popupAlign = POPUPALIGNMENT_TOPLEFT1;
2437 int8_t anchorAlign = POPUPALIGNMENT_BOTTOMRIGHT-2;
2438 if (anchored) {
2439 // See nsMenuPopupFrame::AdjustPositionForAnchorAlign.
2440 popupAlign = popupFrame->GetPopupAlignment();
2441 anchorAlign = popupFrame->GetPopupAnchor();
2442 }
2443 if (isRTL) {
2444 popupAlign = -popupAlign;
2445 anchorAlign = -anchorAlign;
2446 }
2447
2448 // Although we have mPopupPosition / mRelativePopupPosition here
2449 // we can't use it. move-to-rect needs anchor rectangle to position a popup
2450 // but we have only a point from Resize().
2451 //
2452 // So we need to extract popup position from nsMenuPopupFrame() and duplicate
2453 // the layout work here.
2454 LayoutDeviceIntRect anchorRect;
2455 ResolvedPopupMargin popupMargin;
2456 {
2457 nsRect anchorRectAppUnits = popupFrame->GetUntransformedAnchorRect();
2458 // This is a somewhat hacky way of applying the popup margin. We don't know
2459 // if GTK will end up flipping the popup, in which case the offset we
2460 // compute is just wrong / applied to the wrong side.
2461 //
2462 // Instead, we tell it to anchor us at a smaller or bigger rect depending on
2463 // the margin, which achieves the same result if the popup is positioned
2464 // correctly, but doesn't misposition the popup when flipped across the
2465 // anchor.
2466 popupMargin = ResolveMargin(popupFrame, popupAlign, anchorAlign,
2467 anchorRectAppUnits.IsEmpty(), isTopContextMenu);
2468 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)
2469 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)
2470 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)
2471 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)
;
2472 anchorRectAppUnits.Inflate(popupMargin.mAnchorMargin);
2473 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
)
;
2474 nscoord auPerDev = popupFrame->PresContext()->AppUnitsPerDevPixel();
2475 anchorRect = LayoutDeviceIntRect::FromAppUnitsToNearest(anchorRectAppUnits,
2476 auPerDev);
2477 if (anchorRect.width < 0) {
2478 auto w = -anchorRect.width;
2479 anchorRect.width += w + 1;
2480 anchorRect.x += w;
2481 }
2482 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)
;
2483 }
2484
2485 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)
2486 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)
;
2487
2488 // Get gravity and flip type
2489 GdkGravity rectAnchor = PopupAlignmentToGdkGravity(anchorAlign);
2490 GdkGravity menuAnchor = PopupAlignmentToGdkGravity(popupAlign);
2491
2492 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)
;
2493
2494 // Gtk default is: GDK_ANCHOR_FLIP | GDK_ANCHOR_SLIDE | GDK_ANCHOR_RESIZE.
2495 // We want to SLIDE_X menu on the dual monitor setup rather than resize it
2496 // on the other monitor.
2497 GdkAnchorHints hints =
2498 GdkAnchorHints(GDK_ANCHOR_FLIP | GDK_ANCHOR_SLIDE_X | GDK_ANCHOR_RESIZE);
2499
2500 // slideHorizontal from nsMenuPopupFrame::SetPopupPosition
2501 int8_t position = popupFrame->GetAlignmentPosition();
2502 if (position >= POPUPPOSITION_BEFORESTART0 &&
2503 position <= POPUPPOSITION_AFTEREND3) {
2504 hints = GdkAnchorHints(hints | GDK_ANCHOR_SLIDE_X);
2505 }
2506 // slideVertical from nsMenuPopupFrame::SetPopupPosition
2507 if (position >= POPUPPOSITION_STARTBEFORE4 &&
2508 position <= POPUPPOSITION_ENDAFTER7) {
2509 hints = GdkAnchorHints(hints | GDK_ANCHOR_SLIDE_Y);
2510 }
2511
2512 FlipType flipType = popupFrame->GetFlipType();
2513 if (rectAnchor == GDK_GRAVITY_CENTER && menuAnchor == GDK_GRAVITY_CENTER) {
2514 // only slide
2515 hints = GdkAnchorHints(hints | GDK_ANCHOR_SLIDE);
2516 } else {
2517 switch (flipType) {
2518 case FlipType_Both:
2519 hints = GdkAnchorHints(hints | GDK_ANCHOR_FLIP);
2520 break;
2521 case FlipType_Slide:
2522 hints = GdkAnchorHints(hints | GDK_ANCHOR_SLIDE);
2523 break;
2524 case FlipType_Default:
2525 hints = GdkAnchorHints(hints | GDK_ANCHOR_FLIP);
2526 break;
2527 default:
2528 break;
2529 }
2530 }
2531 if (!WaylandPopupIsMenu()) {
2532 // we don't want to slide menus to fit the screen rather resize them
2533 hints = GdkAnchorHints(hints | GDK_ANCHOR_SLIDE);
2534 }
2535
2536 // We want tooltips to flip verticaly or slide only.
2537 // See nsMenuPopupFrame::SetPopupPosition().
2538 // https://searchfox.org/mozilla-central/rev/d0f5bc50aff3462c9d1546b88d60c5cb020eb15c/layout/xul/nsMenuPopupFrame.cpp#1603
2539 if (mPopupType == PopupType::Tooltip) {
2540 hints = GdkAnchorHints(GDK_ANCHOR_FLIP_Y | GDK_ANCHOR_SLIDE);
2541 }
2542
2543 return {
2544 anchorRect,
2545 rectAnchor,
2546 menuAnchor,
2547 hints,
2548 DevicePixelsToGdkPointRoundDown(LayoutDevicePoint::FromAppUnitsToNearest(
2549 popupMargin.mPopupOffset,
2550 popupFrame->PresContext()->AppUnitsPerDevPixel())),
2551 true};
2552}
2553
2554bool nsWindow::WaylandPopupAnchorAdjustForParentPopup(
2555 GdkRectangle* aPopupAnchor, GdkPoint* aOffset) {
2556 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)
;
2557
2558 GtkWindow* parentGtkWindow = gtk_window_get_transient_for(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
2559 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; }))))
) {
2560 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"
, 2560)
;
2561 return false;
2562 }
2563 GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(parentGtkWindow)((((GtkWidget*) (void *) ((parentGtkWindow))))));
2564 if (!window) {
2565 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"
, 2565)
;
2566 return false;
2567 }
2568
2569 GdkRectangle parentWindowRect = {0, 0, gdk_window_get_width(window),
2570 gdk_window_get_height(window)};
2571 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)
2572 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)
;
2573
2574 // We can't have rectangle anchor with zero width/height.
2575 if (!aPopupAnchor->width) {
2576 aPopupAnchor->width = 1;
2577 }
2578 if (!aPopupAnchor->height) {
2579 aPopupAnchor->height = 1;
2580 }
2581
2582 GdkRectangle finalRect;
2583 if (!gdk_rectangle_intersect(aPopupAnchor, &parentWindowRect, &finalRect)) {
2584 return false;
2585 }
2586 *aPopupAnchor = finalRect;
2587 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)
2588 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)
;
2589
2590 *aOffset = mPopupMoveToRectParams.mOffset;
2591 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)
;
2592 return true;
2593}
2594
2595bool nsWindow::WaylandPopupCheckAndGetAnchor(GdkRectangle* aPopupAnchor,
2596 GdkPoint* aOffset) {
2597 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)
;
2598
2599 GdkWindow* gdkWindow = GetToplevelGdkWindow();
2600 nsMenuPopupFrame* popupFrame = GetMenuPopupFrame(GetFrame());
2601 if (!gdkWindow || !popupFrame) {
2602 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)
;
2603 return false;
2604 }
2605
2606 if (popupFrame->IsConstrainedByLayout()) {
2607 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)
;
2608 return false;
2609 }
2610
2611 if (!mPopupMoveToRectParams.mAnchorSet) {
2612 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)
;
2613 return false;
2614 }
2615 // Update popup layout coordinates from layout by recent popup hierarchy
2616 // (calculate correct position according to parent window)
2617 // and convert to Gtk coordinates.
2618 LayoutDeviceIntRect anchorRect = mPopupMoveToRectParams.mAnchorRect;
2619 if (!WaylandPopupIsFirst()) {
2620 GdkPoint parent = WaylandGetParentPosition();
2621 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)
2622 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)
;
2623 anchorRect.MoveBy(-GdkPointToDevicePixels(parent));
2624 }
2625
2626 *aPopupAnchor = DevicePixelsToGdkRectRoundOut(anchorRect);
2627 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)
2628 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)
;
2629
2630 if (!WaylandPopupAnchorAdjustForParentPopup(aPopupAnchor, aOffset)) {
2631 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)
2632 "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)
;
2633 return false;
2634 }
2635
2636 return true;
2637}
2638
2639void nsWindow::WaylandPopupPrepareForMove() {
2640 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)
;
2641
2642 if (mPopupType == PopupType::Tooltip) {
2643 // Don't fiddle with tooltips type, just hide it before move-to-rect
2644 if (mPopupUseMoveToRect && gtk_widget_is_visible(mShell)) {
2645 HideWaylandPopupWindow(/* aTemporaryHide */ true,
2646 /* aRemoveFromPopupList */ false);
2647 }
2648 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)
;
2649 return;
2650 }
2651
2652 // See https://bugzilla.mozilla.org/show_bug.cgi?id=1785185#c8
2653 // gtk_window_move() needs GDK_WINDOW_TYPE_HINT_UTILITY popup type.
2654 // move-to-rect requires GDK_WINDOW_TYPE_HINT_POPUP_MENU popups type.
2655 // We need to set it before map event when popup is hidden.
2656 const GdkWindowTypeHint currentType =
2657 gtk_window_get_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
2658 const GdkWindowTypeHint requiredType = mPopupUseMoveToRect
2659 ? GDK_WINDOW_TYPE_HINT_POPUP_MENU
2660 : GDK_WINDOW_TYPE_HINT_UTILITY;
2661
2662 if (!mPopupUseMoveToRect && currentType == requiredType) {
2663 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)
;
2664 return;
2665 }
2666
2667 if (gtk_widget_is_visible(mShell)) {
2668 HideWaylandPopupWindow(/* aTemporaryHide */ true,
2669 /* aRemoveFromPopupList */ false);
2670 }
2671
2672 if (currentType != requiredType) {
2673 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)
2674 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)
;
2675 gtk_window_set_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), requiredType);
2676 }
2677}
2678
2679// Plain popup move on Wayland - simply place popup on given location.
2680// We can't just call gtk_window_move() as it's not effective on visible
2681// popups.
2682void nsWindow::WaylandPopupMovePlain(int aX, int aY) {
2683 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)
;
2684
2685 // We can directly move only popups based on wl_subsurface type.
2686 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"
, 2689); 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) = 2689; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2687 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"
, 2689); 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) = 2689; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2688 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"
, 2689); 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) = 2689; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
2689 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"
, 2689); 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) = 2689; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2690
2691 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), aX, aY);
2692
2693 // gtk_window_move() can trick us. When widget is hidden gtk_window_move()
2694 // does not move the widget but sets new widget coordinates when widget
2695 // is mapped again.
2696 //
2697 // If popup used move-to-rect before
2698 // (GdkWindow has POSITION_METHOD_MOVE_TO_RECT set), popup will use
2699 // move-to-rect again when it's mapped and we'll get bogus move-to-rect
2700 // callback.
2701 //
2702 // gdk_window_move() sets position_method to POSITION_METHOD_MOVE_RESIZE
2703 // so we'll use plain move when popup is shown.
2704 if (!gtk_widget_get_mapped(mShell)) {
2705 if (GdkWindow* window = GetToplevelGdkWindow()) {
2706 gdk_window_move(window, aX, aY);
2707 }
2708 }
2709}
2710
2711void nsWindow::WaylandPopupMoveImpl() {
2712 // Available as of GTK 3.24+
2713 static auto sGdkWindowMoveToRect = (void (*)(
2714 GdkWindow*, const GdkRectangle*, GdkGravity, GdkGravity, GdkAnchorHints,
2715 gint, gint))dlsym(RTLD_DEFAULT((void *) 0), "gdk_window_move_to_rect");
2716
2717 if (mPopupUseMoveToRect && !sGdkWindowMoveToRect) {
2718 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)
;
2719 mPopupUseMoveToRect = false;
2720 }
2721
2722 GdkRectangle gtkAnchorRect;
2723 GdkPoint offset;
2724 if (mPopupUseMoveToRect) {
2725 mPopupUseMoveToRect =
2726 WaylandPopupCheckAndGetAnchor(&gtkAnchorRect, &offset);
2727 }
2728
2729 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)
;
2730 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)
2731 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)
;
2732 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)
2733 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)
;
2734 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)
;
2735
2736 WaylandPopupPrepareForMove();
2737
2738 if (!mPopupUseMoveToRect) {
2739 WaylandPopupMovePlain(mRelativePopupPosition.x, mRelativePopupPosition.y);
2740 // Layout already should be aware of our bounds, since we didn't change it
2741 // from the widget side for flipping or so.
2742 return;
2743 }
2744
2745 // Correct popup position now. It will be updated by gdk_window_move_to_rect()
2746 // anyway but we need to set it now to avoid a race condition here.
2747 WaylandPopupRemoveNegativePosition();
2748
2749 GdkWindow* gdkWindow = GetToplevelGdkWindow();
2750 if (!g_signal_handler_find(gdkWindow, G_SIGNAL_MATCH_FUNC, 0, 0, nullptr,
2751 FuncToGpointer(NativeMoveResizeCallback), this)) {
2752 g_signal_connect(gdkWindow, "moved-to-rect",g_signal_connect_data ((gdkWindow), ("moved-to-rect"), (((GCallback
) (NativeMoveResizeCallback))), (this), __null, (GConnectFlags
) 0)
2753 G_CALLBACK(NativeMoveResizeCallback), this)g_signal_connect_data ((gdkWindow), ("moved-to-rect"), (((GCallback
) (NativeMoveResizeCallback))), (this), __null, (GConnectFlags
) 0)
;
2754 }
2755 mWaitingForMoveToRectCallback = true;
2756
2757#ifdef MOZ_LOGGING1
2758 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)
))
) {
2759 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)
;
2760 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)
2761 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)
;
2762 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)
;
2763 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)
;
2764 LogPopupGravity(mPopupMoveToRectParams.mAnchorRectType);
2765 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)
;
2766 LogPopupGravity(mPopupMoveToRectParams.mPopupAnchorType);
2767 LogPopupAnchorHints(mPopupMoveToRectParams.mHints);
2768 }
2769#endif
2770
2771 sGdkWindowMoveToRect(gdkWindow, &gtkAnchorRect,
2772 mPopupMoveToRectParams.mAnchorRectType,
2773 mPopupMoveToRectParams.mPopupAnchorType,
2774 mPopupMoveToRectParams.mHints, offset.x, offset.y);
2775}
2776
2777void nsWindow::SetSizeMode(nsSizeMode aMode) {
2778 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)
;
2779
2780 // Return if there's no shell or our current state is the same as the mode we
2781 // were just set to.
2782 if (!mShell) {
2783 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)
;
2784 return;
2785 }
2786
2787 if (mSizeMode == aMode && mLastSizeModeRequest == aMode) {
2788 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)
;
2789 return;
2790 }
2791
2792 // It is tempting to try to optimize calls below based only on current
2793 // mSizeMode, but that wouldn't work if there's a size-request in flight
2794 // (specially before show). See bug 1789823.
2795 const auto SizeModeMightBe = [&](nsSizeMode aModeToTest) {
2796 if (mSizeMode != mLastSizeModeRequest) {
2797 // Arbitrary size mode requests might be ongoing.
2798 return true;
2799 }
2800 return mSizeMode == aModeToTest;
2801 };
2802
2803 if (aMode != nsSizeMode_Fullscreen && aMode != nsSizeMode_Minimized) {
2804 // Fullscreen and minimized are compatible.
2805 if (SizeModeMightBe(nsSizeMode_Fullscreen)) {
2806 MakeFullScreen(false);
2807 }
2808 }
2809
2810 switch (aMode) {
2811 case nsSizeMode_Maximized:
2812 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)
;
2813 gtk_window_maximize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
2814 break;
2815 case nsSizeMode_Minimized:
2816 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)
;
2817 gtk_window_iconify(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
2818 break;
2819 case nsSizeMode_Fullscreen:
2820 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)
;
2821 MakeFullScreen(true);
2822 break;
2823 default:
2824 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"
, 2824); AnnotateMozCrashReason("MOZ_CRASH(" "MOZ_FALLTHROUGH_ASSERT: "
"Unknown size mode" ")"); do { *((volatile int*)__null) = 2824
; __attribute__((nomerge)) ::abort(); } while (false); } while
(false)
;
2825 case nsSizeMode_Normal:
2826 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)
;
2827 if (SizeModeMightBe(nsSizeMode_Maximized)) {
2828 gtk_window_unmaximize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
2829 }
2830 if (SizeModeMightBe(nsSizeMode_Minimized)) {
2831 gtk_window_deiconify(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
2832 // We need this for actual deiconification on mutter.
2833 gtk_window_present(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
2834 }
2835 break;
2836 }
2837 mLastSizeModeRequest = aMode;
2838}
2839
2840#define kDesktopMutterSchema"org.gnome.mutter"_ns "org.gnome.mutter"_ns
2841#define kDesktopDynamicWorkspacesKey"dynamic-workspaces"_ns "dynamic-workspaces"_ns
2842
2843static bool WorkspaceManagementDisabled(GdkScreen* screen) {
2844 if (Preferences::GetBool("widget.disable-workspace-management", false)) {
2845 return true;
2846 }
2847 if (Preferences::HasUserValue("widget.workspace-management")) {
2848 return Preferences::GetBool("widget.workspace-management");
2849 }
2850
2851 if (IsGnomeDesktopEnvironment()) {
2852 // Gnome uses dynamic workspaces by default so disable workspace management
2853 // in that case.
2854 bool usesDynamicWorkspaces = true;
2855 nsCOMPtr<nsIGSettingsService> gsettings =
2856 do_GetService(NS_GSETTINGSSERVICE_CONTRACTID"@mozilla.org/gsettings-service;1");
2857 if (gsettings) {
2858 nsCOMPtr<nsIGSettingsCollection> mutterSettings;
2859 gsettings->GetCollectionForSchema(kDesktopMutterSchema"org.gnome.mutter"_ns,
2860 getter_AddRefs(mutterSettings));
2861 if (mutterSettings) {
2862 mutterSettings->GetBoolean(kDesktopDynamicWorkspacesKey"dynamic-workspaces"_ns,
2863 &usesDynamicWorkspaces);
2864 }
2865 }
2866 return usesDynamicWorkspaces;
2867 }
2868
2869 const auto& desktop = GetDesktopEnvironmentIdentifier();
2870 return desktop.EqualsLiteral("bspwm") || desktop.EqualsLiteral("i3");
2871}
2872
2873void nsWindow::GetWorkspaceID(nsAString& workspaceID) {
2874 workspaceID.Truncate();
2875
2876 if (!GdkIsX11Display() || !mShell) {
2877 return;
2878 }
2879
2880#ifdef MOZ_X111
2881 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)
;
2882
2883 // Get the gdk window for this widget.
2884 GdkWindow* gdk_window = GetToplevelGdkWindow();
2885 if (!gdk_window) {
2886 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)
;
2887 return;
2888 }
2889
2890 if (WorkspaceManagementDisabled(gdk_window_get_screen(gdk_window))) {
2891 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)
;
2892 return;
2893 }
2894
2895 GdkAtom cardinal_atom = gdk_x11_xatom_to_atom(XA_CARDINAL((Atom) 6));
2896 GdkAtom type_returned;
2897 int format_returned;
2898 int length_returned;
2899 long* wm_desktop;
2900
2901 if (!gdk_property_get(gdk_window, gdk_atom_intern("_NET_WM_DESKTOP", FALSE(0)),
2902 cardinal_atom,
2903 0, // offset
2904 INT32_MAX(2147483647), // length
2905 FALSE(0), // delete
2906 &type_returned, &format_returned, &length_returned,
2907 (guchar**)&wm_desktop)) {
2908 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)
;
2909 return;
2910 }
2911
2912 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)
;
2913 workspaceID.AppendInt((int32_t)wm_desktop[0]);
2914 g_free(wm_desktop);
2915#endif
2916}
2917
2918void nsWindow::MoveToWorkspace(const nsAString& workspaceIDStr) {
2919 nsresult rv = NS_OK;
2920 int32_t workspaceID = workspaceIDStr.ToInteger(&rv);
2921
2922 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)
;
2923 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || !workspaceID || !GdkIsX11Display() || !mShell) {
2924 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)
;
2925 return;
2926 }
2927
2928#ifdef MOZ_X111
2929 // Get the gdk window for this widget.
2930 GdkWindow* gdk_window = GetToplevelGdkWindow();
2931 if (!gdk_window) {
2932 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)
;
2933 return;
2934 }
2935
2936 // This code is inspired by some found in the 'gxtuner' project.
2937 // https://github.com/brummer10/gxtuner/blob/792d453da0f3a599408008f0f1107823939d730d/deskpager.cpp#L50
2938 XEvent xevent;
2939 Display* xdisplay = gdk_x11_get_default_xdisplay();
2940 GdkScreen* screen = gdk_window_get_screen(gdk_window);
2941 Window root_win = GDK_WINDOW_XID(gdk_screen_get_root_window(screen))(gdk_x11_window_get_xid (gdk_screen_get_root_window(screen)));
2942 GdkDisplay* display = gdk_window_get_display(gdk_window);
2943 Atom type = gdk_x11_get_xatom_by_name_for_display(display, "_NET_WM_DESKTOP");
2944
2945 xevent.type = ClientMessage33;
2946 xevent.xclient.type = ClientMessage33;
2947 xevent.xclient.serial = 0;
2948 xevent.xclient.send_event = TRUE(!(0));
2949 xevent.xclient.display = xdisplay;
2950 xevent.xclient.window = GDK_WINDOW_XID(gdk_window)(gdk_x11_window_get_xid (gdk_window));
2951 xevent.xclient.message_type = type;
2952 xevent.xclient.format = 32;
2953 xevent.xclient.data.l[0] = workspaceID;
2954 xevent.xclient.data.l[1] = X11CurrentTime0L;
2955 xevent.xclient.data.l[2] = 0;
2956 xevent.xclient.data.l[3] = 0;
2957 xevent.xclient.data.l[4] = 0;
2958
2959 XSendEvent(xdisplay, root_win, FALSE(0),
2960 SubstructureNotifyMask(1L<<19) | SubstructureRedirectMask(1L<<20), &xevent);
2961
2962 XFlush(xdisplay);
2963 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)
;
2964#endif
2965}
2966
2967void nsWindow::SetUserTimeAndStartupTokenForActivatedWindow() {
2968 nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit();
2969 if (!toolkit || MOZ_UNLIKELY(mWindowType == WindowType::Invisible)(__builtin_expect(!!(mWindowType == WindowType::Invisible), 0
))
) {
2970 return;
2971 }
2972
2973 mWindowActivationTokenFromEnv = toolkit->GetStartupToken();
2974 if (!mWindowActivationTokenFromEnv.IsEmpty()) {
2975 if (!GdkIsWaylandDisplay()) {
2976 gtk_window_set_startup_id(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))),
2977 mWindowActivationTokenFromEnv.get());
2978 // In the case of X11, the above call is all we need. For wayland we need
2979 // to keep the token around until we take it in
2980 // TransferFocusToWaylandWindow.
2981 mWindowActivationTokenFromEnv.Truncate();
2982 }
2983 } else if (uint32_t timestamp = toolkit->GetFocusTimestamp()) {
2984 // We don't have the data we need. Fall back to an
2985 // approximation ... using the timestamp of the remote command
2986 // being received as a guess for the timestamp of the user event
2987 // that triggered it.
2988 gdk_window_focus(GetToplevelGdkWindow(), timestamp);
2989 }
2990
2991 // If we used the startup ID, that already contains the focus timestamp;
2992 // we don't want to reuse the timestamp next time we raise the window
2993 toolkit->SetFocusTimestamp(0);
2994 toolkit->SetStartupToken(""_ns);
2995}
2996
2997/* static */
2998guint32 nsWindow::GetLastUserInputTime() {
2999 // gdk_x11_display_get_user_time/gtk_get_current_event_time tracks
3000 // button and key presses, DESKTOP_STARTUP_ID used to start the app,
3001 // drop events from external drags,
3002 // WM_DELETE_WINDOW delete events, but not usually mouse motion nor
3003 // button and key releases. Therefore use the most recent of
3004 // gdk_x11_display_get_user_time and the last time that we have seen.
3005#ifdef MOZ_X111
3006 GdkDisplay* gdkDisplay = gdk_display_get_default();
3007 guint32 timestamp = GdkIsX11Display(gdkDisplay)
3008 ? gdk_x11_display_get_user_time(gdkDisplay)
3009 : gtk_get_current_event_time();
3010#else
3011 guint32 timestamp = gtk_get_current_event_time();
3012#endif
3013
3014 if (sLastUserInputTime != GDK_CURRENT_TIME0L &&
3015 TimestampIsNewerThan(sLastUserInputTime, timestamp)) {
3016 return sLastUserInputTime;
3017 }
3018
3019 return timestamp;
3020}
3021
3022#ifdef MOZ_WAYLAND1
3023void nsWindow::FocusWaylandWindow(const char* aTokenID) {
3024 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"
, 3024); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "aTokenID"
")"); do { *((volatile int*)__null) = 3024; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3025
3026 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)
;
3027 if (IsDestroyed()) {
3028 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)
;
3029 return;
3030 }
3031 wl_surface* surface =
3032 mGdkWindow ? gdk_wayland_window_get_wl_surface(mGdkWindow) : nullptr;
3033 if (!surface) {
3034 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)
;
3035 return;
3036 }
3037
3038 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)
3039 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)
;
3040 xdg_activation_v1* xdg_activation = WaylandDisplayGet()->GetXdgActivation();
3041 if (!xdg_activation) {
3042 return;
3043 }
3044 xdg_activation_v1_activate(xdg_activation, aTokenID, surface);
3045}
3046
3047// Transfer focus from gFocusWindow to aWindow and use xdg_activation
3048// protocol for it.
3049void nsWindow::TransferFocusToWaylandWindow(nsWindow* aWindow) {
3050 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)
3051 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)
;
3052 auto promise = mozilla::widget::RequestWaylandFocusPromise();
3053 if (NS_WARN_IF(!promise)NS_warn_if_impl(!promise, "!promise", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 3053)
) {
3054 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)
;
3055 return;
3056 }
3057 promise->Then(
3058 GetMainThreadSerialEventTarget(), __func__,
3059 /* resolve */
3060 [window = RefPtr{aWindow}](nsCString token) {
3061 window->FocusWaylandWindow(token.get());
3062 },
3063 /* reject */
3064 [window = RefPtr{aWindow}](bool state) {
3065 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)
;
3066 });
3067}
3068#endif
3069
3070// Request activation of this window or give focus to this widget.
3071// aRaise means whether we should request activation of this widget's
3072// toplevel window.
3073//
3074// nsWindow::SetFocus(Raise::Yes) - Raise and give focus to toplevel window.
3075// nsWindow::SetFocus(Raise::No) - Give focus to this window.
3076void nsWindow::SetFocus(Raise aRaise, mozilla::dom::CallerType aCallerType) {
3077 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)
;
3078
3079 // Raise the window if someone passed in true and the prefs are
3080 // set properly.
3081 GtkWidget* toplevelWidget = gtk_widget_get_toplevel(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))));
3082
3083 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)
;
3084 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)
;
3085 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)
;
3086
3087 // Make sure that our owning widget has focus. If it doesn't try to
3088 // grab it. Note that we don't set our focus flag in this case.
3089 if (StaticPrefs::mozilla_widget_raise_on_setfocus_AtStartup() &&
3090 aRaise == Raise::Yes && toplevelWidget &&
3091 !gtk_widget_has_focus(toplevelWidget)) {
3092 if (gtk_widget_get_visible(mShell)) {
3093 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)
;
3094 gdk_window_show_unraised(GetToplevelGdkWindow());
3095 // Unset the urgency hint if possible.
3096 SetUrgencyHint(mShell, false);
3097 }
3098 }
3099
3100 RefPtr<nsWindow> toplevelWindow = get_window_for_gtk_widget(toplevelWidget);
3101 if (!toplevelWindow) {
3102 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)
;
3103 return;
3104 }
3105
3106 if (aRaise == Raise::Yes) {
3107 // means request toplevel activation.
3108
3109 // This is asynchronous. If and when the window manager accepts the request,
3110 // then the focus widget will get a focus-in-event signal.
3111 if (StaticPrefs::mozilla_widget_raise_on_setfocus_AtStartup() &&
3112 toplevelWindow->mIsShown && toplevelWindow->mShell &&
3113 !gtk_window_is_active(GTK_WINDOW(toplevelWindow->mShell)((((GtkWindow*) (void *) ((toplevelWindow->mShell))))))) {
3114 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)
3115 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)
;
3116
3117 // Take the time here explicitly for the call below.
3118 const uint32_t timestamp = [&] {
3119 if (nsGTKToolkit* toolkit = nsGTKToolkit::GetToolkit()) {
3120 if (uint32_t t = toolkit->GetFocusTimestamp()) {
3121 toolkit->SetFocusTimestamp(0);
3122 return t;
3123 }
3124 }
3125 return GetLastUserInputTime();
3126 }();
3127
3128 toplevelWindow->SetUserTimeAndStartupTokenForActivatedWindow();
3129 gtk_window_present_with_time(GTK_WINDOW(toplevelWindow->mShell)((((GtkWindow*) (void *) ((toplevelWindow->mShell))))),
3130 timestamp);
3131
3132#ifdef MOZ_WAYLAND1
3133 if (GdkIsWaylandDisplay()) {
3134 auto existingToken =
3135 std::move(toplevelWindow->mWindowActivationTokenFromEnv);
3136 if (!existingToken.IsEmpty()) {
3137 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)
;
3138 toplevelWindow->FocusWaylandWindow(existingToken.get());
3139 } else {
3140 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)
3141 "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)
;
3142 TransferFocusToWaylandWindow(toplevelWindow);
3143 }
3144 }
3145#endif
3146 }
3147 return;
3148 }
3149
3150 // aRaise == No means that keyboard events should be dispatched from this
3151 // widget.
3152
3153 // Ensure GTK_WIDGET(mContainer) is the focused GtkWidget within its toplevel
3154 // window.
3155 //
3156 // For WindowType::Popup, this GtkWidget may not actually be the one that
3157 // receives the key events as it may be the parent window that is active.
3158 if (!gtk_widget_is_focus(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))))) {
3159 // This is synchronous. It takes focus from a plugin or from a widget
3160 // in an embedder. The focus manager already knows that this window
3161 // is active so gBlockActivateEvent avoids another (unnecessary)
3162 // activate notification.
3163 gBlockActivateEvent = true;
3164 gtk_widget_grab_focus(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))));
3165 gBlockActivateEvent = false;
3166 }
3167
3168 // If this is the widget that already has focus, return.
3169 if (gFocusWindow == this) {
3170 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)
;
3171 return;
3172 }
3173
3174 // Set this window to be the focused child window
3175 gFocusWindow = this;
3176
3177 if (mIMContext) {
3178 mIMContext->OnFocusWindow(this);
3179 }
3180
3181 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)
;
3182}
3183
3184void nsWindow::ResetScreenBounds() {
3185 mGdkWindowOrigin.reset();
3186 mGdkWindowRootOrigin.reset();
3187}
3188
3189LayoutDeviceIntRect nsWindow::GetScreenBounds() {
3190 if (!mGdkWindow) {
3191 return mBounds;
3192 }
3193
3194 const LayoutDeviceIntPoint origin = [&] {
3195 GdkPoint origin;
3196
3197 if (mGdkWindowRootOrigin.isSome()) {
3198 origin = mGdkWindowRootOrigin.value();
3199 } else {
3200 gdk_window_get_root_origin(mGdkWindow, &origin.x, &origin.y);
3201 mGdkWindowRootOrigin = Some(origin);
3202 }
3203
3204 // Workaround for https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/4820
3205 // Bug 1775017 Gtk < 3.24.35 returns scaled values for
3206 // override redirected window on X11.
3207 if (gtk_check_version(3, 24, 35) != nullptr && GdkIsX11Display() &&
3208 gdk_window_get_window_type(mGdkWindow) == GDK_WINDOW_TEMP) {
3209 return LayoutDeviceIntPoint(origin.x, origin.y);
3210 }
3211 return GdkPointToDevicePixels(origin);
3212 }();
3213
3214 // mBounds.Size() is the window bounds, not the window-manager frame
3215 // bounds (bug 581863). gdk_window_get_frame_extents would give the
3216 // frame bounds, but mBounds.Size() is returned here for consistency
3217 // with Resize.
3218 const LayoutDeviceIntRect rect(origin, mBounds.Size());
3219#if MOZ_LOGGING1
3220 if (MOZ_LOG_TEST(IsPopup() ? gWidgetPopupLog : gWidgetLog,(__builtin_expect(!!(mozilla::detail::log_test(IsPopup() ? gWidgetPopupLog
: gWidgetLog, LogLevel::Verbose)), 0))
3221 LogLevel::Verbose)(__builtin_expect(!!(mozilla::detail::log_test(IsPopup() ? gWidgetPopupLog
: gWidgetLog, LogLevel::Verbose)), 0))
) {
3222 gint scale = GdkCeiledScaleFactor();
3223 if (mLastLoggedScale != scale || !(mLastLoggedBoundSize == rect)) {
3224 mLastLoggedScale = scale;
3225 mLastLoggedBoundSize = rect;
3226 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)
3227 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)
3228 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)
;
3229 }
3230 }
3231#endif
3232 return rect;
3233}
3234
3235LayoutDeviceIntSize nsWindow::GetClientSize() { return mBounds.Size(); }
3236
3237LayoutDeviceIntRect nsWindow::GetClientBounds() {
3238 // GetBounds returns a rect whose top left represents the top left of the
3239 // outer bounds, but whose width/height represent the size of the inner
3240 // bounds (which is messed up).
3241 LayoutDeviceIntRect rect = GetBounds();
3242 rect.MoveBy(GetClientOffset());
3243 return rect;
3244}
3245
3246void nsWindow::RecomputeClientOffset(bool aNotify) {
3247 if (!IsTopLevelWindowType()) {
3248 return;
3249 }
3250
3251 auto oldOffset = mClientOffset;
3252
3253 mClientOffset = WidgetToScreenOffset() - mBounds.TopLeft();
3254
3255 if (aNotify && mClientOffset != oldOffset) {
3256 // Send a WindowMoved notification. This ensures that BrowserParent picks up
3257 // the new client offset and sends it to the child process if appropriate.
3258 NotifyWindowMoved(mBounds.x, mBounds.y);
3259 }
3260}
3261
3262gboolean nsWindow::OnPropertyNotifyEvent(GtkWidget* aWidget,
3263 GdkEventProperty* aEvent) {
3264 if (aEvent->atom == gdk_atom_intern("_NET_FRAME_EXTENTS", FALSE(0))) {
3265 ResetScreenBounds();
3266 RecomputeClientOffset(/* aNotify = */ true);
3267 return FALSE(0);
3268 }
3269 if (!mGdkWindow) {
3270 return FALSE(0);
3271 }
3272#ifdef MOZ_X111
3273 if (GetCurrentTimeGetter()->PropertyNotifyHandler(aWidget, aEvent)) {
3274 return TRUE(!(0));
3275 }
3276#endif
3277 return FALSE(0);
3278}
3279
3280static GdkCursor* GetCursorForImage(const nsIWidget::Cursor& aCursor,
3281 int32_t aWidgetScaleFactor) {
3282 if (!aCursor.IsCustom()) {
3283 return nullptr;
3284 }
3285 nsIntSize size = nsIWidget::CustomCursorSize(aCursor);
3286
3287 // NOTE: GTK only allows integer scale factors, so we ceil to the larger scale
3288 // factor and then tell gtk to scale it down. We ensure to scale at least to
3289 // the GDK scale factor, so that cursors aren't downsized in HiDPI on wayland,
3290 // see bug 1707533.
3291 int32_t gtkScale = std::max(
3292 aWidgetScaleFactor, int32_t(std::ceil(std::max(aCursor.mResolution.mX,
3293 aCursor.mResolution.mY))));
3294
3295 // Reject cursors greater than 128 pixels in some direction, to prevent
3296 // spoofing.
3297 // XXX ideally we should rescale. Also, we could modify the API to
3298 // allow trusted content to set larger cursors.
3299 //
3300 // TODO(emilio, bug 1445844): Unify the solution for this with other
3301 // platforms.
3302 if (size.width > 128 || size.height > 128) {
3303 return nullptr;
3304 }
3305
3306 nsIntSize rasterSize = size * gtkScale;
3307 RefPtr<GdkPixbuf> pixbuf =
3308 nsImageToPixbuf::ImageToPixbuf(aCursor.mContainer, Some(rasterSize));
3309 if (!pixbuf) {
3310 return nullptr;
3311 }
3312
3313 // Looks like all cursors need an alpha channel (tested on Gtk 2.4.4). This
3314 // is of course not documented anywhere...
3315 // So add one if there isn't one yet
3316 if (!gdk_pixbuf_get_has_alpha(pixbuf)) {
3317 RefPtr<GdkPixbuf> alphaBuf =
3318 dont_AddRef(gdk_pixbuf_add_alpha(pixbuf, FALSE(0), 0, 0, 0));
3319 pixbuf = std::move(alphaBuf);
3320 if (!pixbuf) {
3321 return nullptr;
3322 }
3323 }
3324
3325 cairo_surface_t* surface =
3326 gdk_cairo_surface_create_from_pixbuf(pixbuf, gtkScale, nullptr);
3327 if (!surface) {
3328 return nullptr;
3329 }
3330
3331 auto CleanupSurface =
3332 MakeScopeExit([&]() { cairo_surface_destroy(surface); });
3333
3334 return gdk_cursor_new_from_surface(gdk_display_get_default(), surface,
3335 aCursor.mHotspotX, aCursor.mHotspotY);
3336}
3337
3338void nsWindow::SetCursor(const Cursor& aCursor) {
3339 if (mWidgetCursorLocked || !mGdkWindow) {
3340 return;
3341 }
3342
3343 // Only change cursor if it's actually been changed
3344 if (!mUpdateCursor && mCursor == aCursor) {
3345 return;
3346 }
3347
3348 mUpdateCursor = false;
3349 mCursor = aCursor;
3350
3351 // Try to set the cursor image first, and fall back to the numeric cursor.
3352 GdkCursor* imageCursor = nullptr;
3353 if (mCustomCursorAllowed) {
3354 imageCursor = GetCursorForImage(aCursor, GdkCeiledScaleFactor());
3355 }
3356
3357 // When using a custom cursor, clear the cursor first using eCursor_none, in
3358 // order to work around https://gitlab.gnome.org/GNOME/gtk/-/issues/6242
3359 GdkCursor* nonImageCursor =
3360 get_gtk_cursor(imageCursor ? eCursor_none : aCursor.mDefaultCursor);
3361 auto CleanupCursor = mozilla::MakeScopeExit([&]() {
3362 // get_gtk_cursor returns a weak reference, which we shouldn't unref.
3363 if (imageCursor) {
3364 g_object_unref(imageCursor);
3365 }
3366 });
3367
3368 gdk_window_set_cursor(mGdkWindow, nonImageCursor);
3369 if (imageCursor) {
3370 gdk_window_set_cursor(mGdkWindow, imageCursor);
3371 }
3372}
3373
3374void nsWindow::Invalidate(const LayoutDeviceIntRect& aRect) {
3375 if (!mGdkWindow) {
3376 return;
3377 }
3378
3379 GdkRectangle rect = DevicePixelsToGdkRectRoundOut(aRect);
3380 gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE(0));
3381
3382 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)
3383 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)
;
3384}
3385
3386void* nsWindow::GetNativeData(uint32_t aDataType) {
3387 switch (aDataType) {
3388 case NS_NATIVE_WINDOW0:
3389 case NS_NATIVE_WIDGET3: {
3390 return mGdkWindow;
3391 }
3392
3393 case NS_NATIVE_SHELLWIDGET10:
3394 return GetToplevelWidget();
3395
3396 case NS_NATIVE_WINDOW_WEBRTC_DEVICE_ID15:
3397 if (!mGdkWindow) {
3398 return nullptr;
3399 }
3400#ifdef MOZ_X111
3401 if (GdkIsX11Display()) {
3402 return (void*)GDK_WINDOW_XID(gdk_window_get_toplevel(mGdkWindow))(gdk_x11_window_get_xid (gdk_window_get_toplevel(mGdkWindow))
)
;
3403 }
3404#endif
3405 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"
, 3407)
3406 "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"
, 3407)
3407 "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"
, 3407)
;
3408 return nullptr;
3409 case NS_RAW_NATIVE_IME_CONTEXT14: {
3410 void* pseudoIMEContext = GetPseudoIMEContext();
3411 if (pseudoIMEContext) {
3412 return pseudoIMEContext;
3413 }
3414 // If IME context isn't available on this widget, we should set |this|
3415 // instead of nullptr.
3416 if (!mIMContext) {
3417 return this;
3418 }
3419 return mIMContext.get();
3420 }
3421 case NS_NATIVE_OPENGL_CONTEXT12:
3422 return nullptr;
3423 case NS_NATIVE_EGL_WINDOW106: {
3424 // On X11 we call it:
3425 // 1) If window is mapped on OnMap() by nsWindow::ResumeCompositorImpl(),
3426 // new EGLSurface/XWindow is created.
3427 // 2) If window is hidden on OnUnmap(), we replace EGLSurface/XWindow
3428 // by offline surface and release XWindow.
3429
3430 // On Wayland it:
3431 // 1) If window is mapped on OnMap(), we request frame callback
3432 // at MozContainer. If we get frame callback at MozContainer,
3433 // nsWindow::ResumeCompositorImpl() is called from it
3434 // and EGLSurface/wl_surface is created.
3435 // 2) If window is hidden on OnUnmap(), we replace EGLSurface/wl_surface
3436 // by offline surface and release XWindow.
3437
3438 // If nsWindow is already destroyed, don't try to get EGL window at all,
3439 // we're going to be deleted anyway.
3440 MutexAutoLock lock(mWindowVisibilityMutex);
3441 void* eglWindow = nullptr;
3442 if (mIsMapped && !mIsDestroyed) {
3443#ifdef MOZ_X111
3444 if (GdkIsX11Display()) {
3445 eglWindow = (void*)GDK_WINDOW_XID(mGdkWindow)(gdk_x11_window_get_xid (mGdkWindow));
3446 }
3447#endif
3448#ifdef MOZ_WAYLAND1
3449 if (GdkIsWaylandDisplay()) {
3450 eglWindow = moz_container_wayland_get_egl_window(
3451 mContainer, FractionalScaleFactor());
3452 }
3453#endif
3454 }
3455 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)
3456 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)
;
3457 return eglWindow;
3458 }
3459 default:
3460 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"
, 3460)
;
3461 return nullptr;
3462 }
3463}
3464
3465nsresult nsWindow::SetTitle(const nsAString& aTitle) {
3466 if (!mShell) {
3467 return NS_OK;
3468 }
3469
3470 // convert the string into utf8 and set the title.
3471#define UTF8_FOLLOWBYTE(ch)(((ch) & 0xC0) == 0x80) (((ch) & 0xC0) == 0x80)
3472 NS_ConvertUTF16toUTF8 titleUTF8(aTitle);
3473 if (titleUTF8.Length() > NS_WINDOW_TITLE_MAX_LENGTH4095) {
3474 // Truncate overlong titles (bug 167315). Make sure we chop after a
3475 // complete sequence by making sure the next char isn't a follow-byte.
3476 uint32_t len = NS_WINDOW_TITLE_MAX_LENGTH4095;
3477 while (UTF8_FOLLOWBYTE(titleUTF8[len])(((titleUTF8[len]) & 0xC0) == 0x80)) --len;
3478 titleUTF8.Truncate(len);
3479 }
3480 gtk_window_set_title(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), (const char*)titleUTF8.get());
3481
3482 return NS_OK;
3483}
3484
3485void nsWindow::SetIcon(const nsAString& aIconSpec) {
3486 if (!mShell) {
3487 return;
3488 }
3489
3490 nsAutoCString iconName;
3491
3492 if (aIconSpec.EqualsLiteral("default")) {
3493 nsAutoString brandName;
3494 WidgetUtils::GetBrandShortName(brandName);
3495 if (brandName.IsEmpty()) {
3496 brandName.AssignLiteral(u"Mozilla");
3497 }
3498 AppendUTF16toUTF8(brandName, iconName);
3499 ToLowerCase(iconName);
3500 } else {
3501 AppendUTF16toUTF8(aIconSpec, iconName);
3502 }
3503
3504 nsCOMPtr<nsIFile> iconFile;
3505 nsAutoCString path;
3506
3507 gint* iconSizes = gtk_icon_theme_get_icon_sizes(gtk_icon_theme_get_default(),
3508 iconName.get());
3509 bool foundIcon = (iconSizes[0] != 0);
3510 g_free(iconSizes);
3511
3512 if (!foundIcon) {
3513 // Look for icons with the following suffixes appended to the base name
3514 // The last two entries (for the old XPM format) will be ignored unless
3515 // no icons are found using other suffixes. XPM icons are deprecated.
3516
3517 const char16_t extensions[9][8] = {u".png", u"16.png", u"32.png",
3518 u"48.png", u"64.png", u"128.png",
3519 u"256.png", u".xpm", u"16.xpm"};
3520
3521 for (uint32_t i = 0; i < ArrayLength(extensions); i++) {
3522 // Don't bother looking for XPM versions if we found a PNG.
3523 if (i == ArrayLength(extensions) - 2 && foundIcon) break;
3524
3525 ResolveIconName(aIconSpec, nsDependentString(extensions[i]),
3526 getter_AddRefs(iconFile));
3527 if (iconFile) {
3528 iconFile->GetNativePath(path);
3529 GdkPixbuf* icon = gdk_pixbuf_new_from_file(path.get(), nullptr);
3530 if (icon) {
3531 gtk_icon_theme_add_builtin_icon(iconName.get(),
3532 gdk_pixbuf_get_height(icon), icon);
3533 g_object_unref(icon);
3534 foundIcon = true;
3535 }
3536 }
3537 }
3538 }
3539
3540 // leave the default icon intact if no matching icons were found
3541 if (foundIcon) {
3542 gtk_window_set_icon_name(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), iconName.get());
3543 }
3544}
3545
3546/* TODO(bug 1655924): gdk_window_get_origin is can block waiting for the X
3547 server for a long time, we would like to use the implementation below
3548 instead. However, removing the synchronous x server queries causes a race
3549 condition to surface, causing issues such as bug 1652743 and bug 1653711.
3550
3551
3552 This code can be used instead of gdk_window_get_origin() but it cuases
3553 such issues:
3554
3555 *aX = 0;
3556 *aY = 0;
3557 if (!aWindow) {
3558 return;
3559 }
3560
3561 GdkWindow* current = aWindow;
3562 while (GdkWindow* parent = gdk_window_get_parent(current)) {
3563 if (parent == current) {
3564 break;
3565 }
3566
3567 int x = 0;
3568 int y = 0;
3569 gdk_window_get_position(current, &x, &y);
3570 *aX += x;
3571 *aY += y;
3572
3573 current = parent;
3574 }
3575*/
3576LayoutDeviceIntPoint nsWindow::WidgetToScreenOffset() {
3577 // Don't use gdk_window_get_origin() on wl_subsurface Wayland popups
3578 // https://gitlab.gnome.org/GNOME/gtk/-/issues/5287
3579 if (IsWaylandPopup() && !mPopupUseMoveToRect) {
3580 return mBounds.TopLeft();
3581 }
3582
3583 GdkPoint origin{};
3584 if (mGdkWindowOrigin.isSome()) {
3585 origin = mGdkWindowOrigin.value();
3586 } else if (mGdkWindow) {
3587 gdk_window_get_origin(mGdkWindow, &origin.x, &origin.y);
3588 mGdkWindowOrigin = Some(origin);
3589 }
3590
3591 return GdkPointToDevicePixels(origin);
3592}
3593
3594void nsWindow::CaptureRollupEvents(bool aDoCapture) {
3595 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)
;
3596 if (mIsDestroyed) {
3597 return;
3598 }
3599
3600 static constexpr auto kCaptureEventsMask =
3601 GdkEventMask(GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
3602 GDK_POINTER_MOTION_MASK | GDK_TOUCH_MASK);
3603
3604 static bool sSystemNeedsPointerGrab = [&] {
3605 if (GdkIsWaylandDisplay()) {
3606 return false;
3607 }
3608 // We only need to grab the pointer for X servers that move the focus with
3609 // the pointer (like twm, sawfish...). Since we roll up popups on focus out,
3610 // not grabbing the pointer triggers rollup when the mouse enters the popup
3611 // and leaves the main window, see bug 1807482.
3612 //
3613 // FVWM is also affected but less severely: the pointer can enter the
3614 // popup, but if it briefly moves out of the popup and over the main window
3615 // then we see a focus change and roll up the popup.
3616 //
3617 // We don't do it for most common desktops, if only because it causes X11
3618 // crashes like bug 1607713.
3619 const auto& desktop = GetDesktopEnvironmentIdentifier();
3620 return desktop.EqualsLiteral("twm") || desktop.EqualsLiteral("sawfish") ||
3621 StringBeginsWith(desktop, "fvwm"_ns);
3622 }();
3623
3624 const bool grabPointer = [] {
3625 switch (StaticPrefs::widget_gtk_grab_pointer()) {
3626 case 0:
3627 return false;
3628 case 1:
3629 return true;
3630 default:
3631 return sSystemNeedsPointerGrab;
3632 }
3633 }();
3634
3635 if (!grabPointer) {
3636 return;
3637 }
3638
3639 mNeedsToRetryCapturingMouse = false;
3640 if (aDoCapture) {
3641 if (mIsDragPopup || DragInProgress()) {
3642 // Don't add a grab if a drag is in progress, or if the widget is a drag
3643 // feedback popup. (panels with type="drag").
3644 return;
3645 }
3646
3647 if (!mHasMappedToplevel) {
3648 // On X, capturing an unmapped window is pointless (returns
3649 // GDK_GRAB_NOT_VIEWABLE). Avoid the X server round-trip and just retry
3650 // when we're mapped.
3651 mNeedsToRetryCapturingMouse = true;
3652 return;
3653 }
3654
3655 // gdk_pointer_grab is deprecated in favor of gdk_device_grab, but that
3656 // causes a strange bug on X11, most obviously with nested popup menus:
3657 // we somehow take the pointer position relative to the top left of the
3658 // outer menu and use it as if it were relative to the submenu. This
3659 // doesn't happen with gdk_pointer_grab even though the code is very
3660 // similar. See the video attached to bug 1750721 for a demonstration,
3661 // and see also bug 1820542 for when the same thing happened with
3662 // another attempt to use gdk_device_grab.
3663 //
3664 // (gdk_device_grab is deprecated in favor of gdk_seat_grab as of 3.20,
3665 // but at the time of this writing we still support older versions of
3666 // GTK 3.)
3667 GdkGrabStatus status =
3668 gdk_pointer_grab(GetToplevelGdkWindow(),
3669 /* owner_events = */ true, kCaptureEventsMask,
3670 /* confine_to = */ nullptr,
3671 /* cursor = */ nullptr, GetLastUserInputTime());
3672 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"
, 3672)
;
3673 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)
;
3674 gtk_grab_add(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))));
3675 } else {
3676 // There may not have been a drag in process when aDoCapture was set,
3677 // so make sure to remove any added grab. This is a no-op if the grab
3678 // was not added to this widget.
3679 gtk_grab_remove(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))));
3680 gdk_pointer_ungrab(GetLastUserInputTime());
3681 }
3682}
3683
3684nsresult nsWindow::GetAttention(int32_t aCycleCount) {
3685 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)
;
3686
3687 GtkWidget* top_window = GetToplevelWidget();
3688 GtkWidget* top_focused_window =
3689 gFocusWindow ? gFocusWindow->GetToplevelWidget() : nullptr;
3690
3691 // Don't get attention if the window is focused anyway.
3692 if (top_window && (gtk_widget_get_visible(top_window)) &&
3693 top_window != top_focused_window) {
3694 SetUrgencyHint(top_window, true);
3695 }
3696
3697 return NS_OK;
3698}
3699
3700bool nsWindow::HasPendingInputEvent() {
3701 // This sucks, but gtk/gdk has no way to answer the question we want while
3702 // excluding paint events, and there's no X API that will let us peek
3703 // without blocking or removing. To prevent event reordering, peek
3704 // anything except expose events. Reordering expose and others should be
3705 // ok, hopefully.
3706 bool haveEvent = false;
3707#ifdef MOZ_X111
3708 XEvent ev;
3709 if (GdkIsX11Display()) {
3710 Display* display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default())(gdk_x11_display_get_xdisplay (gdk_display_get_default()));
3711 haveEvent = XCheckMaskEvent(
3712 display,
3713 KeyPressMask(1L<<0) | KeyReleaseMask(1L<<1) | ButtonPressMask(1L<<2) | ButtonReleaseMask(1L<<3) |
3714 EnterWindowMask(1L<<4) | LeaveWindowMask(1L<<5) | PointerMotionMask(1L<<6) |
3715 PointerMotionHintMask(1L<<7) | Button1MotionMask(1L<<8) | Button2MotionMask(1L<<9) |
3716 Button3MotionMask(1L<<10) | Button4MotionMask(1L<<11) | Button5MotionMask(1L<<12) |
3717 ButtonMotionMask(1L<<13) | KeymapStateMask(1L<<14) | VisibilityChangeMask(1L<<16) |
3718 StructureNotifyMask(1L<<17) | ResizeRedirectMask(1L<<18) | SubstructureNotifyMask(1L<<19) |
3719 SubstructureRedirectMask(1L<<20) | FocusChangeMask(1L<<21) | PropertyChangeMask(1L<<22) |
3720 ColormapChangeMask(1L<<23) | OwnerGrabButtonMask(1L<<24),
3721 &ev);
3722 if (haveEvent) {
3723 XPutBackEvent(display, &ev);
3724 }
3725 }
3726#endif
3727 return haveEvent;
3728}
3729
3730#ifdef cairo_copy_clip_rectangle_list
3731# error "Looks like we're including Mozilla's cairo instead of system cairo"
3732#endif
3733static bool ExtractExposeRegion(LayoutDeviceIntRegion& aRegion, cairo_t* cr) {
3734 cairo_rectangle_list_t* rects = cairo_copy_clip_rectangle_list(cr);
3735 if (rects->status != CAIRO_STATUS_SUCCESS) {
3736 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"
, 3736)
;
3737 return false;
3738 }
3739
3740 for (int i = 0; i < rects->num_rectangles; i++) {
3741 const cairo_rectangle_t& r = rects->rectangles[i];
3742 aRegion.Or(aRegion,
3743 LayoutDeviceIntRect::Truncate((float)r.x, (float)r.y,
3744 (float)r.width, (float)r.height));
3745 }
3746
3747 cairo_rectangle_list_destroy(rects);
3748 return true;
3749}
3750
3751#ifdef MOZ_WAYLAND1
3752void nsWindow::CreateCompositorVsyncDispatcher() {
3753 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)
;
3754 if (!mWaylandVsyncSource) {
3755 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)
3756 " 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)
3757 "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)
;
3758 nsBaseWidget::CreateCompositorVsyncDispatcher();
3759 return;
3760 }
3761 if (!mCompositorVsyncDispatcherLock) {
3762 mCompositorVsyncDispatcherLock =
3763 MakeUnique<Mutex>("mCompositorVsyncDispatcherLock");
3764 }
3765 MutexAutoLock lock(*mCompositorVsyncDispatcherLock);
3766 if (!mCompositorVsyncDispatcher) {
3767 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)
;
3768 mCompositorVsyncDispatcher =
3769 new CompositorVsyncDispatcher(mWaylandVsyncDispatcher);
3770 }
3771}
3772#endif
3773
3774void nsWindow::RequestRepaint(LayoutDeviceIntRegion& aRepaintRegion) {
3775 WindowRenderer* renderer = GetWindowRenderer();
3776 WebRenderLayerManager* layerManager = renderer->AsWebRender();
3777 KnowsCompositor* knowsCompositor = renderer->AsKnowsCompositor();
3778
3779 if (knowsCompositor && layerManager && mCompositorSession) {
3780 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)
;
3781
3782 if (!mConfiguredClearColor && !IsPopup()) {
3783 layerManager->WrBridge()->SendSetDefaultClearColor(LookAndFeel::Color(
3784 LookAndFeel::ColorID::Window, PreferenceSheet::ColorSchemeForChrome(),
3785 LookAndFeel::UseStandins::No));
3786 mConfiguredClearColor = true;
3787 }
3788
3789 // We need to paint to the screen even if nothing changed, since if we
3790 // don't have a compositing window manager, our pixels could be stale.
3791 layerManager->SetNeedsComposite(true);
3792 layerManager->SendInvalidRegion(aRepaintRegion.ToUnknownRegion());
3793 }
3794}
3795
3796gboolean nsWindow::OnExposeEvent(cairo_t* cr) {
3797 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)
3798 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)
;
3799
3800 // This might destroy us.
3801 NotifyOcclusionState(OcclusionState::VISIBLE);
3802 if (mIsDestroyed) {
3803 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)
;
3804 return FALSE(0);
3805 }
3806
3807 // Send any pending resize events so that layout can update.
3808 // May run event loop and destroy us.
3809 MaybeDispatchResized();
3810 if (mIsDestroyed) {
3811 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)
;
3812 return FALSE(0);
3813 }
3814
3815 // Windows that are not visible will be painted after they become visible.
3816 if (!mGdkWindow || !mHasMappedToplevel) {
3817 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)
;
3818 return FALSE(0);
3819 }
3820#ifdef MOZ_WAYLAND1
3821 if (GdkIsWaylandDisplay() && !moz_container_wayland_can_draw(mContainer)) {
3822 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)
;
3823 return FALSE(0);
3824 }
3825#endif
3826
3827 if (!GetListener()) {
3828 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)
;
3829 return FALSE(0);
3830 }
3831
3832 LayoutDeviceIntRegion exposeRegion;
3833 if (!ExtractExposeRegion(exposeRegion, cr)) {
3834 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)
;
3835 return FALSE(0);
3836 }
3837
3838 gint scale = GdkCeiledScaleFactor();
3839 LayoutDeviceIntRegion region = exposeRegion;
3840 region.ScaleRoundOut(scale, scale);
3841
3842 RequestRepaint(region);
3843
3844 RefPtr<nsWindow> strongThis(this);
3845
3846 // Dispatch WillPaintWindow notification to allow scripts etc. to run
3847 // before we paint. It also spins event loop which may show/hide the window
3848 // so we may have new renderer etc.
3849 GetListener()->WillPaintWindow(this);
3850
3851 // If the window has been destroyed during the will paint notification,
3852 // there is nothing left to do.
3853 if (!mGdkWindow || mIsDestroyed) {
3854 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)
;
3855 return TRUE(!(0));
3856 }
3857
3858 // Re-get all rendering components since the will paint notification
3859 // might have killed it.
3860 nsIWidgetListener* listener = GetListener();
3861 if (!listener) {
3862 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)
;
3863 return FALSE(0);
3864 }
3865
3866 WindowRenderer* renderer = GetWindowRenderer();
3867 WebRenderLayerManager* layerManager = renderer->AsWebRender();
3868 KnowsCompositor* knowsCompositor = renderer->AsKnowsCompositor();
3869
3870 if (knowsCompositor && layerManager && layerManager->NeedsComposite()) {
3871 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)
;
3872 layerManager->ScheduleComposite(wr::RenderReasons::WIDGET);
3873 layerManager->SetNeedsComposite(false);
3874 }
3875
3876 // Our bounds may have changed after calling WillPaintWindow. Clip
3877 // to the new bounds here. The region is relative to this
3878 // window.
3879 region.And(region, LayoutDeviceIntRect(0, 0, mBounds.width, mBounds.height));
3880
3881 bool shaped = false;
3882 if (TransparencyMode::Transparent == GetTransparencyMode()) {
3883 auto* window = static_cast<nsWindow*>(GetTopLevelWidget());
3884 if (mTransparencyBitmapForTitlebar) {
3885 if (mSizeMode == nsSizeMode_Normal) {
3886 window->UpdateTitlebarTransparencyBitmap();
3887 } else {
3888 window->ClearTransparencyBitmap();
3889 }
3890 } else {
3891 if (mHasAlphaVisual) {
3892 // Remove possible shape mask from when window manger was not
3893 // previously compositing.
3894 window->ClearTransparencyBitmap();
3895 } else {
3896 shaped = true;
3897 }
3898 }
3899 }
3900
3901 if (region.IsEmpty()) {
3902 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)
;
3903 return TRUE(!(0));
3904 }
3905
3906 // If this widget uses OMTC...
3907 if (renderer->GetBackendType() == LayersBackend::LAYERS_WR) {
3908 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)
;
3909 listener->PaintWindow(this, region);
3910
3911 // Re-get the listener since the will paint notification might have
3912 // killed it.
3913 listener = GetListener();
3914 if (!listener) {
3915 return TRUE(!(0));
3916 }
3917
3918 listener->DidPaintWindow();
3919 return TRUE(!(0));
3920 }
3921
3922 BufferMode layerBuffering = BufferMode::BUFFERED;
3923 RefPtr<DrawTarget> dt = StartRemoteDrawingInRegion(region, &layerBuffering);
3924 if (!dt || !dt->IsValid()) {
3925 return FALSE(0);
3926 }
3927 Maybe<gfxContext> ctx;
3928 IntRect boundsRect = region.GetBounds().ToUnknownRect();
3929 IntPoint offset(0, 0);
3930 if (dt->GetSize() == boundsRect.Size()) {
3931 offset = boundsRect.TopLeft();
3932 dt->SetTransform(Matrix::Translation(-offset));
3933 }
3934
3935#ifdef MOZ_X111
3936 if (shaped) {
3937 // Collapse update area to the bounding box. This is so we only have to
3938 // call UpdateTranslucentWindowAlpha once. After we have dropped
3939 // support for non-Thebes graphics, UpdateTranslucentWindowAlpha will be
3940 // our private interface so we can rework things to avoid this.
3941 dt->PushClipRect(Rect(boundsRect));
3942
3943 // The double buffering is done here to extract the shape mask.
3944 // (The shape mask won't be necessary when a visual with an alpha
3945 // channel is used on compositing window managers.)
3946 layerBuffering = BufferMode::BUFFER_NONE;
3947 RefPtr<DrawTarget> destDT =
3948 dt->CreateSimilarDrawTarget(boundsRect.Size(), SurfaceFormat::B8G8R8A8);
3949 if (!destDT || !destDT->IsValid()) {
3950 return FALSE(0);
3951 }
3952 destDT->SetTransform(Matrix::Translation(-boundsRect.TopLeft()));
3953 ctx.emplace(destDT, /* aPreserveTransform */ true);
3954 } else {
3955 gfxUtils::ClipToRegion(dt, region.ToUnknownRegion());
3956 ctx.emplace(dt, /* aPreserveTransform */ true);
3957 }
3958
3959# if 0
3960 // NOTE: Paint flashing region would be wrong for cairo, since
3961 // cairo inflates the update region, etc. So don't paint flash
3962 // for cairo.
3963# ifdef DEBUG1
3964 // XXX aEvent->region may refer to a newly-invalid area. FIXME
3965 if (0 && WANT_PAINT_FLASHING && gtk_widget_get_window(aEvent))
3966 gdk_window_flash(mGdkWindow, 1, 100, aEvent->region);
3967# endif
3968# endif
3969
3970#endif // MOZ_X11
3971
3972 bool painted = false;
3973 {
3974 if (renderer->GetBackendType() == LayersBackend::LAYERS_NONE) {
3975 if (GetTransparencyMode() == TransparencyMode::Transparent &&
3976 layerBuffering == BufferMode::BUFFER_NONE && mHasAlphaVisual) {
3977 // If our draw target is unbuffered and we use an alpha channel,
3978 // clear the image beforehand to ensure we don't get artifacts from a
3979 // reused SHM image. See bug 1258086.
3980 dt->ClearRect(Rect(boundsRect));
3981 }
3982 AutoLayerManagerSetup setupLayerManager(
3983 this, ctx.isNothing() ? nullptr : &ctx.ref(), layerBuffering);
3984 painted = listener->PaintWindow(this, region);
3985
3986 // Re-get the listener since the will paint notification might have
3987 // killed it.
3988 listener = GetListener();
3989 if (!listener) {
3990 return TRUE(!(0));
3991 }
3992 }
3993 }
3994
3995#ifdef MOZ_X111
3996 // PaintWindow can Destroy us (bug 378273), avoid doing any paint
3997 // operations below if that happened - it will lead to XError and exit().
3998 if (shaped) {
3999 if (MOZ_LIKELY(!mIsDestroyed)(__builtin_expect(!!(!mIsDestroyed), 1))) {
4000 if (painted) {
4001 RefPtr<SourceSurface> surf = ctx->GetDrawTarget()->Snapshot();
4002
4003 UpdateAlpha(surf, boundsRect);
4004
4005 dt->DrawSurface(surf, Rect(boundsRect),
4006 Rect(0, 0, boundsRect.width, boundsRect.height),
4007 DrawSurfaceOptions(SamplingFilter::POINT),
4008 DrawOptions(1.0f, CompositionOp::OP_SOURCE));
4009 }
4010 }
4011 }
4012
4013 ctx.reset();
4014 dt->PopClip();
4015
4016#endif // MOZ_X11
4017
4018 EndRemoteDrawingInRegion(dt, region);
4019
4020 listener->DidPaintWindow();
4021
4022 // Synchronously flush any new dirty areas
4023 cairo_region_t* dirtyArea = gdk_window_get_update_area(mGdkWindow);
4024
4025 if (dirtyArea) {
4026 gdk_window_invalidate_region(mGdkWindow, dirtyArea, false);
4027 cairo_region_destroy(dirtyArea);
4028 gdk_window_process_updates(mGdkWindow, false);
4029 }
4030
4031 // check the return value!
4032 return TRUE(!(0));
4033}
4034
4035void nsWindow::UpdateAlpha(SourceSurface* aSourceSurface,
4036 nsIntRect aBoundsRect) {
4037 // We need to create our own buffer to force the stride to match the
4038 // expected stride.
4039 int32_t stride =
4040 GetAlignedStride<4>(aBoundsRect.width, BytesPerPixel(SurfaceFormat::A8));
4041 if (stride == 0) {
4042 return;
4043 }
4044 int32_t bufferSize = stride * aBoundsRect.height;
4045 auto imageBuffer = MakeUniqueFallible<uint8_t[]>(bufferSize);
4046 {
4047 RefPtr<DrawTarget> drawTarget = gfxPlatform::CreateDrawTargetForData(
4048 imageBuffer.get(), aBoundsRect.Size(), stride, SurfaceFormat::A8);
4049
4050 if (drawTarget) {
4051 drawTarget->DrawSurface(aSourceSurface,
4052 Rect(0, 0, aBoundsRect.width, aBoundsRect.height),
4053 Rect(0, 0, aSourceSurface->GetSize().width,
4054 aSourceSurface->GetSize().height),
4055 DrawSurfaceOptions(SamplingFilter::POINT),
4056 DrawOptions(1.0f, CompositionOp::OP_SOURCE));
4057 }
4058 }
4059 UpdateTranslucentWindowAlphaInternal(aBoundsRect, imageBuffer.get(), stride);
4060}
4061
4062gboolean nsWindow::OnConfigureEvent(GtkWidget* aWidget,
4063 GdkEventConfigure* aEvent) {
4064 // These events are only received on toplevel windows.
4065 //
4066 // GDK ensures that the coordinates are the client window top-left wrt the
4067 // root window.
4068 //
4069 // GDK calculates the cordinates for real ConfigureNotify events on
4070 // managed windows (that would normally be relative to the parent
4071 // window).
4072 //
4073 // Synthetic ConfigureNotify events are from the window manager and
4074 // already relative to the root window. GDK creates all X windows with
4075 // border_width = 0, so synthetic events also indicate the top-left of
4076 // the client window.
4077 //
4078 // Override-redirect windows are children of the root window so parent
4079 // coordinates are root coordinates.
4080
4081#ifdef MOZ_LOGGING1
4082 int scale = mGdkWindow ? gdk_window_get_scale_factor(mGdkWindow) : -1;
4083 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)
4084 "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)
4085 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)
4086 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)
;
4087#endif
4088
4089 if (mPendingConfigures > 0) {
4090 mPendingConfigures--;
4091 }
4092
4093 ResetScreenBounds();
4094
4095 // Don't fire configure event for scale changes, we handle that
4096 // OnScaleChanged event. Skip that for toplevel windows only.
4097 if (mGdkWindow && IsTopLevelWindowType()) {
4098 if (mCeiledScaleFactor != gdk_window_get_scale_factor(mGdkWindow)) {
4099 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)
4100 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)
;
4101 return FALSE(0);
4102 }
4103 }
4104
4105 LayoutDeviceIntRect screenBounds = GetScreenBounds();
4106
4107 if (IsTopLevelWindowType()) {
4108 // This check avoids unwanted rollup on spurious configure events from
4109 // Cygwin/X (bug 672103).
4110 if (mBounds.x != screenBounds.x || mBounds.y != screenBounds.y) {
4111 RollupAllMenus();
4112 }
4113 }
4114
4115 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"
, 4116); MOZ_PretendNoReturn(); } } while (0)
4116 "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"
, 4116); MOZ_PretendNoReturn(); } } while (0)
;
4117 if (mGdkWindow &&
4118 gtk_window_get_window_type(GTK_WINDOW(aWidget)((((GtkWindow*) (void *) ((aWidget)))))) == GTK_WINDOW_POPUP) {
4119 // Override-redirect window
4120 //
4121 // These windows should not be moved by the window manager, and so any
4122 // change in position is a result of our direction. mBounds has
4123 // already been set in std::move() or Resize(), and that is more
4124 // up-to-date than the position in the ConfigureNotify event if the
4125 // event is from an earlier window move.
4126 //
4127 // Skipping the WindowMoved call saves context menus from an infinite
4128 // loop when nsXULPopupManager::PopupMoved moves the window to the new
4129 // position and nsMenuPopupFrame::SetPopupPosition adds
4130 // offsetForContextMenu on each iteration.
4131
4132 // Our back buffer might have been invalidated while we drew the last
4133 // frame, and its contents might be incorrect. See bug 1280653 comment 7
4134 // and comment 10. Specifically we must ensure we recomposite the frame
4135 // as soon as possible to avoid the corrupted frame being displayed.
4136 GetWindowRenderer()->FlushRendering(wr::RenderReasons::WIDGET);
4137 return FALSE(0);
4138 }
4139
4140 mBounds.MoveTo(screenBounds.TopLeft());
4141 RecomputeClientOffset(/* aNotify = */ false);
4142
4143 // XXX mozilla will invalidate the entire window after this move
4144 // complete. wtf?
4145 NotifyWindowMoved(mBounds.x, mBounds.y);
4146
4147 return FALSE(0);
4148}
4149
4150void nsWindow::OnSizeAllocate(GtkAllocation* aAllocation) {
4151 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)
4152 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)
;
4153
4154 ResetScreenBounds();
4155
4156 // Client offset are updated by _NET_FRAME_EXTENTS on X11 when system titlebar
4157 // is enabled. In either cases (Wayland or system titlebar is off on X11)
4158 // we don't get _NET_FRAME_EXTENTS X11 property notification so we derive
4159 // it from mContainer position.
4160 RecomputeClientOffset(/* aNotify = */ true);
4161
4162 mHasReceivedSizeAllocate = true;
4163
4164 LayoutDeviceIntSize size = GdkRectToDevicePixels(*aAllocation).Size();
4165
4166 // Sometimes the window manager gives us garbage sizes (way past the maximum
4167 // texture size) causing crashes if we don't enforce size constraints again
4168 // here.
4169 ConstrainSize(&size.width, &size.height);
4170
4171 if (mBounds.Size() == size) {
4172 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)
;
4173 // mBounds was set at Create() or Resize().
4174 if (mNeedsDispatchSize != LayoutDeviceIntSize(-1, -1)) {
4175 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)
4176 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)
;
4177 mNeedsDispatchSize = LayoutDeviceIntSize(-1, -1);
4178 }
4179 return;
4180 }
4181
4182 // Invalidate the new part of the window now for the pending paint to
4183 // minimize background flashes (GDK does not do this for external resizes
4184 // of toplevels.)
4185 if (mGdkWindow) {
4186 if (mBounds.width < size.width) {
4187 GdkRectangle rect = DevicePixelsToGdkRectRoundOut(LayoutDeviceIntRect(
4188 mBounds.width, 0, size.width - mBounds.width, size.height));
4189 gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE(0));
4190 }
4191 if (mBounds.height < size.height) {
4192 GdkRectangle rect = DevicePixelsToGdkRectRoundOut(LayoutDeviceIntRect(
4193 0, mBounds.height, size.width, size.height - mBounds.height));
4194 gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE(0));
4195 }
4196 }
4197
4198 // If we update mBounds here, then inner/outerHeight are out of sync until
4199 // we call WindowResized.
4200 mNeedsDispatchSize = size;
4201
4202 // Gecko permits running nested event loops during processing of events,
4203 // GtkWindow callers of gtk_widget_size_allocate expect the signal
4204 // handlers to return sometime in the near future.
4205 NS_DispatchToCurrentThread(NewRunnableMethod(
4206 "nsWindow::MaybeDispatchResized", this, &nsWindow::MaybeDispatchResized));
4207}
4208
4209void nsWindow::OnDeleteEvent() {
4210 if (mWidgetListener) mWidgetListener->RequestWindowClose(this);
4211}
4212
4213void nsWindow::OnEnterNotifyEvent(GdkEventCrossing* aEvent) {
4214 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)
4215 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)
4216 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)
;
4217 // This skips NotifyVirtual and NotifyNonlinearVirtual enter notify events
4218 // when the pointer enters a child window. If the destination window is a
4219 // Gecko window then we'll catch the corresponding event on that window,
4220 // but we won't notice when the pointer directly enters a foreign (plugin)
4221 // child window without passing over a visible portion of a Gecko window.
4222 if (aEvent->subwindow) {
4223 return;
4224 }
4225
4226 // Check before checking for ungrab as the button state may have
4227 // changed while a non-Gecko ancestor window had a pointer grab.
4228 DispatchMissedButtonReleases(aEvent);
4229
4230 WidgetMouseEvent event(true, eMouseEnterIntoWidget, this,
4231 WidgetMouseEvent::eReal);
4232
4233 event.mRefPoint = GdkEventCoordsToDevicePixels(aEvent->x, aEvent->y);
4234 event.AssignEventTime(GetWidgetEventTime(aEvent->time));
4235
4236 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)
;
4237
4238 DispatchInputEvent(&event);
4239}
4240
4241// Some window managers send a bogus top-level leave-notify event on every
4242// click. That confuses our event handling code in ways that can break websites,
4243// see bug 1805939 for details.
4244//
4245// Make sure to only check this on bogus environments, since for environments
4246// with CSD, gdk_device_get_window_at_position could return the window even when
4247// the pointer is in the decoration area.
4248static bool IsBogusLeaveNotifyEvent(GdkWindow* aWindow,
4249 GdkEventCrossing* aEvent) {
4250 static bool sBogusWm = [] {
4251 if (GdkIsWaylandDisplay()) {
4252 return false;
4253 }
4254 const auto& desktopEnv = GetDesktopEnvironmentIdentifier();
4255 return desktopEnv.EqualsLiteral("fluxbox") || // Bug 1805939 comment 0.
4256 desktopEnv.EqualsLiteral("blackbox") || // Bug 1805939 comment 32.
4257 desktopEnv.EqualsLiteral("lg3d") || // Bug 1820405.
4258 desktopEnv.EqualsLiteral("pekwm") || // Bug 1822911.
4259 StringBeginsWith(desktopEnv, "fvwm"_ns);
4260 }();
4261
4262 const bool shouldCheck = [] {
4263 switch (StaticPrefs::widget_gtk_ignore_bogus_leave_notify()) {
4264 case 0:
4265 return false;
4266 case 1:
4267 return true;
4268 default:
4269 return sBogusWm;
4270 }
4271 }();
4272
4273 if (!shouldCheck || !aWindow) {
4274 return false;
4275 }
4276 GdkDevice* pointer = GdkGetPointer();
4277 GdkWindow* winAtPt =
4278 gdk_device_get_window_at_position(pointer, nullptr, nullptr);
4279 if (!winAtPt) {
4280 return false;
4281 }
4282 // We're still in the same top level window, ignore this leave notify event.
4283 GdkWindow* topLevelAtPt = gdk_window_get_toplevel(winAtPt);
4284 GdkWindow* topLevelWidget = gdk_window_get_toplevel(aWindow);
4285 return topLevelAtPt == topLevelWidget;
4286}
4287
4288void nsWindow::OnLeaveNotifyEvent(GdkEventCrossing* aEvent) {
4289 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)
4290 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)
4291 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)
;
4292
4293 // This ignores NotifyVirtual and NotifyNonlinearVirtual leave notify
4294 // events when the pointer leaves a child window. If the destination
4295 // window is a Gecko window then we'll catch the corresponding event on
4296 // that window.
4297 //
4298 // XXXkt However, we will miss toplevel exits when the pointer directly
4299 // leaves a foreign (plugin) child window without passing over a visible
4300 // portion of a Gecko window.
4301 if (aEvent->subwindow) {
4302 return;
4303 }
4304
4305 // The filter out for subwindows should make sure that this is targeted to
4306 // this nsWindow.
4307 const bool leavingTopLevel = IsTopLevelWindowType();
4308 if (leavingTopLevel && IsBogusLeaveNotifyEvent(mGdkWindow, aEvent)) {
4309 return;
4310 }
4311
4312 WidgetMouseEvent event(true, eMouseExitFromWidget, this,
4313 WidgetMouseEvent::eReal);
4314
4315 event.mRefPoint = GdkEventCoordsToDevicePixels(aEvent->x, aEvent->y);
4316 event.AssignEventTime(GetWidgetEventTime(aEvent->time));
4317 event.mExitFrom = Some(leavingTopLevel ? WidgetMouseEvent::ePlatformTopLevel
4318 : WidgetMouseEvent::ePlatformChild);
4319
4320 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)
;
4321
4322 DispatchInputEvent(&event);
4323}
4324
4325Maybe<GdkWindowEdge> nsWindow::CheckResizerEdge(
4326 const LayoutDeviceIntPoint& aPoint) {
4327 const bool canResize = [&] {
4328 // Don't allow resizing maximized/fullscreen windows.
4329 if (mSizeMode != nsSizeMode_Normal) {
4330 return false;
4331 }
4332 if (mIsPIPWindow) {
4333 // Note that since we do show resizers on left/right sides on PIP windows,
4334 // we still want the resizers there, even when tiled.
4335 return true;
4336 }
4337 if (!mDrawInTitlebar) {
4338 return false;
4339 }
4340 // On KDE, allow for 1 extra pixel at the top of regular windows when
4341 // drawing to the titlebar. This matches the native titlebar behavior on
4342 // that environment. See bug 1813554.
4343 //
4344 // Don't do that on GNOME (see bug 1822764). If we wanted to do this on
4345 // GNOME we'd need an extra check for mIsTiled, since the window is "stuck"
4346 // to the top and bottom.
4347 //
4348 // Other DEs are untested.
4349 return mDrawInTitlebar && IsKdeDesktopEnvironment();
4350 }();
4351
4352 if (!canResize) {
4353 return Nothing();
4354 }
4355
4356 // If we're not in a PiP window, allow 1px resizer edge from the top edge,
4357 // and nothing else.
4358 // This is to allow resizes of tiled windows on KDE, see bug 1813554.
4359 const int resizerHeight = (mIsPIPWindow ? 15 : 1) * GdkCeiledScaleFactor();
4360 const int resizerWidth = resizerHeight * 4;
4361
4362 const int topDist = aPoint.y;
4363 const int leftDist = aPoint.x;
4364 const int rightDist = mBounds.width - aPoint.x;
4365 const int bottomDist = mBounds.height - aPoint.y;
4366
4367 // We can't emulate resize of North/West edges on Wayland as we can't shift
4368 // toplevel window.
4369 bool waylandLimitedResize = mAspectRatio != 0.0f && GdkIsWaylandDisplay();
4370
4371 if (topDist <= resizerHeight) {
4372 if (rightDist <= resizerWidth) {
4373 return Some(GDK_WINDOW_EDGE_NORTH_EAST);
4374 }
4375 if (leftDist <= resizerWidth) {
4376 return Some(GDK_WINDOW_EDGE_NORTH_WEST);
4377 }
4378 return waylandLimitedResize ? Nothing() : Some(GDK_WINDOW_EDGE_NORTH);
4379 }
4380
4381 if (!mIsPIPWindow) {
4382 return Nothing();
4383 }
4384
4385 if (bottomDist <= resizerHeight) {
4386 if (leftDist <= resizerWidth) {
4387 return Some(GDK_WINDOW_EDGE_SOUTH_WEST);
4388 }
4389 if (rightDist <= resizerWidth) {
4390 return Some(GDK_WINDOW_EDGE_SOUTH_EAST);
4391 }
4392 return Some(GDK_WINDOW_EDGE_SOUTH);
4393 }
4394
4395 if (leftDist <= resizerHeight) {
4396 if (topDist <= resizerWidth) {
4397 return Some(GDK_WINDOW_EDGE_NORTH_WEST);
4398 }
4399 if (bottomDist <= resizerWidth) {
4400 return Some(GDK_WINDOW_EDGE_SOUTH_WEST);
4401 }
4402 return waylandLimitedResize ? Nothing() : Some(GDK_WINDOW_EDGE_WEST);
4403 }
4404
4405 if (rightDist <= resizerHeight) {
4406 if (topDist <= resizerWidth) {
4407 return Some(GDK_WINDOW_EDGE_NORTH_EAST);
4408 }
4409 if (bottomDist <= resizerWidth) {
4410 return Some(GDK_WINDOW_EDGE_SOUTH_EAST);
4411 }
4412 return Some(GDK_WINDOW_EDGE_EAST);
4413 }
4414 return Nothing();
4415}
4416
4417template <typename Event>
4418static LayoutDeviceIntPoint GetRefPoint(nsWindow* aWindow, Event* aEvent) {
4419 if (aEvent->window == aWindow->GetGdkWindow()) {
4420 // we are the window that the event happened on so no need for expensive
4421 // WidgetToScreenOffset
4422 return aWindow->GdkEventCoordsToDevicePixels(aEvent->x, aEvent->y);
4423 }
4424 // XXX we're never quite sure which GdkWindow the event came from due to our
4425 // custom bubbling in scroll_event_cb(), so use ScreenToWidget to translate
4426 // the screen root coordinates into coordinates relative to this widget.
4427 return aWindow->GdkEventCoordsToDevicePixels(aEvent->x_root, aEvent->y_root) -
4428 aWindow->WidgetToScreenOffset();
4429}
4430
4431void nsWindow::EmulateResizeDrag(GdkEventMotion* aEvent) {
4432 auto newPoint = LayoutDeviceIntPoint::Floor(aEvent->x, aEvent->y);
4433 LayoutDeviceIntPoint diff = newPoint - mLastResizePoint;
4434 mLastResizePoint = newPoint;
4435
4436 GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mBounds.Size());
4437 LayoutDeviceIntSize newSize(size.width + diff.x, size.height + diff.y);
4438
4439 if (mAspectResizer.value() == GTK_ORIENTATION_VERTICAL) {
4440 newSize.width = int(newSize.height * mAspectRatio);
4441 } else { // GTK_ORIENTATION_HORIZONTAL
4442 newSize.height = int(newSize.width / mAspectRatio);
4443 }
4444 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)
4445 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)
;
4446 gtk_window_resize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), newSize.width, newSize.height);
4447}
4448
4449void nsWindow::OnMotionNotifyEvent(GdkEventMotion* aEvent) {
4450 if (!mGdkWindow) {
4451 return;
4452 }
4453
4454 // Emulate gdk_window_begin_resize_drag() for windows
4455 // with fixed aspect ratio on Wayland.
4456 if (mAspectResizer && mAspectRatio != 0.0f) {
4457 EmulateResizeDrag(aEvent);
4458 return;
4459 }
4460
4461 if (mWindowShouldStartDragging) {
4462 mWindowShouldStartDragging = false;
4463 GdkWindow* dragWindow = nullptr;
4464
4465 // find the top-level window
4466 if (mGdkWindow) {
4467 dragWindow = gdk_window_get_toplevel(mGdkWindow);
4468 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"
, 4468); AnnotateMozCrashReason("MOZ_ASSERT" "(" "dragWindow"
") (" "gdk_window_get_toplevel should not return null" ")");
do { *((volatile int*)__null) = 4468; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4469 }
4470
4471#ifdef MOZ_X111
4472 if (dragWindow && GdkIsX11Display()) {
4473 // Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=789054
4474 // To avoid crashes disable double-click on WM without _NET_WM_MOVERESIZE.
4475 // See _should_perform_ewmh_drag() at gdkwindow-x11.c
4476 GdkScreen* screen = gdk_window_get_screen(dragWindow);
4477 GdkAtom atom = gdk_atom_intern("_NET_WM_MOVERESIZE", FALSE(0));
4478 if (!gdk_x11_screen_supports_net_wm_hint(screen, atom)) {
4479 dragWindow = nullptr;
4480 }
4481 }
4482#endif
4483
4484 if (dragWindow) {
4485 gdk_window_begin_move_drag(dragWindow, 1, aEvent->x_root, aEvent->y_root,
4486 aEvent->time);
4487 return;
4488 }
4489 }
4490
4491 mWidgetCursorLocked = false;
4492 const auto refPoint = GetRefPoint(this, aEvent);
4493 if (auto edge = CheckResizerEdge(refPoint)) {
4494 nsCursor cursor = eCursor_none;
4495 switch (*edge) {
4496 case GDK_WINDOW_EDGE_SOUTH:
4497 case GDK_WINDOW_EDGE_NORTH:
4498 cursor = eCursor_ns_resize;
4499 break;
4500 case GDK_WINDOW_EDGE_WEST:
4501 case GDK_WINDOW_EDGE_EAST:
4502 cursor = eCursor_ew_resize;
4503 break;
4504 case GDK_WINDOW_EDGE_NORTH_WEST:
4505 case GDK_WINDOW_EDGE_SOUTH_EAST:
4506 cursor = eCursor_nwse_resize;
4507 break;
4508 case GDK_WINDOW_EDGE_NORTH_EAST:
4509 case GDK_WINDOW_EDGE_SOUTH_WEST:
4510 cursor = eCursor_nesw_resize;
4511 break;
4512 }
4513 SetCursor(Cursor{cursor});
4514 // If we set resize cursor on widget level keep it locked and prevent layout
4515 // to switch it back to default (by synthetic mouse events for instance)
4516 // until resize is finished. This affects PIP windows only.
4517 if (mIsPIPWindow) {
4518 mWidgetCursorLocked = true;
4519 }
4520 return;
4521 }
4522
4523 WidgetMouseEvent event(true, eMouseMove, this, WidgetMouseEvent::eReal);
4524
4525 gdouble pressure = 0;
4526 gdk_event_get_axis((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
4527 // Sometime gdk generate 0 pressure value between normal values
4528 // We have to ignore that and use last valid value
4529 if (pressure) {
4530 mLastMotionPressure = pressure;
4531 }
4532 event.mPressure = mLastMotionPressure;
4533 event.mRefPoint = refPoint;
4534 event.AssignEventTime(GetWidgetEventTime(aEvent->time));
4535
4536 KeymapWrapper::InitInputEvent(event, aEvent->state);
4537 InitPenEvent(event, (GdkEvent*)aEvent);
4538
4539 DispatchInputEvent(&event);
4540}
4541
4542// If the automatic pointer grab on ButtonPress has deactivated before
4543// ButtonRelease, and the mouse button is released while the pointer is not
4544// over any a Gecko window, then the ButtonRelease event will not be received.
4545// (A similar situation exists when the pointer is grabbed with owner_events
4546// True as the ButtonRelease may be received on a foreign [plugin] window).
4547// Use this method to check for released buttons when the pointer returns to a
4548// Gecko window.
4549void nsWindow::DispatchMissedButtonReleases(GdkEventCrossing* aGdkEvent) {
4550 guint changed = aGdkEvent->state ^ gButtonState;
4551 // Only consider button releases.
4552 // (Ignore button presses that occurred outside Gecko.)
4553 guint released = changed & gButtonState;
4554 gButtonState = aGdkEvent->state;
4555
4556 // Loop over each button, excluding mouse wheel buttons 4 and 5 for which
4557 // GDK ignores releases.
4558 for (guint buttonMask = GDK_BUTTON1_MASK; buttonMask <= GDK_BUTTON3_MASK;
4559 buttonMask <<= 1) {
4560 if (released & buttonMask) {
4561 int16_t buttonType;
4562 switch (buttonMask) {
4563 case GDK_BUTTON1_MASK:
4564 buttonType = MouseButton::ePrimary;
4565 break;
4566 case GDK_BUTTON2_MASK:
4567 buttonType = MouseButton::eMiddle;
4568 break;
4569 default:
4570 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"
, 4571); MOZ_PretendNoReturn(); } } while (0)
4571 "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"
, 4571); MOZ_PretendNoReturn(); } } while (0)
;
4572 buttonType = MouseButton::eSecondary;
4573 }
4574
4575 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)
;
4576
4577 // Dispatch a synthesized button up event to tell Gecko about the
4578 // change in state. This event is marked as synthesized so that
4579 // it is not dispatched as a DOM event, because we don't know the
4580 // position, widget, modifiers, or time/order.
4581 WidgetMouseEvent synthEvent(true, eMouseUp, this,
4582 WidgetMouseEvent::eSynthesized);
4583 synthEvent.mButton = buttonType;
4584 DispatchInputEvent(&synthEvent);
4585 }
4586 }
4587}
4588
4589void nsWindow::InitButtonEvent(WidgetMouseEvent& aEvent,
4590 GdkEventButton* aGdkEvent,
4591 const LayoutDeviceIntPoint& aRefPoint) {
4592 aEvent.mRefPoint = aRefPoint;
4593
4594 guint modifierState = aGdkEvent->state;
4595 // aEvent's state includes the button state from immediately before this
4596 // event. If aEvent is a mousedown or mouseup event, we need to update
4597 // the button state.
4598 guint buttonMask = 0;
4599 switch (aGdkEvent->button) {
4600 case 1:
4601 buttonMask = GDK_BUTTON1_MASK;
4602 break;
4603 case 2:
4604 buttonMask = GDK_BUTTON2_MASK;
4605 break;
4606 case 3:
4607 buttonMask = GDK_BUTTON3_MASK;
4608 break;
4609 }
4610 if (aGdkEvent->type == GDK_BUTTON_RELEASE) {
4611 modifierState &= ~buttonMask;
4612 } else {
4613 modifierState |= buttonMask;
4614 }
4615
4616 KeymapWrapper::InitInputEvent(aEvent, modifierState);
4617
4618 aEvent.AssignEventTime(GetWidgetEventTime(aGdkEvent->time));
4619
4620 switch (aGdkEvent->type) {
4621 case GDK_2BUTTON_PRESS:
4622 aEvent.mClickCount = 2;
4623 break;
4624 case GDK_3BUTTON_PRESS:
4625 aEvent.mClickCount = 3;
4626 break;
4627 // default is one click
4628 default:
4629 aEvent.mClickCount = 1;
4630 }
4631}
4632
4633static guint ButtonMaskFromGDKButton(guint button) {
4634 return GDK_BUTTON1_MASK << (button - 1);
4635}
4636
4637void nsWindow::DispatchContextMenuEventFromMouseEvent(
4638 uint16_t domButton, GdkEventButton* aEvent,
4639 const LayoutDeviceIntPoint& aRefPoint) {
4640 if (domButton == MouseButton::eSecondary && MOZ_LIKELY(!mIsDestroyed)(__builtin_expect(!!(!mIsDestroyed), 1))) {
4641 Maybe<WidgetPointerEvent> pointerEvent;
4642 Maybe<WidgetMouseEvent> mouseEvent;
4643 if (StaticPrefs::dom_w3c_pointer_events_dispatch_click_as_pointer_event()) {
4644 pointerEvent.emplace(true, eContextMenu, this);
4645 } else {
4646 mouseEvent.emplace(true, eContextMenu, this, WidgetMouseEvent::eReal);
4647 }
4648 WidgetMouseEvent& contextMenuEvent =
4649 pointerEvent.isSome() ? pointerEvent.ref() : mouseEvent.ref();
4650 InitButtonEvent(contextMenuEvent, aEvent, aRefPoint);
4651 contextMenuEvent.mPressure = mLastMotionPressure;
4652 DispatchInputEvent(&contextMenuEvent);
4653 }
4654}
4655
4656void nsWindow::TryToShowNativeWindowMenu(GdkEventButton* aEvent) {
4657 if (!gdk_window_show_window_menu(GetToplevelGdkWindow(), (GdkEvent*)aEvent)) {
4658 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"
, 4658)
;
4659 }
4660}
4661
4662bool nsWindow::DoTitlebarAction(LookAndFeel::TitlebarEvent aEvent,
4663 GdkEventButton* aButtonEvent) {
4664 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)
4665 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)
;
4666 switch (LookAndFeel::GetTitlebarAction(aEvent)) {
4667 case LookAndFeel::TitlebarAction::WindowMenu:
4668 // Titlebar app menu
4669 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)
;
4670 TryToShowNativeWindowMenu(aButtonEvent);
4671 break;
4672 case LookAndFeel::TitlebarAction::WindowLower:
4673 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)
;
4674 // Lower is part of gtk_surface1 protocol which we can't support
4675 // as Gtk keeps it private. So emulate it by minimize.
4676 if (GdkIsWaylandDisplay()) {
4677 SetSizeMode(nsSizeMode_Minimized);
4678 } else {
4679 gdk_window_lower(GetToplevelGdkWindow());
4680 }
4681 break;
4682 case LookAndFeel::TitlebarAction::WindowMinimize:
4683 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)
;
4684 SetSizeMode(nsSizeMode_Minimized);
4685 break;
4686 case LookAndFeel::TitlebarAction::WindowMaximize:
4687 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)
;
4688 SetSizeMode(nsSizeMode_Maximized);
4689 break;
4690 case LookAndFeel::TitlebarAction::WindowMaximizeToggle:
4691 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)
;
4692 if (mSizeMode == nsSizeMode_Maximized) {
4693 SetSizeMode(nsSizeMode_Normal);
4694 } else if (mSizeMode == nsSizeMode_Normal) {
4695 SetSizeMode(nsSizeMode_Maximized);
4696 }
4697 break;
4698 case LookAndFeel::TitlebarAction::None:
4699 default:
4700 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)
;
4701 return false;
4702 }
4703 return true;
4704}
4705
4706void nsWindow::OnButtonPressEvent(GdkEventButton* aEvent) {
4707 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)
;
4708
4709 SetLastMousePressEvent((GdkEvent*)aEvent);
4710
4711 // If you double click in GDK, it will actually generate a second
4712 // GDK_BUTTON_PRESS before sending the GDK_2BUTTON_PRESS, and this is
4713 // different than the DOM spec. GDK puts this in the queue
4714 // programatically, so it's safe to assume that if there's a
4715 // double click in the queue, it was generated so we can just drop
4716 // this click.
4717 GUniquePtr<GdkEvent> peekedEvent(gdk_event_peek());
4718 if (peekedEvent) {
4719 GdkEventType type = peekedEvent->any.type;
4720 if (type == GDK_2BUTTON_PRESS || type == GDK_3BUTTON_PRESS) {
4721 return;
4722 }
4723 }
4724
4725 nsWindow* containerWindow = GetContainerWindow();
4726 if (!gFocusWindow && containerWindow) {
4727 containerWindow->DispatchActivateEvent();
4728 }
4729
4730 const auto refPoint = GetRefPoint(this, aEvent);
4731
4732 // check to see if we should rollup
4733 if (CheckForRollup(aEvent->x_root, aEvent->y_root, false, false)) {
4734 if (aEvent->button == 3 && mDraggableRegion.Contains(refPoint)) {
4735 GUniquePtr<GdkEvent> eventCopy;
4736 if (aEvent->type != GDK_BUTTON_PRESS) {
4737 // If the user double-clicks too fast we'll get a 2BUTTON_PRESS event
4738 // instead, and that isn't handled by open_window_menu, so coerce it
4739 // into a regular press.
4740 eventCopy.reset(gdk_event_copy((GdkEvent*)aEvent));
4741 eventCopy->type = GDK_BUTTON_PRESS;
4742 }
4743 TryToShowNativeWindowMenu(eventCopy ? &eventCopy->button : aEvent);
4744 }
4745 return;
4746 }
4747
4748 // Check to see if the event is within our window's resize region
4749 if (auto edge = CheckResizerEdge(refPoint)) {
4750 // On Wayland Gtk fails to vertically/horizontally resize windows
4751 // with fixed aspect ratio. We need to emulate
4752 // gdk_window_begin_resize_drag() at OnMotionNotifyEvent().
4753 if (mAspectRatio != 0.0f && GdkIsWaylandDisplay()) {
4754 mLastResizePoint = LayoutDeviceIntPoint::Floor(aEvent->x, aEvent->y);
4755 switch (*edge) {
4756 case GDK_WINDOW_EDGE_SOUTH:
4757 mAspectResizer = Some(GTK_ORIENTATION_VERTICAL);
4758 break;
4759 case GDK_WINDOW_EDGE_EAST:
4760 mAspectResizer = Some(GTK_ORIENTATION_HORIZONTAL);
4761 break;
4762 default:
4763 mAspectResizer.reset();
4764 break;
4765 }
4766 ApplySizeConstraints();
4767 }
4768 if (!mAspectResizer) {
4769 gdk_window_begin_resize_drag(GetToplevelGdkWindow(), *edge,
4770 aEvent->button, aEvent->x_root,
4771 aEvent->y_root, aEvent->time);
4772 }
4773 return;
4774 }
4775
4776 gdouble pressure = 0;
4777 gdk_event_get_axis((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
4778 mLastMotionPressure = pressure;
4779
4780 uint16_t domButton;
4781 switch (aEvent->button) {
4782 case 1:
4783 domButton = MouseButton::ePrimary;
4784 break;
4785 case 2:
4786 domButton = MouseButton::eMiddle;
4787 break;
4788 case 3:
4789 domButton = MouseButton::eSecondary;
4790 break;
4791 // These are mapped to horizontal scroll
4792 case 6:
4793 case 7:
4794 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"
, 4794)
;
4795 return;
4796 // Map buttons 8-9(10) to back/forward
4797 case 8:
4798 if (!Preferences::GetBool("mousebutton.4th.enabled", true)) {
4799 return;
4800 }
4801 DispatchCommandEvent(nsGkAtoms::Back);
4802 return;
4803 case 9:
4804 case 10:
4805 if (!Preferences::GetBool("mousebutton.5th.enabled", true)) {
4806 return;
4807 }
4808 DispatchCommandEvent(nsGkAtoms::Forward);
4809 return;
4810 default:
4811 return;
4812 }
4813
4814 gButtonState |= ButtonMaskFromGDKButton(aEvent->button);
4815
4816 WidgetMouseEvent event(true, eMouseDown, this, WidgetMouseEvent::eReal);
4817 event.mButton = domButton;
4818 InitButtonEvent(event, aEvent, refPoint);
4819 event.mPressure = mLastMotionPressure;
4820
4821 InitPenEvent(event, (GdkEvent*)aEvent);
4822 nsIWidget::ContentAndAPZEventStatus eventStatus = DispatchInputEvent(&event);
4823
4824 const bool defaultPrevented =
4825 eventStatus.mContentStatus == nsEventStatus_eConsumeNoDefault;
4826
4827 if (!defaultPrevented && mDraggableRegion.Contains(refPoint)) {
4828 if (domButton == MouseButton::ePrimary) {
4829 mWindowShouldStartDragging = true;
4830 } else if (domButton == MouseButton::eMiddle &&
4831 StaticPrefs::widget_gtk_titlebar_action_middle_click_enabled()) {
4832 DoTitlebarAction(nsXPLookAndFeel::TitlebarEvent::Middle_Click, aEvent);
4833 }
4834 }
4835
4836 // right menu click on linux should also pop up a context menu
4837 if (!StaticPrefs::ui_context_menus_after_mouseup() &&
4838 eventStatus.mApzStatus != nsEventStatus_eConsumeNoDefault) {
4839 DispatchContextMenuEventFromMouseEvent(domButton, aEvent, refPoint);
4840 }
4841}
4842
4843void nsWindow::OnButtonReleaseEvent(GdkEventButton* aEvent) {
4844 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)
;
4845
4846 SetLastMousePressEvent(nullptr);
4847
4848 if (!mGdkWindow) {
4849 return;
4850 }
4851
4852 if (mAspectResizer) {
4853 mAspectResizer = Nothing();
4854 return;
4855 }
4856
4857 if (mWindowShouldStartDragging) {
4858 mWindowShouldStartDragging = false;
4859 }
4860
4861 uint16_t domButton;
4862 switch (aEvent->button) {
4863 case 1:
4864 domButton = MouseButton::ePrimary;
4865 break;
4866 case 2:
4867 domButton = MouseButton::eMiddle;
4868 break;
4869 case 3:
4870 domButton = MouseButton::eSecondary;
4871 break;
4872 default:
4873 return;
4874 }
4875
4876 gButtonState &= ~ButtonMaskFromGDKButton(aEvent->button);
4877
4878 const auto refPoint = GetRefPoint(this, aEvent);
4879
4880 WidgetMouseEvent event(true, eMouseUp, this, WidgetMouseEvent::eReal);
4881 event.mButton = domButton;
4882 InitButtonEvent(event, aEvent, refPoint);
4883 gdouble pressure = 0;
4884 gdk_event_get_axis((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
4885 event.mPressure = pressure ? (float)pressure : (float)mLastMotionPressure;
4886
4887 // The mRefPoint is manipulated in DispatchInputEvent, we're saving it
4888 // to use it for the doubleclick position check.
4889 const LayoutDeviceIntPoint pos = event.mRefPoint;
4890
4891 InitPenEvent(event, (GdkEvent*)aEvent);
4892
4893 nsIWidget::ContentAndAPZEventStatus eventStatus = DispatchInputEvent(&event);
4894
4895 const bool defaultPrevented =
4896 eventStatus.mContentStatus == nsEventStatus_eConsumeNoDefault;
4897 // Check if mouse position in titlebar and doubleclick happened to
4898 // trigger defined action.
4899 if (!defaultPrevented && mDrawInTitlebar &&
4900 event.mButton == MouseButton::ePrimary && event.mClickCount == 2 &&
4901 mDraggableRegion.Contains(pos)) {
4902 DoTitlebarAction(nsXPLookAndFeel::TitlebarEvent::Double_Click, aEvent);
4903 }
4904 mLastMotionPressure = pressure;
4905
4906 // right menu click on linux should also pop up a context menu
4907 if (StaticPrefs::ui_context_menus_after_mouseup() &&
4908 eventStatus.mApzStatus != nsEventStatus_eConsumeNoDefault) {
4909 DispatchContextMenuEventFromMouseEvent(domButton, aEvent, refPoint);
4910 }
4911
4912 // Open window manager menu on PIP window to allow user
4913 // to place it on top / all workspaces.
4914 if (mAlwaysOnTop && aEvent->button == 3) {
4915 TryToShowNativeWindowMenu(aEvent);
4916 }
4917}
4918
4919void nsWindow::OnContainerFocusInEvent(GdkEventFocus* aEvent) {
4920 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)
;
4921
4922 // Unset the urgency hint, if possible
4923 GtkWidget* top_window = GetToplevelWidget();
4924 if (top_window && (gtk_widget_get_visible(top_window))) {
4925 SetUrgencyHint(top_window, false);
4926 }
4927
4928 // Return if being called within SetFocus because the focus manager
4929 // already knows that the window is active.
4930 if (gBlockActivateEvent) {
4931 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)
;
4932 return;
4933 }
4934
4935 // If keyboard input will be accepted, the focus manager will call
4936 // SetFocus to set the correct window.
4937 gFocusWindow = nullptr;
4938
4939 DispatchActivateEvent();
4940
4941 if (!gFocusWindow) {
4942 // We don't really have a window for dispatching key events, but
4943 // setting a non-nullptr value here prevents OnButtonPressEvent() from
4944 // dispatching an activation notification if the widget is already
4945 // active.
4946 gFocusWindow = this;
4947 }
4948
4949 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)
;
4950}
4951
4952void nsWindow::OnContainerFocusOutEvent(GdkEventFocus* aEvent) {
4953 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)
;
4954
4955 if (IsTopLevelWindowType()) {
4956 // Rollup menus when a window is focused out unless a drag is occurring.
4957 // This check is because drags grab the keyboard and cause a focus out on
4958 // versions of GTK before 2.18.
4959 const bool shouldRollupMenus = [&] {
4960 nsCOMPtr<nsIDragService> dragService =
4961 do_GetService("@mozilla.org/widget/dragservice;1");
4962 nsCOMPtr<nsIDragSession> dragSession =
4963 dragService->GetCurrentSession(this);
4964 if (!dragSession) {
4965 return true;
4966 }
4967 // We also roll up when a drag is from a different application
4968 nsCOMPtr<nsINode> sourceNode;
4969 dragSession->GetSourceNode(getter_AddRefs(sourceNode));
4970 return !sourceNode;
4971 }();
4972
4973 if (shouldRollupMenus) {
4974 RollupAllMenus();
4975 }
4976
4977 if (RefPtr pm = nsXULPopupManager::GetInstance()) {
4978 pm->RollupTooltips();
4979 }
4980 }
4981
4982 if (gFocusWindow) {
4983 RefPtr<nsWindow> kungFuDeathGrip = gFocusWindow;
4984 if (gFocusWindow->mIMContext) {
4985 gFocusWindow->mIMContext->OnBlurWindow(gFocusWindow);
4986 }
4987 gFocusWindow = nullptr;
4988 }
4989
4990 DispatchDeactivateEvent();
4991
4992 if (IsChromeWindowTitlebar()) {
4993 // DispatchDeactivateEvent() ultimately results in a call to
4994 // BrowsingContext::SetIsActiveBrowserWindow(), which resets
4995 // the state. We call UpdateMozWindowActive() to keep it in
4996 // sync with GDK_WINDOW_STATE_FOCUSED.
4997 UpdateMozWindowActive();
4998 }
4999
5000 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)
;
5001}
5002
5003bool nsWindow::DispatchCommandEvent(nsAtom* aCommand) {
5004 nsEventStatus status;
5005 WidgetCommandEvent appCommandEvent(true, aCommand, this);
5006 DispatchEvent(&appCommandEvent, status);
5007 return TRUE(!(0));
5008}
5009
5010bool nsWindow::DispatchContentCommandEvent(EventMessage aMsg) {
5011 nsEventStatus status;
5012 WidgetContentCommandEvent event(true, aMsg, this);
5013 DispatchEvent(&event, status);
5014 return TRUE(!(0));
5015}
5016
5017WidgetEventTime nsWindow::GetWidgetEventTime(guint32 aEventTime) {
5018 return WidgetEventTime(GetEventTimeStamp(aEventTime));
5019}
5020
5021TimeStamp nsWindow::GetEventTimeStamp(guint32 aEventTime) {
5022 if (MOZ_UNLIKELY(!mGdkWindow)(__builtin_expect(!!(!mGdkWindow), 0))) {
5023 // nsWindow has been Destroy()ed.
5024 return TimeStamp::Now();
5025 }
5026 if (aEventTime == 0) {
5027 // Some X11 and GDK events may be received with a time of 0 to indicate
5028 // that they are synthetic events. Some input method editors do this.
5029 // In this case too, just return the current timestamp.
5030 return TimeStamp::Now();
5031 }
5032
5033 TimeStamp eventTimeStamp;
5034
5035 if (GdkIsWaylandDisplay()) {
5036 // Wayland compositors use monotonic time to set timestamps.
5037 int64_t timestampTime = g_get_monotonic_time() / 1000;
5038 guint32 refTimeTruncated = guint32(timestampTime);
5039
5040 timestampTime -= refTimeTruncated - aEventTime;
5041 int64_t tick =
5042 BaseTimeDurationPlatformUtils::TicksFromMilliseconds(timestampTime);
5043 eventTimeStamp = TimeStamp::FromSystemTime(tick);
5044 } else {
5045#ifdef MOZ_X111
5046 CurrentX11TimeGetter* getCurrentTime = GetCurrentTimeGetter();
5047 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"
, 5048); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getCurrentTime"
") (" "Null current time getter despite having a window" ")"
); do { *((volatile int*)__null) = 5048; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5048 "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"
, 5048); AnnotateMozCrashReason("MOZ_ASSERT" "(" "getCurrentTime"
") (" "Null current time getter despite having a window" ")"
); do { *((volatile int*)__null) = 5048; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5049 eventTimeStamp =
5050 TimeConverter().GetTimeStampFromSystemTime(aEventTime, *getCurrentTime);
5051#endif
5052 }
5053 return eventTimeStamp;
5054}
5055
5056#ifdef MOZ_X111
5057mozilla::CurrentX11TimeGetter* nsWindow::GetCurrentTimeGetter() {
5058 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"
, 5058); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mGdkWindow"
") (" "Expected mGdkWindow to be set" ")"); do { *((volatile
int*)__null) = 5058; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
5059 if (MOZ_UNLIKELY(!mCurrentTimeGetter)(__builtin_expect(!!(!mCurrentTimeGetter), 0))) {
5060 mCurrentTimeGetter = MakeUnique<CurrentX11TimeGetter>(mGdkWindow);
5061 }
5062 return mCurrentTimeGetter.get();
5063}
5064#endif
5065
5066gboolean nsWindow::OnKeyPressEvent(GdkEventKey* aEvent) {
5067 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)
;
5068
5069 KeymapWrapper::HandleKeyPressEvent(this, aEvent);
5070 return TRUE(!(0));
5071}
5072
5073gboolean nsWindow::OnKeyReleaseEvent(GdkEventKey* aEvent) {
5074 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)
;
5075 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"
, 5075)
) {
5076 return FALSE(0);
5077 }
5078 return TRUE(!(0));
5079}
5080
5081void nsWindow::OnScrollEvent(GdkEventScroll* aEvent) {
5082 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)
;
5083
5084 // check to see if we should rollup
5085 if (CheckForRollup(aEvent->x_root, aEvent->y_root, true, false)) {
5086 return;
5087 }
5088
5089 // check for duplicate legacy scroll event, see GNOME bug 726878
5090 if (aEvent->direction != GDK_SCROLL_SMOOTH &&
5091 mLastScrollEventTime == aEvent->time) {
5092 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)
5093 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)
;
5094 return;
5095 }
5096 WidgetWheelEvent wheelEvent(true, eWheel, this);
5097 wheelEvent.mDeltaMode = dom::WheelEvent_Binding::DOM_DELTA_LINE;
5098 switch (aEvent->direction) {
5099 case GDK_SCROLL_SMOOTH: {
5100 // As of GTK 3.4, all directional scroll events are provided by
5101 // the GDK_SCROLL_SMOOTH direction on XInput2 and Wayland devices.
5102 mLastScrollEventTime = aEvent->time;
5103
5104 // Special handling for touchpads to support flings
5105 // (also known as kinetic/inertial/momentum scrolling)
5106 GdkDevice* device = gdk_event_get_source_device((GdkEvent*)aEvent);
5107 GdkInputSource source = gdk_device_get_source(device);
5108 if (source == GDK_SOURCE_TOUCHSCREEN || source == GDK_SOURCE_TOUCHPAD ||
5109 mCurrentSynthesizedTouchpadPan.mTouchpadGesturePhase.isSome()) {
5110 if (StaticPrefs::apz_gtk_pangesture_enabled() &&
5111 gtk_check_version(3, 20, 0) == nullptr) {
5112 static auto sGdkEventIsScrollStopEvent =
5113 (gboolean(*)(const GdkEvent*))dlsym(
5114 RTLD_DEFAULT((void *) 0), "gdk_event_is_scroll_stop_event");
5115
5116 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)
5117 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)
;
5118 auto eventType = PanGestureInput::PANGESTURE_PAN;
5119 if (sGdkEventIsScrollStopEvent((GdkEvent*)aEvent)) {
5120 eventType = PanGestureInput::PANGESTURE_END;
5121 mPanInProgress = false;
5122 } else if (!mPanInProgress) {
5123 eventType = PanGestureInput::PANGESTURE_START;
5124 mPanInProgress = true;
5125 } else if (mCurrentSynthesizedTouchpadPan.mTouchpadGesturePhase
5126 .isSome()) {
5127 switch (*mCurrentSynthesizedTouchpadPan.mTouchpadGesturePhase) {
5128 case PHASE_BEGIN:
5129 // we should never hit this because we'll hit the above case
5130 // before this.
5131 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"
, 5131); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " ")"); do { *((volatile int*)__null
) = 5131; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
5132 eventType = PanGestureInput::PANGESTURE_START;
5133 mPanInProgress = true;
5134 break;
5135 case PHASE_UPDATE:
5136 // nothing to do here, eventtype should already be set
5137 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"
, 5137); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPanInProgress"
")"); do { *((volatile int*)__null) = 5137; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5138 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"
, 5138); AnnotateMozCrashReason("MOZ_ASSERT" "(" "eventType == PanGestureInput::PANGESTURE_PAN"
")"); do { *((volatile int*)__null) = 5138; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5139 eventType = PanGestureInput::PANGESTURE_PAN;
5140 break;
5141 case PHASE_END:
5142 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"
, 5142); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPanInProgress"
")"); do { *((volatile int*)__null) = 5142; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5143 eventType = PanGestureInput::PANGESTURE_END;
5144 mPanInProgress = false;
5145 break;
5146 default:
5147 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"
, 5147); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " ")"); do { *((volatile int*)__null
) = 5147; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
5148 break;
5149 }
5150 }
5151
5152 mCurrentSynthesizedTouchpadPan.mTouchpadGesturePhase.reset();
5153
5154 const bool isPageMode =
5155#ifdef NIGHTLY_BUILD1
5156 StaticPrefs::apz_gtk_pangesture_delta_mode() == 1;
5157#else
5158 StaticPrefs::apz_gtk_pangesture_delta_mode() != 2;
5159#endif
5160 const double multiplier =
5161 isPageMode
5162 ? StaticPrefs::apz_gtk_pangesture_page_delta_mode_multiplier()
5163 : StaticPrefs::
5164 apz_gtk_pangesture_pixel_delta_mode_multiplier() *
5165 FractionalScaleFactor();
5166
5167 ScreenPoint deltas(float(aEvent->delta_x * multiplier),
5168 float(aEvent->delta_y * multiplier));
5169
5170 LayoutDeviceIntPoint touchPoint = GetRefPoint(this, aEvent);
5171 PanGestureInput panEvent(
5172 eventType, GetEventTimeStamp(aEvent->time),
5173 ScreenPoint(touchPoint.x, touchPoint.y), deltas,
5174 KeymapWrapper::ComputeKeyModifiers(aEvent->state));
5175 panEvent.mDeltaType = isPageMode ? PanGestureInput::PANDELTA_PAGE
5176 : PanGestureInput::PANDELTA_PIXEL;
5177 panEvent.mSimulateMomentum =
5178 StaticPrefs::apz_gtk_kinetic_scroll_enabled();
5179
5180 DispatchPanGesture(panEvent);
5181
5182 if (mCurrentSynthesizedTouchpadPan.mSavedObserver != 0) {
5183 mozilla::widget::AutoObserverNotifier::NotifySavedObserver(
5184 mCurrentSynthesizedTouchpadPan.mSavedObserver,
5185 "touchpadpanevent");
5186 mCurrentSynthesizedTouchpadPan.mSavedObserver = 0;
5187 }
5188
5189 return;
5190 }
5191
5192 // Older GTK doesn't support stop events, so we can't support fling
5193 wheelEvent.mScrollType = WidgetWheelEvent::SCROLL_ASYNCHRONOUSLY;
5194 }
5195
5196 // TODO - use a more appropriate scrolling unit than lines.
5197 // Multiply event deltas by 3 to emulate legacy behaviour.
5198 wheelEvent.mDeltaX = aEvent->delta_x * 3;
5199 wheelEvent.mDeltaY = aEvent->delta_y * 3;
5200 wheelEvent.mWheelTicksX = aEvent->delta_x;
5201 wheelEvent.mWheelTicksY = aEvent->delta_y;
5202 wheelEvent.mIsNoLineOrPageDelta = true;
5203
5204 break;
5205 }
5206 case GDK_SCROLL_UP:
5207 wheelEvent.mDeltaY = wheelEvent.mLineOrPageDeltaY = -3;
5208 wheelEvent.mWheelTicksY = -1;
5209 break;
5210 case GDK_SCROLL_DOWN:
5211 wheelEvent.mDeltaY = wheelEvent.mLineOrPageDeltaY = 3;
5212 wheelEvent.mWheelTicksY = 1;
5213 break;
5214 case GDK_SCROLL_LEFT:
5215 wheelEvent.mDeltaX = wheelEvent.mLineOrPageDeltaX = -1;
5216 wheelEvent.mWheelTicksX = -1;
5217 break;
5218 case GDK_SCROLL_RIGHT:
5219 wheelEvent.mDeltaX = wheelEvent.mLineOrPageDeltaX = 1;
5220 wheelEvent.mWheelTicksX = 1;
5221 break;
5222 }
5223
5224 wheelEvent.mRefPoint = GetRefPoint(this, aEvent);
5225
5226 KeymapWrapper::InitInputEvent(wheelEvent, aEvent->state);
5227
5228 wheelEvent.AssignEventTime(GetWidgetEventTime(aEvent->time));
5229
5230 DispatchInputEvent(&wheelEvent);
5231}
5232
5233void nsWindow::DispatchPanGesture(PanGestureInput& aPanInput) {
5234 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"
, 5234); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 5234; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5235
5236 if (mSwipeTracker) {
5237 // Give the swipe tracker a first pass at the event. If a new pan gesture
5238 // has been started since the beginning of the swipe, the swipe tracker
5239 // will know to ignore the event.
5240 nsEventStatus status = mSwipeTracker->ProcessEvent(aPanInput);
5241 if (status == nsEventStatus_eConsumeNoDefault) {
5242 return;
5243 }
5244 }
5245
5246 APZEventResult result;
5247 if (mAPZC) {
5248 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"
, 5248); AnnotateMozCrashReason("MOZ_ASSERT" "(" "APZThreadUtils::IsControllerThread()"
")"); do { *((volatile int*)__null) = 5248; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5249
5250 result = mAPZC->InputBridge()->ReceiveInputEvent(aPanInput);
5251 if (result.GetStatus() == nsEventStatus_eConsumeNoDefault) {
5252 return;
5253 }
5254 }
5255
5256 WidgetWheelEvent event = aPanInput.ToWidgetEvent(this);
5257 if (!mAPZC) {
5258 if (MayStartSwipeForNonAPZ(aPanInput)) {
5259 return;
5260 }
5261 } else {
5262 event = MayStartSwipeForAPZ(aPanInput, result);
5263 }
5264
5265 ProcessUntransformedAPZEvent(&event, result);
5266}
5267
5268void nsWindow::OnVisibilityNotifyEvent(GdkVisibilityState aState) {
5269 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)
;
5270 auto state = aState == GDK_VISIBILITY_FULLY_OBSCURED
5271 ? OcclusionState::OCCLUDED
5272 : OcclusionState::UNKNOWN;
5273 NotifyOcclusionState(state);
5274}
5275
5276void nsWindow::OnWindowStateEvent(GtkWidget* aWidget,
5277 GdkEventWindowState* aEvent) {
5278 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)
5279 "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)
5280 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)
;
5281
5282 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; }))))
) {
5283 // This event is notifying the container widget of changes to the
5284 // toplevel window. Just detect changes affecting whether windows are
5285 // viewable.
5286 //
5287 // (A visibility notify event is sent to each window that becomes
5288 // viewable when the toplevel is mapped, but we can't rely on that for
5289 // setting mHasMappedToplevel because these toplevel window state
5290 // events are asynchronous. The windows in the hierarchy now may not
5291 // be the same windows as when the toplevel was mapped, so they may
5292 // not get VisibilityNotify events.)
5293 bool mapped = !(aEvent->new_window_state &
5294 (GDK_WINDOW_STATE_ICONIFIED | GDK_WINDOW_STATE_WITHDRAWN));
5295 SetHasMappedToplevel(mapped);
5296 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)
;
5297 return;
5298 }
5299 // else the widget is a shell widget.
5300
5301 // The block below is a bit evil.
5302 //
5303 // When a window is resized before it is shown, gtk_window_resize() delays
5304 // resizes until the window is shown. If gtk_window_state_event() sees a
5305 // GDK_WINDOW_STATE_MAXIMIZED change [1] before the window is shown, then
5306 // gtk_window_compute_configure_request_size() ignores the values from the
5307 // resize [2]. See bug 1449166 for an example of how this could happen.
5308 //
5309 // [1] https://gitlab.gnome.org/GNOME/gtk/blob/3.22.30/gtk/gtkwindow.c#L7967
5310 // [2] https://gitlab.gnome.org/GNOME/gtk/blob/3.22.30/gtk/gtkwindow.c#L9377
5311 //
5312 // In order to provide a sensible size for the window when the user exits
5313 // maximized state, we hide the GDK_WINDOW_STATE_MAXIMIZED change from
5314 // gtk_window_state_event() so as to trick GTK into using the values from
5315 // gtk_window_resize() in its configure request.
5316 //
5317 // We instead notify gtk_window_state_event() of the maximized state change
5318 // once the window is shown.
5319 //
5320 // See https://gitlab.gnome.org/GNOME/gtk/issues/1044
5321 //
5322 // This may be fixed in Gtk 3.24+ but it's still live and kicking
5323 // (Bug 1791779).
5324 if (!mIsShown) {
5325 aEvent->changed_mask = static_cast<GdkWindowState>(
5326 aEvent->changed_mask & ~GDK_WINDOW_STATE_MAXIMIZED);
5327 } else if (aEvent->changed_mask & GDK_WINDOW_STATE_WITHDRAWN &&
5328 aEvent->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
5329 aEvent->changed_mask = static_cast<GdkWindowState>(
5330 aEvent->changed_mask | GDK_WINDOW_STATE_MAXIMIZED);
5331 }
5332
5333 // This is a workaround for https://gitlab.gnome.org/GNOME/gtk/issues/1395
5334 // Gtk+ controls window active appearance by window-state-event signal.
5335 if (IsChromeWindowTitlebar() &&
5336 (aEvent->changed_mask & GDK_WINDOW_STATE_FOCUSED)) {
5337 // Emulate what Gtk+ does at gtk_window_state_event().
5338 // We can't check GTK_STATE_FLAG_BACKDROP directly as it's set by Gtk+
5339 // *after* this window-state-event handler.
5340 mTitlebarBackdropState =
5341 !(aEvent->new_window_state & GDK_WINDOW_STATE_FOCUSED);
5342
5343 // keep IsActiveBrowserWindow in sync with GDK_WINDOW_STATE_FOCUSED
5344 UpdateMozWindowActive();
5345
5346 ForceTitlebarRedraw();
5347 }
5348
5349 // We don't care about anything but changes in the maximized/icon/fullscreen
5350 // states but we need a workaround for bug in Wayland:
5351 // https://gitlab.gnome.org/GNOME/gtk/issues/67
5352 // Under wayland the gtk_window_iconify implementation does NOT synthetize
5353 // window_state_event where the GDK_WINDOW_STATE_ICONIFIED is set.
5354 // During restore we won't get aEvent->changed_mask with
5355 // the GDK_WINDOW_STATE_ICONIFIED so to detect that change we use the stored
5356 // mSizeMode and obtaining a focus.
5357 bool waylandWasIconified =
5358 (GdkIsWaylandDisplay() &&
5359 aEvent->changed_mask & GDK_WINDOW_STATE_FOCUSED &&
5360 aEvent->new_window_state & GDK_WINDOW_STATE_FOCUSED &&
5361 mSizeMode == nsSizeMode_Minimized);
5362 if (!waylandWasIconified &&
5363 (aEvent->changed_mask &
5364 (GDK_WINDOW_STATE_ICONIFIED | GDK_WINDOW_STATE_MAXIMIZED |
5365 GDK_WINDOW_STATE_TILED | GDK_WINDOW_STATE_FULLSCREEN)) == 0) {
5366 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)
;
5367 return;
5368 }
5369
5370 auto oldSizeMode = mSizeMode;
5371 if (aEvent->new_window_state & GDK_WINDOW_STATE_ICONIFIED) {
5372 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)
;
5373 mSizeMode = nsSizeMode_Minimized;
5374#ifdef ACCESSIBILITY1
5375 DispatchMinimizeEventAccessible();
5376#endif // ACCESSIBILITY
5377 } else if (aEvent->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) {
5378 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)
;
5379 mSizeMode = nsSizeMode_Fullscreen;
5380 } else if (aEvent->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
5381 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)
;
5382 mSizeMode = nsSizeMode_Maximized;
5383#ifdef ACCESSIBILITY1
5384 DispatchMaximizeEventAccessible();
5385#endif // ACCESSIBILITY
5386 } else {
5387 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)
;
5388 mSizeMode = nsSizeMode_Normal;
5389#ifdef ACCESSIBILITY1
5390 DispatchRestoreEventAccessible();
5391#endif // ACCESSIBILITY
5392 }
5393
5394 mIsTiled = aEvent->new_window_state & GDK_WINDOW_STATE_TILED;
5395 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)
;
5396
5397 if (mWidgetListener && mSizeMode != oldSizeMode) {
5398 mWidgetListener->SizeModeChanged(mSizeMode);
5399 }
5400
5401 if (mDrawInTitlebar && mTransparencyBitmapForTitlebar) {
5402 if (mSizeMode == nsSizeMode_Normal && !mIsTiled) {
5403 UpdateTitlebarTransparencyBitmap();
5404 } else {
5405 ClearTransparencyBitmap();
5406 }
5407 }
5408}
5409
5410void nsWindow::OnDPIChanged() {
5411 // Update menu's font size etc.
5412 // This affects style / layout because it affects system font sizes.
5413 if (mWidgetListener) {
5414 if (PresShell* presShell = mWidgetListener->GetPresShell()) {
5415 presShell->BackingScaleFactorChanged();
5416 }
5417 }
5418 NotifyAPZOfDPIChange();
5419}
5420
5421void nsWindow::OnCheckResize() { mPendingConfigures++; }
5422
5423void nsWindow::OnCompositedChanged() {
5424 // Update CSD after the change in alpha visibility. This only affects
5425 // system metrics, not other theme shenanigans.
5426 NotifyThemeChanged(ThemeChangeKind::MediaQueriesOnly);
5427 mCompositedScreen = gdk_screen_is_composited(gdk_screen_get_default());
5428}
5429
5430void nsWindow::OnScaleChanged(bool aNotify) {
5431 if (!IsTopLevelWindowType()) {
5432 return;
5433 }
5434 if (!mGdkWindow) {
5435 return; // We'll get there again when we configure the window.
5436 }
5437 gint newCeiled = gdk_window_get_scale_factor(mGdkWindow);
5438 double newFractional = [&] {
5439#ifdef MOZ_WAYLAND1
5440 if (GdkIsWaylandDisplay()) {
5441 return moz_container_wayland_get_fractional_scale(mContainer);
5442 }
5443#endif
5444 return 0.0;
5445 }();
5446
5447 if (mCeiledScaleFactor == newCeiled &&
5448 mFractionalScaleFactor == newFractional) {
5449 return;
5450 }
5451
5452 NotifyAPZOfDPIChange();
5453
5454 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)
5455 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)
;
5456
5457 mCeiledScaleFactor = newCeiled;
5458 mFractionalScaleFactor = newFractional;
5459
5460 if (!aNotify) {
5461 return;
5462 }
5463
5464 // We pause compositor to avoid rendering of obsoleted remote content which
5465 // produces flickering.
5466 // Re-enable compositor again when remote content is updated or timeout
5467 // happens.
5468 PauseCompositorFlickering();
5469
5470 GtkAllocation allocation;
5471 gtk_widget_get_allocation(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))), &allocation);
5472 LayoutDeviceIntSize size = GdkRectToDevicePixels(allocation).Size();
5473 mBounds.SizeTo(size);
5474 // Check mBounds size
5475 if (mCompositorSession &&
5476 !wr::WindowSizeSanityCheck(mBounds.width, mBounds.height)) {
5477 gfxCriticalNoteOncestatic mozilla::gfx::CriticalLog sOnceAtLine5477 = mozilla::gfx
::CriticalLog(mozilla::gfx::CriticalLog::DefaultOptions(false
))
<< "Invalid mBounds in OnScaleChanged " << mBounds;
5478 }
5479
5480 if (mWidgetListener) {
5481 if (PresShell* presShell = mWidgetListener->GetPresShell()) {
5482 presShell->BackingScaleFactorChanged();
5483 }
5484 }
5485
5486 DispatchResized();
5487
5488 if (mCompositorWidgetDelegate) {
5489 mCompositorWidgetDelegate->NotifyClientSizeChanged(GetClientSize());
5490 }
5491
5492 if (mCursor.IsCustom()) {
5493 mUpdateCursor = true;
5494 SetCursor(Cursor{mCursor});
5495 }
5496}
5497
5498void nsWindow::DispatchDragEvent(EventMessage aMsg,
5499 const LayoutDeviceIntPoint& aRefPoint,
5500 guint aTime) {
5501 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)
;
5502 WidgetDragEvent event(true, aMsg, this);
5503
5504 InitDragEvent(event);
5505
5506 event.mRefPoint = aRefPoint;
5507 event.AssignEventTime(GetWidgetEventTime(aTime));
5508
5509 DispatchInputEvent(&event);
5510}
5511
5512void nsWindow::OnDragDataReceivedEvent(GtkWidget* aWidget,
5513 GdkDragContext* aDragContext, gint aX,
5514 gint aY,
5515 GtkSelectionData* aSelectionData,
5516 guint aInfo, guint aTime,
5517 gpointer aData) {
5518 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)
;
5519
5520 RefPtr<nsDragService> dragService = nsDragService::GetInstance();
5521 nsDragSession* dragSession =
5522 static_cast<nsDragSession*>(dragService->GetCurrentSession(this));
5523 if (dragSession) {
5524 nsDragSession::AutoEventLoop loop(dragSession);
5525 dragSession->TargetDataReceived(aWidget, aDragContext, aX, aY,
5526 aSelectionData, aInfo, aTime);
5527 }
5528}
5529
5530nsWindow* nsWindow::GetTransientForWindowIfPopup() {
5531 if (mWindowType != WindowType::Popup) {
5532 return nullptr;
5533 }
5534 GtkWindow* toplevel = gtk_window_get_transient_for(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
5535 if (toplevel) {
5536 return get_window_for_gtk_widget(GTK_WIDGET(toplevel)((((GtkWidget*) (void *) ((toplevel))))));
5537 }
5538 return nullptr;
5539}
5540
5541bool nsWindow::IsHandlingTouchSequence(GdkEventSequence* aSequence) {
5542 return mHandleTouchEvent && mTouches.Contains(aSequence);
5543}
5544
5545gboolean nsWindow::OnTouchpadPinchEvent(GdkEventTouchpadPinch* aEvent) {
5546 if (!StaticPrefs::apz_gtk_touchpad_pinch_enabled()) {
5547 return TRUE(!(0));
5548 }
5549 // Do not respond to pinch gestures involving more than two fingers
5550 // unless specifically preffed on. These are sometimes hooked up to other
5551 // actions at the desktop environment level and having the browser also
5552 // pinch can be undesirable.
5553 if (aEvent->n_fingers > 2 &&
5554 !StaticPrefs::apz_gtk_touchpad_pinch_three_fingers_enabled()) {
5555 return FALSE(0);
5556 }
5557 auto pinchGestureType = PinchGestureInput::PINCHGESTURE_SCALE;
5558 ScreenCoord currentSpan;
5559 ScreenCoord previousSpan;
5560
5561 switch (aEvent->phase) {
5562 case GDK_TOUCHPAD_GESTURE_PHASE_BEGIN:
5563 pinchGestureType = PinchGestureInput::PINCHGESTURE_START;
5564 currentSpan = aEvent->scale;
5565 mCurrentTouchpadFocus = ViewAs<ScreenPixel>(
5566 GetRefPoint(this, aEvent),
5567 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
5568
5569 // Assign PreviousSpan --> 0.999 to make mDeltaY field of the
5570 // WidgetWheelEvent that this PinchGestureInput event will be converted
5571 // to not equal Zero as our discussion because we observed that the
5572 // scale of the PHASE_BEGIN event is 1.
5573 previousSpan = 0.999;
5574 break;
5575
5576 case GDK_TOUCHPAD_GESTURE_PHASE_UPDATE:
5577 pinchGestureType = PinchGestureInput::PINCHGESTURE_SCALE;
5578 mCurrentTouchpadFocus += ScreenPoint(aEvent->dx, aEvent->dy);
5579 if (aEvent->scale == mLastPinchEventSpan) {
5580 return FALSE(0);
5581 }
5582 currentSpan = aEvent->scale;
5583 previousSpan = mLastPinchEventSpan;
5584 break;
5585
5586 case GDK_TOUCHPAD_GESTURE_PHASE_END:
5587 pinchGestureType = PinchGestureInput::PINCHGESTURE_END;
5588 currentSpan = aEvent->scale;
5589 previousSpan = mLastPinchEventSpan;
5590 break;
5591
5592 default:
5593 return FALSE(0);
5594 }
5595
5596 PinchGestureInput event(
5597 pinchGestureType, PinchGestureInput::TRACKPAD,
5598 GetEventTimeStamp(aEvent->time), ExternalPoint(0, 0),
5599 mCurrentTouchpadFocus,
5600 100.0 * ((aEvent->phase == GDK_TOUCHPAD_GESTURE_PHASE_END)
5601 ? ScreenCoord(1.f)
5602 : currentSpan),
5603 100.0 * ((aEvent->phase == GDK_TOUCHPAD_GESTURE_PHASE_END)
5604 ? ScreenCoord(1.f)
5605 : previousSpan),
5606 KeymapWrapper::ComputeKeyModifiers(aEvent->state));
5607
5608 if (!event.SetLineOrPageDeltaY(this)) {
5609 return FALSE(0);
5610 }
5611
5612 mLastPinchEventSpan = aEvent->scale;
5613 DispatchPinchGestureInput(event);
5614 return TRUE(!(0));
5615}
5616
5617gboolean nsWindow::OnTouchEvent(GdkEventTouch* aEvent) {
5618 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)
;
5619 if (!mHandleTouchEvent) {
5620 // If a popup window was spawned (e.g. as the result of a long-press)
5621 // and touch events got diverted to that window within a touch sequence,
5622 // ensure the touch event gets sent to the original window instead. We
5623 // keep the checks here very conservative so that we only redirect
5624 // events in this specific scenario.
5625 nsWindow* targetWindow = GetTransientForWindowIfPopup();
5626 if (targetWindow &&
5627 targetWindow->IsHandlingTouchSequence(aEvent->sequence)) {
5628 return targetWindow->OnTouchEvent(aEvent);
5629 }
5630
5631 return FALSE(0);
5632 }
5633
5634 EventMessage msg;
5635 switch (aEvent->type) {
5636 case GDK_TOUCH_BEGIN:
5637 // check to see if we should rollup
5638 if (CheckForRollup(aEvent->x_root, aEvent->y_root, false, false)) {
5639 return FALSE(0);
5640 }
5641 msg = eTouchStart;
5642 break;
5643 case GDK_TOUCH_UPDATE:
5644 msg = eTouchMove;
5645 // Start dragging when motion events happens in the dragging area
5646 if (mWindowShouldStartDragging) {
5647 mWindowShouldStartDragging = false;
5648 if (mGdkWindow) {
5649 GdkWindow* gdk_window = gdk_window_get_toplevel(mGdkWindow);
5650 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"
, 5651); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gdk_window"
") (" "gdk_window_get_toplevel should not return null" ")");
do { *((volatile int*)__null) = 5651; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
5651 "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"
, 5651); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gdk_window"
") (" "gdk_window_get_toplevel should not return null" ")");
do { *((volatile int*)__null) = 5651; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5652
5653 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)
;
5654 gdk_window_begin_move_drag(gdk_window, 1, aEvent->x_root,
5655 aEvent->y_root, aEvent->time);
5656
5657 // Cancel the event sequence. gdk will steal all subsequent events
5658 // (including TOUCH_END).
5659 msg = eTouchCancel;
5660 }
5661 }
5662 break;
5663 case GDK_TOUCH_END:
5664 msg = eTouchEnd;
5665 if (mWindowShouldStartDragging) {
5666 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)
;
5667 mWindowShouldStartDragging = false;
5668 }
5669 break;
5670 case GDK_TOUCH_CANCEL:
5671 msg = eTouchCancel;
5672 break;
5673 default:
5674 return FALSE(0);
5675 }
5676
5677 const LayoutDeviceIntPoint touchPoint = GetRefPoint(this, aEvent);
5678
5679 int32_t id;
5680 RefPtr<dom::Touch> touch;
5681 if (mTouches.Remove(aEvent->sequence, getter_AddRefs(touch))) {
5682 id = touch->mIdentifier;
5683 } else {
5684 id = ++gLastTouchID & 0x7FFFFFFF;
5685 }
5686
5687 touch =
5688 new dom::Touch(id, touchPoint, LayoutDeviceIntPoint(1, 1), 0.0f, 0.0f);
5689
5690 WidgetTouchEvent event(true, msg, this);
5691 KeymapWrapper::InitInputEvent(event, aEvent->state);
5692
5693 if (msg == eTouchStart || msg == eTouchMove) {
5694 mTouches.InsertOrUpdate(aEvent->sequence, std::move(touch));
5695 // add all touch points to event object
5696 for (const auto& data : mTouches.Values()) {
5697 event.mTouches.AppendElement(new dom::Touch(*data));
5698 }
5699 } else if (msg == eTouchEnd || msg == eTouchCancel) {
5700 *event.mTouches.AppendElement() = std::move(touch);
5701 }
5702
5703 nsIWidget::ContentAndAPZEventStatus eventStatus = DispatchInputEvent(&event);
5704
5705 // There's a chance that we are in drag area and the event is not consumed
5706 // by something on it.
5707 if (msg == eTouchStart && mDraggableRegion.Contains(touchPoint) &&
5708 eventStatus.mApzStatus != nsEventStatus_eConsumeNoDefault) {
5709 mWindowShouldStartDragging = true;
5710 }
5711 return TRUE(!(0));
5712}
5713
5714// Return true if toplevel window is transparent.
5715// It's transparent when we're running on composited screens
5716// and we can draw main window without system titlebar.
5717bool nsWindow::IsToplevelWindowTransparent() {
5718 static bool transparencyConfigured = false;
5719
5720 if (!transparencyConfigured) {
5721 if (gdk_screen_is_composited(gdk_screen_get_default())) {
5722 // Some Gtk+ themes use non-rectangular toplevel windows. To fully
5723 // support such themes we need to make toplevel window transparent
5724 // with ARGB visual.
5725 // It may cause performanance issue so make it configurable
5726 // and enable it by default for selected window managers.
5727 if (Preferences::HasUserValue("mozilla.widget.use-argb-visuals")) {
5728 // argb visual is explicitly required so use it
5729 sTransparentMainWindow =
5730 Preferences::GetBool("mozilla.widget.use-argb-visuals");
5731 } else {
5732 // Enable transparent toplevel window if we can draw main window
5733 // without system titlebar as Gtk+ themes use titlebar round corners.
5734 sTransparentMainWindow =
5735 GetSystemGtkWindowDecoration() != GTK_DECORATION_NONE;
5736 }
5737 }
5738 transparencyConfigured = true;
5739 }
5740
5741 return sTransparentMainWindow;
5742}
5743
5744#ifdef MOZ_X111
5745// Configure GL visual on X11.
5746bool nsWindow::ConfigureX11GLVisual() {
5747 auto* screen = gtk_widget_get_screen(mShell);
5748 int visualId = 0;
5749 bool haveVisual = false;
5750
5751 if (gfxVars::UseEGL()) {
5752 haveVisual = GLContextEGL::FindVisual(&visualId);
5753 }
5754
5755 // We are on GLX or use it as a fallback on Mesa, see
5756 // https://gitlab.freedesktop.org/mesa/mesa/-/issues/149
5757 if (!haveVisual) {
5758 auto* display = GDK_DISPLAY_XDISPLAY(gtk_widget_get_display(mShell))(gdk_x11_display_get_xdisplay (gtk_widget_get_display(mShell)
))
;
5759 int screenNumber = GDK_SCREEN_XNUMBER(screen)(gdk_x11_screen_get_screen_number (screen));
5760 haveVisual = GLContextGLX::FindVisual(display, screenNumber, &visualId);
5761 }
5762
5763 GdkVisual* gdkVisual = nullptr;
5764 if (haveVisual) {
5765 // If we're using CSD, rendering will go through mContainer, but
5766 // it will inherit this visual as it is a child of mShell.
5767 gdkVisual = gdk_x11_screen_lookup_visual(screen, visualId);
5768 }
5769 if (!gdkVisual) {
5770 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"
, 5770)
;
5771 // We try to use a fallback alpha visual
5772 GdkScreen* screen = gtk_widget_get_screen(mShell);
5773 gdkVisual = gdk_screen_get_rgba_visual(screen);
5774 }
5775 if (gdkVisual) {
5776 gtk_widget_set_visual(mShell, gdkVisual);
5777 mHasAlphaVisual = true;
5778 return true;
5779 }
5780
5781 return false;
5782}
5783#endif
5784
5785nsAutoCString nsWindow::GetFrameTag() const {
5786 if (nsIFrame* frame = GetFrame()) {
5787#ifdef DEBUG_FRAME_DUMP1
5788 return frame->ListTag();
5789#else
5790 nsAutoCString buf;
5791 buf.AppendPrintf("Frame(%p)", frame);
5792 if (nsIContent* content = frame->GetContent()) {
5793 buf.Append(' ');
5794 AppendUTF16toUTF8(content->NodeName(), buf);
5795 }
5796 return buf;
5797#endif
5798 }
5799 return nsAutoCString("(no frame)");
5800}
5801
5802nsCString nsWindow::GetPopupTypeName() {
5803 switch (mPopupType) {
5804 case PopupType::Menu:
5805 return nsCString("Menu");
5806 case PopupType::Tooltip:
5807 return nsCString("Tooltip");
5808 case PopupType::Panel:
5809 return nsCString("Panel/Utility");
5810 default:
5811 return nsCString("Unknown");
5812 }
5813}
5814
5815// Disables all rendering of GtkWidget from Gtk side.
5816// We do our best to persuade Gtk/Gdk to ignore all painting
5817// to the widget.
5818static void GtkWidgetDisableUpdates(GtkWidget* aWidget) {
5819 // Clear exposure mask - it disabled synthesized events.
5820 GdkWindow* window = gtk_widget_get_window(aWidget);
5821 if (!window) {
5822 return;
5823 }
5824 gdk_window_set_events(window, (GdkEventMask)(gdk_window_get_events(window) &
5825 (~GDK_EXPOSURE_MASK)));
5826
5827 // Remove before/after paint handles from frame clock.
5828 // It disables widget content updates.
5829 GdkFrameClock* frame_clock = gdk_window_get_frame_clock(window);
5830 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))
;
5831}
5832
5833Window nsWindow::GetX11Window() {
5834#ifdef MOZ_X111
5835 if (GdkIsX11Display()) {
5836 return mGdkWindow ? gdk_x11_window_get_xid(mGdkWindow) : X11None0L;
5837 }
5838#endif
5839 return (Window) nullptr;
5840}
5841
5842void nsWindow::EnsureGdkWindow() {
5843 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"
, 5843); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mIsMapped"
")"); do { *((volatile int*)__null) = 5843; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5844 if (!mGdkWindow) {
5845 mGdkWindow = gtk_widget_get_window(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))));
5846 g_object_set_data(G_OBJECT(mGdkWindow)((((GObject*) (void *) ((mGdkWindow))))), "nsWindow", this);
5847 }
5848}
5849
5850bool nsWindow::GetShapedState() {
5851 return mIsTransparent && !mHasAlphaVisual && !mTransparencyBitmapForTitlebar;
5852}
5853
5854void nsWindow::ConfigureCompositor() {
5855 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"
, 5855); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mIsMapped"
")"); do { *((volatile int*)__null) = 5855; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5856 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"
, 5856); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mCompositorState == COMPOSITOR_ENABLED"
")"); do { *((volatile int*)__null) = 5856; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5857
5858 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)
;
5859 auto startCompositing = [self = RefPtr{this}, this]() -> void {
5860 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)
5861 "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)
;
5862
5863 // too late
5864 if (mIsDestroyed || !mIsMapped) {
5865 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)
5866 !!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)
;
5867 return;
5868 }
5869 // Compositor will be resumed later by ResumeCompositorFlickering().
5870 if (mCompositorState == COMPOSITOR_PAUSED_FLICKERING) {
5871 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)
;
5872 return;
5873 }
5874 // Compositor will be resumed at nsWindow::SetCompositorWidgetDelegate().
5875 if (!mCompositorWidgetDelegate) {
5876 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)
;
5877 return;
5878 }
5879
5880 ResumeCompositorImpl();
5881 };
5882
5883 if (GdkIsWaylandDisplay()) {
5884#ifdef MOZ_WAYLAND1
5885 moz_container_wayland_add_or_fire_initial_draw_callback(mContainer,
5886 startCompositing);
5887#endif
5888 } else {
5889 startCompositing();
5890 }
5891}
5892
5893nsresult nsWindow::Create(nsIWidget* aParent, nsNativeWidget aNativeParent,
5894 const LayoutDeviceIntRect& aRect,
5895 widget::InitData* aInitData) {
5896 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)
;
5897
5898 // only set the base parent if we're going to be a dialog or a
5899 // toplevel
5900 nsIWidget* baseParent =
5901 aInitData && (aInitData->mWindowType == WindowType::Dialog ||
5902 aInitData->mWindowType == WindowType::TopLevel ||
5903 aInitData->mWindowType == WindowType::Invisible)
5904 ? nullptr
5905 : aParent;
5906
5907#ifdef ACCESSIBILITY1
5908 // Send a DBus message to check whether a11y is enabled
5909 a11y::PreInit();
5910#endif
5911
5912#ifdef MOZ_WAYLAND1
5913 // Ensure that KeymapWrapper is created on Wayland as we need it for
5914 // keyboard focus tracking.
5915 if (GdkIsWaylandDisplay()) {
5916 KeymapWrapper::EnsureInstance();
5917 }
5918#endif
5919
5920 // Ensure that the toolkit is created.
5921 nsGTKToolkit::GetToolkit();
5922
5923 // initialize all the common bits of this class
5924 BaseCreate(baseParent, aInitData);
5925
5926 // and do our common creation
5927 mParent = aParent;
5928 // save our bounds
5929 mBounds = aRect;
5930 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)
5931 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)
;
5932
5933 ConstrainSize(&mBounds.width, &mBounds.height);
5934 mLastSizeRequest = mBounds.Size();
5935
5936 bool popupNeedsAlphaVisual = mWindowType == WindowType::Popup &&
5937 (aInitData && aInitData->mTransparencyMode ==
5938 TransparencyMode::Transparent);
5939
5940 // Figure out our parent window - only used for WindowType::Child
5941 nsWindow* parentnsWindow = nullptr;
5942
5943 if (aParent) {
5944 parentnsWindow = static_cast<nsWindow*>(aParent);
5945 } 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; }))))
) {
5946 parentnsWindow = get_window_for_gdk_window(GDK_WINDOW(aNativeParent)((((GdkWindow*) (void *) ((aNativeParent))))));
5947 if (!parentnsWindow) {
5948 return NS_ERROR_FAILURE;
5949 }
5950 }
5951
5952 if (mWindowType == WindowType::Child) {
5953 // We don't support WindowType::Child directly but emulate it by popup
5954 // windows.
5955 mWindowType = WindowType::Popup;
5956 if (!parentnsWindow) {
5957 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; }))))
) {
5958 parentnsWindow = get_window_for_gtk_widget(GTK_WIDGET(aNativeParent)((((GtkWidget*) (void *) ((aNativeParent))))));
5959 }
5960 }
5961 mIsChildWindow = true;
5962 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)
;
5963 }
5964
5965 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"
, 5965); AnnotateMozCrashReason("MOZ_ASSERT" "(" "parentnsWindow"
")"); do { *((volatile int*)__null) = 5965; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); } } while (
false)
;
5966
5967 if (mWindowType != WindowType::Dialog && mWindowType != WindowType::Popup &&
5968 mWindowType != WindowType::TopLevel &&
5969 mWindowType != WindowType::Invisible) {
5970 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"
, 5970); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Unexpected eWindowType" ")"); do
{ *((volatile int*)__null) = 5970; __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
5971 return NS_ERROR_FAILURE;
5972 }
5973
5974 mAlwaysOnTop = aInitData && aInitData->mAlwaysOnTop;
5975 // mNoAutoHide seems to be always false here.
5976 // The mNoAutoHide state is set later on nsMenuPopupFrame level
5977 // and can be changed so we use WaylandPopupIsPermanent() to get
5978 // recent popup config (Bug 1728952).
5979 mNoAutoHide = aInitData && aInitData->mNoAutoHide;
5980 mIsAlert = aInitData && aInitData->mIsAlert;
5981
5982 // Popups that are not noautohide are only temporary. The are used
5983 // for menus and the like and disappear when another window is used.
5984 // For most popups, use the standard GtkWindowType GTK_WINDOW_POPUP,
5985 // which will use a Window with the override-redirect attribute
5986 // (for temporary windows).
5987 // For long-lived windows, their stacking order is managed by the
5988 // window manager, as indicated by GTK_WINDOW_TOPLEVEL.
5989 // For Wayland we have to always use GTK_WINDOW_POPUP to control
5990 // popup window position.
5991 GtkWindowType type = GTK_WINDOW_TOPLEVEL;
5992 if (mWindowType == WindowType::Popup) {
5993 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"
, 5993); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aInitData" ")"
); do { *((volatile int*)__null) = 5993; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
5994 type = GTK_WINDOW_POPUP;
5995 if (GdkIsX11Display() && mNoAutoHide) {
5996 type = GTK_WINDOW_TOPLEVEL;
5997 }
5998 }
5999 mShell = gtk_window_new(type);
6000
6001 // It is important that this happens before the realize() call below, so that
6002 // we don't get bogus CSD margins on Wayland, see bug 1794577.
6003 mUndecorated = IsAlwaysUndecoratedWindow();
6004 if (mUndecorated) {
6005 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)
;
6006 gtk_window_set_titlebar(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), gtk_fixed_new());
6007 gtk_window_set_decorated(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), false);
6008 }
6009
6010 // Ensure gfxPlatform is initialized, since that is what initializes
6011 // gfxVars, used below.
6012 Unused << gfxPlatform::GetPlatform();
6013
6014 if (IsTopLevelWindowType()) {
6015 mGtkWindowDecoration = GetSystemGtkWindowDecoration();
6016 // Inherit initial scale from our parent, or use the default monitor scale
6017 // otherwise.
6018 mCeiledScaleFactor = parentnsWindow
6019 ? int32_t(parentnsWindow->mCeiledScaleFactor)
6020 : ScreenHelperGTK::GetGTKMonitorScaleFactor();
6021 }
6022
6023 // Don't use transparency for PictureInPicture windows.
6024 bool toplevelNeedsAlphaVisual = false;
6025 if (mWindowType == WindowType::TopLevel && !mIsPIPWindow) {
6026 toplevelNeedsAlphaVisual = IsToplevelWindowTransparent();
6027 }
6028
6029 bool isGLVisualSet = false;
6030 mIsAccelerated = ComputeShouldAccelerate();
6031#ifdef MOZ_X111
6032 if (GdkIsX11Display() && mIsAccelerated) {
6033 isGLVisualSet = ConfigureX11GLVisual();
6034 }
6035#endif
6036 if (!isGLVisualSet && (popupNeedsAlphaVisual || toplevelNeedsAlphaVisual)) {
6037 // We're running on composited screen so we can use alpha visual
6038 // for both toplevel and popups.
6039 if (mCompositedScreen) {
6040 GdkVisual* visual =
6041 gdk_screen_get_rgba_visual(gtk_widget_get_screen(mShell));
6042 if (visual) {
6043 gtk_widget_set_visual(mShell, visual);
6044 mHasAlphaVisual = true;
6045 }
6046 }
6047 }
6048
6049 // Use X shape mask to draw round corners of Firefox titlebar.
6050 // We don't use shape masks any more as we switched to ARGB visual
6051 // by default and non-compositing screens use solid-csd decorations
6052 // without round corners.
6053 // Leave the shape mask code here as it can be used to draw round
6054 // corners on EGL (https://gitlab.freedesktop.org/mesa/mesa/-/issues/149)
6055 // or when custom titlebar theme is used.
6056 mTransparencyBitmapForTitlebar = TitlebarUseShapeMask();
6057
6058 // We have a toplevel window with transparency.
6059 // Calls to UpdateTitlebarTransparencyBitmap() from OnExposeEvent()
6060 // occur before SetTransparencyMode() receives TransparencyMode::Transparent
6061 // from layout, so set mIsTransparent here.
6062 if (mWindowType == WindowType::TopLevel &&
6063 (mHasAlphaVisual || mTransparencyBitmapForTitlebar)) {
6064 mIsTransparent = true;
6065 }
6066
6067 // We only move a general managed toplevel window if someone has
6068 // actually placed the window somewhere. If no placement has taken
6069 // place, we just let the window manager Do The Right Thing.
6070 if (AreBoundsSane()) {
6071 GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mBounds.Size());
6072 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
)
6073 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
)
;
6074 gtk_window_resize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), size.width, size.height);
6075 }
6076 if (mIsPIPWindow) {
6077 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)
;
6078 gtk_window_set_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), GDK_WINDOW_TYPE_HINT_UTILITY);
6079 } else if (mIsAlert) {
6080 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)
;
6081 gtk_window_set_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))),
6082 GDK_WINDOW_TYPE_HINT_NOTIFICATION);
6083 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), TRUE(!(0)));
6084 } else if (mWindowType == WindowType::Dialog) {
6085 mGtkWindowRoleName = "Dialog";
6086
6087 SetDefaultIcon();
6088 gtk_window_set_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), GDK_WINDOW_TYPE_HINT_DIALOG);
6089 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)
;
6090 if (parentnsWindow) {
6091 GtkWindowSetTransientFor(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))),
6092 GTK_WINDOW(parentnsWindow->GetGtkWidget())((((GtkWindow*) (void *) ((parentnsWindow->GetGtkWidget())
))))
);
6093 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)
;
6094 }
6095 } else if (mWindowType == WindowType::Popup) {
6096 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"
, 6096); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aInitData" ")"
); do { *((volatile int*)__null) = 6096; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6097 mGtkWindowRoleName = "Popup";
6098
6099 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)
;
6100
6101 if (mNoAutoHide) {
6102 // ... but the window manager does not decorate this window,
6103 // nor provide a separate taskbar icon.
6104 if (mBorderStyle == BorderStyle::Default) {
6105 gtk_window_set_decorated(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), FALSE(0));
6106 } else {
6107 bool decorate = bool(mBorderStyle & BorderStyle::Title);
6108 gtk_window_set_decorated(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), decorate);
6109 if (decorate) {
6110 gtk_window_set_deletable(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))),
6111 bool(mBorderStyle & BorderStyle::Close));
6112 }
6113 }
6114 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), TRUE(!(0)));
6115 // Element focus is managed by the parent window so the
6116 // WM_HINTS input field is set to False to tell the window
6117 // manager not to set input focus to this window ...
6118 gtk_window_set_accept_focus(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), FALSE(0));
6119#ifdef MOZ_X111
6120 // ... but when the window manager offers focus through
6121 // WM_TAKE_FOCUS, focus is requested on the parent window.
6122 if (GdkIsX11Display()) {
6123 gtk_widget_realize(mShell);
6124 gdk_window_add_filter(GetToplevelGdkWindow(), popup_take_focus_filter,
6125 nullptr);
6126 }
6127#endif
6128 }
6129
6130 if (aInitData->mIsDragPopup) {
6131 gtk_window_set_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), GDK_WINDOW_TYPE_HINT_DND);
6132 mIsDragPopup = true;
6133 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)
;
6134 } else if (GdkIsX11Display()) {
6135 // Set the window hints on X11 only. Wayland popups are configured
6136 // at WaylandPopupConfigure().
6137 GdkWindowTypeHint gtkTypeHint;
6138 switch (mPopupType) {
6139 case PopupType::Menu:
6140 gtkTypeHint = GDK_WINDOW_TYPE_HINT_POPUP_MENU;
6141 break;
6142 case PopupType::Tooltip:
6143 gtkTypeHint = GDK_WINDOW_TYPE_HINT_TOOLTIP;
6144 break;
6145 default:
6146 gtkTypeHint = GDK_WINDOW_TYPE_HINT_UTILITY;
6147 break;
6148 }
6149 gtk_window_set_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), gtkTypeHint);
6150 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
)
;
6151 }
6152 if (parentnsWindow) {
6153 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)
6154 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)
;
6155 GtkWindow* parentWidget = GTK_WINDOW(parentnsWindow->GetGtkWidget())((((GtkWindow*) (void *) ((parentnsWindow->GetGtkWidget())
))))
;
6156 GtkWindowSetTransientFor(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), parentWidget);
6157
6158 // If popup parent is modal, we need to make popup modal too.
6159 if (mPopupType != PopupType::Tooltip &&
6160 gtk_window_get_modal(parentWidget)) {
6161 gtk_window_set_modal(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), true);
6162 }
6163 }
6164
6165 // We need realized mShell at NativeMoveResize().
6166 gtk_widget_realize(mShell);
6167
6168 // With popup windows, we want to set their position.
6169 // Place them immediately on X11 and save initial popup position
6170 // on Wayland as we place Wayland popup on show.
6171 if (GdkIsX11Display()) {
6172 NativeMoveResize(/* move */ true, /* resize */ false);
6173 } else if (AreBoundsSane()) {
6174 GdkRectangle rect = DevicePixelsToGdkRectRoundOut(mBounds);
6175 mPopupPosition = {rect.x, rect.y};
6176 }
6177 } else { // must be WindowType::TopLevel
6178 mGtkWindowRoleName = "Toplevel";
6179 SetDefaultIcon();
6180
6181 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)
;
6182
6183 // each toplevel window gets its own window group
6184 GtkWindowGroup* group = gtk_window_group_new();
6185 gtk_window_group_add_window(group, GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
6186 g_object_unref(group);
6187 }
6188
6189 if (mAlwaysOnTop) {
6190 gtk_window_set_keep_above(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), TRUE(!(0)));
6191 }
6192
6193 // Create a container to hold child windows and child GtkWidgets.
6194 GtkWidget* container = moz_container_new();
6195 mContainer = MOZ_CONTAINER(container)((((MozContainer*) (void *) ((container)))));
6196
6197 // Prevent GtkWindow from painting a background to avoid flickering.
6198 gtk_widget_set_app_paintable(
6199 GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))),
6200 StaticPrefs::widget_transparent_windows_AtStartup());
6201
6202 gtk_widget_add_events(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))), kEvents);
6203 gtk_widget_add_events(mShell, GDK_PROPERTY_CHANGE_MASK);
6204 gtk_widget_set_app_paintable(
6205 mShell, StaticPrefs::widget_transparent_windows_AtStartup());
6206
6207 if (mTransparencyBitmapForTitlebar) {
6208 moz_container_force_default_visual(mContainer);
6209 }
6210
6211 // If we draw to mContainer window then configure it now because
6212 // gtk_container_add() realizes the child widget.
6213 gtk_widget_set_has_window(container, true);
6214 gtk_container_add(GTK_CONTAINER(mShell)((((GtkContainer*) (void *) ((mShell))))), container);
6215
6216 // alwaysontop windows are generally used for peripheral indicators,
6217 // so we don't focus them by default.
6218 if (mAlwaysOnTop) {
6219 gtk_window_set_focus_on_map(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), FALSE(0));
6220 }
6221
6222 gtk_widget_realize(container);
6223
6224 // make sure this is the focus widget in the container
6225 gtk_widget_show(container);
6226
6227 if (!mAlwaysOnTop) {
6228 gtk_widget_grab_focus(container);
6229 }
6230
6231#ifdef MOZ_WAYLAND1
6232 if (mIsDragPopup && GdkIsWaylandDisplay()) {
6233 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)
;
6234 moz_container_wayland_set_commit_to_parent(mContainer);
6235 }
6236#endif
6237
6238 if (mWindowType == WindowType::TopLevel && gKioskMode) {
6239 if (gKioskMonitor != -1) {
6240 mKioskMonitor = Some(gKioskMonitor);
6241 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)
;
6242 } else {
6243 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)
;
6244 }
6245 // Kiosk mode always use fullscreen.
6246 MakeFullScreen(/* aFullScreen */ true);
6247 }
6248
6249 if (mWindowType == WindowType::Popup) {
6250 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"
, 6250); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aInitData" ")"
); do { *((volatile int*)__null) = 6250; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6251 // gdk does not automatically set the cursor for "temporary"
6252 // windows, which are what gtk uses for popups.
6253
6254 // force SetCursor to actually set the cursor, even though our internal
6255 // state indicates that we already have the standard cursor.
6256 mUpdateCursor = true;
6257 SetCursor(Cursor{eCursor_standard});
6258 }
6259
6260 if (mIsChildWindow && parentnsWindow) {
6261 GdkWindow* window = GetToplevelGdkWindow();
6262 GdkWindow* parentWindow = parentnsWindow->GetToplevelGdkWindow();
6263 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)
;
6264 gdk_window_reparent(window, parentWindow,
6265 DevicePixelsToGdkCoordRoundDown(mBounds.x),
6266 DevicePixelsToGdkCoordRoundDown(mBounds.y));
6267 }
6268
6269 // Also label mShell toplevel window,
6270 // property_notify_event_cb callback also needs to find its way home
6271 g_object_set_data(G_OBJECT(GetToplevelGdkWindow())((((GObject*) (void *) ((GetToplevelGdkWindow()))))), "nsWindow", this);
6272 g_object_set_data(G_OBJECT(mContainer)((((GObject*) (void *) ((mContainer))))), "nsWindow", this);
6273 g_object_set_data(G_OBJECT(mShell)((((GObject*) (void *) ((mShell))))), "nsWindow", this);
6274
6275 // attach listeners for events
6276 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
)
6277 nullptr)g_signal_connect_data ((mShell), ("configure_event"), (((GCallback
) (configure_event_cb))), (nullptr), __null, (GConnectFlags) 0
)
;
6278 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)
6279 nullptr)g_signal_connect_data ((mShell), ("delete_event"), (((GCallback
) (delete_event_cb))), (nullptr), __null, (GConnectFlags) 0)
;
6280 g_signal_connect(mShell, "window_state_event",g_signal_connect_data ((mShell), ("window_state_event"), (((GCallback
) (window_state_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
6281 G_CALLBACK(window_state_event_cb), nullptr)g_signal_connect_data ((mShell), ("window_state_event"), (((GCallback
) (window_state_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6282 g_signal_connect(mShell, "visibility-notify-event",g_signal_connect_data ((mShell), ("visibility-notify-event"),
(((GCallback) (visibility_notify_event_cb))), (nullptr), __null
, (GConnectFlags) 0)
6283 G_CALLBACK(visibility_notify_event_cb), nullptr)g_signal_connect_data ((mShell), ("visibility-notify-event"),
(((GCallback) (visibility_notify_event_cb))), (nullptr), __null
, (GConnectFlags) 0)
;
6284 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)
6285 nullptr)g_signal_connect_data ((mShell), ("check-resize"), (((GCallback
) (check_resize_cb))), (nullptr), __null, (GConnectFlags) 0)
;
6286 g_signal_connect(mShell, "composited-changed",g_signal_connect_data ((mShell), ("composited-changed"), (((GCallback
) (widget_composited_changed_cb))), (nullptr), __null, (GConnectFlags
) 0)
6287 G_CALLBACK(widget_composited_changed_cb), nullptr)g_signal_connect_data ((mShell), ("composited-changed"), (((GCallback
) (widget_composited_changed_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6288 g_signal_connect(mShell, "property-notify-event",g_signal_connect_data ((mShell), ("property-notify-event"), (
((GCallback) (property_notify_event_cb))), (nullptr), __null,
(GConnectFlags) 0)
6289 G_CALLBACK(property_notify_event_cb), nullptr)g_signal_connect_data ((mShell), ("property-notify-event"), (
((GCallback) (property_notify_event_cb))), (nullptr), __null,
(GConnectFlags) 0)
;
6290
6291 if (mWindowType == WindowType::TopLevel) {
6292 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
)
6293 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
)
6294 nullptr)g_signal_connect_data ((mShell), ("size_allocate"), (((GCallback
) (toplevel_window_size_allocate_cb))), (nullptr), __null, G_CONNECT_AFTER
)
;
6295 }
6296
6297 GdkScreen* screen = gtk_widget_get_screen(mShell);
6298 if (!g_signal_handler_find(screen, G_SIGNAL_MATCH_FUNC, 0, 0, nullptr,
6299 FuncToGpointer(screen_composited_changed_cb),
6300 nullptr)) {
6301 g_signal_connect(screen, "composited-changed",g_signal_connect_data ((screen), ("composited-changed"), (((GCallback
) (screen_composited_changed_cb))), (nullptr), __null, (GConnectFlags
) 0)
6302 G_CALLBACK(screen_composited_changed_cb), nullptr)g_signal_connect_data ((screen), ("composited-changed"), (((GCallback
) (screen_composited_changed_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6303 }
6304
6305 gtk_drag_dest_set((GtkWidget*)mShell, (GtkDestDefaults)0, nullptr, 0,
6306 (GdkDragAction)0);
6307 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)
6308 nullptr)g_signal_connect_data ((mShell), ("drag_motion"), (((GCallback
) (drag_motion_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6309 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)
6310 nullptr)g_signal_connect_data ((mShell), ("drag_leave"), (((GCallback
) (drag_leave_event_cb))), (nullptr), __null, (GConnectFlags)
0)
;
6311 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
)
6312 nullptr)g_signal_connect_data ((mShell), ("drag_drop"), (((GCallback)
(drag_drop_event_cb))), (nullptr), __null, (GConnectFlags) 0
)
;
6313 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)
6314 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)
;
6315
6316 GtkSettings* default_settings = gtk_settings_get_default();
6317 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)
6318 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)
;
6319
6320 // Widget signals
6321 g_signal_connect_after(mContainer, "size_allocate",g_signal_connect_data ((mContainer), ("size_allocate"), (((GCallback
) (size_allocate_cb))), (nullptr), __null, G_CONNECT_AFTER)
6322 G_CALLBACK(size_allocate_cb), nullptr)g_signal_connect_data ((mContainer), ("size_allocate"), (((GCallback
) (size_allocate_cb))), (nullptr), __null, G_CONNECT_AFTER)
;
6323 g_signal_connect(mContainer, "hierarchy-changed",g_signal_connect_data ((mContainer), ("hierarchy-changed"), (
((GCallback) (hierarchy_changed_cb))), (nullptr), __null, (GConnectFlags
) 0)
6324 G_CALLBACK(hierarchy_changed_cb), nullptr)g_signal_connect_data ((mContainer), ("hierarchy-changed"), (
((GCallback) (hierarchy_changed_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6325 g_signal_connect(mContainer, "notify::scale-factor",g_signal_connect_data ((mContainer), ("notify::scale-factor")
, (((GCallback) (scale_changed_cb))), (nullptr), __null, (GConnectFlags
) 0)
6326 G_CALLBACK(scale_changed_cb), nullptr)g_signal_connect_data ((mContainer), ("notify::scale-factor")
, (((GCallback) (scale_changed_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6327 // Initialize mHasMappedToplevel.
6328 hierarchy_changed_cb(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))), nullptr);
6329 // Expose, focus, key, and drag events are sent even to GTK_NO_WINDOW
6330 // widgets.
6331 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)
6332 nullptr)g_signal_connect_data ((((((GObject*) (void *) ((mContainer))
)))), ("draw"), (((GCallback) (expose_event_cb))), (nullptr),
__null, (GConnectFlags) 0)
;
6333 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
)
6334 nullptr)g_signal_connect_data ((mContainer), ("focus_in_event"), (((GCallback
) (focus_in_event_cb))), (nullptr), __null, (GConnectFlags) 0
)
;
6335 g_signal_connect(mContainer, "focus_out_event",g_signal_connect_data ((mContainer), ("focus_out_event"), (((
GCallback) (focus_out_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
6336 G_CALLBACK(focus_out_event_cb), nullptr)g_signal_connect_data ((mContainer), ("focus_out_event"), (((
GCallback) (focus_out_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6337 g_signal_connect(mContainer, "key_press_event",g_signal_connect_data ((mContainer), ("key_press_event"), (((
GCallback) (key_press_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
6338 G_CALLBACK(key_press_event_cb), nullptr)g_signal_connect_data ((mContainer), ("key_press_event"), (((
GCallback) (key_press_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6339 g_signal_connect(mContainer, "key_release_event",g_signal_connect_data ((mContainer), ("key_release_event"), (
((GCallback) (key_release_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
6340 G_CALLBACK(key_release_event_cb), nullptr)g_signal_connect_data ((mContainer), ("key_release_event"), (
((GCallback) (key_release_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6341
6342#ifdef MOZ_X111
6343 if (GdkIsX11Display()) {
6344 gtk_widget_set_double_buffered(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))), FALSE(0));
6345 }
6346#endif
6347#ifdef MOZ_WAYLAND1
6348 // Initialize the window specific VsyncSource early in order to avoid races
6349 // with BrowserParent::UpdateVsyncParentVsyncDispatcher().
6350 // Only use for toplevel windows for now, see bug 1619246.
6351 if (GdkIsWaylandDisplay() &&
6352 StaticPrefs::widget_wayland_vsync_enabled_AtStartup() &&
6353 IsTopLevelWindowType()) {
6354 mWaylandVsyncSource = new WaylandVsyncSource(this);
6355 mWaylandVsyncDispatcher = new VsyncDispatcher(mWaylandVsyncSource);
6356 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)
;
6357 }
6358#endif
6359
6360 // We create input contexts for all containers, except for
6361 // toplevel popup windows
6362 if (mWindowType != WindowType::Popup) {
6363 mIMContext = new IMContextWrapper(this);
6364 }
6365
6366 // These events are sent to the owning widget of the relevant window
6367 // and propagate up to the first widget that handles the events, so we
6368 // need only connect on mShell, if it exists, to catch events on its
6369 // window and windows of mContainer.
6370 g_signal_connect(mContainer, "enter-notify-event",g_signal_connect_data ((mContainer), ("enter-notify-event"), (
((GCallback) (enter_notify_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
6371 G_CALLBACK(enter_notify_event_cb), nullptr)g_signal_connect_data ((mContainer), ("enter-notify-event"), (
((GCallback) (enter_notify_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6372 g_signal_connect(mContainer, "leave-notify-event",g_signal_connect_data ((mContainer), ("leave-notify-event"), (
((GCallback) (leave_notify_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
6373 G_CALLBACK(leave_notify_event_cb), nullptr)g_signal_connect_data ((mContainer), ("leave-notify-event"), (
((GCallback) (leave_notify_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6374 g_signal_connect(mContainer, "motion-notify-event",g_signal_connect_data ((mContainer), ("motion-notify-event"),
(((GCallback) (motion_notify_event_cb))), (nullptr), __null,
(GConnectFlags) 0)
6375 G_CALLBACK(motion_notify_event_cb), nullptr)g_signal_connect_data ((mContainer), ("motion-notify-event"),
(((GCallback) (motion_notify_event_cb))), (nullptr), __null,
(GConnectFlags) 0)
;
6376 g_signal_connect(mContainer, "button-press-event",g_signal_connect_data ((mContainer), ("button-press-event"), (
((GCallback) (button_press_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
6377 G_CALLBACK(button_press_event_cb), nullptr)g_signal_connect_data ((mContainer), ("button-press-event"), (
((GCallback) (button_press_event_cb))), (nullptr), __null, (GConnectFlags
) 0)
;
6378 g_signal_connect(mContainer, "button-release-event",g_signal_connect_data ((mContainer), ("button-release-event")
, (((GCallback) (button_release_event_cb))), (nullptr), __null
, (GConnectFlags) 0)
6379 G_CALLBACK(button_release_event_cb), nullptr)g_signal_connect_data ((mContainer), ("button-release-event")
, (((GCallback) (button_release_event_cb))), (nullptr), __null
, (GConnectFlags) 0)
;
6380 g_signal_connect(mContainer, "scroll-event", G_CALLBACK(scroll_event_cb),g_signal_connect_data ((mContainer), ("scroll-event"), (((GCallback
) (scroll_event_cb))), (nullptr), __null, (GConnectFlags) 0)
6381 nullptr)g_signal_connect_data ((mContainer), ("scroll-event"), (((GCallback
) (scroll_event_cb))), (nullptr), __null, (GConnectFlags) 0)
;
6382 if (gtk_check_version(3, 18, 0) == nullptr) {
6383 g_signal_connect(mContainer, "event", G_CALLBACK(generic_event_cb),g_signal_connect_data ((mContainer), ("event"), (((GCallback)
(generic_event_cb))), (nullptr), __null, (GConnectFlags) 0)
6384 nullptr)g_signal_connect_data ((mContainer), ("event"), (((GCallback)
(generic_event_cb))), (nullptr), __null, (GConnectFlags) 0)
;
6385 }
6386 g_signal_connect(mContainer, "touch-event", G_CALLBACK(touch_event_cb),g_signal_connect_data ((mContainer), ("touch-event"), (((GCallback
) (touch_event_cb))), (nullptr), __null, (GConnectFlags) 0)
6387 nullptr)g_signal_connect_data ((mContainer), ("touch-event"), (((GCallback
) (touch_event_cb))), (nullptr), __null, (GConnectFlags) 0)
;
6388
6389 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)
6390 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)
;
6391 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)
6392 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)
;
6393
6394 // Set default application name when it's empty.
6395 if (mGtkWindowAppName.IsEmpty()) {
6396 mGtkWindowAppName = gAppData->name;
6397 }
6398
6399 mCreated = true;
6400 return NS_OK;
6401}
6402
6403void nsWindow::RefreshWindowClass(void) {
6404 GdkWindow* gdkWindow = GetToplevelGdkWindow();
6405 if (!gdkWindow) {
6406 return;
6407 }
6408
6409 if (!mGtkWindowRoleName.IsEmpty()) {
6410 gdk_window_set_role(gdkWindow, mGtkWindowRoleName.get());
6411 }
6412
6413#ifdef MOZ_X111
6414 if (GdkIsX11Display()) {
6415 XClassHint* class_hint = XAllocClassHint();
6416 if (!class_hint) {
6417 return;
6418 }
6419
6420 const char* res_name =
6421 !mGtkWindowAppName.IsEmpty() ? mGtkWindowAppName.get() : gAppData->name;
6422
6423 const char* res_class = !mGtkWindowAppClass.IsEmpty()
6424 ? mGtkWindowAppClass.get()
6425 : gdk_get_program_class();
6426
6427 if (!res_name || !res_class) {
6428 XFree(class_hint);
6429 return;
6430 }
6431
6432 class_hint->res_name = const_cast<char*>(res_name);
6433 class_hint->res_class = const_cast<char*>(res_class);
6434
6435 // Can't use gtk_window_set_wmclass() for this; it prints
6436 // a warning & refuses to make the change.
6437 GdkDisplay* display = gdk_display_get_default();
6438 XSetClassHint(GDK_DISPLAY_XDISPLAY(display)(gdk_x11_display_get_xdisplay (display)),
6439 gdk_x11_window_get_xid(gdkWindow), class_hint);
6440 XFree(class_hint);
6441 }
6442#endif /* MOZ_X11 */
6443
6444#ifdef MOZ_WAYLAND1
6445 static auto sGdkWaylandWindowSetApplicationId =
6446 (void (*)(GdkWindow*, const char*))dlsym(
6447 RTLD_DEFAULT((void *) 0), "gdk_wayland_window_set_application_id");
6448
6449 if (GdkIsWaylandDisplay() && sGdkWaylandWindowSetApplicationId &&
6450 !mGtkWindowAppClass.IsEmpty()) {
6451 sGdkWaylandWindowSetApplicationId(gdkWindow, mGtkWindowAppClass.get());
6452 }
6453#endif /* MOZ_WAYLAND */
6454}
6455
6456void nsWindow::SetWindowClass(const nsAString& xulWinType,
6457 const nsAString& xulWinClass,
6458 const nsAString& xulWinName) {
6459 if (!mShell) {
6460 return;
6461 }
6462
6463 // If window type attribute is set, parse it into name and role
6464 if (!xulWinType.IsEmpty()) {
6465 char* res_name = ToNewCString(xulWinType, mozilla::fallible);
6466 const char* role = nullptr;
6467
6468 if (res_name) {
6469 // Parse res_name into a name and role. Characters other than
6470 // [A-Za-z0-9_-] are converted to '_'. Anything after the first
6471 // colon is assigned to role; if there's no colon, assign the
6472 // whole thing to both role and res_name.
6473 for (char* c = res_name; *c; c++) {
6474 if (':' == *c) {
6475 *c = 0;
6476 role = c + 1;
6477 } else if (!isascii(*c) ||
6478 (!isalnum(*c) && ('_' != *c) && ('-' != *c))) {
6479 *c = '_';
6480 }
6481 }
6482 res_name[0] = (char)toupper(res_name[0]);
6483 if (!role) role = res_name;
6484
6485 mGtkWindowAppName = res_name;
6486 mGtkWindowRoleName = role;
6487 free(res_name);
6488 }
6489 }
6490
6491 // If window class attribute is set, store it as app class
6492 // If this attribute is not set, reset app class to default
6493 if (!xulWinClass.IsEmpty()) {
6494 CopyUTF16toUTF8(xulWinClass, mGtkWindowAppClass);
6495 } else {
6496 mGtkWindowAppClass = nullptr;
6497 }
6498
6499 // If window class attribute is set, store it as app name
6500 // If both name and type are not set, reset app name to default
6501 if (!xulWinName.IsEmpty()) {
6502 CopyUTF16toUTF8(xulWinName, mGtkWindowAppName);
6503 } else if (xulWinType.IsEmpty()) {
6504 mGtkWindowAppClass = nullptr;
6505 }
6506
6507 RefreshWindowClass();
6508}
6509
6510nsAutoCString nsWindow::GetDebugTag() const {
6511 nsAutoCString tag;
6512 tag.AppendPrintf("[%p]", this);
6513 return tag;
6514}
6515
6516void nsWindow::NativeMoveResize(bool aMoved, bool aResized) {
6517 GdkPoint topLeft = [&] {
6518 auto target = mBounds.TopLeft();
6519 // gtk_window_move will undo the csd offset, but nothing else, so only add
6520 // the client offset if drawing to the csd titlebar.
6521 if (DrawsToCSDTitlebar()) {
6522 target += mClientOffset;
6523 }
6524 return DevicePixelsToGdkPointRoundDown(target);
6525 }();
6526 GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mLastSizeRequest);
6527
6528 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)
6529 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)
;
6530
6531 if (aMoved) {
6532 ResetScreenBounds();
6533 }
6534
6535 if (aResized && !AreBoundsSane()) {
6536 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)
;
6537 // We have been resized but to incorrect size.
6538 // If someone has set this so that the needs show flag is false
6539 // and it needs to be hidden, update the flag and hide the
6540 // window. This flag will be cleared the next time someone
6541 // hides the window or shows it. It also prevents us from
6542 // calling NativeShow(false) excessively on the window which
6543 // causes unneeded X traffic.
6544 if (!mNeedsShow && mIsShown) {
6545 mNeedsShow = true;
6546 NativeShow(false);
6547 }
6548 if (aMoved) {
6549 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)
;
6550 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), topLeft.x, topLeft.y);
6551 }
6552 return;
6553 }
6554
6555 // Set position to hidden window on X11 may fail, so save the position
6556 // and move it when it's shown.
6557 if (aMoved && GdkIsX11Display() && IsPopup() &&
6558 !gtk_widget_get_visible(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))))) {
6559 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)
;
6560 mHiddenPopupPositioned = true;
6561 mPopupPosition = {topLeft.x, topLeft.y};
6562 }
6563
6564 if (IsWaylandPopup()) {
6565 NativeMoveResizeWaylandPopup(aMoved, aResized);
6566 } else {
6567 // x and y give the position of the window manager frame top-left.
6568 if (aMoved) {
6569 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), topLeft.x, topLeft.y);
6570 }
6571 if (aResized) {
6572 gtk_window_resize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), size.width, size.height);
6573 if (mIsDragPopup) {
6574 // DND window is placed inside container so we need to make hard size
6575 // request to ensure parent container is resized too.
6576 gtk_widget_set_size_request(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))), size.width,
6577 size.height);
6578 }
6579 }
6580 }
6581
6582 if (aResized) {
6583 // Recompute the input region, in case the window grew or shrunk.
6584 SetInputRegion(mInputRegion);
6585 }
6586
6587 // Does it need to be shown because bounds were previously insane?
6588 if (mNeedsShow && mIsShown && aResized) {
6589 NativeShow(true);
6590 }
6591}
6592
6593// We pause compositor to avoid rendering of obsoleted remote content which
6594// produces flickering.
6595// Re-enable compositor again when remote content is updated or
6596// timeout happens.
6597
6598// Define maximal compositor pause when it's paused to avoid flickering,
6599// in milliseconds.
6600#define COMPOSITOR_PAUSE_TIMEOUT(1000) (1000)
6601
6602void nsWindow::PauseCompositorFlickering() {
6603 bool pauseCompositor = IsTopLevelWindowType() &&
6604 mCompositorState == COMPOSITOR_ENABLED &&
6605 mCompositorWidgetDelegate && !mIsDestroyed;
6606 if (!pauseCompositor) {
6607 return;
6608 }
6609
6610 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)
;
6611
6612 MozClearHandleID(mCompositorPauseTimeoutID, g_source_remove);
6613
6614 CompositorBridgeChild* remoteRenderer = GetRemoteRenderer();
6615 if (remoteRenderer) {
6616 mCompositorState = COMPOSITOR_PAUSED_FLICKERING;
6617 remoteRenderer->SendPause();
6618 mCompositorPauseTimeoutID = (int)g_timeout_add(
6619 COMPOSITOR_PAUSE_TIMEOUT(1000),
6620 [](void* data) -> gint {
6621 nsWindow* window = static_cast<nsWindow*>(data);
6622 if (!window->IsDestroyed()) {
6623 window->ResumeCompositorFlickering();
6624 }
6625 return true;
6626 },
6627 this);
6628 }
6629}
6630
6631bool nsWindow::IsWaitingForCompositorResume() {
6632 return mCompositorState == COMPOSITOR_PAUSED_FLICKERING;
6633}
6634
6635void nsWindow::ResumeCompositorFlickering() {
6636 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"
, 6636); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 6636; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6637
6638 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)
;
6639
6640 if (mIsDestroyed || !IsWaitingForCompositorResume()) {
6641 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)
;
6642 return;
6643 }
6644
6645 MozClearHandleID(mCompositorPauseTimeoutID, g_source_remove);
6646
6647 // mCompositorWidgetDelegate can be deleted during timeout.
6648 // In such case just flip compositor back to enabled and let
6649 // SetCompositorWidgetDelegate() or Map event resume it.
6650 if (!mCompositorWidgetDelegate) {
6651 mCompositorState = COMPOSITOR_ENABLED;
6652 return;
6653 }
6654
6655 ResumeCompositorImpl();
6656}
6657
6658void nsWindow::ResumeCompositorFromCompositorThread() {
6659 nsCOMPtr<nsIRunnable> event =
6660 NewRunnableMethod("nsWindow::ResumeCompositorFlickering", this,
6661 &nsWindow::ResumeCompositorFlickering);
6662 NS_DispatchToMainThread(event.forget());
6663}
6664
6665void nsWindow::ResumeCompositorImpl() {
6666 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"
, 6666); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 6666; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6667
6668 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)
;
6669
6670 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"
, 6670); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mCompositorWidgetDelegate"
")"); do { *((volatile int*)__null) = 6670; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6671 mCompositorWidgetDelegate->SetRenderingSurface(GetX11Window(),
6672 GetShapedState());
6673
6674 // As WaylandStartVsync needs mCompositorWidgetDelegate this is the right
6675 // time to start it.
6676 WaylandStartVsync();
6677
6678 CompositorBridgeChild* remoteRenderer = GetRemoteRenderer();
6679 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"
, 6679); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "remoteRenderer"
")"); do { *((volatile int*)__null) = 6679; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6680 remoteRenderer->SendResume();
6681 remoteRenderer->SendForcePresent(wr::RenderReasons::WIDGET);
6682 mCompositorState = COMPOSITOR_ENABLED;
6683}
6684
6685void nsWindow::WaylandStartVsync() {
6686#ifdef MOZ_WAYLAND1
6687 if (!mWaylandVsyncSource) {
6688 return;
6689 }
6690
6691 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)
;
6692
6693 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"
, 6693); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mCompositorWidgetDelegate"
")"); do { *((volatile int*)__null) = 6693; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6694 if (mCompositorWidgetDelegate->AsGtkCompositorWidget() &&
6695 mCompositorWidgetDelegate->AsGtkCompositorWidget()
6696 ->GetNativeLayerRoot()) {
6697 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)
;
6698 mWaylandVsyncSource->MaybeUpdateSource(
6699 mCompositorWidgetDelegate->AsGtkCompositorWidget()
6700 ->GetNativeLayerRoot()
6701 ->AsNativeLayerRootWayland());
6702 } else {
6703 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)
;
6704 mWaylandVsyncSource->MaybeUpdateSource(mContainer);
6705 }
6706
6707 mWaylandVsyncSource->EnableMonitor();
6708#endif
6709}
6710
6711void nsWindow::WaylandStopVsync() {
6712#ifdef MOZ_WAYLAND1
6713 if (!mWaylandVsyncSource) {
6714 return;
6715 }
6716
6717 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)
;
6718
6719 // The widget is going to be hidden, so clear the surface of our
6720 // vsync source.
6721 mWaylandVsyncSource->DisableMonitor();
6722 mWaylandVsyncSource->MaybeUpdateSource(nullptr);
6723#endif
6724}
6725
6726void nsWindow::NativeShow(bool aAction) {
6727 if (aAction) {
6728 // unset our flag now that our window has been shown
6729 mNeedsShow = true;
6730 auto removeShow = MakeScopeExit([&] { mNeedsShow = false; });
6731
6732 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)
;
6733
6734 if (IsWaylandPopup()) {
6735 mPopupClosed = false;
6736 if (WaylandPopupConfigure()) {
6737 AddWindowToPopupHierarchy();
6738 UpdateWaylandPopupHierarchy();
6739 if (mPopupClosed) {
6740 return;
6741 }
6742 }
6743 }
6744 // Set up usertime/startupID metadata for the created window.
6745 // On X11 we use gtk_window_set_startup_id() so we need to call it
6746 // before show.
6747 if (GdkIsX11Display()) {
6748 SetUserTimeAndStartupTokenForActivatedWindow();
6749 }
6750 if (GdkIsWaylandDisplay()) {
6751 if (IsWaylandPopup()) {
6752 ShowWaylandPopupWindow();
6753 } else {
6754 ShowWaylandToplevelWindow();
6755 }
6756 } else {
6757 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)
;
6758 gtk_widget_show(mShell);
6759 }
6760 if (GdkIsWaylandDisplay()) {
6761 SetUserTimeAndStartupTokenForActivatedWindow();
6762#ifdef MOZ_WAYLAND1
6763 auto token = std::move(mWindowActivationTokenFromEnv);
6764 if (!token.IsEmpty()) {
6765 FocusWaylandWindow(token.get());
6766 }
6767#endif
6768 }
6769 if (mHiddenPopupPositioned && IsPopup()) {
6770 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)
;
6771 gtk_window_move(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), mPopupPosition.x, mPopupPosition.y);
6772 mHiddenPopupPositioned = false;
6773 }
6774 } else {
6775 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)
;
6776 if (GdkIsWaylandDisplay()) {
6777 if (IsWaylandPopup()) {
6778 // We can't close tracked popups directly as they may have visible
6779 // child popups. Just mark is as closed and let
6780 // UpdateWaylandPopupHierarchy() do the job.
6781 if (IsInPopupHierarchy()) {
6782 WaylandPopupMarkAsClosed();
6783 UpdateWaylandPopupHierarchy();
6784 } else {
6785 // Close untracked popups directly.
6786 HideWaylandPopupWindow(/* aTemporaryHide */ false,
6787 /* aRemoveFromPopupList */ true);
6788 }
6789 } else {
6790 HideWaylandToplevelWindow();
6791 }
6792 } else {
6793 // Workaround window freezes on GTK versions before 3.21.2 by
6794 // ensuring that configure events get dispatched to windows before
6795 // they are unmapped. See bug 1225044.
6796 if (gtk_check_version(3, 21, 2) != nullptr && mPendingConfigures > 0) {
6797 GtkAllocation allocation;
6798 gtk_widget_get_allocation(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))), &allocation);
6799
6800 GdkEventConfigure event;
6801 PodZero(&event);
6802 event.type = GDK_CONFIGURE;
6803 event.window = mGdkWindow;
6804 event.send_event = TRUE(!(0));
6805 event.x = allocation.x;
6806 event.y = allocation.y;
6807 event.width = allocation.width;
6808 event.height = allocation.height;
6809
6810 auto* shellClass = GTK_WIDGET_GET_CLASS(mShell)((((GtkWidgetClass*) (((GTypeInstance*) ((mShell)))->g_class
))))
;
6811 for (unsigned int i = 0; i < mPendingConfigures; i++) {
6812 Unused << shellClass->configure_event(mShell, &event);
6813 }
6814 mPendingConfigures = 0;
6815 }
6816 gtk_widget_hide(mShell);
6817
6818 ClearTransparencyBitmap(); // Release some resources
6819 }
6820 }
6821}
6822
6823void nsWindow::SetHasMappedToplevel(bool aState) {
6824 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)
;
6825 if (aState == mHasMappedToplevel) {
6826 return;
6827 }
6828 // Even when aState == mHasMappedToplevel (as when this method is called
6829 // from Show()), child windows need to have their state checked, so don't
6830 // return early.
6831 mHasMappedToplevel = aState;
6832 if (aState && mNeedsToRetryCapturingMouse) {
6833 CaptureRollupEvents(true);
6834 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"
, 6834); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mNeedsToRetryCapturingMouse"
")"); do { *((volatile int*)__null) = 6834; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6835 }
6836}
6837
6838LayoutDeviceIntSize nsWindow::GetSafeWindowSize(LayoutDeviceIntSize aSize) {
6839 // The X protocol uses CARD32 for window sizes, but the server (1.11.3)
6840 // reads it as CARD16. Sizes of pixmaps, used for drawing, are (unsigned)
6841 // CARD16 in the protocol, but the server's ProcCreatePixmap returns
6842 // BadAlloc if dimensions cannot be represented by signed shorts.
6843 // Because we are creating Cairo surfaces to represent window buffers,
6844 // we also must ensure that the window can fit in a Cairo surface.
6845 LayoutDeviceIntSize result = aSize;
6846 int32_t maxSize = 32767;
6847 if (mWindowRenderer && mWindowRenderer->AsKnowsCompositor()) {
6848 maxSize = std::min(
6849 maxSize, mWindowRenderer->AsKnowsCompositor()->GetMaxTextureSize());
6850 }
6851 if (result.width > maxSize) {
6852 result.width = maxSize;
6853 }
6854 if (result.height > maxSize) {
6855 result.height = maxSize;
6856 }
6857 return result;
6858}
6859
6860void nsWindow::SetTransparencyMode(TransparencyMode aMode) {
6861 bool isTransparent = aMode == TransparencyMode::Transparent;
6862
6863 if (mIsTransparent == isTransparent) {
6864 return;
6865 }
6866
6867 if (mWindowType != WindowType::Popup) {
6868 // https://bugzilla.mozilla.org/show_bug.cgi?id=1344839 reported
6869 // problems cleaning the layer manager for toplevel windows.
6870 // Ignore the request so as to workaround that.
6871 // mIsTransparent is set in Create() if transparency may be required.
6872 if (isTransparent) {
6873 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"
, 6873)
;
6874 }
6875 return;
6876 }
6877
6878 if (!isTransparent) {
6879 ClearTransparencyBitmap();
6880 } // else the new default alpha values are "all 1", so we don't
6881 // need to change anything yet
6882
6883 mIsTransparent = isTransparent;
6884
6885 if (!mHasAlphaVisual) {
6886 // The choice of layer manager depends on
6887 // GtkCompositorWidgetInitData::Shaped(), which will need to change, so
6888 // clean out the old layer manager.
6889 DestroyLayerManager();
6890 }
6891}
6892
6893TransparencyMode nsWindow::GetTransparencyMode() {
6894 return mIsTransparent ? TransparencyMode::Transparent
6895 : TransparencyMode::Opaque;
6896}
6897
6898gint nsWindow::GetInputRegionMarginInGdkCoords() {
6899 return DevicePixelsToGdkCoordRoundDown(mInputRegion.mMargin);
6900}
6901
6902void nsWindow::SetInputRegion(const InputRegion& aInputRegion) {
6903 mInputRegion = aInputRegion;
6904
6905 GdkWindow* window = GetToplevelGdkWindow();
6906 if (!window) {
6907 return;
6908 }
6909
6910 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)
6911 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)
;
6912
6913 cairo_rectangle_int_t rect = {0, 0, 0, 0};
6914 cairo_region_t* region = nullptr;
6915 auto releaseRegion = MakeScopeExit([&] {
6916 if (region) {
6917 cairo_region_destroy(region);
6918 }
6919 });
6920
6921 if (aInputRegion.mFullyTransparent) {
6922 region = cairo_region_create_rectangle(&rect);
6923 } else if (aInputRegion.mMargin != 0) {
6924 LayoutDeviceIntRect inputRegion(LayoutDeviceIntPoint(), mLastSizeRequest);
6925 inputRegion.Deflate(aInputRegion.mMargin);
6926 GdkRectangle gdkRect = DevicePixelsToGdkRectRoundOut(inputRegion);
6927 rect = {gdkRect.x, gdkRect.y, gdkRect.width, gdkRect.height};
6928 region = cairo_region_create_rectangle(&rect);
6929 }
6930
6931 gdk_window_input_shape_combine_region(window, region, 0, 0);
6932
6933 // On Wayland gdk_window_input_shape_combine_region() call is cached and
6934 // applied to underlying wl_surface when GdkWindow is repainted.
6935 // Force repaint of GdkWindow to apply the change immediately.
6936 if (GdkIsWaylandDisplay()) {
6937 gdk_window_invalidate_rect(window, nullptr, false);
6938 }
6939}
6940
6941// For setting the draggable titlebar region from CSS
6942// with -moz-window-dragging: drag.
6943void nsWindow::UpdateWindowDraggingRegion(
6944 const LayoutDeviceIntRegion& aRegion) {
6945 if (mDraggableRegion != aRegion) {
6946 mDraggableRegion = aRegion;
6947 }
6948}
6949
6950#ifdef MOZ_ENABLE_DBUS1
6951void nsWindow::SetDBusMenuBar(
6952 RefPtr<mozilla::widget::DBusMenuBar> aDbusMenuBar) {
6953 mDBusMenuBar = std::move(aDbusMenuBar);
6954}
6955#endif
6956
6957LayoutDeviceIntCoord nsWindow::GetTitlebarRadius() {
6958 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"
, 6958); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 6958; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
6959 int32_t cssCoord = LookAndFeel::GetInt(LookAndFeel::IntID::TitlebarRadius);
6960 return GdkCoordToDevicePixels(cssCoord);
6961}
6962
6963LayoutDeviceIntRegion nsWindow::GetOpaqueRegion() const {
6964 AutoReadLock r(mOpaqueRegionLock);
6965 return mOpaqueRegion;
6966}
6967
6968// See subtract_corners_from_region() at gtk/gtkwindow.c
6969// We need to subtract corners from toplevel window opaque region
6970// to draw transparent corners of default Gtk titlebar.
6971// Both implementations (cairo_region_t and wl_region) needs to be synced.
6972static void SubtractTitlebarCorners(LayoutDeviceIntRegion& aRegion,
6973 const LayoutDeviceIntRect& aRect,
6974 LayoutDeviceIntCoord aRadius) {
6975 if (!aRadius) {
6976 return;
6977 }
6978 const LayoutDeviceIntSize size(aRadius, aRadius);
6979 aRegion.SubOut(LayoutDeviceIntRect(aRect.TopLeft(), size));
6980 aRegion.SubOut(LayoutDeviceIntRect(
6981 aRect.TopRight() - LayoutDeviceIntPoint(aRadius, 0), size));
6982 aRegion.SubOut(LayoutDeviceIntRect(
6983 aRect.BottomLeft() - LayoutDeviceIntPoint(0, aRadius), size));
6984 aRegion.SubOut(LayoutDeviceIntRect(
6985 aRect.BottomRight() - LayoutDeviceIntPoint(aRadius, aRadius), size));
6986}
6987
6988void nsWindow::UpdateOpaqueRegion(const LayoutDeviceIntRegion& aRegion) {
6989 LayoutDeviceIntRegion region = aRegion;
6990 SubtractTitlebarCorners(region, LayoutDeviceIntRect({}, mBounds.Size()),
6991 GetTitlebarRadius());
6992 {
6993 AutoReadLock r(mOpaqueRegionLock);
6994 if (mOpaqueRegion == region) {
6995 return;
6996 }
6997 }
6998 {
6999 AutoWriteLock w(mOpaqueRegionLock);
7000 mOpaqueRegion = region;
7001 }
7002 UpdateOpaqueRegionInternal();
7003}
7004
7005void nsWindow::UpdateOpaqueRegionInternal() {
7006 if (!mCompositedScreen) {
7007 return;
7008 }
7009
7010 if (!IsTopLevelWindowType()) {
7011 // We need to clear target buffer alpha values of popup windows as
7012 // SW-WR paints with alpha blending (see Bug 1674473).
7013 return;
7014 }
7015
7016 GdkWindow* window = GetToplevelGdkWindow();
7017 if (!window) {
7018 return;
7019 }
7020 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"
, 7020); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gdk_window_get_window_type(window) == GDK_WINDOW_TOPLEVEL"
")"); do { *((volatile int*)__null) = 7020; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7021
7022 {
7023 AutoReadLock lock(mOpaqueRegionLock);
7024 cairo_region_t* region = nullptr;
7025 if (!mOpaqueRegion.IsEmpty()) {
7026 // NOTE(emilio): The opaque region is relative to our mContainer /
7027 // mGdkWindow / inner window, but we're setting it on the top level
7028 // GdkWindow / mShell.
7029 //
7030 // So we need to offset the rects by the position of mGdkWindow, in order
7031 // for them to be in the right coordinate system.
7032 GdkPoint offset{0, 0};
7033 gdk_window_get_position(mGdkWindow, &offset.x, &offset.y);
7034
7035 region = cairo_region_create();
7036
7037 for (auto iter = mOpaqueRegion.RectIter(); !iter.Done(); iter.Next()) {
7038 auto gdkRect = DevicePixelsToGdkRectRoundIn(iter.Get());
7039 cairo_rectangle_int_t rect = {gdkRect.x + offset.x,
7040 gdkRect.y + offset.y, gdkRect.width,
7041 gdkRect.height};
7042 cairo_region_union_rectangle(region, &rect);
7043 }
7044 }
7045 gdk_window_set_opaque_region(window, region);
7046 if (region) {
7047 cairo_region_destroy(region);
7048 }
7049 }
7050
7051#ifdef MOZ_WAYLAND1
7052 if (GdkIsWaylandDisplay()) {
7053 moz_container_wayland_update_opaque_region(mContainer);
7054 }
7055#endif
7056}
7057
7058bool nsWindow::IsChromeWindowTitlebar() {
7059 return mDrawInTitlebar && !mIsPIPWindow &&
7060 mWindowType == WindowType::TopLevel;
7061}
7062
7063bool nsWindow::DoDrawTilebarCorners() {
7064 return IsChromeWindowTitlebar() && mSizeMode == nsSizeMode_Normal &&
7065 !mIsTiled;
7066}
7067
7068void nsWindow::ResizeTransparencyBitmap() {
7069 if (!mTransparencyBitmap) {
7070 return;
7071 }
7072
7073 if (mBounds.width == mTransparencyBitmapWidth &&
7074 mBounds.height == mTransparencyBitmapHeight) {
7075 return;
7076 }
7077
7078 int32_t newRowBytes = GetBitmapStride(mBounds.width);
7079 int32_t newSize = newRowBytes * mBounds.height;
7080 auto* newBits = new gchar[newSize];
7081 // fill new mask with "transparent", first
7082 memset(newBits, 0, newSize);
7083
7084 // Now copy the intersection of the old and new areas into the new mask
7085 int32_t copyWidth = std::min(mBounds.width, mTransparencyBitmapWidth);
7086 int32_t copyHeight = std::min(mBounds.height, mTransparencyBitmapHeight);
7087 int32_t oldRowBytes = GetBitmapStride(mTransparencyBitmapWidth);
7088 int32_t copyBytes = GetBitmapStride(copyWidth);
7089
7090 int32_t i;
7091 gchar* fromPtr = mTransparencyBitmap;
7092 gchar* toPtr = newBits;
7093 for (i = 0; i < copyHeight; i++) {
7094 memcpy(toPtr, fromPtr, copyBytes);
7095 fromPtr += oldRowBytes;
7096 toPtr += newRowBytes;
7097 }
7098
7099 delete[] mTransparencyBitmap;
7100 mTransparencyBitmap = newBits;
7101 mTransparencyBitmapWidth = mBounds.width;
7102 mTransparencyBitmapHeight = mBounds.height;
7103}
7104
7105static bool ChangedMaskBits(gchar* aMaskBits, int32_t aMaskWidth,
7106 int32_t aMaskHeight, const nsIntRect& aRect,
7107 uint8_t* aAlphas, int32_t aStride) {
7108 int32_t x, y, xMax = aRect.XMost(), yMax = aRect.YMost();
7109 int32_t maskBytesPerRow = GetBitmapStride(aMaskWidth);
7110 for (y = aRect.y; y < yMax; y++) {
7111 gchar* maskBytes = aMaskBits + y * maskBytesPerRow;
7112 uint8_t* alphas = aAlphas;
7113 for (x = aRect.x; x < xMax; x++) {
7114 bool newBit = *alphas > 0x7f;
7115 alphas++;
7116
7117 gchar maskByte = maskBytes[x >> 3];
7118 bool maskBit = (maskByte & (1 << (x & 7))) != 0;
7119
7120 if (maskBit != newBit) {
7121 return true;
7122 }
7123 }
7124 aAlphas += aStride;
7125 }
7126
7127 return false;
7128}
7129
7130static void UpdateMaskBits(gchar* aMaskBits, int32_t aMaskWidth,
7131 int32_t aMaskHeight, const nsIntRect& aRect,
7132 uint8_t* aAlphas, int32_t aStride) {
7133 int32_t x, y, xMax = aRect.XMost(), yMax = aRect.YMost();
7134 int32_t maskBytesPerRow = GetBitmapStride(aMaskWidth);
7135 for (y = aRect.y; y < yMax; y++) {
7136 gchar* maskBytes = aMaskBits + y * maskBytesPerRow;
7137 uint8_t* alphas = aAlphas;
7138 for (x = aRect.x; x < xMax; x++) {
7139 bool newBit = *alphas > 0x7f;
7140 alphas++;
7141
7142 gchar mask = 1 << (x & 7);
7143 gchar maskByte = maskBytes[x >> 3];
7144 // Note: '-newBit' turns 0 into 00...00 and 1 into 11...11
7145 maskBytes[x >> 3] = (maskByte & ~mask) | (-newBit & mask);
7146 }
7147 aAlphas += aStride;
7148 }
7149}
7150
7151void nsWindow::ApplyTransparencyBitmap() {
7152#ifdef MOZ_X111
7153 // We use X11 calls where possible, because GDK handles expose events
7154 // for shaped windows in a way that's incompatible with us (Bug 635903).
7155 // It doesn't occur when the shapes are set through X.
7156 Display* xDisplay = GDK_WINDOW_XDISPLAY(mGdkWindow)((gdk_x11_display_get_xdisplay (gdk_window_get_display (mGdkWindow
))))
;
7157 Window xDrawable = GDK_WINDOW_XID(mGdkWindow)(gdk_x11_window_get_xid (mGdkWindow));
7158 Pixmap maskPixmap = XCreateBitmapFromData(
7159 xDisplay, xDrawable, mTransparencyBitmap, mTransparencyBitmapWidth,
7160 mTransparencyBitmapHeight);
7161 XShapeCombineMask(xDisplay, xDrawable, ShapeBounding0, 0, 0, maskPixmap,
7162 ShapeSet0);
7163 XFreePixmap(xDisplay, maskPixmap);
7164#endif // MOZ_X11
7165}
7166
7167void nsWindow::ClearTransparencyBitmap() {
7168 if (!mTransparencyBitmap) {
7169 return;
7170 }
7171
7172 delete[] mTransparencyBitmap;
7173 mTransparencyBitmap = nullptr;
7174 mTransparencyBitmapWidth = 0;
7175 mTransparencyBitmapHeight = 0;
7176
7177 if (!mShell) {
7178 return;
7179 }
7180
7181#ifdef MOZ_X111
7182 if (MOZ_UNLIKELY(!mGdkWindow)(__builtin_expect(!!(!mGdkWindow), 0))) {
7183 return;
7184 }
7185
7186 Display* xDisplay = GDK_WINDOW_XDISPLAY(mGdkWindow)((gdk_x11_display_get_xdisplay (gdk_window_get_display (mGdkWindow
))))
;
7187 Window xWindow = gdk_x11_window_get_xid(mGdkWindow);
7188
7189 XShapeCombineMask(xDisplay, xWindow, ShapeBounding0, 0, 0, X11None0L, ShapeSet0);
7190#endif
7191}
7192
7193nsresult nsWindow::UpdateTranslucentWindowAlphaInternal(const nsIntRect& aRect,
7194 uint8_t* aAlphas,
7195 int32_t aStride) {
7196 NS_ASSERTION(mIsTransparent, "Window is not transparent")do { if (!(mIsTransparent)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Window is not transparent", "mIsTransparent", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7196); MOZ_PretendNoReturn(); } } while (0)
;
7197 NS_ASSERTION(!mTransparencyBitmapForTitlebar,do { if (!(!mTransparencyBitmapForTitlebar)) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "Transparency bitmap is already used for titlebar rendering"
, "!mTransparencyBitmapForTitlebar", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7198); MOZ_PretendNoReturn(); } } while (0)
7198 "Transparency bitmap is already used for titlebar rendering")do { if (!(!mTransparencyBitmapForTitlebar)) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "Transparency bitmap is already used for titlebar rendering"
, "!mTransparencyBitmapForTitlebar", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7198); MOZ_PretendNoReturn(); } } while (0)
;
7199
7200 if (mTransparencyBitmap == nullptr) {
7201 int32_t size = GetBitmapStride(mBounds.width) * mBounds.height;
7202 mTransparencyBitmap = new gchar[size];
7203 memset(mTransparencyBitmap, 255, size);
7204 mTransparencyBitmapWidth = mBounds.width;
7205 mTransparencyBitmapHeight = mBounds.height;
7206 } else {
7207 ResizeTransparencyBitmap();
7208 }
7209
7210 nsIntRect rect;
7211 rect.IntersectRect(aRect, nsIntRect(0, 0, mBounds.width, mBounds.height));
7212
7213 if (!ChangedMaskBits(mTransparencyBitmap, mBounds.width, mBounds.height, rect,
7214 aAlphas, aStride)) {
7215 // skip the expensive stuff if the mask bits haven't changed; hopefully
7216 // this is the common case
7217 return NS_OK;
7218 }
7219
7220 UpdateMaskBits(mTransparencyBitmap, mBounds.width, mBounds.height, rect,
7221 aAlphas, aStride);
7222
7223 if (!mNeedsShow) {
7224 ApplyTransparencyBitmap();
7225 }
7226 return NS_OK;
7227}
7228
7229void nsWindow::UpdateTitlebarTransparencyBitmap() {
7230 NS_ASSERTION(mTransparencyBitmapForTitlebar,do { if (!(mTransparencyBitmapForTitlebar)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Transparency bitmap is already used to draw window shape",
"mTransparencyBitmapForTitlebar", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7231); MOZ_PretendNoReturn(); } } while (0)
7231 "Transparency bitmap is already used to draw window shape")do { if (!(mTransparencyBitmapForTitlebar)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Transparency bitmap is already used to draw window shape",
"mTransparencyBitmapForTitlebar", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 7231); MOZ_PretendNoReturn(); } } while (0)
;
7232
7233 if (!mGdkWindow || !mDrawInTitlebar ||
7234 (mBounds.width == mTransparencyBitmapWidth &&
7235 mBounds.height == mTransparencyBitmapHeight)) {
7236 return;
7237 }
7238
7239 bool maskCreate =
7240 !mTransparencyBitmap || mBounds.width > mTransparencyBitmapWidth;
7241
7242 bool maskUpdate =
7243 !mTransparencyBitmap || mBounds.width != mTransparencyBitmapWidth;
7244
7245 LayoutDeviceIntCoord radius = GetTitlebarRadius();
7246 if (maskCreate) {
7247 delete[] mTransparencyBitmap;
7248 int32_t size = GetBitmapStride(mBounds.width) * radius;
7249 mTransparencyBitmap = new gchar[size];
7250 mTransparencyBitmapWidth = mBounds.width;
7251 } else {
7252 mTransparencyBitmapWidth = mBounds.width;
7253 }
7254 mTransparencyBitmapHeight = mBounds.height;
7255
7256 if (maskUpdate) {
7257 cairo_surface_t* surface = cairo_image_surface_create(
7258 CAIRO_FORMAT_A8, mTransparencyBitmapWidth, radius);
7259 if (!surface) {
7260 return;
7261 }
7262
7263 cairo_t* cr = cairo_create(surface);
7264
7265 GtkWidgetState state;
7266 memset((void*)&state, 0, sizeof(state));
7267 GdkRectangle rect = {0, 0, mTransparencyBitmapWidth, radius};
7268
7269 moz_gtk_widget_paint(MOZ_GTK_HEADER_BAR, cr, &rect, &state, 0,
7270 GTK_TEXT_DIR_NONE);
7271
7272 cairo_destroy(cr);
7273 cairo_surface_mark_dirty(surface);
7274 cairo_surface_flush(surface);
7275
7276 UpdateMaskBits(mTransparencyBitmap, mTransparencyBitmapWidth, radius,
7277 nsIntRect(0, 0, mTransparencyBitmapWidth, radius),
7278 cairo_image_surface_get_data(surface),
7279 cairo_format_stride_for_width(CAIRO_FORMAT_A8,
7280 mTransparencyBitmapWidth));
7281
7282 cairo_surface_destroy(surface);
7283 }
7284
7285#ifdef MOZ_X111
7286 if (!mNeedsShow) {
7287 Display* xDisplay = GDK_WINDOW_XDISPLAY(mGdkWindow)((gdk_x11_display_get_xdisplay (gdk_window_get_display (mGdkWindow
))))
;
7288 Window xDrawable = GDK_WINDOW_XID(mGdkWindow)(gdk_x11_window_get_xid (mGdkWindow));
7289
7290 Pixmap maskPixmap =
7291 XCreateBitmapFromData(xDisplay, xDrawable, mTransparencyBitmap,
7292 mTransparencyBitmapWidth, radius);
7293
7294 XShapeCombineMask(xDisplay, xDrawable, ShapeBounding0, 0, 0, maskPixmap,
7295 ShapeSet0);
7296
7297 if (mTransparencyBitmapHeight > radius) {
7298 XRectangle rect = {0, 0, (unsigned short)mTransparencyBitmapWidth,
7299 (unsigned short)(mTransparencyBitmapHeight - radius)};
7300 XShapeCombineRectangles(xDisplay, xDrawable, ShapeBounding0, 0, radius,
7301 &rect, 1, ShapeUnion1, 0);
7302 }
7303
7304 XFreePixmap(xDisplay, maskPixmap);
7305 }
7306#endif
7307}
7308
7309GtkWidget* nsWindow::GetToplevelWidget() const { return mShell; }
7310
7311GdkWindow* nsWindow::GetToplevelGdkWindow() const {
7312 return gtk_widget_get_window(mShell);
7313}
7314
7315nsWindow* nsWindow::GetContainerWindow() const {
7316 GtkWidget* owningWidget = GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer)))));
7317 if (!owningWidget) {
7318 return nullptr;
7319 }
7320
7321 nsWindow* window = get_window_for_gtk_widget(owningWidget);
7322 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"
, 7322); MOZ_PretendNoReturn(); } } while (0)
;
7323 return window;
7324}
7325
7326void nsWindow::SetUrgencyHint(GtkWidget* top_window, bool state) {
7327 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)
;
7328 if (!top_window) {
7329 return;
7330 }
7331 GdkWindow* window = gtk_widget_get_window(top_window);
7332 if (!window) {
7333 return;
7334 }
7335 // TODO: Use xdg-activation on Wayland?
7336 gdk_window_set_urgency_hint(window, state);
7337}
7338
7339void nsWindow::SetDefaultIcon(void) { SetIcon(u"default"_ns); }
7340
7341gint nsWindow::ConvertBorderStyles(BorderStyle aStyle) {
7342 gint w = 0;
7343
7344 if (aStyle == BorderStyle::Default) {
7345 return -1;
7346 }
7347
7348 // note that we don't handle BorderStyle::Close yet
7349 if (aStyle & BorderStyle::All) w |= GDK_DECOR_ALL;
7350 if (aStyle & BorderStyle::Border) w |= GDK_DECOR_BORDER;
7351 if (aStyle & BorderStyle::ResizeH) w |= GDK_DECOR_RESIZEH;
7352 if (aStyle & BorderStyle::Title) w |= GDK_DECOR_TITLE;
7353 if (aStyle & BorderStyle::Menu) w |= GDK_DECOR_MENU;
7354 if (aStyle & BorderStyle::Minimize) w |= GDK_DECOR_MINIMIZE;
7355 if (aStyle & BorderStyle::Maximize) w |= GDK_DECOR_MAXIMIZE;
7356
7357 return w;
7358}
7359
7360class FullscreenTransitionWindow final : public nsISupports {
7361 public:
7362 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:
7363
7364 explicit FullscreenTransitionWindow(GtkWidget* aWidget);
7365
7366 GtkWidget* mWindow;
7367
7368 private:
7369 ~FullscreenTransitionWindow();
7370};
7371
7372NS_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"
, 7372); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
7372; __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"
, 7372); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"FullscreenTransitionWindow\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 7372; __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"
, 7372); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 7372
; __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"
, 7372); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"FullscreenTransitionWindow\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 7372; __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"
, 7372); 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; }
7373
7374FullscreenTransitionWindow::FullscreenTransitionWindow(GtkWidget* aWidget) {
7375 mWindow = gtk_window_new(GTK_WINDOW_POPUP);
7376 GtkWindow* gtkWin = GTK_WINDOW(mWindow)((((GtkWindow*) (void *) ((mWindow)))));
7377
7378 gtk_window_set_type_hint(gtkWin, GDK_WINDOW_TYPE_HINT_SPLASHSCREEN);
7379 GtkWindowSetTransientFor(gtkWin, GTK_WINDOW(aWidget)((((GtkWindow*) (void *) ((aWidget))))));
7380 gtk_window_set_decorated(gtkWin, false);
7381
7382 GdkWindow* gdkWin = gtk_widget_get_window(aWidget);
7383 GdkScreen* screen = gtk_widget_get_screen(aWidget);
7384 gint monitorNum = gdk_screen_get_monitor_at_window(screen, gdkWin);
7385 GdkRectangle monitorRect;
7386 gdk_screen_get_monitor_geometry(screen, monitorNum, &monitorRect);
7387 gtk_window_set_screen(gtkWin, screen);
7388 gtk_window_move(gtkWin, monitorRect.x, monitorRect.y);
7389 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"
, 7390); AnnotateMozCrashReason("MOZ_ASSERT" "(" "monitorRect.width > 0 && monitorRect.height > 0"
") (" "Can't resize window smaller than 1x1." ")"); do { *((
volatile int*)__null) = 7390; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
7390 "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"
, 7390); AnnotateMozCrashReason("MOZ_ASSERT" "(" "monitorRect.width > 0 && monitorRect.height > 0"
") (" "Can't resize window smaller than 1x1." ")"); do { *((
volatile int*)__null) = 7390; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
7391 gtk_window_resize(gtkWin, monitorRect.width, monitorRect.height);
7392
7393 GdkRGBA bgColor;
7394 bgColor.red = bgColor.green = bgColor.blue = 0.0;
7395 bgColor.alpha = 1.0;
7396 gtk_widget_override_background_color(mWindow, GTK_STATE_FLAG_NORMAL,
7397 &bgColor);
7398
7399 gtk_widget_set_opacity(mWindow, 0.0);
7400 gtk_widget_show(mWindow);
7401}
7402
7403FullscreenTransitionWindow::~FullscreenTransitionWindow() {
7404 gtk_widget_destroy(mWindow);
7405}
7406
7407class FullscreenTransitionData {
7408 public:
7409 FullscreenTransitionData(nsIWidget::FullscreenTransitionStage aStage,
7410 uint16_t aDuration, nsIRunnable* aCallback,
7411 FullscreenTransitionWindow* aWindow)
7412 : mStage(aStage),
7413 mStartTime(TimeStamp::Now()),
7414 mDuration(TimeDuration::FromMilliseconds(aDuration)),
7415 mCallback(aCallback),
7416 mWindow(aWindow) {}
7417
7418 static const guint sInterval = 1000 / 30; // 30fps
7419 static gboolean TimeoutCallback(gpointer aData);
7420
7421 private:
7422 nsIWidget::FullscreenTransitionStage mStage;
7423 TimeStamp mStartTime;
7424 TimeDuration mDuration;
7425 nsCOMPtr<nsIRunnable> mCallback;
7426 RefPtr<FullscreenTransitionWindow> mWindow;
7427};
7428
7429/* static */
7430gboolean FullscreenTransitionData::TimeoutCallback(gpointer aData) {
7431 bool finishing = false;
7432 auto* data = static_cast<FullscreenTransitionData*>(aData);
7433 gdouble opacity = (TimeStamp::Now() - data->mStartTime) / data->mDuration;
7434 if (opacity >= 1.0) {
7435 opacity = 1.0;
7436 finishing = true;
7437 }
7438 if (data->mStage == nsIWidget::eAfterFullscreenToggle) {
7439 opacity = 1.0 - opacity;
7440 }
7441 gtk_widget_set_opacity(data->mWindow->mWindow, opacity);
7442
7443 if (!finishing) {
7444 return TRUE(!(0));
7445 }
7446 NS_DispatchToMainThread(data->mCallback.forget());
7447 delete data;
7448 return FALSE(0);
7449}
7450
7451/* virtual */
7452bool nsWindow::PrepareForFullscreenTransition(nsISupports** aData) {
7453 if (!mCompositedScreen) {
7454 return false;
7455 }
7456 *aData = do_AddRef(new FullscreenTransitionWindow(mShell)).take();
7457 return true;
7458}
7459
7460/* virtual */
7461void nsWindow::PerformFullscreenTransition(FullscreenTransitionStage aStage,
7462 uint16_t aDuration,
7463 nsISupports* aData,
7464 nsIRunnable* aCallback) {
7465 auto* data = static_cast<FullscreenTransitionWindow*>(aData);
7466 // This will be released at the end of the last timeout callback for it.
7467 auto* transitionData =
7468 new FullscreenTransitionData(aStage, aDuration, aCallback, data);
7469 g_timeout_add_full(G_PRIORITY_HIGH-100, FullscreenTransitionData::sInterval,
7470 FullscreenTransitionData::TimeoutCallback, transitionData,
7471 nullptr);
7472}
7473
7474already_AddRefed<widget::Screen> nsWindow::GetWidgetScreen() {
7475 // Wayland can read screen directly
7476 if (GdkIsWaylandDisplay()) {
7477 if (RefPtr<Screen> screen = ScreenHelperGTK::GetScreenForWindow(this)) {
7478 return screen.forget();
7479 }
7480 }
7481
7482 // GetScreenBounds() is slow for the GTK port so we override and use
7483 // mBounds directly.
7484 ScreenManager& screenManager = ScreenManager::GetSingleton();
7485 LayoutDeviceIntRect bounds = mBounds;
7486 DesktopIntRect deskBounds = RoundedToInt(bounds / GetDesktopToDeviceScale());
7487 return screenManager.ScreenForRect(deskBounds);
7488}
7489
7490RefPtr<VsyncDispatcher> nsWindow::GetVsyncDispatcher() {
7491#ifdef MOZ_WAYLAND1
7492 if (mWaylandVsyncDispatcher) {
7493 return mWaylandVsyncDispatcher;
7494 }
7495#endif
7496 return nullptr;
7497}
7498
7499bool nsWindow::SynchronouslyRepaintOnResize() {
7500 if (GdkIsWaylandDisplay()) {
7501 // See Bug 1734368
7502 // Don't request synchronous repaint on HW accelerated backend - mesa can be
7503 // deadlocked when it's missing back buffer and main event loop is blocked.
7504 return false;
7505 }
7506
7507 // default is synced repaint.
7508 return true;
7509}
7510
7511void nsWindow::KioskLockOnMonitor() {
7512 // Available as of GTK 3.18+
7513 static auto sGdkWindowFullscreenOnMonitor =
7514 (void (*)(GdkWindow* window, gint monitor))dlsym(
7515 RTLD_DEFAULT((void *) 0), "gdk_window_fullscreen_on_monitor");
7516
7517 if (!sGdkWindowFullscreenOnMonitor) {
7518 return;
7519 }
7520
7521 int monitor = mKioskMonitor.value();
7522 if (monitor < 0 || monitor >= ScreenHelperGTK::GetMonitorCount()) {
7523 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)
;
7524 return;
7525 }
7526
7527 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)
;
7528 sGdkWindowFullscreenOnMonitor(GetToplevelGdkWindow(), monitor);
7529}
7530
7531static bool IsFullscreenSupported(GtkWidget* aShell) {
7532#ifdef MOZ_X111
7533 GdkScreen* screen = gtk_widget_get_screen(aShell);
7534 GdkAtom atom = gdk_atom_intern("_NET_WM_STATE_FULLSCREEN", FALSE(0));
7535 return gdk_x11_screen_supports_net_wm_hint(screen, atom);
7536#else
7537 return true;
7538#endif
7539}
7540
7541nsresult nsWindow::MakeFullScreen(bool aFullScreen) {
7542 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)
;
7543
7544 if (GdkIsX11Display() && !IsFullscreenSupported(mShell)) {
7545 return NS_ERROR_NOT_AVAILABLE;
7546 }
7547
7548 if (aFullScreen) {
7549 if (mSizeMode != nsSizeMode_Fullscreen &&
7550 mSizeMode != nsSizeMode_Minimized) {
7551 mLastSizeModeBeforeFullscreen = mSizeMode;
7552 }
7553 if (mIsPIPWindow) {
7554 gtk_window_set_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), GDK_WINDOW_TYPE_HINT_NORMAL);
7555 if (gUseAspectRatio) {
7556 mAspectRatioSaved = mAspectRatio;
7557 mAspectRatio = 0.0f;
7558 ApplySizeConstraints();
7559 }
7560 }
7561
7562 if (mKioskMonitor.isSome()) {
7563 KioskLockOnMonitor();
7564 } else {
7565 gtk_window_fullscreen(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
7566 }
7567 } else {
7568 // Kiosk mode always use fullscreen mode.
7569 if (gKioskMode) {
7570 return NS_ERROR_NOT_AVAILABLE;
7571 }
7572
7573 gtk_window_unfullscreen(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))));
7574
7575 if (mIsPIPWindow && gUseAspectRatio) {
7576 mAspectRatio = mAspectRatioSaved;
7577 // ApplySizeConstraints();
7578 }
7579 }
7580
7581 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"
, 7581); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mLastSizeModeBeforeFullscreen != nsSizeMode_Fullscreen"
")"); do { *((volatile int*)__null) = 7581; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
7582 return NS_OK;
7583}
7584
7585void nsWindow::SetWindowDecoration(BorderStyle aStyle) {
7586 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)
;
7587
7588 // We can't use mGdkWindow directly here as it can be
7589 // derived from mContainer which is not a top-level GdkWindow.
7590 GdkWindow* window = GetToplevelGdkWindow();
7591
7592 // Sawfish, metacity, and presumably other window managers get
7593 // confused if we change the window decorations while the window
7594 // is visible.
7595 bool wasVisible = false;
7596 if (gdk_window_is_visible(window)) {
7597 gdk_window_hide(window);
7598 wasVisible = true;
7599 }
7600
7601 gint wmd = ConvertBorderStyles(aStyle);
7602 if (wmd != -1) gdk_window_set_decorations(window, (GdkWMDecoration)wmd);
7603
7604 if (wasVisible) gdk_window_show(window);
7605
7606 // For some window managers, adding or removing window decorations
7607 // requires unmapping and remapping our toplevel window. Go ahead
7608 // and flush the queue here so that we don't end up with a BadWindow
7609 // error later when this happens (when the persistence timer fires
7610 // and GetWindowPos is called)
7611#ifdef MOZ_X111
7612 if (GdkIsX11Display()) {
7613 XSync(GDK_DISPLAY_XDISPLAY(gdk_display_get_default())(gdk_x11_display_get_xdisplay (gdk_display_get_default())), X11False0);
7614 } else
7615#endif /* MOZ_X11 */
7616 {
7617 gdk_flush();
7618 }
7619}
7620
7621void nsWindow::HideWindowChrome(bool aShouldHide) {
7622 SetWindowDecoration(aShouldHide ? BorderStyle::None : mBorderStyle);
7623}
7624
7625bool nsWindow::CheckForRollup(gdouble aMouseX, gdouble aMouseY, bool aIsWheel,
7626 bool aAlwaysRollup) {
7627 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)
;
7628 nsIRollupListener* rollupListener = GetActiveRollupListener();
7629 nsCOMPtr<nsIWidget> rollupWidget;
7630 if (rollupListener) {
7631 rollupWidget = rollupListener->GetRollupWidget();
7632 }
7633 if (!rollupWidget) {
7634 return false;
7635 }
7636
7637 auto* rollupWindow =
7638 (GdkWindow*)rollupWidget->GetNativeData(NS_NATIVE_WINDOW0);
7639 if (!aAlwaysRollup && is_mouse_in_window(rollupWindow, aMouseX, aMouseY)) {
7640 return false;
7641 }
7642 bool retVal = false;
7643 if (aIsWheel) {
7644 retVal = rollupListener->ShouldConsumeOnMouseWheelEvent();
7645 if (!rollupListener->ShouldRollupOnMouseWheelEvent()) {
7646 return retVal;
7647 }
7648 }
7649 LayoutDeviceIntPoint point;
7650 nsIRollupListener::RollupOptions options{0,
7651 nsIRollupListener::FlushViews::Yes};
7652 // if we're dealing with menus, we probably have submenus and
7653 // we don't want to rollup if the click is in a parent menu of
7654 // the current submenu
7655 if (!aAlwaysRollup) {
7656 AutoTArray<nsIWidget*, 5> widgetChain;
7657 uint32_t sameTypeCount =
7658 rollupListener->GetSubmenuWidgetChain(&widgetChain);
7659 for (unsigned long i = 0; i < widgetChain.Length(); ++i) {
7660 nsIWidget* widget = widgetChain[i];
7661 auto* currWindow = (GdkWindow*)widget->GetNativeData(NS_NATIVE_WINDOW0);
7662 if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) {
7663 // Don't roll up if the mouse event occurred within a menu of the same
7664 // type.
7665 // If the mouse event occurred in a menu higher than that, roll up, but
7666 // pass the number of popups to Rollup so that only those of the same
7667 // type close up.
7668 if (i < sameTypeCount) {
7669 return retVal;
7670 }
7671 options.mCount = sameTypeCount;
7672 break;
7673 }
7674 } // foreach parent menu widget
7675 if (!aIsWheel) {
7676 point = GdkEventCoordsToDevicePixels(aMouseX, aMouseY);
7677 options.mPoint = &point;
7678 }
7679 }
7680
7681 if (mSizeMode == nsSizeMode_Minimized) {
7682 // When we try to rollup in a minimized window, transitionend events for
7683 // panels might not fire and thus we might not hide the popup after all,
7684 // see bug 1810797.
7685 options.mAllowAnimations = nsIRollupListener::AllowAnimations::No;
7686 }
7687
7688 if (rollupListener->Rollup(options)) {
7689 retVal = true;
7690 }
7691 return retVal;
7692}
7693
7694bool nsWindow::DragInProgress() {
7695 nsCOMPtr<nsIDragService> dragService =
7696 do_GetService("@mozilla.org/widget/dragservice;1");
7697 if (!dragService) {
7698 return false;
7699 }
7700
7701 nsCOMPtr<nsIDragSession> currentDragSession =
7702 dragService->GetCurrentSession(this);
7703 return !!currentDragSession;
7704}
7705
7706// This is an ugly workaround for
7707// https://bugzilla.mozilla.org/show_bug.cgi?id=1622107
7708// We try to detect when Wayland compositor / gtk fails to deliver
7709// info about finished D&D operations and cancel it on our own.
7710MOZ_CAN_RUN_SCRIPT static void WaylandDragWorkaround(nsWindow* aWindow,
7711 GdkEventButton* aEvent) {
7712 static int buttonPressCountWithDrag = 0;
7713
7714 // We track only left button state as Firefox performs D&D on left
7715 // button only.
7716 if (aEvent->button != 1 || aEvent->type != GDK_BUTTON_PRESS) {
7717 return;
7718 }
7719
7720 nsCOMPtr<nsIDragService> dragService =
7721 do_GetService("@mozilla.org/widget/dragservice;1");
7722 if (!dragService) {
7723 return;
7724 }
7725 nsCOMPtr<nsIDragSession> currentDragSession =
7726 dragService->GetCurrentSession(aWindow);
7727
7728 if (!currentDragSession) {
7729 buttonPressCountWithDrag = 0;
7730 return;
7731 }
7732
7733 buttonPressCountWithDrag++;
7734 if (buttonPressCountWithDrag > 1) {
7735 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"
, 7737)
7736 "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"
, 7737)
7737 "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"
, 7737)
;
7738 buttonPressCountWithDrag = 0;
7739 currentDragSession->EndDragSession(false, 0);
7740 }
7741}
7742
7743static nsWindow* get_window_for_gtk_widget(GtkWidget* widget) {
7744 gpointer user_data = g_object_get_data(G_OBJECT(widget)((((GObject*) (void *) ((widget))))), "nsWindow");
7745 return static_cast<nsWindow*>(user_data);
7746}
7747
7748static nsWindow* get_window_for_gdk_window(GdkWindow* window) {
7749 gpointer user_data = g_object_get_data(G_OBJECT(window)((((GObject*) (void *) ((window))))), "nsWindow");
7750 return static_cast<nsWindow*>(user_data);
7751}
7752
7753static bool is_mouse_in_window(GdkWindow* aWindow, gdouble aMouseX,
7754 gdouble aMouseY) {
7755 GdkWindow* window = aWindow;
7756 if (!window) {
7757 return false;
7758 }
7759
7760 gint x = 0;
7761 gint y = 0;
7762
7763 {
7764 gint offsetX = 0;
7765 gint offsetY = 0;
7766
7767 while (window) {
7768 gint tmpX = 0;
7769 gint tmpY = 0;
7770
7771 gdk_window_get_position(window, &tmpX, &tmpY);
7772 GtkWidget* widget = get_gtk_widget_for_gdk_window(window);
7773
7774 // if this is a window, compute x and y given its origin and our
7775 // offset
7776 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; }))))
) {
7777 x = tmpX + offsetX;
7778 y = tmpY + offsetY;
7779 break;
7780 }
7781
7782 offsetX += tmpX;
7783 offsetY += tmpY;
7784 window = gdk_window_get_parent(window);
7785 }
7786 }
7787
7788 gint margin = 0;
7789 if (nsWindow* w = get_window_for_gdk_window(aWindow)) {
7790 margin = w->GetInputRegionMarginInGdkCoords();
7791 }
7792
7793 x += margin;
7794 y += margin;
7795
7796 gint w = gdk_window_get_width(aWindow) - margin;
7797 gint h = gdk_window_get_height(aWindow) - margin;
7798
7799 return aMouseX > x && aMouseX < x + w && aMouseY > y && aMouseY < y + h;
7800}
7801
7802static GtkWidget* get_gtk_widget_for_gdk_window(GdkWindow* window) {
7803 gpointer user_data = nullptr;
7804 gdk_window_get_user_data(window, &user_data);
7805
7806 return GTK_WIDGET(user_data)((((GtkWidget*) (void *) ((user_data)))));
7807}
7808
7809static GdkCursor* get_gtk_cursor_from_type(uint8_t aCursorType) {
7810 GdkDisplay* defaultDisplay = gdk_display_get_default();
7811 GdkCursor* gdkcursor = nullptr;
7812
7813 // GtkCursors are defined at nsGtkCursors.h
7814 if (aCursorType > MOZ_CURSOR_NONE) {
7815 return nullptr;
7816 }
7817
7818 // If by now we don't have a xcursor, this means we have to make a custom
7819 // one. First, we try creating a named cursor based on the hash of our
7820 // custom bitmap, as libXcursor has some magic to convert bitmapped cursors
7821 // to themed cursors
7822 if (GtkCursors[aCursorType].hash) {
7823 gdkcursor =
7824 gdk_cursor_new_from_name(defaultDisplay, GtkCursors[aCursorType].hash);
7825 if (gdkcursor) {
7826 return gdkcursor;
7827 }
7828 }
7829
7830 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)
7831 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)
;
7832
7833 // If we still don't have a xcursor, we now really create a bitmap cursor
7834 GdkPixbuf* cursor_pixbuf =
7835 gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE(!(0)), 8, 32, 32);
7836 if (!cursor_pixbuf) {
7837 return nullptr;
7838 }
7839
7840 guchar* data = gdk_pixbuf_get_pixels(cursor_pixbuf);
7841
7842 // Read data from GtkCursors and compose RGBA surface from 1bit bitmap and
7843 // mask GtkCursors bits and mask are 32x32 monochrome bitmaps (1 bit for
7844 // each pixel) so it's 128 byte array (4 bytes for are one bitmap row and
7845 // there are 32 rows here).
7846 const unsigned char* bits = GtkCursors[aCursorType].bits;
7847 const unsigned char* mask_bits = GtkCursors[aCursorType].mask_bits;
7848
7849 for (int i = 0; i < 128; i++) {
7850 char bit = (char)*bits++;
7851 char mask = (char)*mask_bits++;
7852 for (int j = 0; j < 8; j++) {
7853 unsigned char pix = ~(((bit >> j) & 0x01) * 0xff);
7854 *data++ = pix;
7855 *data++ = pix;
7856 *data++ = pix;
7857 *data++ = (((mask >> j) & 0x01) * 0xff);
7858 }
7859 }
7860
7861 gdkcursor = gdk_cursor_new_from_pixbuf(
7862 gdk_display_get_default(), cursor_pixbuf, GtkCursors[aCursorType].hot_x,
7863 GtkCursors[aCursorType].hot_y);
7864
7865 g_object_unref(cursor_pixbuf);
7866 return gdkcursor;
7867}
7868
7869static GdkCursor* get_gtk_cursor_legacy(nsCursor aCursor) {
7870 GdkCursor* gdkcursor = nullptr;
7871 Maybe<uint8_t> fallbackType;
7872
7873 GdkDisplay* defaultDisplay = gdk_display_get_default();
7874
7875 // The strategy here is to use standard GDK cursors, and, if not available,
7876 // load by standard name with gdk_cursor_new_from_name.
7877 // Spec is here: http://www.freedesktop.org/wiki/Specifications/cursor-spec/
7878 switch (aCursor) {
7879 case eCursor_standard:
7880 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_LEFT_PTR);
7881 break;
7882 case eCursor_wait:
7883 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_WATCH);
7884 break;
7885 case eCursor_select:
7886 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_XTERM);
7887 break;
7888 case eCursor_hyperlink:
7889 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_HAND2);
7890 break;
7891 case eCursor_n_resize:
7892 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_TOP_SIDE);
7893 break;
7894 case eCursor_s_resize:
7895 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_BOTTOM_SIDE);
7896 break;
7897 case eCursor_w_resize:
7898 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_LEFT_SIDE);
7899 break;
7900 case eCursor_e_resize:
7901 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_RIGHT_SIDE);
7902 break;
7903 case eCursor_nw_resize:
7904 gdkcursor =
7905 gdk_cursor_new_for_display(defaultDisplay, GDK_TOP_LEFT_CORNER);
7906 break;
7907 case eCursor_se_resize:
7908 gdkcursor =
7909 gdk_cursor_new_for_display(defaultDisplay, GDK_BOTTOM_RIGHT_CORNER);
7910 break;
7911 case eCursor_ne_resize:
7912 gdkcursor =
7913 gdk_cursor_new_for_display(defaultDisplay, GDK_TOP_RIGHT_CORNER);
7914 break;
7915 case eCursor_sw_resize:
7916 gdkcursor =
7917 gdk_cursor_new_for_display(defaultDisplay, GDK_BOTTOM_LEFT_CORNER);
7918 break;
7919 case eCursor_crosshair:
7920 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_CROSSHAIR);
7921 break;
7922 case eCursor_move:
7923 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_FLEUR);
7924 break;
7925 case eCursor_help:
7926 gdkcursor =
7927 gdk_cursor_new_for_display(defaultDisplay, GDK_QUESTION_ARROW);
7928 break;
7929 case eCursor_copy: // CSS3
7930 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "copy");
7931 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_COPY);
7932 break;
7933 case eCursor_alias:
7934 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "alias");
7935 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ALIAS);
7936 break;
7937 case eCursor_context_menu:
7938 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "context-menu");
7939 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_CONTEXT_MENU);
7940 break;
7941 case eCursor_cell:
7942 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_PLUS);
7943 break;
7944 // Those two aren’t standardized. Trying both KDE’s and GNOME’s names
7945 case eCursor_grab:
7946 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "openhand");
7947 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_HAND_GRAB);
7948 break;
7949 case eCursor_grabbing:
7950 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "closedhand");
7951 if (!gdkcursor) {
7952 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "grabbing");
7953 }
7954 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_HAND_GRABBING);
7955 break;
7956 case eCursor_spinning:
7957 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "progress");
7958 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_SPINNING);
7959 break;
7960 case eCursor_zoom_in:
7961 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "zoom-in");
7962 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ZOOM_IN);
7963 break;
7964 case eCursor_zoom_out:
7965 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "zoom-out");
7966 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ZOOM_OUT);
7967 break;
7968 case eCursor_not_allowed:
7969 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "not-allowed");
7970 if (!gdkcursor) { // nonstandard, yet common
7971 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "crossed_circle");
7972 }
7973 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NOT_ALLOWED);
7974 break;
7975 case eCursor_no_drop:
7976 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "no-drop");
7977 if (!gdkcursor) { // this nonstandard sequence makes it work on KDE and
7978 // GNOME
7979 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "forbidden");
7980 }
7981 if (!gdkcursor) {
7982 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "circle");
7983 }
7984 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NOT_ALLOWED);
7985 break;
7986 case eCursor_vertical_text:
7987 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "vertical-text");
7988 if (!gdkcursor) {
7989 fallbackType.emplace(MOZ_CURSOR_VERTICAL_TEXT);
7990 }
7991 break;
7992 case eCursor_all_scroll:
7993 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_FLEUR);
7994 break;
7995 case eCursor_nesw_resize:
7996 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "size_bdiag");
7997 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NESW_RESIZE);
7998 break;
7999 case eCursor_nwse_resize:
8000 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "size_fdiag");
8001 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NWSE_RESIZE);
8002 break;
8003 case eCursor_ns_resize:
8004 gdkcursor =
8005 gdk_cursor_new_for_display(defaultDisplay, GDK_SB_V_DOUBLE_ARROW);
8006 break;
8007 case eCursor_ew_resize:
8008 gdkcursor =
8009 gdk_cursor_new_for_display(defaultDisplay, GDK_SB_H_DOUBLE_ARROW);
8010 break;
8011 // Here, two better fitting cursors exist in some cursor themes. Try those
8012 // first
8013 case eCursor_row_resize:
8014 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "split_v");
8015 if (!gdkcursor) {
8016 gdkcursor =
8017 gdk_cursor_new_for_display(defaultDisplay, GDK_SB_V_DOUBLE_ARROW);
8018 }
8019 break;
8020 case eCursor_col_resize:
8021 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "split_h");
8022 if (!gdkcursor) {
8023 gdkcursor =
8024 gdk_cursor_new_for_display(defaultDisplay, GDK_SB_H_DOUBLE_ARROW);
8025 }
8026 break;
8027 case eCursor_none:
8028 fallbackType.emplace(MOZ_CURSOR_NONE);
8029 break;
8030 default:
8031 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"
, 8031); MOZ_PretendNoReturn(); } } while (0)
;
8032 gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_LEFT_PTR);
8033 break;
8034 }
8035
8036 if (!gdkcursor && fallbackType.isSome()) {
8037 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)
8038 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)
;
8039 gdkcursor = get_gtk_cursor_from_type(*fallbackType);
8040 }
8041
8042 return gdkcursor;
8043}
8044
8045static GdkCursor* get_gtk_cursor_from_name(nsCursor aCursor) {
8046 GdkCursor* gdkcursor = nullptr;
8047 Maybe<uint8_t> fallbackType;
8048
8049 GdkDisplay* defaultDisplay = gdk_display_get_default();
8050
8051 switch (aCursor) {
8052 case eCursor_standard:
8053 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "default");
8054 break;
8055 case eCursor_wait:
8056 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "wait");
8057 break;
8058 case eCursor_select:
8059 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "text");
8060 break;
8061 case eCursor_hyperlink:
8062 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "pointer");
8063 break;
8064 case eCursor_n_resize:
8065 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "n-resize");
8066 break;
8067 case eCursor_s_resize:
8068 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "s-resize");
8069 break;
8070 case eCursor_w_resize:
8071 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "w-resize");
8072 break;
8073 case eCursor_e_resize:
8074 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "e-resize");
8075 break;
8076 case eCursor_nw_resize:
8077 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "nw-resize");
8078 break;
8079 case eCursor_se_resize:
8080 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "se-resize");
8081 break;
8082 case eCursor_ne_resize:
8083 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "ne-resize");
8084 break;
8085 case eCursor_sw_resize:
8086 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "sw-resize");
8087 break;
8088 case eCursor_crosshair:
8089 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "crosshair");
8090 break;
8091 case eCursor_move:
8092 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "move");
8093 break;
8094 case eCursor_help:
8095 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "help");
8096 break;
8097 case eCursor_copy:
8098 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "copy");
8099 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_COPY);
8100 break;
8101 case eCursor_alias:
8102 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "alias");
8103 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ALIAS);
8104 break;
8105 case eCursor_context_menu:
8106 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "context-menu");
8107 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_CONTEXT_MENU);
8108 break;
8109 case eCursor_cell:
8110 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "cell");
8111 break;
8112 case eCursor_grab:
8113 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "grab");
8114 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_HAND_GRAB);
8115 break;
8116 case eCursor_grabbing:
8117 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "grabbing");
8118 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_HAND_GRABBING);
8119 break;
8120 case eCursor_spinning:
8121 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "progress");
8122 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_SPINNING);
8123 break;
8124 case eCursor_zoom_in:
8125 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "zoom-in");
8126 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ZOOM_IN);
8127 break;
8128 case eCursor_zoom_out:
8129 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "zoom-out");
8130 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_ZOOM_OUT);
8131 break;
8132 case eCursor_not_allowed:
8133 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "not-allowed");
8134 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NOT_ALLOWED);
8135 break;
8136 case eCursor_no_drop:
8137 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "no-drop");
8138 if (!gdkcursor) { // this nonstandard sequence makes it work on KDE and
8139 // GNOME
8140 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "forbidden");
8141 }
8142 if (!gdkcursor) {
8143 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "circle");
8144 }
8145 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NOT_ALLOWED);
8146 break;
8147 case eCursor_vertical_text:
8148 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "vertical-text");
8149 if (!gdkcursor) {
8150 fallbackType.emplace(MOZ_CURSOR_VERTICAL_TEXT);
8151 }
8152 break;
8153 case eCursor_all_scroll:
8154 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "move");
8155 break;
8156 case eCursor_nesw_resize:
8157 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "nesw-resize");
8158 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NESW_RESIZE);
8159 break;
8160 case eCursor_nwse_resize:
8161 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "nwse-resize");
8162 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NWSE_RESIZE);
8163 break;
8164 case eCursor_ns_resize:
8165 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "ns-resize");
8166 break;
8167 case eCursor_ew_resize:
8168 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "ew-resize");
8169 break;
8170 case eCursor_row_resize:
8171 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "row-resize");
8172 break;
8173 case eCursor_col_resize:
8174 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "col-resize");
8175 break;
8176 case eCursor_none:
8177 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "none");
8178 if (!gdkcursor) fallbackType.emplace(MOZ_CURSOR_NONE);
8179 break;
8180 default:
8181 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"
, 8181); MOZ_PretendNoReturn(); } } while (0)
;
8182 gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "default");
8183 break;
8184 }
8185
8186 if (!gdkcursor && fallbackType.isSome()) {
8187 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)
8188 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)
;
8189 gdkcursor = get_gtk_cursor_from_type(*fallbackType);
8190 }
8191
8192 return gdkcursor;
8193}
8194
8195static GdkCursor* get_gtk_cursor(nsCursor aCursor) {
8196 GdkCursor* gdkcursor = nullptr;
8197
8198 if ((gdkcursor = gCursorCache[aCursor])) {
8199 return gdkcursor;
8200 }
8201
8202 gdkcursor = StaticPrefs::widget_gtk_legacy_cursors_enabled()
8203 ? get_gtk_cursor_legacy(aCursor)
8204 : get_gtk_cursor_from_name(aCursor);
8205
8206 gCursorCache[aCursor] = gdkcursor;
8207
8208 return gdkcursor;
8209}
8210
8211// gtk callbacks
8212
8213void draw_window_of_widget(GtkWidget* widget, GdkWindow* aWindow, cairo_t* cr) {
8214 if (gtk_cairo_should_draw_window(cr, aWindow)) {
8215 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
8216 if (!window) {
8217 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"
, 8217)
;
8218 } else {
8219 cairo_save(cr);
8220 gtk_cairo_transform_to_window(cr, widget, aWindow);
8221 // TODO - window->OnExposeEvent() can destroy this or other windows,
8222 // do we need to handle it somehow?
8223 window->OnExposeEvent(cr);
8224 cairo_restore(cr);
8225 }
8226 }
8227}
8228
8229/* static */
8230gboolean expose_event_cb(GtkWidget* widget, cairo_t* cr) {
8231 draw_window_of_widget(widget, gtk_widget_get_window(widget), cr);
8232
8233 // A strong reference is already held during "draw" signal emission,
8234 // but GTK+ 3.4 wants the object to live a little longer than that
8235 // (bug 1225970).
8236 g_object_ref(widget);
8237 g_idle_add(
8238 [](gpointer data) -> gboolean {
8239 g_object_unref(data);
8240 return G_SOURCE_REMOVE(0);
8241 },
8242 widget);
8243
8244 return FALSE(0);
8245}
8246
8247static gboolean configure_event_cb(GtkWidget* widget,
8248 GdkEventConfigure* event) {
8249 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
8250 if (!window) {
8251 return FALSE(0);
8252 }
8253
8254 return window->OnConfigureEvent(widget, event);
8255}
8256
8257static void size_allocate_cb(GtkWidget* widget, GtkAllocation* allocation) {
8258 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
8259 if (!window) {
8260 return;
8261 }
8262
8263 window->OnSizeAllocate(allocation);
8264}
8265
8266static void toplevel_window_size_allocate_cb(GtkWidget* widget,
8267 GtkAllocation* allocation) {
8268 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
8269 if (!window) {
8270 return;
8271 }
8272
8273 // NOTE(emilio): We need to do this here to override GTK's own opaque region
8274 // setting (which would clobber ours).
8275 window->UpdateOpaqueRegionInternal();
8276}
8277
8278static gboolean delete_event_cb(GtkWidget* widget, GdkEventAny* event) {
8279 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
8280 if (!window) {
8281 return FALSE(0);
8282 }
8283
8284 window->OnDeleteEvent();
8285
8286 return TRUE(!(0));
8287}
8288
8289static gboolean enter_notify_event_cb(GtkWidget* widget,
8290 GdkEventCrossing* event) {
8291 RefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
8292 if (!window) {
8293 return TRUE(!(0));
8294 }
8295
8296 // We have stored leave notify - check if it's the correct one and
8297 // fire it before enter notify in such case.
8298 if (sStoredLeaveNotifyEvent) {
8299 auto clearNofityEvent =
8300 MakeScopeExit([&] { sStoredLeaveNotifyEvent = nullptr; });
8301 if (event->x_root == sStoredLeaveNotifyEvent->x_root &&
8302 event->y_root == sStoredLeaveNotifyEvent->y_root &&
8303 window->ApplyEnterLeaveMutterWorkaround()) {
8304 // Enter/Leave notify events has the same coordinates
8305 // and uses know buggy window config.
8306 // Consider it as a bogus one.
8307 return TRUE(!(0));
8308 }
8309 RefPtr<nsWindow> leftWindow =
8310 get_window_for_gdk_window(sStoredLeaveNotifyEvent->window);
8311 if (leftWindow) {
8312 leftWindow->OnLeaveNotifyEvent(sStoredLeaveNotifyEvent.get());
8313 }
8314 }
8315
8316 window->OnEnterNotifyEvent(event);
8317 return TRUE(!(0));
8318}
8319
8320static gboolean leave_notify_event_cb(GtkWidget* widget,
8321 GdkEventCrossing* event) {
8322 RefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
8323 if (!window) {
8324 return TRUE(!(0));
8325 }
8326
8327 if (window->ApplyEnterLeaveMutterWorkaround()) {
8328 // The leave event is potentially wrong, don't fire it now but store
8329 // it for further check at enter_notify_event_cb().
8330 sStoredLeaveNotifyEvent.reset(reinterpret_cast<GdkEventCrossing*>(
8331 gdk_event_copy(reinterpret_cast<GdkEvent*>(event))));
8332 } else {
8333 sStoredLeaveNotifyEvent = nullptr;
8334 window->OnLeaveNotifyEvent(event);
8335 }
8336
8337 return TRUE(!(0));
8338}
8339
8340static nsWindow* GetFirstNSWindowForGDKWindow(GdkWindow* aGdkWindow) {
8341 nsWindow* window;
8342 while (!(window = get_window_for_gdk_window(aGdkWindow))) {
8343 // The event has bubbled to the moz_container widget as passed into each
8344 // caller's *widget parameter, but its corresponding nsWindow is an ancestor
8345 // of the window that we need. Instead, look at event->window and find the
8346 // first ancestor nsWindow of it because event->window may be in a plugin.
8347 aGdkWindow = gdk_window_get_parent(aGdkWindow);
8348 if (!aGdkWindow) {
8349 window = nullptr;
8350 break;
8351 }
8352 }
8353 return window;
8354}
8355
8356static gboolean motion_notify_event_cb(GtkWidget* widget,
8357 GdkEventMotion* event) {
8358 UpdateLastInputEventTime(event);
8359
8360 RefPtr<nsWindow> window = GetFirstNSWindowForGDKWindow(event->window);
8361 if (!window) {
8362 return FALSE(0);
8363 }
8364
8365 window->OnMotionNotifyEvent(event);
8366
8367 return TRUE(!(0));
8368}
8369
8370static gboolean button_press_event_cb(GtkWidget* widget,
8371 GdkEventButton* event) {
8372 UpdateLastInputEventTime(event);
8373
8374 if (event->button == 2 && !StaticPrefs::widget_gtk_middle_click_enabled()) {
8375 return FALSE(0);
8376 }
8377
8378 RefPtr<nsWindow> window = GetFirstNSWindowForGDKWindow(event->window);
8379 if (!window) {
8380 return FALSE(0);
8381 }
8382
8383 window->OnButtonPressEvent(event);
8384
8385 if (GdkIsWaylandDisplay()) {
8386 WaylandDragWorkaround(window, event);
8387 }
8388
8389 return TRUE(!(0));
8390}
8391
8392static gboolean button_release_event_cb(GtkWidget* widget,
8393 GdkEventButton* event) {
8394 UpdateLastInputEventTime(event);
8395
8396 if (event->button == 2 && !StaticPrefs::widget_gtk_middle_click_enabled()) {
8397 return FALSE(0);
8398 }
8399
8400 RefPtr<nsWindow> window = GetFirstNSWindowForGDKWindow(event->window);
8401 if (!window) {
8402 return FALSE(0);
8403 }
8404
8405 window->OnButtonReleaseEvent(event);
8406
8407 return TRUE(!(0));
8408}
8409
8410static gboolean focus_in_event_cb(GtkWidget* widget, GdkEventFocus* event) {
8411 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
8412 if (!window) {
8413 return FALSE(0);
8414 }
8415
8416 window->OnContainerFocusInEvent(event);
8417
8418 return FALSE(0);
8419}
8420
8421static gboolean focus_out_event_cb(GtkWidget* widget, GdkEventFocus* event) {
8422 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
8423 if (!window) {
8424 return FALSE(0);
8425 }
8426
8427 window->OnContainerFocusOutEvent(event);
8428
8429 return FALSE(0);
8430}
8431
8432#ifdef MOZ_X111
8433// For long-lived popup windows that don't really take focus themselves but
8434// may have elements that accept keyboard input when the parent window is
8435// active, focus is handled specially. These windows include noautohide
8436// panels. (This special handling is not necessary for temporary popups where
8437// the keyboard is grabbed.)
8438//
8439// Mousing over or clicking on these windows should not cause them to steal
8440// focus from their parent windows, so, the input field of WM_HINTS is set to
8441// False to request that the window manager not set the input focus to this
8442// window. http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.7
8443//
8444// However, these windows can still receive WM_TAKE_FOCUS messages from the
8445// window manager, so they can still detect when the user has indicated that
8446// they wish to direct keyboard input at these windows. When the window
8447// manager offers focus to these windows (after a mouse over or click, for
8448// example), a request to make the parent window active is issued. When the
8449// parent window becomes active, keyboard events will be received.
8450
8451static GdkFilterReturn popup_take_focus_filter(GdkXEvent* gdk_xevent,
8452 GdkEvent* event, gpointer data) {
8453 auto* xevent = static_cast<XEvent*>(gdk_xevent);
8454 if (xevent->type != ClientMessage33) {
8455 return GDK_FILTER_CONTINUE;
8456 }
8457
8458 XClientMessageEvent& xclient = xevent->xclient;
8459 if (xclient.message_type != gdk_x11_get_xatom_by_name("WM_PROTOCOLS")) {
8460 return GDK_FILTER_CONTINUE;
8461 }
8462
8463 Atom atom = xclient.data.l[0];
8464 if (atom != gdk_x11_get_xatom_by_name("WM_TAKE_FOCUS")) {
8465 return GDK_FILTER_CONTINUE;
8466 }
8467
8468 guint32 timestamp = xclient.data.l[1];
8469
8470 GtkWidget* widget = get_gtk_widget_for_gdk_window(event->any.window);
8471 if (!widget) {
8472 return GDK_FILTER_CONTINUE;
8473 }
8474
8475 GtkWindow* parent = gtk_window_get_transient_for(GTK_WINDOW(widget)((((GtkWindow*) (void *) ((widget))))));
8476 if (!parent) {
8477 return GDK_FILTER_CONTINUE;
8478 }
8479
8480 if (gtk_window_is_active(parent)) {
8481 return GDK_FILTER_REMOVE; // leave input focus on the parent
8482 }
8483
8484 GdkWindow* parent_window = gtk_widget_get_window(GTK_WIDGET(parent)((((GtkWidget*) (void *) ((parent))))));
8485 if (!parent_window) {
8486 return GDK_FILTER_CONTINUE;
8487 }
8488
8489 // In case the parent has not been deiconified.
8490 gdk_window_show_unraised(parent_window);
8491
8492 // Request focus on the parent window.
8493 // Use gdk_window_focus rather than gtk_window_present to avoid
8494 // raising the parent window.
8495 gdk_window_focus(parent_window, timestamp);
8496 return GDK_FILTER_REMOVE;
8497}
8498#endif /* MOZ_X11 */
8499
8500static gboolean key_press_event_cb(GtkWidget* widget, GdkEventKey* event) {
8501 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)
;
8502
8503 UpdateLastInputEventTime(event);
8504
8505 // find the window with focus and dispatch this event to that widget
8506 nsWindow* window = get_window_for_gtk_widget(widget);
8507 if (!window) {
8508 return FALSE(0);
8509 }
8510
8511 RefPtr<nsWindow> focusWindow = gFocusWindow ? gFocusWindow : window;
8512
8513#ifdef MOZ_X111
8514 // Keyboard repeat can cause key press events to queue up when there are
8515 // slow event handlers (bug 301029). Throttle these events by removing
8516 // consecutive pending duplicate KeyPress events to the same window.
8517 // We use the event time of the last one.
8518 // Note: GDK calls XkbSetDetectableAutorepeat so that KeyRelease events
8519 // are generated only when the key is physically released.
8520# define NS_GDKEVENT_MATCH_MASK0x1FFF 0x1FFF // GDK_SHIFT_MASK .. GDK_BUTTON5_MASK
8521 // Our headers undefine X11 KeyPress - let's redefine it here.
8522# ifndef KeyPress2
8523# define KeyPress2 2
8524# endif
8525 GdkDisplay* gdkDisplay = gtk_widget_get_display(widget);
8526 if (GdkIsX11Display(gdkDisplay)) {
8527 Display* dpy = GDK_DISPLAY_XDISPLAY(gdkDisplay)(gdk_x11_display_get_xdisplay (gdkDisplay));
8528 while (XPending(dpy)) {
8529 XEvent next_event;
8530 XPeekEvent(dpy, &next_event);
8531 GdkWindow* nextGdkWindow =
8532 gdk_x11_window_lookup_for_display(gdkDisplay, next_event.xany.window);
8533 if (nextGdkWindow != event->window || next_event.type != KeyPress2 ||
8534 next_event.xkey.keycode != event->hardware_keycode ||
8535 next_event.xkey.state != (event->state & NS_GDKEVENT_MATCH_MASK0x1FFF)) {
8536 break;
8537 }
8538 XNextEvent(dpy, &next_event);
8539 event->time = next_event.xkey.time;
8540 }
8541 }
8542#endif
8543
8544 return focusWindow->OnKeyPressEvent(event);
8545}
8546
8547static gboolean key_release_event_cb(GtkWidget* widget, GdkEventKey* event) {
8548 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)
;
8549
8550 UpdateLastInputEventTime(event);
8551
8552 // find the window with focus and dispatch this event to that widget
8553 nsWindow* window = get_window_for_gtk_widget(widget);
8554 if (!window) {
8555 return FALSE(0);
8556 }
8557
8558 RefPtr<nsWindow> focusWindow = gFocusWindow ? gFocusWindow : window;
8559 return focusWindow->OnKeyReleaseEvent(event);
8560}
8561
8562static gboolean property_notify_event_cb(GtkWidget* aWidget,
8563 GdkEventProperty* aEvent) {
8564 RefPtr<nsWindow> window = get_window_for_gdk_window(aEvent->window);
8565 if (!window) {
8566 return FALSE(0);
8567 }
8568
8569 return window->OnPropertyNotifyEvent(aWidget, aEvent);
8570}
8571
8572static gboolean scroll_event_cb(GtkWidget* widget, GdkEventScroll* event) {
8573 RefPtr<nsWindow> window = GetFirstNSWindowForGDKWindow(event->window);
8574 if (NS_WARN_IF(!window)NS_warn_if_impl(!window, "!window", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 8574)
) {
8575 return FALSE(0);
8576 }
8577
8578 window->OnScrollEvent(event);
8579
8580 return TRUE(!(0));
8581}
8582
8583static gboolean visibility_notify_event_cb(GtkWidget* widget,
8584 GdkEventVisibility* event) {
8585 RefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
8586 if (!window) {
8587 return FALSE(0);
8588 }
8589 window->OnVisibilityNotifyEvent(event->state);
8590 return TRUE(!(0));
8591}
8592
8593static void hierarchy_changed_cb(GtkWidget* widget,
8594 GtkWidget* previous_toplevel) {
8595 GtkWidget* toplevel = gtk_widget_get_toplevel(widget);
8596 GdkWindowState old_window_state = GDK_WINDOW_STATE_WITHDRAWN;
8597 GdkEventWindowState event;
8598
8599 event.new_window_state = GDK_WINDOW_STATE_WITHDRAWN;
8600
8601 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; }
))))
) {
8602 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))
8603 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))
;
8604 GdkWindow* win = gtk_widget_get_window(previous_toplevel);
8605 if (win) {
8606 old_window_state = gdk_window_get_state(win);
8607 }
8608 }
8609
8610 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; }))))
) {
8611 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
)
8612 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
)
;
8613 GdkWindow* win = gtk_widget_get_window(toplevel);
8614 if (win) {
8615 event.new_window_state = gdk_window_get_state(win);
8616 }
8617 }
8618
8619 event.changed_mask =
8620 static_cast<GdkWindowState>(old_window_state ^ event.new_window_state);
8621
8622 if (event.changed_mask) {
8623 event.type = GDK_WINDOW_STATE;
8624 event.window = nullptr;
8625 event.send_event = TRUE(!(0));
8626 window_state_event_cb(widget, &event);
8627 }
8628}
8629
8630static gboolean window_state_event_cb(GtkWidget* widget,
8631 GdkEventWindowState* event) {
8632 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
8633 if (!window) {
8634 return FALSE(0);
8635 }
8636
8637 window->OnWindowStateEvent(widget, event);
8638
8639 return FALSE(0);
8640}
8641
8642static void settings_xft_dpi_changed_cb(GtkSettings* gtk_settings,
8643 GParamSpec* pspec, nsWindow* data) {
8644 RefPtr<nsWindow> window = data;
8645 window->OnDPIChanged();
8646 // Even though the window size in screen pixels has not changed,
8647 // nsViewManager stores the dimensions in app units.
8648 // DispatchResized() updates those.
8649 window->DispatchResized();
8650}
8651
8652static void check_resize_cb(GtkContainer* container, gpointer user_data) {
8653 RefPtr<nsWindow> window = get_window_for_gtk_widget(GTK_WIDGET(container)((((GtkWidget*) (void *) ((container))))));
8654 if (!window) {
8655 return;
8656 }
8657 window->OnCheckResize();
8658}
8659
8660static void screen_composited_changed_cb(GdkScreen* screen,
8661 gpointer user_data) {
8662 // This callback can run before gfxPlatform::Init() in rare
8663 // cases involving the profile manager. When this happens,
8664 // we have no reason to reset any compositors as graphics
8665 // hasn't been initialized yet.
8666 if (GPUProcessManager::Get()) {
8667 GPUProcessManager::Get()->ResetCompositors();
8668 }
8669}
8670
8671static void widget_composited_changed_cb(GtkWidget* widget,
8672 gpointer user_data) {
8673 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
8674 if (!window) {
8675 return;
8676 }
8677 window->OnCompositedChanged();
8678}
8679
8680static void scale_changed_cb(GtkWidget* widget, GParamSpec* aPSpec,
8681 gpointer aPointer) {
8682 RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
8683 if (!window) {
8684 return;
8685 }
8686
8687 window->OnScaleChanged(/* aNotify = */ true);
8688}
8689
8690static gboolean touch_event_cb(GtkWidget* aWidget, GdkEventTouch* aEvent) {
8691 UpdateLastInputEventTime(aEvent);
8692
8693 RefPtr<nsWindow> window = GetFirstNSWindowForGDKWindow(aEvent->window);
8694 if (!window) {
8695 return FALSE(0);
8696 }
8697
8698 return window->OnTouchEvent(aEvent);
8699}
8700
8701// This function called generic because there is no signal specific to touchpad
8702// pinch events.
8703static gboolean generic_event_cb(GtkWidget* widget, GdkEvent* aEvent) {
8704 if (aEvent->type != GDK_TOUCHPAD_PINCH) {
8705 return FALSE(0);
8706 }
8707 // Using reinterpret_cast because the touchpad_pinch field of GdkEvent is not
8708 // available in GTK+ versions lower than v3.18
8709 GdkEventTouchpadPinch* event =
8710 reinterpret_cast<GdkEventTouchpadPinch*>(aEvent);
8711
8712 RefPtr<nsWindow> window = GetFirstNSWindowForGDKWindow(event->window);
8713
8714 if (!window) {
8715 return FALSE(0);
8716 }
8717 return window->OnTouchpadPinchEvent(event);
8718}
8719
8720//////////////////////////////////////////////////////////////////////
8721// These are all of our drag and drop operations
8722
8723void nsWindow::InitDragEvent(WidgetDragEvent& aEvent) {
8724 // set the keyboard modifiers
8725 guint modifierState = KeymapWrapper::GetCurrentModifierState();
8726 KeymapWrapper::InitInputEvent(aEvent, modifierState);
8727}
8728
8729static LayoutDeviceIntPoint GetWindowDropPosition(nsWindow* aWindow, int aX,
8730 int aY) {
8731 // Workaround for Bug 1710344
8732 // Caused by Gtk issue https://gitlab.gnome.org/GNOME/gtk/-/issues/4437
8733 if (aWindow->IsWaylandPopup()) {
8734 int tx = 0, ty = 0;
8735 gdk_window_get_position(aWindow->GetToplevelGdkWindow(), &tx, &ty);
8736 aX += tx;
8737 aY += ty;
8738 }
8739 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)
;
8740 return aWindow->GdkPointToDevicePixels({aX, aY});
8741}
8742
8743gboolean WindowDragMotionHandler(GtkWidget* aWidget,
8744 GdkDragContext* aDragContext, gint aX, gint aY,
8745 guint aTime) {
8746 RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
8747 if (!window || !window->GetGdkWindow()) {
8748 return FALSE(0);
8749 }
8750
8751 // We're getting aX,aY in mShell coordinates space.
8752 // mContainer is shifted by CSD decorations so translate the coords
8753 // to mContainer space where our content lives.
8754 if (aWidget == window->GetGtkWidget()) {
8755 int x, y;
8756 gdk_window_get_geometry(window->GetGdkWindow(), &x, &y, nullptr, nullptr);
8757 aX -= x;
8758 aY -= y;
8759 }
8760
8761 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)
;
8762
8763 RefPtr<nsDragService> dragService = nsDragService::GetInstance();
8764 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"
, 8764); return (0); } } while (false)
;
8765 nsDragSession* dragSession =
8766 static_cast<nsDragSession*>(dragService->GetCurrentSession(window));
8767 if (!dragSession) {
8768 // This may be the start of an external drag session.
8769 nsIWidget* widget = window;
8770 dragSession =
8771 static_cast<nsDragSession*>(dragService->StartDragSession(widget));
8772 }
8773 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"
, 8773); return (0); } } while (false)
;
8774
8775 nsDragSession::AutoEventLoop loop(dragSession);
8776 if (!dragSession->ScheduleMotionEvent(
8777 window, aDragContext, GetWindowDropPosition(window, aX, aY), aTime)) {
8778 return FALSE(0);
8779 }
8780 return TRUE(!(0));
8781}
8782
8783static gboolean drag_motion_event_cb(GtkWidget* aWidget,
8784 GdkDragContext* aDragContext, gint aX,
8785 gint aY, guint aTime, gpointer aData) {
8786 return WindowDragMotionHandler(aWidget, aDragContext, aX, aY, aTime);
8787}
8788
8789void WindowDragLeaveHandler(GtkWidget* aWidget) {
8790 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)
;
8791
8792 RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
8793 if (!window) {
8794 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)
;
8795 return;
8796 }
8797
8798 RefPtr<nsDragService> dragService = nsDragService::GetInstance();
8799 nsIWidget* widget = window;
8800 nsDragSession* dragSession =
8801 static_cast<nsDragSession*>(dragService->GetCurrentSession(widget));
8802 if (!dragSession) {
8803 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)
;
8804 return;
8805 }
8806
8807 nsDragSession::AutoEventLoop loop(dragSession);
8808
8809 nsWindow* mostRecentDragWindow = dragSession->GetMostRecentDestWindow();
8810 if (!mostRecentDragWindow) {
8811 // This can happen when the target will not accept a drop. A GTK drag
8812 // source sends the leave message to the destination before the
8813 // drag-failed signal on the source widget, but the leave message goes
8814 // via the X server, and so doesn't get processed at least until the
8815 // event loop runs again.
8816 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)
;
8817 return;
8818 }
8819
8820 if (aWidget != window->GetGtkWidget()) {
8821 // When the drag moves between widgets, GTK can send leave signal for
8822 // the old widget after the motion or drop signal for the new widget.
8823 // We'll send the leave event when the motion or drop event is run.
8824 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)
;
8825 return;
8826 }
8827
8828 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)
;
8829 dragSession->ScheduleLeaveEvent();
8830}
8831
8832static void drag_leave_event_cb(GtkWidget* aWidget,
8833 GdkDragContext* aDragContext, guint aTime,
8834 gpointer aData) {
8835 WindowDragLeaveHandler(aWidget);
8836}
8837
8838gboolean WindowDragDropHandler(GtkWidget* aWidget, GdkDragContext* aDragContext,
8839 gint aX, gint aY, guint aTime) {
8840 RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
8841 if (!window || !window->GetGdkWindow()) {
8842 return FALSE(0);
8843 }
8844
8845 // We're getting aX,aY in mShell coordinates space.
8846 // mContainer is shifted by CSD decorations so translate the coords
8847 // to mContainer space where our content lives.
8848 if (aWidget == window->GetGtkWidget()) {
8849 int x, y;
8850 gdk_window_get_geometry(window->GetGdkWindow(), &x, &y, nullptr, nullptr);
8851 aX -= x;
8852 aY -= y;
8853 }
8854
8855 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)
;
8856 RefPtr<nsDragService> dragService = nsDragService::GetInstance();
8857 nsDragSession* dragSession =
8858 static_cast<nsDragSession*>(dragService->GetCurrentSession(window));
8859 nsDragSession::AutoEventLoop loop(dragSession);
8860 return dragSession->ScheduleDropEvent(
8861 window, aDragContext, GetWindowDropPosition(window, aX, aY), aTime);
8862}
8863
8864static gboolean drag_drop_event_cb(GtkWidget* aWidget,
8865 GdkDragContext* aDragContext, gint aX,
8866 gint aY, guint aTime, gpointer aData) {
8867 return WindowDragDropHandler(aWidget, aDragContext, aX, aY, aTime);
8868}
8869
8870static void drag_data_received_event_cb(GtkWidget* aWidget,
8871 GdkDragContext* aDragContext, gint aX,
8872 gint aY,
8873 GtkSelectionData* aSelectionData,
8874 guint aInfo, guint aTime,
8875 gpointer aData) {
8876 RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
8877 if (!window) {
8878 return;
8879 }
8880
8881 window->OnDragDataReceivedEvent(aWidget, aDragContext, aX, aY, aSelectionData,
8882 aInfo, aTime, aData);
8883}
8884
8885static nsresult initialize_prefs(void) {
8886 if (Preferences::HasUserValue("widget.use-aspect-ratio")) {
8887 gUseAspectRatio = Preferences::GetBool("widget.use-aspect-ratio", true);
8888 } else {
8889 gUseAspectRatio = IsGnomeDesktopEnvironment() || IsKdeDesktopEnvironment();
8890 }
8891 return NS_OK;
8892}
8893
8894#ifdef ACCESSIBILITY1
8895void nsWindow::CreateRootAccessible() {
8896 if (!mRootAccessible) {
8897 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)
;
8898 mRootAccessible = GetRootAccessible();
8899 }
8900}
8901
8902void nsWindow::DispatchEventToRootAccessible(uint32_t aEventType) {
8903 if (!a11y::ShouldA11yBeEnabled()) {
8904 return;
8905 }
8906
8907 nsAccessibilityService* accService = GetOrCreateAccService();
8908 if (!accService) {
8909 return;
8910 }
8911
8912 // Get the root document accessible and fire event to it.
8913 a11y::LocalAccessible* acc = GetRootAccessible();
8914 if (acc) {
8915 accService->FireAccessibleEvent(aEventType, acc);
8916 }
8917}
8918
8919void nsWindow::DispatchActivateEventAccessible(void) {
8920 DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_ACTIVATE);
8921}
8922
8923void nsWindow::DispatchDeactivateEventAccessible(void) {
8924 DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_DEACTIVATE);
8925}
8926
8927void nsWindow::DispatchMaximizeEventAccessible(void) {
8928 DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_MAXIMIZE);
8929}
8930
8931void nsWindow::DispatchMinimizeEventAccessible(void) {
8932 DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_MINIMIZE);
8933}
8934
8935void nsWindow::DispatchRestoreEventAccessible(void) {
8936 DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_RESTORE);
8937}
8938
8939#endif /* #ifdef ACCESSIBILITY */
8940
8941void nsWindow::SetInputContext(const InputContext& aContext,
8942 const InputContextAction& aAction) {
8943 if (!mIMContext) {
8944 return;
8945 }
8946 mIMContext->SetInputContext(this, &aContext, &aAction);
8947}
8948
8949InputContext nsWindow::GetInputContext() {
8950 InputContext context;
8951 if (!mIMContext) {
8952 context.mIMEState.mEnabled = IMEEnabled::Disabled;
8953 context.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
8954 } else {
8955 context = mIMContext->GetInputContext();
8956 }
8957 return context;
8958}
8959
8960TextEventDispatcherListener* nsWindow::GetNativeTextEventDispatcherListener() {
8961 if (NS_WARN_IF(!mIMContext)NS_warn_if_impl(!mIMContext, "!mIMContext", "/var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp"
, 8961)
) {
8962 return nullptr;
8963 }
8964 return mIMContext;
8965}
8966
8967bool nsWindow::GetEditCommands(NativeKeyBindingsType aType,
8968 const WidgetKeyboardEvent& aEvent,
8969 nsTArray<CommandInt>& aCommands) {
8970 // Validate the arguments.
8971 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"
, 8971)
) {
8972 return false;
8973 }
8974
8975 Maybe<WritingMode> writingMode;
8976 if (aEvent.NeedsToRemapNavigationKey()) {
8977 if (RefPtr<TextEventDispatcher> dispatcher = GetTextEventDispatcher()) {
8978 writingMode = dispatcher->MaybeQueryWritingModeAtSelection();
8979 }
8980 }
8981
8982 NativeKeyBindings* keyBindings = NativeKeyBindings::GetInstance(aType);
8983 keyBindings->GetEditCommands(aEvent, writingMode, aCommands);
8984 return true;
8985}
8986
8987already_AddRefed<DrawTarget> nsWindow::StartRemoteDrawingInRegion(
8988 const LayoutDeviceIntRegion& aInvalidRegion, BufferMode* aBufferMode) {
8989 return mSurfaceProvider.StartRemoteDrawingInRegion(aInvalidRegion,
8990 aBufferMode);
8991}
8992
8993void nsWindow::EndRemoteDrawingInRegion(
8994 DrawTarget* aDrawTarget, const LayoutDeviceIntRegion& aInvalidRegion) {
8995 mSurfaceProvider.EndRemoteDrawingInRegion(aDrawTarget, aInvalidRegion);
8996}
8997
8998bool nsWindow::GetDragInfo(WidgetMouseEvent* aMouseEvent, GdkWindow** aWindow,
8999 gint* aButton, gint* aRootX, gint* aRootY) {
9000 if (aMouseEvent->mButton != MouseButton::ePrimary) {
9001 // we can only begin a move drag with the left mouse button
9002 return false;
9003 }
9004 *aButton = 1;
9005
9006 // get the gdk window for this widget
9007 GdkWindow* gdk_window = mGdkWindow;
9008 if (!gdk_window) {
9009 return false;
9010 }
9011#ifdef DEBUG1
9012 // GDK_IS_WINDOW(...) expands to a statement-expression, and
9013 // statement-expressions are not allowed in template-argument lists. So we
9014 // have to make the MOZ_ASSERT condition indirect.
9015 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; }))))
) {
9016 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"
, 9016); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"must really be window" ")"); do { *((volatile int*)__null) =
9016; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
9017 }
9018#endif
9019
9020 // find the top-level window
9021 gdk_window = gdk_window_get_toplevel(gdk_window);
9022 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"
, 9022); AnnotateMozCrashReason("MOZ_ASSERT" "(" "gdk_window"
") (" "gdk_window_get_toplevel should not return null" ")");
do { *((volatile int*)__null) = 9022; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9023 *aWindow = gdk_window;
9024
9025 if (!aMouseEvent->mWidget) {
9026 return false;
9027 }
9028
9029#ifdef MOZ_X111
9030 if (GdkIsX11Display()) {
9031 // Workaround for https://bugzilla.gnome.org/show_bug.cgi?id=789054
9032 // To avoid crashes disable double-click on WM without _NET_WM_MOVERESIZE.
9033 // See _should_perform_ewmh_drag() at gdkwindow-x11.c
9034 // XXXsmaug remove this old hack. gtk should be fixed now.
9035 GdkScreen* screen = gdk_window_get_screen(gdk_window);
9036 GdkAtom atom = gdk_atom_intern("_NET_WM_MOVERESIZE", FALSE(0));
9037 if (!gdk_x11_screen_supports_net_wm_hint(screen, atom)) {
9038 static TimeStamp lastTimeStamp;
9039 if (lastTimeStamp != aMouseEvent->mTimeStamp) {
9040 lastTimeStamp = aMouseEvent->mTimeStamp;
9041 } else {
9042 return false;
9043 }
9044 }
9045 }
9046#endif
9047
9048 // FIXME: It would be nice to have the widget position at the time
9049 // of the event, but it's relatively unlikely that the widget has
9050 // moved since the mousedown. (On the other hand, it's quite likely
9051 // that the mouse has moved, which is why we use the mouse position
9052 // from the event.)
9053 LayoutDeviceIntPoint offset = aMouseEvent->mWidget->WidgetToScreenOffset();
9054 *aRootX = aMouseEvent->mRefPoint.x + offset.x;
9055 *aRootY = aMouseEvent->mRefPoint.y + offset.y;
9056
9057 return true;
9058}
9059
9060nsIWidget::WindowRenderer* nsWindow::GetWindowRenderer() {
9061 if (mIsDestroyed) {
9062 // Prevent external code from triggering the re-creation of the
9063 // LayerManager/Compositor during shutdown. Just return what we currently
9064 // have, which is most likely null.
9065 return mWindowRenderer;
9066 }
9067
9068 return nsBaseWidget::GetWindowRenderer();
9069}
9070
9071void nsWindow::DidGetNonBlankPaint() {
9072 if (mGotNonBlankPaint) {
9073 return;
9074 }
9075 mGotNonBlankPaint = true;
9076 if (!mConfiguredClearColor) {
9077 // Nothing to do, we hadn't overridden the clear color.
9078 mConfiguredClearColor = true;
9079 return;
9080 }
9081 // Reset the clear color set in the expose event to transparent.
9082 GetWindowRenderer()->AsWebRender()->WrBridge()->SendSetDefaultClearColor(
9083 NS_TRANSPARENT);
9084}
9085
9086/* nsWindow::SetCompositorWidgetDelegate() sets remote GtkCompositorWidget
9087 * to render into with compositor.
9088 *
9089 * SetCompositorWidgetDelegate(delegate) is called from
9090 * nsBaseWidget::CreateCompositor(), i.e. nsWindow::GetWindowRenderer().
9091 *
9092 * SetCompositorWidgetDelegate(null) is called from
9093 * nsBaseWidget::DestroyCompositor().
9094 */
9095void nsWindow::SetCompositorWidgetDelegate(CompositorWidgetDelegate* delegate) {
9096 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)
9097 "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)
9098 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)
;
9099
9100 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"
, 9100); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "NS_IsMainThread()"
")"); do { *((volatile int*)__null) = 9100; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9101 if (delegate) {
9102 mCompositorWidgetDelegate = delegate->AsPlatformSpecificDelegate();
9103 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"
, 9105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCompositorWidgetDelegate"
") (" "nsWindow::SetCompositorWidgetDelegate called with a "
"non-PlatformCompositorWidgetDelegate" ")"); do { *((volatile
int*)__null) = 9105; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
9104 "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"
, 9105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCompositorWidgetDelegate"
") (" "nsWindow::SetCompositorWidgetDelegate called with a "
"non-PlatformCompositorWidgetDelegate" ")"); do { *((volatile
int*)__null) = 9105; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
9105 "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"
, 9105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCompositorWidgetDelegate"
") (" "nsWindow::SetCompositorWidgetDelegate called with a "
"non-PlatformCompositorWidgetDelegate" ")"); do { *((volatile
int*)__null) = 9105; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
9106 if (mIsMapped) {
9107 ConfigureCompositor();
9108 }
9109 } else {
9110 mCompositorWidgetDelegate = nullptr;
9111 }
9112}
9113
9114nsresult nsWindow::SetNonClientMargins(const LayoutDeviceIntMargin& aMargins) {
9115 SetDrawsInTitlebar(aMargins.top == 0);
9116 return NS_OK;
9117}
9118
9119bool nsWindow::IsAlwaysUndecoratedWindow() const {
9120 if (mIsPIPWindow || gKioskMode) {
9121 return true;
9122 }
9123 if (mWindowType == WindowType::Dialog &&
9124 mBorderStyle != BorderStyle::Default &&
9125 mBorderStyle != BorderStyle::All &&
9126 !(mBorderStyle & BorderStyle::Title) &&
9127 !(mBorderStyle & BorderStyle::ResizeH)) {
9128 return true;
9129 }
9130 return false;
9131}
9132
9133void nsWindow::SetDrawsInTitlebar(bool aState) {
9134 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)
9135 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)
;
9136
9137 if (mGtkWindowDecoration == GTK_DECORATION_NONE ||
9138 aState == mDrawInTitlebar) {
9139 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)
;
9140 return;
9141 }
9142
9143 if (mUndecorated) {
9144 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"
, 9144); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aState" ") ("
"Unexpected decoration request" ")"); do { *((volatile int*)
__null) = 9144; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
9145 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"
, 9145); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!gtk_window_get_decorated(((((GtkWindow*) (void *) ((mShell))))))"
")"); do { *((volatile int*)__null) = 9145; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9146 return;
9147 }
9148
9149 mDrawInTitlebar = aState;
9150
9151 if (mGtkWindowDecoration == GTK_DECORATION_SYSTEM) {
9152 SetWindowDecoration(aState ? BorderStyle::Border : mBorderStyle);
9153 } else if (mGtkWindowDecoration == GTK_DECORATION_CLIENT) {
9154 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)
;
9155
9156 if (!gtk_widget_get_realized(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))))) {
9157 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)
;
9158 gtk_window_set_titlebar(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))),
9159 aState ? gtk_fixed_new() : nullptr);
9160 return;
9161 }
9162
9163 /* Window manager does not support GDK_DECOR_BORDER,
9164 * emulate it by CSD.
9165 *
9166 * gtk_window_set_titlebar() works on unrealized widgets only,
9167 * we need to handle mShell carefully here.
9168 * When CSD is enabled mGdkWindow is owned by mContainer which is good
9169 * as we can't delete our mGdkWindow. To make mShell unrealized while
9170 * mContainer is preserved we temporary reparent mContainer to an
9171 * invisible GtkWindow.
9172 */
9173 bool visible = !mNeedsShow && mIsShown;
9174 if (visible) {
9175 NativeShow(false);
9176 }
9177
9178 // Using GTK_WINDOW_POPUP rather than
9179 // GTK_WINDOW_TOPLEVEL in the hope that POPUP results in less
9180 // initialization and window manager interaction.
9181 GtkWidget* tmpWindow = gtk_window_new(GTK_WINDOW_POPUP);
9182 gtk_widget_realize(tmpWindow);
9183
9184 gtk_widget_reparent(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))), tmpWindow);
9185 gtk_widget_unrealize(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))));
9186
9187 // Add a hidden titlebar widget to trigger CSD, but disable the default
9188 // titlebar. GtkFixed is a somewhat random choice for a simple unused
9189 // widget. gtk_window_set_titlebar() takes ownership of the titlebar
9190 // widget.
9191 gtk_window_set_titlebar(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))),
9192 aState ? gtk_fixed_new() : nullptr);
9193
9194 /* A workaround for https://bugzilla.gnome.org/show_bug.cgi?id=791081
9195 * gtk_widget_realize() throws:
9196 * "In pixman_region32_init_rect: Invalid rectangle passed"
9197 * when mShell has default 1x1 size.
9198 */
9199 GtkAllocation allocation = {0, 0, 0, 0};
9200 gtk_widget_get_preferred_width(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))), nullptr,
9201 &allocation.width);
9202 gtk_widget_get_preferred_height(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))), nullptr,
9203 &allocation.height);
9204 gtk_widget_size_allocate(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))), &allocation);
9205
9206 gtk_widget_realize(GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))));
9207 gtk_widget_reparent(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))), GTK_WIDGET(mShell)((((GtkWidget*) (void *) ((mShell))))));
9208
9209 // Label mShell toplevel window so property_notify_event_cb callback
9210 // can find its way home.
9211 g_object_set_data(G_OBJECT(GetToplevelGdkWindow())((((GObject*) (void *) ((GetToplevelGdkWindow()))))), "nsWindow", this);
9212
9213 if (AreBoundsSane()) {
9214 GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mBounds.Size());
9215 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)
;
9216 gtk_window_resize(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell))))), size.width, size.height);
9217 }
9218
9219 if (visible) {
9220 mNeedsShow = true;
9221 NativeShow(true);
9222 }
9223
9224 gtk_widget_destroy(tmpWindow);
9225 }
9226
9227 if (mTransparencyBitmapForTitlebar) {
9228 if (mDrawInTitlebar && mSizeMode == nsSizeMode_Normal && !mIsTiled) {
9229 UpdateTitlebarTransparencyBitmap();
9230 } else {
9231 ClearTransparencyBitmap();
9232 }
9233 }
9234
9235 // Recompute the input region (which should generally be null, but this is
9236 // enough to work around bug 1844497, which is probably a gtk bug).
9237 SetInputRegion(mInputRegion);
9238}
9239
9240GtkWindow* nsWindow::GetCurrentTopmostWindow() const {
9241 GtkWindow* parentWindow = GTK_WINDOW(GetGtkWidget())((((GtkWindow*) (void *) ((GetGtkWidget())))));
9242 GtkWindow* topmostParentWindow = nullptr;
9243 while (parentWindow) {
9244 topmostParentWindow = parentWindow;
9245 parentWindow = gtk_window_get_transient_for(parentWindow);
9246 }
9247 return topmostParentWindow;
9248}
9249
9250gint nsWindow::GdkCeiledScaleFactor() {
9251 if (IsTopLevelWindowType()) {
9252 return mCeiledScaleFactor;
9253 }
9254 if (nsWindow* topmost = GetTopmostWindow()) {
9255 return topmost->mCeiledScaleFactor;
9256 }
9257 return ScreenHelperGTK::GetGTKMonitorScaleFactor();
9258}
9259
9260double nsWindow::FractionalScaleFactor() {
9261#ifdef MOZ_WAYLAND1
9262 double fractional_scale = [&] {
9263 if (IsTopLevelWindowType()) {
9264 return mFractionalScaleFactor;
9265 }
9266 if (nsWindow* topmost = GetTopmostWindow()) {
9267 return topmost->mFractionalScaleFactor;
9268 }
9269 return 0.0;
9270 }();
9271 if (fractional_scale != 0.0) {
9272 return fractional_scale;
9273 }
9274#endif
9275 return GdkCeiledScaleFactor();
9276}
9277
9278gint nsWindow::DevicePixelsToGdkCoordRoundUp(int aPixels) {
9279 double scale = FractionalScaleFactor();
9280 return ceil(aPixels / scale);
9281}
9282
9283gint nsWindow::DevicePixelsToGdkCoordRoundDown(int aPixels) {
9284 double scale = FractionalScaleFactor();
9285 return floor(aPixels / scale);
9286}
9287
9288GdkPoint nsWindow::DevicePixelsToGdkPointRoundDown(
9289 const LayoutDeviceIntPoint& aPoint) {
9290 double scale = FractionalScaleFactor();
9291 return {int(aPoint.x / scale), int(aPoint.y / scale)};
9292}
9293
9294GdkRectangle nsWindow::DevicePixelsToGdkRectRoundOut(
9295 const LayoutDeviceIntRect& aRect) {
9296 double scale = FractionalScaleFactor();
9297 int x = floor(aRect.x / scale);
9298 int y = floor(aRect.y / scale);
9299 int right = ceil((aRect.x + aRect.width) / scale);
9300 int bottom = ceil((aRect.y + aRect.height) / scale);
9301 return {x, y, right - x, bottom - y};
9302}
9303
9304GdkRectangle nsWindow::DevicePixelsToGdkRectRoundIn(
9305 const LayoutDeviceIntRect& aRect) {
9306 double scale = FractionalScaleFactor();
9307 int x = ceil(aRect.x / scale);
9308 int y = ceil(aRect.y / scale);
9309 int right = floor((aRect.x + aRect.width) / scale);
9310 int bottom = floor((aRect.y + aRect.height) / scale);
9311 return {x, y, std::max(right - x, 0), std::max(bottom - y, 0)};
9312}
9313
9314GdkRectangle nsWindow::DevicePixelsToGdkSizeRoundUp(
9315 const LayoutDeviceIntSize& aSize) {
9316 double scale = FractionalScaleFactor();
9317 gint width = ceil(aSize.width / scale);
9318 gint height = ceil(aSize.height / scale);
9319 return {0, 0, width, height};
9320}
9321
9322int nsWindow::GdkCoordToDevicePixels(gint aCoord) {
9323 return (int)(aCoord * FractionalScaleFactor());
9324}
9325
9326LayoutDeviceIntPoint nsWindow::GdkEventCoordsToDevicePixels(gdouble aX,
9327 gdouble aY) {
9328 double scale = FractionalScaleFactor();
9329 return LayoutDeviceIntPoint::Floor((float)(aX * scale), (float)(aY * scale));
9330}
9331
9332LayoutDeviceIntPoint nsWindow::GdkPointToDevicePixels(const GdkPoint& aPoint) {
9333 double scale = FractionalScaleFactor();
9334 return LayoutDeviceIntPoint::Floor((float)(aPoint.x * scale),
9335 (float)(aPoint.y * scale));
9336}
9337
9338LayoutDeviceIntRect nsWindow::GdkRectToDevicePixels(const GdkRectangle& aRect) {
9339 double scale = FractionalScaleFactor();
9340 return LayoutDeviceIntRect::RoundIn(
9341 (float)(aRect.x * scale), (float)(aRect.y * scale),
9342 (float)(aRect.width * scale), (float)(aRect.height * scale));
9343}
9344
9345nsresult nsWindow::SynthesizeNativeMouseEvent(
9346 LayoutDeviceIntPoint aPoint, NativeMouseMessage aNativeMessage,
9347 MouseButton aButton, nsIWidget::Modifiers aModifierFlags,
9348 nsIObserver* aObserver) {
9349 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)
9350 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)
;
9351
9352 AutoObserverNotifier notifier(aObserver, "mouseevent");
9353
9354 if (!mGdkWindow) {
9355 return NS_OK;
9356 }
9357
9358 // When a button-press/release event is requested, create it here and put it
9359 // in the event queue. This will not emit a motion event - this needs to be
9360 // done explicitly *before* requesting a button-press/release. You will also
9361 // need to wait for the motion event to be dispatched before requesting a
9362 // button-press/release event to maintain the desired event order.
9363 switch (aNativeMessage) {
9364 case NativeMouseMessage::ButtonDown:
9365 case NativeMouseMessage::ButtonUp: {
9366 GdkEvent event;
9367 memset(&event, 0, sizeof(GdkEvent));
9368 event.type = aNativeMessage == NativeMouseMessage::ButtonDown
9369 ? GDK_BUTTON_PRESS
9370 : GDK_BUTTON_RELEASE;
9371 switch (aButton) {
9372 case MouseButton::ePrimary:
9373 case MouseButton::eMiddle:
9374 case MouseButton::eSecondary:
9375 case MouseButton::eX1:
9376 case MouseButton::eX2:
9377 event.button.button = aButton + 1;
9378 break;
9379 default:
9380 return NS_ERROR_INVALID_ARG;
9381 }
9382 event.button.state =
9383 KeymapWrapper::ConvertWidgetModifierToGdkState(aModifierFlags);
9384 event.button.window = mGdkWindow;
9385 event.button.time = GDK_CURRENT_TIME0L;
9386
9387 // Get device for event source
9388 event.button.device = GdkGetPointer();
9389
9390 event.button.x_root = DevicePixelsToGdkCoordRoundDown(aPoint.x);
9391 event.button.y_root = DevicePixelsToGdkCoordRoundDown(aPoint.y);
9392
9393 LayoutDeviceIntPoint pointInWindow = aPoint - WidgetToScreenOffset();
9394 event.button.x = DevicePixelsToGdkCoordRoundDown(pointInWindow.x);
9395 event.button.y = DevicePixelsToGdkCoordRoundDown(pointInWindow.y);
9396
9397 gdk_event_put(&event);
9398 return NS_OK;
9399 }
9400 case NativeMouseMessage::Move: {
9401 // We don't support specific events other than button-press/release. In
9402 // all other cases we'll synthesize a motion event that will be emitted by
9403 // gdk_display_warp_pointer().
9404 // XXX How to activate native modifier for the other events?
9405#ifdef MOZ_WAYLAND1
9406 // Impossible to warp the pointer on Wayland.
9407 // For pointer lock, pointer-constraints and relative-pointer are used.
9408 if (GdkIsWaylandDisplay()) {
9409 return NS_OK;
9410 }
9411#endif
9412 GdkScreen* screen = gdk_window_get_screen(mGdkWindow);
9413 GdkPoint point = DevicePixelsToGdkPointRoundDown(aPoint);
9414 gdk_device_warp(GdkGetPointer(), screen, point.x, point.y);
9415 return NS_OK;
9416 }
9417 case NativeMouseMessage::EnterWindow:
9418 case NativeMouseMessage::LeaveWindow:
9419 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"
, 9419); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "Non supported mouse event on Linux"
")"); do { *((volatile int*)__null) = 9419; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9420 return NS_ERROR_INVALID_ARG;
9421 }
9422 return NS_ERROR_UNEXPECTED;
9423}
9424
9425void nsWindow::CreateAndPutGdkScrollEvent(mozilla::LayoutDeviceIntPoint aPoint,
9426 double aDeltaX, double aDeltaY) {
9427 GdkEvent event;
9428 memset(&event, 0, sizeof(GdkEvent));
9429 event.type = GDK_SCROLL;
9430 event.scroll.window = mGdkWindow;
9431 event.scroll.time = GDK_CURRENT_TIME0L;
9432 // Get device for event source
9433 GdkDisplay* display = gdk_window_get_display(mGdkWindow);
9434 GdkDeviceManager* device_manager = gdk_display_get_device_manager(display);
9435 // See note in nsWindow::SynthesizeNativeTouchpadPan about the device we use
9436 // here.
9437 event.scroll.device = gdk_device_manager_get_client_pointer(device_manager);
9438 event.scroll.x_root = DevicePixelsToGdkCoordRoundDown(aPoint.x);
9439 event.scroll.y_root = DevicePixelsToGdkCoordRoundDown(aPoint.y);
9440
9441 LayoutDeviceIntPoint pointInWindow = aPoint - WidgetToScreenOffset();
9442 event.scroll.x = DevicePixelsToGdkCoordRoundDown(pointInWindow.x);
9443 event.scroll.y = DevicePixelsToGdkCoordRoundDown(pointInWindow.y);
9444
9445 // The delta values are backwards on Linux compared to Windows and Cocoa,
9446 // hence the negation.
9447 event.scroll.direction = GDK_SCROLL_SMOOTH;
9448 event.scroll.delta_x = -aDeltaX;
9449 event.scroll.delta_y = -aDeltaY;
9450
9451 gdk_event_put(&event);
9452}
9453
9454nsresult nsWindow::SynthesizeNativeMouseScrollEvent(
9455 mozilla::LayoutDeviceIntPoint aPoint, uint32_t aNativeMessage,
9456 double aDeltaX, double aDeltaY, double aDeltaZ, uint32_t aModifierFlags,
9457 uint32_t aAdditionalFlags, nsIObserver* aObserver) {
9458 AutoObserverNotifier notifier(aObserver, "mousescrollevent");
9459
9460 if (!mGdkWindow) {
9461 return NS_OK;
9462 }
9463
9464 CreateAndPutGdkScrollEvent(aPoint, aDeltaX, aDeltaY);
9465
9466 return NS_OK;
9467}
9468
9469nsresult nsWindow::SynthesizeNativeTouchPoint(uint32_t aPointerId,
9470 TouchPointerState aPointerState,
9471 LayoutDeviceIntPoint aPoint,
9472 double aPointerPressure,
9473 uint32_t aPointerOrientation,
9474 nsIObserver* aObserver) {
9475 AutoObserverNotifier notifier(aObserver, "touchpoint");
9476
9477 if (!mGdkWindow) {
9478 return NS_OK;
9479 }
9480
9481 GdkEvent event;
9482 memset(&event, 0, sizeof(GdkEvent));
9483
9484 static std::map<uint32_t, GdkEventSequence*> sKnownPointers;
9485
9486 auto result = sKnownPointers.find(aPointerId);
9487 switch (aPointerState) {
9488 case TOUCH_CONTACT:
9489 if (result == sKnownPointers.end()) {
9490 // GdkEventSequence isn't a thing we can instantiate, and never gets
9491 // dereferenced in the gtk code. It's an opaque pointer, the only
9492 // requirement is that it be distinct from other instances of
9493 // GdkEventSequence*.
9494 event.touch.sequence = (GdkEventSequence*)((uintptr_t)aPointerId);
9495 sKnownPointers[aPointerId] = event.touch.sequence;
9496 event.type = GDK_TOUCH_BEGIN;
9497 } else {
9498 event.touch.sequence = result->second;
9499 event.type = GDK_TOUCH_UPDATE;
9500 }
9501 break;
9502 case TOUCH_REMOVE:
9503 event.type = GDK_TOUCH_END;
9504 if (result == sKnownPointers.end()) {
9505 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"
, 9505)
;
9506 return NS_ERROR_UNEXPECTED;
9507 }
9508 event.touch.sequence = result->second;
9509 sKnownPointers.erase(result);
9510 break;
9511 case TOUCH_CANCEL:
9512 event.type = GDK_TOUCH_CANCEL;
9513 if (result == sKnownPointers.end()) {
9514 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"
, 9514)
;
9515 return NS_ERROR_UNEXPECTED;
9516 }
9517 event.touch.sequence = result->second;
9518 sKnownPointers.erase(result);
9519 break;
9520 case TOUCH_HOVER:
9521 default:
9522 return NS_ERROR_NOT_IMPLEMENTED;
9523 }
9524
9525 event.touch.window = mGdkWindow;
9526 event.touch.time = GDK_CURRENT_TIME0L;
9527
9528 GdkDisplay* display = gdk_window_get_display(mGdkWindow);
9529 GdkDeviceManager* device_manager = gdk_display_get_device_manager(display);
9530 event.touch.device = gdk_device_manager_get_client_pointer(device_manager);
9531
9532 event.touch.x_root = DevicePixelsToGdkCoordRoundDown(aPoint.x);
9533 event.touch.y_root = DevicePixelsToGdkCoordRoundDown(aPoint.y);
9534
9535 LayoutDeviceIntPoint pointInWindow = aPoint - WidgetToScreenOffset();
9536 event.touch.x = DevicePixelsToGdkCoordRoundDown(pointInWindow.x);
9537 event.touch.y = DevicePixelsToGdkCoordRoundDown(pointInWindow.y);
9538
9539 gdk_event_put(&event);
9540
9541 return NS_OK;
9542}
9543
9544nsresult nsWindow::SynthesizeNativeTouchPadPinch(
9545 TouchpadGesturePhase aEventPhase, float aScale, LayoutDeviceIntPoint aPoint,
9546 int32_t aModifierFlags) {
9547 if (!mGdkWindow) {
9548 return NS_OK;
9549 }
9550 GdkEvent event;
9551 memset(&event, 0, sizeof(GdkEvent));
9552
9553 GdkEventTouchpadPinch* touchpad_event =
9554 reinterpret_cast<GdkEventTouchpadPinch*>(&event);
9555 touchpad_event->type = GDK_TOUCHPAD_PINCH;
9556
9557 const ScreenIntPoint widgetToScreenOffset = ViewAs<ScreenPixel>(
9558 WidgetToScreenOffset(),
9559 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent);
9560
9561 ScreenPoint pointInWindow =
9562 ViewAs<ScreenPixel>(
9563 aPoint,
9564 PixelCastJustification::LayoutDeviceIsScreenForUntransformedEvent) -
9565 widgetToScreenOffset;
9566
9567 gdouble dx = 0, dy = 0;
9568
9569 switch (aEventPhase) {
9570 case PHASE_BEGIN:
9571 touchpad_event->phase = GDK_TOUCHPAD_GESTURE_PHASE_BEGIN;
9572 mCurrentSynthesizedTouchpadPinch = {pointInWindow, pointInWindow};
9573 break;
9574 case PHASE_UPDATE:
9575 dx = pointInWindow.x - mCurrentSynthesizedTouchpadPinch.mCurrentFocus.x;
9576 dy = pointInWindow.y - mCurrentSynthesizedTouchpadPinch.mCurrentFocus.y;
9577 mCurrentSynthesizedTouchpadPinch.mCurrentFocus = pointInWindow;
9578 touchpad_event->phase = GDK_TOUCHPAD_GESTURE_PHASE_UPDATE;
9579 break;
9580 case PHASE_END:
9581 touchpad_event->phase = GDK_TOUCHPAD_GESTURE_PHASE_END;
9582 break;
9583
9584 default:
9585 return NS_ERROR_NOT_IMPLEMENTED;
9586 }
9587
9588 touchpad_event->window = mGdkWindow;
9589 // We only set the fields of GdkEventTouchpadPinch which are
9590 // actually used in OnTouchpadPinchEvent().
9591 // GdkEventTouchpadPinch has additional fields.
9592 // If OnTouchpadPinchEvent() is changed to use other fields, this function
9593 // will need to change to set them as well.
9594 touchpad_event->time = GDK_CURRENT_TIME0L;
9595 touchpad_event->scale = aScale;
9596 touchpad_event->x_root = DevicePixelsToGdkCoordRoundDown(
9597 mCurrentSynthesizedTouchpadPinch.mBeginFocus.x +
9598 ScreenCoord(widgetToScreenOffset.x));
9599 touchpad_event->y_root = DevicePixelsToGdkCoordRoundDown(
9600 mCurrentSynthesizedTouchpadPinch.mBeginFocus.y +
9601 ScreenCoord(widgetToScreenOffset.y));
9602
9603 touchpad_event->x = DevicePixelsToGdkCoordRoundDown(
9604 mCurrentSynthesizedTouchpadPinch.mBeginFocus.x);
9605 touchpad_event->y = DevicePixelsToGdkCoordRoundDown(
9606 mCurrentSynthesizedTouchpadPinch.mBeginFocus.y);
9607
9608 touchpad_event->dx = dx;
9609 touchpad_event->dy = dy;
9610
9611 touchpad_event->state = aModifierFlags;
9612
9613 gdk_event_put(&event);
9614
9615 return NS_OK;
9616}
9617
9618nsresult nsWindow::SynthesizeNativeTouchpadPan(TouchpadGesturePhase aEventPhase,
9619 LayoutDeviceIntPoint aPoint,
9620 double aDeltaX, double aDeltaY,
9621 int32_t aModifierFlags,
9622 nsIObserver* aObserver) {
9623 AutoObserverNotifier notifier(aObserver, "touchpadpanevent");
9624
9625 if (!mGdkWindow) {
9626 return NS_OK;
9627 }
9628
9629 // This should/could maybe send GdkEventTouchpadSwipe events, however we don't
9630 // currently consume those (either real user input or testing events). So we
9631 // send gdk scroll events to be more like what we do for real user input. If
9632 // we start consuming GdkEventTouchpadSwipe and get those hooked up to swipe
9633 // to nav, then maybe we should test those too.
9634
9635 mCurrentSynthesizedTouchpadPan.mTouchpadGesturePhase = Some(aEventPhase);
9636 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"
, 9636); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCurrentSynthesizedTouchpadPan.mSavedObserver == 0"
")"); do { *((volatile int*)__null) = 9636; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9637 mCurrentSynthesizedTouchpadPan.mSavedObserver = notifier.SaveObserver();
9638
9639 // Note that CreateAndPutGdkScrollEvent sets the device source for the created
9640 // event as the "client pointer" (a kind of default device) which will
9641 // probably be of type mouse. We would ideally want to set the device of the
9642 // created event to be a touchpad, but the system might not have a touchpad.
9643 // To get around this we use
9644 // mCurrentSynthesizedTouchpadPan.mTouchpadGesturePhase being something to
9645 // indicate that we should treat the source of the event as touchpad in
9646 // OnScrollEvent.
9647 CreateAndPutGdkScrollEvent(aPoint, aDeltaX, aDeltaY);
9648
9649 return NS_OK;
9650}
9651
9652nsWindow::GtkWindowDecoration nsWindow::GetSystemGtkWindowDecoration() {
9653 static GtkWindowDecoration sGtkWindowDecoration = [] {
9654 // Allow MOZ_GTK_TITLEBAR_DECORATION to override our heuristics
9655 if (const char* decorationOverride =
9656 getenv("MOZ_GTK_TITLEBAR_DECORATION")) {
9657 if (strcmp(decorationOverride, "none") == 0) {
9658 return GTK_DECORATION_NONE;
9659 }
9660 if (strcmp(decorationOverride, "client") == 0) {
9661 return GTK_DECORATION_CLIENT;
9662 }
9663 if (strcmp(decorationOverride, "system") == 0) {
9664 return GTK_DECORATION_SYSTEM;
9665 }
9666 }
9667
9668 // nsWindow::GetSystemGtkWindowDecoration can be called from various
9669 // threads so we can't use gfxPlatformGtk here.
9670 if (GdkIsWaylandDisplay()) {
9671 return GTK_DECORATION_CLIENT;
9672 }
9673
9674 // GTK_CSD forces CSD mode - use also CSD because window manager
9675 // decorations does not work with CSD.
9676 // We check GTK_CSD as well as gtk_window_should_use_csd() does.
9677 if (const char* csdOverride = getenv("GTK_CSD")) {
9678 return *csdOverride == '0' ? GTK_DECORATION_NONE : GTK_DECORATION_CLIENT;
9679 }
9680
9681 // TODO: Consider switching this to GetDesktopEnvironmentIdentifier().
9682 const char* currentDesktop = getenv("XDG_CURRENT_DESKTOP");
9683 if (!currentDesktop) {
9684 return GTK_DECORATION_NONE;
9685 }
9686 if (strstr(currentDesktop, "i3")) {
9687 return GTK_DECORATION_NONE;
9688 }
9689
9690 // Tested desktops: pop:GNOME, KDE, Enlightenment, LXDE, openbox, MATE,
9691 // X-Cinnamon, Pantheon, Deepin, GNOME, LXQt, Unity.
9692 return GTK_DECORATION_CLIENT;
9693 }();
9694 return sGtkWindowDecoration;
9695}
9696
9697bool nsWindow::TitlebarUseShapeMask() {
9698 static int useShapeMask = []() {
9699 // Don't use titlebar shape mask on Wayland
9700 if (!GdkIsX11Display()) {
9701 return false;
9702 }
9703
9704 // We can't use shape masks on Mutter/X.org as we can't resize Firefox
9705 // window there (Bug 1530252).
9706 if (IsGnomeDesktopEnvironment()) {
9707 return false;
9708 }
9709
9710 return Preferences::GetBool("widget.titlebar-x11-use-shape-mask", false);
9711 }();
9712 return useShapeMask;
9713}
9714
9715int32_t nsWindow::RoundsWidgetCoordinatesTo() { return GdkCeiledScaleFactor(); }
9716
9717void nsWindow::GetCompositorWidgetInitData(
9718 mozilla::widget::CompositorWidgetInitData* aInitData) {
9719 nsCString displayName;
9720
9721 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)
;
9722
9723 Window window = GetX11Window();
9724#ifdef MOZ_X111
9725 // We're bit hackish here. Old GLX backend needs XWindow when GLContext
9726 // is created so get XWindow now before map signal.
9727 // We may see crashes/errors when nsWindow is unmapped (XWindow is
9728 // invalidated) but we can't do anything about it.
9729 if (!window && !gfxVars::UseEGL()) {
9730 window =
9731 gdk_x11_window_get_xid(gtk_widget_get_window(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer)))))));
9732 }
9733#endif
9734 *aInitData = mozilla::widget::GtkCompositorWidgetInitData(
9735 window, displayName, GetShapedState(), GdkIsX11Display(),
9736 GetClientSize());
9737
9738#ifdef MOZ_X111
9739 if (GdkIsX11Display()) {
9740 // Make sure the window XID is propagated to X server, we can fail otherwise
9741 // in GPU process (Bug 1401634).
9742 Display* display = DefaultXDisplay();
9743 XFlush(display);
9744 displayName = nsCString(XDisplayString(display));
9745 }
9746#endif
9747}
9748
9749#ifdef MOZ_X111
9750/* XApp progress support currently works by setting a property
9751 * on a window with this Atom name. A supporting window manager
9752 * will notice this and pass it along to whatever handling has
9753 * been implemented on that end (e.g. passing it on to a taskbar
9754 * widget.) There is no issue if WM support is lacking, this is
9755 * simply ignored in that case.
9756 *
9757 * See https://github.com/linuxmint/xapps/blob/master/libxapp/xapp-gtk-window.c
9758 * for further details.
9759 */
9760
9761# define PROGRESS_HINT"_NET_WM_XAPP_PROGRESS" "_NET_WM_XAPP_PROGRESS"
9762
9763static void set_window_hint_cardinal(Window xid, const gchar* atom_name,
9764 gulong cardinal) {
9765 GdkDisplay* display;
9766
9767 display = gdk_display_get_default();
9768
9769 if (cardinal > 0) {
9770 XChangeProperty(GDK_DISPLAY_XDISPLAY(display)(gdk_x11_display_get_xdisplay (display)), xid,
9771 gdk_x11_get_xatom_by_name_for_display(display, atom_name),
9772 XA_CARDINAL((Atom) 6), 32, PropModeReplace0, (guchar*)&cardinal, 1);
9773 } else {
9774 XDeleteProperty(GDK_DISPLAY_XDISPLAY(display)(gdk_x11_display_get_xdisplay (display)), xid,
9775 gdk_x11_get_xatom_by_name_for_display(display, atom_name));
9776 }
9777}
9778#endif // MOZ_X11
9779
9780void nsWindow::SetProgress(unsigned long progressPercent) {
9781#ifdef MOZ_X111
9782
9783 if (!GdkIsX11Display()) {
9784 return;
9785 }
9786
9787 if (!mShell) {
9788 return;
9789 }
9790
9791 progressPercent = MIN(progressPercent, 100)(((progressPercent) < (100)) ? (progressPercent) : (100));
9792
9793 set_window_hint_cardinal(GDK_WINDOW_XID(GetToplevelGdkWindow())(gdk_x11_window_get_xid (GetToplevelGdkWindow())),
9794 PROGRESS_HINT"_NET_WM_XAPP_PROGRESS", progressPercent);
9795#endif // MOZ_X11
9796}
9797
9798#ifdef MOZ_X111
9799void nsWindow::SetCompositorHint(WindowComposeRequest aState) {
9800 if (!GdkIsX11Display()) {
9801 return;
9802 }
9803
9804 gulong value = aState;
9805 GdkAtom cardinal_atom = gdk_x11_xatom_to_atom(XA_CARDINAL((Atom) 6));
9806 gdk_property_change(GetToplevelGdkWindow(),
9807 gdk_atom_intern("_NET_WM_BYPASS_COMPOSITOR", FALSE(0)),
9808 cardinal_atom,
9809 32, // format
9810 GDK_PROP_MODE_REPLACE, (guchar*)&value, 1);
9811}
9812#endif
9813
9814nsresult nsWindow::SetSystemFont(const nsCString& aFontName) {
9815 GtkSettings* settings = gtk_settings_get_default();
9816 g_object_set(settings, "gtk-font-name", aFontName.get(), nullptr);
9817 return NS_OK;
9818}
9819
9820nsresult nsWindow::GetSystemFont(nsCString& aFontName) {
9821 GtkSettings* settings = gtk_settings_get_default();
9822 gchar* fontName = nullptr;
9823 g_object_get(settings, "gtk-font-name", &fontName, nullptr);
9824 if (fontName) {
9825 aFontName.Assign(fontName);
9826 g_free(fontName);
9827 }
9828 return NS_OK;
9829}
9830
9831already_AddRefed<nsIWidget> nsIWidget::CreateTopLevelWindow() {
9832 nsCOMPtr<nsIWidget> window = new nsWindow();
9833 return window.forget();
9834}
9835
9836already_AddRefed<nsIWidget> nsIWidget::CreateChildWindow() {
9837 nsCOMPtr<nsIWidget> window = new nsWindow();
9838 return window.forget();
9839}
9840
9841#ifdef MOZ_WAYLAND1
9842static void relative_pointer_handle_relative_motion(
9843 void* data, struct zwp_relative_pointer_v1* pointer, uint32_t time_hi,
9844 uint32_t time_lo, wl_fixed_t dx_w, wl_fixed_t dy_w, wl_fixed_t dx_unaccel_w,
9845 wl_fixed_t dy_unaccel_w) {
9846 RefPtr<nsWindow> window(reinterpret_cast<nsWindow*>(data));
9847
9848 WidgetMouseEvent event(true, eMouseMove, window, WidgetMouseEvent::eReal);
9849
9850 double scale = window->FractionalScaleFactor();
9851 event.mRefPoint = window->GetNativePointerLockCenter();
9852 event.mRefPoint.x += int(wl_fixed_to_double(dx_w) * scale);
9853 event.mRefPoint.y += int(wl_fixed_to_double(dy_w) * scale);
9854
9855 event.AssignEventTime(window->GetWidgetEventTime(time_lo));
9856 window->DispatchInputEvent(&event);
9857}
9858
9859static const struct zwp_relative_pointer_v1_listener relative_pointer_listener =
9860 {
9861 relative_pointer_handle_relative_motion,
9862};
9863
9864void nsWindow::SetNativePointerLockCenter(
9865 const LayoutDeviceIntPoint& aLockCenter) {
9866 mNativePointerLockCenter = aLockCenter;
9867}
9868
9869void nsWindow::LockNativePointer() {
9870 if (!GdkIsWaylandDisplay()) {
9871 return;
9872 }
9873
9874 auto* waylandDisplay = WaylandDisplayGet();
9875
9876 auto* pointerConstraints = waylandDisplay->GetPointerConstraints();
9877 if (!pointerConstraints) {
9878 return;
9879 }
9880
9881 auto* relativePointerMgr = waylandDisplay->GetRelativePointerManager();
9882 if (!relativePointerMgr) {
9883 return;
9884 }
9885
9886 GdkDisplay* display = gdk_display_get_default();
9887
9888 GdkDeviceManager* manager = gdk_display_get_device_manager(display);
9889 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"
, 9889); AnnotateMozCrashReason("MOZ_ASSERT" "(" "manager" ")"
); do { *((volatile int*)__null) = 9889; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9890
9891 GdkDevice* device = gdk_device_manager_get_client_pointer(manager);
9892 if (!device) {
9893 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"
, 9893)
;
9894 return;
9895 }
9896 wl_pointer* pointer = gdk_wayland_device_get_wl_pointer(device);
9897 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"
, 9897); AnnotateMozCrashReason("MOZ_ASSERT" "(" "pointer" ")"
); do { *((volatile int*)__null) = 9897; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
9898
9899 wl_surface* surface =
9900 gdk_wayland_window_get_wl_surface(GetToplevelGdkWindow());
9901 if (!surface) {
9902 /* Can be null when the window is hidden.
9903 * Though it's unlikely that a lock request comes in that case, be
9904 * defensive. */
9905 return;
9906 }
9907
9908 UnlockNativePointer();
9909
9910 mLockedPointer = zwp_pointer_constraints_v1_lock_pointer(
9911 pointerConstraints, surface, pointer, nullptr,
9912 ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT);
9913 if (!mLockedPointer) {
9914 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"
, 9914)
;
9915 return;
9916 }
9917
9918 mRelativePointer = zwp_relative_pointer_manager_v1_get_relative_pointer(
9919 relativePointerMgr, pointer);
9920 if (!mRelativePointer) {
9921 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"
, 9921)
;
9922 zwp_locked_pointer_v1_destroy(mLockedPointer);
9923 mLockedPointer = nullptr;
9924 return;
9925 }
9926
9927 zwp_relative_pointer_v1_add_listener(mRelativePointer,
9928 &relative_pointer_listener, this);
9929}
9930
9931void nsWindow::UnlockNativePointer() {
9932 if (mRelativePointer) {
9933 zwp_relative_pointer_v1_destroy(mRelativePointer);
9934 mRelativePointer = nullptr;
9935 }
9936 if (mLockedPointer) {
9937 zwp_locked_pointer_v1_destroy(mLockedPointer);
9938 mLockedPointer = nullptr;
9939 }
9940}
9941#endif
9942
9943static nsIFrame* FindTitlebarFrame(nsIFrame* aFrame) {
9944 for (nsIFrame* childFrame : aFrame->PrincipalChildList()) {
9945 StyleAppearance appearance =
9946 childFrame->StyleDisplay()->EffectiveAppearance();
9947 if (appearance == StyleAppearance::MozWindowTitlebar ||
9948 appearance == StyleAppearance::MozWindowTitlebarMaximized) {
9949 return childFrame;
9950 }
9951
9952 if (nsIFrame* foundFrame = FindTitlebarFrame(childFrame)) {
9953 return foundFrame;
9954 }
9955 }
9956 return nullptr;
9957}
9958
9959nsIFrame* nsWindow::GetFrame() const {
9960 nsView* view = nsView::GetViewFor(this);
9961 if (!view) {
9962 return nullptr;
9963 }
9964 return view->GetFrame();
9965}
9966
9967void nsWindow::UpdateMozWindowActive() {
9968 // Update activation state for the :-moz-window-inactive pseudoclass.
9969 // Normally, this follows focus; we override it here to follow
9970 // GDK_WINDOW_STATE_FOCUSED.
9971 if (mozilla::dom::Document* document = GetDocument()) {
9972 if (nsPIDOMWindowOuter* window = document->GetWindow()) {
9973 if (RefPtr<mozilla::dom::BrowsingContext> bc =
9974 window->GetBrowsingContext()) {
9975 bc->SetIsActiveBrowserWindow(!mTitlebarBackdropState);
9976 }
9977 }
9978 }
9979}
9980
9981void nsWindow::ForceTitlebarRedraw() {
9982 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"
, 9982); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mDrawInTitlebar"
") (" "We should not redraw invisible titlebar." ")"); do { *
((volatile int*)__null) = 9982; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
9983
9984 if (!mWidgetListener || !mWidgetListener->GetPresShell()) {
9985 return;
9986 }
9987
9988 nsIFrame* frame = GetFrame();
9989 if (!frame) {
9990 return;
9991 }
9992
9993 frame = FindTitlebarFrame(frame);
9994 if (frame) {
9995 nsIContent* content = frame->GetContent();
9996 if (content) {
9997 nsLayoutUtils::PostRestyleEvent(content->AsElement(), RestyleHint{0},
9998 nsChangeHint_RepaintFrame);
9999 }
10000 }
10001}
10002
10003void nsWindow::LockAspectRatio(bool aShouldLock) {
10004 if (!gUseAspectRatio) {
10005 return;
10006 }
10007
10008 if (aShouldLock) {
10009 int decWidth = 0, decHeight = 0;
10010 AddCSDDecorationSize(&decWidth, &decHeight);
10011
10012 float width =
10013 DevicePixelsToGdkCoordRoundDown(mLastSizeRequest.width) + decWidth;
10014 float height =
10015 DevicePixelsToGdkCoordRoundDown(mLastSizeRequest.height) + decHeight;
10016
10017 mAspectRatio = width / height;
10018 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)
10019 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)
;
10020 } else {
10021 mAspectRatio = 0.0;
10022 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)
;
10023 }
10024
10025 ApplySizeConstraints();
10026}
10027
10028nsWindow* nsWindow::GetFocusedWindow() { return gFocusWindow; }
10029
10030#ifdef MOZ_WAYLAND1
10031bool nsWindow::SetEGLNativeWindowSize(
10032 const LayoutDeviceIntSize& aEGLWindowSize) {
10033 if (!GdkIsWaylandDisplay() || !mIsMapped) {
10034 return true;
10035 }
10036
10037 if (mCompositorState == COMPOSITOR_PAUSED_FLICKERING) {
10038 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)
10039 "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)
;
10040 return false;
10041 }
10042
10043 gint scale = GdkCeiledScaleFactor();
10044# ifdef MOZ_LOGGING1
10045 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)
))
) {
10046 static uintptr_t lastSizeLog = 0;
10047 uintptr_t sizeLog =
10048 uintptr_t(this) + aEGLWindowSize.width + aEGLWindowSize.height + scale +
10049 aEGLWindowSize.width / scale + aEGLWindowSize.height / scale;
10050 if (lastSizeLog != sizeLog) {
10051 lastSizeLog = sizeLog;
10052 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)
10053 "%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)
10054 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)
10055 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)
;
10056 }
10057 }
10058# endif
10059 return moz_container_wayland_egl_window_set_size(
10060 mContainer, aEGLWindowSize.ToUnknownSize(), scale);
10061}
10062#endif
10063
10064nsWindow* nsWindow::GetWindow(GdkWindow* window) {
10065 return get_window_for_gdk_window(window);
10066}
10067
10068void nsWindow::ClearRenderingQueue() {
10069 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)
;
10070
10071 if (mWidgetListener) {
10072 mWidgetListener->RequestWindowClose(this);
10073 }
10074 DestroyLayerManager();
10075}
10076
10077// nsWindow::OnMap() / nsWindow::OnUnmap() is called from map/unmap mContainer
10078// handlers directly as we paint to mContainer.
10079void nsWindow::OnMap() {
10080 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)
;
10081
10082 {
10083 MutexAutoLock lock(mWindowVisibilityMutex);
10084 mIsMapped = true;
10085
10086 EnsureGdkWindow();
10087 OnScaleChanged(/* aNotify = */ false);
10088
10089 if (mIsAlert) {
10090 gdk_window_set_override_redirect(GetToplevelGdkWindow(), TRUE(!(0)));
10091 }
10092
10093#ifdef MOZ_X111
10094 if (GdkIsX11Display()) {
10095 mSurfaceProvider.Initialize(GetX11Window(), GetShapedState());
10096
10097 // Set window manager hint to keep fullscreen windows composited.
10098 //
10099 // If the window were to get unredirected, there could be visible
10100 // tearing because Gecko does not align its framebuffer updates with
10101 // vblank.
10102 SetCompositorHint(GTK_WIDGET_COMPOSITED_ENABLED);
10103 }
10104#endif
10105#ifdef MOZ_WAYLAND1
10106 if (GdkIsWaylandDisplay()) {
10107 mSurfaceProvider.Initialize(this);
10108 }
10109#endif
10110 }
10111
10112 if (mIsDragPopup) {
10113 if (GdkIsWaylandDisplay()) {
10114 // Disable painting to the widget on Wayland as we paint directly to the
10115 // widget. Wayland compositors does not paint wl_subsurface
10116 // of D&D widget.
10117 if (GtkWidget* parent = gtk_widget_get_parent(mShell)) {
10118 GtkWidgetDisableUpdates(parent);
10119 }
10120 GtkWidgetDisableUpdates(mShell);
10121 GtkWidgetDisableUpdates(GTK_WIDGET(mContainer)((((GtkWidget*) (void *) ((mContainer))))));
10122 } else {
10123 // Disable rendering of parent container on X11 to avoid flickering.
10124 if (GtkWidget* parent = gtk_widget_get_parent(mShell)) {
10125 gtk_widget_set_opacity(parent, 0.0);
10126 }
10127 }
10128 }
10129
10130 if (mWindowType == WindowType::Popup) {
10131 if (mNoAutoHide) {
10132 gint wmd = ConvertBorderStyles(mBorderStyle);
10133 if (wmd != -1) {
10134 gdk_window_set_decorations(mGdkWindow, (GdkWMDecoration)wmd);
10135 }
10136 }
10137 // If the popup ignores mouse events, set an empty input shape.
10138 SetInputRegion(mInputRegion);
10139 }
10140
10141 RefreshWindowClass();
10142
10143 // We're not mapped yet but we have already created compositor.
10144 if (mCompositorWidgetDelegate) {
10145 ConfigureCompositor();
10146 }
10147
10148 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)
;
10149}
10150
10151void nsWindow::OnUnmap() {
10152 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)
;
10153
10154 {
10155 MutexAutoLock lock(mWindowVisibilityMutex);
10156 mIsMapped = false;
10157
10158 if (mSourceDragContext) {
10159 static auto sGtkDragCancel =
10160 (void (*)(GdkDragContext*))dlsym(RTLD_DEFAULT((void *) 0), "gtk_drag_cancel");
10161 if (sGtkDragCancel) {
10162 sGtkDragCancel(mSourceDragContext);
10163 mSourceDragContext = nullptr;
10164 }
10165 }
10166
10167 if (mGdkWindow) {
10168 g_object_set_data(G_OBJECT(mGdkWindow)((((GObject*) (void *) ((mGdkWindow))))), "nsWindow", nullptr);
10169 mGdkWindow = nullptr;
10170 }
10171
10172 // Clear resources (mainly XWindow) stored at GtkCompositorWidget.
10173 // It makes sure we don't paint to it when nsWindow becomes hiden/deleted
10174 // and XWindow is released.
10175 if (mCompositorWidgetDelegate) {
10176 mCompositorWidgetDelegate->CleanupResources();
10177 }
10178
10179 // Clear nsWindow resources used for old (in-thread) rendering.
10180 mSurfaceProvider.CleanupResources();
10181 }
10182
10183 // Until Bug 1654938 is fixed we delete layer manager for hidden popups,
10184 // otherwise it can easily hold 1GB+ memory for long time.
10185 if (mWindowType == WindowType::Popup) {
10186 DestroyLayerManager();
10187 } else {
10188 // Widget is backed by OpenGL EGLSurface created over wl_surface/XWindow.
10189 //
10190 // RenderCompositorEGL::Resume() deletes recent EGLSurface,
10191 // calls nsWindow::GetNativeData(NS_NATIVE_EGL_WINDOW) from compositor
10192 // thread to get new native rendering surface.
10193 //
10194 // For hidden/unmapped windows we return nullptr NS_NATIVE_EGL_WINDOW at
10195 // nsWindow::GetNativeData() so RenderCompositorEGL::Resume() creates
10196 // offscreen fallback EGLSurface to avoid compositor pause.
10197 //
10198 // We don't want to pause compositor as it may lead to whole
10199 // browser freeze (Bug 1777664).
10200 //
10201 // If RenderCompositorSWGL compositor is used (SW fallback)
10202 // RenderCompositorSWGL::Resume() only requests full render for next paint
10203 // as wl_surface/XWindow is managed by WindowSurfaceProvider owned
10204 // directly by GtkCompositorWidget and that's covered by
10205 // mCompositorWidgetDelegate->CleanupResources() call above.
10206 if (CompositorBridgeChild* remoteRenderer = GetRemoteRenderer()) {
10207 remoteRenderer->SendResume();
10208 }
10209 }
10210}
10211
10212// Apply workaround for Mutter compositor bug (mzbz#1777269).
10213//
10214// When we open a popup window (tooltip for instance) attached to
10215// GDK_WINDOW_TYPE_HINT_UTILITY parent popup, Mutter compositor sends bogus
10216// leave/enter events to the GDK_WINDOW_TYPE_HINT_UTILITY popup.
10217// That leads to immediate tooltip close. As a workaround ignore these
10218// bogus events.
10219//
10220// We need to check two affected window types:
10221//
10222// - toplevel window with at least two child popups where the first one is
10223// GDK_WINDOW_TYPE_HINT_UTILITY.
10224// - GDK_WINDOW_TYPE_HINT_UTILITY popup with a child popup
10225//
10226// We need to mask two bogus leave/enter sequences:
10227// 1) Leave (popup) -> Enter (toplevel)
10228// 2) Leave (toplevel) -> Enter (popup)
10229//
10230// TODO: persistent (non-tracked) popups with tooltip/child popups?
10231//
10232bool nsWindow::ApplyEnterLeaveMutterWorkaround() {
10233 // Leave (toplevel) case
10234 if (mWindowType == WindowType::TopLevel && mWaylandPopupNext &&
10235 mWaylandPopupNext->mWaylandPopupNext &&
10236 gtk_window_get_type_hint(GTK_WINDOW(mWaylandPopupNext->GetGtkWidget())((((GtkWindow*) (void *) ((mWaylandPopupNext->GetGtkWidget
())))))
) ==
10237 GDK_WINDOW_TYPE_HINT_UTILITY) {
10238 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)
;
10239 return true;
10240 }
10241 // Leave (popup) case
10242 if (IsWaylandPopup() && mWaylandPopupNext &&
10243 gtk_window_get_type_hint(GTK_WINDOW(mShell)((((GtkWindow*) (void *) ((mShell)))))) ==
10244 GDK_WINDOW_TYPE_HINT_UTILITY) {
10245 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)
;
10246 return true;
10247 }
10248 return false;
10249}
10250
10251void nsWindow::NotifyOcclusionState(OcclusionState aState) {
10252 if (!IsTopLevelWindowType()) {
10253 return;
10254 }
10255
10256 bool isFullyOccluded = aState == OcclusionState::OCCLUDED;
10257 if (mIsFullyOccluded == isFullyOccluded) {
10258 return;
10259 }
10260 mIsFullyOccluded = isFullyOccluded;
10261
10262 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)
;
10263 if (mWidgetListener) {
10264 mWidgetListener->OcclusionStateChanged(mIsFullyOccluded);
10265 }
10266}
10267
10268void nsWindow::SetDragSource(GdkDragContext* aSourceDragContext) {
10269 mSourceDragContext = aSourceDragContext;
10270 if (IsPopup() &&
10271 (widget::GdkIsWaylandDisplay() || widget::IsXWaylandProtocol())) {
10272 if (auto* menuPopupFrame = GetMenuPopupFrame(GetFrame())) {
10273 menuPopupFrame->SetIsDragSource(!!aSourceDragContext);
10274 }
10275 }
10276}
10277
10278UniquePtr<MozContainerSurfaceLock> nsWindow::LockSurface() {
10279 if (mIsDestroyed) {
10280 return nullptr;
10281 }
10282 return MakeUnique<MozContainerSurfaceLock>(mContainer);
10283}