Bug Summary

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