Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp
Warning:line 2118, column 14
Value stored to 'tmp' during its initialization is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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