Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/widget/gtk/nsWindow.cpp
Warning:line 5484, column 5
Value stored to 'parentGdkWindow' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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