Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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