LCOV - code coverage report
Current view: top level - widget/gtk - nsWindow.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 879 3000 29.3 %
Date: 2017-07-14 16:53:18 Functions: 111 238 46.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* vim:expandtab:shiftwidth=4:tabstop=4:
       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 "mozilla/ArrayUtils.h"
      11             : #include "mozilla/EventForwards.h"
      12             : #include "mozilla/MiscEvents.h"
      13             : #include "mozilla/MouseEvents.h"
      14             : #include "mozilla/RefPtr.h"
      15             : #include "mozilla/TextEventDispatcher.h"
      16             : #include "mozilla/TextEvents.h"
      17             : #include "mozilla/TimeStamp.h"
      18             : #include "mozilla/TouchEvents.h"
      19             : #include "mozilla/UniquePtrExtensions.h"
      20             : #include <algorithm>
      21             : 
      22             : #include "GeckoProfiler.h"
      23             : 
      24             : #include "prlink.h"
      25             : #include "nsGTKToolkit.h"
      26             : #include "nsIRollupListener.h"
      27             : #include "nsIDOMNode.h"
      28             : 
      29             : #include "nsWidgetsCID.h"
      30             : #include "nsDragService.h"
      31             : #include "nsIWidgetListener.h"
      32             : #include "nsIScreenManager.h"
      33             : #include "SystemTimeConverter.h"
      34             : 
      35             : #include "nsGtkKeyUtils.h"
      36             : #include "nsGtkCursors.h"
      37             : #include "ScreenHelperGTK.h"
      38             : 
      39             : #include <gtk/gtk.h>
      40             : #if (MOZ_WIDGET_GTK == 3)
      41             : #include <gtk/gtkx.h>
      42             : #endif
      43             : #ifdef MOZ_X11
      44             : #include <gdk/gdkx.h>
      45             : #include <X11/Xatom.h>
      46             : #include <X11/extensions/XShm.h>
      47             : #include <X11/extensions/shape.h>
      48             : #if (MOZ_WIDGET_GTK == 3)
      49             : #include <gdk/gdkkeysyms-compat.h>
      50             : #endif
      51             : 
      52             : #if (MOZ_WIDGET_GTK == 2)
      53             : #include "gtk2xtbin.h"
      54             : #endif
      55             : #endif /* MOZ_X11 */
      56             : #include <gdk/gdkkeysyms.h>
      57             : #if (MOZ_WIDGET_GTK == 2)
      58             : #include <gtk/gtkprivate.h>
      59             : #endif
      60             : 
      61             : #include "nsGkAtoms.h"
      62             : 
      63             : #ifdef MOZ_ENABLE_STARTUP_NOTIFICATION
      64             : #define SN_API_NOT_YET_FROZEN
      65             : #include <startup-notification-1.0/libsn/sn.h>
      66             : #endif
      67             : 
      68             : #include "mozilla/Assertions.h"
      69             : #include "mozilla/Likely.h"
      70             : #include "mozilla/Preferences.h"
      71             : #include "nsIPrefService.h"
      72             : #include "nsIGConfService.h"
      73             : #include "nsIServiceManager.h"
      74             : #include "nsIStringBundle.h"
      75             : #include "nsGfxCIID.h"
      76             : #include "nsGtkUtils.h"
      77             : #include "nsIObserverService.h"
      78             : #include "mozilla/layers/LayersTypes.h"
      79             : #include "nsIIdleServiceInternal.h"
      80             : #include "nsIPropertyBag2.h"
      81             : #include "GLContext.h"
      82             : #include "gfx2DGlue.h"
      83             : 
      84             : #ifdef ACCESSIBILITY
      85             : #include "mozilla/a11y/Accessible.h"
      86             : #include "mozilla/a11y/Platform.h"
      87             : #include "nsAccessibilityService.h"
      88             : 
      89             : using namespace mozilla;
      90             : using namespace mozilla::widget;
      91             : #endif
      92             : 
      93             : /* For SetIcon */
      94             : #include "nsAppDirectoryServiceDefs.h"
      95             : #include "nsXPIDLString.h"
      96             : #include "nsIFile.h"
      97             : 
      98             : /* SetCursor(imgIContainer*) */
      99             : #include <gdk/gdk.h>
     100             : #include <wchar.h>
     101             : #include "imgIContainer.h"
     102             : #include "nsGfxCIID.h"
     103             : #include "nsImageToPixbuf.h"
     104             : #include "nsIInterfaceRequestorUtils.h"
     105             : #include "ClientLayerManager.h"
     106             : 
     107             : #include "gfxPlatformGtk.h"
     108             : #include "gfxContext.h"
     109             : #include "gfxImageSurface.h"
     110             : #include "gfxUtils.h"
     111             : #include "Layers.h"
     112             : #include "GLContextProvider.h"
     113             : #include "mozilla/gfx/2D.h"
     114             : #include "mozilla/gfx/HelpersCairo.h"
     115             : #include "mozilla/layers/CompositorBridgeParent.h"
     116             : #include "mozilla/layers/CompositorThread.h"
     117             : 
     118             : #ifdef MOZ_X11
     119             : #include "X11CompositorWidget.h"
     120             : #include "gfxXlibSurface.h"
     121             : #include "WindowSurfaceX11Image.h"
     122             : #include "WindowSurfaceX11SHM.h"
     123             : #include "WindowSurfaceXRender.h"
     124             : #endif // MOZ_X11
     125             : 
     126             : #include "nsShmImage.h"
     127             : 
     128             : #include "nsIDOMWheelEvent.h"
     129             : 
     130             : #include "NativeKeyBindings.h"
     131             : 
     132             : #include <dlfcn.h>
     133             : 
     134             : #include "mozilla/layers/APZCTreeManager.h"
     135             : 
     136             : using namespace mozilla;
     137             : using namespace mozilla::gfx;
     138             : using namespace mozilla::widget;
     139             : using namespace mozilla::layers;
     140             : using mozilla::gl::GLContext;
     141             : 
     142             : // Don't put more than this many rects in the dirty region, just fluff
     143             : // out to the bounding-box if there are more
     144             : #define MAX_RECTS_IN_REGION 100
     145             : 
     146             : const gint kEvents = GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK |
     147             :                      GDK_VISIBILITY_NOTIFY_MASK |
     148             :                      GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
     149             :                      GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
     150             : #if GTK_CHECK_VERSION(3,4,0)
     151             :                      GDK_SMOOTH_SCROLL_MASK |
     152             :                      GDK_TOUCH_MASK |
     153             : #endif
     154             :                      GDK_SCROLL_MASK |
     155             :                      GDK_POINTER_MOTION_MASK |
     156             :                      GDK_PROPERTY_CHANGE_MASK;
     157             : 
     158             : /* utility functions */
     159             : static bool       is_mouse_in_window(GdkWindow* aWindow,
     160             :                                      gdouble aMouseX, gdouble aMouseY);
     161             : static nsWindow  *get_window_for_gtk_widget(GtkWidget *widget);
     162             : static nsWindow  *get_window_for_gdk_window(GdkWindow *window);
     163             : static GtkWidget *get_gtk_widget_for_gdk_window(GdkWindow *window);
     164             : static GdkCursor *get_gtk_cursor(nsCursor aCursor);
     165             : 
     166             : static GdkWindow *get_inner_gdk_window (GdkWindow *aWindow,
     167             :                                         gint x, gint y,
     168             :                                         gint *retx, gint *rety);
     169             : 
     170             : static int    is_parent_ungrab_enter(GdkEventCrossing *aEvent);
     171             : static int    is_parent_grab_leave(GdkEventCrossing *aEvent);
     172             : 
     173             : static void GetBrandName(nsXPIDLString& brandName);
     174             : 
     175             : /* callbacks from widgets */
     176             : #if (MOZ_WIDGET_GTK == 2)
     177             : static gboolean expose_event_cb           (GtkWidget *widget,
     178             :                                            GdkEventExpose *event);
     179             : #else
     180             : static gboolean expose_event_cb           (GtkWidget *widget,
     181             :                                            cairo_t *rect);
     182             : #endif
     183             : static gboolean configure_event_cb        (GtkWidget *widget,
     184             :                                            GdkEventConfigure *event);
     185             : static void     container_unrealize_cb    (GtkWidget *widget);
     186             : static void     size_allocate_cb          (GtkWidget *widget,
     187             :                                            GtkAllocation *allocation);
     188             : static gboolean delete_event_cb           (GtkWidget *widget,
     189             :                                            GdkEventAny *event);
     190             : static gboolean enter_notify_event_cb     (GtkWidget *widget,
     191             :                                            GdkEventCrossing *event);
     192             : static gboolean leave_notify_event_cb     (GtkWidget *widget,
     193             :                                            GdkEventCrossing *event);
     194             : static gboolean motion_notify_event_cb    (GtkWidget *widget,
     195             :                                            GdkEventMotion *event);
     196             : static gboolean button_press_event_cb     (GtkWidget *widget,
     197             :                                            GdkEventButton *event);
     198             : static gboolean button_release_event_cb   (GtkWidget *widget,
     199             :                                            GdkEventButton *event);
     200             : static gboolean focus_in_event_cb         (GtkWidget *widget,
     201             :                                            GdkEventFocus *event);
     202             : static gboolean focus_out_event_cb        (GtkWidget *widget,
     203             :                                            GdkEventFocus *event);
     204             : static gboolean key_press_event_cb        (GtkWidget *widget,
     205             :                                            GdkEventKey *event);
     206             : static gboolean key_release_event_cb      (GtkWidget *widget,
     207             :                                            GdkEventKey *event);
     208             : static gboolean property_notify_event_cb  (GtkWidget *widget,
     209             :                                            GdkEventProperty *event);
     210             : static gboolean scroll_event_cb           (GtkWidget *widget,
     211             :                                            GdkEventScroll *event);
     212             : static gboolean visibility_notify_event_cb(GtkWidget *widget,
     213             :                                            GdkEventVisibility *event);
     214             : static void     hierarchy_changed_cb      (GtkWidget *widget,
     215             :                                            GtkWidget *previous_toplevel);
     216             : static gboolean window_state_event_cb     (GtkWidget *widget,
     217             :                                            GdkEventWindowState *event);
     218             : static void     theme_changed_cb          (GtkSettings *settings,
     219             :                                            GParamSpec *pspec,
     220             :                                            nsWindow *data);
     221             : static void     check_resize_cb           (GtkContainer* container,
     222             :                                            gpointer user_data);
     223             : static void     composited_changed_cb     (GtkWidget* widget,
     224             :                                            gpointer user_data);
     225             : 
     226             : #if (MOZ_WIDGET_GTK == 3)
     227             : static void     scale_changed_cb          (GtkWidget* widget,
     228             :                                            GParamSpec* aPSpec,
     229             :                                            gpointer aPointer);
     230             : #endif
     231             : #if GTK_CHECK_VERSION(3,4,0)
     232             : static gboolean touch_event_cb            (GtkWidget* aWidget,
     233             :                                            GdkEventTouch* aEvent);
     234             : #endif
     235             : static nsWindow* GetFirstNSWindowForGDKWindow (GdkWindow *aGdkWindow);
     236             : 
     237             : #ifdef __cplusplus
     238             : extern "C" {
     239             : #endif /* __cplusplus */
     240             : #ifdef MOZ_X11
     241             : static GdkFilterReturn popup_take_focus_filter (GdkXEvent *gdk_xevent,
     242             :                                                 GdkEvent *event,
     243             :                                                 gpointer data);
     244             : #endif /* MOZ_X11 */
     245             : #ifdef __cplusplus
     246             : }
     247             : #endif /* __cplusplus */
     248             : 
     249             : static gboolean drag_motion_event_cb      (GtkWidget *aWidget,
     250             :                                            GdkDragContext *aDragContext,
     251             :                                            gint aX,
     252             :                                            gint aY,
     253             :                                            guint aTime,
     254             :                                            gpointer aData);
     255             : static void     drag_leave_event_cb       (GtkWidget *aWidget,
     256             :                                            GdkDragContext *aDragContext,
     257             :                                            guint aTime,
     258             :                                            gpointer aData);
     259             : static gboolean drag_drop_event_cb        (GtkWidget *aWidget,
     260             :                                            GdkDragContext *aDragContext,
     261             :                                            gint aX,
     262             :                                            gint aY,
     263             :                                            guint aTime,
     264             :                                            gpointer aData);
     265             : static void    drag_data_received_event_cb(GtkWidget *aWidget,
     266             :                                            GdkDragContext *aDragContext,
     267             :                                            gint aX,
     268             :                                            gint aY,
     269             :                                            GtkSelectionData  *aSelectionData,
     270             :                                            guint aInfo,
     271             :                                            guint32 aTime,
     272             :                                            gpointer aData);
     273             : 
     274             : /* initialization static functions */
     275             : static nsresult    initialize_prefs        (void);
     276             : 
     277             : static guint32 sLastUserInputTime = GDK_CURRENT_TIME;
     278             : static guint32 sRetryGrabTime;
     279             : 
     280             : static SystemTimeConverter<guint32>&
     281           7 : TimeConverter() {
     282           7 :     static SystemTimeConverter<guint32> sTimeConverterSingleton;
     283           7 :     return sTimeConverterSingleton;
     284             : }
     285             : 
     286             : namespace mozilla {
     287             : 
     288             : class CurrentX11TimeGetter
     289             : {
     290             : public:
     291           2 :     explicit CurrentX11TimeGetter(GdkWindow* aWindow)
     292           2 :         : mWindow(aWindow)
     293           2 :         , mAsyncUpdateStart()
     294             :     {
     295           2 :     }
     296             : 
     297           1 :     guint32 GetCurrentTime() const
     298             :     {
     299           1 :         return gdk_x11_get_server_time(mWindow);
     300             :     }
     301             : 
     302           2 :     void GetTimeAsyncForPossibleBackwardsSkew(const TimeStamp& aNow)
     303             :     {
     304             :         // Check for in-flight request
     305           2 :         if (!mAsyncUpdateStart.IsNull()) {
     306           1 :             return;
     307             :         }
     308           1 :         mAsyncUpdateStart = aNow;
     309             : 
     310           1 :         Display* xDisplay = GDK_WINDOW_XDISPLAY(mWindow);
     311           1 :         Window xWindow = GDK_WINDOW_XID(mWindow);
     312           1 :         unsigned char c = 'a';
     313           1 :         Atom timeStampPropAtom = TimeStampPropAtom();
     314             :         XChangeProperty(xDisplay, xWindow, timeStampPropAtom,
     315           1 :                         timeStampPropAtom, 8, PropModeReplace, &c, 1);
     316           1 :         XFlush(xDisplay);
     317             :     }
     318             : 
     319          77 :     gboolean PropertyNotifyHandler(GtkWidget* aWidget,
     320             :                                    GdkEventProperty* aEvent)
     321             :     {
     322         154 :         if (aEvent->atom !=
     323          77 :             gdk_x11_xatom_to_atom(TimeStampPropAtom())) {
     324          76 :             return FALSE;
     325             :         }
     326             : 
     327           1 :         guint32 eventTime = aEvent->time;
     328           1 :         TimeStamp lowerBound = mAsyncUpdateStart;
     329             : 
     330           1 :         TimeConverter().CompensateForBackwardsSkew(eventTime, lowerBound);
     331           1 :         mAsyncUpdateStart = TimeStamp();
     332           1 :         return TRUE;
     333             :     }
     334             : 
     335             : private:
     336          78 :     static Atom TimeStampPropAtom() {
     337          78 :         return gdk_x11_get_xatom_by_name_for_display(
     338          78 :             gdk_display_get_default(), "GDK_TIMESTAMP_PROP");
     339             :     }
     340             : 
     341             :     // This is safe because this class is stored as a member of mWindow and
     342             :     // won't outlive it.
     343             :     GdkWindow* mWindow;
     344             :     TimeStamp  mAsyncUpdateStart;
     345             : };
     346             : 
     347             : } // namespace mozilla
     348             : 
     349             : static NS_DEFINE_IID(kCDragServiceCID,  NS_DRAGSERVICE_CID);
     350             : 
     351             : // The window from which the focus manager asks us to dispatch key events.
     352             : static nsWindow         *gFocusWindow          = nullptr;
     353             : static bool              gBlockActivateEvent   = false;
     354             : static bool              gGlobalsInitialized   = false;
     355             : static bool              gRaiseWindows         = true;
     356             : 
     357             : #if GTK_CHECK_VERSION(3,4,0)
     358             : static uint32_t          gLastTouchID = 0;
     359             : #endif
     360             : 
     361             : #define NS_WINDOW_TITLE_MAX_LENGTH 4095
     362             : 
     363             : // If after selecting profile window, the startup fail, please refer to
     364             : // http://bugzilla.gnome.org/show_bug.cgi?id=88940
     365             : 
     366             : // needed for imgIContainer cursors
     367             : // GdkDisplay* was added in 2.2
     368             : typedef struct _GdkDisplay GdkDisplay;
     369             : 
     370             : #define kWindowPositionSlop 20
     371             : 
     372             : // cursor cache
     373             : static GdkCursor *gCursorCache[eCursorCount];
     374             : 
     375             : static GtkWidget *gInvisibleContainer = nullptr;
     376             : 
     377             : // Sometimes this actually also includes the state of the modifier keys, but
     378             : // only the button state bits are used.
     379             : static guint gButtonState;
     380             : 
     381             : static inline int32_t
     382           0 : GetBitmapStride(int32_t width)
     383             : {
     384             : #if defined(MOZ_X11) || (MOZ_WIDGET_GTK == 2)
     385           0 :   return (width+7)/8;
     386             : #else
     387             :   return cairo_format_stride_for_width(CAIRO_FORMAT_A1, width);
     388             : #endif
     389             : }
     390             : 
     391           0 : static inline bool TimestampIsNewerThan(guint32 a, guint32 b)
     392             : {
     393             :     // Timestamps are just the least significant bits of a monotonically
     394             :     // increasing function, and so the use of unsigned overflow arithmetic.
     395           0 :     return a - b <= G_MAXUINT32/2;
     396             : }
     397             : 
     398             : static void
     399           4 : UpdateLastInputEventTime(void *aGdkEvent)
     400             : {
     401             :     nsCOMPtr<nsIIdleServiceInternal> idleService =
     402           8 :         do_GetService("@mozilla.org/widget/idleservice;1");
     403           4 :     if (idleService) {
     404           4 :         idleService->ResetIdleTimeOut(0);
     405             :     }
     406             : 
     407           4 :     guint timestamp = gdk_event_get_time(static_cast<GdkEvent*>(aGdkEvent));
     408           4 :     if (timestamp == GDK_CURRENT_TIME)
     409           0 :         return;
     410             : 
     411           4 :     sLastUserInputTime = timestamp;
     412             : }
     413             : 
     414        2732 : NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
     415             : 
     416           2 : nsWindow::nsWindow()
     417             : {
     418           2 :     mIsTopLevel          = false;
     419           2 :     mIsDestroyed         = false;
     420           2 :     mListenForResizes    = false;
     421           2 :     mNeedsDispatchResized = false;
     422           2 :     mIsShown             = false;
     423           2 :     mNeedsShow           = false;
     424           2 :     mEnabled             = true;
     425           2 :     mCreated             = false;
     426             : #if GTK_CHECK_VERSION(3,4,0)
     427           2 :     mHandleTouchEvent    = false;
     428             : #endif
     429           2 :     mIsDragPopup         = false;
     430           2 :     mIsX11Display        = GDK_IS_X11_DISPLAY(gdk_display_get_default());
     431             : 
     432           2 :     mContainer           = nullptr;
     433           2 :     mGdkWindow           = nullptr;
     434           2 :     mShell               = nullptr;
     435           2 :     mHasMappedToplevel   = false;
     436           2 :     mIsFullyObscured     = false;
     437           2 :     mRetryPointerGrab    = false;
     438           2 :     mWindowType          = eWindowType_child;
     439           2 :     mSizeState           = nsSizeMode_Normal;
     440           2 :     mLastSizeMode        = nsSizeMode_Normal;
     441           2 :     mSizeConstraints.mMaxSize = GetSafeWindowSize(mSizeConstraints.mMaxSize);
     442             : 
     443             : #ifdef MOZ_X11
     444           2 :     mOldFocusWindow      = 0;
     445             : 
     446           2 :     mXDisplay = nullptr;
     447           2 :     mXWindow  = X11None;
     448           2 :     mXVisual  = nullptr;
     449           2 :     mXDepth   = 0;
     450             : #endif /* MOZ_X11 */
     451           2 :     if (!gGlobalsInitialized) {
     452           1 :         gGlobalsInitialized = true;
     453             : 
     454             :         // It's OK if either of these fail, but it may not be one day.
     455           1 :         initialize_prefs();
     456             :     }
     457             : 
     458           2 :     mLastMotionPressure = 0;
     459             : 
     460             : #ifdef ACCESSIBILITY
     461           2 :     mRootAccessible  = nullptr;
     462             : #endif
     463             : 
     464           2 :     mIsTransparent = false;
     465           2 :     mTransparencyBitmap = nullptr;
     466             : 
     467           2 :     mTransparencyBitmapWidth  = 0;
     468           2 :     mTransparencyBitmapHeight = 0;
     469             : 
     470             : #if GTK_CHECK_VERSION(3,4,0)
     471           2 :     mLastScrollEventTime = GDK_CURRENT_TIME;
     472             : #endif
     473           2 :     mPendingConfigures = 0;
     474           2 : }
     475             : 
     476           0 : nsWindow::~nsWindow()
     477             : {
     478           0 :     LOG(("nsWindow::~nsWindow() [%p]\n", (void *)this));
     479             : 
     480           0 :     delete[] mTransparencyBitmap;
     481           0 :     mTransparencyBitmap = nullptr;
     482             : 
     483           0 :     Destroy();
     484           0 : }
     485             : 
     486             : /* static */ void
     487           0 : nsWindow::ReleaseGlobals()
     488             : {
     489           0 :   for (auto & cursor : gCursorCache) {
     490           0 :     if (cursor) {
     491             : #if (MOZ_WIDGET_GTK == 3)
     492           0 :       g_object_unref(cursor);
     493             : #else
     494             :       gdk_cursor_unref(cursor);
     495             : #endif
     496           0 :       cursor = nullptr;
     497             :     }
     498             :   }
     499           0 : }
     500             : 
     501             : void
     502           2 : nsWindow::CommonCreate(nsIWidget *aParent, bool aListenForResizes)
     503             : {
     504           2 :     mParent = aParent;
     505           2 :     mListenForResizes = aListenForResizes;
     506           2 :     mCreated = true;
     507           2 : }
     508             : 
     509             : void
     510           1 : nsWindow::DispatchActivateEvent(void)
     511             : {
     512           1 :     NS_ASSERTION(mContainer || mIsDestroyed,
     513             :                  "DispatchActivateEvent only intended for container windows");
     514             : 
     515             : #ifdef ACCESSIBILITY
     516           1 :     DispatchActivateEventAccessible();
     517             : #endif //ACCESSIBILITY
     518             : 
     519           1 :     if (mWidgetListener)
     520           1 :       mWidgetListener->WindowActivated();
     521           1 : }
     522             : 
     523             : void
     524           0 : nsWindow::DispatchDeactivateEvent(void)
     525             : {
     526           0 :     if (mWidgetListener)
     527           0 :       mWidgetListener->WindowDeactivated();
     528             : 
     529             : #ifdef ACCESSIBILITY
     530           0 :     DispatchDeactivateEventAccessible();
     531             : #endif //ACCESSIBILITY
     532           0 : }
     533             : 
     534             : void
     535           2 : nsWindow::DispatchResized()
     536             : {
     537           2 :     mNeedsDispatchResized = false;
     538           2 :     if (mWidgetListener) {
     539           2 :         mWidgetListener->WindowResized(this, mBounds.width, mBounds.height);
     540             :     }
     541           2 :     if (mAttachedWidgetListener) {
     542           4 :         mAttachedWidgetListener->WindowResized(this,
     543           4 :                                                mBounds.width, mBounds.height);
     544             :     }
     545           2 : }
     546             : 
     547             : void
     548           2 : nsWindow::MaybeDispatchResized()
     549             : {
     550           2 :     if (mNeedsDispatchResized && !mIsDestroyed) {
     551           1 :         DispatchResized();
     552             :     }
     553           2 : }
     554             : 
     555             : nsIWidgetListener*
     556           9 : nsWindow::GetListener()
     557             : {
     558           9 :     return mAttachedWidgetListener ? mAttachedWidgetListener : mWidgetListener;
     559             : }
     560             : 
     561             : nsresult
     562           6 : nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus)
     563             : {
     564             : #ifdef DEBUG
     565           6 :     debug_DumpEvent(stdout, aEvent->mWidget, aEvent,
     566           6 :                     "something", 0);
     567             : #endif
     568           6 :     aStatus = nsEventStatus_eIgnore;
     569           6 :     nsIWidgetListener* listener = GetListener();
     570           6 :     if (listener) {
     571           6 :       aStatus = listener->HandleEvent(aEvent, mUseAttachedEvents);
     572             :     }
     573             : 
     574           6 :     return NS_OK;
     575             : }
     576             : 
     577             : void
     578           0 : nsWindow::OnDestroy(void)
     579             : {
     580           0 :     if (mOnDestroyCalled)
     581           0 :         return;
     582             : 
     583           0 :     mOnDestroyCalled = true;
     584             : 
     585             :     // Prevent deletion.
     586           0 :     nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
     587             : 
     588             :     // release references to children, device context, toolkit + app shell
     589           0 :     nsBaseWidget::OnDestroy();
     590             : 
     591             :     // Remove association between this object and its parent and siblings.
     592           0 :     nsBaseWidget::Destroy();
     593           0 :     mParent = nullptr;
     594             : 
     595           0 :     NotifyWindowDestroyed();
     596             : }
     597             : 
     598             : bool
     599           4 : nsWindow::AreBoundsSane(void)
     600             : {
     601           4 :     if (mBounds.width > 0 && mBounds.height > 0)
     602           4 :         return true;
     603             : 
     604           0 :     return false;
     605             : }
     606             : 
     607             : static GtkWidget*
     608           0 : EnsureInvisibleContainer()
     609             : {
     610           0 :     if (!gInvisibleContainer) {
     611             :         // GtkWidgets need to be anchored to a GtkWindow to be realized (to
     612             :         // have a window).  Using GTK_WINDOW_POPUP rather than
     613             :         // GTK_WINDOW_TOPLEVEL in the hope that POPUP results in less
     614             :         // initialization and window manager interaction.
     615           0 :         GtkWidget* window = gtk_window_new(GTK_WINDOW_POPUP);
     616           0 :         gInvisibleContainer = moz_container_new();
     617           0 :         gtk_container_add(GTK_CONTAINER(window), gInvisibleContainer);
     618           0 :         gtk_widget_realize(gInvisibleContainer);
     619             : 
     620             :     }
     621           0 :     return gInvisibleContainer;
     622             : }
     623             : 
     624             : static void
     625           0 : CheckDestroyInvisibleContainer()
     626             : {
     627           0 :     NS_PRECONDITION(gInvisibleContainer, "oh, no");
     628             : 
     629           0 :     if (!gdk_window_peek_children(gtk_widget_get_window(gInvisibleContainer))) {
     630             :         // No children, so not in use.
     631             :         // Make sure to destroy the GtkWindow also.
     632           0 :         gtk_widget_destroy(gtk_widget_get_parent(gInvisibleContainer));
     633           0 :         gInvisibleContainer = nullptr;
     634             :     }
     635           0 : }
     636             : 
     637             : // Change the containing GtkWidget on a sub-hierarchy of GdkWindows belonging
     638             : // to aOldWidget and rooted at aWindow, and reparent any child GtkWidgets of
     639             : // the GdkWindow hierarchy to aNewWidget.
     640             : static void
     641           0 : SetWidgetForHierarchy(GdkWindow *aWindow,
     642             :                       GtkWidget *aOldWidget,
     643             :                       GtkWidget *aNewWidget)
     644             : {
     645             :     gpointer data;
     646           0 :     gdk_window_get_user_data(aWindow, &data);
     647             : 
     648           0 :     if (data != aOldWidget) {
     649           0 :         if (!GTK_IS_WIDGET(data))
     650           0 :             return;
     651             : 
     652           0 :         auto* widget = static_cast<GtkWidget*>(data);
     653           0 :         if (gtk_widget_get_parent(widget) != aOldWidget)
     654           0 :             return;
     655             : 
     656             :         // This window belongs to a child widget, which will no longer be a
     657             :         // child of aOldWidget.
     658           0 :         gtk_widget_reparent(widget, aNewWidget);
     659             : 
     660           0 :         return;
     661             :     }
     662             : 
     663           0 :     GList *children = gdk_window_get_children(aWindow);
     664           0 :     for(GList *list = children; list; list = list->next) {
     665           0 :         SetWidgetForHierarchy(GDK_WINDOW(list->data), aOldWidget, aNewWidget);
     666             :     }
     667           0 :     g_list_free(children);
     668             : 
     669           0 :     gdk_window_set_user_data(aWindow, aNewWidget);
     670             : }
     671             : 
     672             : // Walk the list of child windows and call destroy on them.
     673             : void
     674           0 : nsWindow::DestroyChildWindows()
     675             : {
     676           0 :     if (!mGdkWindow)
     677           0 :         return;
     678             : 
     679           0 :     while (GList *children = gdk_window_peek_children(mGdkWindow)) {
     680           0 :         GdkWindow *child = GDK_WINDOW(children->data);
     681           0 :         nsWindow *kid = get_window_for_gdk_window(child);
     682           0 :         if (kid) {
     683           0 :             kid->Destroy();
     684             :         } else {
     685             :             // This child is not an nsWindow.
     686             :             // Destroy the child GtkWidget.
     687             :             gpointer data;
     688           0 :             gdk_window_get_user_data(child, &data);
     689           0 :             if (GTK_IS_WIDGET(data)) {
     690           0 :                 gtk_widget_destroy(static_cast<GtkWidget*>(data));
     691             :             }
     692             :         }
     693           0 :     }
     694             : }
     695             : 
     696             : void
     697           0 : nsWindow::Destroy()
     698             : {
     699           0 :     if (mIsDestroyed || !mCreated)
     700           0 :         return;
     701             : 
     702           0 :     LOG(("nsWindow::Destroy [%p]\n", (void *)this));
     703           0 :     mIsDestroyed = true;
     704           0 :     mCreated = false;
     705             : 
     706             :     /** Need to clean our LayerManager up while still alive */
     707           0 :     if (mLayerManager) {
     708           0 :         mLayerManager->Destroy();
     709             :     }
     710           0 :     mLayerManager = nullptr;
     711             : 
     712             :     // It is safe to call DestroyeCompositor several times (here and
     713             :     // in the parent class) since it will take effect only once.
     714             :     // The reason we call it here is because on gtk platforms we need
     715             :     // to destroy the compositor before we destroy the gdk window (which
     716             :     // destroys the the gl context attached to it).
     717           0 :     DestroyCompositor();
     718             : 
     719             : #ifdef MOZ_X11
     720             :     // Ensure any resources assigned to the window get cleaned up first
     721             :     // to avoid double-freeing.
     722           0 :     mSurfaceProvider.CleanupResources();
     723             : #endif
     724             : 
     725           0 :     ClearCachedResources();
     726             : 
     727           0 :     g_signal_handlers_disconnect_by_func(gtk_settings_get_default(),
     728             :                                          FuncToGpointer(theme_changed_cb),
     729           0 :                                          this);
     730             : 
     731           0 :     nsIRollupListener* rollupListener = nsBaseWidget::GetActiveRollupListener();
     732           0 :     if (rollupListener) {
     733           0 :         nsCOMPtr<nsIWidget> rollupWidget = rollupListener->GetRollupWidget();
     734           0 :         if (static_cast<nsIWidget *>(this) == rollupWidget) {
     735           0 :             rollupListener->Rollup(0, false, nullptr, nullptr);
     736             :         }
     737             :     }
     738             : 
     739             :     // dragService will be null after shutdown of the service manager.
     740           0 :     RefPtr<nsDragService> dragService = nsDragService::GetInstance();
     741           0 :     if (dragService && this == dragService->GetMostRecentDestWindow()) {
     742           0 :         dragService->ScheduleLeaveEvent();
     743             :     }
     744             : 
     745           0 :     NativeShow(false);
     746             : 
     747           0 :     if (mIMContext) {
     748           0 :         mIMContext->OnDestroyWindow(this);
     749             :     }
     750             : 
     751             :     // make sure that we remove ourself as the focus window
     752           0 :     if (gFocusWindow == this) {
     753           0 :         LOGFOCUS(("automatically losing focus...\n"));
     754           0 :         gFocusWindow = nullptr;
     755             :     }
     756             : 
     757           0 :     GtkWidget *owningWidget = GetMozContainerWidget();
     758           0 :     if (mShell) {
     759           0 :         gtk_widget_destroy(mShell);
     760           0 :         mShell = nullptr;
     761           0 :         mContainer = nullptr;
     762           0 :         MOZ_ASSERT(!mGdkWindow,
     763             :                    "mGdkWindow should be NULL when mContainer is destroyed");
     764             :     }
     765           0 :     else if (mContainer) {
     766           0 :         gtk_widget_destroy(GTK_WIDGET(mContainer));
     767           0 :         mContainer = nullptr;
     768           0 :         MOZ_ASSERT(!mGdkWindow,
     769             :                    "mGdkWindow should be NULL when mContainer is destroyed");
     770             :     }
     771           0 :     else if (mGdkWindow) {
     772             :         // Destroy child windows to ensure that their mThebesSurfaces are
     773             :         // released and to remove references from GdkWindows back to their
     774             :         // container widget.  (OnContainerUnrealize() does this when the
     775             :         // MozContainer widget is destroyed.)
     776           0 :         DestroyChildWindows();
     777             : 
     778           0 :         gdk_window_set_user_data(mGdkWindow, nullptr);
     779           0 :         g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", nullptr);
     780           0 :         gdk_window_destroy(mGdkWindow);
     781           0 :         mGdkWindow = nullptr;
     782             :     }
     783             : 
     784           0 :     if (gInvisibleContainer && owningWidget == gInvisibleContainer) {
     785           0 :         CheckDestroyInvisibleContainer();
     786             :     }
     787             : 
     788             : #ifdef ACCESSIBILITY
     789           0 :      if (mRootAccessible) {
     790           0 :          mRootAccessible = nullptr;
     791             :      }
     792             : #endif
     793             : 
     794             :     // Save until last because OnDestroy() may cause us to be deleted.
     795           0 :     OnDestroy();
     796             : }
     797             : 
     798             : nsIWidget *
     799           9 : nsWindow::GetParent(void)
     800             : {
     801           9 :     return mParent;
     802             : }
     803             : 
     804             : float
     805          36 : nsWindow::GetDPI()
     806             : {
     807          36 :     GdkScreen *screen = gdk_display_get_default_screen(gdk_display_get_default());
     808          36 :     double heightInches = gdk_screen_get_height_mm(screen)/MM_PER_INCH_FLOAT;
     809          36 :     if (heightInches < 0.25) {
     810             :         // Something's broken, but we'd better not crash.
     811           0 :         return 96.0f;
     812             :     }
     813          36 :     return float(gdk_screen_get_height(screen)/heightInches);
     814             : }
     815             : 
     816             : double
     817          50 : nsWindow::GetDefaultScaleInternal()
     818             : {
     819          50 :     return GdkScaleFactor() * gfxPlatformGtk::GetDPIScale();
     820             : }
     821             : 
     822             : void
     823           0 : nsWindow::SetParent(nsIWidget *aNewParent)
     824             : {
     825           0 :     if (mContainer || !mGdkWindow) {
     826           0 :         NS_NOTREACHED("nsWindow::SetParent called illegally");
     827           0 :         return;
     828             :     }
     829             : 
     830           0 :     nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
     831           0 :     if (mParent) {
     832           0 :         mParent->RemoveChild(this);
     833             :     }
     834             : 
     835           0 :     mParent = aNewParent;
     836             : 
     837           0 :     GtkWidget* oldContainer = GetMozContainerWidget();
     838           0 :     if (!oldContainer) {
     839             :         // The GdkWindows have been destroyed so there is nothing else to
     840             :         // reparent.
     841           0 :         MOZ_ASSERT(gdk_window_is_destroyed(mGdkWindow),
     842             :                    "live GdkWindow with no widget");
     843           0 :         return;
     844             :     }
     845             : 
     846           0 :     if (aNewParent) {
     847           0 :         aNewParent->AddChild(this);
     848           0 :         ReparentNativeWidget(aNewParent);
     849             :     } else {
     850             :         // aNewParent is nullptr, but reparent to a hidden window to avoid
     851             :         // destroying the GdkWindow and its descendants.
     852             :         // An invisible container widget is needed to hold descendant
     853             :         // GtkWidgets.
     854           0 :         GtkWidget* newContainer = EnsureInvisibleContainer();
     855           0 :         GdkWindow* newParentWindow = gtk_widget_get_window(newContainer);
     856             :         ReparentNativeWidgetInternal(aNewParent, newContainer, newParentWindow,
     857           0 :                                      oldContainer);
     858             :     }
     859             : }
     860             : 
     861             : bool
     862           1 : nsWindow::WidgetTypeSupportsAcceleration()
     863             : {
     864           1 :   return !IsSmallPopup();
     865             : }
     866             : 
     867             : void
     868           0 : nsWindow::ReparentNativeWidget(nsIWidget* aNewParent)
     869             : {
     870           0 :     NS_PRECONDITION(aNewParent, "");
     871           0 :     NS_ASSERTION(!mIsDestroyed, "");
     872           0 :     NS_ASSERTION(!static_cast<nsWindow*>(aNewParent)->mIsDestroyed, "");
     873             : 
     874           0 :     GtkWidget* oldContainer = GetMozContainerWidget();
     875           0 :     if (!oldContainer) {
     876             :         // The GdkWindows have been destroyed so there is nothing else to
     877             :         // reparent.
     878           0 :         MOZ_ASSERT(gdk_window_is_destroyed(mGdkWindow),
     879             :                    "live GdkWindow with no widget");
     880           0 :         return;
     881             :     }
     882           0 :     MOZ_ASSERT(!gdk_window_is_destroyed(mGdkWindow),
     883             :                "destroyed GdkWindow with widget");
     884             : 
     885           0 :     auto* newParent = static_cast<nsWindow*>(aNewParent);
     886           0 :     GdkWindow* newParentWindow = newParent->mGdkWindow;
     887           0 :     GtkWidget* newContainer = newParent->GetMozContainerWidget();
     888           0 :     GtkWindow* shell = GTK_WINDOW(mShell);
     889             : 
     890           0 :     if (shell && gtk_window_get_transient_for(shell)) {
     891             :       GtkWindow* topLevelParent =
     892           0 :           GTK_WINDOW(gtk_widget_get_toplevel(newContainer));
     893           0 :       gtk_window_set_transient_for(shell, topLevelParent);
     894             :     }
     895             : 
     896             :     ReparentNativeWidgetInternal(aNewParent, newContainer, newParentWindow,
     897           0 :                                  oldContainer);
     898             : }
     899             : 
     900             : void
     901           0 : nsWindow::ReparentNativeWidgetInternal(nsIWidget* aNewParent,
     902             :                                        GtkWidget* aNewContainer,
     903             :                                        GdkWindow* aNewParentWindow,
     904             :                                        GtkWidget* aOldContainer)
     905             : {
     906           0 :     if (!aNewContainer) {
     907             :         // The new parent GdkWindow has been destroyed.
     908           0 :         MOZ_ASSERT(!aNewParentWindow ||
     909             :                    gdk_window_is_destroyed(aNewParentWindow),
     910             :                    "live GdkWindow with no widget");
     911           0 :         Destroy();
     912             :     } else {
     913           0 :         if (aNewContainer != aOldContainer) {
     914           0 :             MOZ_ASSERT(!gdk_window_is_destroyed(aNewParentWindow),
     915             :                        "destroyed GdkWindow with widget");
     916           0 :             SetWidgetForHierarchy(mGdkWindow, aOldContainer, aNewContainer);
     917             : 
     918           0 :             if (aOldContainer == gInvisibleContainer) {
     919           0 :                 CheckDestroyInvisibleContainer();
     920             :             }
     921             :         }
     922             : 
     923           0 :         if (!mIsTopLevel) {
     924           0 :             gdk_window_reparent(mGdkWindow, aNewParentWindow,
     925             :                                 DevicePixelsToGdkCoordRoundDown(mBounds.x),
     926           0 :                                 DevicePixelsToGdkCoordRoundDown(mBounds.y));
     927             :         }
     928             :     }
     929             : 
     930           0 :     auto* newParent = static_cast<nsWindow*>(aNewParent);
     931             :     bool parentHasMappedToplevel =
     932           0 :         newParent && newParent->mHasMappedToplevel;
     933           0 :     if (mHasMappedToplevel != parentHasMappedToplevel) {
     934           0 :         SetHasMappedToplevel(parentHasMappedToplevel);
     935             :     }
     936           0 : }
     937             : 
     938             : void
     939           0 : nsWindow::SetModal(bool aModal)
     940             : {
     941           0 :     LOG(("nsWindow::SetModal [%p] %d\n", (void *)this, aModal));
     942           0 :     if (mIsDestroyed)
     943           0 :         return;
     944           0 :     if (!mIsTopLevel || !mShell)
     945           0 :         return;
     946           0 :     gtk_window_set_modal(GTK_WINDOW(mShell), aModal ? TRUE : FALSE);
     947             : }
     948             : 
     949             : // nsIWidget method, which means IsShown.
     950             : bool
     951          31 : nsWindow::IsVisible() const
     952             : {
     953          31 :     return mIsShown;
     954             : }
     955             : 
     956             : void
     957           1 : nsWindow::RegisterTouchWindow()
     958             : {
     959             : #if GTK_CHECK_VERSION(3,4,0)
     960           1 :     mHandleTouchEvent = true;
     961           1 :     mTouches.Clear();
     962             : #endif
     963           1 : }
     964             : 
     965             : void
     966           0 : nsWindow::ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY)
     967             : {
     968           0 :     if (!mIsTopLevel || !mShell)
     969           0 :       return;
     970             : 
     971           0 :     double dpiScale = GetDefaultScale().scale;
     972             : 
     973             :     // we need to use the window size in logical screen pixels
     974           0 :     int32_t logWidth = std::max(NSToIntRound(mBounds.width / dpiScale), 1);
     975           0 :     int32_t logHeight = std::max(NSToIntRound(mBounds.height / dpiScale), 1);
     976             : 
     977             :     /* get our playing field. use the current screen, or failing that
     978             :       for any reason, use device caps for the default screen. */
     979           0 :     nsCOMPtr<nsIScreen> screen;
     980           0 :     nsCOMPtr<nsIScreenManager> screenmgr = do_GetService("@mozilla.org/gfx/screenmanager;1");
     981           0 :     if (screenmgr) {
     982           0 :       screenmgr->ScreenForRect(*aX, *aY, logWidth, logHeight,
     983           0 :                                getter_AddRefs(screen));
     984             :     }
     985             : 
     986             :     // We don't have any screen so leave the coordinates as is
     987           0 :     if (!screen)
     988           0 :       return;
     989             : 
     990           0 :     nsIntRect screenRect;
     991           0 :     if (mSizeMode != nsSizeMode_Fullscreen) {
     992             :       // For normalized windows, use the desktop work area.
     993           0 :       screen->GetAvailRectDisplayPix(&screenRect.x, &screenRect.y,
     994           0 :                                      &screenRect.width, &screenRect.height);
     995             :     } else {
     996             :       // For full screen windows, use the desktop.
     997           0 :       screen->GetRectDisplayPix(&screenRect.x, &screenRect.y,
     998           0 :                                 &screenRect.width, &screenRect.height);
     999             :     }
    1000             : 
    1001           0 :     if (aAllowSlop) {
    1002           0 :       if (*aX < screenRect.x - logWidth + kWindowPositionSlop)
    1003           0 :           *aX = screenRect.x - logWidth + kWindowPositionSlop;
    1004           0 :       else if (*aX >= screenRect.XMost() - kWindowPositionSlop)
    1005           0 :           *aX = screenRect.XMost() - kWindowPositionSlop;
    1006             : 
    1007           0 :       if (*aY < screenRect.y - logHeight + kWindowPositionSlop)
    1008           0 :           *aY = screenRect.y - logHeight + kWindowPositionSlop;
    1009           0 :       else if (*aY >= screenRect.YMost() - kWindowPositionSlop)
    1010           0 :           *aY = screenRect.YMost() - kWindowPositionSlop;
    1011             :     } else {
    1012           0 :       if (*aX < screenRect.x)
    1013           0 :           *aX = screenRect.x;
    1014           0 :       else if (*aX >= screenRect.XMost() - logWidth)
    1015           0 :           *aX = screenRect.XMost() - logWidth;
    1016             : 
    1017           0 :       if (*aY < screenRect.y)
    1018           0 :           *aY = screenRect.y;
    1019           0 :       else if (*aY >= screenRect.YMost() - logHeight)
    1020           0 :           *aY = screenRect.YMost() - logHeight;
    1021             :     }
    1022             : }
    1023             : 
    1024          20 : void nsWindow::SetSizeConstraints(const SizeConstraints& aConstraints)
    1025             : {
    1026          20 :     mSizeConstraints.mMinSize = GetSafeWindowSize(aConstraints.mMinSize);
    1027          20 :     mSizeConstraints.mMaxSize = GetSafeWindowSize(aConstraints.mMaxSize);
    1028             : 
    1029          20 :     if (mShell) {
    1030             :         GdkGeometry geometry;
    1031          20 :         geometry.min_width = DevicePixelsToGdkCoordRoundUp(
    1032             :                              mSizeConstraints.mMinSize.width);
    1033          20 :         geometry.min_height = DevicePixelsToGdkCoordRoundUp(
    1034             :                               mSizeConstraints.mMinSize.height);
    1035          20 :         geometry.max_width = DevicePixelsToGdkCoordRoundDown(
    1036             :                              mSizeConstraints.mMaxSize.width);
    1037          20 :         geometry.max_height = DevicePixelsToGdkCoordRoundDown(
    1038             :                               mSizeConstraints.mMaxSize.height);
    1039             : 
    1040          20 :         uint32_t hints = 0;
    1041          20 :         if (aConstraints.mMinSize != LayoutDeviceIntSize(0, 0)) {
    1042          20 :             hints |= GDK_HINT_MIN_SIZE;
    1043             :         }
    1044          40 :         if (aConstraints.mMaxSize !=
    1045          40 :             LayoutDeviceIntSize(NS_MAXSIZE, NS_MAXSIZE)) {
    1046           0 :             hints |= GDK_HINT_MAX_SIZE;
    1047             :         }
    1048          20 :         gtk_window_set_geometry_hints(GTK_WINDOW(mShell), nullptr,
    1049          20 :                                       &geometry, GdkWindowHints(hints));
    1050             :     }
    1051          20 : }
    1052             : 
    1053             : void
    1054           1 : nsWindow::Show(bool aState)
    1055             : {
    1056           1 :     if (aState == mIsShown)
    1057           0 :         return;
    1058             : 
    1059             :     // Clear our cached resources when the window is hidden.
    1060           1 :     if (mIsShown && !aState) {
    1061           0 :         ClearCachedResources();
    1062             :     }
    1063             : 
    1064           1 :     mIsShown = aState;
    1065             : 
    1066           1 :     LOG(("nsWindow::Show [%p] state %d\n", (void *)this, aState));
    1067             : 
    1068           1 :     if (aState) {
    1069             :         // Now that this window is shown, mHasMappedToplevel needs to be
    1070             :         // tracked on viewable descendants.
    1071           1 :         SetHasMappedToplevel(mHasMappedToplevel);
    1072             :     }
    1073             : 
    1074             :     // Ok, someone called show on a window that isn't sized to a sane
    1075             :     // value.  Mark this window as needing to have Show() called on it
    1076             :     // and return.
    1077           1 :     if ((aState && !AreBoundsSane()) || !mCreated) {
    1078           0 :         LOG(("\tbounds are insane or window hasn't been created yet\n"));
    1079           0 :         mNeedsShow = true;
    1080           0 :         return;
    1081             :     }
    1082             : 
    1083             :     // If someone is hiding this widget, clear any needing show flag.
    1084           1 :     if (!aState)
    1085           0 :         mNeedsShow = false;
    1086             : 
    1087             : #ifdef ACCESSIBILITY
    1088           1 :     if (aState && a11y::ShouldA11yBeEnabled())
    1089           0 :         CreateRootAccessible();
    1090             : #endif
    1091             : 
    1092           1 :     NativeShow(aState);
    1093             : }
    1094             : 
    1095             : void
    1096           1 : nsWindow::Resize(double aWidth, double aHeight, bool aRepaint)
    1097             : {
    1098           1 :     double scale = BoundsUseDesktopPixels() ? GetDesktopToDeviceScale().scale : 1.0;
    1099           1 :     int32_t width = NSToIntRound(scale * aWidth);
    1100           1 :     int32_t height = NSToIntRound(scale * aHeight);
    1101           1 :     ConstrainSize(&width, &height);
    1102             : 
    1103             :     // For top-level windows, aWidth and aHeight should possibly be
    1104             :     // interpreted as frame bounds, but NativeResize treats these as window
    1105             :     // bounds (Bug 581866).
    1106             : 
    1107           1 :     mBounds.SizeTo(width, height);
    1108             : 
    1109           1 :     if (!mCreated)
    1110           0 :         return;
    1111             : 
    1112           1 :     NativeResize();
    1113             : 
    1114           1 :     NotifyRollupGeometryChange();
    1115             : 
    1116             :     // send a resize notification if this is a toplevel
    1117           1 :     if (mIsTopLevel || mListenForResizes) {
    1118           1 :         DispatchResized();
    1119             :     }
    1120             : }
    1121             : 
    1122             : void
    1123           0 : nsWindow::Resize(double aX, double aY, double aWidth, double aHeight,
    1124             :                  bool aRepaint)
    1125             : {
    1126           0 :     double scale = BoundsUseDesktopPixels() ? GetDesktopToDeviceScale().scale : 1.0;
    1127           0 :     int32_t width = NSToIntRound(scale * aWidth);
    1128           0 :     int32_t height = NSToIntRound(scale * aHeight);
    1129           0 :     ConstrainSize(&width, &height);
    1130             : 
    1131           0 :     int32_t x = NSToIntRound(scale * aX);
    1132           0 :     int32_t y = NSToIntRound(scale * aY);
    1133           0 :     mBounds.x = x;
    1134           0 :     mBounds.y = y;
    1135           0 :     mBounds.SizeTo(width, height);
    1136             : 
    1137           0 :     if (!mCreated)
    1138           0 :         return;
    1139             : 
    1140           0 :     NativeMoveResize();
    1141             : 
    1142           0 :     NotifyRollupGeometryChange();
    1143             : 
    1144           0 :     if (mIsTopLevel || mListenForResizes) {
    1145           0 :         DispatchResized();
    1146             :     }
    1147             : }
    1148             : 
    1149             : void
    1150           0 : nsWindow::Enable(bool aState)
    1151             : {
    1152           0 :     mEnabled = aState;
    1153           0 : }
    1154             : 
    1155             : bool
    1156           1 : nsWindow::IsEnabled() const
    1157             : {
    1158           1 :     return mEnabled;
    1159             : }
    1160             : 
    1161             : void
    1162           0 : nsWindow::Move(double aX, double aY)
    1163             : {
    1164           0 :     LOG(("nsWindow::Move [%p] %f %f\n", (void *)this,
    1165             :          aX, aY));
    1166             : 
    1167           0 :     double scale = BoundsUseDesktopPixels() ? GetDesktopToDeviceScale().scale : 1.0;
    1168           0 :     int32_t x = NSToIntRound(aX * scale);
    1169           0 :     int32_t y = NSToIntRound(aY * scale);
    1170             : 
    1171           0 :     if (mWindowType == eWindowType_toplevel ||
    1172           0 :         mWindowType == eWindowType_dialog) {
    1173           0 :         SetSizeMode(nsSizeMode_Normal);
    1174             :     }
    1175             : 
    1176             :     // Since a popup window's x/y coordinates are in relation to to
    1177             :     // the parent, the parent might have moved so we always move a
    1178             :     // popup window.
    1179           0 :     if (x == mBounds.x && y == mBounds.y &&
    1180           0 :         mWindowType != eWindowType_popup)
    1181           0 :         return;
    1182             : 
    1183             :     // XXX Should we do some AreBoundsSane check here?
    1184             : 
    1185           0 :     mBounds.x = x;
    1186           0 :     mBounds.y = y;
    1187             : 
    1188           0 :     if (!mCreated)
    1189           0 :         return;
    1190             : 
    1191           0 :     NativeMove();
    1192             : 
    1193           0 :     NotifyRollupGeometryChange();
    1194             : }
    1195             : 
    1196             : 
    1197             : void
    1198           0 : nsWindow::NativeMove()
    1199             : {
    1200           0 :     GdkPoint point = DevicePixelsToGdkPointRoundDown(mBounds.TopLeft());
    1201             : 
    1202           0 :     if (mIsTopLevel) {
    1203           0 :         gtk_window_move(GTK_WINDOW(mShell), point.x, point.y);
    1204             :     }
    1205           0 :     else if (mGdkWindow) {
    1206           0 :         gdk_window_move(mGdkWindow, point.x, point.y);
    1207             :     }
    1208           0 : }
    1209             : 
    1210             : void
    1211           0 : nsWindow::SetZIndex(int32_t aZIndex)
    1212             : {
    1213           0 :     nsIWidget* oldPrev = GetPrevSibling();
    1214             : 
    1215           0 :     nsBaseWidget::SetZIndex(aZIndex);
    1216             : 
    1217           0 :     if (GetPrevSibling() == oldPrev) {
    1218           0 :         return;
    1219             :     }
    1220             : 
    1221           0 :     NS_ASSERTION(!mContainer, "Expected Mozilla child widget");
    1222             : 
    1223             :     // We skip the nsWindows that don't have mGdkWindows.
    1224             :     // These are probably in the process of being destroyed.
    1225             : 
    1226           0 :     if (!GetNextSibling()) {
    1227             :         // We're to be on top.
    1228           0 :         if (mGdkWindow)
    1229           0 :             gdk_window_raise(mGdkWindow);
    1230             :     } else {
    1231             :         // All the siblings before us need to be below our widget.
    1232           0 :         for (nsWindow* w = this; w;
    1233           0 :              w = static_cast<nsWindow*>(w->GetPrevSibling())) {
    1234           0 :             if (w->mGdkWindow)
    1235           0 :                 gdk_window_lower(w->mGdkWindow);
    1236             :         }
    1237             :     }
    1238             : }
    1239             : 
    1240             : void
    1241           3 : nsWindow::SetSizeMode(nsSizeMode aMode)
    1242             : {
    1243           3 :     LOG(("nsWindow::SetSizeMode [%p] %d\n", (void *)this, aMode));
    1244             : 
    1245             :     // Save the requested state.
    1246           3 :     nsBaseWidget::SetSizeMode(aMode);
    1247             : 
    1248             :     // return if there's no shell or our current state is the same as
    1249             :     // the mode we were just set to.
    1250           3 :     if (!mShell || mSizeState == mSizeMode) {
    1251           2 :         return;
    1252             :     }
    1253             : 
    1254           1 :     switch (aMode) {
    1255             :     case nsSizeMode_Maximized:
    1256           1 :         gtk_window_maximize(GTK_WINDOW(mShell));
    1257           1 :         break;
    1258             :     case nsSizeMode_Minimized:
    1259           0 :         gtk_window_iconify(GTK_WINDOW(mShell));
    1260           0 :         break;
    1261             :     case nsSizeMode_Fullscreen:
    1262           0 :         MakeFullScreen(true);
    1263           0 :         break;
    1264             : 
    1265             :     default:
    1266             :         // nsSizeMode_Normal, really.
    1267           0 :         if (mSizeState == nsSizeMode_Minimized)
    1268           0 :             gtk_window_deiconify(GTK_WINDOW(mShell));
    1269           0 :         else if (mSizeState == nsSizeMode_Maximized)
    1270           0 :             gtk_window_unmaximize(GTK_WINDOW(mShell));
    1271           0 :         break;
    1272             :     }
    1273             : 
    1274           1 :     mSizeState = mSizeMode;
    1275             : }
    1276             : 
    1277             : typedef void (* SetUserTimeFunc)(GdkWindow* aWindow, guint32 aTimestamp);
    1278             : 
    1279             : // This will become obsolete when new GTK APIs are widely supported,
    1280             : // as described here: http://bugzilla.gnome.org/show_bug.cgi?id=347375
    1281             : static void
    1282           1 : SetUserTimeAndStartupIDForActivatedWindow(GtkWidget* aWindow)
    1283             : {
    1284           1 :     nsGTKToolkit* GTKToolkit = nsGTKToolkit::GetToolkit();
    1285           1 :     if (!GTKToolkit)
    1286           1 :         return;
    1287             : 
    1288           1 :     nsAutoCString desktopStartupID;
    1289           1 :     GTKToolkit->GetDesktopStartupID(&desktopStartupID);
    1290           1 :     if (desktopStartupID.IsEmpty()) {
    1291             :         // We don't have the data we need. Fall back to an
    1292             :         // approximation ... using the timestamp of the remote command
    1293             :         // being received as a guess for the timestamp of the user event
    1294             :         // that triggered it.
    1295           1 :         uint32_t timestamp = GTKToolkit->GetFocusTimestamp();
    1296           1 :         if (timestamp) {
    1297           0 :             gdk_window_focus(gtk_widget_get_window(aWindow), timestamp);
    1298           0 :             GTKToolkit->SetFocusTimestamp(0);
    1299             :         }
    1300           1 :         return;
    1301             :     }
    1302             : 
    1303             : #if defined(MOZ_ENABLE_STARTUP_NOTIFICATION)
    1304             :     // TODO - Implement for non-X11 Gtk backends (Bug 726479)
    1305             :     if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) {
    1306             :         GdkWindow* gdkWindow = gtk_widget_get_window(aWindow);
    1307             : 
    1308             :         GdkScreen* screen = gdk_window_get_screen(gdkWindow);
    1309             :         SnDisplay* snd =
    1310             :             sn_display_new(gdk_x11_display_get_xdisplay(gdk_window_get_display(gdkWindow)),
    1311             :                            nullptr, nullptr);
    1312             :         if (!snd)
    1313             :             return;
    1314             :         SnLauncheeContext* ctx =
    1315             :             sn_launchee_context_new(snd, gdk_screen_get_number(screen),
    1316             :                                     desktopStartupID.get());
    1317             :         if (!ctx) {
    1318             :             sn_display_unref(snd);
    1319             :             return;
    1320             :         }
    1321             : 
    1322             :         if (sn_launchee_context_get_id_has_timestamp(ctx)) {
    1323             :             gdk_x11_window_set_user_time(gdkWindow,
    1324             :                 sn_launchee_context_get_timestamp(ctx));
    1325             :         }
    1326             : 
    1327             :         sn_launchee_context_setup_window(ctx, gdk_x11_window_get_xid(gdkWindow));
    1328             :         sn_launchee_context_complete(ctx);
    1329             : 
    1330             :         sn_launchee_context_unref(ctx);
    1331             :         sn_display_unref(snd);
    1332             :     }
    1333             : #endif
    1334             : 
    1335             :     // If we used the startup ID, that already contains the focus timestamp;
    1336             :     // we don't want to reuse the timestamp next time we raise the window
    1337           0 :     GTKToolkit->SetFocusTimestamp(0);
    1338           0 :     GTKToolkit->SetDesktopStartupID(EmptyCString());
    1339             : }
    1340             : 
    1341             : /* static */ guint32
    1342           0 : nsWindow::GetLastUserInputTime()
    1343             : {
    1344             :     // gdk_x11_display_get_user_time tracks button and key presses,
    1345             :     // DESKTOP_STARTUP_ID used to start the app, drop events from external
    1346             :     // drags, WM_DELETE_WINDOW delete events, but not usually mouse motion nor
    1347             :     // button and key releases.  Therefore use the most recent of
    1348             :     // gdk_x11_display_get_user_time and the last time that we have seen.
    1349             :     guint32 timestamp =
    1350           0 :             gdk_x11_display_get_user_time(gdk_display_get_default());
    1351           0 :     if (sLastUserInputTime != GDK_CURRENT_TIME &&
    1352           0 :         TimestampIsNewerThan(sLastUserInputTime, timestamp)) {
    1353           0 :         return sLastUserInputTime;
    1354             :     }
    1355             : 
    1356           0 :     return timestamp;
    1357             : }
    1358             : 
    1359             : nsresult
    1360           0 : nsWindow::SetFocus(bool aRaise)
    1361             : {
    1362             :     // Make sure that our owning widget has focus.  If it doesn't try to
    1363             :     // grab it.  Note that we don't set our focus flag in this case.
    1364             : 
    1365           0 :     LOGFOCUS(("  SetFocus %d [%p]\n", aRaise, (void *)this));
    1366             : 
    1367           0 :     GtkWidget *owningWidget = GetMozContainerWidget();
    1368           0 :     if (!owningWidget)
    1369           0 :         return NS_ERROR_FAILURE;
    1370             : 
    1371             :     // Raise the window if someone passed in true and the prefs are
    1372             :     // set properly.
    1373           0 :     GtkWidget *toplevelWidget = gtk_widget_get_toplevel(owningWidget);
    1374             : 
    1375           0 :     if (gRaiseWindows && aRaise && toplevelWidget &&
    1376           0 :         !gtk_widget_has_focus(owningWidget) &&
    1377           0 :         !gtk_widget_has_focus(toplevelWidget)) {
    1378           0 :         GtkWidget* top_window = GetToplevelWidget();
    1379           0 :         if (top_window && (gtk_widget_get_visible(top_window)))
    1380             :         {
    1381           0 :             gdk_window_show_unraised(gtk_widget_get_window(top_window));
    1382             :             // Unset the urgency hint if possible.
    1383           0 :             SetUrgencyHint(top_window, false);
    1384             :         }
    1385             :     }
    1386             : 
    1387           0 :     RefPtr<nsWindow> owningWindow = get_window_for_gtk_widget(owningWidget);
    1388           0 :     if (!owningWindow)
    1389           0 :         return NS_ERROR_FAILURE;
    1390             : 
    1391           0 :     if (aRaise) {
    1392             :         // aRaise == true means request toplevel activation.
    1393             : 
    1394             :         // This is asynchronous.
    1395             :         // If and when the window manager accepts the request, then the focus
    1396             :         // widget will get a focus-in-event signal.
    1397           0 :         if (gRaiseWindows && owningWindow->mIsShown && owningWindow->mShell &&
    1398           0 :             !gtk_window_is_active(GTK_WINDOW(owningWindow->mShell))) {
    1399             : 
    1400           0 :             uint32_t timestamp = GDK_CURRENT_TIME;
    1401             : 
    1402           0 :             nsGTKToolkit* GTKToolkit = nsGTKToolkit::GetToolkit();
    1403           0 :             if (GTKToolkit)
    1404           0 :                 timestamp = GTKToolkit->GetFocusTimestamp();
    1405             : 
    1406           0 :             LOGFOCUS(("  requesting toplevel activation [%p]\n", (void *)this));
    1407           0 :             NS_ASSERTION(owningWindow->mWindowType != eWindowType_popup
    1408             :                          || mParent,
    1409             :                          "Presenting an override-redirect window");
    1410           0 :             gtk_window_present_with_time(GTK_WINDOW(owningWindow->mShell), timestamp);
    1411             : 
    1412           0 :             if (GTKToolkit)
    1413           0 :                 GTKToolkit->SetFocusTimestamp(0);
    1414             :         }
    1415             : 
    1416           0 :         return NS_OK;
    1417             :     }
    1418             : 
    1419             :     // aRaise == false means that keyboard events should be dispatched
    1420             :     // from this widget.
    1421             : 
    1422             :     // Ensure owningWidget is the focused GtkWidget within its toplevel window.
    1423             :     //
    1424             :     // For eWindowType_popup, this GtkWidget may not actually be the one that
    1425             :     // receives the key events as it may be the parent window that is active.
    1426           0 :     if (!gtk_widget_is_focus(owningWidget)) {
    1427             :         // This is synchronous.  It takes focus from a plugin or from a widget
    1428             :         // in an embedder.  The focus manager already knows that this window
    1429             :         // is active so gBlockActivateEvent avoids another (unnecessary)
    1430             :         // activate notification.
    1431           0 :         gBlockActivateEvent = true;
    1432           0 :         gtk_widget_grab_focus(owningWidget);
    1433           0 :         gBlockActivateEvent = false;
    1434             :     }
    1435             : 
    1436             :     // If this is the widget that already has focus, return.
    1437           0 :     if (gFocusWindow == this) {
    1438           0 :         LOGFOCUS(("  already have focus [%p]\n", (void *)this));
    1439           0 :         return NS_OK;
    1440             :     }
    1441             : 
    1442             :     // Set this window to be the focused child window
    1443           0 :     gFocusWindow = this;
    1444             : 
    1445           0 :     if (mIMContext) {
    1446           0 :         mIMContext->OnFocusWindow(this);
    1447             :     }
    1448             : 
    1449           0 :     LOGFOCUS(("  widget now has focus in SetFocus() [%p]\n",
    1450             :               (void *)this));
    1451             : 
    1452           0 :     return NS_OK;
    1453             : }
    1454             : 
    1455             : LayoutDeviceIntRect
    1456          26 : nsWindow::GetScreenBounds()
    1457             : {
    1458          26 :     LayoutDeviceIntRect rect;
    1459          26 :     if (mIsTopLevel && mContainer) {
    1460             :         // use the point including window decorations
    1461             :         gint x, y;
    1462          26 :         gdk_window_get_root_origin(gtk_widget_get_window(GTK_WIDGET(mContainer)), &x, &y);
    1463          26 :         rect.MoveTo(GdkPointToDevicePixels({ x, y }));
    1464             :     } else {
    1465           0 :         rect.MoveTo(WidgetToScreenOffset());
    1466             :     }
    1467             :     // mBounds.Size() is the window bounds, not the window-manager frame
    1468             :     // bounds (bug 581863).  gdk_window_get_frame_extents would give the
    1469             :     // frame bounds, but mBounds.Size() is returned here for consistency
    1470             :     // with Resize.
    1471          26 :     rect.SizeTo(mBounds.Size());
    1472          26 :     LOG(("GetScreenBounds %d,%d | %dx%d\n",
    1473             :          rect.x, rect.y, rect.width, rect.height));
    1474          26 :     return rect;
    1475             : }
    1476             : 
    1477             : LayoutDeviceIntSize
    1478           3 : nsWindow::GetClientSize()
    1479             : {
    1480           3 :   return LayoutDeviceIntSize(mBounds.width, mBounds.height);
    1481             : }
    1482             : 
    1483             : LayoutDeviceIntRect
    1484           3 : nsWindow::GetClientBounds()
    1485             : {
    1486             :     // GetBounds returns a rect whose top left represents the top left of the
    1487             :     // outer bounds, but whose width/height represent the size of the inner
    1488             :     // bounds (which is messed up).
    1489           3 :     LayoutDeviceIntRect rect = GetBounds();
    1490           3 :     rect.MoveBy(GetClientOffset());
    1491           3 :     return rect;
    1492             : }
    1493             : 
    1494             : void
    1495           0 : nsWindow::UpdateClientOffset()
    1496             : {
    1497           0 :     AUTO_PROFILER_LABEL("nsWindow::UpdateClientOffset", GRAPHICS);
    1498             : 
    1499           0 :     if (!mIsTopLevel || !mShell || !mGdkWindow || !mIsX11Display ||
    1500           0 :         gtk_window_get_window_type(GTK_WINDOW(mShell)) == GTK_WINDOW_POPUP) {
    1501           0 :         mClientOffset = nsIntPoint(0, 0);
    1502           0 :         return;
    1503             :     }
    1504             : 
    1505           0 :     GdkAtom cardinal_atom = gdk_x11_xatom_to_atom(XA_CARDINAL);
    1506             : 
    1507             :     GdkAtom type_returned;
    1508             :     int format_returned;
    1509             :     int length_returned;
    1510             :     long *frame_extents;
    1511             : 
    1512           0 :     if (!gdk_property_get(mGdkWindow,
    1513             :                           gdk_atom_intern ("_NET_FRAME_EXTENTS", FALSE),
    1514             :                           cardinal_atom,
    1515             :                           0, // offset
    1516             :                           4*4, // length
    1517             :                           FALSE, // delete
    1518             :                           &type_returned,
    1519             :                           &format_returned,
    1520             :                           &length_returned,
    1521           0 :                           (guchar **) &frame_extents) ||
    1522           0 :         length_returned/sizeof(glong) != 4) {
    1523           0 :         mClientOffset = nsIntPoint(0, 0);
    1524           0 :         return;
    1525             :     }
    1526             : 
    1527             :     // data returned is in the order left, right, top, bottom
    1528           0 :     auto left = int32_t(frame_extents[0]);
    1529           0 :     auto top = int32_t(frame_extents[2]);
    1530             : 
    1531           0 :     g_free(frame_extents);
    1532             : 
    1533           0 :     mClientOffset = nsIntPoint(left, top);
    1534             : }
    1535             : 
    1536             : LayoutDeviceIntPoint
    1537          11 : nsWindow::GetClientOffset()
    1538             : {
    1539          11 :     return LayoutDeviceIntPoint::FromUnknownPoint(mClientOffset);
    1540             : }
    1541             : 
    1542             : gboolean
    1543          77 : nsWindow::OnPropertyNotifyEvent(GtkWidget* aWidget, GdkEventProperty* aEvent)
    1544             : 
    1545             : {
    1546          77 :   if (aEvent->atom == gdk_atom_intern("_NET_FRAME_EXTENTS", FALSE)) {
    1547           0 :     UpdateClientOffset();
    1548           0 :     return FALSE;
    1549             :   }
    1550             : 
    1551          77 :   if (GetCurrentTimeGetter()->PropertyNotifyHandler(aWidget, aEvent)) {
    1552           1 :     return TRUE;
    1553             :   }
    1554             : 
    1555          76 :   return FALSE;
    1556             : }
    1557             : 
    1558             : void
    1559           0 : nsWindow::SetCursor(nsCursor aCursor)
    1560             : {
    1561             :     // if we're not the toplevel window pass up the cursor request to
    1562             :     // the toplevel window to handle it.
    1563           0 :     if (!mContainer && mGdkWindow) {
    1564           0 :         nsWindow *window = GetContainerWindow();
    1565           0 :         if (!window)
    1566           0 :             return;
    1567             : 
    1568           0 :         window->SetCursor(aCursor);
    1569           0 :         return;
    1570             :     }
    1571             : 
    1572             :     // Only change cursor if it's actually been changed
    1573           0 :     if (aCursor != mCursor || mUpdateCursor) {
    1574           0 :         GdkCursor *newCursor = nullptr;
    1575           0 :         mUpdateCursor = false;
    1576             : 
    1577           0 :         newCursor = get_gtk_cursor(aCursor);
    1578             : 
    1579           0 :         if (nullptr != newCursor) {
    1580           0 :             mCursor = aCursor;
    1581             : 
    1582           0 :             if (!mContainer)
    1583           0 :                 return;
    1584             : 
    1585           0 :             gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(mContainer)), newCursor);
    1586             :         }
    1587             :     }
    1588             : }
    1589             : 
    1590             : nsresult
    1591           0 : nsWindow::SetCursor(imgIContainer* aCursor,
    1592             :                     uint32_t aHotspotX, uint32_t aHotspotY)
    1593             : {
    1594             :     // if we're not the toplevel window pass up the cursor request to
    1595             :     // the toplevel window to handle it.
    1596           0 :     if (!mContainer && mGdkWindow) {
    1597           0 :         nsWindow *window = GetContainerWindow();
    1598           0 :         if (!window)
    1599           0 :             return NS_ERROR_FAILURE;
    1600             : 
    1601           0 :         return window->SetCursor(aCursor, aHotspotX, aHotspotY);
    1602             :     }
    1603             : 
    1604           0 :     mCursor = nsCursor(-1);
    1605             : 
    1606             :     // Get the image's current frame
    1607           0 :     GdkPixbuf* pixbuf = nsImageToPixbuf::ImageToPixbuf(aCursor);
    1608           0 :     if (!pixbuf)
    1609           0 :         return NS_ERROR_NOT_AVAILABLE;
    1610             : 
    1611           0 :     int width = gdk_pixbuf_get_width(pixbuf);
    1612           0 :     int height = gdk_pixbuf_get_height(pixbuf);
    1613             :     // Reject cursors greater than 128 pixels in some direction, to prevent
    1614             :     // spoofing.
    1615             :     // XXX ideally we should rescale. Also, we could modify the API to
    1616             :     // allow trusted content to set larger cursors.
    1617           0 :     if (width > 128 || height > 128) {
    1618           0 :         g_object_unref(pixbuf);
    1619           0 :         return NS_ERROR_NOT_AVAILABLE;
    1620             :     }
    1621             : 
    1622             :     // Looks like all cursors need an alpha channel (tested on Gtk 2.4.4). This
    1623             :     // is of course not documented anywhere...
    1624             :     // So add one if there isn't one yet
    1625           0 :     if (!gdk_pixbuf_get_has_alpha(pixbuf)) {
    1626           0 :         GdkPixbuf* alphaBuf = gdk_pixbuf_add_alpha(pixbuf, FALSE, 0, 0, 0);
    1627           0 :         g_object_unref(pixbuf);
    1628           0 :         if (!alphaBuf) {
    1629           0 :             return NS_ERROR_OUT_OF_MEMORY;
    1630             :         }
    1631           0 :         pixbuf = alphaBuf;
    1632             :     }
    1633             : 
    1634           0 :     GdkCursor* cursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(),
    1635             :                                                    pixbuf,
    1636           0 :                                                    aHotspotX, aHotspotY);
    1637           0 :     g_object_unref(pixbuf);
    1638           0 :     nsresult rv = NS_ERROR_OUT_OF_MEMORY;
    1639           0 :     if (cursor) {
    1640           0 :         if (mContainer) {
    1641           0 :             gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(mContainer)), cursor);
    1642           0 :             rv = NS_OK;
    1643             :         }
    1644             : #if (MOZ_WIDGET_GTK == 3)
    1645           0 :         g_object_unref(cursor);
    1646             : #else
    1647             :         gdk_cursor_unref(cursor);
    1648             : #endif
    1649             :     }
    1650             : 
    1651           0 :     return rv;
    1652             : }
    1653             : 
    1654             : void
    1655           0 : nsWindow::Invalidate(const LayoutDeviceIntRect& aRect)
    1656             : {
    1657           0 :     if (!mGdkWindow)
    1658           0 :         return;
    1659             : 
    1660           0 :     GdkRectangle rect = DevicePixelsToGdkRectRoundOut(aRect);
    1661           0 :     gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
    1662             : 
    1663           0 :     LOGDRAW(("Invalidate (rect) [%p]: %d %d %d %d\n", (void *)this,
    1664             :              rect.x, rect.y, rect.width, rect.height));
    1665             : }
    1666             : 
    1667             : void*
    1668           1 : nsWindow::GetNativeData(uint32_t aDataType)
    1669             : {
    1670           1 :     switch (aDataType) {
    1671             :     case NS_NATIVE_WINDOW:
    1672             :     case NS_NATIVE_WIDGET: {
    1673           0 :         if (!mGdkWindow)
    1674           0 :             return nullptr;
    1675             : 
    1676           0 :         return mGdkWindow;
    1677             :     }
    1678             : 
    1679             :     case NS_NATIVE_DISPLAY: {
    1680             : #ifdef MOZ_X11
    1681           0 :         GdkDisplay* gdkDisplay = gdk_display_get_default();
    1682           0 :         if (GDK_IS_X11_DISPLAY(gdkDisplay)) {
    1683           0 :           return GDK_DISPLAY_XDISPLAY(gdkDisplay);
    1684             :         }
    1685             : #endif /* MOZ_X11 */
    1686           0 :         return nullptr;
    1687             :     }
    1688             :     case NS_NATIVE_SHELLWIDGET:
    1689           0 :         return GetToplevelWidget();
    1690             : 
    1691             :     case NS_NATIVE_SHAREABLE_WINDOW:
    1692           1 :         return (void *) GDK_WINDOW_XID(gdk_window_get_toplevel(mGdkWindow));
    1693             :     case NS_RAW_NATIVE_IME_CONTEXT: {
    1694           0 :         void* pseudoIMEContext = GetPseudoIMEContext();
    1695           0 :         if (pseudoIMEContext) {
    1696           0 :             return pseudoIMEContext;
    1697             :         }
    1698             :         // If IME context isn't available on this widget, we should set |this|
    1699             :         // instead of nullptr.
    1700           0 :         if (!mIMContext) {
    1701           0 :             return this;
    1702             :         }
    1703           0 :         return mIMContext.get();
    1704             :     }
    1705             :     case NS_NATIVE_OPENGL_CONTEXT:
    1706           0 :       return nullptr;
    1707             : #ifdef MOZ_X11
    1708             :     case NS_NATIVE_COMPOSITOR_DISPLAY:
    1709           0 :         return gfxPlatformGtk::GetPlatform()->GetCompositorDisplay();
    1710             : #endif // MOZ_X11
    1711             :     default:
    1712           0 :         NS_WARNING("nsWindow::GetNativeData called with bad value");
    1713           0 :         return nullptr;
    1714             :     }
    1715             : }
    1716             : 
    1717             : nsresult
    1718           2 : nsWindow::SetTitle(const nsAString& aTitle)
    1719             : {
    1720           2 :     if (!mShell)
    1721           0 :         return NS_OK;
    1722             : 
    1723             :     // convert the string into utf8 and set the title.
    1724             : #define UTF8_FOLLOWBYTE(ch) (((ch) & 0xC0) == 0x80)
    1725           4 :     NS_ConvertUTF16toUTF8 titleUTF8(aTitle);
    1726           2 :     if (titleUTF8.Length() > NS_WINDOW_TITLE_MAX_LENGTH) {
    1727             :         // Truncate overlong titles (bug 167315). Make sure we chop after a
    1728             :         // complete sequence by making sure the next char isn't a follow-byte.
    1729           0 :         uint32_t len = NS_WINDOW_TITLE_MAX_LENGTH;
    1730           0 :         while(UTF8_FOLLOWBYTE(titleUTF8[len]))
    1731           0 :             --len;
    1732           0 :         titleUTF8.Truncate(len);
    1733             :     }
    1734           2 :     gtk_window_set_title(GTK_WINDOW(mShell), (const char *)titleUTF8.get());
    1735             : 
    1736           2 :     return NS_OK;
    1737             : }
    1738             : 
    1739             : void
    1740           4 : nsWindow::SetIcon(const nsAString& aIconSpec)
    1741             : {
    1742           4 :     if (!mShell)
    1743           0 :         return;
    1744             : 
    1745           8 :     nsAutoCString iconName;
    1746             : 
    1747           4 :     if (aIconSpec.EqualsLiteral("default")) {
    1748           6 :         nsXPIDLString brandName;
    1749           3 :         GetBrandName(brandName);
    1750           3 :         AppendUTF16toUTF8(brandName, iconName);
    1751           3 :         ToLowerCase(iconName);
    1752             :     } else {
    1753           1 :         AppendUTF16toUTF8(aIconSpec, iconName);
    1754             :     }
    1755             : 
    1756           8 :     nsCOMPtr<nsIFile> iconFile;
    1757           8 :     nsAutoCString path;
    1758             : 
    1759             :     gint *iconSizes =
    1760           4 :         gtk_icon_theme_get_icon_sizes(gtk_icon_theme_get_default(),
    1761           4 :                                       iconName.get());
    1762           4 :     bool foundIcon = (iconSizes[0] != 0);
    1763           4 :     g_free(iconSizes);
    1764             : 
    1765           4 :     if (!foundIcon) {
    1766             :         // Look for icons with the following suffixes appended to the base name
    1767             :         // The last two entries (for the old XPM format) will be ignored unless
    1768             :         // no icons are found using other suffixes. XPM icons are deprecated.
    1769             : 
    1770             :         const char extensions[6][7] = { ".png", "16.png", "32.png", "48.png",
    1771           2 :                                     ".xpm", "16.xpm" };
    1772             : 
    1773          12 :         for (uint32_t i = 0; i < ArrayLength(extensions); i++) {
    1774             :             // Don't bother looking for XPM versions if we found a PNG.
    1775          11 :             if (i == ArrayLength(extensions) - 2 && foundIcon)
    1776           1 :                 break;
    1777             : 
    1778          20 :             nsAutoString extension;
    1779          10 :             extension.AppendASCII(extensions[i]);
    1780             : 
    1781          10 :             ResolveIconName(aIconSpec, extension, getter_AddRefs(iconFile));
    1782          10 :             if (iconFile) {
    1783           3 :                 iconFile->GetNativePath(path);
    1784           3 :                 GdkPixbuf *icon = gdk_pixbuf_new_from_file(path.get(), nullptr);
    1785           3 :                 if (icon) {
    1786           3 :                     gtk_icon_theme_add_builtin_icon(iconName.get(),
    1787             :                                                     gdk_pixbuf_get_height(icon),
    1788           3 :                                                     icon);
    1789           3 :                     g_object_unref(icon);
    1790           3 :                     foundIcon = true;
    1791             :                 }
    1792             :             }
    1793             :         }
    1794             :     }
    1795             : 
    1796             :     // leave the default icon intact if no matching icons were found
    1797           4 :     if (foundIcon) {
    1798           3 :         gtk_window_set_icon_name(GTK_WINDOW(mShell), iconName.get());
    1799             :     }
    1800             : }
    1801             : 
    1802             : 
    1803             : LayoutDeviceIntPoint
    1804          38 : nsWindow::WidgetToScreenOffset()
    1805             : {
    1806          38 :     gint x = 0, y = 0;
    1807             : 
    1808          38 :     if (mGdkWindow) {
    1809          38 :         gdk_window_get_origin(mGdkWindow, &x, &y);
    1810             :     }
    1811             : 
    1812          38 :     return GdkPointToDevicePixels({ x, y });
    1813             : }
    1814             : 
    1815             : void
    1816           0 : nsWindow::CaptureMouse(bool aCapture)
    1817             : {
    1818           0 :     LOG(("CaptureMouse %p\n", (void *)this));
    1819             : 
    1820           0 :     if (!mGdkWindow)
    1821           0 :         return;
    1822             : 
    1823           0 :     if (!mContainer)
    1824           0 :         return;
    1825             : 
    1826           0 :     if (aCapture) {
    1827           0 :         gtk_grab_add(GTK_WIDGET(mContainer));
    1828           0 :         GrabPointer(GetLastUserInputTime());
    1829             :     }
    1830             :     else {
    1831           0 :         ReleaseGrabs();
    1832           0 :         gtk_grab_remove(GTK_WIDGET(mContainer));
    1833             :     }
    1834             : }
    1835             : 
    1836             : void
    1837           0 : nsWindow::CaptureRollupEvents(nsIRollupListener *aListener,
    1838             :                               bool               aDoCapture)
    1839             : {
    1840           0 :     if (!mGdkWindow)
    1841           0 :         return;
    1842             : 
    1843           0 :     if (!mContainer)
    1844           0 :         return;
    1845             : 
    1846           0 :     LOG(("CaptureRollupEvents %p %i\n", this, int(aDoCapture)));
    1847             : 
    1848           0 :     if (aDoCapture) {
    1849           0 :         gRollupListener = aListener;
    1850             :         // Don't add a grab if a drag is in progress, or if the widget is a drag
    1851             :         // feedback popup. (panels with type="drag").
    1852           0 :         if (!mIsDragPopup && !nsWindow::DragInProgress()) {
    1853           0 :             gtk_grab_add(GTK_WIDGET(mContainer));
    1854           0 :             GrabPointer(GetLastUserInputTime());
    1855             :         }
    1856             :     }
    1857             :     else {
    1858           0 :         if (!nsWindow::DragInProgress()) {
    1859           0 :             ReleaseGrabs();
    1860             :         }
    1861             :         // There may not have been a drag in process when aDoCapture was set,
    1862             :         // so make sure to remove any added grab.  This is a no-op if the grab
    1863             :         // was not added to this widget.
    1864           0 :         gtk_grab_remove(GTK_WIDGET(mContainer));
    1865           0 :         gRollupListener = nullptr;
    1866             :     }
    1867             : }
    1868             : 
    1869             : nsresult
    1870           0 : nsWindow::GetAttention(int32_t aCycleCount)
    1871             : {
    1872           0 :     LOG(("nsWindow::GetAttention [%p]\n", (void *)this));
    1873             : 
    1874           0 :     GtkWidget* top_window = GetToplevelWidget();
    1875             :     GtkWidget* top_focused_window =
    1876           0 :         gFocusWindow ? gFocusWindow->GetToplevelWidget() : nullptr;
    1877             : 
    1878             :     // Don't get attention if the window is focused anyway.
    1879           0 :     if (top_window && (gtk_widget_get_visible(top_window)) &&
    1880             :         top_window != top_focused_window) {
    1881           0 :         SetUrgencyHint(top_window, true);
    1882             :     }
    1883             : 
    1884           0 :     return NS_OK;
    1885             : }
    1886             : 
    1887             : bool
    1888           0 : nsWindow::HasPendingInputEvent()
    1889             : {
    1890             :     // This sucks, but gtk/gdk has no way to answer the question we want while
    1891             :     // excluding paint events, and there's no X API that will let us peek
    1892             :     // without blocking or removing.  To prevent event reordering, peek
    1893             :     // anything except expose events.  Reordering expose and others should be
    1894             :     // ok, hopefully.
    1895           0 :     bool haveEvent = false;
    1896             : #ifdef MOZ_X11
    1897             :     XEvent ev;
    1898           0 :     if (mIsX11Display) {
    1899           0 :         Display *display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default());
    1900           0 :         haveEvent =
    1901           0 :             XCheckMaskEvent(display,
    1902             :                             KeyPressMask | KeyReleaseMask | ButtonPressMask |
    1903             :                             ButtonReleaseMask | EnterWindowMask | LeaveWindowMask |
    1904             :                             PointerMotionMask | PointerMotionHintMask |
    1905             :                             Button1MotionMask | Button2MotionMask |
    1906             :                             Button3MotionMask | Button4MotionMask |
    1907             :                             Button5MotionMask | ButtonMotionMask | KeymapStateMask |
    1908             :                             VisibilityChangeMask | StructureNotifyMask |
    1909             :                             ResizeRedirectMask | SubstructureNotifyMask |
    1910             :                             SubstructureRedirectMask | FocusChangeMask |
    1911             :                             PropertyChangeMask | ColormapChangeMask |
    1912             :                             OwnerGrabButtonMask, &ev);
    1913           0 :         if (haveEvent) {
    1914           0 :             XPutBackEvent(display, &ev);
    1915             :         }
    1916             :     }
    1917             : #endif
    1918           0 :     return haveEvent;
    1919             : }
    1920             : 
    1921             : #if 0
    1922             : #ifdef DEBUG
    1923             : // Paint flashing code (disabled for cairo - see below)
    1924             : 
    1925             : #define CAPS_LOCK_IS_ON \
    1926             : (KeymapWrapper::AreModifiersCurrentlyActive(KeymapWrapper::CAPS_LOCK))
    1927             : 
    1928             : #define WANT_PAINT_FLASHING \
    1929             : (debug_WantPaintFlashing() && CAPS_LOCK_IS_ON)
    1930             : 
    1931             : #ifdef MOZ_X11
    1932             : static void
    1933             : gdk_window_flash(GdkWindow *    aGdkWindow,
    1934             :                  unsigned int   aTimes,
    1935             :                  unsigned int   aInterval,  // Milliseconds
    1936             :                  GdkRegion *    aRegion)
    1937             : {
    1938             :   gint         x;
    1939             :   gint         y;
    1940             :   gint         width;
    1941             :   gint         height;
    1942             :   guint        i;
    1943             :   GdkGC *      gc = 0;
    1944             :   GdkColor     white;
    1945             : 
    1946             : #if (MOZ_WIDGET_GTK == 2)
    1947             :   gdk_window_get_geometry(aGdkWindow,nullptr,nullptr,&width,&height,nullptr);
    1948             : #else
    1949             :   gdk_window_get_geometry(aGdkWindow,nullptr,nullptr,&width,&height);
    1950             : #endif
    1951             : 
    1952             :   gdk_window_get_origin (aGdkWindow,
    1953             :                          &x,
    1954             :                          &y);
    1955             : 
    1956             :   gc = gdk_gc_new(gdk_get_default_root_window());
    1957             : 
    1958             :   white.pixel = WhitePixel(gdk_display,DefaultScreen(gdk_display));
    1959             : 
    1960             :   gdk_gc_set_foreground(gc,&white);
    1961             :   gdk_gc_set_function(gc,GDK_XOR);
    1962             :   gdk_gc_set_subwindow(gc,GDK_INCLUDE_INFERIORS);
    1963             : 
    1964             :   gdk_region_offset(aRegion, x, y);
    1965             :   gdk_gc_set_clip_region(gc, aRegion);
    1966             : 
    1967             :   /*
    1968             :    * Need to do this twice so that the XOR effect can replace
    1969             :    * the original window contents.
    1970             :    */
    1971             :   for (i = 0; i < aTimes * 2; i++)
    1972             :   {
    1973             :     gdk_draw_rectangle(gdk_get_default_root_window(),
    1974             :                        gc,
    1975             :                        TRUE,
    1976             :                        x,
    1977             :                        y,
    1978             :                        width,
    1979             :                        height);
    1980             : 
    1981             :     gdk_flush();
    1982             : 
    1983             :     PR_Sleep(PR_MillisecondsToInterval(aInterval));
    1984             :   }
    1985             : 
    1986             :   gdk_gc_destroy(gc);
    1987             : 
    1988             :   gdk_region_offset(aRegion, -x, -y);
    1989             : }
    1990             : #endif /* MOZ_X11 */
    1991             : #endif // DEBUG
    1992             : #endif
    1993             : 
    1994             : #if (MOZ_WIDGET_GTK == 2)
    1995             : static bool
    1996             : ExtractExposeRegion(LayoutDeviceIntRegion& aRegion, GdkEventExpose* aEvent)
    1997             : {
    1998             :   GdkRectangle* rects;
    1999             :   gint nrects;
    2000             :   gdk_region_get_rectangles(aEvent->region, &rects, &nrects);
    2001             : 
    2002             :   if (nrects > MAX_RECTS_IN_REGION) {
    2003             :       // Just use the bounding box
    2004             :       rects[0] = aEvent->area;
    2005             :       nrects = 1;
    2006             :   }
    2007             : 
    2008             :   for (GdkRectangle* r = rects; r < rects + nrects; r++) {
    2009             :       aRegion.Or(aRegion, LayoutDeviceIntRect(r->x, r->y, r->width, r->height));
    2010             :       LOGDRAW(("\t%d %d %d %d\n", r->x, r->y, r->width, r->height));
    2011             :   }
    2012             : 
    2013             :   g_free(rects);
    2014             :   return true;
    2015             : }
    2016             : 
    2017             : #else
    2018             : # ifdef cairo_copy_clip_rectangle_list
    2019             : #  error "Looks like we're including Mozilla's cairo instead of system cairo"
    2020             : # endif
    2021             : static bool
    2022           1 : ExtractExposeRegion(LayoutDeviceIntRegion& aRegion, cairo_t* cr)
    2023             : {
    2024           1 :   cairo_rectangle_list_t* rects = cairo_copy_clip_rectangle_list(cr);
    2025           1 :   if (rects->status != CAIRO_STATUS_SUCCESS) {
    2026           0 :       NS_WARNING("Failed to obtain cairo rectangle list.");
    2027           0 :       return false;
    2028             :   }
    2029             : 
    2030           2 :   for (int i = 0; i < rects->num_rectangles; i++)  {
    2031           1 :       const cairo_rectangle_t& r = rects->rectangles[i];
    2032           1 :       aRegion.Or(aRegion, LayoutDeviceIntRect::Truncate(r.x, r.y, r.width, r.height));
    2033           1 :       LOGDRAW(("\t%f %f %f %f\n", r.x, r.y, r.width, r.height));
    2034             :   }
    2035             : 
    2036           1 :   cairo_rectangle_list_destroy(rects);
    2037           1 :   return true;
    2038             : }
    2039             : #endif
    2040             : 
    2041             : #if (MOZ_WIDGET_GTK == 2)
    2042             : gboolean
    2043             : nsWindow::OnExposeEvent(GdkEventExpose *aEvent)
    2044             : #else
    2045             : gboolean
    2046           1 : nsWindow::OnExposeEvent(cairo_t *cr)
    2047             : #endif
    2048             : {
    2049             :     // Send any pending resize events so that layout can update.
    2050             :     // May run event loop.
    2051           1 :     MaybeDispatchResized();
    2052             : 
    2053           1 :     if (mIsDestroyed) {
    2054           0 :         return FALSE;
    2055             :     }
    2056             : 
    2057             :     // Windows that are not visible will be painted after they become visible.
    2058           1 :     if (!mGdkWindow || mIsFullyObscured || !mHasMappedToplevel)
    2059           0 :         return FALSE;
    2060             : 
    2061           1 :     nsIWidgetListener *listener = GetListener();
    2062           1 :     if (!listener)
    2063           0 :         return FALSE;
    2064             : 
    2065           2 :     LayoutDeviceIntRegion exposeRegion;
    2066             : #if (MOZ_WIDGET_GTK == 2)
    2067             :     if (!ExtractExposeRegion(exposeRegion, aEvent)) {
    2068             : #else
    2069           1 :     if (!ExtractExposeRegion(exposeRegion, cr)) {
    2070             : #endif
    2071           0 :         return FALSE;
    2072             :     }
    2073             : 
    2074           1 :     gint scale = GdkScaleFactor();
    2075           2 :     LayoutDeviceIntRegion region = exposeRegion;
    2076           1 :     region.ScaleRoundOut(scale, scale);
    2077             : 
    2078           1 :     if (GetLayerManager()->AsKnowsCompositor() && mCompositorSession) {
    2079             :         // We need to paint to the screen even if nothing changed, since if we
    2080             :         // don't have a compositing window manager, our pixels could be stale.
    2081           1 :         GetLayerManager()->SetNeedsComposite(true);
    2082           1 :         GetLayerManager()->SendInvalidRegion(region.ToUnknownRegion());
    2083             :     }
    2084             : 
    2085           2 :     RefPtr<nsWindow> strongThis(this);
    2086             : 
    2087             :     // Dispatch WillPaintWindow notification to allow scripts etc. to run
    2088             :     // before we paint
    2089             :     {
    2090           1 :         listener->WillPaintWindow(this);
    2091             : 
    2092             :         // If the window has been destroyed during the will paint notification,
    2093             :         // there is nothing left to do.
    2094           1 :         if (!mGdkWindow)
    2095           0 :             return TRUE;
    2096             : 
    2097             :         // Re-get the listener since the will paint notification might have
    2098             :         // killed it.
    2099           1 :         listener = GetListener();
    2100           1 :         if (!listener)
    2101           0 :             return FALSE;
    2102             :     }
    2103             : 
    2104           1 :     if (GetLayerManager()->AsKnowsCompositor() && GetLayerManager()->NeedsComposite()) {
    2105           0 :       GetLayerManager()->ScheduleComposite();
    2106           0 :       GetLayerManager()->SetNeedsComposite(false);
    2107             :     }
    2108             : 
    2109           1 :     LOGDRAW(("sending expose event [%p] %p 0x%lx (rects follow):\n",
    2110             :              (void *)this, (void *)mGdkWindow,
    2111             :              gdk_x11_window_get_xid(mGdkWindow)));
    2112             : 
    2113             :     // Our bounds may have changed after calling WillPaintWindow.  Clip
    2114             :     // to the new bounds here.  The region is relative to this
    2115             :     // window.
    2116           1 :     region.And(region, LayoutDeviceIntRect(0, 0, mBounds.width, mBounds.height));
    2117             : 
    2118           1 :     bool shaped = false;
    2119           1 :     if (eTransparencyTransparent == GetTransparencyMode()) {
    2120           0 :         GdkScreen *screen = gdk_window_get_screen(mGdkWindow);
    2121           0 :         if (gdk_screen_is_composited(screen) &&
    2122           0 :             gdk_window_get_visual(mGdkWindow) ==
    2123           0 :             gdk_screen_get_rgba_visual(screen)) {
    2124             :             // Remove possible shape mask from when window manger was not
    2125             :             // previously compositing.
    2126           0 :             static_cast<nsWindow*>(GetTopLevelWidget())->
    2127           0 :                 ClearTransparencyBitmap();
    2128             :         } else {
    2129           0 :             shaped = true;
    2130             :         }
    2131             :     }
    2132             : 
    2133           1 :     if (!shaped) {
    2134             :         GList *children =
    2135           1 :             gdk_window_peek_children(mGdkWindow);
    2136           1 :         while (children) {
    2137           0 :             GdkWindow *gdkWin = GDK_WINDOW(children->data);
    2138           0 :             nsWindow *kid = get_window_for_gdk_window(gdkWin);
    2139           0 :             if (kid && gdk_window_is_visible(gdkWin)) {
    2140           0 :                 AutoTArray<LayoutDeviceIntRect,1> clipRects;
    2141           0 :                 kid->GetWindowClipRegion(&clipRects);
    2142           0 :                 LayoutDeviceIntRect bounds = kid->GetBounds();
    2143           0 :                 for (uint32_t i = 0; i < clipRects.Length(); ++i) {
    2144           0 :                     LayoutDeviceIntRect r = clipRects[i] + bounds.TopLeft();
    2145           0 :                     region.Sub(region, r);
    2146             :                 }
    2147             :             }
    2148           0 :             children = children->next;
    2149             :         }
    2150             :     }
    2151             : 
    2152           1 :     if (region.IsEmpty()) {
    2153           0 :         return TRUE;
    2154             :     }
    2155             : 
    2156             :     // If this widget uses OMTC...
    2157           1 :     if (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT ||
    2158           0 :         GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_WR) {
    2159           1 :         listener->PaintWindow(this, region);
    2160             : 
    2161             :         // Re-get the listener since the will paint notification might have
    2162             :         // killed it.
    2163           1 :         listener = GetListener();
    2164           1 :         if (!listener)
    2165           0 :             return TRUE;
    2166             : 
    2167           1 :         listener->DidPaintWindow();
    2168           1 :         return TRUE;
    2169             :     }
    2170             : 
    2171           0 :     BufferMode layerBuffering = BufferMode::BUFFERED;
    2172           0 :     RefPtr<DrawTarget> dt = StartRemoteDrawingInRegion(region, &layerBuffering);
    2173           0 :     if (!dt || !dt->IsValid()) {
    2174           0 :         return FALSE;
    2175             :     }
    2176           0 :     RefPtr<gfxContext> ctx;
    2177           0 :     IntRect boundsRect = region.GetBounds().ToUnknownRect();
    2178           0 :     IntPoint offset(0, 0);
    2179           0 :     if (dt->GetSize() == boundsRect.Size()) {
    2180           0 :       offset = boundsRect.TopLeft();
    2181           0 :       dt->SetTransform(Matrix::Translation(-offset));
    2182             :     }
    2183             : 
    2184             : #ifdef MOZ_X11
    2185           0 :     if (shaped) {
    2186             :         // Collapse update area to the bounding box. This is so we only have to
    2187             :         // call UpdateTranslucentWindowAlpha once. After we have dropped
    2188             :         // support for non-Thebes graphics, UpdateTranslucentWindowAlpha will be
    2189             :         // our private interface so we can rework things to avoid this.
    2190           0 :         dt->PushClipRect(Rect(boundsRect));
    2191             : 
    2192             :         // The double buffering is done here to extract the shape mask.
    2193             :         // (The shape mask won't be necessary when a visual with an alpha
    2194             :         // channel is used on compositing window managers.)
    2195           0 :         layerBuffering = BufferMode::BUFFER_NONE;
    2196           0 :         RefPtr<DrawTarget> destDT = dt->CreateSimilarDrawTarget(boundsRect.Size(), SurfaceFormat::B8G8R8A8);
    2197           0 :         if (!destDT || !destDT->IsValid()) {
    2198           0 :             return FALSE;
    2199             :         }
    2200           0 :         destDT->SetTransform(Matrix::Translation(-boundsRect.TopLeft()));
    2201           0 :         ctx = gfxContext::CreatePreservingTransformOrNull(destDT);
    2202             :     } else {
    2203           0 :         gfxUtils::ClipToRegion(dt, region.ToUnknownRegion());
    2204           0 :         ctx = gfxContext::CreatePreservingTransformOrNull(dt);
    2205             :     }
    2206           0 :     MOZ_ASSERT(ctx); // checked both dt and destDT valid draw target above
    2207             : 
    2208             : #if 0
    2209             :     // NOTE: Paint flashing region would be wrong for cairo, since
    2210             :     // cairo inflates the update region, etc.  So don't paint flash
    2211             :     // for cairo.
    2212             : #ifdef DEBUG
    2213             :     // XXX aEvent->region may refer to a newly-invalid area.  FIXME
    2214             :     if (0 && WANT_PAINT_FLASHING && gtk_widget_get_window(aEvent))
    2215             :         gdk_window_flash(mGdkWindow, 1, 100, aEvent->region);
    2216             : #endif
    2217             : #endif
    2218             : 
    2219             : #endif // MOZ_X11
    2220             : 
    2221           0 :     bool painted = false;
    2222             :     {
    2223           0 :       if (GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_BASIC) {
    2224           0 :         GdkScreen *screen = gdk_window_get_screen(mGdkWindow);
    2225           0 :         if (GetTransparencyMode() == eTransparencyTransparent &&
    2226           0 :             layerBuffering == BufferMode::BUFFER_NONE &&
    2227           0 :             gdk_screen_is_composited(screen) &&
    2228           0 :             gdk_window_get_visual(mGdkWindow) ==
    2229           0 :             gdk_screen_get_rgba_visual(screen)) {
    2230             :           // If our draw target is unbuffered and we use an alpha channel,
    2231             :           // clear the image beforehand to ensure we don't get artifacts from a
    2232             :           // reused SHM image. See bug 1258086.
    2233           0 :           dt->ClearRect(Rect(boundsRect));
    2234             :         }
    2235           0 :         AutoLayerManagerSetup setupLayerManager(this, ctx, layerBuffering);
    2236           0 :         painted = listener->PaintWindow(this, region);
    2237             : 
    2238             :         // Re-get the listener since the will paint notification might have
    2239             :         // killed it.
    2240           0 :         listener = GetListener();
    2241           0 :         if (!listener)
    2242           0 :             return TRUE;
    2243             : 
    2244             :       }
    2245             :     }
    2246             : 
    2247             : #ifdef MOZ_X11
    2248             :     // PaintWindow can Destroy us (bug 378273), avoid doing any paint
    2249             :     // operations below if that happened - it will lead to XError and exit().
    2250           0 :     if (shaped) {
    2251           0 :         if (MOZ_LIKELY(!mIsDestroyed)) {
    2252           0 :             if (painted) {
    2253           0 :                 RefPtr<SourceSurface> surf = ctx->GetDrawTarget()->Snapshot();
    2254             : 
    2255           0 :                 UpdateAlpha(surf, boundsRect);
    2256             : 
    2257           0 :                 dt->DrawSurface(surf, Rect(boundsRect), Rect(0, 0, boundsRect.width, boundsRect.height),
    2258           0 :                                 DrawSurfaceOptions(SamplingFilter::POINT),
    2259           0 :                                 DrawOptions(1.0f, CompositionOp::OP_SOURCE));
    2260             :             }
    2261             :         }
    2262             :     }
    2263             : 
    2264           0 :     ctx = nullptr;
    2265           0 :     dt->PopClip();
    2266             : 
    2267             : #endif // MOZ_X11
    2268             : 
    2269           0 :     EndRemoteDrawingInRegion(dt, region);
    2270             : 
    2271           0 :     listener->DidPaintWindow();
    2272             : 
    2273             :     // Synchronously flush any new dirty areas
    2274             : #if (MOZ_WIDGET_GTK == 2)
    2275             :     GdkRegion* dirtyArea = gdk_window_get_update_area(mGdkWindow);
    2276             : #else
    2277           0 :     cairo_region_t* dirtyArea = gdk_window_get_update_area(mGdkWindow);
    2278             : #endif
    2279             : 
    2280           0 :     if (dirtyArea) {
    2281           0 :         gdk_window_invalidate_region(mGdkWindow, dirtyArea, false);
    2282             : #if (MOZ_WIDGET_GTK == 2)
    2283             :         gdk_region_destroy(dirtyArea);
    2284             : #else
    2285           0 :         cairo_region_destroy(dirtyArea);
    2286             : #endif
    2287           0 :         gdk_window_process_updates(mGdkWindow, false);
    2288             :     }
    2289             : 
    2290             :     // check the return value!
    2291           0 :     return TRUE;
    2292             : }
    2293             : 
    2294             : void
    2295           0 : nsWindow::UpdateAlpha(SourceSurface* aSourceSurface, nsIntRect aBoundsRect)
    2296             : {
    2297             :     // We need to create our own buffer to force the stride to match the
    2298             :     // expected stride.
    2299           0 :     int32_t stride = GetAlignedStride<4>(aBoundsRect.width,
    2300           0 :                                          BytesPerPixel(SurfaceFormat::A8));
    2301           0 :     if (stride == 0) {
    2302           0 :         return;
    2303             :     }
    2304           0 :     int32_t bufferSize = stride * aBoundsRect.height;
    2305           0 :     auto imageBuffer = MakeUniqueFallible<uint8_t[]>(bufferSize);
    2306             :     {
    2307           0 :         RefPtr<DrawTarget> drawTarget = gfxPlatform::CreateDrawTargetForData(
    2308             :                                               imageBuffer.get(),
    2309           0 :                                               aBoundsRect.Size(),
    2310           0 :                                               stride, SurfaceFormat::A8);
    2311             : 
    2312           0 :         if (drawTarget) {
    2313           0 :             drawTarget->DrawSurface(aSourceSurface, Rect(0, 0, aBoundsRect.width, aBoundsRect.height),
    2314           0 :                                     Rect(0, 0, aSourceSurface->GetSize().width, aSourceSurface->GetSize().height),
    2315           0 :                                     DrawSurfaceOptions(SamplingFilter::POINT),
    2316           0 :                                     DrawOptions(1.0f, CompositionOp::OP_SOURCE));
    2317             :         }
    2318             :     }
    2319           0 :     UpdateTranslucentWindowAlphaInternal(aBoundsRect, imageBuffer.get(), stride);
    2320             : }
    2321             : 
    2322             : gboolean
    2323           5 : nsWindow::OnConfigureEvent(GtkWidget *aWidget, GdkEventConfigure *aEvent)
    2324             : {
    2325             :     // These events are only received on toplevel windows.
    2326             :     //
    2327             :     // GDK ensures that the coordinates are the client window top-left wrt the
    2328             :     // root window.
    2329             :     //
    2330             :     //   GDK calculates the cordinates for real ConfigureNotify events on
    2331             :     //   managed windows (that would normally be relative to the parent
    2332             :     //   window).
    2333             :     //
    2334             :     //   Synthetic ConfigureNotify events are from the window manager and
    2335             :     //   already relative to the root window.  GDK creates all X windows with
    2336             :     //   border_width = 0, so synthetic events also indicate the top-left of
    2337             :     //   the client window.
    2338             :     //
    2339             :     //   Override-redirect windows are children of the root window so parent
    2340             :     //   coordinates are root coordinates.
    2341             : 
    2342           5 :     LOG(("configure event [%p] %d %d %d %d\n", (void *)this,
    2343             :          aEvent->x, aEvent->y, aEvent->width, aEvent->height));
    2344             : 
    2345           5 :     if (mPendingConfigures > 0) {
    2346           1 :         mPendingConfigures--;
    2347             :     }
    2348             : 
    2349           5 :     LayoutDeviceIntRect screenBounds = GetScreenBounds();
    2350             : 
    2351           5 :     if (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog) {
    2352             :         // This check avoids unwanted rollup on spurious configure events from
    2353             :         // Cygwin/X (bug 672103).
    2354           9 :         if (mBounds.x != screenBounds.x ||
    2355           4 :             mBounds.y != screenBounds.y) {
    2356           1 :             CheckForRollup(0, 0, false, true);
    2357             :         }
    2358             :     }
    2359             : 
    2360             :     // This event indicates that the window position may have changed.
    2361             :     // mBounds.Size() is updated in OnSizeAllocate().
    2362             : 
    2363           5 :     NS_ASSERTION(GTK_IS_WINDOW(aWidget),
    2364             :                  "Configure event on widget that is not a GtkWindow");
    2365           5 :     if (gtk_window_get_window_type(GTK_WINDOW(aWidget)) == GTK_WINDOW_POPUP) {
    2366             :         // Override-redirect window
    2367             :         //
    2368             :         // These windows should not be moved by the window manager, and so any
    2369             :         // change in position is a result of our direction.  mBounds has
    2370             :         // already been set in Move() or Resize(), and that is more
    2371             :         // up-to-date than the position in the ConfigureNotify event if the
    2372             :         // event is from an earlier window move.
    2373             :         //
    2374             :         // Skipping the WindowMoved call saves context menus from an infinite
    2375             :         // loop when nsXULPopupManager::PopupMoved moves the window to the new
    2376             :         // position and nsMenuPopupFrame::SetPopupPosition adds
    2377             :         // offsetForContextMenu on each iteration.
    2378           0 :         return FALSE;
    2379             :     }
    2380             : 
    2381           5 :     mBounds.MoveTo(screenBounds.TopLeft());
    2382             : 
    2383             :     // XXX mozilla will invalidate the entire window after this move
    2384             :     // complete.  wtf?
    2385           5 :     NotifyWindowMoved(mBounds.x, mBounds.y);
    2386             : 
    2387           5 :     return FALSE;
    2388             : }
    2389             : 
    2390             : void
    2391           0 : nsWindow::OnContainerUnrealize()
    2392             : {
    2393             :     // The GdkWindows are about to be destroyed (but not deleted), so remove
    2394             :     // their references back to their container widget while the GdkWindow
    2395             :     // hierarchy is still available.
    2396             : 
    2397           0 :     if (mGdkWindow) {
    2398           0 :         DestroyChildWindows();
    2399             : 
    2400           0 :         g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", nullptr);
    2401           0 :         mGdkWindow = nullptr;
    2402             :     }
    2403           0 : }
    2404             : 
    2405             : void
    2406           1 : nsWindow::OnSizeAllocate(GtkAllocation *aAllocation)
    2407             : {
    2408           1 :     LOG(("size_allocate [%p] %d %d %d %d\n",
    2409             :          (void *)this, aAllocation->x, aAllocation->y,
    2410             :          aAllocation->width, aAllocation->height));
    2411             : 
    2412           1 :     LayoutDeviceIntSize size = GdkRectToDevicePixels(*aAllocation).Size();
    2413             : 
    2414           1 :     if (mBounds.Size() == size)
    2415           0 :         return;
    2416             : 
    2417             :     // Invalidate the new part of the window now for the pending paint to
    2418             :     // minimize background flashes (GDK does not do this for external resizes
    2419             :     // of toplevels.)
    2420           1 :     if (mBounds.width < size.width) {
    2421             :         GdkRectangle rect = DevicePixelsToGdkRectRoundOut(
    2422             :             LayoutDeviceIntRect(mBounds.width, 0,
    2423           1 :                                 size.width - mBounds.width, size.height));
    2424           1 :         gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
    2425             :     }
    2426           1 :     if (mBounds.height < size.height) {
    2427             :         GdkRectangle rect = DevicePixelsToGdkRectRoundOut(
    2428             :             LayoutDeviceIntRect(0, mBounds.height,
    2429           1 :                                 size.width, size.height - mBounds.height));
    2430           1 :         gdk_window_invalidate_rect(mGdkWindow, &rect, FALSE);
    2431             :     }
    2432             : 
    2433           1 :     mBounds.SizeTo(size);
    2434             : 
    2435             : #ifdef MOZ_X11
    2436             :     // Notify the X11CompositorWidget of a ClientSizeChange
    2437           1 :     if (mCompositorWidgetDelegate) {
    2438           1 :       mCompositorWidgetDelegate->NotifyClientSizeChanged(GetClientSize());
    2439             :     }
    2440             : #endif
    2441             : 
    2442             :     // Gecko permits running nested event loops during processing of events,
    2443             :     // GtkWindow callers of gtk_widget_size_allocate expect the signal
    2444             :     // handlers to return sometime in the near future.
    2445           1 :     mNeedsDispatchResized = true;
    2446           2 :     NS_DispatchToCurrentThread(NewRunnableMethod(
    2447           1 :       "nsWindow::MaybeDispatchResized", this, &nsWindow::MaybeDispatchResized));
    2448             : }
    2449             : 
    2450             : void
    2451           0 : nsWindow::OnDeleteEvent()
    2452             : {
    2453           0 :     if (mWidgetListener)
    2454           0 :         mWidgetListener->RequestWindowClose(this);
    2455           0 : }
    2456             : 
    2457             : void
    2458           1 : nsWindow::OnEnterNotifyEvent(GdkEventCrossing *aEvent)
    2459             : {
    2460             :     // This skips NotifyVirtual and NotifyNonlinearVirtual enter notify events
    2461             :     // when the pointer enters a child window.  If the destination window is a
    2462             :     // Gecko window then we'll catch the corresponding event on that window,
    2463             :     // but we won't notice when the pointer directly enters a foreign (plugin)
    2464             :     // child window without passing over a visible portion of a Gecko window.
    2465           1 :     if (aEvent->subwindow != nullptr)
    2466           0 :         return;
    2467             : 
    2468             :     // Check before is_parent_ungrab_enter() as the button state may have
    2469             :     // changed while a non-Gecko ancestor window had a pointer grab.
    2470           1 :     DispatchMissedButtonReleases(aEvent);
    2471             : 
    2472           1 :     if (is_parent_ungrab_enter(aEvent))
    2473           0 :         return;
    2474             : 
    2475             :     WidgetMouseEvent event(true, eMouseEnterIntoWidget, this,
    2476           2 :                            WidgetMouseEvent::eReal);
    2477             : 
    2478           1 :     event.mRefPoint = GdkEventCoordsToDevicePixels(aEvent->x, aEvent->y);
    2479           1 :     event.AssignEventTime(GetWidgetEventTime(aEvent->time));
    2480             : 
    2481           1 :     LOG(("OnEnterNotify: %p\n", (void *)this));
    2482             : 
    2483           1 :     DispatchInputEvent(&event);
    2484             : }
    2485             : 
    2486             : // XXX Is this the right test for embedding cases?
    2487             : static bool
    2488           1 : is_top_level_mouse_exit(GdkWindow* aWindow, GdkEventCrossing *aEvent)
    2489             : {
    2490           1 :     auto x = gint(aEvent->x_root);
    2491           1 :     auto y = gint(aEvent->y_root);
    2492           1 :     GdkDisplay* display = gdk_window_get_display(aWindow);
    2493           1 :     GdkWindow* winAtPt = gdk_display_get_window_at_pointer(display, &x, &y);
    2494           1 :     if (!winAtPt)
    2495           1 :         return true;
    2496           0 :     GdkWindow* topLevelAtPt = gdk_window_get_toplevel(winAtPt);
    2497           0 :     GdkWindow* topLevelWidget = gdk_window_get_toplevel(aWindow);
    2498           0 :     return topLevelAtPt != topLevelWidget;
    2499             : }
    2500             : 
    2501             : void
    2502           1 : nsWindow::OnLeaveNotifyEvent(GdkEventCrossing *aEvent)
    2503             : {
    2504             :     // This ignores NotifyVirtual and NotifyNonlinearVirtual leave notify
    2505             :     // events when the pointer leaves a child window.  If the destination
    2506             :     // window is a Gecko window then we'll catch the corresponding event on
    2507             :     // that window.
    2508             :     //
    2509             :     // XXXkt However, we will miss toplevel exits when the pointer directly
    2510             :     // leaves a foreign (plugin) child window without passing over a visible
    2511             :     // portion of a Gecko window.
    2512           1 :     if (aEvent->subwindow != nullptr)
    2513           0 :         return;
    2514             : 
    2515             :     WidgetMouseEvent event(true, eMouseExitFromWidget, this,
    2516           2 :                            WidgetMouseEvent::eReal);
    2517             : 
    2518           1 :     event.mRefPoint = GdkEventCoordsToDevicePixels(aEvent->x, aEvent->y);
    2519           1 :     event.AssignEventTime(GetWidgetEventTime(aEvent->time));
    2520             : 
    2521           2 :     event.mExitFrom = is_top_level_mouse_exit(mGdkWindow, aEvent)
    2522           1 :         ? WidgetMouseEvent::eTopLevel : WidgetMouseEvent::eChild;
    2523             : 
    2524           1 :     LOG(("OnLeaveNotify: %p\n", (void *)this));
    2525             : 
    2526           1 :     DispatchInputEvent(&event);
    2527             : }
    2528             : 
    2529             : template <typename Event> static LayoutDeviceIntPoint
    2530           4 : GetRefPoint(nsWindow* aWindow, Event* aEvent)
    2531             : {
    2532           4 :     if (aEvent->window == aWindow->GetGdkWindow()) {
    2533             :         // we are the window that the event happened on so no need for expensive WidgetToScreenOffset
    2534           4 :         return aWindow->GdkEventCoordsToDevicePixels(aEvent->x, aEvent->y);
    2535             :     }
    2536             :     // XXX we're never quite sure which GdkWindow the event came from due to our custom bubbling
    2537             :     // in scroll_event_cb(), so use ScreenToWidget to translate the screen root coordinates into
    2538             :     // coordinates relative to this widget.
    2539             :     return aWindow->GdkEventCoordsToDevicePixels(
    2540           0 :         aEvent->x_root, aEvent->y_root) - aWindow->WidgetToScreenOffset();
    2541             : }
    2542             : 
    2543             : void
    2544           4 : nsWindow::OnMotionNotifyEvent(GdkEventMotion *aEvent)
    2545             : {
    2546             :     // see if we can compress this event
    2547             :     // XXXldb Why skip every other motion event when we have multiple,
    2548             :     // but not more than that?
    2549           4 :     bool synthEvent = false;
    2550             : #ifdef MOZ_X11
    2551             :     XEvent xevent;
    2552             : 
    2553           4 :     if (mIsX11Display) {
    2554           4 :         while (XPending (GDK_WINDOW_XDISPLAY(aEvent->window))) {
    2555             :             XEvent peeked;
    2556           3 :             XPeekEvent (GDK_WINDOW_XDISPLAY(aEvent->window), &peeked);
    2557           6 :             if (peeked.xany.window != gdk_x11_window_get_xid(aEvent->window)
    2558           3 :                 || peeked.type != MotionNotify)
    2559           3 :                 break;
    2560             : 
    2561           0 :             synthEvent = true;
    2562           0 :             XNextEvent (GDK_WINDOW_XDISPLAY(aEvent->window), &xevent);
    2563             :         }
    2564             :     }
    2565             : #endif /* MOZ_X11 */
    2566             : 
    2567           8 :     WidgetMouseEvent event(true, eMouseMove, this, WidgetMouseEvent::eReal);
    2568             : 
    2569           4 :     gdouble pressure = 0;
    2570           4 :     gdk_event_get_axis ((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
    2571             :     // Sometime gdk generate 0 pressure value between normal values
    2572             :     // We have to ignore that and use last valid value
    2573           4 :     if (pressure)
    2574           0 :       mLastMotionPressure = pressure;
    2575           4 :     event.pressure = mLastMotionPressure;
    2576             : 
    2577             :     guint modifierState;
    2578           4 :     if (synthEvent) {
    2579             : #ifdef MOZ_X11
    2580           0 :         event.mRefPoint.x = nscoord(xevent.xmotion.x);
    2581           0 :         event.mRefPoint.y = nscoord(xevent.xmotion.y);
    2582             : 
    2583           0 :         modifierState = xevent.xmotion.state;
    2584             : 
    2585           0 :         event.AssignEventTime(GetWidgetEventTime(xevent.xmotion.time));
    2586             : #else
    2587             :         event.mRefPoint = GdkEventCoordsToDevicePixels(aEvent->x, aEvent->y);
    2588             : 
    2589             :         modifierState = aEvent->state;
    2590             : 
    2591             :         event.AssignEventTime(GetWidgetEventTime(aEvent->time));
    2592             : #endif /* MOZ_X11 */
    2593             :     } else {
    2594           4 :         event.mRefPoint = GetRefPoint(this, aEvent);
    2595             : 
    2596           4 :         modifierState = aEvent->state;
    2597             : 
    2598           4 :         event.AssignEventTime(GetWidgetEventTime(aEvent->time));
    2599             :     }
    2600             : 
    2601           4 :     KeymapWrapper::InitInputEvent(event, modifierState);
    2602             : 
    2603           4 :     DispatchInputEvent(&event);
    2604           4 : }
    2605             : 
    2606             : // If the automatic pointer grab on ButtonPress has deactivated before
    2607             : // ButtonRelease, and the mouse button is released while the pointer is not
    2608             : // over any a Gecko window, then the ButtonRelease event will not be received.
    2609             : // (A similar situation exists when the pointer is grabbed with owner_events
    2610             : // True as the ButtonRelease may be received on a foreign [plugin] window).
    2611             : // Use this method to check for released buttons when the pointer returns to a
    2612             : // Gecko window.
    2613             : void
    2614           1 : nsWindow::DispatchMissedButtonReleases(GdkEventCrossing *aGdkEvent)
    2615             : {
    2616           1 :     guint changed = aGdkEvent->state ^ gButtonState;
    2617             :     // Only consider button releases.
    2618             :     // (Ignore button presses that occurred outside Gecko.)
    2619           1 :     guint released = changed & gButtonState;
    2620           1 :     gButtonState = aGdkEvent->state;
    2621             : 
    2622             :     // Loop over each button, excluding mouse wheel buttons 4 and 5 for which
    2623             :     // GDK ignores releases.
    2624           4 :     for (guint buttonMask = GDK_BUTTON1_MASK;
    2625           4 :          buttonMask <= GDK_BUTTON3_MASK;
    2626           3 :          buttonMask <<= 1) {
    2627             : 
    2628           3 :         if (released & buttonMask) {
    2629             :             int16_t buttonType;
    2630           0 :             switch (buttonMask) {
    2631             :             case GDK_BUTTON1_MASK:
    2632           0 :                 buttonType = WidgetMouseEvent::eLeftButton;
    2633           0 :                 break;
    2634             :             case GDK_BUTTON2_MASK:
    2635           0 :                 buttonType = WidgetMouseEvent::eMiddleButton;
    2636           0 :                 break;
    2637             :             default:
    2638           0 :                 NS_ASSERTION(buttonMask == GDK_BUTTON3_MASK,
    2639             :                              "Unexpected button mask");
    2640           0 :                 buttonType = WidgetMouseEvent::eRightButton;
    2641             :             }
    2642             : 
    2643           0 :             LOG(("Synthesized button %u release on %p\n",
    2644             :                  guint(buttonType + 1), (void *)this));
    2645             : 
    2646             :             // Dispatch a synthesized button up event to tell Gecko about the
    2647             :             // change in state.  This event is marked as synthesized so that
    2648             :             // it is not dispatched as a DOM event, because we don't know the
    2649             :             // position, widget, modifiers, or time/order.
    2650             :             WidgetMouseEvent synthEvent(true, eMouseUp, this,
    2651           0 :                                         WidgetMouseEvent::eSynthesized);
    2652           0 :             synthEvent.button = buttonType;
    2653           0 :             DispatchInputEvent(&synthEvent);
    2654             :         }
    2655             :     }
    2656           1 : }
    2657             : 
    2658             : void
    2659           0 : nsWindow::InitButtonEvent(WidgetMouseEvent& aEvent,
    2660             :                           GdkEventButton* aGdkEvent)
    2661             : {
    2662           0 :     aEvent.mRefPoint = GetRefPoint(this, aGdkEvent);
    2663             : 
    2664           0 :     guint modifierState = aGdkEvent->state;
    2665             :     // aEvent's state includes the button state from immediately before this
    2666             :     // event.  If aEvent is a mousedown or mouseup event, we need to update
    2667             :     // the button state.
    2668           0 :     guint buttonMask = 0;
    2669           0 :     switch (aGdkEvent->button) {
    2670             :         case 1:
    2671           0 :             buttonMask = GDK_BUTTON1_MASK;
    2672           0 :             break;
    2673             :         case 2:
    2674           0 :             buttonMask = GDK_BUTTON2_MASK;
    2675           0 :             break;
    2676             :         case 3:
    2677           0 :             buttonMask = GDK_BUTTON3_MASK;
    2678           0 :             break;
    2679             :     }
    2680           0 :     if (aGdkEvent->type == GDK_BUTTON_RELEASE) {
    2681           0 :         modifierState &= ~buttonMask;
    2682             :     } else {
    2683           0 :         modifierState |= buttonMask;
    2684             :     }
    2685             : 
    2686           0 :     KeymapWrapper::InitInputEvent(aEvent, modifierState);
    2687             : 
    2688           0 :     aEvent.AssignEventTime(GetWidgetEventTime(aGdkEvent->time));
    2689             : 
    2690           0 :     switch (aGdkEvent->type) {
    2691             :     case GDK_2BUTTON_PRESS:
    2692           0 :         aEvent.mClickCount = 2;
    2693           0 :         break;
    2694             :     case GDK_3BUTTON_PRESS:
    2695           0 :         aEvent.mClickCount = 3;
    2696           0 :         break;
    2697             :         // default is one click
    2698             :     default:
    2699           0 :         aEvent.mClickCount = 1;
    2700             :     }
    2701           0 : }
    2702             : 
    2703           0 : static guint ButtonMaskFromGDKButton(guint button)
    2704             : {
    2705           0 :     return GDK_BUTTON1_MASK << (button - 1);
    2706             : }
    2707             : 
    2708             : void
    2709           0 : nsWindow::OnButtonPressEvent(GdkEventButton *aEvent)
    2710             : {
    2711           0 :     LOG(("Button %u press on %p\n", aEvent->button, (void *)this));
    2712             : 
    2713             :     // If you double click in GDK, it will actually generate a second
    2714             :     // GDK_BUTTON_PRESS before sending the GDK_2BUTTON_PRESS, and this is
    2715             :     // different than the DOM spec.  GDK puts this in the queue
    2716             :     // programatically, so it's safe to assume that if there's a
    2717             :     // double click in the queue, it was generated so we can just drop
    2718             :     // this click.
    2719           0 :     GdkEvent *peekedEvent = gdk_event_peek();
    2720           0 :     if (peekedEvent) {
    2721           0 :         GdkEventType type = peekedEvent->any.type;
    2722           0 :         gdk_event_free(peekedEvent);
    2723           0 :         if (type == GDK_2BUTTON_PRESS || type == GDK_3BUTTON_PRESS)
    2724           0 :             return;
    2725             :     }
    2726             : 
    2727           0 :     nsWindow *containerWindow = GetContainerWindow();
    2728           0 :     if (!gFocusWindow && containerWindow) {
    2729           0 :         containerWindow->DispatchActivateEvent();
    2730             :     }
    2731             : 
    2732             :     // check to see if we should rollup
    2733           0 :     if (CheckForRollup(aEvent->x_root, aEvent->y_root, false, false))
    2734           0 :         return;
    2735             : 
    2736           0 :     gdouble pressure = 0;
    2737           0 :     gdk_event_get_axis ((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
    2738           0 :     mLastMotionPressure = pressure;
    2739             : 
    2740             :     uint16_t domButton;
    2741           0 :     switch (aEvent->button) {
    2742             :     case 1:
    2743           0 :         domButton = WidgetMouseEvent::eLeftButton;
    2744           0 :         break;
    2745             :     case 2:
    2746           0 :         domButton = WidgetMouseEvent::eMiddleButton;
    2747           0 :         break;
    2748             :     case 3:
    2749           0 :         domButton = WidgetMouseEvent::eRightButton;
    2750           0 :         break;
    2751             :     // These are mapped to horizontal scroll
    2752             :     case 6:
    2753             :     case 7:
    2754           0 :         NS_WARNING("We're not supporting legacy horizontal scroll event");
    2755           0 :         return;
    2756             :     // Map buttons 8-9 to back/forward
    2757             :     case 8:
    2758           0 :         DispatchCommandEvent(nsGkAtoms::Back);
    2759           0 :         return;
    2760             :     case 9:
    2761           0 :         DispatchCommandEvent(nsGkAtoms::Forward);
    2762           0 :         return;
    2763             :     default:
    2764           0 :         return;
    2765             :     }
    2766             : 
    2767           0 :     gButtonState |= ButtonMaskFromGDKButton(aEvent->button);
    2768             : 
    2769           0 :     WidgetMouseEvent event(true, eMouseDown, this, WidgetMouseEvent::eReal);
    2770           0 :     event.button = domButton;
    2771           0 :     InitButtonEvent(event, aEvent);
    2772           0 :     event.pressure = mLastMotionPressure;
    2773             : 
    2774           0 :     DispatchInputEvent(&event);
    2775             : 
    2776             :     // right menu click on linux should also pop up a context menu
    2777           0 :     if (domButton == WidgetMouseEvent::eRightButton &&
    2778           0 :         MOZ_LIKELY(!mIsDestroyed)) {
    2779             :         WidgetMouseEvent contextMenuEvent(true, eContextMenu, this,
    2780           0 :                                           WidgetMouseEvent::eReal);
    2781           0 :         InitButtonEvent(contextMenuEvent, aEvent);
    2782           0 :         contextMenuEvent.pressure = mLastMotionPressure;
    2783           0 :         DispatchInputEvent(&contextMenuEvent);
    2784             :     }
    2785             : }
    2786             : 
    2787             : void
    2788           0 : nsWindow::OnButtonReleaseEvent(GdkEventButton *aEvent)
    2789             : {
    2790           0 :     LOG(("Button %u release on %p\n", aEvent->button, (void *)this));
    2791             : 
    2792             :     uint16_t domButton;
    2793           0 :     switch (aEvent->button) {
    2794             :     case 1:
    2795           0 :         domButton = WidgetMouseEvent::eLeftButton;
    2796           0 :         break;
    2797             :     case 2:
    2798           0 :         domButton = WidgetMouseEvent::eMiddleButton;
    2799           0 :         break;
    2800             :     case 3:
    2801           0 :         domButton = WidgetMouseEvent::eRightButton;
    2802           0 :         break;
    2803             :     default:
    2804           0 :         return;
    2805             :     }
    2806             : 
    2807           0 :     gButtonState &= ~ButtonMaskFromGDKButton(aEvent->button);
    2808             : 
    2809             :     WidgetMouseEvent event(true, eMouseUp, this,
    2810           0 :                            WidgetMouseEvent::eReal);
    2811           0 :     event.button = domButton;
    2812           0 :     InitButtonEvent(event, aEvent);
    2813           0 :     gdouble pressure = 0;
    2814           0 :     gdk_event_get_axis ((GdkEvent*)aEvent, GDK_AXIS_PRESSURE, &pressure);
    2815           0 :     event.pressure = pressure ? pressure : mLastMotionPressure;
    2816             : 
    2817           0 :     DispatchInputEvent(&event);
    2818           0 :     mLastMotionPressure = pressure;
    2819             : }
    2820             : 
    2821             : void
    2822           1 : nsWindow::OnContainerFocusInEvent(GdkEventFocus *aEvent)
    2823             : {
    2824           1 :     LOGFOCUS(("OnContainerFocusInEvent [%p]\n", (void *)this));
    2825             : 
    2826             :     // Unset the urgency hint, if possible
    2827           1 :     GtkWidget* top_window = GetToplevelWidget();
    2828           1 :     if (top_window && (gtk_widget_get_visible(top_window)))
    2829           1 :         SetUrgencyHint(top_window, false);
    2830             : 
    2831             :     // Return if being called within SetFocus because the focus manager
    2832             :     // already knows that the window is active.
    2833           1 :     if (gBlockActivateEvent) {
    2834           0 :         LOGFOCUS(("activated notification is blocked [%p]\n", (void *)this));
    2835           0 :         return;
    2836             :     }
    2837             : 
    2838             :     // If keyboard input will be accepted, the focus manager will call
    2839             :     // SetFocus to set the correct window.
    2840           1 :     gFocusWindow = nullptr;
    2841             : 
    2842           1 :     DispatchActivateEvent();
    2843             : 
    2844           1 :     if (!gFocusWindow) {
    2845             :         // We don't really have a window for dispatching key events, but
    2846             :         // setting a non-nullptr value here prevents OnButtonPressEvent() from
    2847             :         // dispatching an activation notification if the widget is already
    2848             :         // active.
    2849           1 :         gFocusWindow = this;
    2850             :     }
    2851             : 
    2852           1 :     LOGFOCUS(("Events sent from focus in event [%p]\n", (void *)this));
    2853             : }
    2854             : 
    2855             : void
    2856           0 : nsWindow::OnContainerFocusOutEvent(GdkEventFocus *aEvent)
    2857             : {
    2858           0 :     LOGFOCUS(("OnContainerFocusOutEvent [%p]\n", (void *)this));
    2859             : 
    2860           0 :     if (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog) {
    2861           0 :         nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
    2862           0 :         nsCOMPtr<nsIDragSession> dragSession;
    2863           0 :         dragService->GetCurrentSession(getter_AddRefs(dragSession));
    2864             : 
    2865             :         // Rollup popups when a window is focused out unless a drag is occurring.
    2866             :         // This check is because drags grab the keyboard and cause a focus out on
    2867             :         // versions of GTK before 2.18.
    2868           0 :         bool shouldRollup = !dragSession;
    2869           0 :         if (!shouldRollup) {
    2870             :             // we also roll up when a drag is from a different application
    2871           0 :             nsCOMPtr<nsIDOMNode> sourceNode;
    2872           0 :             dragSession->GetSourceNode(getter_AddRefs(sourceNode));
    2873           0 :             shouldRollup = (sourceNode == nullptr);
    2874             :         }
    2875             : 
    2876           0 :         if (shouldRollup) {
    2877           0 :             CheckForRollup(0, 0, false, true);
    2878             :         }
    2879             :     }
    2880             : 
    2881           0 :     if (gFocusWindow) {
    2882           0 :         RefPtr<nsWindow> kungFuDeathGrip = gFocusWindow;
    2883           0 :         if (gFocusWindow->mIMContext) {
    2884           0 :             gFocusWindow->mIMContext->OnBlurWindow(gFocusWindow);
    2885             :         }
    2886           0 :         gFocusWindow = nullptr;
    2887             :     }
    2888             : 
    2889           0 :     DispatchDeactivateEvent();
    2890             : 
    2891           0 :     LOGFOCUS(("Done with container focus out [%p]\n", (void *)this));
    2892           0 : }
    2893             : 
    2894             : bool
    2895           0 : nsWindow::DispatchCommandEvent(nsIAtom* aCommand)
    2896             : {
    2897             :     nsEventStatus status;
    2898           0 :     WidgetCommandEvent event(true, nsGkAtoms::onAppCommand, aCommand, this);
    2899           0 :     DispatchEvent(&event, status);
    2900           0 :     return TRUE;
    2901             : }
    2902             : 
    2903             : bool
    2904           0 : nsWindow::DispatchContentCommandEvent(EventMessage aMsg)
    2905             : {
    2906             :   nsEventStatus status;
    2907           0 :   WidgetContentCommandEvent event(true, aMsg, this);
    2908           0 :   DispatchEvent(&event, status);
    2909           0 :   return TRUE;
    2910             : }
    2911             : 
    2912             : static bool
    2913           0 : IsCtrlAltTab(GdkEventKey *aEvent)
    2914             : {
    2915           0 :     return aEvent->keyval == GDK_Tab &&
    2916           0 :         KeymapWrapper::AreModifiersActive(
    2917           0 :             KeymapWrapper::CTRL | KeymapWrapper::ALT, aEvent->state);
    2918             : }
    2919             : 
    2920             : bool
    2921           0 : nsWindow::DispatchKeyDownEvent(GdkEventKey *aEvent, bool *aCancelled)
    2922             : {
    2923           0 :     NS_PRECONDITION(aCancelled, "aCancelled must not be null");
    2924             : 
    2925           0 :     *aCancelled = false;
    2926             : 
    2927           0 :     if (IsCtrlAltTab(aEvent)) {
    2928           0 :         return false;
    2929             :     }
    2930             : 
    2931           0 :     RefPtr<TextEventDispatcher> dispatcher = GetTextEventDispatcher();
    2932           0 :     nsresult rv = dispatcher->BeginNativeInputTransaction();
    2933           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    2934           0 :         return FALSE;
    2935             :     }
    2936             : 
    2937           0 :     WidgetKeyboardEvent keydownEvent(true, eKeyDown, this);
    2938           0 :     KeymapWrapper::InitKeyEvent(keydownEvent, aEvent);
    2939           0 :     nsEventStatus status = nsEventStatus_eIgnore;
    2940             :     bool dispatched =
    2941           0 :         dispatcher->DispatchKeyboardEvent(eKeyDown, keydownEvent,
    2942           0 :                                           status, aEvent);
    2943           0 :     *aCancelled = (status == nsEventStatus_eConsumeNoDefault);
    2944           0 :     return dispatched ? TRUE : FALSE;
    2945             : }
    2946             : 
    2947             : WidgetEventTime
    2948           6 : nsWindow::GetWidgetEventTime(guint32 aEventTime)
    2949             : {
    2950           6 :   return WidgetEventTime(aEventTime, GetEventTimeStamp(aEventTime));
    2951             : }
    2952             : 
    2953             : TimeStamp
    2954           6 : nsWindow::GetEventTimeStamp(guint32 aEventTime)
    2955             : {
    2956           6 :     if (MOZ_UNLIKELY(!mGdkWindow)) {
    2957             :         // nsWindow has been Destroy()ed.
    2958           0 :         return TimeStamp::Now();
    2959             :     }
    2960           6 :     if (aEventTime == 0) {
    2961             :         // Some X11 and GDK events may be received with a time of 0 to indicate
    2962             :         // that they are synthetic events. Some input method editors do this.
    2963             :         // In this case too, just return the current timestamp.
    2964           0 :         return TimeStamp::Now();
    2965             :     }
    2966           6 :     CurrentX11TimeGetter* getCurrentTime = GetCurrentTimeGetter();
    2967           6 :     MOZ_ASSERT(getCurrentTime,
    2968             :                "Null current time getter despite having a window");
    2969           6 :     return TimeConverter().GetTimeStampFromSystemTime(aEventTime,
    2970           6 :                                                       *getCurrentTime);
    2971             : }
    2972             : 
    2973             : mozilla::CurrentX11TimeGetter*
    2974          83 : nsWindow::GetCurrentTimeGetter() {
    2975          83 :     MOZ_ASSERT(mGdkWindow, "Expected mGdkWindow to be set");
    2976          83 :     if (MOZ_UNLIKELY(!mCurrentTimeGetter)) {
    2977           2 :         mCurrentTimeGetter = MakeUnique<CurrentX11TimeGetter>(mGdkWindow);
    2978             :     }
    2979          83 :     return mCurrentTimeGetter.get();
    2980             : }
    2981             : 
    2982             : gboolean
    2983           0 : nsWindow::OnKeyPressEvent(GdkEventKey *aEvent)
    2984             : {
    2985           0 :     LOGFOCUS(("OnKeyPressEvent [%p]\n", (void *)this));
    2986             : 
    2987             :     // if we are in the middle of composing text, XIM gets to see it
    2988             :     // before mozilla does.
    2989             :     // FYI: Don't dispatch keydown event before notifying IME of the event
    2990             :     //      because IME may send a key event synchronously and consume the
    2991             :     //      original event.
    2992           0 :     bool IMEWasEnabled = false;
    2993           0 :     if (mIMContext) {
    2994           0 :         IMEWasEnabled = mIMContext->IsEnabled();
    2995           0 :         if (mIMContext->OnKeyEvent(this, aEvent)) {
    2996           0 :             return TRUE;
    2997             :         }
    2998             :     }
    2999             : 
    3000             :     // work around for annoying things.
    3001           0 :     if (IsCtrlAltTab(aEvent)) {
    3002           0 :         return TRUE;
    3003             :     }
    3004             : 
    3005           0 :     nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
    3006             : 
    3007             :     // Dispatch keydown event always.  At auto repeating, we should send
    3008             :     // KEYDOWN -> KEYPRESS -> KEYDOWN -> KEYPRESS ... -> KEYUP
    3009             :     // However, old distributions (e.g., Ubuntu 9.10) sent native key
    3010             :     // release event, so, on such platform, the DOM events will be:
    3011             :     // KEYDOWN -> KEYPRESS -> KEYUP -> KEYDOWN -> KEYPRESS -> KEYUP...
    3012             : 
    3013           0 :     bool isKeyDownCancelled = false;
    3014           0 :     if (DispatchKeyDownEvent(aEvent, &isKeyDownCancelled) &&
    3015           0 :         (MOZ_UNLIKELY(mIsDestroyed) || isKeyDownCancelled)) {
    3016           0 :         return TRUE;
    3017             :     }
    3018             : 
    3019             :     // If a keydown event handler causes to enable IME, i.e., it moves
    3020             :     // focus from IME unusable content to IME usable editor, we should
    3021             :     // send the native key event to IME for the first input on the editor.
    3022           0 :     if (!IMEWasEnabled && mIMContext && mIMContext->IsEnabled()) {
    3023             :         // Notice our keydown event was already dispatched.  This prevents
    3024             :         // unnecessary DOM keydown event in the editor.
    3025           0 :         if (mIMContext->OnKeyEvent(this, aEvent, true)) {
    3026           0 :             return TRUE;
    3027             :         }
    3028             :     }
    3029             : 
    3030             :     // Look for specialized app-command keys
    3031           0 :     switch (aEvent->keyval) {
    3032             :         case GDK_Back:
    3033           0 :             return DispatchCommandEvent(nsGkAtoms::Back);
    3034             :         case GDK_Forward:
    3035           0 :             return DispatchCommandEvent(nsGkAtoms::Forward);
    3036             :         case GDK_Refresh:
    3037           0 :             return DispatchCommandEvent(nsGkAtoms::Reload);
    3038             :         case GDK_Stop:
    3039           0 :             return DispatchCommandEvent(nsGkAtoms::Stop);
    3040             :         case GDK_Search:
    3041           0 :             return DispatchCommandEvent(nsGkAtoms::Search);
    3042             :         case GDK_Favorites:
    3043           0 :             return DispatchCommandEvent(nsGkAtoms::Bookmarks);
    3044             :         case GDK_HomePage:
    3045           0 :             return DispatchCommandEvent(nsGkAtoms::Home);
    3046             :         case GDK_Copy:
    3047             :         case GDK_F16:  // F16, F20, F18, F14 are old keysyms for Copy Cut Paste Undo
    3048           0 :             return DispatchContentCommandEvent(eContentCommandCopy);
    3049             :         case GDK_Cut:
    3050             :         case GDK_F20:
    3051           0 :             return DispatchContentCommandEvent(eContentCommandCut);
    3052             :         case GDK_Paste:
    3053             :         case GDK_F18:
    3054           0 :             return DispatchContentCommandEvent(eContentCommandPaste);
    3055             :         case GDK_Redo:
    3056           0 :             return DispatchContentCommandEvent(eContentCommandRedo);
    3057             :         case GDK_Undo:
    3058             :         case GDK_F14:
    3059           0 :             return DispatchContentCommandEvent(eContentCommandUndo);
    3060             :     }
    3061             : 
    3062           0 :     WidgetKeyboardEvent keypressEvent(true, eKeyPress, this);
    3063           0 :     KeymapWrapper::InitKeyEvent(keypressEvent, aEvent);
    3064             : 
    3065             :     // before we dispatch a key, check if it's the context menu key.
    3066             :     // If so, send a context menu key event instead.
    3067           0 :     if (MaybeDispatchContextMenuEvent(aEvent)) {
    3068           0 :         return TRUE;
    3069             :     }
    3070             : 
    3071           0 :     RefPtr<TextEventDispatcher> dispatcher = GetTextEventDispatcher();
    3072           0 :     nsresult rv = dispatcher->BeginNativeInputTransaction();
    3073           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    3074           0 :         return TRUE;
    3075             :     }
    3076             : 
    3077             :     // If the character code is in the BMP, send the key press event.
    3078             :     // Otherwise, send a compositionchange event with the equivalent UTF-16
    3079             :     // string.
    3080             :     // TODO: Investigate other browser's behavior in this case because
    3081             :     //       this hack is odd for UI Events.
    3082           0 :     nsEventStatus status = nsEventStatus_eIgnore;
    3083           0 :     if (keypressEvent.mKeyNameIndex != KEY_NAME_INDEX_USE_STRING ||
    3084           0 :         keypressEvent.mKeyValue.Length() == 1) {
    3085           0 :         dispatcher->MaybeDispatchKeypressEvents(keypressEvent,
    3086           0 :                                                 status, aEvent);
    3087             :     } else {
    3088           0 :         WidgetEventTime eventTime = GetWidgetEventTime(aEvent->time);
    3089           0 :         dispatcher->CommitComposition(status, &keypressEvent.mKeyValue,
    3090           0 :                                       &eventTime);
    3091             :     }
    3092             : 
    3093           0 :     return TRUE;
    3094             : }
    3095             : 
    3096             : bool
    3097           0 : nsWindow::MaybeDispatchContextMenuEvent(const GdkEventKey* aEvent)
    3098             : {
    3099           0 :     KeyNameIndex keyNameIndex = KeymapWrapper::ComputeDOMKeyNameIndex(aEvent);
    3100             : 
    3101             :     // Shift+F10 and ContextMenu should cause eContextMenu event.
    3102           0 :     if (keyNameIndex != KEY_NAME_INDEX_F10 &&
    3103             :         keyNameIndex != KEY_NAME_INDEX_ContextMenu) {
    3104           0 :       return false;
    3105             :     }
    3106             : 
    3107             :     WidgetMouseEvent contextMenuEvent(true, eContextMenu, this,
    3108             :                                       WidgetMouseEvent::eReal,
    3109           0 :                                       WidgetMouseEvent::eContextMenuKey);
    3110             : 
    3111           0 :     contextMenuEvent.mRefPoint = LayoutDeviceIntPoint(0, 0);
    3112           0 :     contextMenuEvent.AssignEventTime(GetWidgetEventTime(aEvent->time));
    3113           0 :     contextMenuEvent.mClickCount = 1;
    3114           0 :     KeymapWrapper::InitInputEvent(contextMenuEvent, aEvent->state);
    3115             : 
    3116           0 :     if (contextMenuEvent.IsControl() || contextMenuEvent.IsMeta() ||
    3117           0 :         contextMenuEvent.IsAlt()) {
    3118           0 :         return false;
    3119             :     }
    3120             : 
    3121             :     // If the key is ContextMenu, then an eContextMenu mouse event is
    3122             :     // dispatched regardless of the state of the Shift modifier.  When it is
    3123             :     // pressed without the Shift modifier, a web page can prevent the default
    3124             :     // context menu action.  When pressed with the Shift modifier, the web page
    3125             :     // cannot prevent the default context menu action.
    3126             :     // (PresShell::HandleEventInternal() sets mOnlyChromeDispatch to true.)
    3127             : 
    3128             :     // If the key is F10, it needs Shift state because Shift+F10 is well-known
    3129             :     // shortcut key on Linux.  However, eContextMenu with Shift state is
    3130             :     // special.  It won't fire "contextmenu" event in the web content for
    3131             :     // blocking web page to prevent its default.  Therefore, this combination
    3132             :     // should work same as ContextMenu key.
    3133             :     // XXX Should we allow to block web page to prevent its default with
    3134             :     //     Ctrl+Shift+F10 or Alt+Shift+F10 instead?
    3135           0 :     if (keyNameIndex == KEY_NAME_INDEX_F10) {
    3136           0 :         if (!contextMenuEvent.IsShift()) {
    3137           0 :             return false;
    3138             :         }
    3139           0 :         contextMenuEvent.mModifiers &= ~MODIFIER_SHIFT;
    3140             :     }
    3141             : 
    3142           0 :     DispatchInputEvent(&contextMenuEvent);
    3143           0 :     return true;
    3144             : }
    3145             : 
    3146             : gboolean
    3147           0 : nsWindow::OnKeyReleaseEvent(GdkEventKey *aEvent)
    3148             : {
    3149           0 :     LOGFOCUS(("OnKeyReleaseEvent [%p]\n", (void *)this));
    3150             : 
    3151           0 :     if (mIMContext && mIMContext->OnKeyEvent(this, aEvent)) {
    3152           0 :         return TRUE;
    3153             :     }
    3154             : 
    3155           0 :     RefPtr<TextEventDispatcher> dispatcher = GetTextEventDispatcher();
    3156           0 :     nsresult rv = dispatcher->BeginNativeInputTransaction();
    3157           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
    3158           0 :         return false;
    3159             :     }
    3160             : 
    3161           0 :     WidgetKeyboardEvent keyupEvent(true, eKeyUp, this);
    3162           0 :     KeymapWrapper::InitKeyEvent(keyupEvent, aEvent);
    3163           0 :     nsEventStatus status = nsEventStatus_eIgnore;
    3164           0 :     dispatcher->DispatchKeyboardEvent(eKeyUp, keyupEvent, status, aEvent);
    3165             : 
    3166           0 :     return TRUE;
    3167             : }
    3168             : 
    3169             : void
    3170           0 : nsWindow::OnScrollEvent(GdkEventScroll *aEvent)
    3171             : {
    3172             :     // check to see if we should rollup
    3173           0 :     if (CheckForRollup(aEvent->x_root, aEvent->y_root, true, false))
    3174           0 :         return;
    3175             : #if GTK_CHECK_VERSION(3,4,0)
    3176             :     // check for duplicate legacy scroll event, see GNOME bug 726878
    3177           0 :     if (aEvent->direction != GDK_SCROLL_SMOOTH &&
    3178           0 :         mLastScrollEventTime == aEvent->time)
    3179           0 :         return;
    3180             : #endif
    3181           0 :     WidgetWheelEvent wheelEvent(true, eWheel, this);
    3182           0 :     wheelEvent.mDeltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE;
    3183           0 :     switch (aEvent->direction) {
    3184             : #if GTK_CHECK_VERSION(3,4,0)
    3185             :     case GDK_SCROLL_SMOOTH:
    3186             :     {
    3187             :         // As of GTK 3.4, all directional scroll events are provided by
    3188             :         // the GDK_SCROLL_SMOOTH direction on XInput2 devices.
    3189           0 :         mLastScrollEventTime = aEvent->time;
    3190             :         // TODO - use a more appropriate scrolling unit than lines.
    3191             :         // Multiply event deltas by 3 to emulate legacy behaviour.
    3192           0 :         wheelEvent.mDeltaX = aEvent->delta_x * 3;
    3193           0 :         wheelEvent.mDeltaY = aEvent->delta_y * 3;
    3194           0 :         wheelEvent.mIsNoLineOrPageDelta = true;
    3195             :         // This next step manually unsets smooth scrolling for touch devices
    3196             :         // that trigger GDK_SCROLL_SMOOTH. We use the slave device, which
    3197             :         // represents the actual input.
    3198           0 :         GdkDevice *device = gdk_event_get_source_device((GdkEvent*)aEvent);
    3199           0 :         GdkInputSource source = gdk_device_get_source(device);
    3200           0 :         if (source == GDK_SOURCE_TOUCHSCREEN ||
    3201             :             source == GDK_SOURCE_TOUCHPAD) {
    3202           0 :             wheelEvent.mScrollType = WidgetWheelEvent::SCROLL_ASYNCHRONOUSELY;
    3203             :         }
    3204           0 :         break;
    3205             :     }
    3206             : #endif
    3207             :     case GDK_SCROLL_UP:
    3208           0 :         wheelEvent.mDeltaY = wheelEvent.mLineOrPageDeltaY = -3;
    3209           0 :         break;
    3210             :     case GDK_SCROLL_DOWN:
    3211           0 :         wheelEvent.mDeltaY = wheelEvent.mLineOrPageDeltaY = 3;
    3212           0 :         break;
    3213             :     case GDK_SCROLL_LEFT:
    3214           0 :         wheelEvent.mDeltaX = wheelEvent.mLineOrPageDeltaX = -1;
    3215           0 :         break;
    3216             :     case GDK_SCROLL_RIGHT:
    3217           0 :         wheelEvent.mDeltaX = wheelEvent.mLineOrPageDeltaX = 1;
    3218           0 :         break;
    3219             :     }
    3220             : 
    3221           0 :     wheelEvent.mRefPoint = GetRefPoint(this, aEvent);
    3222             : 
    3223           0 :     KeymapWrapper::InitInputEvent(wheelEvent, aEvent->state);
    3224             : 
    3225           0 :     wheelEvent.AssignEventTime(GetWidgetEventTime(aEvent->time));
    3226             : 
    3227           0 :     DispatchInputEvent(&wheelEvent);
    3228             : }
    3229             : 
    3230             : void
    3231           2 : nsWindow::OnVisibilityNotifyEvent(GdkEventVisibility *aEvent)
    3232             : {
    3233           2 :     LOGDRAW(("Visibility event %i on [%p] %p\n",
    3234             :              aEvent->state, this, aEvent->window));
    3235             : 
    3236           2 :     if (!mGdkWindow)
    3237           0 :         return;
    3238             : 
    3239           2 :     switch (aEvent->state) {
    3240             :     case GDK_VISIBILITY_UNOBSCURED:
    3241             :     case GDK_VISIBILITY_PARTIAL:
    3242           2 :         if (mIsFullyObscured && mHasMappedToplevel) {
    3243             :             // GDK_EXPOSE events have been ignored, so make sure GDK
    3244             :             // doesn't think that the window has already been painted.
    3245           0 :             gdk_window_invalidate_rect(mGdkWindow, nullptr, FALSE);
    3246             :         }
    3247             : 
    3248           2 :         mIsFullyObscured = false;
    3249             : 
    3250             :         // if we have to retry the grab, retry it.
    3251           2 :         EnsureGrabs();
    3252           2 :         break;
    3253             :     default: // includes GDK_VISIBILITY_FULLY_OBSCURED
    3254           0 :         mIsFullyObscured = true;
    3255           0 :         break;
    3256             :     }
    3257             : }
    3258             : 
    3259             : void
    3260           2 : nsWindow::OnWindowStateEvent(GtkWidget *aWidget, GdkEventWindowState *aEvent)
    3261             : {
    3262           2 :     LOG(("nsWindow::OnWindowStateEvent [%p] changed %d new_window_state %d\n",
    3263             :          (void *)this, aEvent->changed_mask, aEvent->new_window_state));
    3264             : 
    3265           2 :     if (IS_MOZ_CONTAINER(aWidget)) {
    3266             :         // This event is notifying the container widget of changes to the
    3267             :         // toplevel window.  Just detect changes affecting whether windows are
    3268             :         // viewable.
    3269             :         //
    3270             :         // (A visibility notify event is sent to each window that becomes
    3271             :         // viewable when the toplevel is mapped, but we can't rely on that for
    3272             :         // setting mHasMappedToplevel because these toplevel window state
    3273             :         // events are asynchronous.  The windows in the hierarchy now may not
    3274             :         // be the same windows as when the toplevel was mapped, so they may
    3275             :         // not get VisibilityNotify events.)
    3276             :         bool mapped =
    3277           1 :             !(aEvent->new_window_state &
    3278           1 :               (GDK_WINDOW_STATE_ICONIFIED|GDK_WINDOW_STATE_WITHDRAWN));
    3279           1 :         if (mHasMappedToplevel != mapped) {
    3280           1 :             SetHasMappedToplevel(mapped);
    3281             :         }
    3282           1 :         return;
    3283             :     }
    3284             :     // else the widget is a shell widget.
    3285             : 
    3286             :     // We don't care about anything but changes in the maximized/icon/fullscreen
    3287             :     // states
    3288           2 :     if ((aEvent->changed_mask
    3289           1 :          & (GDK_WINDOW_STATE_ICONIFIED |
    3290             :             GDK_WINDOW_STATE_MAXIMIZED |
    3291             :             GDK_WINDOW_STATE_FULLSCREEN)) == 0) {
    3292           0 :         return;
    3293             :     }
    3294             : 
    3295           1 :     if (aEvent->new_window_state & GDK_WINDOW_STATE_ICONIFIED) {
    3296           0 :         LOG(("\tIconified\n"));
    3297           0 :         mSizeState = nsSizeMode_Minimized;
    3298             : #ifdef ACCESSIBILITY
    3299           0 :         DispatchMinimizeEventAccessible();
    3300             : #endif //ACCESSIBILITY
    3301             :     }
    3302           1 :     else if (aEvent->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) {
    3303           0 :         LOG(("\tFullscreen\n"));
    3304           0 :         mSizeState = nsSizeMode_Fullscreen;
    3305             :     }
    3306           1 :     else if (aEvent->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) {
    3307           1 :         LOG(("\tMaximized\n"));
    3308           1 :         mSizeState = nsSizeMode_Maximized;
    3309             : #ifdef ACCESSIBILITY
    3310           1 :         DispatchMaximizeEventAccessible();
    3311             : #endif //ACCESSIBILITY
    3312             :     }
    3313             :     else {
    3314           0 :         LOG(("\tNormal\n"));
    3315           0 :         mSizeState = nsSizeMode_Normal;
    3316             : #ifdef ACCESSIBILITY
    3317           0 :         DispatchRestoreEventAccessible();
    3318             : #endif //ACCESSIBILITY
    3319             :     }
    3320             : 
    3321           1 :     if (mWidgetListener) {
    3322           1 :       mWidgetListener->SizeModeChanged(mSizeState);
    3323           1 :       if (aEvent->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) {
    3324           0 :         mWidgetListener->FullscreenChanged(
    3325           0 :           aEvent->new_window_state & GDK_WINDOW_STATE_FULLSCREEN);
    3326             :       }
    3327             :     }
    3328             : }
    3329             : 
    3330             : void
    3331           0 : nsWindow::ThemeChanged()
    3332             : {
    3333           0 :     NotifyThemeChanged();
    3334             : 
    3335           0 :     if (!mGdkWindow || MOZ_UNLIKELY(mIsDestroyed))
    3336           0 :         return;
    3337             : 
    3338             :     // Dispatch theme change notification to all child windows
    3339             :     GList *children =
    3340           0 :         gdk_window_peek_children(mGdkWindow);
    3341           0 :     while (children) {
    3342           0 :         GdkWindow *gdkWin = GDK_WINDOW(children->data);
    3343             : 
    3344           0 :         auto *win = (nsWindow*) g_object_get_data(G_OBJECT(gdkWin),
    3345           0 :                                                       "nsWindow");
    3346             : 
    3347           0 :         if (win && win != this) { // guard against infinite recursion
    3348           0 :             RefPtr<nsWindow> kungFuDeathGrip = win;
    3349           0 :             win->ThemeChanged();
    3350             :         }
    3351             : 
    3352           0 :         children = children->next;
    3353             :     }
    3354             : }
    3355             : 
    3356             : void
    3357           0 : nsWindow::OnDPIChanged()
    3358             : {
    3359           0 :   if (mWidgetListener) {
    3360           0 :     nsIPresShell* presShell = mWidgetListener->GetPresShell();
    3361           0 :     if (presShell) {
    3362           0 :       presShell->BackingScaleFactorChanged();
    3363             :       // Update menu's font size etc
    3364           0 :       presShell->ThemeChanged();
    3365             :     }
    3366             :   }
    3367           0 : }
    3368             : 
    3369             : void
    3370          17 : nsWindow::OnCheckResize()
    3371             : {
    3372          17 :     mPendingConfigures++;
    3373          17 : }
    3374             : 
    3375             : void
    3376           0 : nsWindow::OnCompositedChanged()
    3377             : {
    3378           0 :   if (mWidgetListener) {
    3379           0 :     nsIPresShell* presShell = mWidgetListener->GetPresShell();
    3380           0 :     if (presShell) {
    3381             :       // Update CSD after the change in alpha visibility
    3382           0 :       presShell->ThemeChanged();
    3383             :     }
    3384             :   }
    3385           0 :   CleanLayerManagerRecursive();
    3386           0 : }
    3387             : 
    3388             : void
    3389           0 : nsWindow::DispatchDragEvent(EventMessage aMsg, const LayoutDeviceIntPoint& aRefPoint,
    3390             :                             guint aTime)
    3391             : {
    3392           0 :     WidgetDragEvent event(true, aMsg, this);
    3393             : 
    3394           0 :     InitDragEvent(event);
    3395             : 
    3396           0 :     event.mRefPoint = aRefPoint;
    3397           0 :     event.AssignEventTime(GetWidgetEventTime(aTime));
    3398             : 
    3399           0 :     DispatchInputEvent(&event);
    3400           0 : }
    3401             : 
    3402             : void
    3403           0 : nsWindow::OnDragDataReceivedEvent(GtkWidget *aWidget,
    3404             :                                   GdkDragContext *aDragContext,
    3405             :                                   gint aX,
    3406             :                                   gint aY,
    3407             :                                   GtkSelectionData  *aSelectionData,
    3408             :                                   guint aInfo,
    3409             :                                   guint aTime,
    3410             :                                   gpointer aData)
    3411             : {
    3412           0 :     LOGDRAG(("nsWindow::OnDragDataReceived(%p)\n", (void*)this));
    3413             : 
    3414           0 :     RefPtr<nsDragService> dragService = nsDragService::GetInstance();
    3415             :     dragService->
    3416           0 :         TargetDataReceived(aWidget, aDragContext, aX, aY,
    3417           0 :                            aSelectionData, aInfo, aTime);
    3418           0 : }
    3419             : 
    3420             : #if GTK_CHECK_VERSION(3,4,0)
    3421             : gboolean
    3422           0 : nsWindow::OnTouchEvent(GdkEventTouch* aEvent)
    3423             : {
    3424           0 :     if (!mHandleTouchEvent) {
    3425           0 :         return FALSE;
    3426             :     }
    3427             : 
    3428             :     EventMessage msg;
    3429           0 :     switch (aEvent->type) {
    3430             :     case GDK_TOUCH_BEGIN:
    3431           0 :         msg = eTouchStart;
    3432           0 :         break;
    3433             :     case GDK_TOUCH_UPDATE:
    3434           0 :         msg = eTouchMove;
    3435           0 :         break;
    3436             :     case GDK_TOUCH_END:
    3437           0 :         msg = eTouchEnd;
    3438           0 :         break;
    3439             :     case GDK_TOUCH_CANCEL:
    3440           0 :         msg = eTouchCancel;
    3441           0 :         break;
    3442             :     default:
    3443           0 :         return FALSE;
    3444             :     }
    3445             : 
    3446           0 :     LayoutDeviceIntPoint touchPoint = GetRefPoint(this, aEvent);
    3447             : 
    3448             :     int32_t id;
    3449           0 :     RefPtr<dom::Touch> touch;
    3450           0 :     if (mTouches.Remove(aEvent->sequence, getter_AddRefs(touch))) {
    3451           0 :         id = touch->mIdentifier;
    3452             :     } else {
    3453           0 :         id = ++gLastTouchID & 0x7FFFFFFF;
    3454             :     }
    3455             : 
    3456           0 :     touch = new dom::Touch(id, touchPoint, LayoutDeviceIntPoint(1, 1),
    3457           0 :                            0.0f, 0.0f);
    3458             : 
    3459           0 :     WidgetTouchEvent event(true, msg, this);
    3460           0 :     KeymapWrapper::InitInputEvent(event, aEvent->state);
    3461           0 :     event.mTime = aEvent->time;
    3462             : 
    3463           0 :     if (aEvent->type == GDK_TOUCH_BEGIN || aEvent->type == GDK_TOUCH_UPDATE) {
    3464           0 :         mTouches.Put(aEvent->sequence, touch.forget());
    3465             :         // add all touch points to event object
    3466           0 :         for (auto iter = mTouches.Iter(); !iter.Done(); iter.Next()) {
    3467           0 :             event.mTouches.AppendElement(new dom::Touch(*iter.UserData()));
    3468           0 :         }
    3469           0 :     } else if (aEvent->type == GDK_TOUCH_END ||
    3470           0 :                aEvent->type == GDK_TOUCH_CANCEL) {
    3471           0 :         *event.mTouches.AppendElement() = touch.forget();
    3472             :     }
    3473             : 
    3474           0 :     DispatchInputEvent(&event);
    3475           0 :     return TRUE;
    3476             : }
    3477             : #endif
    3478             : 
    3479             : static void
    3480           3 : GetBrandName(nsXPIDLString& brandName)
    3481             : {
    3482             :     nsCOMPtr<nsIStringBundleService> bundleService =
    3483           6 :         do_GetService(NS_STRINGBUNDLE_CONTRACTID);
    3484             : 
    3485           6 :     nsCOMPtr<nsIStringBundle> bundle;
    3486           3 :     if (bundleService)
    3487           6 :         bundleService->CreateBundle(
    3488             :             "chrome://branding/locale/brand.properties",
    3489           6 :             getter_AddRefs(bundle));
    3490             : 
    3491           3 :     if (bundle)
    3492           6 :         bundle->GetStringFromName(
    3493             :             u"brandShortName",
    3494           6 :             getter_Copies(brandName));
    3495             : 
    3496           3 :     if (brandName.IsEmpty())
    3497           0 :         brandName.AssignLiteral(u"Mozilla");
    3498           3 : }
    3499             : 
    3500             : static GdkWindow *
    3501           0 : CreateGdkWindow(GdkWindow *parent, GtkWidget *widget)
    3502             : {
    3503             :     GdkWindowAttr attributes;
    3504           0 :     gint          attributes_mask = GDK_WA_VISUAL;
    3505             : 
    3506           0 :     attributes.event_mask = kEvents;
    3507             : 
    3508           0 :     attributes.width = 1;
    3509           0 :     attributes.height = 1;
    3510           0 :     attributes.wclass = GDK_INPUT_OUTPUT;
    3511           0 :     attributes.visual = gtk_widget_get_visual(widget);
    3512           0 :     attributes.window_type = GDK_WINDOW_CHILD;
    3513             : 
    3514             : #if (MOZ_WIDGET_GTK == 2)
    3515             :     attributes_mask |= GDK_WA_COLORMAP;
    3516             :     attributes.colormap = gtk_widget_get_colormap(widget);
    3517             : #endif
    3518             : 
    3519           0 :     GdkWindow *window = gdk_window_new(parent, &attributes, attributes_mask);
    3520           0 :     gdk_window_set_user_data(window, widget);
    3521             : 
    3522             : // GTK3 TODO?
    3523             : #if (MOZ_WIDGET_GTK == 2)
    3524             :     /* set the default pixmap to None so that you don't end up with the
    3525             :        gtk default which is BlackPixel. */
    3526             :     gdk_window_set_back_pixmap(window, nullptr, FALSE);
    3527             : #endif
    3528             : 
    3529           0 :     return window;
    3530             : }
    3531             : 
    3532             : nsresult
    3533           2 : nsWindow::Create(nsIWidget* aParent,
    3534             :                  nsNativeWidget aNativeParent,
    3535             :                  const LayoutDeviceIntRect& aRect,
    3536             :                  nsWidgetInitData* aInitData)
    3537             : {
    3538             :     // only set the base parent if we're going to be a dialog or a
    3539             :     // toplevel
    3540           2 :     nsIWidget *baseParent = aInitData &&
    3541           4 :         (aInitData->mWindowType == eWindowType_dialog ||
    3542           3 :          aInitData->mWindowType == eWindowType_toplevel ||
    3543           3 :          aInitData->mWindowType == eWindowType_invisible) ?
    3544           2 :         nullptr : aParent;
    3545             : 
    3546             : #ifdef ACCESSIBILITY
    3547             :     // Send a DBus message to check whether a11y is enabled
    3548           2 :     a11y::PreInit();
    3549             : #endif
    3550             : 
    3551             :     // Ensure that the toolkit is created.
    3552           2 :     nsGTKToolkit::GetToolkit();
    3553             : 
    3554             :     // initialize all the common bits of this class
    3555           2 :     BaseCreate(baseParent, aInitData);
    3556             : 
    3557             :     // Do we need to listen for resizes?
    3558           2 :     bool listenForResizes = false;;
    3559           2 :     if (aNativeParent || (aInitData && aInitData->mListenForResizes))
    3560           0 :         listenForResizes = true;
    3561             : 
    3562             :     // and do our common creation
    3563           2 :     CommonCreate(aParent, listenForResizes);
    3564             : 
    3565             :     // save our bounds
    3566           2 :     mBounds = aRect;
    3567           2 :     ConstrainSize(&mBounds.width, &mBounds.height);
    3568             : 
    3569             :     // figure out our parent window
    3570           2 :     GtkWidget      *parentMozContainer = nullptr;
    3571           2 :     GtkContainer   *parentGtkContainer = nullptr;
    3572           2 :     GdkWindow      *parentGdkWindow = nullptr;
    3573           2 :     GtkWindow      *topLevelParent = nullptr;
    3574           2 :     nsWindow       *parentnsWindow = nullptr;
    3575           2 :     GtkWidget      *eventWidget = nullptr;
    3576           2 :     bool            shellHasCSD = false;
    3577             : 
    3578           2 :     if (aParent) {
    3579           0 :         parentnsWindow = static_cast<nsWindow*>(aParent);
    3580           0 :         parentGdkWindow = parentnsWindow->mGdkWindow;
    3581           2 :     } else if (aNativeParent && GDK_IS_WINDOW(aNativeParent)) {
    3582           0 :         parentGdkWindow = GDK_WINDOW(aNativeParent);
    3583           0 :         parentnsWindow = get_window_for_gdk_window(parentGdkWindow);
    3584           0 :         if (!parentnsWindow)
    3585           0 :             return NS_ERROR_FAILURE;
    3586             : 
    3587           2 :     } else if (aNativeParent && GTK_IS_CONTAINER(aNativeParent)) {
    3588           0 :         parentGtkContainer = GTK_CONTAINER(aNativeParent);
    3589             :     }
    3590             : 
    3591           2 :     if (parentGdkWindow) {
    3592             :         // get the widget for the window - it should be a moz container
    3593           0 :         parentMozContainer = parentnsWindow->GetMozContainerWidget();
    3594           0 :         if (!parentMozContainer)
    3595           0 :             return NS_ERROR_FAILURE;
    3596             : 
    3597             :         // get the toplevel window just in case someone needs to use it
    3598             :         // for setting transients or whatever.
    3599             :         topLevelParent =
    3600           0 :             GTK_WINDOW(gtk_widget_get_toplevel(parentMozContainer));
    3601             :     }
    3602             : 
    3603             :     // ok, create our windows
    3604           2 :     switch (mWindowType) {
    3605             :     case eWindowType_dialog:
    3606             :     case eWindowType_popup:
    3607             :     case eWindowType_toplevel:
    3608             :     case eWindowType_invisible: {
    3609           2 :         mIsTopLevel = true;
    3610             : 
    3611             :         // Popups that are not noautohide are only temporary. The are used
    3612             :         // for menus and the like and disappear when another window is used.
    3613             :         // For most popups, use the standard GtkWindowType GTK_WINDOW_POPUP,
    3614             :         // which will use a Window with the override-redirect attribute
    3615             :         // (for temporary windows).
    3616             :         // For long-lived windows, their stacking order is managed by the
    3617             :         // window manager, as indicated by GTK_WINDOW_TOPLEVEL ...
    3618             :         GtkWindowType type =
    3619           2 :             mWindowType != eWindowType_popup || aInitData->mNoAutoHide ?
    3620           2 :               GTK_WINDOW_TOPLEVEL : GTK_WINDOW_POPUP;
    3621           2 :         mShell = gtk_window_new(type);
    3622             : 
    3623           2 :         bool useAlphaVisual = (mWindowType == eWindowType_popup &&
    3624           2 :                                aInitData->mSupportTranslucency);
    3625             : 
    3626             :         // mozilla.widget.use-argb-visuals is a hidden pref defaulting to false
    3627             :         // to allow experimentation
    3628           2 :         if (Preferences::GetBool("mozilla.widget.use-argb-visuals", false))
    3629           0 :             useAlphaVisual = true;
    3630             : 
    3631             :         // We need to select an ARGB visual here instead of in
    3632             :         // SetTransparencyMode() because it has to be done before the
    3633             :         // widget is realized.  An ARGB visual is only useful if we
    3634             :         // are on a compositing window manager.
    3635           2 :         if (useAlphaVisual) {
    3636           0 :             GdkScreen *screen = gtk_widget_get_screen(mShell);
    3637           0 :             if (gdk_screen_is_composited(screen)) {
    3638             : #if (MOZ_WIDGET_GTK == 2)
    3639             :                 GdkColormap *colormap = gdk_screen_get_rgba_colormap(screen);
    3640             :                 gtk_widget_set_colormap(mShell, colormap);
    3641             : #else
    3642           0 :                 GdkVisual *visual = gdk_screen_get_rgba_visual(screen);
    3643           0 :                 gtk_widget_set_visual(mShell, visual);
    3644             : #endif
    3645             :             }
    3646             :         }
    3647             : 
    3648             :         // We only move a general managed toplevel window if someone has
    3649             :         // actually placed the window somewhere.  If no placement has taken
    3650             :         // place, we just let the window manager Do The Right Thing.
    3651           2 :         NativeResize();
    3652             : 
    3653           2 :         if (mWindowType == eWindowType_dialog) {
    3654           0 :             SetDefaultIcon();
    3655           0 :             gtk_window_set_wmclass(GTK_WINDOW(mShell), "Dialog",
    3656           0 :                                    gdk_get_program_class());
    3657           0 :             gtk_window_set_type_hint(GTK_WINDOW(mShell),
    3658           0 :                                      GDK_WINDOW_TYPE_HINT_DIALOG);
    3659           0 :             gtk_window_set_transient_for(GTK_WINDOW(mShell),
    3660           0 :                                          topLevelParent);
    3661             :         }
    3662           2 :         else if (mWindowType == eWindowType_popup) {
    3663             :             // With popup windows, we want to control their position, so don't
    3664             :             // wait for the window manager to place them (which wouldn't
    3665             :             // happen with override-redirect windows anyway).
    3666           0 :             NativeMove();
    3667             : 
    3668           0 :             gtk_window_set_wmclass(GTK_WINDOW(mShell), "Popup",
    3669           0 :                                    gdk_get_program_class());
    3670             : 
    3671           0 :             if (aInitData->mNoAutoHide) {
    3672             :                 // ... but the window manager does not decorate this window,
    3673             :                 // nor provide a separate taskbar icon.
    3674           0 :                 if (mBorderStyle == eBorderStyle_default) {
    3675           0 :                   gtk_window_set_decorated(GTK_WINDOW(mShell), FALSE);
    3676             :                 }
    3677             :                 else {
    3678           0 :                   bool decorate = mBorderStyle & eBorderStyle_title;
    3679           0 :                   gtk_window_set_decorated(GTK_WINDOW(mShell), decorate);
    3680           0 :                   if (decorate) {
    3681           0 :                     gtk_window_set_deletable(GTK_WINDOW(mShell), mBorderStyle & eBorderStyle_close);
    3682             :                   }
    3683             :                 }
    3684           0 :                 gtk_window_set_skip_taskbar_hint(GTK_WINDOW(mShell), TRUE);
    3685             :                 // Element focus is managed by the parent window so the
    3686             :                 // WM_HINTS input field is set to False to tell the window
    3687             :                 // manager not to set input focus to this window ...
    3688           0 :                 gtk_window_set_accept_focus(GTK_WINDOW(mShell), FALSE);
    3689             : #ifdef MOZ_X11
    3690             :                 // ... but when the window manager offers focus through
    3691             :                 // WM_TAKE_FOCUS, focus is requested on the parent window.
    3692           0 :                 gtk_widget_realize(mShell);
    3693           0 :                 gdk_window_add_filter(gtk_widget_get_window(mShell),
    3694           0 :                                       popup_take_focus_filter, nullptr);
    3695             : #endif
    3696             :             }
    3697             : 
    3698             :             GdkWindowTypeHint gtkTypeHint;
    3699           0 :             if (aInitData->mIsDragPopup) {
    3700           0 :                 gtkTypeHint = GDK_WINDOW_TYPE_HINT_DND;
    3701           0 :                 mIsDragPopup = true;
    3702             :             }
    3703             :             else {
    3704           0 :                 switch (aInitData->mPopupHint) {
    3705             :                     case ePopupTypeMenu:
    3706           0 :                         gtkTypeHint = GDK_WINDOW_TYPE_HINT_POPUP_MENU;
    3707           0 :                         break;
    3708             :                     case ePopupTypeTooltip:
    3709           0 :                         gtkTypeHint = GDK_WINDOW_TYPE_HINT_TOOLTIP;
    3710           0 :                         break;
    3711             :                     default:
    3712           0 :                         gtkTypeHint = GDK_WINDOW_TYPE_HINT_UTILITY;
    3713           0 :                         break;
    3714             :                 }
    3715             :             }
    3716           0 :             gtk_window_set_type_hint(GTK_WINDOW(mShell), gtkTypeHint);
    3717             : 
    3718           0 :             if (topLevelParent) {
    3719           0 :                 gtk_window_set_transient_for(GTK_WINDOW(mShell),
    3720           0 :                                             topLevelParent);
    3721             :             }
    3722             :         }
    3723             :         else { // must be eWindowType_toplevel
    3724           2 :             SetDefaultIcon();
    3725           2 :             gtk_window_set_wmclass(GTK_WINDOW(mShell), "Toplevel",
    3726           2 :                                    gdk_get_program_class());
    3727             : 
    3728             :             // each toplevel window gets its own window group
    3729           2 :             GtkWindowGroup *group = gtk_window_group_new();
    3730           2 :             gtk_window_group_add_window(group, GTK_WINDOW(mShell));
    3731           2 :             g_object_unref(group);
    3732             :         }
    3733             : 
    3734             :         // Create a container to hold child windows and child GtkWidgets.
    3735           2 :         GtkWidget *container = moz_container_new();
    3736           2 :         mContainer = MOZ_CONTAINER(container);
    3737             : 
    3738             : #if (MOZ_WIDGET_GTK == 3)
    3739             :         // "csd" style is set when widget is realized so we need to call
    3740             :         // it explicitly now.
    3741           2 :         gtk_widget_realize(mShell);
    3742             : 
    3743             :         // We can't draw directly to top-level window when client side
    3744             :         // decorations are enabled. We use container with GdkWindow instead.
    3745           2 :         GtkStyleContext* style = gtk_widget_get_style_context(mShell);
    3746           2 :         shellHasCSD = gtk_style_context_has_class(style, "csd");
    3747             : #endif
    3748           2 :         if (!shellHasCSD) {
    3749             :             // Use mShell's window for drawing and events.
    3750           2 :             gtk_widget_set_has_window(container, FALSE);
    3751             :             // Prevent GtkWindow from painting a background to flicker.
    3752           2 :             gtk_widget_set_app_paintable(mShell, TRUE);
    3753             :         }
    3754             :         // Set up event widget
    3755           2 :         eventWidget = shellHasCSD ? container : mShell;
    3756           2 :         gtk_widget_add_events(eventWidget, kEvents);
    3757             : 
    3758           2 :         gtk_container_add(GTK_CONTAINER(mShell), container);
    3759           2 :         gtk_widget_realize(container);
    3760             : 
    3761             :         // make sure this is the focus widget in the container
    3762           2 :         gtk_widget_show(container);
    3763           2 :         gtk_widget_grab_focus(container);
    3764             : 
    3765             :         // the drawing window
    3766           2 :         mGdkWindow = gtk_widget_get_window(eventWidget);
    3767             : 
    3768           2 :         if (mWindowType == eWindowType_popup) {
    3769             :             // gdk does not automatically set the cursor for "temporary"
    3770             :             // windows, which are what gtk uses for popups.
    3771             : 
    3772           0 :             mCursor = eCursor_wait; // force SetCursor to actually set the
    3773             :                                     // cursor, even though our internal state
    3774             :                                     // indicates that we already have the
    3775             :                                     // standard cursor.
    3776           0 :             SetCursor(eCursor_standard);
    3777             : 
    3778           0 :             if (aInitData->mNoAutoHide) {
    3779           0 :                 gint wmd = ConvertBorderStyles(mBorderStyle);
    3780           0 :                 if (wmd != -1)
    3781           0 :                   gdk_window_set_decorations(mGdkWindow, (GdkWMDecoration) wmd);
    3782             :             }
    3783             : 
    3784             :             // If the popup ignores mouse events, set an empty input shape.
    3785           0 :             if (aInitData->mMouseTransparent) {
    3786             : #if (MOZ_WIDGET_GTK == 2)
    3787             :               GdkRectangle rect = { 0, 0, 0, 0 };
    3788             :               GdkRegion *region = gdk_region_rectangle(&rect);
    3789             : 
    3790             :               gdk_window_input_shape_combine_region(mGdkWindow, region, 0, 0);
    3791             :               gdk_region_destroy(region);
    3792             : #else
    3793           0 :               cairo_rectangle_int_t rect = { 0, 0, 0, 0 };
    3794           0 :               cairo_region_t *region = cairo_region_create_rectangle(&rect);
    3795             : 
    3796           0 :               gdk_window_input_shape_combine_region(mGdkWindow, region, 0, 0);
    3797           0 :               cairo_region_destroy(region);
    3798             : #endif
    3799             :             }
    3800             :         }
    3801             :     }
    3802           2 :         break;
    3803             :     case eWindowType_plugin:
    3804             :     case eWindowType_plugin_ipc_chrome:
    3805             :     case eWindowType_plugin_ipc_content:
    3806           0 :         MOZ_ASSERT_UNREACHABLE();
    3807             :         return NS_ERROR_FAILURE;
    3808             : 
    3809             :     case eWindowType_child: {
    3810           0 :         if (parentMozContainer) {
    3811           0 :             mGdkWindow = CreateGdkWindow(parentGdkWindow, parentMozContainer);
    3812           0 :             mHasMappedToplevel = parentnsWindow->mHasMappedToplevel;
    3813             :         }
    3814           0 :         else if (parentGtkContainer) {
    3815             :             // This MozContainer has its own window for drawing and receives
    3816             :             // events because there is no mShell widget (corresponding to this
    3817             :             // nsWindow).
    3818           0 :             GtkWidget *container = moz_container_new();
    3819           0 :             mContainer = MOZ_CONTAINER(container);
    3820           0 :             eventWidget = container;
    3821           0 :             gtk_widget_add_events(eventWidget, kEvents);
    3822           0 :             gtk_container_add(parentGtkContainer, container);
    3823           0 :             gtk_widget_realize(container);
    3824             : 
    3825           0 :             mGdkWindow = gtk_widget_get_window(container);
    3826             :         }
    3827             :         else {
    3828           0 :             NS_WARNING("Warning: tried to create a new child widget with no parent!");
    3829           0 :             return NS_ERROR_FAILURE;
    3830             :         }
    3831             :     }
    3832           0 :         break;
    3833             :     default:
    3834           0 :         break;
    3835             :     }
    3836             : 
    3837             :     // label the drawing window with this object so we can find our way home
    3838           2 :     g_object_set_data(G_OBJECT(mGdkWindow), "nsWindow", this);
    3839             : 
    3840           2 :     if (mContainer)
    3841           2 :         g_object_set_data(G_OBJECT(mContainer), "nsWindow", this);
    3842             : 
    3843           2 :     if (mShell)
    3844           2 :         g_object_set_data(G_OBJECT(mShell), "nsWindow", this);
    3845             : 
    3846             :     // attach listeners for events
    3847           2 :     if (mShell) {
    3848           2 :         g_signal_connect(mShell, "configure_event",
    3849           2 :                          G_CALLBACK(configure_event_cb), nullptr);
    3850           2 :         g_signal_connect(mShell, "delete_event",
    3851           2 :                          G_CALLBACK(delete_event_cb), nullptr);
    3852           2 :         g_signal_connect(mShell, "window_state_event",
    3853           2 :                          G_CALLBACK(window_state_event_cb), nullptr);
    3854           2 :         g_signal_connect(mShell, "check-resize",
    3855           2 :                          G_CALLBACK(check_resize_cb), nullptr);
    3856           2 :         g_signal_connect(mShell, "composited-changed",
    3857           2 :                          G_CALLBACK(composited_changed_cb), nullptr);
    3858             : 
    3859           2 :         GtkSettings* default_settings = gtk_settings_get_default();
    3860             :         g_signal_connect_after(default_settings,
    3861             :                                "notify::gtk-theme-name",
    3862           2 :                                G_CALLBACK(theme_changed_cb), this);
    3863             :         g_signal_connect_after(default_settings,
    3864             :                                "notify::gtk-font-name",
    3865           2 :                                G_CALLBACK(theme_changed_cb), this);
    3866             :     }
    3867             : 
    3868           2 :     if (mContainer) {
    3869             :         // Widget signals
    3870           2 :         g_signal_connect(mContainer, "unrealize",
    3871           2 :                          G_CALLBACK(container_unrealize_cb), nullptr);
    3872           2 :         g_signal_connect_after(mContainer, "size_allocate",
    3873           2 :                                G_CALLBACK(size_allocate_cb), nullptr);
    3874           2 :         g_signal_connect(mContainer, "hierarchy-changed",
    3875           2 :                          G_CALLBACK(hierarchy_changed_cb), nullptr);
    3876             : #if (MOZ_WIDGET_GTK == 3)
    3877           2 :         g_signal_connect(mContainer, "notify::scale-factor",
    3878           2 :                          G_CALLBACK(scale_changed_cb), nullptr);
    3879             : #endif
    3880             :         // Initialize mHasMappedToplevel.
    3881           2 :         hierarchy_changed_cb(GTK_WIDGET(mContainer), nullptr);
    3882             :         // Expose, focus, key, and drag events are sent even to GTK_NO_WINDOW
    3883             :         // widgets.
    3884             : #if (MOZ_WIDGET_GTK == 2)
    3885             :         g_signal_connect(mContainer, "expose_event",
    3886             :                          G_CALLBACK(expose_event_cb), nullptr);
    3887             : #else
    3888           2 :         g_signal_connect(G_OBJECT(mContainer), "draw",
    3889           2 :                          G_CALLBACK(expose_event_cb), nullptr);
    3890             : #endif
    3891           2 :         g_signal_connect(mContainer, "focus_in_event",
    3892           2 :                          G_CALLBACK(focus_in_event_cb), nullptr);
    3893           2 :         g_signal_connect(mContainer, "focus_out_event",
    3894           2 :                          G_CALLBACK(focus_out_event_cb), nullptr);
    3895           2 :         g_signal_connect(mContainer, "key_press_event",
    3896           2 :                          G_CALLBACK(key_press_event_cb), nullptr);
    3897           2 :         g_signal_connect(mContainer, "key_release_event",
    3898           2 :                          G_CALLBACK(key_release_event_cb), nullptr);
    3899             : 
    3900           2 :         gtk_drag_dest_set((GtkWidget *)mContainer,
    3901             :                           (GtkDestDefaults)0,
    3902             :                           nullptr,
    3903             :                           0,
    3904           2 :                           (GdkDragAction)0);
    3905             : 
    3906           2 :         g_signal_connect(mContainer, "drag_motion",
    3907           2 :                          G_CALLBACK(drag_motion_event_cb), nullptr);
    3908           2 :         g_signal_connect(mContainer, "drag_leave",
    3909           2 :                          G_CALLBACK(drag_leave_event_cb), nullptr);
    3910           2 :         g_signal_connect(mContainer, "drag_drop",
    3911           2 :                          G_CALLBACK(drag_drop_event_cb), nullptr);
    3912           2 :         g_signal_connect(mContainer, "drag_data_received",
    3913           2 :                          G_CALLBACK(drag_data_received_event_cb), nullptr);
    3914             : 
    3915           2 :         GtkWidget *widgets[] = { GTK_WIDGET(mContainer),
    3916           2 :                                  !shellHasCSD ? mShell : nullptr };
    3917           6 :         for (size_t i = 0; i < ArrayLength(widgets) && widgets[i]; ++i) {
    3918             :             // Visibility events are sent to the owning widget of the relevant
    3919             :             // window but do not propagate to parent widgets so connect on
    3920             :             // mShell (if it exists) as well as mContainer.
    3921           4 :             g_signal_connect(widgets[i], "visibility-notify-event",
    3922           4 :                              G_CALLBACK(visibility_notify_event_cb), nullptr);
    3923             :             // Similarly double buffering is controlled by the window's owning
    3924             :             // widget.  Disable double buffering for painting directly to the
    3925             :             // X Window.
    3926           4 :             gtk_widget_set_double_buffered(widgets[i], FALSE);
    3927             :         }
    3928             : 
    3929             :         // We create input contexts for all containers, except for
    3930             :         // toplevel popup windows
    3931           2 :         if (mWindowType != eWindowType_popup) {
    3932           2 :             mIMContext = new IMContextWrapper(this);
    3933             :         }
    3934           0 :     } else if (!mIMContext) {
    3935           0 :         nsWindow *container = GetContainerWindow();
    3936           0 :         if (container) {
    3937           0 :             mIMContext = container->mIMContext;
    3938             :         }
    3939             :     }
    3940             : 
    3941           2 :     if (eventWidget) {
    3942             : #if (MOZ_WIDGET_GTK == 2)
    3943             :         // Don't let GTK mess with the shapes of our GdkWindows
    3944             :         GTK_PRIVATE_SET_FLAG(eventWidget, GTK_HAS_SHAPE_MASK);
    3945             : #endif
    3946             : 
    3947             :         // These events are sent to the owning widget of the relevant window
    3948             :         // and propagate up to the first widget that handles the events, so we
    3949             :         // need only connect on mShell, if it exists, to catch events on its
    3950             :         // window and windows of mContainer.
    3951             :         g_signal_connect(eventWidget, "enter-notify-event",
    3952           2 :                          G_CALLBACK(enter_notify_event_cb), nullptr);
    3953             :         g_signal_connect(eventWidget, "leave-notify-event",
    3954           2 :                          G_CALLBACK(leave_notify_event_cb), nullptr);
    3955             :         g_signal_connect(eventWidget, "motion-notify-event",
    3956           2 :                          G_CALLBACK(motion_notify_event_cb), nullptr);
    3957             :         g_signal_connect(eventWidget, "button-press-event",
    3958           2 :                          G_CALLBACK(button_press_event_cb), nullptr);
    3959             :         g_signal_connect(eventWidget, "button-release-event",
    3960           2 :                          G_CALLBACK(button_release_event_cb), nullptr);
    3961             :         g_signal_connect(eventWidget, "property-notify-event",
    3962           2 :                          G_CALLBACK(property_notify_event_cb), nullptr);
    3963             :         g_signal_connect(eventWidget, "scroll-event",
    3964           2 :                          G_CALLBACK(scroll_event_cb), nullptr);
    3965             : #if GTK_CHECK_VERSION(3,4,0)
    3966             :         g_signal_connect(eventWidget, "touch-event",
    3967           2 :                          G_CALLBACK(touch_event_cb), nullptr);
    3968             : #endif
    3969             :     }
    3970             : 
    3971           2 :     LOG(("nsWindow [%p]\n", (void *)this));
    3972           2 :     if (mShell) {
    3973           2 :         LOG(("\tmShell %p mContainer %p mGdkWindow %p 0x%lx\n",
    3974             :              mShell, mContainer, mGdkWindow,
    3975             :              gdk_x11_window_get_xid(mGdkWindow)));
    3976           0 :     } else if (mContainer) {
    3977           0 :         LOG(("\tmContainer %p mGdkWindow %p\n", mContainer, mGdkWindow));
    3978             :     }
    3979           0 :     else if (mGdkWindow) {
    3980           0 :         LOG(("\tmGdkWindow %p parent %p\n",
    3981             :              mGdkWindow, gdk_window_get_parent(mGdkWindow)));
    3982             :     }
    3983             : 
    3984             :     // resize so that everything is set to the right dimensions
    3985           2 :     if (!mIsTopLevel)
    3986           0 :         Resize(mBounds.x, mBounds.y, mBounds.width, mBounds.height, false);
    3987             : 
    3988             : #ifdef MOZ_X11
    3989           2 :     if (mIsX11Display && mGdkWindow) {
    3990           2 :       mXDisplay = GDK_WINDOW_XDISPLAY(mGdkWindow);
    3991           2 :       mXWindow = gdk_x11_window_get_xid(mGdkWindow);
    3992             : 
    3993           2 :       GdkVisual* gdkVisual = gdk_window_get_visual(mGdkWindow);
    3994           2 :       mXVisual = gdk_x11_visual_get_xvisual(gdkVisual);
    3995           2 :       mXDepth = gdk_visual_get_depth(gdkVisual);
    3996             : 
    3997           2 :       mSurfaceProvider.Initialize(mXDisplay, mXWindow, mXVisual, mXDepth);
    3998             :     }
    3999             : #endif
    4000             : 
    4001           2 :     return NS_OK;
    4002             : }
    4003             : 
    4004             : void
    4005           1 : nsWindow::SetWindowClass(const nsAString &xulWinType)
    4006             : {
    4007           1 :   if (!mShell)
    4008           0 :     return;
    4009             : 
    4010           1 :   const char *res_class = gdk_get_program_class();
    4011           1 :   if (!res_class)
    4012           0 :     return;
    4013             : 
    4014           1 :   char *res_name = ToNewCString(xulWinType);
    4015           1 :   if (!res_name)
    4016           0 :     return;
    4017             : 
    4018           1 :   const char *role = nullptr;
    4019             : 
    4020             :   // Parse res_name into a name and role. Characters other than
    4021             :   // [A-Za-z0-9_-] are converted to '_'. Anything after the first
    4022             :   // colon is assigned to role; if there's no colon, assign the
    4023             :   // whole thing to both role and res_name.
    4024          18 :   for (char *c = res_name; *c; c++) {
    4025          17 :     if (':' == *c) {
    4026           1 :       *c = 0;
    4027           1 :       role = c + 1;
    4028             :     }
    4029          16 :     else if (!isascii(*c) || (!isalnum(*c) && ('_' != *c) && ('-' != *c)))
    4030           0 :       *c = '_';
    4031             :   }
    4032           1 :   res_name[0] = toupper(res_name[0]);
    4033           1 :   if (!role) role = res_name;
    4034             : 
    4035           1 :   gdk_window_set_role(mGdkWindow, role);
    4036             : 
    4037             : #ifdef MOZ_X11
    4038           1 :   if (mIsX11Display) {
    4039           1 :       XClassHint *class_hint = XAllocClassHint();
    4040           1 :       if (!class_hint) {
    4041           0 :         free(res_name);
    4042           0 :         return;
    4043             :       }
    4044           1 :       class_hint->res_name = res_name;
    4045           1 :       class_hint->res_class = const_cast<char*>(res_class);
    4046             : 
    4047             :       // Can't use gtk_window_set_wmclass() for this; it prints
    4048             :       // a warning & refuses to make the change.
    4049           1 :       GdkDisplay *display = gdk_display_get_default();
    4050           1 :       XSetClassHint(GDK_DISPLAY_XDISPLAY(display),
    4051             :                     gdk_x11_window_get_xid(mGdkWindow),
    4052           1 :                     class_hint);
    4053           1 :       XFree(class_hint);
    4054             :   }
    4055             : #endif /* MOZ_X11 */
    4056             : 
    4057           1 :   free(res_name);
    4058             : }
    4059             : 
    4060             : void
    4061           3 : nsWindow::NativeResize()
    4062             : {
    4063           3 :     if (!AreBoundsSane()) {
    4064             :         // If someone has set this so that the needs show flag is false
    4065             :         // and it needs to be hidden, update the flag and hide the
    4066             :         // window.  This flag will be cleared the next time someone
    4067             :         // hides the window or shows it.  It also prevents us from
    4068             :         // calling NativeShow(false) excessively on the window which
    4069             :         // causes unneeded X traffic.
    4070           0 :         if (!mNeedsShow && mIsShown) {
    4071           0 :             mNeedsShow = true;
    4072           0 :             NativeShow(false);
    4073             :         }
    4074           0 :         return;
    4075             :     }
    4076             : 
    4077           3 :     GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mBounds.Size());
    4078             : 
    4079           3 :     LOG(("nsWindow::NativeResize [%p] %d %d\n", (void *)this,
    4080             :          size.width, size.height));
    4081             : 
    4082           3 :     if (mIsTopLevel) {
    4083           3 :         gtk_window_resize(GTK_WINDOW(mShell), size.width, size.height);
    4084             :     }
    4085           0 :     else if (mContainer) {
    4086           0 :         GtkWidget *widget = GTK_WIDGET(mContainer);
    4087             :         GtkAllocation allocation, prev_allocation;
    4088           0 :         gtk_widget_get_allocation(widget, &prev_allocation);
    4089           0 :         allocation.x = prev_allocation.x;
    4090           0 :         allocation.y = prev_allocation.y;
    4091           0 :         allocation.width = size.width;
    4092           0 :         allocation.height = size.height;
    4093           0 :         gtk_widget_size_allocate(widget, &allocation);
    4094             :     }
    4095           0 :     else if (mGdkWindow) {
    4096           0 :         gdk_window_resize(mGdkWindow, size.width, size.height);
    4097             :     }
    4098             : 
    4099             : #ifdef MOZ_X11
    4100             :     // Notify the X11CompositorWidget of a ClientSizeChange
    4101             :     // This is different than OnSizeAllocate to catch initial sizing
    4102           3 :     if (mCompositorWidgetDelegate) {
    4103           1 :       mCompositorWidgetDelegate->NotifyClientSizeChanged(GetClientSize());
    4104             :     }
    4105             : #endif
    4106             : 
    4107             :     // Does it need to be shown because bounds were previously insane?
    4108           3 :     if (mNeedsShow && mIsShown) {
    4109           0 :         NativeShow(true);
    4110             :     }
    4111             : }
    4112             : 
    4113             : void
    4114           0 : nsWindow::NativeMoveResize()
    4115             : {
    4116           0 :     if (!AreBoundsSane()) {
    4117             :         // If someone has set this so that the needs show flag is false
    4118             :         // and it needs to be hidden, update the flag and hide the
    4119             :         // window.  This flag will be cleared the next time someone
    4120             :         // hides the window or shows it.  It also prevents us from
    4121             :         // calling NativeShow(false) excessively on the window which
    4122             :         // causes unneeded X traffic.
    4123           0 :         if (!mNeedsShow && mIsShown) {
    4124           0 :             mNeedsShow = true;
    4125           0 :             NativeShow(false);
    4126             :         }
    4127           0 :         NativeMove();
    4128             :     }
    4129             : 
    4130           0 :     GdkRectangle size = DevicePixelsToGdkSizeRoundUp(mBounds.Size());
    4131           0 :     GdkPoint topLeft = DevicePixelsToGdkPointRoundDown(mBounds.TopLeft());
    4132             : 
    4133           0 :     LOG(("nsWindow::NativeMoveResize [%p] %d %d %d %d\n", (void *)this,
    4134             :          topLeft.x, topLeft.y, size.width, size.height));
    4135             : 
    4136           0 :     if (mIsTopLevel) {
    4137             :         // x and y give the position of the window manager frame top-left.
    4138           0 :         gtk_window_move(GTK_WINDOW(mShell), topLeft.x, topLeft.y);
    4139             :         // This sets the client window size.
    4140           0 :         gtk_window_resize(GTK_WINDOW(mShell), size.width, size.height);
    4141             :     }
    4142           0 :     else if (mContainer) {
    4143             :         GtkAllocation allocation;
    4144           0 :         allocation.x = topLeft.x;
    4145           0 :         allocation.y = topLeft.y;
    4146           0 :         allocation.width = size.width;
    4147           0 :         allocation.height = size.height;
    4148           0 :         gtk_widget_size_allocate(GTK_WIDGET(mContainer), &allocation);
    4149             :     }
    4150           0 :     else if (mGdkWindow) {
    4151           0 :         gdk_window_move_resize(mGdkWindow,
    4152           0 :                                topLeft.x, topLeft.y, size.width, size.height);
    4153             :     }
    4154             : 
    4155             : #ifdef MOZ_X11
    4156             :     // Notify the X11CompositorWidget of a ClientSizeChange
    4157             :     // This is different than OnSizeAllocate to catch initial sizing
    4158           0 :     if (mCompositorWidgetDelegate) {
    4159           0 :       mCompositorWidgetDelegate->NotifyClientSizeChanged(GetClientSize());
    4160             :     }
    4161             : #endif
    4162             : 
    4163             :     // Does it need to be shown because bounds were previously insane?
    4164           0 :     if (mNeedsShow && mIsShown) {
    4165           0 :         NativeShow(true);
    4166             :     }
    4167           0 : }
    4168             : 
    4169             : void
    4170           1 : nsWindow::NativeShow(bool aAction)
    4171             : {
    4172           1 :     if (aAction) {
    4173             :         // unset our flag now that our window has been shown
    4174           1 :         mNeedsShow = false;
    4175             : 
    4176           1 :         if (mIsTopLevel) {
    4177             :             // Set up usertime/startupID metadata for the created window.
    4178           1 :             if (mWindowType != eWindowType_invisible) {
    4179           1 :                 SetUserTimeAndStartupIDForActivatedWindow(mShell);
    4180             :             }
    4181             : 
    4182           1 :             gtk_widget_show(mShell);
    4183             :         }
    4184           0 :         else if (mContainer) {
    4185           0 :             gtk_widget_show(GTK_WIDGET(mContainer));
    4186             :         }
    4187           0 :         else if (mGdkWindow) {
    4188           0 :             gdk_window_show_unraised(mGdkWindow);
    4189             :         }
    4190             :     }
    4191             :     else {
    4192           0 :         if (mIsTopLevel) {
    4193             :             // Workaround window freezes on GTK versions before 3.21.2 by
    4194             :             // ensuring that configure events get dispatched to windows before
    4195             :             // they are unmapped. See bug 1225044.
    4196           0 :             if (gtk_check_version(3, 21, 2) != nullptr && mPendingConfigures > 0) {
    4197             :                 GtkAllocation allocation;
    4198           0 :                 gtk_widget_get_allocation(GTK_WIDGET(mShell), &allocation);
    4199             : 
    4200             :                 GdkEventConfigure event;
    4201           0 :                 PodZero(&event);
    4202           0 :                 event.type = GDK_CONFIGURE;
    4203           0 :                 event.window = mGdkWindow;
    4204           0 :                 event.send_event = TRUE;
    4205           0 :                 event.x = allocation.x;
    4206           0 :                 event.y = allocation.y;
    4207           0 :                 event.width = allocation.width;
    4208           0 :                 event.height = allocation.height;
    4209             : 
    4210           0 :                 auto shellClass = GTK_WIDGET_GET_CLASS(mShell);
    4211           0 :                 for (unsigned int i = 0; i < mPendingConfigures; i++) {
    4212           0 :                     Unused << shellClass->configure_event(mShell, &event);
    4213             :                 }
    4214           0 :                 mPendingConfigures = 0;
    4215             :             }
    4216             : 
    4217           0 :             gtk_widget_hide(mShell);
    4218             : 
    4219           0 :             ClearTransparencyBitmap(); // Release some resources
    4220             :         }
    4221           0 :         else if (mContainer) {
    4222           0 :             gtk_widget_hide(GTK_WIDGET(mContainer));
    4223             :         }
    4224           0 :         else if (mGdkWindow) {
    4225           0 :             gdk_window_hide(mGdkWindow);
    4226             :         }
    4227             :     }
    4228           1 : }
    4229             : 
    4230             : void
    4231           2 : nsWindow::SetHasMappedToplevel(bool aState)
    4232             : {
    4233             :     // Even when aState == mHasMappedToplevel (as when this method is called
    4234             :     // from Show()), child windows need to have their state checked, so don't
    4235             :     // return early.
    4236           2 :     bool oldState = mHasMappedToplevel;
    4237           2 :     mHasMappedToplevel = aState;
    4238             : 
    4239             :     // mHasMappedToplevel is not updated for children of windows that are
    4240             :     // hidden; GDK knows not to send expose events for these windows.  The
    4241             :     // state is recorded on the hidden window itself, but, for child trees of
    4242             :     // hidden windows, their state essentially becomes disconnected from their
    4243             :     // hidden parent.  When the hidden parent gets shown, the child trees are
    4244             :     // reconnected, and the state of the window being shown can be easily
    4245             :     // propagated.
    4246           2 :     if (!mIsShown || !mGdkWindow)
    4247           0 :         return;
    4248             : 
    4249           2 :     if (aState && !oldState && !mIsFullyObscured) {
    4250             :         // GDK_EXPOSE events have been ignored but the window is now visible,
    4251             :         // so make sure GDK doesn't think that the window has already been
    4252             :         // painted.
    4253           1 :         gdk_window_invalidate_rect(mGdkWindow, nullptr, FALSE);
    4254             : 
    4255             :         // Check that a grab didn't fail due to the window not being
    4256             :         // viewable.
    4257           1 :         EnsureGrabs();
    4258             :     }
    4259             : 
    4260           2 :     for (GList *children = gdk_window_peek_children(mGdkWindow);
    4261           2 :          children;
    4262           0 :          children = children->next) {
    4263           0 :         GdkWindow *gdkWin = GDK_WINDOW(children->data);
    4264           0 :         nsWindow *child = get_window_for_gdk_window(gdkWin);
    4265             : 
    4266           0 :         if (child && child->mHasMappedToplevel != aState) {
    4267           0 :             child->SetHasMappedToplevel(aState);
    4268             :         }
    4269             :     }
    4270             : }
    4271             : 
    4272             : LayoutDeviceIntSize
    4273          42 : nsWindow::GetSafeWindowSize(LayoutDeviceIntSize aSize)
    4274             : {
    4275             :     // The X protocol uses CARD32 for window sizes, but the server (1.11.3)
    4276             :     // reads it as CARD16.  Sizes of pixmaps, used for drawing, are (unsigned)
    4277             :     // CARD16 in the protocol, but the server's ProcCreatePixmap returns
    4278             :     // BadAlloc if dimensions cannot be represented by signed shorts.
    4279          42 :     LayoutDeviceIntSize result = aSize;
    4280          42 :     const int32_t kInt16Max = 32767;
    4281          42 :     if (result.width > kInt16Max) {
    4282          22 :         result.width = kInt16Max;
    4283             :     }
    4284          42 :     if (result.height > kInt16Max) {
    4285          22 :         result.height = kInt16Max;
    4286             :     }
    4287          42 :     return result;
    4288             : }
    4289             : 
    4290             : void
    4291           3 : nsWindow::EnsureGrabs(void)
    4292             : {
    4293           3 :     if (mRetryPointerGrab)
    4294           0 :         GrabPointer(sRetryGrabTime);
    4295           3 : }
    4296             : 
    4297             : void
    4298           0 : nsWindow::CleanLayerManagerRecursive(void) {
    4299           0 :     if (mLayerManager) {
    4300           0 :         mLayerManager->Destroy();
    4301           0 :         mLayerManager = nullptr;
    4302             :     }
    4303             : 
    4304           0 :     DestroyCompositor();
    4305             : 
    4306           0 :     GList* children = gdk_window_peek_children(mGdkWindow);
    4307           0 :     for (GList* list = children; list; list = list->next) {
    4308           0 :         nsWindow* window = get_window_for_gdk_window(GDK_WINDOW(list->data));
    4309           0 :         if (window) {
    4310           0 :             window->CleanLayerManagerRecursive();
    4311             :         }
    4312             :     }
    4313           0 : }
    4314             : 
    4315             : void
    4316          20 : nsWindow::SetTransparencyMode(nsTransparencyMode aMode)
    4317             : {
    4318          20 :     if (!mShell) {
    4319             :         // Pass the request to the toplevel window
    4320           0 :         GtkWidget *topWidget = GetToplevelWidget();
    4321           0 :         if (!topWidget)
    4322           0 :             return;
    4323             : 
    4324           0 :         nsWindow *topWindow = get_window_for_gtk_widget(topWidget);
    4325           0 :         if (!topWindow)
    4326           0 :             return;
    4327             : 
    4328           0 :         topWindow->SetTransparencyMode(aMode);
    4329           0 :         return;
    4330             :     }
    4331             : 
    4332          20 :     bool isTransparent = aMode == eTransparencyTransparent;
    4333             : 
    4334          20 :     if (mIsTransparent == isTransparent) {
    4335          20 :         return;
    4336           0 :     } else if (mWindowType != eWindowType_popup) {
    4337           0 :         NS_WARNING("Cannot set transparency mode on non-popup windows.");
    4338           0 :         return;
    4339             :     }
    4340             : 
    4341           0 :     if (!isTransparent) {
    4342           0 :         ClearTransparencyBitmap();
    4343             :     } // else the new default alpha values are "all 1", so we don't
    4344             :     // need to change anything yet
    4345             : 
    4346           0 :     mIsTransparent = isTransparent;
    4347             : 
    4348             :     // Need to clean our LayerManager up while still alive because
    4349             :     // we don't want to use layers acceleration on shaped windows
    4350           0 :     CleanLayerManagerRecursive();
    4351             : }
    4352             : 
    4353             : nsTransparencyMode
    4354          26 : nsWindow::GetTransparencyMode()
    4355             : {
    4356          26 :     if (!mShell) {
    4357             :         // Pass the request to the toplevel window
    4358           0 :         GtkWidget *topWidget = GetToplevelWidget();
    4359           0 :         if (!topWidget) {
    4360           0 :             return eTransparencyOpaque;
    4361             :         }
    4362             : 
    4363           0 :         nsWindow *topWindow = get_window_for_gtk_widget(topWidget);
    4364           0 :         if (!topWindow) {
    4365           0 :             return eTransparencyOpaque;
    4366             :         }
    4367             : 
    4368           0 :         return topWindow->GetTransparencyMode();
    4369             :     }
    4370             : 
    4371          26 :     return mIsTransparent ? eTransparencyTransparent : eTransparencyOpaque;
    4372             : }
    4373             : 
    4374             : #if (MOZ_WIDGET_GTK >= 3)
    4375          24 : void nsWindow::UpdateOpaqueRegion(const LayoutDeviceIntRegion& aOpaqueRegion)
    4376             : {
    4377             :     // Available as of GTK 3.10+
    4378             :     static auto sGdkWindowSetOpaqueRegion =
    4379           1 :         (void (*)(GdkWindow*, cairo_region_t*))
    4380          25 :             dlsym(RTLD_DEFAULT, "gdk_window_set_opaque_region");
    4381             : 
    4382          48 :     if (sGdkWindowSetOpaqueRegion && mGdkWindow &&
    4383          24 :         gdk_window_get_window_type(mGdkWindow) == GDK_WINDOW_TOPLEVEL) {
    4384          24 :         if (aOpaqueRegion.IsEmpty()) {
    4385          24 :             (*sGdkWindowSetOpaqueRegion)(mGdkWindow, nullptr);
    4386             :         } else {
    4387           0 :             cairo_region_t *region = cairo_region_create();
    4388           0 :             for (auto iter = aOpaqueRegion.RectIter(); !iter.Done();
    4389           0 :                  iter.Next()) {
    4390           0 :                 const LayoutDeviceIntRect &r = iter.Get();
    4391           0 :                 cairo_rectangle_int_t rect = { r.x, r.y, r.width, r.height };
    4392           0 :                 cairo_region_union_rectangle(region, &rect);
    4393             :             }
    4394           0 :             (*sGdkWindowSetOpaqueRegion)(mGdkWindow, region);
    4395           0 :             cairo_region_destroy(region);
    4396             :         }
    4397             :     }
    4398          24 : }
    4399             : #endif
    4400             : 
    4401             : nsresult
    4402           0 : nsWindow::ConfigureChildren(const nsTArray<Configuration>& aConfigurations)
    4403             : {
    4404             :     // If this is a remotely updated widget we receive clipping, position, and
    4405             :     // size information from a source other than our owner. Don't let our parent
    4406             :     // update this information.
    4407           0 :     if (mWindowType == eWindowType_plugin_ipc_chrome) {
    4408           0 :       return NS_OK;
    4409             :     }
    4410             : 
    4411           0 :     for (uint32_t i = 0; i < aConfigurations.Length(); ++i) {
    4412           0 :         const Configuration& configuration = aConfigurations[i];
    4413           0 :         auto* w = static_cast<nsWindow*>(configuration.mChild.get());
    4414           0 :         NS_ASSERTION(w->GetParent() == this,
    4415             :                      "Configured widget is not a child");
    4416           0 :         w->SetWindowClipRegion(configuration.mClipRegion, true);
    4417           0 :         if (w->mBounds.Size() != configuration.mBounds.Size()) {
    4418           0 :             w->Resize(configuration.mBounds.x, configuration.mBounds.y,
    4419           0 :                       configuration.mBounds.width, configuration.mBounds.height,
    4420           0 :                       true);
    4421           0 :         } else if (w->mBounds.TopLeft() != configuration.mBounds.TopLeft()) {
    4422           0 :             w->Move(configuration.mBounds.x, configuration.mBounds.y);
    4423             :         }
    4424           0 :         w->SetWindowClipRegion(configuration.mClipRegion, false);
    4425             :     }
    4426           0 :     return NS_OK;
    4427             : }
    4428             : 
    4429             : nsresult
    4430           0 : nsWindow::SetWindowClipRegion(const nsTArray<LayoutDeviceIntRect>& aRects,
    4431             :                               bool aIntersectWithExisting)
    4432             : {
    4433           0 :     const nsTArray<LayoutDeviceIntRect>* newRects = &aRects;
    4434             : 
    4435           0 :     AutoTArray<LayoutDeviceIntRect,1> intersectRects;
    4436           0 :     if (aIntersectWithExisting) {
    4437           0 :         AutoTArray<LayoutDeviceIntRect,1> existingRects;
    4438           0 :         GetWindowClipRegion(&existingRects);
    4439             : 
    4440           0 :         LayoutDeviceIntRegion existingRegion = RegionFromArray(existingRects);
    4441           0 :         LayoutDeviceIntRegion newRegion = RegionFromArray(aRects);
    4442           0 :         LayoutDeviceIntRegion intersectRegion;
    4443           0 :         intersectRegion.And(newRegion, existingRegion);
    4444             : 
    4445             :         // If mClipRects is null we haven't set a clip rect yet, so we
    4446             :         // need to set the clip even if it is equal.
    4447           0 :         if (mClipRects && intersectRegion.IsEqual(existingRegion)) {
    4448           0 :             return NS_OK;
    4449             :         }
    4450             : 
    4451           0 :         if (!intersectRegion.IsEqual(newRegion)) {
    4452           0 :             ArrayFromRegion(intersectRegion, intersectRects);
    4453           0 :             newRects = &intersectRects;
    4454             :         }
    4455             :     }
    4456             : 
    4457           0 :     if (IsWindowClipRegionEqual(*newRects))
    4458           0 :         return NS_OK;
    4459             : 
    4460           0 :     StoreWindowClipRegion(*newRects);
    4461             : 
    4462           0 :     if (!mGdkWindow)
    4463           0 :         return NS_OK;
    4464             : 
    4465             : #if (MOZ_WIDGET_GTK == 2)
    4466             :     GdkRegion *region = gdk_region_new(); // aborts on OOM
    4467             :     for (uint32_t i = 0; i < newRects->Length(); ++i) {
    4468             :         const LayoutDeviceIntRect& r = newRects->ElementAt(i);
    4469             :         GdkRectangle rect = { r.x, r.y, r.width, r.height };
    4470             :         gdk_region_union_with_rect(region, &rect);
    4471             :     }
    4472             : 
    4473             :     gdk_window_shape_combine_region(mGdkWindow, region, 0, 0);
    4474             :     gdk_region_destroy(region);
    4475             : #else
    4476           0 :     cairo_region_t *region = cairo_region_create();
    4477           0 :     for (uint32_t i = 0; i < newRects->Length(); ++i) {
    4478           0 :         const LayoutDeviceIntRect& r = newRects->ElementAt(i);
    4479           0 :         cairo_rectangle_int_t rect = { r.x, r.y, r.width, r.height };
    4480           0 :         cairo_region_union_rectangle(region, &rect);
    4481             :     }
    4482             : 
    4483           0 :     gdk_window_shape_combine_region(mGdkWindow, region, 0, 0);
    4484           0 :     cairo_region_destroy(region);
    4485             : #endif
    4486             : 
    4487           0 :     return NS_OK;
    4488             : }
    4489             : 
    4490             : void
    4491           0 : nsWindow::ResizeTransparencyBitmap()
    4492             : {
    4493           0 :     if (!mTransparencyBitmap)
    4494           0 :         return;
    4495             : 
    4496           0 :     if (mBounds.width == mTransparencyBitmapWidth &&
    4497           0 :         mBounds.height == mTransparencyBitmapHeight)
    4498           0 :         return;
    4499             : 
    4500           0 :     int32_t newRowBytes = GetBitmapStride(mBounds.width);
    4501           0 :     int32_t newSize = newRowBytes * mBounds.height;
    4502           0 :     auto* newBits = new gchar[newSize];
    4503             :     // fill new mask with "transparent", first
    4504           0 :     memset(newBits, 0, newSize);
    4505             : 
    4506             :     // Now copy the intersection of the old and new areas into the new mask
    4507           0 :     int32_t copyWidth = std::min(mBounds.width, mTransparencyBitmapWidth);
    4508           0 :     int32_t copyHeight = std::min(mBounds.height, mTransparencyBitmapHeight);
    4509           0 :     int32_t oldRowBytes = GetBitmapStride(mTransparencyBitmapWidth);
    4510           0 :     int32_t copyBytes = GetBitmapStride(copyWidth);
    4511             : 
    4512             :     int32_t i;
    4513           0 :     gchar* fromPtr = mTransparencyBitmap;
    4514           0 :     gchar* toPtr = newBits;
    4515           0 :     for (i = 0; i < copyHeight; i++) {
    4516           0 :         memcpy(toPtr, fromPtr, copyBytes);
    4517           0 :         fromPtr += oldRowBytes;
    4518           0 :         toPtr += newRowBytes;
    4519             :     }
    4520             : 
    4521           0 :     delete[] mTransparencyBitmap;
    4522           0 :     mTransparencyBitmap = newBits;
    4523           0 :     mTransparencyBitmapWidth = mBounds.width;
    4524           0 :     mTransparencyBitmapHeight = mBounds.height;
    4525             : }
    4526             : 
    4527             : static bool
    4528           0 : ChangedMaskBits(gchar* aMaskBits, int32_t aMaskWidth, int32_t aMaskHeight,
    4529             :         const nsIntRect& aRect, uint8_t* aAlphas, int32_t aStride)
    4530             : {
    4531           0 :     int32_t x, y, xMax = aRect.XMost(), yMax = aRect.YMost();
    4532           0 :     int32_t maskBytesPerRow = GetBitmapStride(aMaskWidth);
    4533           0 :     for (y = aRect.y; y < yMax; y++) {
    4534           0 :         gchar* maskBytes = aMaskBits + y*maskBytesPerRow;
    4535           0 :         uint8_t* alphas = aAlphas;
    4536           0 :         for (x = aRect.x; x < xMax; x++) {
    4537           0 :             bool newBit = *alphas > 0x7f;
    4538           0 :             alphas++;
    4539             : 
    4540           0 :             gchar maskByte = maskBytes[x >> 3];
    4541           0 :             bool maskBit = (maskByte & (1 << (x & 7))) != 0;
    4542             : 
    4543           0 :             if (maskBit != newBit) {
    4544           0 :                 return true;
    4545             :             }
    4546             :         }
    4547           0 :         aAlphas += aStride;
    4548             :     }
    4549             : 
    4550           0 :     return false;
    4551             : }
    4552             : 
    4553             : static
    4554           0 : void UpdateMaskBits(gchar* aMaskBits, int32_t aMaskWidth, int32_t aMaskHeight,
    4555             :         const nsIntRect& aRect, uint8_t* aAlphas, int32_t aStride)
    4556             : {
    4557           0 :     int32_t x, y, xMax = aRect.XMost(), yMax = aRect.YMost();
    4558           0 :     int32_t maskBytesPerRow = GetBitmapStride(aMaskWidth);
    4559           0 :     for (y = aRect.y; y < yMax; y++) {
    4560           0 :         gchar* maskBytes = aMaskBits + y*maskBytesPerRow;
    4561           0 :         uint8_t* alphas = aAlphas;
    4562           0 :         for (x = aRect.x; x < xMax; x++) {
    4563           0 :             bool newBit = *alphas > 0x7f;
    4564           0 :             alphas++;
    4565             : 
    4566           0 :             gchar mask = 1 << (x & 7);
    4567           0 :             gchar maskByte = maskBytes[x >> 3];
    4568             :             // Note: '-newBit' turns 0 into 00...00 and 1 into 11...11
    4569           0 :             maskBytes[x >> 3] = (maskByte & ~mask) | (-newBit & mask);
    4570             :         }
    4571           0 :         aAlphas += aStride;
    4572             :     }
    4573           0 : }
    4574             : 
    4575             : void
    4576           0 : nsWindow::ApplyTransparencyBitmap()
    4577             : {
    4578             : #ifdef MOZ_X11
    4579             :     // We use X11 calls where possible, because GDK handles expose events
    4580             :     // for shaped windows in a way that's incompatible with us (Bug 635903).
    4581             :     // It doesn't occur when the shapes are set through X.
    4582           0 :     Display* xDisplay = GDK_WINDOW_XDISPLAY(mGdkWindow);
    4583           0 :     Window xDrawable = GDK_WINDOW_XID(mGdkWindow);
    4584           0 :     Pixmap maskPixmap = XCreateBitmapFromData(xDisplay,
    4585             :                                               xDrawable,
    4586           0 :                                               mTransparencyBitmap,
    4587           0 :                                               mTransparencyBitmapWidth,
    4588           0 :                                               mTransparencyBitmapHeight);
    4589             :     XShapeCombineMask(xDisplay, xDrawable,
    4590             :                       ShapeBounding, 0, 0,
    4591           0 :                       maskPixmap, ShapeSet);
    4592           0 :     XFreePixmap(xDisplay, maskPixmap);
    4593             : #else
    4594             : #if (MOZ_WIDGET_GTK == 2)
    4595             :     gtk_widget_reset_shapes(mShell);
    4596             :     GdkBitmap* maskBitmap = gdk_bitmap_create_from_data(mGdkWindow,
    4597             :             mTransparencyBitmap,
    4598             :             mTransparencyBitmapWidth, mTransparencyBitmapHeight);
    4599             :     if (!maskBitmap)
    4600             :         return;
    4601             : 
    4602             :     gtk_widget_shape_combine_mask(mShell, maskBitmap, 0, 0);
    4603             :     g_object_unref(maskBitmap);
    4604             : #else
    4605             :     cairo_surface_t *maskBitmap;
    4606             :     maskBitmap = cairo_image_surface_create_for_data((unsigned char*)mTransparencyBitmap,
    4607             :                                                      CAIRO_FORMAT_A1,
    4608             :                                                      mTransparencyBitmapWidth,
    4609             :                                                      mTransparencyBitmapHeight,
    4610             :                                                      GetBitmapStride(mTransparencyBitmapWidth));
    4611             :     if (!maskBitmap)
    4612             :         return;
    4613             : 
    4614             :     cairo_region_t * maskRegion = gdk_cairo_region_create_from_surface(maskBitmap);
    4615             :     gtk_widget_shape_combine_region(mShell, maskRegion);
    4616             :     cairo_region_destroy(maskRegion);
    4617             :     cairo_surface_destroy(maskBitmap);
    4618             : #endif // MOZ_WIDGET_GTK == 2
    4619             : #endif // MOZ_X11
    4620           0 : }
    4621             : 
    4622             : void
    4623           0 : nsWindow::ClearTransparencyBitmap()
    4624             : {
    4625           0 :     if (!mTransparencyBitmap)
    4626           0 :         return;
    4627             : 
    4628           0 :     delete[] mTransparencyBitmap;
    4629           0 :     mTransparencyBitmap = nullptr;
    4630           0 :     mTransparencyBitmapWidth = 0;
    4631           0 :     mTransparencyBitmapHeight = 0;
    4632             : 
    4633           0 :     if (!mShell)
    4634           0 :         return;
    4635             : 
    4636             : #ifdef MOZ_X11
    4637           0 :     if (!mGdkWindow)
    4638           0 :         return;
    4639             : 
    4640           0 :     Display* xDisplay = GDK_WINDOW_XDISPLAY(mGdkWindow);
    4641           0 :     Window xWindow = gdk_x11_window_get_xid(mGdkWindow);
    4642             : 
    4643           0 :     XShapeCombineMask(xDisplay, xWindow, ShapeBounding, 0, 0, X11None, ShapeSet);
    4644             : #endif
    4645             : }
    4646             : 
    4647             : nsresult
    4648           0 : nsWindow::UpdateTranslucentWindowAlphaInternal(const nsIntRect& aRect,
    4649             :                                                uint8_t* aAlphas, int32_t aStride)
    4650             : {
    4651           0 :     if (!mShell) {
    4652             :         // Pass the request to the toplevel window
    4653           0 :         GtkWidget *topWidget = GetToplevelWidget();
    4654           0 :         if (!topWidget)
    4655           0 :             return NS_ERROR_FAILURE;
    4656             : 
    4657           0 :         nsWindow *topWindow = get_window_for_gtk_widget(topWidget);
    4658           0 :         if (!topWindow)
    4659           0 :             return NS_ERROR_FAILURE;
    4660             : 
    4661           0 :         return topWindow->UpdateTranslucentWindowAlphaInternal(aRect, aAlphas, aStride);
    4662             :     }
    4663             : 
    4664           0 :     NS_ASSERTION(mIsTransparent, "Window is not transparent");
    4665             : 
    4666           0 :     if (mTransparencyBitmap == nullptr) {
    4667           0 :         int32_t size = GetBitmapStride(mBounds.width)*mBounds.height;
    4668           0 :         mTransparencyBitmap = new gchar[size];
    4669           0 :         memset(mTransparencyBitmap, 255, size);
    4670           0 :         mTransparencyBitmapWidth = mBounds.width;
    4671           0 :         mTransparencyBitmapHeight = mBounds.height;
    4672             :     } else {
    4673           0 :         ResizeTransparencyBitmap();
    4674             :     }
    4675             : 
    4676           0 :     nsIntRect rect;
    4677           0 :     rect.IntersectRect(aRect, nsIntRect(0, 0, mBounds.width, mBounds.height));
    4678             : 
    4679           0 :     if (!ChangedMaskBits(mTransparencyBitmap, mBounds.width, mBounds.height,
    4680             :                          rect, aAlphas, aStride))
    4681             :         // skip the expensive stuff if the mask bits haven't changed; hopefully
    4682             :         // this is the common case
    4683           0 :         return NS_OK;
    4684             : 
    4685           0 :     UpdateMaskBits(mTransparencyBitmap, mBounds.width, mBounds.height,
    4686           0 :                    rect, aAlphas, aStride);
    4687             : 
    4688           0 :     if (!mNeedsShow) {
    4689           0 :         ApplyTransparencyBitmap();
    4690             :     }
    4691           0 :     return NS_OK;
    4692             : }
    4693             : 
    4694             : void
    4695           0 : nsWindow::GrabPointer(guint32 aTime)
    4696             : {
    4697           0 :     LOG(("GrabPointer time=0x%08x retry=%d\n",
    4698             :          (unsigned int)aTime, mRetryPointerGrab));
    4699             : 
    4700           0 :     mRetryPointerGrab = false;
    4701           0 :     sRetryGrabTime = aTime;
    4702             : 
    4703             :     // If the window isn't visible, just set the flag to retry the
    4704             :     // grab.  When this window becomes visible, the grab will be
    4705             :     // retried.
    4706           0 :     if (!mHasMappedToplevel || mIsFullyObscured) {
    4707           0 :         LOG(("GrabPointer: window not visible\n"));
    4708           0 :         mRetryPointerGrab = true;
    4709           0 :         return;
    4710             :     }
    4711             : 
    4712           0 :     if (!mGdkWindow)
    4713           0 :         return;
    4714             : 
    4715             :     gint retval;
    4716           0 :     retval = gdk_pointer_grab(mGdkWindow, TRUE,
    4717             :                               (GdkEventMask)(GDK_BUTTON_PRESS_MASK |
    4718             :                                              GDK_BUTTON_RELEASE_MASK |
    4719             :                                              GDK_ENTER_NOTIFY_MASK |
    4720             :                                              GDK_LEAVE_NOTIFY_MASK |
    4721             :                                              GDK_POINTER_MOTION_MASK),
    4722             :                               (GdkWindow *)nullptr, nullptr, aTime);
    4723             : 
    4724           0 :     if (retval == GDK_GRAB_NOT_VIEWABLE) {
    4725           0 :         LOG(("GrabPointer: window not viewable; will retry\n"));
    4726           0 :         mRetryPointerGrab = true;
    4727           0 :     } else if (retval != GDK_GRAB_SUCCESS) {
    4728           0 :         LOG(("GrabPointer: pointer grab failed: %i\n", retval));
    4729             :         // A failed grab indicates that another app has grabbed the pointer.
    4730             :         // Check for rollup now, because, without the grab, we likely won't
    4731             :         // get subsequent button press events. Do this with an event so that
    4732             :         // popups don't rollup while potentially adjusting the grab for
    4733             :         // this popup.
    4734             :         nsCOMPtr<nsIRunnable> event =
    4735           0 :           NewRunnableMethod("nsWindow::CheckForRollupDuringGrab",
    4736             :                             this,
    4737           0 :                             &nsWindow::CheckForRollupDuringGrab);
    4738           0 :         NS_DispatchToCurrentThread(event.forget());
    4739             :     }
    4740             : }
    4741             : 
    4742             : void
    4743           0 : nsWindow::ReleaseGrabs(void)
    4744             : {
    4745           0 :     LOG(("ReleaseGrabs\n"));
    4746             : 
    4747           0 :     mRetryPointerGrab = false;
    4748           0 :     gdk_pointer_ungrab(GDK_CURRENT_TIME);
    4749           0 : }
    4750             : 
    4751             : GtkWidget *
    4752           1 : nsWindow::GetToplevelWidget()
    4753             : {
    4754           1 :     if (mShell) {
    4755           1 :         return mShell;
    4756             :     }
    4757             : 
    4758           0 :     GtkWidget *widget = GetMozContainerWidget();
    4759           0 :     if (!widget)
    4760           0 :         return nullptr;
    4761             : 
    4762           0 :     return gtk_widget_get_toplevel(widget);
    4763             : }
    4764             : 
    4765             : GtkWidget *
    4766           0 : nsWindow::GetMozContainerWidget()
    4767             : {
    4768           0 :     if (!mGdkWindow)
    4769           0 :         return nullptr;
    4770             : 
    4771           0 :     if (mContainer)
    4772           0 :         return GTK_WIDGET(mContainer);
    4773             : 
    4774             :     GtkWidget *owningWidget =
    4775           0 :         get_gtk_widget_for_gdk_window(mGdkWindow);
    4776           0 :     return owningWidget;
    4777             : }
    4778             : 
    4779             : nsWindow *
    4780           0 : nsWindow::GetContainerWindow()
    4781             : {
    4782           0 :     GtkWidget *owningWidget = GetMozContainerWidget();
    4783           0 :     if (!owningWidget)
    4784           0 :         return nullptr;
    4785             : 
    4786           0 :     nsWindow *window = get_window_for_gtk_widget(owningWidget);
    4787           0 :     NS_ASSERTION(window, "No nsWindow for container widget");
    4788           0 :     return window;
    4789             : }
    4790             : 
    4791             : void
    4792           1 : nsWindow::SetUrgencyHint(GtkWidget *top_window, bool state)
    4793             : {
    4794           1 :     if (!top_window)
    4795           0 :         return;
    4796             : 
    4797           1 :     gdk_window_set_urgency_hint(gtk_widget_get_window(top_window), state);
    4798             : }
    4799             : 
    4800             : void
    4801           2 : nsWindow::SetDefaultIcon(void)
    4802             : {
    4803           2 :     SetIcon(NS_LITERAL_STRING("default"));
    4804           2 : }
    4805             : 
    4806             : gint
    4807           0 : nsWindow::ConvertBorderStyles(nsBorderStyle aStyle)
    4808             : {
    4809           0 :     gint w = 0;
    4810             : 
    4811           0 :     if (aStyle == eBorderStyle_default)
    4812           0 :         return -1;
    4813             : 
    4814             :     // note that we don't handle eBorderStyle_close yet
    4815           0 :     if (aStyle & eBorderStyle_all)
    4816           0 :         w |= GDK_DECOR_ALL;
    4817           0 :     if (aStyle & eBorderStyle_border)
    4818           0 :         w |= GDK_DECOR_BORDER;
    4819           0 :     if (aStyle & eBorderStyle_resizeh)
    4820           0 :         w |= GDK_DECOR_RESIZEH;
    4821           0 :     if (aStyle & eBorderStyle_title)
    4822           0 :         w |= GDK_DECOR_TITLE;
    4823           0 :     if (aStyle & eBorderStyle_menu)
    4824           0 :         w |= GDK_DECOR_MENU;
    4825           0 :     if (aStyle & eBorderStyle_minimize)
    4826           0 :         w |= GDK_DECOR_MINIMIZE;
    4827           0 :     if (aStyle & eBorderStyle_maximize)
    4828           0 :         w |= GDK_DECOR_MAXIMIZE;
    4829             : 
    4830           0 :     return w;
    4831             : }
    4832             : 
    4833             : class FullscreenTransitionWindow final : public nsISupports
    4834             : {
    4835             : public:
    4836             :     NS_DECL_ISUPPORTS
    4837             : 
    4838             :     explicit FullscreenTransitionWindow(GtkWidget* aWidget);
    4839             : 
    4840             :     GtkWidget* mWindow;
    4841             : 
    4842             : private:
    4843             :     ~FullscreenTransitionWindow();
    4844             : };
    4845             : 
    4846           0 : NS_IMPL_ISUPPORTS0(FullscreenTransitionWindow)
    4847             : 
    4848           0 : FullscreenTransitionWindow::FullscreenTransitionWindow(GtkWidget* aWidget)
    4849             : {
    4850           0 :     mWindow = gtk_window_new(GTK_WINDOW_POPUP);
    4851           0 :     GtkWindow* gtkWin = GTK_WINDOW(mWindow);
    4852             : 
    4853           0 :     gtk_window_set_type_hint(gtkWin, GDK_WINDOW_TYPE_HINT_SPLASHSCREEN);
    4854           0 :     gtk_window_set_transient_for(gtkWin, GTK_WINDOW(aWidget));
    4855           0 :     gtk_window_set_decorated(gtkWin, false);
    4856             : 
    4857           0 :     GdkWindow* gdkWin = gtk_widget_get_window(aWidget);
    4858           0 :     GdkScreen* screen = gtk_widget_get_screen(aWidget);
    4859           0 :     gint monitorNum = gdk_screen_get_monitor_at_window(screen, gdkWin);
    4860             :     GdkRectangle monitorRect;
    4861           0 :     gdk_screen_get_monitor_geometry(screen, monitorNum, &monitorRect);
    4862           0 :     gtk_window_set_screen(gtkWin, screen);
    4863           0 :     gtk_window_move(gtkWin, monitorRect.x, monitorRect.y);
    4864           0 :     gtk_window_resize(gtkWin, monitorRect.width, monitorRect.height);
    4865             : 
    4866             :     GdkColor bgColor;
    4867           0 :     bgColor.red = bgColor.green = bgColor.blue = 0;
    4868           0 :     gtk_widget_modify_bg(mWindow, GTK_STATE_NORMAL, &bgColor);
    4869             : 
    4870           0 :     gtk_window_set_opacity(gtkWin, 0.0);
    4871           0 :     gtk_widget_show(mWindow);
    4872           0 : }
    4873             : 
    4874           0 : FullscreenTransitionWindow::~FullscreenTransitionWindow()
    4875             : {
    4876           0 :     gtk_widget_destroy(mWindow);
    4877           0 : }
    4878             : 
    4879           0 : class FullscreenTransitionData
    4880             : {
    4881             : public:
    4882           0 :     FullscreenTransitionData(nsIWidget::FullscreenTransitionStage aStage,
    4883             :                              uint16_t aDuration, nsIRunnable* aCallback,
    4884             :                              FullscreenTransitionWindow* aWindow)
    4885           0 :         : mStage(aStage)
    4886             :         , mStartTime(TimeStamp::Now())
    4887           0 :         , mDuration(TimeDuration::FromMilliseconds(aDuration))
    4888             :         , mCallback(aCallback)
    4889           0 :         , mWindow(aWindow) { }
    4890             : 
    4891             :     static const guint sInterval = 1000 / 30; // 30fps
    4892             :     static gboolean TimeoutCallback(gpointer aData);
    4893             : 
    4894             : private:
    4895             :     nsIWidget::FullscreenTransitionStage mStage;
    4896             :     TimeStamp mStartTime;
    4897             :     TimeDuration mDuration;
    4898             :     nsCOMPtr<nsIRunnable> mCallback;
    4899             :     RefPtr<FullscreenTransitionWindow> mWindow;
    4900             : };
    4901             : 
    4902             : /* static */ gboolean
    4903           0 : FullscreenTransitionData::TimeoutCallback(gpointer aData)
    4904             : {
    4905           0 :     bool finishing = false;
    4906           0 :     auto data = static_cast<FullscreenTransitionData*>(aData);
    4907           0 :     gdouble opacity = (TimeStamp::Now() - data->mStartTime) / data->mDuration;
    4908           0 :     if (opacity >= 1.0) {
    4909           0 :         opacity = 1.0;
    4910           0 :         finishing = true;
    4911             :     }
    4912           0 :     if (data->mStage == nsIWidget::eAfterFullscreenToggle) {
    4913           0 :         opacity = 1.0 - opacity;
    4914             :     }
    4915           0 :     gtk_window_set_opacity(GTK_WINDOW(data->mWindow->mWindow), opacity);
    4916             : 
    4917           0 :     if (!finishing) {
    4918           0 :         return TRUE;
    4919             :     }
    4920           0 :     NS_DispatchToMainThread(data->mCallback.forget());
    4921           0 :     delete data;
    4922           0 :     return FALSE;
    4923             : }
    4924             : 
    4925             : /* virtual */ bool
    4926           0 : nsWindow::PrepareForFullscreenTransition(nsISupports** aData)
    4927             : {
    4928           0 :     GdkScreen* screen = gtk_widget_get_screen(mShell);
    4929           0 :     if (!gdk_screen_is_composited(screen)) {
    4930           0 :         return false;
    4931             :     }
    4932           0 :     *aData = do_AddRef(new FullscreenTransitionWindow(mShell)).take();
    4933           0 :     return true;
    4934             : }
    4935             : 
    4936             : /* virtual */ void
    4937           0 : nsWindow::PerformFullscreenTransition(FullscreenTransitionStage aStage,
    4938             :                                       uint16_t aDuration, nsISupports* aData,
    4939             :                                       nsIRunnable* aCallback)
    4940             : {
    4941           0 :     auto data = static_cast<FullscreenTransitionWindow*>(aData);
    4942             :     // This will be released at the end of the last timeout callback for it.
    4943             :     auto transitionData = new FullscreenTransitionData(aStage, aDuration,
    4944           0 :                                                        aCallback, data);
    4945             :     g_timeout_add_full(G_PRIORITY_HIGH,
    4946             :                        FullscreenTransitionData::sInterval,
    4947             :                        FullscreenTransitionData::TimeoutCallback,
    4948           0 :                        transitionData, nullptr);
    4949           0 : }
    4950             : 
    4951             : already_AddRefed<nsIScreen>
    4952          24 : nsWindow::GetWidgetScreen()
    4953             : {
    4954          48 :   nsCOMPtr<nsIScreenManager> screenManager;
    4955          24 :   screenManager = do_GetService("@mozilla.org/gfx/screenmanager;1");
    4956          24 :   if (!screenManager) {
    4957           0 :     return nullptr;
    4958             :   }
    4959             : 
    4960             :   // GetScreenBounds() is slow for the GTK port so we override and use
    4961             :   // mBounds directly.
    4962          24 :   LayoutDeviceIntRect bounds = mBounds;
    4963          24 :   if (!mIsTopLevel) {
    4964           0 :       bounds.MoveTo(WidgetToScreenOffset());
    4965             :   }
    4966             : 
    4967          24 :   DesktopIntRect deskBounds = RoundedToInt(bounds / GetDesktopToDeviceScale());
    4968          48 :   nsCOMPtr<nsIScreen> screen;
    4969          48 :   screenManager->ScreenForRect(deskBounds.x, deskBounds.y,
    4970             :                                deskBounds.width, deskBounds.height,
    4971          48 :                                getter_AddRefs(screen));
    4972          24 :   return screen.forget();
    4973             : }
    4974             : 
    4975             : static bool
    4976           0 : IsFullscreenSupported(GtkWidget* aShell)
    4977             : {
    4978             : #ifdef MOZ_X11
    4979           0 :     GdkScreen* screen = gtk_widget_get_screen(aShell);
    4980           0 :     GdkAtom atom = gdk_atom_intern("_NET_WM_STATE_FULLSCREEN", FALSE);
    4981           0 :     if (!gdk_x11_screen_supports_net_wm_hint(screen, atom)) {
    4982           0 :         return false;
    4983             :     }
    4984             : #endif
    4985           0 :     return true;
    4986             : }
    4987             : 
    4988             : nsresult
    4989           0 : nsWindow::MakeFullScreen(bool aFullScreen, nsIScreen* aTargetScreen)
    4990             : {
    4991           0 :     LOG(("nsWindow::MakeFullScreen [%p] aFullScreen %d\n",
    4992             :          (void *)this, aFullScreen));
    4993             : 
    4994           0 :     if (!IsFullscreenSupported(mShell)) {
    4995           0 :         return NS_ERROR_NOT_AVAILABLE;
    4996             :     }
    4997             : 
    4998           0 :     if (aFullScreen) {
    4999           0 :         if (mSizeMode != nsSizeMode_Fullscreen)
    5000           0 :             mLastSizeMode = mSizeMode;
    5001             : 
    5002           0 :         mSizeMode = nsSizeMode_Fullscreen;
    5003           0 :         gtk_window_fullscreen(GTK_WINDOW(mShell));
    5004             :     }
    5005             :     else {
    5006           0 :         mSizeMode = mLastSizeMode;
    5007           0 :         gtk_window_unfullscreen(GTK_WINDOW(mShell));
    5008             :     }
    5009             : 
    5010           0 :     NS_ASSERTION(mLastSizeMode != nsSizeMode_Fullscreen,
    5011             :                  "mLastSizeMode should never be fullscreen");
    5012           0 :     return NS_OK;
    5013             : }
    5014             : 
    5015             : void
    5016           0 : nsWindow::HideWindowChrome(bool aShouldHide)
    5017             : {
    5018           0 :     if (!mShell) {
    5019             :         // Pass the request to the toplevel window
    5020           0 :         GtkWidget *topWidget = GetToplevelWidget();
    5021           0 :         if (!topWidget)
    5022           0 :             return;
    5023             : 
    5024           0 :         nsWindow *topWindow = get_window_for_gtk_widget(topWidget);
    5025           0 :         if (!topWindow)
    5026           0 :             return;
    5027             : 
    5028           0 :         topWindow->HideWindowChrome(aShouldHide);
    5029           0 :         return;
    5030             :     }
    5031             : 
    5032             :     // Sawfish, metacity, and presumably other window managers get
    5033             :     // confused if we change the window decorations while the window
    5034             :     // is visible.
    5035           0 :     bool wasVisible = false;
    5036           0 :     if (gdk_window_is_visible(mGdkWindow)) {
    5037           0 :         gdk_window_hide(mGdkWindow);
    5038           0 :         wasVisible = true;
    5039             :     }
    5040             : 
    5041             :     gint wmd;
    5042           0 :     if (aShouldHide)
    5043           0 :         wmd = 0;
    5044             :     else
    5045           0 :         wmd = ConvertBorderStyles(mBorderStyle);
    5046             : 
    5047           0 :     if (wmd != -1)
    5048           0 :       gdk_window_set_decorations(mGdkWindow, (GdkWMDecoration) wmd);
    5049             : 
    5050           0 :     if (wasVisible)
    5051           0 :         gdk_window_show(mGdkWindow);
    5052             : 
    5053             :     // For some window managers, adding or removing window decorations
    5054             :     // requires unmapping and remapping our toplevel window.  Go ahead
    5055             :     // and flush the queue here so that we don't end up with a BadWindow
    5056             :     // error later when this happens (when the persistence timer fires
    5057             :     // and GetWindowPos is called)
    5058             : #ifdef MOZ_X11
    5059           0 :     XSync(GDK_DISPLAY_XDISPLAY(gdk_display_get_default()) , False);
    5060             : #else
    5061             :     gdk_flush ();
    5062             : #endif /* MOZ_X11 */
    5063             : }
    5064             : 
    5065             : bool
    5066           1 : nsWindow::CheckForRollup(gdouble aMouseX, gdouble aMouseY,
    5067             :                          bool aIsWheel, bool aAlwaysRollup)
    5068             : {
    5069           1 :     nsIRollupListener* rollupListener = GetActiveRollupListener();
    5070           2 :     nsCOMPtr<nsIWidget> rollupWidget;
    5071           1 :     if (rollupListener) {
    5072           1 :         rollupWidget = rollupListener->GetRollupWidget();
    5073             :     }
    5074           1 :     if (!rollupWidget) {
    5075           1 :         nsBaseWidget::gRollupListener = nullptr;
    5076           1 :         return false;
    5077             :     }
    5078             : 
    5079           0 :     bool retVal = false;
    5080             :     auto *currentPopup =
    5081           0 :         (GdkWindow *)rollupWidget->GetNativeData(NS_NATIVE_WINDOW);
    5082           0 :     if (aAlwaysRollup || !is_mouse_in_window(currentPopup, aMouseX, aMouseY)) {
    5083           0 :         bool rollup = true;
    5084           0 :         if (aIsWheel) {
    5085           0 :             rollup = rollupListener->ShouldRollupOnMouseWheelEvent();
    5086           0 :             retVal = rollupListener->ShouldConsumeOnMouseWheelEvent();
    5087             :         }
    5088             :         // if we're dealing with menus, we probably have submenus and
    5089             :         // we don't want to rollup if the click is in a parent menu of
    5090             :         // the current submenu
    5091           0 :         uint32_t popupsToRollup = UINT32_MAX;
    5092           0 :         if (!aAlwaysRollup) {
    5093           0 :             AutoTArray<nsIWidget*, 5> widgetChain;
    5094           0 :             uint32_t sameTypeCount = rollupListener->GetSubmenuWidgetChain(&widgetChain);
    5095           0 :             for (uint32_t i=0; i<widgetChain.Length(); ++i) {
    5096           0 :                 nsIWidget* widget = widgetChain[i];
    5097             :                 auto* currWindow =
    5098           0 :                     (GdkWindow*) widget->GetNativeData(NS_NATIVE_WINDOW);
    5099           0 :                 if (is_mouse_in_window(currWindow, aMouseX, aMouseY)) {
    5100             :                   // don't roll up if the mouse event occurred within a
    5101             :                   // menu of the same type. If the mouse event occurred
    5102             :                   // in a menu higher than that, roll up, but pass the
    5103             :                   // number of popups to Rollup so that only those of the
    5104             :                   // same type close up.
    5105           0 :                   if (i < sameTypeCount) {
    5106           0 :                     rollup = false;
    5107             :                   }
    5108             :                   else {
    5109           0 :                     popupsToRollup = sameTypeCount;
    5110             :                   }
    5111           0 :                   break;
    5112             :                 }
    5113             :             } // foreach parent menu widget
    5114             :         } // if rollup listener knows about menus
    5115             : 
    5116             :         // if we've determined that we should still rollup, do it.
    5117           0 :         bool usePoint = !aIsWheel && !aAlwaysRollup;
    5118           0 :         IntPoint point = IntPoint::Truncate(aMouseX, aMouseY);
    5119           0 :         if (rollup && rollupListener->Rollup(popupsToRollup, true, usePoint ? &point : nullptr, nullptr)) {
    5120           0 :             retVal = true;
    5121             :         }
    5122             :     }
    5123           0 :     return retVal;
    5124             : }
    5125             : 
    5126             : /* static */
    5127             : bool
    5128           0 : nsWindow::DragInProgress(void)
    5129             : {
    5130           0 :     nsCOMPtr<nsIDragService> dragService = do_GetService(kCDragServiceCID);
    5131             : 
    5132           0 :     if (!dragService)
    5133           0 :         return false;
    5134             : 
    5135           0 :     nsCOMPtr<nsIDragSession> currentDragSession;
    5136           0 :     dragService->GetCurrentSession(getter_AddRefs(currentDragSession));
    5137             : 
    5138           0 :     return currentDragSession != nullptr;
    5139             : }
    5140             : 
    5141             : static bool
    5142           0 : is_mouse_in_window (GdkWindow* aWindow, gdouble aMouseX, gdouble aMouseY)
    5143             : {
    5144           0 :     gint x = 0;
    5145           0 :     gint y = 0;
    5146             :     gint w, h;
    5147             : 
    5148           0 :     gint offsetX = 0;
    5149           0 :     gint offsetY = 0;
    5150             : 
    5151           0 :     GdkWindow *window = aWindow;
    5152             : 
    5153           0 :     while (window) {
    5154           0 :         gint tmpX = 0;
    5155           0 :         gint tmpY = 0;
    5156             : 
    5157           0 :         gdk_window_get_position(window, &tmpX, &tmpY);
    5158           0 :         GtkWidget *widget = get_gtk_widget_for_gdk_window(window);
    5159             : 
    5160             :         // if this is a window, compute x and y given its origin and our
    5161             :         // offset
    5162           0 :         if (GTK_IS_WINDOW(widget)) {
    5163           0 :             x = tmpX + offsetX;
    5164           0 :             y = tmpY + offsetY;
    5165           0 :             break;
    5166             :         }
    5167             : 
    5168           0 :         offsetX += tmpX;
    5169           0 :         offsetY += tmpY;
    5170           0 :         window = gdk_window_get_parent(window);
    5171             :     }
    5172             : 
    5173             : #if (MOZ_WIDGET_GTK == 2)
    5174             :     gdk_drawable_get_size(aWindow, &w, &h);
    5175             : #else
    5176           0 :     w = gdk_window_get_width(aWindow);
    5177           0 :     h = gdk_window_get_height(aWindow);
    5178             : #endif
    5179             : 
    5180           0 :     if (aMouseX > x && aMouseX < x + w &&
    5181           0 :         aMouseY > y && aMouseY < y + h)
    5182           0 :         return true;
    5183             : 
    5184           0 :     return false;
    5185             : }
    5186             : 
    5187             : static nsWindow *
    5188          26 : get_window_for_gtk_widget(GtkWidget *widget)
    5189             : {
    5190          26 :     gpointer user_data = g_object_get_data(G_OBJECT(widget), "nsWindow");
    5191             : 
    5192          26 :     return static_cast<nsWindow *>(user_data);
    5193             : }
    5194             : 
    5195             : static nsWindow *
    5196          86 : get_window_for_gdk_window(GdkWindow *window)
    5197             : {
    5198          86 :     gpointer user_data = g_object_get_data(G_OBJECT(window), "nsWindow");
    5199             : 
    5200          86 :     return static_cast<nsWindow *>(user_data);
    5201             : }
    5202             : 
    5203             : static GtkWidget *
    5204           0 : get_gtk_widget_for_gdk_window(GdkWindow *window)
    5205             : {
    5206           0 :     gpointer user_data = nullptr;
    5207           0 :     gdk_window_get_user_data(window, &user_data);
    5208             : 
    5209           0 :     return GTK_WIDGET(user_data);
    5210             : }
    5211             : 
    5212             : static GdkCursor *
    5213           0 : get_gtk_cursor(nsCursor aCursor)
    5214             : {
    5215           0 :     GdkCursor *gdkcursor = nullptr;
    5216           0 :     uint8_t newType = 0xff;
    5217             : 
    5218           0 :     if ((gdkcursor = gCursorCache[aCursor])) {
    5219           0 :         return gdkcursor;
    5220             :     }
    5221             : 
    5222           0 :     GdkDisplay *defaultDisplay = gdk_display_get_default();
    5223             : 
    5224             :     // The strategy here is to use standard GDK cursors, and, if not available,
    5225             :     // load by standard name with gdk_cursor_new_from_name.
    5226             :     // Spec is here: http://www.freedesktop.org/wiki/Specifications/cursor-spec/
    5227           0 :     switch (aCursor) {
    5228             :     case eCursor_standard:
    5229           0 :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_LEFT_PTR);
    5230           0 :         break;
    5231             :     case eCursor_wait:
    5232           0 :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_WATCH);
    5233           0 :         break;
    5234             :     case eCursor_select:
    5235           0 :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_XTERM);
    5236           0 :         break;
    5237             :     case eCursor_hyperlink:
    5238           0 :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_HAND2);
    5239           0 :         break;
    5240             :     case eCursor_n_resize:
    5241           0 :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_TOP_SIDE);
    5242           0 :         break;
    5243             :     case eCursor_s_resize:
    5244           0 :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_BOTTOM_SIDE);
    5245           0 :         break;
    5246             :     case eCursor_w_resize:
    5247           0 :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_LEFT_SIDE);
    5248           0 :         break;
    5249             :     case eCursor_e_resize:
    5250           0 :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_RIGHT_SIDE);
    5251           0 :         break;
    5252             :     case eCursor_nw_resize:
    5253             :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay,
    5254           0 :                                                GDK_TOP_LEFT_CORNER);
    5255           0 :         break;
    5256             :     case eCursor_se_resize:
    5257             :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay,
    5258           0 :                                                GDK_BOTTOM_RIGHT_CORNER);
    5259           0 :         break;
    5260             :     case eCursor_ne_resize:
    5261             :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay,
    5262           0 :                                                GDK_TOP_RIGHT_CORNER);
    5263           0 :         break;
    5264             :     case eCursor_sw_resize:
    5265             :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay,
    5266           0 :                                                GDK_BOTTOM_LEFT_CORNER);
    5267           0 :         break;
    5268             :     case eCursor_crosshair:
    5269           0 :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_CROSSHAIR);
    5270           0 :         break;
    5271             :     case eCursor_move:
    5272           0 :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_FLEUR);
    5273           0 :         break;
    5274             :     case eCursor_help:
    5275             :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay,
    5276           0 :                                                GDK_QUESTION_ARROW);
    5277           0 :         break;
    5278             :     case eCursor_copy: // CSS3
    5279           0 :         gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "copy");
    5280           0 :         if (!gdkcursor)
    5281           0 :             newType = MOZ_CURSOR_COPY;
    5282           0 :         break;
    5283             :     case eCursor_alias:
    5284           0 :         gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "alias");
    5285           0 :         if (!gdkcursor)
    5286           0 :             newType = MOZ_CURSOR_ALIAS;
    5287           0 :         break;
    5288             :     case eCursor_context_menu:
    5289           0 :         gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "context-menu");
    5290           0 :         if (!gdkcursor)
    5291           0 :             newType = MOZ_CURSOR_CONTEXT_MENU;
    5292           0 :         break;
    5293             :     case eCursor_cell:
    5294           0 :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_PLUS);
    5295           0 :         break;
    5296             :     // Those two aren’t standardized. Trying both KDE’s and GNOME’s names
    5297             :     case eCursor_grab:
    5298           0 :         gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "openhand");
    5299           0 :         if (!gdkcursor)
    5300           0 :             newType = MOZ_CURSOR_HAND_GRAB;
    5301           0 :         break;
    5302             :     case eCursor_grabbing:
    5303           0 :         gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "closedhand");
    5304           0 :         if (!gdkcursor)
    5305           0 :             gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "grabbing");
    5306           0 :         if (!gdkcursor)
    5307           0 :             newType = MOZ_CURSOR_HAND_GRABBING;
    5308           0 :         break;
    5309             :     case eCursor_spinning:
    5310           0 :         gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "progress");
    5311           0 :         if (!gdkcursor)
    5312           0 :             newType = MOZ_CURSOR_SPINNING;
    5313           0 :         break;
    5314             :     case eCursor_zoom_in:
    5315           0 :         gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "zoom-in");
    5316           0 :         if (!gdkcursor)
    5317           0 :             newType = MOZ_CURSOR_ZOOM_IN;
    5318           0 :         break;
    5319             :     case eCursor_zoom_out:
    5320           0 :         gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "zoom-out");
    5321           0 :         if (!gdkcursor)
    5322           0 :             newType = MOZ_CURSOR_ZOOM_OUT;
    5323           0 :         break;
    5324             :     case eCursor_not_allowed:
    5325           0 :         gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "not-allowed");
    5326           0 :         if (!gdkcursor) // nonstandard, yet common
    5327           0 :             gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "crossed_circle");
    5328           0 :         if (!gdkcursor)
    5329           0 :             newType = MOZ_CURSOR_NOT_ALLOWED;
    5330           0 :         break;
    5331             :     case eCursor_no_drop:
    5332           0 :         gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "no-drop");
    5333           0 :         if (!gdkcursor) // this nonstandard sequence makes it work on KDE and GNOME
    5334           0 :             gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "forbidden");
    5335           0 :         if (!gdkcursor)
    5336           0 :             gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "circle");
    5337           0 :         if (!gdkcursor)
    5338           0 :             newType = MOZ_CURSOR_NOT_ALLOWED;
    5339           0 :         break;
    5340             :     case eCursor_vertical_text:
    5341           0 :         newType = MOZ_CURSOR_VERTICAL_TEXT;
    5342           0 :         break;
    5343             :     case eCursor_all_scroll:
    5344           0 :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_FLEUR);
    5345           0 :         break;
    5346             :     case eCursor_nesw_resize:
    5347           0 :         gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "size_bdiag");
    5348           0 :         if (!gdkcursor)
    5349           0 :             newType = MOZ_CURSOR_NESW_RESIZE;
    5350           0 :         break;
    5351             :     case eCursor_nwse_resize:
    5352           0 :         gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "size_fdiag");
    5353           0 :         if (!gdkcursor)
    5354           0 :             newType = MOZ_CURSOR_NWSE_RESIZE;
    5355           0 :         break;
    5356             :     case eCursor_ns_resize:
    5357             :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay,
    5358           0 :                                                GDK_SB_V_DOUBLE_ARROW);
    5359           0 :         break;
    5360             :     case eCursor_ew_resize:
    5361             :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay,
    5362           0 :                                                GDK_SB_H_DOUBLE_ARROW);
    5363           0 :         break;
    5364             :     // Here, two better fitting cursors exist in some cursor themes. Try those first
    5365             :     case eCursor_row_resize:
    5366           0 :         gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "split_v");
    5367           0 :         if (!gdkcursor)
    5368             :             gdkcursor = gdk_cursor_new_for_display(defaultDisplay,
    5369           0 :                                                    GDK_SB_V_DOUBLE_ARROW);
    5370           0 :         break;
    5371             :     case eCursor_col_resize:
    5372           0 :         gdkcursor = gdk_cursor_new_from_name(defaultDisplay, "split_h");
    5373           0 :         if (!gdkcursor)
    5374             :             gdkcursor = gdk_cursor_new_for_display(defaultDisplay,
    5375           0 :                                                    GDK_SB_H_DOUBLE_ARROW);
    5376           0 :         break;
    5377             :     case eCursor_none:
    5378           0 :         newType = MOZ_CURSOR_NONE;
    5379           0 :         break;
    5380             :     default:
    5381           0 :         NS_ASSERTION(aCursor, "Invalid cursor type");
    5382           0 :         gdkcursor = gdk_cursor_new_for_display(defaultDisplay, GDK_LEFT_PTR);
    5383           0 :         break;
    5384             :     }
    5385             : 
    5386             :     // If by now we don't have a xcursor, this means we have to make a custom
    5387             :     // one. First, we try creating a named cursor based on the hash of our
    5388             :     // custom bitmap, as libXcursor has some magic to convert bitmapped cursors
    5389             :     // to themed cursors
    5390           0 :     if (newType != 0xFF && GtkCursors[newType].hash) {
    5391           0 :         gdkcursor = gdk_cursor_new_from_name(defaultDisplay, GtkCursors[newType].hash);
    5392             :     }
    5393             : 
    5394             :     // If we still don't have a xcursor, we now really create a bitmap cursor
    5395           0 :     if (newType != 0xff && !gdkcursor) {
    5396           0 :         GdkPixbuf * cursor_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 32, 32);
    5397           0 :         if (!cursor_pixbuf)
    5398           0 :             return nullptr;
    5399             : 
    5400           0 :         guchar *data = gdk_pixbuf_get_pixels(cursor_pixbuf);
    5401             : 
    5402             :         // Read data from GtkCursors and compose RGBA surface from 1bit bitmap and mask
    5403             :         // GtkCursors bits and mask are 32x32 monochrome bitmaps (1 bit for each pixel)
    5404             :         // so it's 128 byte array (4 bytes for are one bitmap row and there are 32 rows here).
    5405           0 :         const unsigned char *bits = GtkCursors[newType].bits;
    5406           0 :         const unsigned char *mask_bits = GtkCursors[newType].mask_bits;
    5407             : 
    5408           0 :         for (int i = 0; i < 128; i++) {
    5409           0 :             char bit = *bits++;
    5410           0 :             char mask = *mask_bits++;
    5411           0 :             for (int j = 0; j < 8; j++) {
    5412           0 :                 unsigned char pix = ~(((bit >> j) & 0x01) * 0xff);
    5413           0 :                 *data++ = pix;
    5414           0 :                 *data++ = pix;
    5415           0 :                 *data++ = pix;
    5416           0 :                 *data++ = (((mask >> j) & 0x01) * 0xff);
    5417             :             }
    5418             :         }
    5419             : 
    5420           0 :         gdkcursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(), cursor_pixbuf,
    5421           0 :                                                GtkCursors[newType].hot_x,
    5422           0 :                                                GtkCursors[newType].hot_y);
    5423             : 
    5424           0 :         g_object_unref(cursor_pixbuf);
    5425             :     }
    5426             : 
    5427           0 :     gCursorCache[aCursor] = gdkcursor;
    5428             : 
    5429           0 :     return gdkcursor;
    5430             : }
    5431             : 
    5432             : // gtk callbacks
    5433             : 
    5434             : #if (MOZ_WIDGET_GTK == 2)
    5435             : static gboolean
    5436             : expose_event_cb(GtkWidget *widget, GdkEventExpose *event)
    5437             : {
    5438             :     RefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
    5439             :     if (!window)
    5440             :         return FALSE;
    5441             : 
    5442             :     window->OnExposeEvent(event);
    5443             :     return FALSE;
    5444             : }
    5445             : #else
    5446             : void
    5447           1 : draw_window_of_widget(GtkWidget *widget, GdkWindow *aWindow, cairo_t *cr)
    5448             : {
    5449           1 :     if (gtk_cairo_should_draw_window(cr, aWindow)) {
    5450           2 :         RefPtr<nsWindow> window = get_window_for_gdk_window(aWindow);
    5451           1 :         if (!window) {
    5452           0 :             NS_WARNING("Cannot get nsWindow from GtkWidget");
    5453             :         }
    5454             :         else {
    5455           1 :             cairo_save(cr);
    5456           1 :             gtk_cairo_transform_to_window(cr, widget, aWindow);
    5457             :             // TODO - window->OnExposeEvent() can destroy this or other windows,
    5458             :             // do we need to handle it somehow?
    5459           1 :             window->OnExposeEvent(cr);
    5460           1 :             cairo_restore(cr);
    5461             :         }
    5462             :     }
    5463             : 
    5464           1 :     GList *children = gdk_window_get_children(aWindow);
    5465           1 :     GList *child = children;
    5466           1 :     while (child) {
    5467           0 :         GdkWindow *window = GDK_WINDOW(child->data);
    5468             :         gpointer windowWidget;
    5469           0 :         gdk_window_get_user_data(window, &windowWidget);
    5470           0 :         if (windowWidget == widget) {
    5471           0 :             draw_window_of_widget(widget, window, cr);
    5472             :         }
    5473           0 :         child = g_list_next(child);
    5474             :     }
    5475           1 :     g_list_free(children);
    5476           1 : }
    5477             : 
    5478             : /* static */
    5479             : gboolean
    5480           1 : expose_event_cb(GtkWidget *widget, cairo_t *cr)
    5481             : {
    5482           1 :     draw_window_of_widget(widget, gtk_widget_get_window(widget), cr);
    5483             : 
    5484             :     // A strong reference is already held during "draw" signal emission,
    5485             :     // but GTK+ 3.4 wants the object to live a little longer than that
    5486             :     // (bug 1225970).
    5487           1 :     g_object_ref(widget);
    5488           2 :     g_idle_add(
    5489           3 :         [](gpointer data) -> gboolean {
    5490           1 :             g_object_unref(data);
    5491           1 :             return G_SOURCE_REMOVE;
    5492           2 :         },
    5493           1 :         widget);
    5494             : 
    5495           1 :     return FALSE;
    5496             : }
    5497             : #endif //MOZ_WIDGET_GTK == 2
    5498             : 
    5499             : static gboolean
    5500           5 : configure_event_cb(GtkWidget *widget,
    5501             :                    GdkEventConfigure *event)
    5502             : {
    5503          10 :     RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
    5504           5 :     if (!window)
    5505           0 :         return FALSE;
    5506             : 
    5507           5 :     return window->OnConfigureEvent(widget, event);
    5508             : }
    5509             : 
    5510             : static void
    5511           0 : container_unrealize_cb (GtkWidget *widget)
    5512             : {
    5513           0 :     RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
    5514           0 :     if (!window)
    5515           0 :         return;
    5516             : 
    5517           0 :     window->OnContainerUnrealize();
    5518             : }
    5519             : 
    5520             : static void
    5521           1 : size_allocate_cb (GtkWidget *widget, GtkAllocation *allocation)
    5522             : {
    5523           2 :     RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
    5524           1 :     if (!window)
    5525           0 :         return;
    5526             : 
    5527           1 :     window->OnSizeAllocate(allocation);
    5528             : }
    5529             : 
    5530             : static gboolean
    5531           0 : delete_event_cb(GtkWidget *widget, GdkEventAny *event)
    5532             : {
    5533           0 :     RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
    5534           0 :     if (!window)
    5535           0 :         return FALSE;
    5536             : 
    5537           0 :     window->OnDeleteEvent();
    5538             : 
    5539           0 :     return TRUE;
    5540             : }
    5541             : 
    5542             : static gboolean
    5543           1 : enter_notify_event_cb(GtkWidget *widget,
    5544             :                       GdkEventCrossing *event)
    5545             : {
    5546           2 :     RefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
    5547           1 :     if (!window)
    5548           0 :         return TRUE;
    5549             : 
    5550           1 :     window->OnEnterNotifyEvent(event);
    5551             : 
    5552           1 :     return TRUE;
    5553             : }
    5554             : 
    5555             : static gboolean
    5556           1 : leave_notify_event_cb(GtkWidget *widget,
    5557             :                       GdkEventCrossing *event)
    5558             : {
    5559           1 :     if (is_parent_grab_leave(event)) {
    5560           0 :         return TRUE;
    5561             :     }
    5562             : 
    5563             :     // bug 369599: Suppress LeaveNotify events caused by pointer grabs to
    5564             :     // avoid generating spurious mouse exit events.
    5565           1 :     auto x = gint(event->x_root);
    5566           1 :     auto y = gint(event->y_root);
    5567           1 :     GdkDisplay* display = gtk_widget_get_display(widget);
    5568           1 :     GdkWindow* winAtPt = gdk_display_get_window_at_pointer(display, &x, &y);
    5569           1 :     if (winAtPt == event->window) {
    5570           0 :         return TRUE;
    5571             :     }
    5572             : 
    5573           2 :     RefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
    5574           1 :     if (!window)
    5575           0 :         return TRUE;
    5576             : 
    5577           1 :     window->OnLeaveNotifyEvent(event);
    5578             : 
    5579           1 :     return TRUE;
    5580             : }
    5581             : 
    5582             : static nsWindow*
    5583           4 : GetFirstNSWindowForGDKWindow(GdkWindow *aGdkWindow)
    5584             : {
    5585             :     nsWindow* window;
    5586           4 :     while (!(window = get_window_for_gdk_window(aGdkWindow))) {
    5587             :         // The event has bubbled to the moz_container widget as passed into each caller's *widget parameter,
    5588             :         // but its corresponding nsWindow is an ancestor of the window that we need.  Instead, look at
    5589             :         // event->window and find the first ancestor nsWindow of it because event->window may be in a plugin.
    5590           0 :         aGdkWindow = gdk_window_get_parent(aGdkWindow);
    5591           0 :         if (!aGdkWindow) {
    5592           0 :             window = nullptr;
    5593           0 :             break;
    5594             :         }
    5595             :     }
    5596           4 :     return window;
    5597             : }
    5598             : 
    5599             : static gboolean
    5600           4 : motion_notify_event_cb(GtkWidget *widget, GdkEventMotion *event)
    5601             : {
    5602           4 :     UpdateLastInputEventTime(event);
    5603             : 
    5604           4 :     nsWindow *window = GetFirstNSWindowForGDKWindow(event->window);
    5605           4 :     if (!window)
    5606           0 :         return FALSE;
    5607             : 
    5608           4 :     window->OnMotionNotifyEvent(event);
    5609             : 
    5610           4 :     return TRUE;
    5611             : }
    5612             : 
    5613             : static gboolean
    5614           0 : button_press_event_cb(GtkWidget *widget, GdkEventButton *event)
    5615             : {
    5616           0 :     UpdateLastInputEventTime(event);
    5617             : 
    5618           0 :     nsWindow *window = GetFirstNSWindowForGDKWindow(event->window);
    5619           0 :     if (!window)
    5620           0 :         return FALSE;
    5621             : 
    5622           0 :     window->OnButtonPressEvent(event);
    5623             : 
    5624           0 :     return TRUE;
    5625             : }
    5626             : 
    5627             : static gboolean
    5628           0 : button_release_event_cb(GtkWidget *widget, GdkEventButton *event)
    5629             : {
    5630           0 :     UpdateLastInputEventTime(event);
    5631             : 
    5632           0 :     nsWindow *window = GetFirstNSWindowForGDKWindow(event->window);
    5633           0 :     if (!window)
    5634           0 :         return FALSE;
    5635             : 
    5636           0 :     window->OnButtonReleaseEvent(event);
    5637             : 
    5638           0 :     return TRUE;
    5639             : }
    5640             : 
    5641             : static gboolean
    5642           1 : focus_in_event_cb(GtkWidget *widget, GdkEventFocus *event)
    5643             : {
    5644           2 :     RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
    5645           1 :     if (!window)
    5646           0 :         return FALSE;
    5647             : 
    5648           1 :     window->OnContainerFocusInEvent(event);
    5649             : 
    5650           1 :     return FALSE;
    5651             : }
    5652             : 
    5653             : static gboolean
    5654           0 : focus_out_event_cb(GtkWidget *widget, GdkEventFocus *event)
    5655             : {
    5656           0 :     RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
    5657           0 :     if (!window)
    5658           0 :         return FALSE;
    5659             : 
    5660           0 :     window->OnContainerFocusOutEvent(event);
    5661             : 
    5662           0 :     return FALSE;
    5663             : }
    5664             : 
    5665             : #ifdef MOZ_X11
    5666             : // For long-lived popup windows that don't really take focus themselves but
    5667             : // may have elements that accept keyboard input when the parent window is
    5668             : // active, focus is handled specially.  These windows include noautohide
    5669             : // panels.  (This special handling is not necessary for temporary popups where
    5670             : // the keyboard is grabbed.)
    5671             : //
    5672             : // Mousing over or clicking on these windows should not cause them to steal
    5673             : // focus from their parent windows, so, the input field of WM_HINTS is set to
    5674             : // False to request that the window manager not set the input focus to this
    5675             : // window.  http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.7
    5676             : //
    5677             : // However, these windows can still receive WM_TAKE_FOCUS messages from the
    5678             : // window manager, so they can still detect when the user has indicated that
    5679             : // they wish to direct keyboard input at these windows.  When the window
    5680             : // manager offers focus to these windows (after a mouse over or click, for
    5681             : // example), a request to make the parent window active is issued.  When the
    5682             : // parent window becomes active, keyboard events will be received.
    5683             : 
    5684             : static GdkFilterReturn
    5685           0 : popup_take_focus_filter(GdkXEvent *gdk_xevent,
    5686             :                         GdkEvent *event,
    5687             :                         gpointer data)
    5688             : {
    5689           0 :     auto* xevent = static_cast<XEvent*>(gdk_xevent);
    5690           0 :     if (xevent->type != ClientMessage)
    5691           0 :         return GDK_FILTER_CONTINUE;
    5692             : 
    5693           0 :     XClientMessageEvent& xclient = xevent->xclient;
    5694           0 :     if (xclient.message_type != gdk_x11_get_xatom_by_name("WM_PROTOCOLS"))
    5695           0 :         return GDK_FILTER_CONTINUE;
    5696             : 
    5697           0 :     Atom atom = xclient.data.l[0];
    5698           0 :     if (atom != gdk_x11_get_xatom_by_name("WM_TAKE_FOCUS"))
    5699           0 :         return GDK_FILTER_CONTINUE;
    5700             : 
    5701           0 :     guint32 timestamp = xclient.data.l[1];
    5702             : 
    5703           0 :     GtkWidget* widget = get_gtk_widget_for_gdk_window(event->any.window);
    5704           0 :     if (!widget)
    5705           0 :         return GDK_FILTER_CONTINUE;
    5706             : 
    5707           0 :     GtkWindow* parent = gtk_window_get_transient_for(GTK_WINDOW(widget));
    5708           0 :     if (!parent)
    5709           0 :         return GDK_FILTER_CONTINUE;
    5710             : 
    5711           0 :     if (gtk_window_is_active(parent))
    5712           0 :         return GDK_FILTER_REMOVE; // leave input focus on the parent
    5713             : 
    5714           0 :     GdkWindow* parent_window = gtk_widget_get_window(GTK_WIDGET(parent));
    5715           0 :     if (!parent_window)
    5716           0 :         return GDK_FILTER_CONTINUE;
    5717             : 
    5718             :     // In case the parent has not been deconified.
    5719           0 :     gdk_window_show_unraised(parent_window);
    5720             : 
    5721             :     // Request focus on the parent window.
    5722             :     // Use gdk_window_focus rather than gtk_window_present to avoid
    5723             :     // raising the parent window.
    5724           0 :     gdk_window_focus(parent_window, timestamp);
    5725           0 :     return GDK_FILTER_REMOVE;
    5726             : }
    5727             : #endif /* MOZ_X11 */
    5728             : 
    5729             : static gboolean
    5730           0 : key_press_event_cb(GtkWidget *widget, GdkEventKey *event)
    5731             : {
    5732           0 :     LOG(("key_press_event_cb\n"));
    5733             : 
    5734           0 :     UpdateLastInputEventTime(event);
    5735             : 
    5736             :     // find the window with focus and dispatch this event to that widget
    5737           0 :     nsWindow *window = get_window_for_gtk_widget(widget);
    5738           0 :     if (!window)
    5739           0 :         return FALSE;
    5740             : 
    5741           0 :     RefPtr<nsWindow> focusWindow = gFocusWindow ? gFocusWindow : window;
    5742             : 
    5743             : #ifdef MOZ_X11
    5744             :     // Keyboard repeat can cause key press events to queue up when there are
    5745             :     // slow event handlers (bug 301029).  Throttle these events by removing
    5746             :     // consecutive pending duplicate KeyPress events to the same window.
    5747             :     // We use the event time of the last one.
    5748             :     // Note: GDK calls XkbSetDetectableAutorepeat so that KeyRelease events
    5749             :     // are generated only when the key is physically released.
    5750             : #define NS_GDKEVENT_MATCH_MASK 0x1FFF /* GDK_SHIFT_MASK .. GDK_BUTTON5_MASK */
    5751           0 :     GdkDisplay* gdkDisplay = gtk_widget_get_display(widget);
    5752           0 :     if (GDK_IS_X11_DISPLAY(gdkDisplay)) {
    5753           0 :         Display* dpy = GDK_DISPLAY_XDISPLAY(gdkDisplay);
    5754           0 :         while (XPending(dpy)) {
    5755             :             XEvent next_event;
    5756           0 :             XPeekEvent(dpy, &next_event);
    5757             :             GdkWindow* nextGdkWindow =
    5758           0 :                 gdk_x11_window_lookup_for_display(gdkDisplay, next_event.xany.window);
    5759           0 :             if (nextGdkWindow != event->window ||
    5760           0 :                 next_event.type != KeyPress ||
    5761           0 :                 next_event.xkey.keycode != event->hardware_keycode ||
    5762           0 :                 next_event.xkey.state != (event->state & NS_GDKEVENT_MATCH_MASK)) {
    5763             :                 break;
    5764             :             }
    5765           0 :             XNextEvent(dpy, &next_event);
    5766           0 :             event->time = next_event.xkey.time;
    5767             :         }
    5768             :     }
    5769             : #endif
    5770             : 
    5771           0 :     return focusWindow->OnKeyPressEvent(event);
    5772             : }
    5773             : 
    5774             : static gboolean
    5775           0 : key_release_event_cb(GtkWidget *widget, GdkEventKey *event)
    5776             : {
    5777           0 :     LOG(("key_release_event_cb\n"));
    5778             : 
    5779           0 :     UpdateLastInputEventTime(event);
    5780             : 
    5781             :     // find the window with focus and dispatch this event to that widget
    5782           0 :     nsWindow *window = get_window_for_gtk_widget(widget);
    5783           0 :     if (!window)
    5784           0 :         return FALSE;
    5785             : 
    5786           0 :     RefPtr<nsWindow> focusWindow = gFocusWindow ? gFocusWindow : window;
    5787             : 
    5788           0 :     return focusWindow->OnKeyReleaseEvent(event);
    5789             : }
    5790             : 
    5791             : static gboolean
    5792          77 : property_notify_event_cb(GtkWidget* aWidget, GdkEventProperty* aEvent)
    5793             : {
    5794         154 :     RefPtr<nsWindow> window = get_window_for_gdk_window(aEvent->window);
    5795          77 :     if (!window)
    5796           0 :         return FALSE;
    5797             : 
    5798          77 :     return window->OnPropertyNotifyEvent(aWidget, aEvent);
    5799             : }
    5800             : 
    5801             : static gboolean
    5802           0 : scroll_event_cb(GtkWidget *widget, GdkEventScroll *event)
    5803             : {
    5804           0 :     nsWindow *window = GetFirstNSWindowForGDKWindow(event->window);
    5805           0 :     if (!window)
    5806           0 :         return FALSE;
    5807             : 
    5808           0 :     window->OnScrollEvent(event);
    5809             : 
    5810           0 :     return TRUE;
    5811             : }
    5812             : 
    5813             : static gboolean
    5814           2 : visibility_notify_event_cb (GtkWidget *widget, GdkEventVisibility *event)
    5815             : {
    5816           4 :     RefPtr<nsWindow> window = get_window_for_gdk_window(event->window);
    5817           2 :     if (!window)
    5818           0 :         return FALSE;
    5819             : 
    5820           2 :     window->OnVisibilityNotifyEvent(event);
    5821             : 
    5822           2 :     return TRUE;
    5823             : }
    5824             : 
    5825             : static void
    5826           2 : hierarchy_changed_cb (GtkWidget *widget,
    5827             :                       GtkWidget *previous_toplevel)
    5828             : {
    5829           2 :     GtkWidget *toplevel = gtk_widget_get_toplevel(widget);
    5830           2 :     GdkWindowState old_window_state = GDK_WINDOW_STATE_WITHDRAWN;
    5831             :     GdkEventWindowState event;
    5832             : 
    5833           2 :     event.new_window_state = GDK_WINDOW_STATE_WITHDRAWN;
    5834             : 
    5835           2 :     if (GTK_IS_WINDOW(previous_toplevel)) {
    5836           0 :         g_signal_handlers_disconnect_by_func(previous_toplevel,
    5837             :                                              FuncToGpointer(window_state_event_cb),
    5838           0 :                                              widget);
    5839           0 :         GdkWindow *win = gtk_widget_get_window(previous_toplevel);
    5840           0 :         if (win) {
    5841           0 :             old_window_state = gdk_window_get_state(win);
    5842             :         }
    5843             :     }
    5844             : 
    5845           2 :     if (GTK_IS_WINDOW(toplevel)) {
    5846             :         g_signal_connect_swapped(toplevel, "window-state-event",
    5847           2 :                                  G_CALLBACK(window_state_event_cb), widget);
    5848           2 :         GdkWindow *win = gtk_widget_get_window(toplevel);
    5849           2 :         if (win) {
    5850           2 :             event.new_window_state = gdk_window_get_state(win);
    5851             :         }
    5852             :     }
    5853             : 
    5854           2 :     event.changed_mask = static_cast<GdkWindowState>
    5855           2 :         (old_window_state ^ event.new_window_state);
    5856             : 
    5857           2 :     if (event.changed_mask) {
    5858           0 :         event.type = GDK_WINDOW_STATE;
    5859           0 :         event.window = nullptr;
    5860           0 :         event.send_event = TRUE;
    5861           0 :         window_state_event_cb(widget, &event);
    5862             :     }
    5863           2 : }
    5864             : 
    5865             : static gboolean
    5866           2 : window_state_event_cb (GtkWidget *widget, GdkEventWindowState *event)
    5867             : {
    5868           4 :     RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
    5869           2 :     if (!window)
    5870           0 :         return FALSE;
    5871             : 
    5872           2 :     window->OnWindowStateEvent(widget, event);
    5873             : 
    5874           2 :     return FALSE;
    5875             : }
    5876             : 
    5877             : static void
    5878           0 : theme_changed_cb (GtkSettings *settings, GParamSpec *pspec, nsWindow *data)
    5879             : {
    5880           0 :     RefPtr<nsWindow> window = data;
    5881           0 :     window->ThemeChanged();
    5882           0 : }
    5883             : 
    5884             : static void
    5885          17 : check_resize_cb (GtkContainer* container, gpointer user_data)
    5886             : {
    5887          34 :     RefPtr<nsWindow> window = get_window_for_gtk_widget(GTK_WIDGET(container));
    5888          17 :     if (!window) {
    5889           0 :       return;
    5890             :     }
    5891          17 :     window->OnCheckResize();
    5892             : }
    5893             : 
    5894             : static void
    5895           0 : composited_changed_cb (GtkWidget* widget, gpointer user_data)
    5896             : {
    5897           0 :     RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
    5898           0 :     if (!window) {
    5899           0 :       return;
    5900             :     }
    5901           0 :     window->OnCompositedChanged();
    5902             : }
    5903             : 
    5904             : #if (MOZ_WIDGET_GTK == 3)
    5905             : static void
    5906           0 : scale_changed_cb (GtkWidget* widget, GParamSpec* aPSpec, gpointer aPointer)
    5907             : {
    5908           0 :     RefPtr<nsWindow> window = get_window_for_gtk_widget(widget);
    5909           0 :     if (!window) {
    5910           0 :       return;
    5911             :     }
    5912           0 :     window->OnDPIChanged();
    5913             : 
    5914             :     // configure_event is already fired before scale-factor signal,
    5915             :     // but size-allocate isn't fired by changing scale
    5916             :     GtkAllocation allocation;
    5917           0 :     gtk_widget_get_allocation(widget, &allocation);
    5918           0 :     window->OnSizeAllocate(&allocation);
    5919             : }
    5920             : #endif
    5921             : 
    5922             : #if GTK_CHECK_VERSION(3,4,0)
    5923             : static gboolean
    5924           0 : touch_event_cb(GtkWidget* aWidget, GdkEventTouch* aEvent)
    5925             : {
    5926           0 :     UpdateLastInputEventTime(aEvent);
    5927             : 
    5928           0 :     nsWindow* window = GetFirstNSWindowForGDKWindow(aEvent->window);
    5929           0 :     if (!window) {
    5930           0 :         return FALSE;
    5931             :     }
    5932             : 
    5933           0 :     return window->OnTouchEvent(aEvent);
    5934             : }
    5935             : #endif
    5936             : 
    5937             : //////////////////////////////////////////////////////////////////////
    5938             : // These are all of our drag and drop operations
    5939             : 
    5940             : void
    5941           0 : nsWindow::InitDragEvent(WidgetDragEvent &aEvent)
    5942             : {
    5943             :     // set the keyboard modifiers
    5944           0 :     guint modifierState = KeymapWrapper::GetCurrentModifierState();
    5945           0 :     KeymapWrapper::InitInputEvent(aEvent, modifierState);
    5946           0 : }
    5947             : 
    5948             : static gboolean
    5949           0 : drag_motion_event_cb(GtkWidget *aWidget,
    5950             :                      GdkDragContext *aDragContext,
    5951             :                      gint aX,
    5952             :                      gint aY,
    5953             :                      guint aTime,
    5954             :                      gpointer aData)
    5955             : {
    5956           0 :     RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
    5957           0 :     if (!window)
    5958           0 :         return FALSE;
    5959             : 
    5960             :     // figure out which internal widget this drag motion actually happened on
    5961           0 :     nscoord retx = 0;
    5962           0 :     nscoord rety = 0;
    5963             : 
    5964             :     GdkWindow *innerWindow =
    5965           0 :         get_inner_gdk_window(gtk_widget_get_window(aWidget), aX, aY,
    5966           0 :                              &retx, &rety);
    5967           0 :     RefPtr<nsWindow> innerMostWindow = get_window_for_gdk_window(innerWindow);
    5968             : 
    5969           0 :     if (!innerMostWindow) {
    5970           0 :         innerMostWindow = window;
    5971             :     }
    5972             : 
    5973           0 :     LOGDRAG(("nsWindow drag-motion signal for %p\n", (void*)innerMostWindow));
    5974             : 
    5975           0 :     LayoutDeviceIntPoint point = window->GdkPointToDevicePixels({ retx, rety });
    5976             : 
    5977           0 :     RefPtr<nsDragService> dragService = nsDragService::GetInstance();
    5978             :     return dragService->
    5979           0 :         ScheduleMotionEvent(innerMostWindow, aDragContext,
    5980           0 :                             point, aTime);
    5981             : }
    5982             : 
    5983             : static void
    5984           0 : drag_leave_event_cb(GtkWidget *aWidget,
    5985             :                     GdkDragContext *aDragContext,
    5986             :                     guint aTime,
    5987             :                     gpointer aData)
    5988             : {
    5989           0 :     RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
    5990           0 :     if (!window)
    5991           0 :         return;
    5992             : 
    5993           0 :     RefPtr<nsDragService> dragService = nsDragService::GetInstance();
    5994             : 
    5995           0 :     nsWindow *mostRecentDragWindow = dragService->GetMostRecentDestWindow();
    5996           0 :     if (!mostRecentDragWindow) {
    5997             :         // This can happen when the target will not accept a drop.  A GTK drag
    5998             :         // source sends the leave message to the destination before the
    5999             :         // drag-failed signal on the source widget, but the leave message goes
    6000             :         // via the X server, and so doesn't get processed at least until the
    6001             :         // event loop runs again.
    6002           0 :         return;
    6003             :     }
    6004             : 
    6005           0 :     GtkWidget *mozContainer = mostRecentDragWindow->GetMozContainerWidget();
    6006           0 :     if (aWidget != mozContainer)
    6007             :     {
    6008             :         // When the drag moves between widgets, GTK can send leave signal for
    6009             :         // the old widget after the motion or drop signal for the new widget.
    6010             :         // We'll send the leave event when the motion or drop event is run.
    6011           0 :         return;
    6012             :     }
    6013             : 
    6014           0 :     LOGDRAG(("nsWindow drag-leave signal for %p\n",
    6015             :              (void*)mostRecentDragWindow));
    6016             : 
    6017           0 :     dragService->ScheduleLeaveEvent();
    6018             : }
    6019             : 
    6020             : 
    6021             : static gboolean
    6022           0 : drag_drop_event_cb(GtkWidget *aWidget,
    6023             :                    GdkDragContext *aDragContext,
    6024             :                    gint aX,
    6025             :                    gint aY,
    6026             :                    guint aTime,
    6027             :                    gpointer aData)
    6028             : {
    6029           0 :     RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
    6030           0 :     if (!window)
    6031           0 :         return FALSE;
    6032             : 
    6033             :     // figure out which internal widget this drag motion actually happened on
    6034           0 :     nscoord retx = 0;
    6035           0 :     nscoord rety = 0;
    6036             : 
    6037             :     GdkWindow *innerWindow =
    6038           0 :         get_inner_gdk_window(gtk_widget_get_window(aWidget), aX, aY,
    6039           0 :                              &retx, &rety);
    6040           0 :     RefPtr<nsWindow> innerMostWindow = get_window_for_gdk_window(innerWindow);
    6041             : 
    6042           0 :     if (!innerMostWindow) {
    6043           0 :         innerMostWindow = window;
    6044             :     }
    6045             : 
    6046           0 :     LOGDRAG(("nsWindow drag-drop signal for %p\n", (void*)innerMostWindow));
    6047             : 
    6048           0 :     LayoutDeviceIntPoint point = window->GdkPointToDevicePixels({ retx, rety });
    6049             : 
    6050           0 :     RefPtr<nsDragService> dragService = nsDragService::GetInstance();
    6051             :     return dragService->
    6052           0 :         ScheduleDropEvent(innerMostWindow, aDragContext,
    6053           0 :                           point, aTime);
    6054             : }
    6055             : 
    6056             : static void
    6057           0 : drag_data_received_event_cb(GtkWidget *aWidget,
    6058             :                             GdkDragContext *aDragContext,
    6059             :                             gint aX,
    6060             :                             gint aY,
    6061             :                             GtkSelectionData  *aSelectionData,
    6062             :                             guint aInfo,
    6063             :                             guint aTime,
    6064             :                             gpointer aData)
    6065             : {
    6066           0 :     RefPtr<nsWindow> window = get_window_for_gtk_widget(aWidget);
    6067           0 :     if (!window)
    6068           0 :         return;
    6069             : 
    6070           0 :     window->OnDragDataReceivedEvent(aWidget,
    6071             :                                     aDragContext,
    6072             :                                     aX, aY,
    6073             :                                     aSelectionData,
    6074           0 :                                     aInfo, aTime, aData);
    6075             : }
    6076             : 
    6077             : static nsresult
    6078           1 : initialize_prefs(void)
    6079             : {
    6080           1 :     gRaiseWindows =
    6081           1 :         Preferences::GetBool("mozilla.widget.raise-on-setfocus", true);
    6082             : 
    6083           1 :     return NS_OK;
    6084             : }
    6085             : 
    6086             : static GdkWindow *
    6087           0 : get_inner_gdk_window (GdkWindow *aWindow,
    6088             :                       gint x, gint y,
    6089             :                       gint *retx, gint *rety)
    6090             : {
    6091             :     gint cx, cy, cw, ch;
    6092           0 :     GList *children = gdk_window_peek_children(aWindow);
    6093           0 :     for (GList *child = g_list_last(children);
    6094           0 :          child;
    6095           0 :          child = g_list_previous(child)) {
    6096           0 :         auto *childWindow = (GdkWindow *) child->data;
    6097           0 :         if (get_window_for_gdk_window(childWindow)) {
    6098             : #if (MOZ_WIDGET_GTK == 2)
    6099             :             gdk_window_get_geometry(childWindow, &cx, &cy, &cw, &ch, nullptr);
    6100             : #else
    6101           0 :             gdk_window_get_geometry(childWindow, &cx, &cy, &cw, &ch);
    6102             : #endif
    6103           0 :             if ((cx < x) && (x < (cx + cw)) &&
    6104           0 :                 (cy < y) && (y < (cy + ch)) &&
    6105           0 :                 gdk_window_is_visible(childWindow)) {
    6106           0 :                 return get_inner_gdk_window(childWindow,
    6107             :                                             x - cx, y - cy,
    6108           0 :                                             retx, rety);
    6109             :             }
    6110             :         }
    6111             :     }
    6112           0 :     *retx = x;
    6113           0 :     *rety = y;
    6114           0 :     return aWindow;
    6115             : }
    6116             : 
    6117             : static int
    6118           1 : is_parent_ungrab_enter(GdkEventCrossing *aEvent)
    6119             : {
    6120           1 :     return (GDK_CROSSING_UNGRAB == aEvent->mode) &&
    6121           0 :         ((GDK_NOTIFY_ANCESTOR == aEvent->detail) ||
    6122           1 :          (GDK_NOTIFY_VIRTUAL == aEvent->detail));
    6123             : 
    6124             : }
    6125             : 
    6126             : static int
    6127           1 : is_parent_grab_leave(GdkEventCrossing *aEvent)
    6128             : {
    6129           1 :     return (GDK_CROSSING_GRAB == aEvent->mode) &&
    6130           0 :         ((GDK_NOTIFY_ANCESTOR == aEvent->detail) ||
    6131           1 :             (GDK_NOTIFY_VIRTUAL == aEvent->detail));
    6132             : }
    6133             : 
    6134             : #ifdef ACCESSIBILITY
    6135             : void
    6136           0 : nsWindow::CreateRootAccessible()
    6137             : {
    6138           0 :     if (mIsTopLevel && !mRootAccessible) {
    6139           0 :         LOG(("nsWindow:: Create Toplevel Accessibility\n"));
    6140           0 :         mRootAccessible = GetRootAccessible();
    6141             :     }
    6142           0 : }
    6143             : 
    6144             : void
    6145           2 : nsWindow::DispatchEventToRootAccessible(uint32_t aEventType)
    6146             : {
    6147           2 :     if (!a11y::ShouldA11yBeEnabled()) {
    6148           2 :         return;
    6149             :     }
    6150             : 
    6151           0 :     nsAccessibilityService* accService = GetOrCreateAccService();
    6152           0 :     if (!accService) {
    6153           0 :         return;
    6154             :     }
    6155             : 
    6156             :     // Get the root document accessible and fire event to it.
    6157           0 :     a11y::Accessible* acc = GetRootAccessible();
    6158           0 :     if (acc) {
    6159           0 :         accService->FireAccessibleEvent(aEventType, acc);
    6160             :     }
    6161             : }
    6162             : 
    6163             : void
    6164           1 : nsWindow::DispatchActivateEventAccessible(void)
    6165             : {
    6166           1 :     DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_ACTIVATE);
    6167           1 : }
    6168             : 
    6169             : void
    6170           0 : nsWindow::DispatchDeactivateEventAccessible(void)
    6171             : {
    6172           0 :     DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_DEACTIVATE);
    6173           0 : }
    6174             : 
    6175             : void
    6176           1 : nsWindow::DispatchMaximizeEventAccessible(void)
    6177             : {
    6178           1 :     DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_MAXIMIZE);
    6179           1 : }
    6180             : 
    6181             : void
    6182           0 : nsWindow::DispatchMinimizeEventAccessible(void)
    6183             : {
    6184           0 :     DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_MINIMIZE);
    6185           0 : }
    6186             : 
    6187             : void
    6188           0 : nsWindow::DispatchRestoreEventAccessible(void)
    6189             : {
    6190           0 :     DispatchEventToRootAccessible(nsIAccessibleEvent::EVENT_WINDOW_RESTORE);
    6191           0 : }
    6192             : 
    6193             : #endif /* #ifdef ACCESSIBILITY */
    6194             : 
    6195             : void
    6196           4 : nsWindow::SetInputContext(const InputContext& aContext,
    6197             :                           const InputContextAction& aAction)
    6198             : {
    6199           4 :     if (!mIMContext) {
    6200           0 :         return;
    6201             :     }
    6202           4 :     mIMContext->SetInputContext(this, &aContext, &aAction);
    6203             : }
    6204             : 
    6205             : InputContext
    6206           1 : nsWindow::GetInputContext()
    6207             : {
    6208           1 :   InputContext context;
    6209           1 :   if (!mIMContext) {
    6210           0 :       context.mIMEState.mEnabled = IMEState::DISABLED;
    6211           0 :       context.mIMEState.mOpen = IMEState::OPEN_STATE_NOT_SUPPORTED;
    6212             :   } else {
    6213           1 :       context = mIMContext->GetInputContext();
    6214             :   }
    6215           1 :   return context;
    6216             : }
    6217             : 
    6218             : TextEventDispatcherListener*
    6219           0 : nsWindow::GetNativeTextEventDispatcherListener()
    6220             : {
    6221           0 :     if (NS_WARN_IF(!mIMContext)) {
    6222           0 :         return nullptr;
    6223             :     }
    6224           0 :     return mIMContext;
    6225             : }
    6226             : 
    6227             : void
    6228           0 : nsWindow::GetEditCommandsRemapped(NativeKeyBindingsType aType,
    6229             :                                   const WidgetKeyboardEvent& aEvent,
    6230             :                                   nsTArray<CommandInt>& aCommands,
    6231             :                                   uint32_t aGeckoKeyCode,
    6232             :                                   uint32_t aNativeKeyCode)
    6233             : {
    6234           0 :     WidgetKeyboardEvent modifiedEvent(aEvent);
    6235           0 :     modifiedEvent.mKeyCode = aGeckoKeyCode;
    6236           0 :     static_cast<GdkEventKey*>(modifiedEvent.mNativeKeyEvent)->keyval =
    6237             :         aNativeKeyCode;
    6238             : 
    6239           0 :     NativeKeyBindings* keyBindings = NativeKeyBindings::GetInstance(aType);
    6240           0 :     return keyBindings->GetEditCommands(modifiedEvent, aCommands);
    6241             : }
    6242             : 
    6243             : void
    6244           0 : nsWindow::GetEditCommands(NativeKeyBindingsType aType,
    6245             :                           const WidgetKeyboardEvent& aEvent,
    6246             :                           nsTArray<CommandInt>& aCommands)
    6247             : {
    6248             :     // Validate the arguments.
    6249           0 :     nsIWidget::GetEditCommands(aType, aEvent, aCommands);
    6250             : 
    6251           0 :     if (aEvent.mKeyCode >= NS_VK_LEFT && aEvent.mKeyCode <= NS_VK_DOWN) {
    6252             :         // Check if we're targeting content with vertical writing mode,
    6253             :         // and if so remap the arrow keys.
    6254             :         // XXX This may be expensive.
    6255           0 :         WidgetQueryContentEvent query(true, eQuerySelectedText, this);
    6256             :         nsEventStatus status;
    6257           0 :         DispatchEvent(&query, status);
    6258             : 
    6259           0 :         if (query.mSucceeded && query.mReply.mWritingMode.IsVertical()) {
    6260           0 :             uint32_t geckoCode = 0;
    6261           0 :             uint32_t gdkCode = 0;
    6262           0 :             switch (aEvent.mKeyCode) {
    6263             :             case NS_VK_LEFT:
    6264           0 :                 if (query.mReply.mWritingMode.IsVerticalLR()) {
    6265           0 :                     geckoCode = NS_VK_UP;
    6266           0 :                     gdkCode = GDK_Up;
    6267             :                 } else {
    6268           0 :                     geckoCode = NS_VK_DOWN;
    6269           0 :                     gdkCode = GDK_Down;
    6270             :                 }
    6271           0 :                 break;
    6272             : 
    6273             :             case NS_VK_RIGHT:
    6274           0 :                 if (query.mReply.mWritingMode.IsVerticalLR()) {
    6275           0 :                     geckoCode = NS_VK_DOWN;
    6276           0 :                     gdkCode = GDK_Down;
    6277             :                 } else {
    6278           0 :                     geckoCode = NS_VK_UP;
    6279           0 :                     gdkCode = GDK_Up;
    6280             :                 }
    6281           0 :                 break;
    6282             : 
    6283             :             case NS_VK_UP:
    6284           0 :                 geckoCode = NS_VK_LEFT;
    6285           0 :                 gdkCode = GDK_Left;
    6286           0 :                 break;
    6287             : 
    6288             :             case NS_VK_DOWN:
    6289           0 :                 geckoCode = NS_VK_RIGHT;
    6290           0 :                 gdkCode = GDK_Right;
    6291           0 :                 break;
    6292             :             }
    6293             : 
    6294           0 :             GetEditCommandsRemapped(aType, aEvent, aCommands,
    6295           0 :                                     geckoCode, gdkCode);
    6296           0 :             return;
    6297             :         }
    6298             :     }
    6299             : 
    6300           0 :     NativeKeyBindings* keyBindings = NativeKeyBindings::GetInstance(aType);
    6301           0 :     keyBindings->GetEditCommands(aEvent, aCommands);
    6302             : }
    6303             : 
    6304             : #if defined(MOZ_X11) && (MOZ_WIDGET_GTK == 2)
    6305             : /* static */ already_AddRefed<DrawTarget>
    6306             : nsWindow::GetDrawTargetForGdkDrawable(GdkDrawable* aDrawable,
    6307             :                                       const IntSize& aSize)
    6308             : {
    6309             :     GdkVisual* visual = gdk_drawable_get_visual(aDrawable);
    6310             :     Screen* xScreen =
    6311             :         gdk_x11_screen_get_xscreen(gdk_drawable_get_screen(aDrawable));
    6312             :     Display* xDisplay = DisplayOfScreen(xScreen);
    6313             :     Drawable xDrawable = gdk_x11_drawable_get_xid(aDrawable);
    6314             : 
    6315             :     RefPtr<gfxASurface> surface;
    6316             : 
    6317             :     if (visual) {
    6318             :         Visual* xVisual = gdk_x11_visual_get_xvisual(visual);
    6319             : 
    6320             :         surface = new gfxXlibSurface(xDisplay, xDrawable, xVisual, aSize);
    6321             :     } else {
    6322             :         // no visual? we must be using an xrender format.  Find a format
    6323             :         // for this depth.
    6324             :         XRenderPictFormat *pf = nullptr;
    6325             :         switch (gdk_drawable_get_depth(aDrawable)) {
    6326             :             case 32:
    6327             :                 pf = XRenderFindStandardFormat(xDisplay, PictStandardARGB32);
    6328             :                 break;
    6329             :             case 24:
    6330             :                 pf = XRenderFindStandardFormat(xDisplay, PictStandardRGB24);
    6331             :                 break;
    6332             :             default:
    6333             :                 NS_ERROR("Don't know how to handle the given depth!");
    6334             :                 break;
    6335             :         }
    6336             : 
    6337             :         surface = new gfxXlibSurface(xScreen, xDrawable, pf, aSize);
    6338             :     }
    6339             : 
    6340             :     RefPtr<DrawTarget> dt =
    6341             :         gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surface, aSize);
    6342             : 
    6343             :     if (!dt || !dt->IsValid()) {
    6344             :         return nullptr;
    6345             :     }
    6346             : 
    6347             :     return dt.forget();
    6348             : }
    6349             : #endif
    6350             : 
    6351             : already_AddRefed<DrawTarget>
    6352           0 : nsWindow::StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion, BufferMode* aBufferMode)
    6353             : {
    6354           0 :   return mSurfaceProvider.StartRemoteDrawingInRegion(aInvalidRegion, aBufferMode);
    6355             : }
    6356             : 
    6357             : void
    6358           0 : nsWindow::EndRemoteDrawingInRegion(DrawTarget* aDrawTarget,
    6359             :                                    LayoutDeviceIntRegion& aInvalidRegion)
    6360             : {
    6361           0 :   mSurfaceProvider.EndRemoteDrawingInRegion(aDrawTarget, aInvalidRegion);
    6362           0 : }
    6363             : 
    6364             : // Code shared begin BeginMoveDrag and BeginResizeDrag
    6365             : bool
    6366           0 : nsWindow::GetDragInfo(WidgetMouseEvent* aMouseEvent,
    6367             :                       GdkWindow** aWindow, gint* aButton,
    6368             :                       gint* aRootX, gint* aRootY)
    6369             : {
    6370           0 :     if (aMouseEvent->button != WidgetMouseEvent::eLeftButton) {
    6371             :         // we can only begin a move drag with the left mouse button
    6372           0 :         return false;
    6373             :     }
    6374           0 :     *aButton = 1;
    6375             : 
    6376             :     // get the gdk window for this widget
    6377           0 :     GdkWindow* gdk_window = mGdkWindow;
    6378           0 :     if (!gdk_window) {
    6379           0 :         return false;
    6380             :     }
    6381             : #ifdef DEBUG
    6382             :     // GDK_IS_WINDOW(...) expands to a statement-expression, and
    6383             :     // statement-expressions are not allowed in template-argument lists. So we
    6384             :     // have to make the MOZ_ASSERT condition indirect.
    6385           0 :     if (!GDK_IS_WINDOW(gdk_window)) {
    6386           0 :         MOZ_ASSERT(false, "must really be window");
    6387             :     }
    6388             : #endif
    6389             : 
    6390             :     // find the top-level window
    6391           0 :     gdk_window = gdk_window_get_toplevel(gdk_window);
    6392           0 :     MOZ_ASSERT(gdk_window,
    6393             :                "gdk_window_get_toplevel should not return null");
    6394           0 :     *aWindow = gdk_window;
    6395             : 
    6396           0 :     if (!aMouseEvent->mWidget) {
    6397           0 :         return false;
    6398             :     }
    6399             : 
    6400             :     // FIXME: It would be nice to have the widget position at the time
    6401             :     // of the event, but it's relatively unlikely that the widget has
    6402             :     // moved since the mousedown.  (On the other hand, it's quite likely
    6403             :     // that the mouse has moved, which is why we use the mouse position
    6404             :     // from the event.)
    6405           0 :     LayoutDeviceIntPoint offset = aMouseEvent->mWidget->WidgetToScreenOffset();
    6406           0 :     *aRootX = aMouseEvent->mRefPoint.x + offset.x;
    6407           0 :     *aRootY = aMouseEvent->mRefPoint.y + offset.y;
    6408             : 
    6409           0 :     return true;
    6410             : }
    6411             : 
    6412             : nsresult
    6413           0 : nsWindow::BeginMoveDrag(WidgetMouseEvent* aEvent)
    6414             : {
    6415           0 :     MOZ_ASSERT(aEvent, "must have event");
    6416           0 :     MOZ_ASSERT(aEvent->mClass == eMouseEventClass,
    6417             :                "event must have correct struct type");
    6418             : 
    6419             :     GdkWindow *gdk_window;
    6420             :     gint button, screenX, screenY;
    6421           0 :     if (!GetDragInfo(aEvent, &gdk_window, &button, &screenX, &screenY)) {
    6422           0 :         return NS_ERROR_FAILURE;
    6423             :     }
    6424             : 
    6425             :     // tell the window manager to start the move
    6426           0 :     screenX = DevicePixelsToGdkCoordRoundDown(screenX);
    6427           0 :     screenY = DevicePixelsToGdkCoordRoundDown(screenY);
    6428           0 :     gdk_window_begin_move_drag(gdk_window, button, screenX, screenY,
    6429           0 :                                aEvent->mTime);
    6430             : 
    6431           0 :     return NS_OK;
    6432             : }
    6433             : 
    6434             : nsresult
    6435           0 : nsWindow::BeginResizeDrag(WidgetGUIEvent* aEvent,
    6436             :                           int32_t aHorizontal,
    6437             :                           int32_t aVertical)
    6438             : {
    6439           0 :     NS_ENSURE_ARG_POINTER(aEvent);
    6440             : 
    6441           0 :     if (aEvent->mClass != eMouseEventClass) {
    6442             :         // you can only begin a resize drag with a mouse event
    6443           0 :         return NS_ERROR_INVALID_ARG;
    6444             :     }
    6445             : 
    6446             :     GdkWindow *gdk_window;
    6447             :     gint button, screenX, screenY;
    6448           0 :     if (!GetDragInfo(aEvent->AsMouseEvent(), &gdk_window, &button,
    6449             :                      &screenX, &screenY)) {
    6450           0 :         return NS_ERROR_FAILURE;
    6451             :     }
    6452             : 
    6453             :     // work out what GdkWindowEdge we're talking about
    6454             :     GdkWindowEdge window_edge;
    6455           0 :     if (aVertical < 0) {
    6456           0 :         if (aHorizontal < 0) {
    6457           0 :             window_edge = GDK_WINDOW_EDGE_NORTH_WEST;
    6458           0 :         } else if (aHorizontal == 0) {
    6459           0 :             window_edge = GDK_WINDOW_EDGE_NORTH;
    6460             :         } else {
    6461           0 :             window_edge = GDK_WINDOW_EDGE_NORTH_EAST;
    6462             :         }
    6463           0 :     } else if (aVertical == 0) {
    6464           0 :         if (aHorizontal < 0) {
    6465           0 :             window_edge = GDK_WINDOW_EDGE_WEST;
    6466           0 :         } else if (aHorizontal == 0) {
    6467           0 :             return NS_ERROR_INVALID_ARG;
    6468             :         } else {
    6469           0 :             window_edge = GDK_WINDOW_EDGE_EAST;
    6470             :         }
    6471             :     } else {
    6472           0 :         if (aHorizontal < 0) {
    6473           0 :             window_edge = GDK_WINDOW_EDGE_SOUTH_WEST;
    6474           0 :         } else if (aHorizontal == 0) {
    6475           0 :             window_edge = GDK_WINDOW_EDGE_SOUTH;
    6476             :         } else {
    6477           0 :             window_edge = GDK_WINDOW_EDGE_SOUTH_EAST;
    6478             :         }
    6479             :     }
    6480             : 
    6481             :     // tell the window manager to start the resize
    6482           0 :     gdk_window_begin_resize_drag(gdk_window, window_edge, button,
    6483           0 :                                  screenX, screenY, aEvent->mTime);
    6484             : 
    6485           0 :     return NS_OK;
    6486             : }
    6487             : 
    6488             : nsIWidget::LayerManager*
    6489         219 : nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager,
    6490             :                           LayersBackend aBackendHint,
    6491             :                           LayerManagerPersistence aPersistence)
    6492             : {
    6493         219 :     if (mIsDestroyed) {
    6494             :       // Prevent external code from triggering the re-creation of the LayerManager/Compositor
    6495             :       // during shutdown. Just return what we currently have, which is most likely null.
    6496           0 :       return mLayerManager;
    6497             :     }
    6498             : 
    6499         220 :     if (!mLayerManager && !IsComposited() &&
    6500           1 :         eTransparencyTransparent == GetTransparencyMode())
    6501             :     {
    6502           0 :         mLayerManager = CreateBasicLayerManager();
    6503             :     }
    6504             : 
    6505         219 :     return nsBaseWidget::GetLayerManager(aShadowManager, aBackendHint, aPersistence);
    6506             : }
    6507             : 
    6508             : void
    6509           0 : nsWindow::ClearCachedResources()
    6510             : {
    6511           0 :     if (mLayerManager &&
    6512           0 :         mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_BASIC) {
    6513           0 :         mLayerManager->ClearCachedResources();
    6514             :     }
    6515             : 
    6516           0 :     GList* children = gdk_window_peek_children(mGdkWindow);
    6517           0 :     for (GList* list = children; list; list = list->next) {
    6518           0 :         nsWindow* window = get_window_for_gdk_window(GDK_WINDOW(list->data));
    6519           0 :         if (window) {
    6520           0 :             window->ClearCachedResources();
    6521             :         }
    6522             :     }
    6523           0 : }
    6524             : 
    6525             : gint
    6526         208 : nsWindow::GdkScaleFactor()
    6527             : {
    6528             : #if (MOZ_WIDGET_GTK >= 3)
    6529             :     // Available as of GTK 3.10+
    6530           1 :     static auto sGdkWindowGetScaleFactorPtr = (gint (*)(GdkWindow*))
    6531         209 :         dlsym(RTLD_DEFAULT, "gdk_window_get_scale_factor");
    6532         208 :     if (sGdkWindowGetScaleFactorPtr && mGdkWindow)
    6533         206 :         return (*sGdkWindowGetScaleFactorPtr)(mGdkWindow);
    6534             : #endif
    6535           2 :     return ScreenHelperGTK::GetGTKMonitorScaleFactor();
    6536             : }
    6537             : 
    6538             : 
    6539             : gint
    6540          40 : nsWindow::DevicePixelsToGdkCoordRoundUp(int pixels) {
    6541          40 :     gint scale = GdkScaleFactor();
    6542          40 :     return (pixels + scale - 1) / scale;
    6543             : }
    6544             : 
    6545             : gint
    6546          40 : nsWindow::DevicePixelsToGdkCoordRoundDown(int pixels) {
    6547          40 :     gint scale = GdkScaleFactor();
    6548          40 :     return pixels / scale;
    6549             : }
    6550             : 
    6551             : GdkPoint
    6552           0 : nsWindow::DevicePixelsToGdkPointRoundDown(LayoutDeviceIntPoint point) {
    6553           0 :     gint scale = GdkScaleFactor();
    6554           0 :     return { point.x / scale, point.y / scale };
    6555             : }
    6556             : 
    6557             : GdkRectangle
    6558           2 : nsWindow::DevicePixelsToGdkRectRoundOut(LayoutDeviceIntRect rect) {
    6559           2 :     gint scale = GdkScaleFactor();
    6560           2 :     int x = rect.x / scale;
    6561           2 :     int y = rect.y / scale;
    6562           2 :     int right = (rect.x + rect.width + scale - 1) / scale;
    6563           2 :     int bottom = (rect.y + rect.height + scale - 1) / scale;
    6564           2 :     return { x, y, right - x, bottom - y };
    6565             : }
    6566             : 
    6567             : GdkRectangle
    6568           3 : nsWindow::DevicePixelsToGdkSizeRoundUp(LayoutDeviceIntSize pixelSize) {
    6569           3 :     gint scale = GdkScaleFactor();
    6570           3 :     gint width = (pixelSize.width + scale - 1) / scale;
    6571           3 :     gint height = (pixelSize.height + scale - 1) / scale;
    6572           3 :     return { 0, 0, width, height };
    6573             : }
    6574             : 
    6575             : int
    6576           0 : nsWindow::GdkCoordToDevicePixels(gint coord) {
    6577           0 :     return coord * GdkScaleFactor();
    6578             : }
    6579             : 
    6580             : LayoutDeviceIntPoint
    6581           6 : nsWindow::GdkEventCoordsToDevicePixels(gdouble x, gdouble y)
    6582             : {
    6583           6 :     gint scale = GdkScaleFactor();
    6584           6 :     return LayoutDeviceIntPoint::Round(x * scale, y * scale);
    6585             : }
    6586             : 
    6587             : LayoutDeviceIntPoint
    6588          64 : nsWindow::GdkPointToDevicePixels(GdkPoint point) {
    6589          64 :     gint scale = GdkScaleFactor();
    6590         128 :     return LayoutDeviceIntPoint(point.x * scale,
    6591         192 :                                 point.y * scale);
    6592             : }
    6593             : 
    6594             : LayoutDeviceIntRect
    6595           1 : nsWindow::GdkRectToDevicePixels(GdkRectangle rect) {
    6596           1 :     gint scale = GdkScaleFactor();
    6597           4 :     return LayoutDeviceIntRect(rect.x * scale,
    6598           1 :                                rect.y * scale,
    6599           1 :                                rect.width * scale,
    6600           3 :                                rect.height * scale);
    6601             : }
    6602             : 
    6603             : nsresult
    6604           0 : nsWindow::SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
    6605             :                                      uint32_t aNativeMessage,
    6606             :                                      uint32_t aModifierFlags,
    6607             :                                      nsIObserver* aObserver)
    6608             : {
    6609           0 :   AutoObserverNotifier notifier(aObserver, "mouseevent");
    6610             : 
    6611           0 :   if (!mGdkWindow) {
    6612           0 :     return NS_OK;
    6613             :   }
    6614             : 
    6615           0 :   GdkDisplay* display = gdk_window_get_display(mGdkWindow);
    6616             : 
    6617             :   // When a button-press/release event is requested, create it here and put it in the
    6618             :   // event queue. This will not emit a motion event - this needs to be done
    6619             :   // explicitly *before* requesting a button-press/release. You will also need to wait
    6620             :   // for the motion event to be dispatched before requesting a button-press/release
    6621             :   // event to maintain the desired event order.
    6622           0 :   if (aNativeMessage == GDK_BUTTON_PRESS || aNativeMessage == GDK_BUTTON_RELEASE) {
    6623             :     GdkEvent event;
    6624           0 :     memset(&event, 0, sizeof(GdkEvent));
    6625           0 :     event.type = (GdkEventType)aNativeMessage;
    6626           0 :     event.button.button = 1;
    6627           0 :     event.button.window = mGdkWindow;
    6628           0 :     event.button.time = GDK_CURRENT_TIME;
    6629             : 
    6630             : #if (MOZ_WIDGET_GTK == 3)
    6631             :     // Get device for event source
    6632           0 :     GdkDeviceManager *device_manager = gdk_display_get_device_manager(display);
    6633           0 :     event.button.device = gdk_device_manager_get_client_pointer(device_manager);
    6634             : #endif
    6635             : 
    6636           0 :     event.button.x_root = DevicePixelsToGdkCoordRoundDown(aPoint.x);
    6637           0 :     event.button.y_root = DevicePixelsToGdkCoordRoundDown(aPoint.y);
    6638             : 
    6639           0 :     LayoutDeviceIntPoint pointInWindow = aPoint - WidgetToScreenOffset();
    6640           0 :     event.button.x = DevicePixelsToGdkCoordRoundDown(pointInWindow.x);
    6641           0 :     event.button.y = DevicePixelsToGdkCoordRoundDown(pointInWindow.y);
    6642             : 
    6643           0 :     gdk_event_put(&event);
    6644             :   } else {
    6645             :     // We don't support specific events other than button-press/release. In all
    6646             :     // other cases we'll synthesize a motion event that will be emitted by
    6647             :     // gdk_display_warp_pointer().
    6648           0 :     GdkScreen* screen = gdk_window_get_screen(mGdkWindow);
    6649           0 :     GdkPoint point = DevicePixelsToGdkPointRoundDown(aPoint);
    6650           0 :     gdk_display_warp_pointer(display, screen, point.x, point.y);
    6651             :   }
    6652             : 
    6653           0 :   return NS_OK;
    6654             : }
    6655             : 
    6656             : nsresult
    6657           0 : nsWindow::SynthesizeNativeMouseScrollEvent(mozilla::LayoutDeviceIntPoint aPoint,
    6658             :                                            uint32_t aNativeMessage,
    6659             :                                            double aDeltaX,
    6660             :                                            double aDeltaY,
    6661             :                                            double aDeltaZ,
    6662             :                                            uint32_t aModifierFlags,
    6663             :                                            uint32_t aAdditionalFlags,
    6664             :                                            nsIObserver* aObserver)
    6665             : {
    6666           0 :   AutoObserverNotifier notifier(aObserver, "mousescrollevent");
    6667             : 
    6668           0 :   if (!mGdkWindow) {
    6669           0 :     return NS_OK;
    6670             :   }
    6671             : 
    6672             :   GdkEvent event;
    6673           0 :   memset(&event, 0, sizeof(GdkEvent));
    6674           0 :   event.type = GDK_SCROLL;
    6675           0 :   event.scroll.window = mGdkWindow;
    6676           0 :   event.scroll.time = GDK_CURRENT_TIME;
    6677             : #if (MOZ_WIDGET_GTK == 3)
    6678             :   // Get device for event source
    6679           0 :   GdkDisplay* display = gdk_window_get_display(mGdkWindow);
    6680           0 :   GdkDeviceManager *device_manager = gdk_display_get_device_manager(display);
    6681           0 :   event.scroll.device = gdk_device_manager_get_client_pointer(device_manager);
    6682             : #endif
    6683           0 :   event.scroll.x_root = DevicePixelsToGdkCoordRoundDown(aPoint.x);
    6684           0 :   event.scroll.y_root = DevicePixelsToGdkCoordRoundDown(aPoint.y);
    6685             : 
    6686           0 :   LayoutDeviceIntPoint pointInWindow = aPoint - WidgetToScreenOffset();
    6687           0 :   event.scroll.x = DevicePixelsToGdkCoordRoundDown(pointInWindow.x);
    6688           0 :   event.scroll.y = DevicePixelsToGdkCoordRoundDown(pointInWindow.y);
    6689             : 
    6690             :   // The delta values are backwards on Linux compared to Windows and Cocoa,
    6691             :   // hence the negation.
    6692             : #if GTK_CHECK_VERSION(3,4,0)
    6693             :   // TODO: is this correct? I don't have GTK 3.4+ so I can't check
    6694           0 :   event.scroll.direction = GDK_SCROLL_SMOOTH;
    6695           0 :   event.scroll.delta_x = -aDeltaX;
    6696           0 :   event.scroll.delta_y = -aDeltaY;
    6697             : #else
    6698             :   if (aDeltaX < 0) {
    6699             :     event.scroll.direction = GDK_SCROLL_RIGHT;
    6700             :   } else if (aDeltaX > 0) {
    6701             :     event.scroll.direction = GDK_SCROLL_LEFT;
    6702             :   } else if (aDeltaY < 0) {
    6703             :     event.scroll.direction = GDK_SCROLL_DOWN;
    6704             :   } else if (aDeltaY > 0) {
    6705             :     event.scroll.direction = GDK_SCROLL_UP;
    6706             :   } else {
    6707             :     return NS_OK;
    6708             :   }
    6709             : #endif
    6710             : 
    6711           0 :   gdk_event_put(&event);
    6712             : 
    6713           0 :   return NS_OK;
    6714             : }
    6715             : 
    6716             : #if GTK_CHECK_VERSION(3,4,0)
    6717             : nsresult
    6718           0 : nsWindow::SynthesizeNativeTouchPoint(uint32_t aPointerId,
    6719             :                                      TouchPointerState aPointerState,
    6720             :                                      LayoutDeviceIntPoint aPoint,
    6721             :                                      double aPointerPressure,
    6722             :                                      uint32_t aPointerOrientation,
    6723             :                                      nsIObserver* aObserver)
    6724             : {
    6725           0 :   AutoObserverNotifier notifier(aObserver, "touchpoint");
    6726             : 
    6727           0 :   if (!mGdkWindow) {
    6728           0 :     return NS_OK;
    6729             :   }
    6730             : 
    6731             :   GdkEvent event;
    6732           0 :   memset(&event, 0, sizeof(GdkEvent));
    6733             : 
    6734           0 :   static std::map<uint32_t, GdkEventSequence*> sKnownPointers;
    6735             : 
    6736           0 :   auto result = sKnownPointers.find(aPointerId);
    6737           0 :   switch (aPointerState) {
    6738             :   case TOUCH_CONTACT:
    6739           0 :     if (result == sKnownPointers.end()) {
    6740             :       // GdkEventSequence isn't a thing we can instantiate, and never gets
    6741             :       // dereferenced in the gtk code. It's an opaque pointer, the only
    6742             :       // requirement is that it be distinct from other instances of
    6743             :       // GdkEventSequence*.
    6744           0 :       event.touch.sequence = (GdkEventSequence*)((uintptr_t)aPointerId);
    6745           0 :       sKnownPointers[aPointerId] = event.touch.sequence;
    6746           0 :       event.type = GDK_TOUCH_BEGIN;
    6747             :     } else {
    6748           0 :       event.touch.sequence = result->second;
    6749           0 :       event.type = GDK_TOUCH_UPDATE;
    6750             :     }
    6751           0 :     break;
    6752             :   case TOUCH_REMOVE:
    6753           0 :     event.type = GDK_TOUCH_END;
    6754           0 :     if (result == sKnownPointers.end()) {
    6755           0 :       NS_WARNING("Tried to synthesize touch-end for unknown pointer!");
    6756           0 :       return NS_ERROR_UNEXPECTED;
    6757             :     }
    6758           0 :     event.touch.sequence = result->second;
    6759           0 :     sKnownPointers.erase(result);
    6760           0 :     break;
    6761             :   case TOUCH_CANCEL:
    6762           0 :     event.type = GDK_TOUCH_CANCEL;
    6763           0 :     if (result == sKnownPointers.end()) {
    6764           0 :       NS_WARNING("Tried to synthesize touch-cancel for unknown pointer!");
    6765           0 :       return NS_ERROR_UNEXPECTED;
    6766             :     }
    6767           0 :     event.touch.sequence = result->second;
    6768           0 :     sKnownPointers.erase(result);
    6769           0 :     break;
    6770             :   case TOUCH_HOVER:
    6771             :   default:
    6772           0 :     return NS_ERROR_NOT_IMPLEMENTED;
    6773             :   }
    6774             : 
    6775           0 :   event.touch.window = mGdkWindow;
    6776           0 :   event.touch.time = GDK_CURRENT_TIME;
    6777             : 
    6778           0 :   GdkDisplay* display = gdk_window_get_display(mGdkWindow);
    6779           0 :   GdkDeviceManager* device_manager = gdk_display_get_device_manager(display);
    6780           0 :   event.touch.device = gdk_device_manager_get_client_pointer(device_manager);
    6781             : 
    6782           0 :   event.touch.x_root = DevicePixelsToGdkCoordRoundDown(aPoint.x);
    6783           0 :   event.touch.y_root = DevicePixelsToGdkCoordRoundDown(aPoint.y);
    6784             : 
    6785           0 :   LayoutDeviceIntPoint pointInWindow = aPoint - WidgetToScreenOffset();
    6786           0 :   event.touch.x = DevicePixelsToGdkCoordRoundDown(pointInWindow.x);
    6787           0 :   event.touch.y = DevicePixelsToGdkCoordRoundDown(pointInWindow.y);
    6788             : 
    6789           0 :   gdk_event_put(&event);
    6790             : 
    6791           0 :   return NS_OK;
    6792             : }
    6793             : #endif
    6794             : 
    6795             : int32_t
    6796           1 : nsWindow::RoundsWidgetCoordinatesTo()
    6797             : {
    6798           1 :     return GdkScaleFactor();
    6799             : }
    6800             : 
    6801           1 : void nsWindow::GetCompositorWidgetInitData(mozilla::widget::CompositorWidgetInitData* aInitData)
    6802             : {
    6803             :   #ifdef MOZ_X11
    6804           2 :   *aInitData = mozilla::widget::CompositorWidgetInitData(
    6805             :                                   mXWindow,
    6806           2 :                                   nsCString(XDisplayString(mXDisplay)),
    6807           3 :                                   GetClientSize());
    6808             :   #endif
    6809           1 : }
    6810             : 
    6811             : bool
    6812           1 : nsWindow::IsComposited() const
    6813             : {
    6814           1 :   if (!mGdkWindow) {
    6815           0 :     NS_WARNING("nsWindow::HasARGBVisual called before realization!");
    6816           0 :     return false;
    6817             :   }
    6818             : 
    6819           1 :   GdkScreen* gdkScreen = gdk_screen_get_default();
    6820           2 :   return gdk_screen_is_composited(gdkScreen) &&
    6821           1 :          (gdk_window_get_visual(mGdkWindow)
    6822           2 :             == gdk_screen_get_rgba_visual(gdkScreen));
    6823             : }

Generated by: LCOV version 1.13